initial font support

This commit is contained in:
Henry Jameson 2018-11-25 21:48:16 +03:00
parent e8536f3d95
commit 1a65895bfd
8 changed files with 251 additions and 32 deletions

View file

@ -34,6 +34,7 @@ h4 {
body { body {
font-family: sans-serif; font-family: sans-serif;
font-family: var(--interfaceFont, sans-serif);
font-size: 14px; font-size: 14px;
margin: 0; margin: 0;
color: $fallback--text; color: $fallback--text;
@ -62,6 +63,7 @@ button {
box-shadow: var(--buttonShadow); box-shadow: var(--buttonShadow);
font-size: 14px; font-size: 14px;
font-family: sans-serif; font-family: sans-serif;
font-family: var(--interfaceFont, sans-serif);
i[class*=icon-] { i[class*=icon-] {
color: $fallback--text; color: $fallback--text;
@ -111,6 +113,7 @@ input, textarea, .select {
color: $fallback--lightText; color: $fallback--lightText;
color: var(--inputText, $fallback--lightText); color: var(--inputText, $fallback--lightText);
font-family: sans-serif; font-family: sans-serif;
font-family: var(--inputFont, sans-serif);
font-size: 14px; font-size: 14px;
padding: 8px 7px; padding: 8px 7px;
box-sizing: border-box; box-sizing: border-box;

View file

@ -0,0 +1,93 @@
<template>
<div class="font-control style-control">
<label :for="preset === 'custom' ? name : name + '-font-switcher'" class="label">
{{label}}
</label>
<input
v-if="typeof fallback !== 'undefined'"
class="opt exlcude-disabled"
type="checkbox"
:id="name + '-o'"
:checked="present"
@input="$emit('input', typeof value === 'undefined' ? fallback : undefined)">
<label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label>
<label :for="name + '-font-switcher'" class="select" :disabled="!present">
<select
:disabled="!present"
v-model="preset"
class="font-switcher"
id="name + '-font-switcher'">
<option v-for="option in options" :value="option">
{{ option }}
</option>
</select>
<i class="icon-down-open"/>
</label>
<input
v-if="preset === 'custom'"
class="custom-font"
type="text"
id="name"
v-model="family">
</div>
</template>
<script>
import { set } from 'vue'
export default {
props: [
'name', 'label', 'value', 'fallback', 'options'
],
data () {
return {
lValue: this.value
}
},
beforeUpdate () {
this.lValue = this.value
},
computed: {
present () {
return typeof this.lValue !== 'undefined'
},
dValue () {
return this.lValue || this.fallback || {}
},
family: {
get () {
return this.dValue.family
},
set (v) {
set(this.lValue, 'family', v)
this.$emit('input', this.lValue)
}
},
preset: {
get () {
console.log(this.family)
if (this.family === 'serif' ||
this.family === 'sans-serif' ||
this.family === 'monospace' ||
this.family === 'inherit') {
return this.family
} else {
return 'custom'
}
},
set (v) {
this.family = v === 'custom' ? '' : v
}
}
}
}
</script>
<style lang="scss">
@import '../../_variables.scss';
.font-control {
input.custom-font {
min-width: 10em;
}
}
</style>

View file

@ -124,9 +124,9 @@
<OpacityInput <OpacityInput
v-model="selected.alpha" v-model="selected.alpha"
:disabled="!present"/> :disabled="!present"/>
<div> <p>
{{$t('settings.style.shadows.hint')}} {{$t('settings.style.shadows.hint')}}
</div> </p>
</div> </div>
</div> </div>
</template> </template>
@ -139,6 +139,7 @@
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
justify-content: center; justify-content: center;
margin-bottom: 1em;
.shadow-preview-container, .shadow-preview-container,
.shadow-tweak { .shadow-tweak {

View file

@ -1,10 +1,11 @@
import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js' import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js'
import { set, delete as del } from 'vue' import { set, delete as del } from 'vue'
import { generateColors, generateShadows, generateRadii, composePreset } from '../../services/style_setter/style_setter.js' import { generateColors, generateShadows, generateRadii, generateFonts, composePreset } from '../../services/style_setter/style_setter.js'
import ColorInput from '../color_input/color_input.vue' import ColorInput from '../color_input/color_input.vue'
import RangeInput from '../range_input/range_input.vue' import RangeInput from '../range_input/range_input.vue'
import OpacityInput from '../opacity_input/opacity_input.vue' import OpacityInput from '../opacity_input/opacity_input.vue'
import ShadowControl from '../shadow_control/shadow_control.vue' import ShadowControl from '../shadow_control/shadow_control.vue'
import FontControl from '../font_control/font_control.vue'
import ContrastRatio from '../contrast_ratio/contrast_ratio.vue' import ContrastRatio from '../contrast_ratio/contrast_ratio.vue'
import TabSwitcher from '../tab_switcher/tab_switcher.jsx' import TabSwitcher from '../tab_switcher/tab_switcher.jsx'
@ -30,6 +31,7 @@ export default {
previewShadows: {}, previewShadows: {},
previewColors: {}, previewColors: {},
previewRadii: {}, previewRadii: {},
previewFonts: {},
shadowsInvalid: true, shadowsInvalid: true,
colorsInvalid: true, colorsInvalid: true,
@ -38,6 +40,7 @@ export default {
keepShadows: false, keepShadows: false,
keepOpacity: false, keepOpacity: false,
keepRoundness: false, keepRoundness: false,
keepFonts: false,
textColorLocal: '', textColorLocal: '',
linkColorLocal: '', linkColorLocal: '',
@ -85,6 +88,7 @@ export default {
shadowSelected: undefined, shadowSelected: undefined,
shadowsLocal: {}, shadowsLocal: {},
fontsLocal: {},
btnRadiusLocal: '', btnRadiusLocal: '',
inputRadiusLocal: '', inputRadiusLocal: '',
@ -176,10 +180,11 @@ export default {
} }
}, },
preview () { preview () {
return composePreset(this.previewColors, this.previewRadii, this.previewShadows) return composePreset(this.previewColors, this.previewRadii, this.previewShadows, this.previewFonts)
}, },
previewTheme () { previewTheme () {
if (!this.preview.theme.colors) return { colors: {}, opacity: {}, radii: {}, shadows: {} } if (!this.preview.theme.colors) return { colors: {}, opacity: {}, radii: {}, shadows: {}, fonts: {} }
console.log(this.preview.theme)
return this.preview.theme return this.preview.theme
}, },
// This needs optimization maybe // This needs optimization maybe
@ -253,7 +258,11 @@ export default {
}, },
previewRules () { previewRules () {
if (!this.preview.rules) return '' if (!this.preview.rules) return ''
return [...Object.values(this.preview.rules), 'color: var(--text)'].join(';') return [
...Object.values(this.preview.rules),
'color: var(--text)',
'font-family: var(--interfaceFont, sans-serif)'
].join(';')
}, },
shadowsAvailable () { shadowsAvailable () {
return Object.keys(this.previewTheme.shadows).sort() return Object.keys(this.previewTheme.shadows).sort()
@ -291,6 +300,7 @@ export default {
RangeInput, RangeInput,
ContrastRatio, ContrastRatio,
ShadowControl, ShadowControl,
FontControl,
TabSwitcher TabSwitcher
}, },
methods: { methods: {
@ -300,6 +310,7 @@ export default {
_pleroma_theme_version: 2, _pleroma_theme_version: 2,
theme: { theme: {
shadows: this.shadowsLocal, shadows: this.shadowsLocal,
fonts: this.fontsLocal,
opacity: this.currentOpacity, opacity: this.currentOpacity,
colors: this.currentColors, colors: this.currentColors,
radii: this.currentRadii radii: this.currentRadii
@ -357,6 +368,7 @@ export default {
name: 'customTheme', name: 'customTheme',
value: { value: {
shadows: this.shadowsLocal, shadows: this.shadowsLocal,
fonts: this.fontsLocal,
opacity: this.currentOpacity, opacity: this.currentOpacity,
colors: this.currentColors, colors: this.currentColors,
radii: this.currentRadii radii: this.currentRadii
@ -398,6 +410,10 @@ export default {
this.shadowsLocal = {} this.shadowsLocal = {}
}, },
clearFonts () {
this.fontsLocal = {}
},
/** /**
* This applies stored theme data onto form. * This applies stored theme data onto form.
* @param {Object} input - input data * @param {Object} input - input data
@ -408,6 +424,7 @@ export default {
const radii = input.radii || input const radii = input.radii || input
const opacity = input.opacity const opacity = input.opacity
const shadows = input.shadows || {} const shadows = input.shadows || {}
const fonts = input.fonts || {}
if (version === 0) { if (version === 0) {
if (input.version) version = input.version if (input.version) version = input.version
@ -458,6 +475,11 @@ export default {
this.shadowSelected = this.shadowsAvailable[0] this.shadowSelected = this.shadowsAvailable[0]
} }
if (!this.keepFonts) {
this.clearFonts()
this.fontsLocal = fonts
}
if (opacity && !this.keepOpacity) { if (opacity && !this.keepOpacity) {
this.clearOpacity() this.clearOpacity()
Object.entries(opacity).forEach(([k, v]) => { Object.entries(opacity).forEach(([k, v]) => {
@ -477,14 +499,31 @@ export default {
console.warn(e) console.warn(e)
} }
}, },
shadowsLocal () { shadowsLocal: {
try { handler () {
this.previewShadows = generateShadows({ shadows: this.shadowsLocal }) try {
this.shadowsInvalid = false this.previewShadows = generateShadows({ shadows: this.shadowsLocal })
} catch (e) { this.shadowsInvalid = false
this.shadowsInvalid = true } catch (e) {
console.warn(e) this.shadowsInvalid = true
} console.warn(e)
}
},
deep: true
},
fontsLocal: {
handler () {
try {
this.previewFonts = generateFonts({ fonts: this.fontsLocal })
console.log('BENIS')
console.log(this.previewFonts)
this.fontsInvalid = false
} catch (e) {
this.fontsInvalid = true
console.warn(e)
}
},
deep: true
}, },
currentColors () { currentColors () {
try { try {

View file

@ -67,6 +67,7 @@
flex-wrap: wrap; flex-wrap: wrap;
} }
.fonts-container,
.reset-container, .reset-container,
.apply-container, .apply-container,
.radius-container, .radius-container,
@ -75,6 +76,7 @@
display: flex; display: flex;
} }
.fonts-container,
.radius-container { .radius-container {
flex-direction: column; flex-direction: column;
} }
@ -87,6 +89,7 @@
justify-content: space-between; justify-content: space-between;
} }
.fonts-container,
.color-container, .color-container,
.shadow-container, .shadow-container,
.radius-container, .radius-container,

View file

@ -75,7 +75,7 @@
<tab-switcher key="style-tweak"> <tab-switcher key="style-tweak">
<div :label="$t('settings.style.common_colors._tab_label')" class="color-container"> <div :label="$t('settings.style.common_colors._tab_label')" class="color-container">
<div class="tab-header"> <div class="tab-header">
<p>{{$t('settings.theme_help')}}</p> <p>{{$t('settings.theme_help')}}</p>
<button class="btn" @click="clearOpacity">{{$t('settings.style.switcher.clear_opacity')}}</button> <button class="btn" @click="clearOpacity">{{$t('settings.style.switcher.clear_opacity')}}</button>
<button class="btn" @click="clearV1">{{$t('settings.style.switcher.clear_all')}}</button> <button class="btn" @click="clearV1">{{$t('settings.style.switcher.clear_all')}}</button>
</div> </div>
@ -169,20 +169,18 @@
</div> </div>
</div> </div>
<div :label="$t('settings.style.radii._tab_label')" class="radius-container"> <div :label="$t('settings.style.radii._tab_label')" class="radius-container">
<div> <div class="tab-header">
<div class="tab-header"> <p>{{$t('settings.radii_help')}}</p>
<p>{{$t('settings.radii_help')}}</p> <button class="btn" @click="clearRoundness">{{$t('settings.style.switcher.clear_all')}}</button>
<button class="btn" @click="clearRoundness">{{$t('settings.style.switcher.clear_all')}}</button>
</div>
<RangeInput name="btnRadius" :label="$t('settings.btnRadius')" v-model="btnRadiusLocal" :fallback="previewTheme.radii.btn" max="16" hardMin="0"/>
<RangeInput name="inputRadius" :label="$t('settings.inputRadius')" v-model="inputRadiusLocal" :fallback="previewTheme.radii.input" max="9" hardMin="0"/>
<RangeInput name="checkboxRadius" :label="$t('settings.checkboxRadius')" v-model="checkboxRadiusLocal" :fallback="previewTheme.radii.checkbox" max="16" hardMin="0"/>
<RangeInput name="panelRadius" :label="$t('settings.panelRadius')" v-model="panelRadiusLocal" :fallback="previewTheme.radii.panel" max="50" hardMin="0"/>
<RangeInput name="avatarRadius" :label="$t('settings.avatarRadius')" v-model="avatarRadiusLocal" :fallback="previewTheme.radii.avatar" max="28" hardMin="0"/>
<RangeInput name="avatarAltRadius" :label="$t('settings.avatarAltRadius')" v-model="avatarAltRadiusLocal" :fallback="previewTheme.radii.avatarAlt" max="28" hardMin="0"/>
<RangeInput name="attachmentRadius" :label="$t('settings.attachmentRadius')" v-model="attachmentRadiusLocal" :fallback="previewTheme.radii.attachment" max="50" hardMin="0"/>
<RangeInput name="tooltipRadius" :label="$t('settings.tooltipRadius')" v-model="tooltipRadiusLocal" :fallback="previewTheme.radii.tooltip" max="50" hardMin="0"/>
</div> </div>
<RangeInput name="btnRadius" :label="$t('settings.btnRadius')" v-model="btnRadiusLocal" :fallback="previewTheme.radii.btn" max="16" hardMin="0"/>
<RangeInput name="inputRadius" :label="$t('settings.inputRadius')" v-model="inputRadiusLocal" :fallback="previewTheme.radii.input" max="9" hardMin="0"/>
<RangeInput name="checkboxRadius" :label="$t('settings.checkboxRadius')" v-model="checkboxRadiusLocal" :fallback="previewTheme.radii.checkbox" max="16" hardMin="0"/>
<RangeInput name="panelRadius" :label="$t('settings.panelRadius')" v-model="panelRadiusLocal" :fallback="previewTheme.radii.panel" max="50" hardMin="0"/>
<RangeInput name="avatarRadius" :label="$t('settings.avatarRadius')" v-model="avatarRadiusLocal" :fallback="previewTheme.radii.avatar" max="28" hardMin="0"/>
<RangeInput name="avatarAltRadius" :label="$t('settings.avatarAltRadius')" v-model="avatarAltRadiusLocal" :fallback="previewTheme.radii.avatarAlt" max="28" hardMin="0"/>
<RangeInput name="attachmentRadius" :label="$t('settings.attachmentRadius')" v-model="attachmentRadiusLocal" :fallback="previewTheme.radii.attachment" max="50" hardMin="0"/>
<RangeInput name="tooltipRadius" :label="$t('settings.tooltipRadius')" v-model="tooltipRadiusLocal" :fallback="previewTheme.radii.tooltip" max="50" hardMin="0"/>
</div> </div>
<div :label="$t('settings.style.shadows._tab_label')" class="shadow-container"> <div :label="$t('settings.style.shadows._tab_label')" class="shadow-container">
<div class="tab-header shadow-selector"> <div class="tab-header shadow-selector">
@ -214,6 +212,35 @@
</div> </div>
<shadow-control :ready="!!currentShadowFallback" :fallback="currentShadowFallback" v-model="currentShadow"/> <shadow-control :ready="!!currentShadowFallback" :fallback="currentShadowFallback" v-model="currentShadow"/>
</div> </div>
<div :label="$t('settings.style.fonts._tab_label')" class="fonts-container">
<div class="tab-header">
<p>{{$t('settings.style.fonts.help')}}</p>
</div>
<FontControl
name="ui"
v-model="fontsLocal.interface"
:label="$t('settings.style.fonts.components.interface')"
:fallback="previewTheme.fonts.interface"
:options="['serif', 'sans-serif', 'monospace', 'custom']" />
<FontControl
name="input"
v-model="fontsLocal.input"
:label="$t('settings.style.fonts.components.input')"
:fallback="previewTheme.fonts.input"
:options="['serif', 'sans-serif', 'monospace', 'inherit', 'custom']" />
<FontControl
name="post"
v-model="fontsLocal.post"
:label="$t('settings.style.fonts.components.post')"
:fallback="previewTheme.fonts.post"
:options="['serif', 'sans-serif', 'monospace', 'inherit', 'custom']" />
<FontControl
name="postCode"
v-model="fontsLocal.postCode"
:label="$t('settings.style.fonts.components.postCode')"
:fallback="previewTheme.fonts.postCode"
:options="['serif', 'sans-serif', 'monospace', 'inherit', 'custom']" />
</div>
</tab-switcher> </tab-switcher>
</keep-alive> </keep-alive>

View file

@ -236,6 +236,19 @@
"buttonPressedHover": "Button (pressed+hover)", "buttonPressedHover": "Button (pressed+hover)",
"input": "Input field" "input": "Input field"
} }
},
"fonts": {
"_tab_label": "Fonts",
"help": "Select font to use for elements of UI. For \"custom\" you have to enter exact font name as it appears in system.",
"components": {
"interface": "Interface",
"input": "Input fields",
"post": "Post text",
"postCode": "Monospaced text in a post (rich text)"
},
"family": "Font name",
"size": "Size (in px)",
"weight": "Weight (boldness)"
} }
} }
}, },

View file

@ -85,6 +85,7 @@ const setColors = (input, commit) => {
styleSheet.insertRule(`body { ${rules.radii} }`, 'index-max') styleSheet.insertRule(`body { ${rules.radii} }`, 'index-max')
styleSheet.insertRule(`body { ${rules.colors} }`, 'index-max') styleSheet.insertRule(`body { ${rules.colors} }`, 'index-max')
styleSheet.insertRule(`body { ${rules.shadows} }`, 'index-max') styleSheet.insertRule(`body { ${rules.shadows} }`, 'index-max')
styleSheet.insertRule(`body { ${rules.fonts} }`, 'index-max')
body.style.display = 'initial' body.style.display = 'initial'
// commit('setOption', { name: 'colors', value: htmlColors }) // commit('setOption', { name: 'colors', value: htmlColors })
@ -267,6 +268,41 @@ const generateRadii = (input) => {
} }
} }
const generateFonts = (input) => {
const fonts = Object.entries(input.fonts || {}).filter(([k, v]) => v).reduce((acc, [k, v]) => {
acc[k] = Object.entries(v).filter(([k, v]) => v).reduce((acc, [k, v]) => {
acc[k] = v
return acc
}, acc[k])
return acc
}, {
interface: {
family: 'sans-serif'
},
input: {
family: 'inherit'
},
post: {
family: 'inherit'
},
postCode: {
family: 'monospace'
}
})
return {
rules: {
fonts: Object
.entries(fonts)
.filter(([k, v]) => v)
.map(([k, v]) => `--${k}Font: ${v.family}`).join(';')
},
theme: {
fonts
}
}
}
const generateShadows = (input) => { const generateShadows = (input) => {
const border = (top, shadow) => ({ const border = (top, shadow) => ({
x: 0, x: 0,
@ -355,17 +391,19 @@ const generateShadows = (input) => {
} }
} }
const composePreset = (colors, radii, shadows) => { const composePreset = (colors, radii, shadows, fonts) => {
return { return {
rules: { rules: {
...shadows.rules, ...shadows.rules,
...colors.rules, ...colors.rules,
...radii.rules ...radii.rules,
...fonts.rules
}, },
theme: { theme: {
...shadows.theme, ...shadows.theme,
...colors.theme, ...colors.theme,
...radii.theme ...radii.theme,
...fonts.theme
} }
} }
} }
@ -374,8 +412,9 @@ const generatePreset = (input) => {
const shadows = generateShadows(input) const shadows = generateShadows(input)
const colors = generateColors(input) const colors = generateColors(input)
const radii = generateRadii(input) const radii = generateRadii(input)
const fonts = generateFonts(input)
return composePreset(colors, radii, shadows) return composePreset(colors, radii, shadows, fonts)
} }
const setPreset = (val, commit) => { const setPreset = (val, commit) => {
@ -424,6 +463,7 @@ export {
generateColors, generateColors,
generateRadii, generateRadii,
generateShadows, generateShadows,
generateFonts,
generatePreset, generatePreset,
composePreset, composePreset,
getCssShadow getCssShadow