diff --git a/assets/static/js/main.ts b/assets/static/js/main.ts
index 4d1fc3f..bb462a8 100644
--- a/assets/static/js/main.ts
+++ b/assets/static/js/main.ts
@@ -2,6 +2,10 @@
// degraded mode (shared across all apps). Must stay first so the shim is in
// place before any render.
import '@screenly-labs/signage-kit/polyfills'
+// On a Screenly player the viewer is already a customer, so the promotional
+// Screenly badge (.brand) is removed; every other browser keeps it. Shared with
+// every signage app via the kit.
+import { removeScreenlyBranding } from '@screenly-labs/signage-kit/branding'
import qrcode from 'qrcode-generator'
import { hostLabel, largestFit, relativeTime } from './render'
// The wire contract is defined once in the worker's parser. `import type` is
@@ -411,15 +415,6 @@ interface FeedResponse {
stage?.style.setProperty('--rotate-ms', `${rotateMs}ms`)
}
- // On a Screenly player the viewer is already a Screenly customer, so the
- // promotional Screenly badge is removed. The 'screenly-viewer' token in the
- // user agent marks these devices; every other browser keeps the badge.
- const removeScreenlyBranding = (): void => {
- if (navigator.userAgent.includes('screenly-viewer')) {
- document.querySelector('.brand')?.remove()
- }
- }
-
const init = (): void => {
removeScreenlyBranding()
readConfig()
diff --git a/assets/static/styles/main.css b/assets/static/styles/main.css
index aaa6d54..a02dd30 100644
--- a/assets/static/styles/main.css
+++ b/assets/static/styles/main.css
@@ -10,43 +10,10 @@
orientations; the per-item fit is finished in main.ts.
========================================================================= */
-@font-face {
- font-family: "Bricolage Grotesque";
- font-weight: 200 800;
- font-style: normal;
- font-optical-sizing: auto;
- font-display: swap;
- src: url("/static/fonts/bricolage-grotesque-latin-standard-normal.woff2") format("woff2");
- unicode-range:
- U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
-}
-@font-face {
- font-family: "Hanken Grotesk";
- font-weight: 100 900;
- font-style: normal;
- font-display: swap;
- src: url("/static/fonts/hanken-grotesk-latin-wght-normal.woff2") format("woff2");
- unicode-range:
- U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
-}
-@font-face {
- font-family: "Space Mono";
- font-weight: 400;
- font-style: normal;
- font-display: swap;
- src: url("/static/fonts/space-mono-latin-400-normal.woff2") format("woff2");
- unicode-range:
- U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
-}
-@font-face {
- font-family: "Space Mono";
- font-weight: 700;
- font-style: normal;
- font-display: swap;
- src: url("/static/fonts/space-mono-latin-700-normal.woff2") format("woff2");
- unicode-range:
- U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
-}
+/* Webfonts (@font-face) and the standardized footer badge (.brand) come from
+ @screenly-labs/signage-kit — build.ts prepends styles/fonts.css + styles/brand.css
+ to this file before down-leveling. This file keeps the app's own tokens, reset,
+ fluid root, and "The Wire" component styles. */
:root {
--font-display: "Bricolage Grotesque", "Hanken Grotesk", system-ui, sans-serif;
@@ -154,20 +121,6 @@ body {
font-weight: 700;
white-space: nowrap;
}
-.rail__brand {
- flex: none;
- display: flex;
- align-items: center;
- padding-inline-start: clamp(0.7rem, 2vmin, 1.6rem);
- margin-inline-start: clamp(0.7rem, 2vmin, 1.6rem);
- border-inline-start: 1px solid var(--hairline);
- opacity: 0.85;
-}
-.rail__brand img {
- block-size: clamp(0.7rem, 1vmin + 0.5rem, 1.4rem);
- inline-size: auto;
- display: block;
-}
/* Transmission line: a track on the rail's bottom edge that fills amber over
each rotation interval (set in motion below). */
.rail__line {
diff --git a/build.ts b/build.ts
index 547d5dc..19e4f70 100644
--- a/build.ts
+++ b/build.ts
@@ -16,12 +16,21 @@
// CSS step (used by `bun run dev`, which only needs the JS bundle, so the
// working-tree CSS stays unminified for editing).
+import { readFileSync } from 'node:fs'
import { Glob } from 'bun'
import { bundleJs, processCss } from '@screenly-labs/signage-kit/build'
import { run as syncFonts } from './sync-fonts'
const clientOnly = process.argv.includes('--client')
+// Shared chrome CSS from @screenly-labs/signage-kit — the canonical @font-face
+// set and the standardized fixed footer badge. Prepended to this app's raw
+// main.css at build time (a raw-CSS Worker can't resolve a bare `@import`), so
+// the shared rules land before the app's, which override where they overlap.
+const sharedCss = ['fonts.css', 'brand.css']
+ .map((f) => readFileSync(Bun.resolveSync(`@screenly-labs/signage-kit/styles/${f}`, import.meta.dir), 'utf8'))
+ .join('\n')
+
// Vendor the Bun-managed webfonts into ./assets first.
await syncFonts()
@@ -47,7 +56,7 @@ console.log('✓ JS: assets/static/js/main.js (iife, es2017)')
if (!clientOnly) {
for await (const path of new Glob('assets/static/styles/*.css').scan('.')) {
try {
- const code = await processCss(await Bun.file(path).text(), {
+ const code = await processCss(`${sharedCss}\n${await Bun.file(path).text()}`, {
includeDegraded: true,
filename: path
})
diff --git a/bun.lock b/bun.lock
index dbdc82e..7cce354 100644
--- a/bun.lock
+++ b/bun.lock
@@ -5,10 +5,7 @@
"": {
"name": "screenly-rss-reader",
"dependencies": {
- "@fontsource-variable/bricolage-grotesque": "^5.2.10",
- "@fontsource-variable/hanken-grotesk": "^5.2.8",
- "@fontsource/space-mono": "^5.2.9",
- "@screenly-labs/signage-kit": "github:Screenly-Labs/signage-kit#2026.7.0",
+ "@screenly-labs/signage-kit": "github:Screenly-Labs/signage-kit#2026.7.2",
"hono": "^4.12.27",
"qrcode-generator": "^2.0.4",
},
@@ -118,8 +115,14 @@
"@fontsource-variable/bricolage-grotesque": ["@fontsource-variable/bricolage-grotesque@5.2.10", "", {}, "sha512-5EDsCqgGpKVcJWE4sg9ydli+t5WM97mISYw5lla/Ev4z71FwXh1oN0YUU8xjkRW9+wBCGD9R+ntAvI8G4bUFJg=="],
+ "@fontsource-variable/fraunces": ["@fontsource-variable/fraunces@5.2.9", "", {}, "sha512-Y6IjunlN9Ni723np+GIgAaKzCDBrPRrqNi01TZxHs5wtHYROWFM9W6yiT+/gGwSjWIRD18oX17kD/BRWekc/Lw=="],
+
"@fontsource-variable/hanken-grotesk": ["@fontsource-variable/hanken-grotesk@5.2.8", "", {}, "sha512-K7hu09ZKReBc7EifRLeM4K94NZBrxFEg0nGcISmVwlFQOJo4EmYkLXTWEwr5JcNW4z2hr5zy8vLS2sxC8JDmrQ=="],
+ "@fontsource-variable/jetbrains-mono": ["@fontsource-variable/jetbrains-mono@5.2.8", "", {}, "sha512-WBA9elru6Jdp5df2mES55wuOO0WIrn3kpXnI4+W2ek5u3ZgLS9XS4gmIlcQhiZOWEKl95meYdvK7xI+ETLCq/Q=="],
+
+ "@fontsource-variable/newsreader": ["@fontsource-variable/newsreader@5.2.10", "", {}, "sha512-MdI2iRwrqWpMOU/2aV2BgfZ4dJNlj/XlYaY8Zb7t87mWqHskYW0XiUANkt1cyOCiEfW2VQ0bQ5vZgGPp6B2B4w=="],
+
"@fontsource/space-mono": ["@fontsource/space-mono@5.2.9", "", {}, "sha512-b61faFOHEISQ/pD25G+cfGY9o/WW6lRv6hBQQfpWvEJ4y1V+S4gmth95EVyBE2VL3qDYHeVQ8nBzrplzdXTDDg=="],
"@img/colour": ["@img/colour@1.1.0", "", {}, "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ=="],
@@ -184,7 +187,7 @@
"@poppinss/exception": ["@poppinss/exception@1.2.3", "", {}, "sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw=="],
- "@screenly-labs/signage-kit": ["@screenly-labs/signage-kit@github:Screenly-Labs/signage-kit#eb470fb", { "peerDependencies": { "@csstools/postcss-cascade-layers": "^6", "browserslist": "^4", "esbuild": "^0.28", "lightningcss": "^1.32", "postcss": "^8" }, "optionalPeers": ["@csstools/postcss-cascade-layers", "postcss"] }, "Screenly-Labs-signage-kit-eb470fb", "sha512-acuAb2R/77crUjgnT9GFVlNdpgUTzvK5OLRRsZsZ30dZcJ7ThH/f8al2janEIJWC1JoyqTiarJ2x1uAH6In86A=="],
+ "@screenly-labs/signage-kit": ["@screenly-labs/signage-kit@github:Screenly-Labs/signage-kit#b7f3d44", { "dependencies": { "@fontsource-variable/bricolage-grotesque": "^5.2.10", "@fontsource-variable/fraunces": "^5.2.9", "@fontsource-variable/hanken-grotesk": "^5.2.8", "@fontsource-variable/jetbrains-mono": "^5.2.8", "@fontsource-variable/newsreader": "^5.2.10", "@fontsource/space-mono": "^5.2.9" }, "peerDependencies": { "@csstools/postcss-cascade-layers": "^6", "browserslist": "^4", "esbuild": "^0.28", "lightningcss": "^1.32", "postcss": "^8" }, "optionalPeers": ["@csstools/postcss-cascade-layers", "postcss"] }, "Screenly-Labs-signage-kit-b7f3d44", "sha512-42YdnSCPpYpTyMucl1T+FGv3HQeyzz2UDEvYoLdP4EMVAD1m0U1G8WN2hgTE4vFVs3w8hGcqFisWBjkEc26rFA=="],
"@sindresorhus/is": ["@sindresorhus/is@7.2.0", "", {}, "sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw=="],
diff --git a/package.json b/package.json
index f0d7e96..69646cc 100644
--- a/package.json
+++ b/package.json
@@ -17,10 +17,7 @@
},
"license": "AGPL-3.0-only",
"dependencies": {
- "@fontsource-variable/bricolage-grotesque": "^5.2.10",
- "@fontsource-variable/hanken-grotesk": "^5.2.8",
- "@fontsource/space-mono": "^5.2.9",
- "@screenly-labs/signage-kit": "github:Screenly-Labs/signage-kit#2026.7.0",
+ "@screenly-labs/signage-kit": "github:Screenly-Labs/signage-kit#2026.7.2",
"hono": "^4.12.27",
"qrcode-generator": "^2.0.4"
},
diff --git a/src/components/App.tsx b/src/components/App.tsx
index 654c04b..8a125cf 100644
--- a/src/components/App.tsx
+++ b/src/components/App.tsx
@@ -30,7 +30,7 @@ const App = ({ env, feedId, feedTitle, v }: AppProps) => {
=> {
- let count = 0
+export const run = (): Promise =>
+ syncFonts(['bricolage-grotesque', 'hanken-grotesk', 'space-mono'])
- for (const rel of FONTS) {
- const file = rel.split('/').pop()
- const src = Bun.file(`node_modules/${rel}`)
-
- if (!(await src.exists())) {
- console.error(`✗ Missing ${file} — run \`bun install\` first.`)
- process.exit(1)
- }
-
- await Bun.write(`${DEST_DIR}/${file}`, src)
- console.log(`✓ Font: ${DEST_DIR}/${file}`)
- count++
- }
-
- console.log(`Fonts synced — ${count} file(s) vendored from @fontsource.`)
-}
-
-// Allow running standalone: `bun run sync-fonts.ts`
if (import.meta.main) {
await run()
}