Merge branch 'appearance-tab' into shigusegubu-themes3

This commit is contained in:
Henry Jameson 2024-06-26 18:14:05 +03:00
commit 29fae18b49
6 changed files with 268 additions and 87 deletions

View file

@ -375,7 +375,6 @@ nav {
user-select: none;
color: var(--text);
border: none;
border-radius: var(--roundness);
cursor: pointer;
background-color: var(--background);
box-shadow: var(--shadow);
@ -511,7 +510,6 @@ textarea {
--_padding: 0.5em;
border: none;
border-radius: var(--roundness);
background-color: var(--background);
color: var(--text);
box-shadow: var(--shadow);
@ -617,6 +615,17 @@ textarea {
}
}
.input,
.button-default {
--_roundness-left: var(--roundness);
--_roundness-right: var(--roundness);
border-top-left-radius: var(--_roundness-left);
border-bottom-left-radius: var(--_roundness-left);
border-top-right-radius: var(--_roundness-right);
border-bottom-right-radius: var(--_roundness-right);
}
// Textareas should have stock line-height + vertical padding instead of huge line-height
textarea.input {
padding: var(--_padding);
@ -662,22 +671,20 @@ option {
display: inline-flex;
vertical-align: middle;
button,
.button-dropdown {
> * {
--_roundness-left: 0;
--_roundness-right: 0;
position: relative;
flex: 1 1 auto;
}
&:not(:last-child),
&:not(:last-child) .button-default {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
> *:first-child {
--_roundness-left: var(--roundness);
}
&:not(:first-child),
&:not(:first-child) .button-default {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
> *:last-child {
--_roundness-right: var(--roundness);
}
}

View file

@ -1,9 +1,28 @@
import { set } from 'lodash'
import { set, clone } from 'lodash'
import Select from '../select/select.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import Popover from 'src/components/popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faExclamationTriangle,
faKeyboard,
faFont
} from '@fortawesome/free-solid-svg-icons'
library.add(
faExclamationTriangle,
faKeyboard,
faFont
)
const PRESET_FONTS = new Set(['serif', 'sans-serif', 'monospace', 'inherit'])
export default {
components: {
Select
Select,
Checkbox,
Popover
},
props: [
'name', 'label', 'modelValue', 'fallback', 'options', 'no-inherit'
@ -11,52 +30,90 @@ export default {
emits: ['update:modelValue'],
data () {
return {
lValue: this.modelValue,
manualEntry: true,
localValue: clone(this.modelValue),
familyCustomLocal: null,
availableOptions: [
this.noInherit ? '' : 'inherit',
'custom',
...(this.options || []),
'serif',
'sans-serif',
'monospace',
'sans-serif'
'local',
...(this.options || [])
].filter(_ => _)
}
},
beforeUpdate () {
this.lValue = this.modelValue
this.localValue = clone(this.modelValue)
if (this.familyCustomLocal === null && !this.isInvalidFamily(this.modelValue?.family)) {
this.familyCustomLocal = this.modelValue?.family
}
},
methods: {
lookupLocalFonts () {
if (!this.fontsList) {
this.$store.dispatch('queryLocalFonts')
}
this.toggleManualEntry()
},
isInvalidFamily (value) {
return PRESET_FONTS.has(value) || (value === '')
},
toggleManualEntry () {
this.manualEntry = !this.manualEntry
}
},
computed: {
present () {
return typeof this.lValue !== 'undefined'
return typeof this.localValue !== 'undefined'
},
dValue () {
return this.lValue || this.fallback || {}
defaultValue () {
return this.localValue || this.fallback || {}
},
fontsListCapable () {
return this.$store.state.interface.browserSupport.localFonts
},
fontsList () {
return this.$store.state.interface.localFonts
},
family: {
get () {
return this.dValue.family
return this.defaultValue.family
},
set (v) {
set(this.lValue, 'family', v)
this.$emit('update:modelValue', this.lValue)
this.familyCustomLocal = ''
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 this.preset === 'custom'
return !PRESET_FONTS.has(this.defaultValue.family)
},
preset: {
get () {
if (this.family === 'serif' ||
this.family === 'sans-serif' ||
this.family === 'monospace' ||
this.family === 'inherit') {
if (PRESET_FONTS.has(this.family)) {
return this.family
} else {
return 'custom'
return 'local'
}
},
set (v) {
this.family = v === 'custom' ? '' : v
this.family = v === 'local' ? '' : v
}
}
}

View file

@ -1,6 +1,6 @@
<template>
<div
class="font-control style-control"
class="font-control"
:class="{ custom: isCustom }"
>
<label
@ -10,43 +10,124 @@
>
{{ label }}
</label>
<input
v-if="typeof fallback !== 'undefined'"
:id="name + '-o'"
:aria-labelledby="name + '-label'"
class="input -checkbox opt exlcude-disabled visible-for-screenreader-only"
type="checkbox"
:checked="present"
@change="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
>
<label
v-if="typeof fallback !== 'undefined'"
class="opt-l"
:for="name + '-o'"
:aria-hidden="true"
/>
{{ ' ' }}
<Select
:id="name + '-font-switcher'"
v-model="preset"
:disabled="!present"
class="font-switcher"
>
<option
v-for="option in availableOptions"
:key="option"
:value="option"
<p>
<Select
:id="name + '-font-switcher'"
v-model="preset"
:disabled="!present"
class="font-switcher"
>
{{ option === 'custom' ? $t('settings.style.fonts.custom') : option }}
</option>
</Select>
<input
v-if="isCustom"
:id="name"
v-model="family"
class="input custom-font"
type="text"
>
<option
v-for="option in availableOptions"
:key="option"
:value="option"
>
{{ $t('settings.style.themes3.font.' + option) }}
</option>
</Select>
{{ ' ' }}
<Checkbox
v-if="typeof fallback !== 'undefined'"
:id="name + '-o'"
:modelValue="present"
@change="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
>
{{ $t('settings.style.themes3.define') }}
</Checkbox>
</p>
<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
v-else
:id="name + '-label'"
:for="preset === 'custom' ? name : name + '-font-switcher'"
class="label"
>
<i18n-t
keypath="settings.style.themes3.font.entry"
tag="span"
>
<template #fontFamily>
<code>font-family</code>
</template>
</i18n-t>
</label>
{{ ' ' }}
<span class="btn-group">
<button
v-if="fontsListCapable && (fontsList === null || manualEntry)"
class="btn button-default"
@click="lookupLocalFonts"
:title="$t('settings.style.themes3.font.lookup_local_fonts')"
>
<FAIcon
fixed-width
icon="font"
/>
</button>
<input
v-if="fontsLists === null || manualEntry"
:id="name"
v-model="familyCustom"
class="input custom-font"
type="text"
>
</span>
<span class="btn-group">
<button
v-if="fontsList !== null && !manualEntry"
class="btn button-default"
@click="toggleManualEntry"
:title="$t('settings.style.themes3.font.enter_manually')"
>
<FAIcon
fixed-width
icon="keyboard"
/>
</button>
<Select
v-if="fontsList !== null && !manualEntry"
:id="name + '-local-font-switcher'"
v-model="familyCustom"
class="custom-font"
>
<option
v-for="option in fontsList.values()"
:key="option"
:value="option"
:style="{ fontFamily: option }"
>
{{ option }}
</option>
</Select>
</span>
<span
v-if="invalidCustom"
class="InvalidIndicator"
>
<Popover
trigger="hover"
:trigger-attrs="{ 'aria-label': $t('settings.style.themes3.font.invalid_custom_reserved') }"
>
<template #trigger>
&nbsp;
<FAIcon icon="exclamation-triangle" />
</template>
<template #content>
<div class="invalid-tooltip">
{{ $t('settings.style.themes3.font.invalid_custom_reserved') }}
</div>
</template>
</Popover>
</span>
</p>
</div>
</template>
@ -54,21 +135,15 @@
<style lang="scss">
.font-control {
input.custom-font {
min-width: 10em;
}
&.custom {
/* TODO Should make proper joiners... */
.font-switcher {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.custom-font {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
.custom-font {
min-width: 20em;
max-width: 20em;
}
}
.invalid-tooltip {
margin: 0.5em 1em;
min-width: 10em;
text-align: center;
}
</style>

View file

@ -10,6 +10,10 @@
margin-right: 0.25em;
}
.btn-group .btn {
margin: 0;
}
.style-control {
display: flex;
align-items: baseline;

View file

@ -745,6 +745,22 @@
"enable_web_push_always_show_tip": "Some browsers (Chromium, Chrome) require that push messages always result in a notification, otherwise generic 'Website was updated in background' is shown, enable this to prevent this notification from showing, as Chrome seem to hide push notifications if tab is in focus. Can result in showing duplicate notifications on other browsers.",
"more_settings": "More settings",
"style": {
"themes3": {
"define": "Override",
"font": {
"local": "Local font (must be installed on computer)",
"serif": "Serif (browser default)",
"sans-serif": "Sans-serif (browser default)",
"monospace": "Monospace (browser default)",
"inherit": "Same as parent component",
"invalid_custom_reserved": "Empty or reserved font name, it will not be saved as custom font - use dropdown instead",
"font_list_unavailable": "Couldn't get locally installed fonts: {error}",
"lookup_local_fonts": "Load list of fonts installed on this computer",
"enter_manually": "Enter font name family manually",
"entry": "Font's {fontFamily}",
"select": "Select local font"
}
},
"switcher": {
"keep_color": "Keep colors",
"keep_shadows": "Keep shadows",

View file

@ -1,4 +1,5 @@
const defaultState = {
localFonts: null,
themeApplied: false,
temporaryChangesTimeoutId: null, // used for temporary options that revert after a timeout
temporaryChangesConfirm: () => {}, // used for applying temporary options
@ -17,7 +18,8 @@ const defaultState = {
cssFilter: window.CSS && window.CSS.supports && (
window.CSS.supports('filter', 'drop-shadow(0 0)') ||
window.CSS.supports('-webkit-filter', 'drop-shadow(0 0)')
)
),
localFonts: typeof window.queryLocalFonts === 'function'
},
layoutType: 'normal',
globalNotices: [],
@ -104,6 +106,10 @@ const interfaceMod = {
},
setLastTimeline (state, value) {
state.lastTimeline = value
},
setFontsList (state, value) {
console.log(value)
state.localFonts = new Set(value.map(font => font.family))
}
},
actions: {
@ -178,6 +184,22 @@ const interfaceMod = {
commit('setLayoutType', wideLayout ? 'wide' : normalOrMobile)
}
},
queryLocalFonts ({ commit, dispatch }) {
window
.queryLocalFonts()
.then((fonts) => {
commit('setFontsList', fonts)
})
.catch((e) => {
dispatch('pushGlobalNotice', {
messageKey: 'settings.style.themes3.font.font_list_unavailable',
messageArgs: {
error: e
},
level: 'error'
})
})
},
setLastTimeline ({ commit }, value) {
commit('setLastTimeline', value)
}