feat(FontSelector): refactor font selector logic and move to component

This commit is contained in:
Sean McBroom 2024-07-18 15:33:19 -05:00 committed by Fernando Fernández
parent 84dcbe2260
commit ac424696e8
6 changed files with 117 additions and 83 deletions

View File

@ -104,6 +104,7 @@
"dlnaSettingsDescription": "Configure DLNA settings and profile",
"editMetadata": "Edit metadata",
"editPerson": "Edit person",
"enablePermission": "Enable Permission",
"enableUPNP": "Enable UPnP",
"endsAt": "Ends at {time}",
"eps": "EPs",
@ -145,7 +146,8 @@
"lastActive": "Last active",
"lastActivityDate": "Last seen {value}",
"latestLibrary": "Latest {libraryName}",
"lazyLoading": "Showing {value} items. Loading more…",
"lazyLoading": "Showing {value} items. Loading more...",
"learnMore": "Learn More",
"libraries": "Libraries",
"librariesSettingsDescription": "Manage libraries and their metadata",
"libraryAccess": "Library access",
@ -155,6 +157,7 @@
"liked": "Liked",
"liveTv": "Live TV & DVR",
"liveTvSettingsDescription": "Manage TV tuners, guide data providers and DVR settings",
"localFontsPermissionWarning": "Access to the local fonts permission is required to select a font.",
"login": "Login",
"loginAs": "Login as {name}",
"logo": "Logo",
@ -279,6 +282,7 @@
"pushToBottom": "Move to the end",
"pushToTop": "Move to the beginning",
"quality": "Quality",
"queryLocalFontsNotSupportedWarning": "Local fonts are currently not supported by your browser.",
"queue": "Queue",
"queueItems": "{items} tracks",
"rating": "Rating",

View File

@ -0,0 +1,74 @@
<template>
<VAlert
v-if="!isQueryLocalFontsSupported"
class="uno-mb-5"
color="warning"
icon="$warning">
{{ $t('queryLocalFontsNotSupportedWarning') }}
<br>
<a
class="uno-font-bold"
href="https://caniuse.com/mdn-api_window_querylocalfonts"
target="_blank"
rel="noopener">
{{ $t('learnMore') }}
</a>
</VAlert>
<VAlert
v-if="isQueryLocalFontsSupported && !fontAccess"
class="uno-mb-5"
color="warning"
icon="$warning">
{{ $t('localFontsPermissionWarning') }}
<br>
<a
class="uno-font-bold"
href="https://support.google.com/chrome/answer/114662?hl=en&co=GENIE.Platform=Desktop"
target="_blank"
rel="noopener">
{{ $t('enablePermission') }}
</a>
</VAlert>
<VSelect
v-model="model"
:label="label"
:items="fontList"
:disabled="!isQueryLocalFontsSupported || !fontAccess" />
</template>
<script setup lang="ts">
import { usePermission, useSupported } from '@vueuse/core';
import { ref, computed, watchEffect } from 'vue';
import { useI18n } from 'vue-i18n';
defineProps<{
label?: string;
}>();
const { t } = useI18n();
const model = defineModel<string | undefined>();
const fontList = ref<string[]>([]);
const fontPermission = usePermission('local-fonts');
const fontAccess = computed(() => fontPermission.value == 'granted');
const isQueryLocalFontsSupported = useSupported(() => 'queryLocalFonts' in window);
watchEffect(async () => {
if (isQueryLocalFontsSupported.value && fontAccess.value) {
const localFonts = await window.queryLocalFonts();
const uniqueFonts: string[] = [];
for (const font of localFonts) {
if (!uniqueFonts.includes(font.family)) {
uniqueFonts.push(font.family);
}
}
fontList.value = uniqueFonts;
}
});
</script>

View File

@ -1,80 +1,52 @@
<template>
<SettingsPage page-title="subtitles">
<SettingsPage>
<template #title>
{{ t('subtitles') }}
</template>
<template #content>
<VCol
md="6"
class="pt-0 pb-4">
<VSelect
<FontSelector
v-model="clientSettings.subtitleAppearance.fontFamily"
:label="$t('subtitleFont')"
:items="availableSubtitleFonts"/>
:label="$t('subtitleFont')" />
<VSlider
v-model="clientSettings.subtitleAppearance.fontSize"
:label="$t('fontSize')"
:min="1"
:max="4.5"
:step="0.1"/>
:step="0.1" />
<VSlider
v-model="clientSettings.subtitleAppearance.positionFromBottom"
:label="$t('positionFromBottom')"
:min="0"
:max="30"
:step="1"/>
:step="1" />
<VCheckbox
v-model="clientSettings.subtitleAppearance.backdrop"
:label="$t('backdrop')"/>
:label="$t('backdrop')" />
<VCheckbox
v-model="clientSettings.subtitleAppearance.stroke"
:label="$t('stroke')"/>
:label="$t('stroke')" />
<SubtitleTrack :previewText="$t('subtitlePreviewText')"/>
<SubtitleTrack :preview-text="$t('subtitlePreviewText')" />
</VCol>
</template>
</SettingsPage>
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { useI18n } from 'vue-i18n';
import { useRoute } from 'vue-router/auto';
import { clientSettings } from '@/store/client-settings';
import { SUBTITLE_FONT_FAMILIES } from '@/utils/subtitles';
const { t } = useI18n();
const route = useRoute();
route.meta.title = t('subtitles');
const availableSubtitleFonts = ref<string[]>([]);
// Load subtitle fonts available to the client
const loadAvailableFonts = async () => {
const checkFontAvailability = async (font: string) => {
// Default font
if (font == SUBTITLE_FONT_FAMILIES[0]) {
return font;
}
try {
const fontFace = new FontFace(font, `local(${font})`);
const loaded = await fontFace.load();
if (loaded.status !== 'error') {
return font;
}
} catch {}
};
const fontChecks = SUBTITLE_FONT_FAMILIES.map(checkFontAvailability);
const fonts = await Promise.all(fontChecks);
const validFonts = fonts.filter(font => font !== undefined);
availableSubtitleFonts.value = validFonts;
};
await loadAvailableFonts();
</script>

View File

@ -8,19 +8,17 @@ import { remote } from '@/plugins/remote';
import { vuetify } from '@/plugins/vuetify';
import { sealed } from '@/utils/validation';
import { SyncedStore } from '@/store/super/synced-store';
import { FALLBACK_SUBTITLE_FONT, SUBTITLE_FONT_FAMILIES } from '@/utils/subtitles';
/**
* == INTERFACES AND TYPES ==
* Casted typings for the CustomPrefs property of DisplayPreferencesDto
*/
export type subtitleFontFamily = typeof SUBTITLE_FONT_FAMILIES[number];
export interface ClientSettingsState {
darkMode: 'auto' | boolean;
locale: string;
subtitleAppearance: {
fontFamily: subtitleFontFamily;
fontFamily: string;
fontSize: number;
positionFromBottom: number;
backdrop: boolean;
@ -92,7 +90,7 @@ class ClientSettingsStore extends SyncedStore<ClientSettingsState> {
darkMode: 'auto',
locale: 'auto',
subtitleAppearance: {
fontFamily: SUBTITLE_FONT_FAMILIES[0],
fontFamily: 'FigTree Variable',
fontSize: 1.5,
positionFromBottom: 10,
backdrop: true,

View File

@ -17,22 +17,6 @@ export interface ParsedSubtitleTrack {
type TagMap = Record<string, string>;
export const SUBTITLE_FONT_FAMILIES = [
'Figtree Variable',
'Trebuchet MS',
'Verdana',
'Sans Serif MS',
'Arial',
'Courier New',
'Times New Roman',
'Old English Text MT',
'Century Gothic',
'Helvetica',
'Garamond'
] as const;
export const FALLBACK_SUBTITLE_FONT = 'sans-serif, system-ui';
/**
* Parse time string used in subtitle files to seconds
*/

View File

@ -27,6 +27,7 @@ declare module 'vue' {
DateInput: typeof import('./../../src/components/Item/Metadata/DateInput.vue')['default']
DraggableQueue: typeof import('./../../src/components/Playback/DraggableQueue.vue')['default']
FilterButton: typeof import('./../../src/components/Buttons/FilterButton.vue')['default']
FontSelector: typeof import('./../../src/components/Selectors/FontSelector.vue')['default']
GenericDialog: typeof import('./../../src/components/Dialogs/GenericDialog.vue')['default']
GenericItemCard: typeof import('./../../src/components/Item/Card/GenericItemCard.vue')['default']
IDashiconsAlbum: typeof import('~icons/dashicons/album')['default']
@ -156,6 +157,7 @@ declare module 'vue' {
UserButton: typeof import('./../../src/components/Layout/AppBar/Buttons/UserButton.vue')['default']
UserCard: typeof import('./../../src/components/Users/UserCard.vue')['default']
UserImage: typeof import('./../../src/components/Layout/Images/UserImage.vue')['default']
VAlert: typeof import('vuetify/components')['VAlert']
VApp: typeof import('vuetify/components')['VApp']
VAppBar: typeof import('vuetify/components')['VAppBar']
VAppBarNavIcon: typeof import('vuetify/components')['VAppBarNavIcon']