2018-11-14 08:39:17 -08:00
|
|
|
import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js'
|
2018-11-19 07:15:27 -08:00
|
|
|
import { set, delete as del } from 'vue'
|
2018-12-10 14:38:20 -08:00
|
|
|
import { generateColors, generateShadows, generateRadii, generateFonts, composePreset, getThemes } from '../../services/style_setter/style_setter.js'
|
2018-10-02 11:43:58 -07:00
|
|
|
import ColorInput from '../color_input/color_input.vue'
|
2018-11-20 16:14:59 -08:00
|
|
|
import RangeInput from '../range_input/range_input.vue'
|
|
|
|
import OpacityInput from '../opacity_input/opacity_input.vue'
|
2018-11-18 17:40:25 -08:00
|
|
|
import ShadowControl from '../shadow_control/shadow_control.vue'
|
2018-11-25 10:48:16 -08:00
|
|
|
import FontControl from '../font_control/font_control.vue'
|
2018-10-09 14:07:28 -07:00
|
|
|
import ContrastRatio from '../contrast_ratio/contrast_ratio.vue'
|
2018-11-14 08:39:17 -08:00
|
|
|
import TabSwitcher from '../tab_switcher/tab_switcher.jsx'
|
2017-11-20 12:45:09 -08:00
|
|
|
|
2018-11-20 09:58:20 -08:00
|
|
|
// List of color values used in v1
|
2018-11-19 09:22:46 -08:00
|
|
|
const v1OnlyNames = [
|
|
|
|
'bg',
|
|
|
|
'fg',
|
|
|
|
'text',
|
|
|
|
'link',
|
|
|
|
'cRed',
|
|
|
|
'cGreen',
|
|
|
|
'cBlue',
|
|
|
|
'cOrange'
|
|
|
|
].map(_ => _ + 'ColorLocal')
|
|
|
|
|
2017-01-16 09:57:03 -08:00
|
|
|
export default {
|
2017-02-17 09:21:02 -08:00
|
|
|
data () {
|
|
|
|
return {
|
|
|
|
availableStyles: [],
|
2017-11-17 07:24:42 -08:00
|
|
|
selected: this.$store.state.config.theme,
|
2018-07-04 05:25:40 -07:00
|
|
|
invalidThemeImported: false,
|
2018-10-02 11:43:58 -07:00
|
|
|
|
2018-11-25 08:12:38 -08:00
|
|
|
previewShadows: {},
|
|
|
|
previewColors: {},
|
|
|
|
previewRadii: {},
|
2018-11-25 10:48:16 -08:00
|
|
|
previewFonts: {},
|
2018-11-25 08:12:38 -08:00
|
|
|
|
|
|
|
shadowsInvalid: true,
|
|
|
|
colorsInvalid: true,
|
|
|
|
radiiInvalid: true,
|
|
|
|
|
2018-11-22 21:24:55 -08:00
|
|
|
keepShadows: false,
|
2018-11-22 23:17:01 -08:00
|
|
|
keepOpacity: false,
|
2018-11-22 21:24:55 -08:00
|
|
|
keepRoundness: false,
|
2018-11-25 10:48:16 -08:00
|
|
|
keepFonts: false,
|
2018-11-22 21:24:55 -08:00
|
|
|
|
2017-11-17 07:24:42 -08:00
|
|
|
textColorLocal: '',
|
2018-04-01 12:07:25 -07:00
|
|
|
linkColorLocal: '',
|
2018-10-02 11:43:58 -07:00
|
|
|
|
2018-10-03 11:21:48 -07:00
|
|
|
bgColorLocal: '',
|
|
|
|
bgOpacityLocal: undefined,
|
|
|
|
|
2018-10-04 08:16:14 -07:00
|
|
|
fgColorLocal: '',
|
|
|
|
fgTextColorLocal: undefined,
|
|
|
|
fgLinkColorLocal: undefined,
|
|
|
|
|
|
|
|
btnColorLocal: undefined,
|
2018-10-03 11:21:48 -07:00
|
|
|
btnTextColorLocal: undefined,
|
|
|
|
btnOpacityLocal: undefined,
|
|
|
|
|
|
|
|
inputColorLocal: undefined,
|
|
|
|
inputTextColorLocal: undefined,
|
|
|
|
inputOpacityLocal: undefined,
|
|
|
|
|
2018-10-02 11:43:58 -07:00
|
|
|
panelColorLocal: undefined,
|
2018-10-03 11:21:48 -07:00
|
|
|
panelTextColorLocal: undefined,
|
2018-11-26 09:12:59 -08:00
|
|
|
panelLinkColorLocal: undefined,
|
2018-10-07 09:59:22 -07:00
|
|
|
panelFaintColorLocal: undefined,
|
2018-10-02 11:43:58 -07:00
|
|
|
panelOpacityLocal: undefined,
|
2018-10-03 11:21:48 -07:00
|
|
|
|
2018-10-02 11:43:58 -07:00
|
|
|
topBarColorLocal: undefined,
|
2018-10-03 11:21:48 -07:00
|
|
|
topBarTextColorLocal: undefined,
|
2018-10-04 08:16:14 -07:00
|
|
|
topBarLinkColorLocal: undefined,
|
2018-10-02 11:43:58 -07:00
|
|
|
|
2018-11-13 05:30:01 -08:00
|
|
|
alertErrorColorLocal: undefined,
|
|
|
|
|
|
|
|
badgeOpacityLocal: undefined,
|
|
|
|
badgeNotificationColorLocal: undefined,
|
2018-10-04 08:16:14 -07:00
|
|
|
|
2018-10-07 09:59:22 -07:00
|
|
|
borderColorLocal: undefined,
|
|
|
|
borderOpacityLocal: undefined,
|
|
|
|
|
|
|
|
faintColorLocal: undefined,
|
|
|
|
faintOpacityLocal: undefined,
|
|
|
|
faintLinkColorLocal: undefined,
|
|
|
|
|
|
|
|
cRedColorLocal: '',
|
|
|
|
cBlueColorLocal: '',
|
|
|
|
cGreenColorLocal: '',
|
|
|
|
cOrangeColorLocal: '',
|
2018-10-02 11:43:58 -07:00
|
|
|
|
2018-11-19 09:22:46 -08:00
|
|
|
shadowSelected: undefined,
|
|
|
|
shadowsLocal: {},
|
2018-11-25 10:48:16 -08:00
|
|
|
fontsLocal: {},
|
2018-11-19 09:22:46 -08:00
|
|
|
|
2018-04-07 16:39:39 -07:00
|
|
|
btnRadiusLocal: '',
|
2018-04-14 21:25:59 -07:00
|
|
|
inputRadiusLocal: '',
|
2018-11-22 20:28:53 -08:00
|
|
|
checkboxRadiusLocal: '',
|
2018-04-07 16:39:39 -07:00
|
|
|
panelRadiusLocal: '',
|
|
|
|
avatarRadiusLocal: '',
|
|
|
|
avatarAltRadiusLocal: '',
|
|
|
|
attachmentRadiusLocal: '',
|
|
|
|
tooltipRadiusLocal: ''
|
2017-02-17 09:21:02 -08:00
|
|
|
}
|
|
|
|
},
|
2017-01-16 09:57:03 -08:00
|
|
|
created () {
|
|
|
|
const self = this
|
2017-11-17 07:24:42 -08:00
|
|
|
|
2018-12-10 14:38:20 -08:00
|
|
|
getThemes().then((themesComplete) => {
|
|
|
|
self.availableStyles = themesComplete
|
|
|
|
})
|
2017-11-17 07:24:42 -08:00
|
|
|
},
|
2017-11-18 03:13:51 -08:00
|
|
|
mounted () {
|
2018-10-02 11:43:58 -07:00
|
|
|
this.normalizeLocalState(this.$store.state.config.customTheme)
|
2018-11-20 12:25:38 -08:00
|
|
|
if (typeof this.shadowSelected === 'undefined') {
|
|
|
|
this.shadowSelected = this.shadowsAvailable[0]
|
|
|
|
}
|
2018-10-02 11:43:58 -07:00
|
|
|
},
|
|
|
|
computed: {
|
2018-10-03 11:21:48 -07:00
|
|
|
selectedVersion () {
|
|
|
|
return Array.isArray(this.selected) ? 1 : 2
|
|
|
|
},
|
2018-11-19 09:22:46 -08:00
|
|
|
currentColors () {
|
2018-10-02 11:43:58 -07:00
|
|
|
return {
|
2018-11-19 09:22:46 -08:00
|
|
|
bg: this.bgColorLocal,
|
|
|
|
text: this.textColorLocal,
|
|
|
|
link: this.linkColorLocal,
|
|
|
|
|
|
|
|
fg: this.fgColorLocal,
|
|
|
|
fgText: this.fgTextColorLocal,
|
|
|
|
fgLink: this.fgLinkColorLocal,
|
|
|
|
|
|
|
|
panel: this.panelColorLocal,
|
|
|
|
panelText: this.panelTextColorLocal,
|
2018-11-26 09:12:59 -08:00
|
|
|
panelLink: this.panelLinkColorLocal,
|
2018-11-19 09:22:46 -08:00
|
|
|
panelFaint: this.panelFaintColorLocal,
|
|
|
|
|
|
|
|
input: this.inputColorLocal,
|
|
|
|
inputText: this.inputTextColorLocal,
|
|
|
|
|
|
|
|
topBar: this.topBarColorLocal,
|
|
|
|
topBarText: this.topBarTextColorLocal,
|
|
|
|
topBarLink: this.topBarLinkColorLocal,
|
|
|
|
|
|
|
|
btn: this.btnColorLocal,
|
|
|
|
btnText: this.btnTextColorLocal,
|
|
|
|
|
|
|
|
alertError: this.alertErrorColorLocal,
|
|
|
|
badgeNotification: this.badgeNotificationColorLocal,
|
|
|
|
|
|
|
|
faint: this.faintColorLocal,
|
|
|
|
faintLink: this.faintLinkColorLocal,
|
|
|
|
border: this.borderColorLocal,
|
|
|
|
|
|
|
|
cRed: this.cRedColorLocal,
|
|
|
|
cBlue: this.cBlueColorLocal,
|
|
|
|
cGreen: this.cGreenColorLocal,
|
|
|
|
cOrange: this.cOrangeColorLocal
|
2018-10-02 11:43:58 -07:00
|
|
|
}
|
|
|
|
},
|
2018-11-19 09:22:46 -08:00
|
|
|
currentOpacity () {
|
|
|
|
return {
|
|
|
|
bg: this.bgOpacityLocal,
|
|
|
|
btn: this.btnOpacityLocal,
|
|
|
|
input: this.inputOpacityLocal,
|
|
|
|
panel: this.panelOpacityLocal,
|
|
|
|
topBar: this.topBarOpacityLocal,
|
|
|
|
border: this.borderOpacityLocal,
|
|
|
|
faint: this.faintOpacityLocal
|
|
|
|
}
|
|
|
|
},
|
|
|
|
currentRadii () {
|
|
|
|
return {
|
|
|
|
btn: this.btnRadiusLocal,
|
|
|
|
input: this.inputRadiusLocal,
|
2018-11-22 20:28:53 -08:00
|
|
|
checkbox: this.checkboxRadiusLocal,
|
2018-11-19 09:22:46 -08:00
|
|
|
panel: this.panelRadiusLocal,
|
|
|
|
avatar: this.avatarRadiusLocal,
|
|
|
|
avatarAlt: this.avatarAltRadiusLocal,
|
|
|
|
tooltip: this.tooltipRadiusLocal,
|
|
|
|
attachment: this.attachmentRadiusLocal
|
|
|
|
}
|
|
|
|
},
|
|
|
|
preview () {
|
2018-11-25 10:48:16 -08:00
|
|
|
return composePreset(this.previewColors, this.previewRadii, this.previewShadows, this.previewFonts)
|
2018-11-19 09:22:46 -08:00
|
|
|
},
|
2018-10-04 08:16:14 -07:00
|
|
|
previewTheme () {
|
2018-11-25 10:48:16 -08:00
|
|
|
if (!this.preview.theme.colors) return { colors: {}, opacity: {}, radii: {}, shadows: {}, fonts: {} }
|
2018-10-04 08:16:14 -07:00
|
|
|
return this.preview.theme
|
|
|
|
},
|
2018-11-20 12:25:38 -08:00
|
|
|
// This needs optimization maybe
|
2018-10-09 14:07:28 -07:00
|
|
|
previewContrast () {
|
2018-11-19 09:22:46 -08:00
|
|
|
if (!this.previewTheme.colors.bg) return {}
|
2018-10-09 14:07:28 -07:00
|
|
|
const colors = this.previewTheme.colors
|
2018-10-09 19:39:02 -07:00
|
|
|
const opacity = this.previewTheme.opacity
|
2018-11-14 08:39:17 -08:00
|
|
|
if (!colors.bg) return {}
|
2018-10-09 14:07:28 -07:00
|
|
|
const hints = (ratio) => ({
|
|
|
|
text: ratio.toPrecision(3) + ':1',
|
|
|
|
// AA level, AAA level
|
|
|
|
aa: ratio >= 4.5,
|
|
|
|
aaa: ratio >= 7,
|
|
|
|
// same but for 18pt+ texts
|
|
|
|
laa: ratio >= 3,
|
|
|
|
laaa: ratio >= 4.5
|
|
|
|
})
|
|
|
|
|
2018-10-09 19:39:02 -07:00
|
|
|
// fgsfds :DDDD
|
|
|
|
const fgs = {
|
|
|
|
text: hex2rgb(colors.text),
|
|
|
|
panelText: hex2rgb(colors.panelText),
|
2018-11-26 09:12:59 -08:00
|
|
|
panelLink: hex2rgb(colors.panelLink),
|
2018-10-09 19:39:02 -07:00
|
|
|
btnText: hex2rgb(colors.btnText),
|
|
|
|
topBarText: hex2rgb(colors.topBarText),
|
2018-11-13 05:30:01 -08:00
|
|
|
inputText: hex2rgb(colors.inputText),
|
2018-10-09 19:39:02 -07:00
|
|
|
|
|
|
|
link: hex2rgb(colors.link),
|
|
|
|
topBarLink: hex2rgb(colors.topBarLink),
|
2018-10-21 05:25:21 -07:00
|
|
|
|
|
|
|
red: hex2rgb(colors.cRed),
|
|
|
|
green: hex2rgb(colors.cGreen),
|
|
|
|
blue: hex2rgb(colors.cBlue),
|
|
|
|
orange: hex2rgb(colors.cOrange)
|
2018-10-09 19:39:02 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
const bgs = {
|
|
|
|
bg: hex2rgb(colors.bg),
|
|
|
|
btn: hex2rgb(colors.btn),
|
|
|
|
panel: hex2rgb(colors.panel),
|
2018-11-13 05:30:01 -08:00
|
|
|
topBar: hex2rgb(colors.topBar),
|
|
|
|
input: hex2rgb(colors.input),
|
|
|
|
alertError: hex2rgb(colors.alertError),
|
|
|
|
badgeNotification: hex2rgb(colors.badgeNotification)
|
2018-10-09 19:39:02 -07:00
|
|
|
}
|
|
|
|
|
2018-11-14 08:39:17 -08:00
|
|
|
/* This is a bit confusing because "bottom layer" used is text color
|
|
|
|
* This is done to get worst case scenario when background below transparent
|
|
|
|
* layer matches text color, making it harder to read the lower alpha is.
|
|
|
|
*/
|
2018-10-09 14:07:28 -07:00
|
|
|
const ratios = {
|
2018-11-14 08:39:17 -08:00
|
|
|
bgText: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.text), fgs.text),
|
|
|
|
bgLink: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.link), fgs.link),
|
|
|
|
bgRed: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.red), fgs.red),
|
|
|
|
bgGreen: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.green), fgs.green),
|
|
|
|
bgBlue: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.blue), fgs.blue),
|
|
|
|
bgOrange: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.orange), fgs.orange),
|
2018-10-09 19:39:02 -07:00
|
|
|
|
2018-11-14 08:39:17 -08:00
|
|
|
tintText: getContrastRatio(alphaBlend(bgs.bg, 0.5, fgs.panelText), fgs.text),
|
2018-10-09 14:07:28 -07:00
|
|
|
|
2018-11-14 08:39:17 -08:00
|
|
|
panelText: getContrastRatio(alphaBlend(bgs.panel, opacity.panel, fgs.panelText), fgs.panelText),
|
2018-11-26 09:12:59 -08:00
|
|
|
panelLink: getContrastRatio(alphaBlend(bgs.panel, opacity.panel, fgs.panelLink), fgs.panelLink),
|
2018-10-09 14:07:28 -07:00
|
|
|
|
2018-11-14 08:39:17 -08:00
|
|
|
btnText: getContrastRatio(alphaBlend(bgs.btn, opacity.btn, fgs.btnText), fgs.btnText),
|
2018-10-09 14:07:28 -07:00
|
|
|
|
2018-11-14 08:39:17 -08:00
|
|
|
inputText: getContrastRatio(alphaBlend(bgs.input, opacity.input, fgs.inputText), fgs.inputText),
|
2018-11-13 05:30:01 -08:00
|
|
|
|
2018-11-14 08:39:17 -08:00
|
|
|
topBarText: getContrastRatio(alphaBlend(bgs.topBar, opacity.topBar, fgs.topBarText), fgs.topBarText),
|
|
|
|
topBarLink: getContrastRatio(alphaBlend(bgs.topBar, opacity.topBar, fgs.topBarLink), fgs.topBarLink)
|
2018-10-09 14:07:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return Object.entries(ratios).reduce((acc, [k, v]) => { acc[k] = hints(v); return acc }, {})
|
|
|
|
},
|
2018-10-04 08:16:14 -07:00
|
|
|
previewRules () {
|
2018-11-19 09:22:46 -08:00
|
|
|
if (!this.preview.rules) return ''
|
2018-11-25 10:48:16 -08:00
|
|
|
return [
|
|
|
|
...Object.values(this.preview.rules),
|
|
|
|
'color: var(--text)',
|
|
|
|
'font-family: var(--interfaceFont, sans-serif)'
|
|
|
|
].join(';')
|
2018-11-18 17:40:25 -08:00
|
|
|
},
|
|
|
|
shadowsAvailable () {
|
2018-11-21 10:40:45 -08:00
|
|
|
return Object.keys(this.previewTheme.shadows).sort()
|
2018-11-18 17:40:25 -08:00
|
|
|
},
|
2018-11-19 07:15:27 -08:00
|
|
|
currentShadowOverriden: {
|
|
|
|
get () {
|
2018-11-19 09:22:46 -08:00
|
|
|
return !!this.currentShadow
|
2018-11-19 07:15:27 -08:00
|
|
|
},
|
|
|
|
set (val) {
|
|
|
|
if (val) {
|
2018-11-19 09:22:46 -08:00
|
|
|
set(this.shadowsLocal, this.shadowSelected, this.currentShadowFallback.map(_ => Object.assign({}, _)))
|
2018-11-19 07:15:27 -08:00
|
|
|
} else {
|
|
|
|
del(this.shadowsLocal, this.shadowSelected)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
currentShadowFallback () {
|
|
|
|
return this.previewTheme.shadows[this.shadowSelected]
|
|
|
|
},
|
|
|
|
currentShadow: {
|
|
|
|
get () {
|
|
|
|
return this.shadowsLocal[this.shadowSelected]
|
|
|
|
},
|
|
|
|
set (v) {
|
|
|
|
set(this.shadowsLocal, this.shadowSelected, v)
|
|
|
|
}
|
2018-11-25 08:12:38 -08:00
|
|
|
},
|
|
|
|
themeValid () {
|
|
|
|
return !this.shadowsInvalid && !this.colorsInvalid && !this.radiiInvalid
|
2018-10-02 11:43:58 -07:00
|
|
|
}
|
|
|
|
},
|
|
|
|
components: {
|
|
|
|
ColorInput,
|
2018-10-09 14:07:28 -07:00
|
|
|
OpacityInput,
|
2018-11-20 16:14:59 -08:00
|
|
|
RangeInput,
|
2018-11-14 08:39:17 -08:00
|
|
|
ContrastRatio,
|
2018-11-18 17:40:25 -08:00
|
|
|
ShadowControl,
|
2018-11-25 10:48:16 -08:00
|
|
|
FontControl,
|
2018-11-14 08:39:17 -08:00
|
|
|
TabSwitcher
|
2017-11-17 07:24:42 -08:00
|
|
|
},
|
|
|
|
methods: {
|
2018-06-27 16:08:06 -07:00
|
|
|
exportCurrentTheme () {
|
2018-11-26 10:07:22 -08:00
|
|
|
const saveEverything = !this.keepFonts && !this.keepShadows && !this.keepColors && !this.keepOpacity && !this.keepRoundness
|
|
|
|
const theme = {
|
|
|
|
shadows: this.shadowsLocal,
|
|
|
|
fonts: this.fontsLocal,
|
|
|
|
opacity: this.currentOpacity,
|
|
|
|
colors: this.currentColors,
|
|
|
|
radii: this.currentRadii
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.keepFonts && !saveEverything) {
|
|
|
|
delete theme.fonts
|
|
|
|
}
|
|
|
|
if (!this.keepShadows && !saveEverything) {
|
|
|
|
delete theme.shadows
|
|
|
|
}
|
|
|
|
if (!this.keepOpacity && !saveEverything) {
|
|
|
|
delete theme.opacity
|
|
|
|
}
|
|
|
|
if (!this.keepColors && !saveEverything) {
|
|
|
|
delete theme.colors
|
|
|
|
}
|
|
|
|
if (!this.keepRoundness && !saveEverything) {
|
|
|
|
delete theme.radii
|
|
|
|
}
|
|
|
|
|
2018-06-27 16:08:06 -07:00
|
|
|
const stringified = JSON.stringify({
|
2018-07-04 05:25:40 -07:00
|
|
|
// To separate from other random JSON files and possible future theme formats
|
2018-11-26 10:07:22 -08:00
|
|
|
_pleroma_theme_version: 2, theme
|
2018-06-27 16:08:06 -07:00
|
|
|
}, null, 2) // Pretty-print and indent with 2 spaces
|
|
|
|
|
|
|
|
// Create an invisible link with a data url and simulate a click
|
|
|
|
const e = document.createElement('a')
|
|
|
|
e.setAttribute('download', 'pleroma_theme.json')
|
|
|
|
e.setAttribute('href', 'data:application/json;base64,' + window.btoa(stringified))
|
|
|
|
e.style.display = 'none'
|
|
|
|
|
|
|
|
document.body.appendChild(e)
|
|
|
|
e.click()
|
|
|
|
document.body.removeChild(e)
|
|
|
|
},
|
|
|
|
|
2018-06-27 17:59:57 -07:00
|
|
|
importTheme () {
|
2018-07-04 05:25:40 -07:00
|
|
|
this.invalidThemeImported = false
|
2018-06-27 17:59:57 -07:00
|
|
|
const filePicker = document.createElement('input')
|
|
|
|
filePicker.setAttribute('type', 'file')
|
|
|
|
filePicker.setAttribute('accept', '.json')
|
|
|
|
|
|
|
|
filePicker.addEventListener('change', event => {
|
|
|
|
if (event.target.files[0]) {
|
|
|
|
// eslint-disable-next-line no-undef
|
|
|
|
const reader = new FileReader()
|
|
|
|
reader.onload = ({target}) => {
|
2018-07-04 05:25:40 -07:00
|
|
|
try {
|
|
|
|
const parsed = JSON.parse(target.result)
|
|
|
|
if (parsed._pleroma_theme_version === 1) {
|
2018-10-03 11:21:48 -07:00
|
|
|
this.normalizeLocalState(parsed, 1)
|
|
|
|
} else if (parsed._pleroma_theme_version === 2) {
|
2018-10-04 08:16:14 -07:00
|
|
|
this.normalizeLocalState(parsed.theme, 2)
|
2018-07-04 05:25:40 -07:00
|
|
|
} else {
|
|
|
|
// A theme from the future, spooky
|
|
|
|
this.invalidThemeImported = true
|
|
|
|
}
|
|
|
|
} catch (e) {
|
|
|
|
// This will happen both if there is a JSON syntax error or the theme is missing components
|
|
|
|
this.invalidThemeImported = true
|
|
|
|
}
|
2018-06-27 17:59:57 -07:00
|
|
|
}
|
|
|
|
reader.readAsText(event.target.files[0])
|
|
|
|
}
|
|
|
|
})
|
|
|
|
|
|
|
|
document.body.appendChild(filePicker)
|
|
|
|
filePicker.click()
|
|
|
|
document.body.removeChild(filePicker)
|
|
|
|
},
|
|
|
|
|
2017-11-17 07:24:42 -08:00
|
|
|
setCustomTheme () {
|
2018-10-02 11:43:58 -07:00
|
|
|
this.$store.dispatch('setOption', {
|
|
|
|
name: 'customTheme',
|
2018-11-19 07:15:27 -08:00
|
|
|
value: {
|
2018-11-19 09:22:46 -08:00
|
|
|
shadows: this.shadowsLocal,
|
2018-11-25 10:48:16 -08:00
|
|
|
fonts: this.fontsLocal,
|
2018-11-19 09:22:46 -08:00
|
|
|
opacity: this.currentOpacity,
|
|
|
|
colors: this.currentColors,
|
|
|
|
radii: this.currentRadii
|
2018-11-19 07:15:27 -08:00
|
|
|
}
|
2018-10-02 11:43:58 -07:00
|
|
|
})
|
2018-06-27 17:07:50 -07:00
|
|
|
},
|
|
|
|
|
2018-11-23 00:36:36 -08:00
|
|
|
clearAll () {
|
2018-11-26 10:07:22 -08:00
|
|
|
const state = this.$store.state.config.customTheme
|
|
|
|
const version = state.colors ? 2 : 'l1'
|
|
|
|
this.normalizeLocalState(this.$store.state.config.customTheme, version)
|
2018-11-23 00:36:36 -08:00
|
|
|
},
|
|
|
|
|
2018-11-19 09:22:46 -08:00
|
|
|
// Clears all the extra stuff when loading V1 theme
|
2018-10-03 11:21:48 -07:00
|
|
|
clearV1 () {
|
2018-11-19 09:22:46 -08:00
|
|
|
Object.keys(this.$data)
|
|
|
|
.filter(_ => _.endsWith('ColorLocal') || _.endsWith('OpacityLocal'))
|
|
|
|
.filter(_ => !v1OnlyNames.includes(_))
|
|
|
|
.forEach(key => {
|
|
|
|
set(this.$data, key, undefined)
|
|
|
|
})
|
2018-10-03 11:21:48 -07:00
|
|
|
},
|
|
|
|
|
2018-11-22 21:24:55 -08:00
|
|
|
clearRoundness () {
|
|
|
|
Object.keys(this.$data)
|
|
|
|
.filter(_ => _.endsWith('RadiusLocal'))
|
|
|
|
.forEach(key => {
|
|
|
|
set(this.$data, key, undefined)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2018-11-22 23:17:01 -08:00
|
|
|
clearOpacity () {
|
|
|
|
Object.keys(this.$data)
|
|
|
|
.filter(_ => _.endsWith('OpacityLocal'))
|
|
|
|
.forEach(key => {
|
|
|
|
set(this.$data, key, undefined)
|
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2018-11-22 21:24:55 -08:00
|
|
|
clearShadows () {
|
|
|
|
this.shadowsLocal = {}
|
|
|
|
},
|
|
|
|
|
2018-11-25 10:48:16 -08:00
|
|
|
clearFonts () {
|
|
|
|
this.fontsLocal = {}
|
|
|
|
},
|
|
|
|
|
2018-10-04 08:16:14 -07:00
|
|
|
/**
|
2018-11-26 10:07:22 -08:00
|
|
|
* This applies stored theme data onto form. Supports three versions of data:
|
|
|
|
* v2 (version = 2) - newer version of themes.
|
|
|
|
* v1 (version = 1) - older version of themes (import from file)
|
|
|
|
* v1l (version = l1) - older version of theme (load from local storage)
|
|
|
|
* v1 and v1l differ because of way themes were stored/exported.
|
2018-10-04 08:16:14 -07:00
|
|
|
* @param {Object} input - input data
|
2018-11-26 10:07:22 -08:00
|
|
|
* @param {Number} version - version of data. 0 means try to guess based on data. "l1" means v1, locastorage type
|
2018-10-04 08:16:14 -07:00
|
|
|
*/
|
|
|
|
normalizeLocalState (input, version = 0) {
|
2018-10-02 11:43:58 -07:00
|
|
|
const colors = input.colors || input
|
|
|
|
const radii = input.radii || input
|
2018-11-22 23:17:01 -08:00
|
|
|
const opacity = input.opacity
|
2018-11-18 17:40:25 -08:00
|
|
|
const shadows = input.shadows || {}
|
2018-11-25 10:48:16 -08:00
|
|
|
const fonts = input.fonts || {}
|
2018-10-02 11:43:58 -07:00
|
|
|
|
2018-10-07 09:59:22 -07:00
|
|
|
if (version === 0) {
|
|
|
|
if (input.version) version = input.version
|
|
|
|
// Old v1 naming: fg is text, btn is foreground
|
|
|
|
if (typeof colors.text === 'undefined' && typeof colors.fg !== 'undefined') {
|
|
|
|
version = 1
|
|
|
|
}
|
|
|
|
// New v2 naming: text is text, fg is foreground
|
|
|
|
if (typeof colors.text !== 'undefined' && typeof colors.fg !== 'undefined') {
|
|
|
|
version = 2
|
|
|
|
}
|
|
|
|
}
|
2018-10-02 11:43:58 -07:00
|
|
|
|
2018-10-07 09:59:22 -07:00
|
|
|
// Stuff that differs between V1 and V2
|
2018-10-03 11:21:48 -07:00
|
|
|
if (version === 1) {
|
2018-10-07 09:59:22 -07:00
|
|
|
this.fgColorLocal = rgb2hex(colors.btn)
|
|
|
|
this.textColorLocal = rgb2hex(colors.fg)
|
2018-10-03 11:21:48 -07:00
|
|
|
}
|
|
|
|
|
2018-12-01 23:22:25 -08:00
|
|
|
this.clearV1()
|
2018-10-07 09:59:22 -07:00
|
|
|
const keys = new Set(version !== 1 ? Object.keys(colors) : [])
|
2018-11-26 10:07:22 -08:00
|
|
|
if (version === 1 || version === 'l1') {
|
2018-10-07 09:59:22 -07:00
|
|
|
keys
|
|
|
|
.add('bg')
|
|
|
|
.add('link')
|
|
|
|
.add('cRed')
|
|
|
|
.add('cBlue')
|
|
|
|
.add('cGreen')
|
|
|
|
.add('cOrange')
|
|
|
|
}
|
2018-11-26 10:07:22 -08:00
|
|
|
|
2018-10-07 09:59:22 -07:00
|
|
|
keys.forEach(key => {
|
|
|
|
this[key + 'ColorLocal'] = rgb2hex(colors[key])
|
|
|
|
})
|
2018-06-27 17:07:50 -07:00
|
|
|
|
2018-11-22 21:24:55 -08:00
|
|
|
if (!this.keepRoundness) {
|
|
|
|
this.clearRoundness()
|
2018-11-22 22:02:10 -08:00
|
|
|
Object.entries(radii).forEach(([k, v]) => {
|
|
|
|
// 'Radius' is kept mostly for v1->v2 localstorage transition
|
|
|
|
const key = k.endsWith('Radius') ? k.split('Radius')[0] : k
|
|
|
|
this[key + 'RadiusLocal'] = v
|
|
|
|
})
|
2018-11-22 21:24:55 -08:00
|
|
|
}
|
2018-10-07 12:03:34 -07:00
|
|
|
|
2018-11-22 21:24:55 -08:00
|
|
|
if (!this.keepShadows) {
|
|
|
|
this.clearShadows()
|
|
|
|
this.shadowsLocal = shadows
|
|
|
|
this.shadowSelected = this.shadowsAvailable[0]
|
|
|
|
}
|
2018-11-18 17:40:25 -08:00
|
|
|
|
2018-11-25 10:48:16 -08:00
|
|
|
if (!this.keepFonts) {
|
|
|
|
this.clearFonts()
|
|
|
|
this.fontsLocal = fonts
|
|
|
|
}
|
|
|
|
|
2018-11-22 23:17:01 -08:00
|
|
|
if (opacity && !this.keepOpacity) {
|
|
|
|
this.clearOpacity()
|
|
|
|
Object.entries(opacity).forEach(([k, v]) => {
|
|
|
|
if (typeof v === 'undefined' || v === null || Number.isNaN(v)) return
|
|
|
|
this[k + 'OpacityLocal'] = v
|
|
|
|
})
|
|
|
|
}
|
2017-11-17 07:24:42 -08:00
|
|
|
}
|
2017-01-16 09:57:03 -08:00
|
|
|
},
|
|
|
|
watch: {
|
2018-11-25 08:12:38 -08:00
|
|
|
currentRadii () {
|
|
|
|
try {
|
|
|
|
this.previewRadii = generateRadii({ radii: this.currentRadii })
|
|
|
|
this.radiiInvalid = false
|
|
|
|
} catch (e) {
|
|
|
|
this.radiiInvalid = true
|
|
|
|
console.warn(e)
|
|
|
|
}
|
|
|
|
},
|
2018-11-25 10:48:16 -08:00
|
|
|
shadowsLocal: {
|
|
|
|
handler () {
|
|
|
|
try {
|
|
|
|
this.previewShadows = generateShadows({ shadows: this.shadowsLocal })
|
|
|
|
this.shadowsInvalid = false
|
|
|
|
} catch (e) {
|
|
|
|
this.shadowsInvalid = true
|
|
|
|
console.warn(e)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
deep: true
|
|
|
|
},
|
|
|
|
fontsLocal: {
|
|
|
|
handler () {
|
|
|
|
try {
|
|
|
|
this.previewFonts = generateFonts({ fonts: this.fontsLocal })
|
|
|
|
this.fontsInvalid = false
|
|
|
|
} catch (e) {
|
|
|
|
this.fontsInvalid = true
|
|
|
|
console.warn(e)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
deep: true
|
2018-11-25 08:12:38 -08:00
|
|
|
},
|
|
|
|
currentColors () {
|
|
|
|
try {
|
|
|
|
this.previewColors = generateColors({
|
|
|
|
opacity: this.currentOpacity,
|
|
|
|
colors: this.currentColors
|
|
|
|
})
|
|
|
|
this.colorsInvalid = false
|
|
|
|
} catch (e) {
|
|
|
|
this.colorsInvalid = true
|
|
|
|
console.warn(e)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
currentOpacity () {
|
|
|
|
try {
|
|
|
|
this.previewColors = generateColors({
|
|
|
|
opacity: this.currentOpacity,
|
|
|
|
colors: this.currentColors
|
|
|
|
})
|
|
|
|
} catch (e) {
|
|
|
|
console.warn(e)
|
|
|
|
}
|
|
|
|
},
|
2017-01-16 09:57:03 -08:00
|
|
|
selected () {
|
2018-10-03 11:21:48 -07:00
|
|
|
if (this.selectedVersion === 1) {
|
2018-11-22 21:24:55 -08:00
|
|
|
if (!this.keepRoundness) {
|
|
|
|
this.clearRoundness()
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.keepShadows) {
|
|
|
|
this.clearShadows()
|
|
|
|
}
|
|
|
|
|
2018-11-22 23:17:01 -08:00
|
|
|
if (!this.keepOpacity) {
|
|
|
|
this.clearOpacity()
|
|
|
|
}
|
|
|
|
|
2018-10-04 08:16:14 -07:00
|
|
|
this.clearV1()
|
2018-11-22 21:24:55 -08:00
|
|
|
|
2018-10-03 11:21:48 -07:00
|
|
|
this.bgColorLocal = this.selected[1]
|
2018-10-07 09:59:22 -07:00
|
|
|
this.fgColorLocal = this.selected[2]
|
2018-10-03 11:21:48 -07:00
|
|
|
this.textColorLocal = this.selected[3]
|
|
|
|
this.linkColorLocal = this.selected[4]
|
2018-10-21 05:25:21 -07:00
|
|
|
this.cRedColorLocal = this.selected[5]
|
|
|
|
this.cGreenColorLocal = this.selected[6]
|
|
|
|
this.cBlueColorLocal = this.selected[7]
|
|
|
|
this.cOrangeColorLocal = this.selected[8]
|
2018-11-21 17:37:49 -08:00
|
|
|
} else if (this.selectedVersion >= 2) {
|
|
|
|
this.normalizeLocalState(this.selected.theme, 2)
|
2018-10-03 11:21:48 -07:00
|
|
|
}
|
2017-01-16 09:57:03 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|