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..21026c2 100644 --- a/assets/static/styles/main.css +++ b/assets/static/styles/main.css @@ -10,43 +10,11 @@ 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) come from @screenly-labs/signage-kit — build.ts prepends + styles/fonts.css to this file before down-leveling. The Screenly badge stays in + the rail (see .brand below), not the kit's fixed corner badge, because a QR + lockup owns the bottom-right corner here. 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,7 +122,10 @@ body { font-weight: 700; white-space: nowrap; } -.rail__brand { +/* Screenly badge — carried in the rail (not the kit's fixed corner badge): a QR + "scan to read" lockup owns the bottom-right corner here. Kept as `.brand` so + the shared removeScreenlyBranding() hides it on Screenly players. */ +.brand { flex: none; display: flex; align-items: center; @@ -163,7 +134,7 @@ body { border-inline-start: 1px solid var(--hairline); opacity: 0.85; } -.rail__brand img { +.brand img { block-size: clamp(0.7rem, 1vmin + 0.5rem, 1.4rem); inline-size: auto; display: block; diff --git a/build.ts b/build.ts index 547d5dc..fbdd718 100644 --- a/build.ts +++ b/build.ts @@ -16,12 +16,23 @@ // 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. Prepended to this app's raw main.css at build time (a raw-CSS Worker +// can't resolve a bare `@import`). NOT the kit's brand.css: this app carries the +// Screenly badge in its top rail, and a QR "scan to read" lockup already sits in +// the bottom-right corner, so the kit's fixed corner badge would overlap it. The +// badge stays in the rail (`.brand`, below); only the removal logic is shared. +const sharedCss = ['fonts.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 +58,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) => {