Merge branch 'appearance-tab' into shigusegubu-themes3
This commit is contained in:
commit
29fae18b49
6 changed files with 268 additions and 87 deletions
35
src/App.scss
35
src/App.scss
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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>
|
||||
|
||||
<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>
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
margin-right: 0.25em;
|
||||
}
|
||||
|
||||
.btn-group .btn {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.style-control {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue