diff --git a/frontend/locales/en.json b/frontend/locales/en.json index 9f01a108..f24fb428 100644 --- a/frontend/locales/en.json +++ b/frontend/locales/en.json @@ -27,12 +27,14 @@ "anErrorHappened": "An error happened", "apiKeys": "API keys", "apiKeysSettingsDescription": "Add and revoke API keys for external access to your server", + "appDefaultTypography": "Application default typography ({value})", "appName": "App name", "appVersion": "App version", "appearsOn": "Appearances", "art": "Art", "artist": "Artist", "artists": "Artists", + "askAgain": "Ask again", "audio": "Audio", "auto": "Automatic", "backdrop": "Backdrop", @@ -72,6 +74,7 @@ "createKeySuccess": "Successfully created a new API key", "crew": "Crew", "criticRating": "Critic rating", + "currentAppTypography": "Current application typography ({value})", "currentPassword": "Current password", "customRating": "Custom rating", "dateAdded": "Date added", @@ -369,6 +372,7 @@ "switchToLightMode": "Switch to light mode", "syncPlayGroups": "SyncPlay groups", "syncingSettingsInProgress": "Syncing settingsā€¦", + "systemTypography": "System typography", "tagName": "Tag name", "tagline": "Tagline", "tags": "Tags", diff --git a/frontend/src/assets/styles/global.css b/frontend/src/assets/styles/global.css index 726c5992..cf18c603 100644 --- a/frontend/src/assets/styles/global.css +++ b/frontend/src/assets/styles/global.css @@ -1,5 +1,5 @@ * { - font-family: 'Figtree Variable', sans-serif, system-ui !important; + font-family: var(--j-font-family), sans-serif, system-ui !important; } html { diff --git a/frontend/src/components/Playback/SubtitleTrack.vue b/frontend/src/components/Playback/SubtitleTrack.vue index b7fdf400..64c44ae1 100644 --- a/frontend/src/components/Playback/SubtitleTrack.vue +++ b/frontend/src/components/Playback/SubtitleTrack.vue @@ -5,26 +5,32 @@ :srclang="playerElement.currentExternalSubtitleTrack?.srcLang" :src="playerElement.currentExternalSubtitleTrack?.src"> + - {{ previewText }} + + diff --git a/frontend/src/components/Selectors/FontSelector.vue b/frontend/src/components/Selectors/FontSelector.vue index 8f507d80..9bc199e6 100644 --- a/frontend/src/components/Selectors/FontSelector.vue +++ b/frontend/src/components/Selectors/FontSelector.vue @@ -6,7 +6,6 @@ icon="$warning"> {{ $t('queryLocalFontsNotSupportedWarning') }}
- {{ $t('enablePermission') }} + + {{ $t('askAgain') }} + diff --git a/frontend/src/components/lib/JApp.vue b/frontend/src/components/lib/JApp.vue index 8ac2d96e..349887a1 100644 --- a/frontend/src/components/lib/JApp.vue +++ b/frontend/src/components/lib/JApp.vue @@ -11,6 +11,7 @@ cursor: wait; --j-color-background: rgb(var(--v-theme-background)); + --j-font-family: '{{ typography }}'; } @@ -22,7 +23,20 @@ /** * TODO: Investigate or propose an RFC to allow style tags inside SFCs */ +import { computed } from 'vue'; import { useLoading } from '@/composables/use-loading'; +import { DEFAULT_TYPOGRAPHY } from '@/store'; +import { clientSettings } from '@/store/client-settings'; const { isLoading } = useLoading(); + +const typography = computed(() => { + if (clientSettings.typography === 'system') { + return 'system-ui'; + } else if (clientSettings.typography === 'default') { + return DEFAULT_TYPOGRAPHY; + } else { + return clientSettings.typography; + } +}); diff --git a/frontend/src/composables/use-font.ts b/frontend/src/composables/use-font.ts deleted file mode 100644 index 2a483a97..00000000 --- a/frontend/src/composables/use-font.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { ref } from 'vue'; - -const currentFont = ref(''); - -/** - * Updates the currentFont reactive reference based on the font family of the document body. - * It retrieves the computed font style of the body and sets the currentFont to the primary font. - */ -const updateFont = () => { - const body = document.body; - const style = window.getComputedStyle(body); - - // Remove fallback fonts and quotes around the font name - const fontFamily = style.fontFamily.split(', ')[0].replaceAll(/["']/g, ''); - - currentFont.value = fontFamily; -}; - -// Event listener to update the font when the font loading is done -document.fonts.addEventListener('loadingdone', () => { - updateFont(); -}); - -// Initial font retrieval -updateFont(); - -/** - * Provides a reactive reference for the current font. - * - * @returns An object containing the `currentFont` reactive reference. - */ -export function useFont() { - return { currentFont }; -} diff --git a/frontend/src/pages/settings/subtitles.vue b/frontend/src/pages/settings/subtitles.vue index 405c40a4..adca8765 100644 --- a/frontend/src/pages/settings/subtitles.vue +++ b/frontend/src/pages/settings/subtitles.vue @@ -1,48 +1,45 @@ diff --git a/frontend/src/store/client-settings/index.ts b/frontend/src/store/client-settings/index.ts index 18ed744f..dd7a23d8 100644 --- a/frontend/src/store/client-settings/index.ts +++ b/frontend/src/store/client-settings/index.ts @@ -8,6 +8,7 @@ import { remote } from '@/plugins/remote'; import { vuetify } from '@/plugins/vuetify'; import { sealed } from '@/utils/validation'; import { SyncedStore } from '@/store/super/synced-store'; +import type { TypographyChoices } from '@/store'; /** * == INTERFACES AND TYPES == @@ -15,6 +16,7 @@ import { SyncedStore } from '@/store/super/synced-store'; */ export interface ClientSettingsState { + typography: TypographyChoices; darkMode: 'auto' | boolean; locale: string; } @@ -44,6 +46,14 @@ class ClientSettingsStore extends SyncedStore { return this._state.locale; } + public get typography() { + return this._state.typography; + } + + public set typography(newVal: ClientSettingsState['typography']) { + this._state.typography = newVal; + } + public set darkMode(newVal: 'auto' | boolean) { this._state.darkMode = newVal; } @@ -72,6 +82,7 @@ class ClientSettingsStore extends SyncedStore { public constructor() { super('clientSettings', { + typography: 'default', darkMode: 'auto', locale: 'auto' }, 'localStorage'); diff --git a/frontend/src/store/client-settings/subtitle-settings.ts b/frontend/src/store/client-settings/subtitle-settings.ts index 9b9887d2..5951ae4e 100644 --- a/frontend/src/store/client-settings/subtitle-settings.ts +++ b/frontend/src/store/client-settings/subtitle-settings.ts @@ -2,13 +2,22 @@ import { watch } from 'vue'; import { remote } from '@/plugins/remote'; import { sealed } from '@/utils/validation'; import { SyncedStore } from '@/store/super/synced-store'; +import type { TypographyChoices } from '@/store'; /** * == INTERFACES AND TYPES == */ export interface SubtitleSettingsState { - fontFamily: string; + /** + * default: Default application typography. + * + * system: System typography + * + * auto: Selects the current selected typography for the application + * @default: auto + */ + fontFamily: 'auto' | TypographyChoices; fontSize: number; positionFromBottom: number; backdrop: boolean; diff --git a/frontend/src/store/index.ts b/frontend/src/store/index.ts index a371fd46..b3134723 100644 --- a/frontend/src/store/index.ts +++ b/frontend/src/store/index.ts @@ -10,6 +10,16 @@ import { isNil } from '@/utils/validation'; * efficient to reuse those, both in components and TS files. */ +export const DEFAULT_TYPOGRAPHY = 'Figtree Variable'; +/** + * Type for the different typography choices across the application + * + * default: Default application typography. + * + * system: System typography + */ +export type TypographyChoices = 'default' | 'system' | (string & {}); + /** * == BLURHASH DEFAULTS == * By default, 20x20 pixels with a punch of 1 is returned. diff --git a/frontend/src/store/super/synced-store.ts b/frontend/src/store/super/synced-store.ts index 5602c956..5559588b 100644 --- a/frontend/src/store/super/synced-store.ts +++ b/frontend/src/store/super/synced-store.ts @@ -110,21 +110,19 @@ export abstract class SyncedStore extends CommonStore { try { const data = await this._fetchState(); - if (data) { - for (const watcher of this._pausableWatchers) { - watcher.pause(); - } + for (const watcher of this._pausableWatchers) { + watcher.pause(); + } - const newState = { - ...toRaw(this._state), - ...data - }; + const newState = { + ...toRaw(this._state), + ...data + }; - Object.assign(this._state, newState); + Object.assign(this._state, newState); - for (const watcher of this._pausableWatchers) { - watcher.resume(); - } + for (const watcher of this._pausableWatchers) { + watcher.resume(); } } catch { useSnackbar(i18n.t('failedSyncingUserSettings'), 'error'); @@ -144,12 +142,12 @@ export abstract class SyncedStore extends CommonStore { if (keys) { for (const key of keys) { this._pausableWatchers.push( - watchPausable(() => this._state[key], this._updateState) + watchPausable(() => this._state[key], this._updateState, { deep: true }) ); } } else { this._pausableWatchers.push( - watchPausable(this._state, this._updateState) + watchPausable(this._state, this._updateState, { deep: true }) ); }