From 0588e145ae6ad17bbce0561f042e8a53f06b0063 Mon Sep 17 00:00:00 2001 From: undefined Date: Fri, 9 May 2025 09:53:52 +0800 Subject: [PATCH] ui: add custom font support --- package.json | 2 +- packages/components/package.json | 2 + packages/hydrooj/package.json | 2 +- .../ui-default/components/customFont.page.tsx | 88 +++++++++++++++++++ packages/ui-default/package.json | 4 +- 5 files changed, 94 insertions(+), 4 deletions(-) create mode 100644 packages/ui-default/components/customFont.page.tsx diff --git a/package.json b/package.json index 7700f86ba..f11c8bb26 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "version": "1.0.0", "license": "AGPL-3.0-only", "devDependencies": { - "@types/autocannon": "^7.12.6", + "@types/autocannon": "^7.12.7", "@types/chai": "^5.2.2", "@types/cross-spawn": "^6.0.6", "@types/node": "22.14.1", diff --git a/packages/components/package.json b/packages/components/package.json index 9c7c8c053..c67179e20 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -19,6 +19,8 @@ "sass": "^1.87.0" }, "peerDependencies": { + "react": "*", + "react-dom": "*", "schemastery": "*" } } diff --git a/packages/hydrooj/package.json b/packages/hydrooj/package.json index c62aaf7d4..17d0a99f1 100644 --- a/packages/hydrooj/package.json +++ b/packages/hydrooj/package.json @@ -41,7 +41,7 @@ "mongodb": "^6.16.0", "mongodb-uri": "^0.9.7", "nanoid": "^5.1.5", - "nodemailer": "^7.0.2", + "nodemailer": "^7.0.3", "notp": "^2.0.3", "p-queue": "^8.1.0", "sanitize-filename": "^1.6.3", diff --git a/packages/ui-default/components/customFont.page.tsx b/packages/ui-default/components/customFont.page.tsx new file mode 100644 index 000000000..f059742b8 --- /dev/null +++ b/packages/ui-default/components/customFont.page.tsx @@ -0,0 +1,88 @@ +import { CustomSelectAutoComplete } from '@hydrooj/components'; +import $ from 'jquery'; +import { AutoloadPage } from 'vj/misc/Page'; +import { i18n, tpl } from 'vj/utils'; +import { ActionDialog } from './dialog'; + +async function getAvailableFonts() { + const fonts = await (window as any).queryLocalFonts(); + const result = {}; + for (const font of fonts) result[font.family] ||= font.fullName; + return Object.entries(result).map(([family, fullName]) => ({ + id: family, + name: family === fullName ? family : `${fullName} (${family})`, + fullName, + })); +} + +const customFont = localStorage.getItem('customFont'); +const customCodeFont = localStorage.getItem('customCodeFont'); + +export default new AutoloadPage('customFont', (pageName) => { + let dialog; + let selection = ''; + let handle = null; + + async function showDialog(saveKey: string) { + if (!dialog) { + const fonts = await getAvailableFonts(); + dialog = new ActionDialog({ + $body: $(tpl( { handle = el; }} + allowEmptyQuery={false} + data={fonts} + renderItem={(item) =>
{item.name}
} + />, true)), + onDispatch: (action) => { + selection = handle.getSelectedItems()?.[0]?.id; + return action !== 'ok' || selection; + }, + cancelByEsc: false, + cancelByClickingBack: false, + }); + } + dialog.open().then((action) => { + console.log(action, saveKey, selection); + if (action === 'ok') { + localStorage.setItem(saveKey, selection); + window.location.reload(); + } else { + localStorage.removeItem(saveKey); + } + }); + } + + function FontSelectButton(props: { key: string, label: string, value: string }) { + return
; + } + + if (pageName === 'home_preference' && 'queryLocalFonts' in window) { + $('[name="form_item_fontFamily"]').parent().parent().parent().append($(tpl( + , + ))); + $('[name="form_item_codeFontFamily"]').parent().parent().parent().append($(tpl( + , + ))); + $(document).on('click', '[data-show-font-dialog]', (ev) => { + ev.preventDefault(); + showDialog(ev.target.dataset.showFontDialog); + }); + } +}, () => { + const fontBlock = Array.from(document.head.children).find((el) => el.tagName === 'STYLE' && el.textContent?.includes('--code-font-family')); + if (fontBlock) { + if (customFont) { + fontBlock.textContent = fontBlock.textContent?.replace(/--font-family:/, `--font-family: "${customFont}", `); + } + if (customCodeFont) { + fontBlock.textContent = fontBlock.textContent?.replace(/--code-font-family:/, `--code-font-family: "${customCodeFont}", `); + } + } else { + console.warn('No font style block found'); + } +}); diff --git a/packages/ui-default/package.json b/packages/ui-default/package.json index 5a58e6a94..3e4efe31a 100644 --- a/packages/ui-default/package.json +++ b/packages/ui-default/package.json @@ -21,7 +21,7 @@ "@fontsource/source-code-pro": "^5.2.5", "@fontsource/ubuntu-mono": "^5.2.5", "@hydrooj/utils": "workspace:^", - "@sentry/browser": "^9.15.0", + "@sentry/browser": "^9.17.0", "@sentry/webpack-plugin": "^3.4.0", "@simplewebauthn/browser": "13.1.0", "@svgr/webpack": "^8.1.0", @@ -66,7 +66,7 @@ "jquery.easing": "^1.4.1", "jquery.transit": "^0.9.12", "matchmedia-polyfill": "^0.3.2", - "md-editor-rt": "^5.5.0", + "md-editor-rt": "^5.5.1", "mini-css-extract-plugin": "^2.9.2", "moment": "^2.30.1", "monaco-editor": "0.52.2",