Massively simplify and improve font input component

appearance-tab
Henry Jameson 3 months ago
parent d5d37849ea
commit 925fd863fe

@ -1,4 +1,3 @@
import { set, clone } from 'lodash'
import Select from '../select/select.vue' import Select from '../select/select.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue' import Checkbox from 'src/components/checkbox/checkbox.vue'
import Popover from 'src/components/popover/popover.vue' import Popover from 'src/components/popover/popover.vue'
@ -16,8 +15,6 @@ library.add(
faFont faFont
) )
const PRESET_FONTS = new Set(['serif', 'sans-serif', 'monospace', 'inherit'])
export default { export default {
components: { components: {
Select, Select,
@ -27,94 +24,36 @@ export default {
props: [ props: [
'name', 'label', 'modelValue', 'fallback', 'options', 'no-inherit' 'name', 'label', 'modelValue', 'fallback', 'options', 'no-inherit'
], ],
mounted () {
this.$store.dispatch('queryLocalFonts')
},
emits: ['update:modelValue'], emits: ['update:modelValue'],
data () { data () {
return { return {
manualEntry: true, manualEntry: true,
localValue: clone(this.modelValue),
familyCustomLocal: null,
availableOptions: [ availableOptions: [
this.noInherit ? '' : 'inherit', this.noInherit ? '' : 'inherit',
'serif', 'serif',
'sans-serif', 'sans-serif',
'monospace', 'monospace',
'local',
...(this.options || []) ...(this.options || [])
].filter(_ => _) ].filter(_ => _)
} }
}, },
beforeUpdate () {
this.localValue = clone(this.modelValue)
if (this.familyCustomLocal === null && !this.isInvalidFamily(this.modelValue?.family)) {
this.familyCustomLocal = this.modelValue?.family
}
},
methods: { methods: {
lookupLocalFonts () {
if (!this.fontsList) {
this.$store.dispatch('queryLocalFonts')
}
this.toggleManualEntry()
},
isInvalidFamily (value) {
return PRESET_FONTS.has(value) || (value === '')
},
toggleManualEntry () { toggleManualEntry () {
this.manualEntry = !this.manualEntry this.manualEntry = !this.manualEntry
} }
}, },
computed: { computed: {
present () { present () {
return typeof this.localValue !== 'undefined' return typeof this.modelValue !== 'undefined'
},
defaultValue () {
return this.localValue || this.fallback || {}
},
fontsListCapable () {
return this.$store.state.interface.browserSupport.localFonts
},
fontsList () {
return this.$store.state.interface.localFonts
}, },
family: { localFontsList () {
get () { return this.$store.state.interface.localFonts?.values()
return this.defaultValue.family
}, },
set (v) { localFontsSize () {
this.familyCustomLocal = '' return this.$store.state.interface.localFonts?.size
set(this.localValue, 'family', v)
this.$emit('update:modelValue', this.localValue)
}
},
familyCustom: {
get () {
return this.familyCustomLocal
},
set (v) {
this.familyCustomLocal = v
if (!this.isInvalidFamily(v)) {
set(this.localValue, 'family', v)
this.$emit('update:modelValue', this.localValue)
}
}
},
invalidCustom () {
return this.isInvalidFamily(this.familyCustomLocal)
},
isCustom () {
return !PRESET_FONTS.has(this.defaultValue.family)
},
preset: {
get () {
if (PRESET_FONTS.has(this.family)) {
return this.family
} else {
return 'local'
}
},
set (v) {
this.family = v === 'local' ? '' : v
}
} }
} }
} }

@ -10,21 +10,6 @@
> >
{{ label }} {{ label }}
</label> </label>
<p>
<Select
:id="name + '-font-switcher'"
v-model="preset"
:disabled="!present"
class="font-switcher"
>
<option
v-for="option in availableOptions"
:key="option"
:value="option"
>
{{ $t('settings.style.themes3.font.' + option) }}
</option>
</Select>
{{ ' ' }} {{ ' ' }}
<Checkbox <Checkbox
v-if="typeof fallback !== 'undefined'" v-if="typeof fallback !== 'undefined'"
@ -34,18 +19,9 @@
> >
{{ $t('settings.style.themes3.define') }} {{ $t('settings.style.themes3.define') }}
</Checkbox> </Checkbox>
</p> <p v-if="modelValue?.family">
<p v-if="isCustom">
<label
v-if="fontsList !== null && !manualEntry"
:id="name + '-label'"
:for="preset === 'custom' ? name : name + '-font-switcher'"
class="label"
>
{{ $t('settings.style.themes3.font.select') }}
</label>
<label <label
v-else v-if="manualEntry"
:id="name + '-label'" :id="name + '-label'"
:for="preset === 'custom' ? name : name + '-font-switcher'" :for="preset === 'custom' ? name : name + '-font-switcher'"
class="label" class="label"
@ -59,12 +35,22 @@
</template> </template>
</i18n-t> </i18n-t>
</label> </label>
<label
v-else
:id="name + '-label'"
:for="preset === 'custom' ? name : name + '-font-switcher'"
class="label"
>
{{ $t('settings.style.themes3.font.select') }}
</label>
{{ ' ' }} {{ ' ' }}
<span class="btn-group"> <span
v-if="manualEntry"
class="btn-group"
>
<button <button
v-if="fontsListCapable && (fontsList === null || manualEntry)"
class="btn button-default" class="btn button-default"
@click="lookupLocalFonts" @click="toggleManualEntry"
:title="$t('settings.style.themes3.font.lookup_local_fonts')" :title="$t('settings.style.themes3.font.lookup_local_fonts')"
> >
<FAIcon <FAIcon
@ -73,16 +59,18 @@
/> />
</button> </button>
<input <input
v-if="fontsLists === null || manualEntry"
:id="name" :id="name"
v-model="familyCustom" :model-value="modelValue.family"
class="input custom-font" class="input custom-font"
type="text" type="text"
@update:modelValue="$emit('update:modelValue', { ...(modelValue || {}), family: $event.target.value })"
> >
</span> </span>
<span class="btn-group"> <span
v-else
class="btn-group"
>
<button <button
v-if="fontsList !== null && !manualEntry"
class="btn button-default" class="btn button-default"
@click="toggleManualEntry" @click="toggleManualEntry"
:title="$t('settings.style.themes3.font.enter_manually')" :title="$t('settings.style.themes3.font.enter_manually')"
@ -93,39 +81,48 @@
/> />
</button> </button>
<Select <Select
v-if="fontsList !== null && !manualEntry"
:id="name + '-local-font-switcher'" :id="name + '-local-font-switcher'"
v-model="familyCustom" :model-value="modelValue.family"
class="custom-font" class="custom-font"
@update:modelValue="$emit('update:modelValue', { ...(modelValue || {}), family: $event.target.value })"
>
<optgroup
:label="$t('settings.style.themes3.font.group-builtin')"
> >
<option <option
v-for="option in fontsList.values()" v-for="option in availableOptions"
:key="option"
:value="option"
:style="{ fontFamily: option === 'inherit' ? null : option }"
>
{{ $t('settings.style.themes3.font.builtin.' + option) }}
</option>
</optgroup>
<optgroup
v-if="localFontsSize > 0"
:label="$t('settings.style.themes3.font.group-local')"
>
<option
v-for="option in localFontsList"
:key="option" :key="option"
:value="option" :value="option"
:style="{ fontFamily: option }" :style="{ fontFamily: option }"
> >
{{ option }} {{ option }}
</option> </option>
</Select> </optgroup>
</span> <optgroup
<span v-else
v-if="invalidCustom" :label="$t('settings.style.themes3.font.group-local')"
class="InvalidIndicator"
>
<Popover
trigger="hover"
:trigger-attrs="{ 'aria-label': $t('settings.style.themes3.font.invalid_custom_reserved') }"
> >
<template #trigger> <option disabled>
&nbsp; {{ $t('settings.style.themes3.font.local-unavailable1') }}
<FAIcon icon="exclamation-triangle" /> </option>
</template> <option disabled>
<template #content> {{ $t('settings.style.themes3.font.local-unavailable2') }}
<div class="invalid-tooltip"> </option>
{{ $t('settings.style.themes3.font.invalid_custom_reserved') }} </optgroup>
</div> </Select>
</template>
</Popover>
</span> </span>
</p> </p>
</div> </div>

@ -748,17 +748,21 @@
"themes3": { "themes3": {
"define": "Override", "define": "Override",
"font": { "font": {
"local": "Local font (must be installed on computer)", "group-builtin": "Browser default fonts",
"serif": "Serif (browser default)", "builtin" : {
"sans-serif": "Sans-serif (browser default)", "serif": "Serif",
"monospace": "Monospace (browser default)", "sans-serif": "Sans-serif",
"inherit": "Same as parent component", "monospace": "Monospace",
"invalid_custom_reserved": "Empty or reserved font name, it will not be saved as custom font - use dropdown instead", "inherit": "Unchanged"
},
"group-local": "Locally installed fonts",
"local-unavailable1": "List of locally installed fonts unavailalbe",
"local-unavailable2": "Use manual entry to specify custom font",
"font_list_unavailable": "Couldn't get locally installed fonts: {error}", "font_list_unavailable": "Couldn't get locally installed fonts: {error}",
"lookup_local_fonts": "Load list of fonts installed on this computer", "lookup_local_fonts": "Load list of fonts installed on this computer",
"enter_manually": "Enter font name family manually", "enter_manually": "Enter font name family manually",
"entry": "Font's {fontFamily}", "entry": "Enter {fontFamily}",
"select": "Select local font" "select": "Select font"
} }
}, },
"switcher": { "switcher": {

@ -108,7 +108,6 @@ const interfaceMod = {
state.lastTimeline = value state.lastTimeline = value
}, },
setFontsList (state, value) { setFontsList (state, value) {
console.log(value)
state.localFonts = new Set(value.map(font => font.family)) state.localFonts = new Set(value.map(font => font.family))
} }
}, },
@ -184,10 +183,16 @@ const interfaceMod = {
commit('setLayoutType', wideLayout ? 'wide' : normalOrMobile) commit('setLayoutType', wideLayout ? 'wide' : normalOrMobile)
} }
}, },
queryLocalFonts ({ commit, dispatch }) { queryLocalFonts ({ commit, dispatch, state }) {
if (state.localFonts !== null) return
commit('setFontsList', [])
if (!state.browserSupport.localFonts) {
return
}
window window
.queryLocalFonts() .queryLocalFonts()
.then((fonts) => { .then((fonts) => {
console.log(fonts)
commit('setFontsList', fonts) commit('setFontsList', fonts)
}) })
.catch((e) => { .catch((e) => {

Loading…
Cancel
Save