From 7f2a66f262e5b378909c15f5a2c51befeffbf82a Mon Sep 17 00:00:00 2001 From: Gianni Ceccarelli Date: Thu, 14 Dec 2023 13:58:07 +0000 Subject: [PATCH] allow a theme to specify a font - #225 --- packages/backend/src/server/web/boot.js | 23 +++++++++++++++++- packages/frontend/src/scripts/theme.ts | 31 +++++++++++++++++++++++++ packages/frontend/src/style.scss | 2 +- 3 files changed, 54 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/server/web/boot.js b/packages/backend/src/server/web/boot.js index e1864ae12..e1aaee1d4 100644 --- a/packages/backend/src/server/web/boot.js +++ b/packages/backend/src/server/web/boot.js @@ -106,8 +106,29 @@ //#region Theme const theme = localStorage.getItem('theme'); + const themeFontFaceName = 'sharkey-theme-font-face'; if (theme) { - for (const [k, v] of Object.entries(JSON.parse(theme))) { + let existingFontFace; + document.fonts.forEach((v,k,s)=>{if (v.family === themeFontFaceName) existingFontFace=v;}); + if (existingFontFace) document.fonts.delete(existingFontFace); + + const themeProps = JSON.parse(theme); + const fontFaceSrc = themeProps.fontFaceSrc; + const fontFaceOpts = themeProps.fontFaceOpts || {}; + if (fontFaceSrc) { + const fontFace = new FontFace( + themeFontFaceName, + fontFaceSrc, fontFaceOpts || {}, + ); + document.fonts.add(fontFace); + fontFace.load().catch( + (failure) => { + console.log(failure) + } + ); + } + for (const [k, v] of Object.entries(themeProps)) { + if (k.startsWith('font')) continue; document.documentElement.style.setProperty(`--${k}`, v.toString()); // HTMLの theme-color 適用 diff --git a/packages/frontend/src/scripts/theme.ts b/packages/frontend/src/scripts/theme.ts index d2474bf10..8bfb03f0d 100644 --- a/packages/frontend/src/scripts/theme.ts +++ b/packages/frontend/src/scripts/theme.ts @@ -54,6 +54,8 @@ export const getBuiltinThemesRef = () => { return builtinThemes; }; +const themeFontFaceName = 'sharkey-theme-font-face'; + let timeout = null; export function applyTheme(theme: Theme, persist = true) { @@ -84,7 +86,32 @@ export function applyTheme(theme: Theme, persist = true) { } } + let existingFontFace; + document.fonts.forEach( + (fontFace) => { + if (fontFace.family === themeFontFaceName) existingFontFace = fontFace; + }, + ); + if (existingFontFace) document.fonts.delete(existingFontFace); + + const fontFaceSrc = props.fontFaceSrc; + const fontFaceOpts = props.fontFaceOpts || {}; + + if (fontFaceSrc) { + const fontFace = new FontFace( + themeFontFaceName, + fontFaceSrc, fontFaceOpts, + ); + document.fonts.add(fontFace); + fontFace.load().catch( + (failure) => { + console.log(failure); + }, + ); + } + for (const [k, v] of Object.entries(props)) { + if (k.startsWith('font')) continue; document.documentElement.style.setProperty(`--${k}`, v.toString()); } @@ -128,6 +155,10 @@ function compile(theme: Theme): Record { for (const [k, v] of Object.entries(theme.props)) { if (k.startsWith('$')) continue; // ignore const + if (k.startsWith('font')) { // font specs are different + props[k] = v; + continue; + } props[k] = v.startsWith('"') ? v.replace(/^"\s*/, '') : genValue(getColor(v)); } diff --git a/packages/frontend/src/style.scss b/packages/frontend/src/style.scss index 8c531fc2c..b863f61cb 100644 --- a/packages/frontend/src/style.scss +++ b/packages/frontend/src/style.scss @@ -62,7 +62,7 @@ html { accent-color: var(--accent); overflow: auto; overflow-wrap: break-word; - font-family: 'Lexend', 'Hiragino Maru Gothic Pro', "BIZ UDGothic", Roboto, HelveticaNeue, Arial, sans-serif; + font-family: 'sharkey-theme-font-face', 'Lexend', 'Hiragino Maru Gothic Pro', "BIZ UDGothic", Roboto, HelveticaNeue, Arial, sans-serif; font-size: 14px; line-height: 1.35; text-size-adjust: 100%;