2020-01-12 02:00:41 +00:00
|
|
|
import {
|
|
|
|
rgb2hex,
|
|
|
|
hex2rgb,
|
2020-01-12 15:58:26 +00:00
|
|
|
getContrastRatioLayers
|
2020-05-10 03:46:06 +00:00
|
|
|
} from 'src/services/color_convert/color_convert.js'
|
2020-01-02 18:36:10 +00:00
|
|
|
import {
|
2020-01-19 22:34:49 +00:00
|
|
|
DEFAULT_SHADOWS,
|
2020-01-02 18:36:10 +00:00
|
|
|
generateColors,
|
|
|
|
generateShadows,
|
|
|
|
generateRadii,
|
|
|
|
generateFonts,
|
|
|
|
composePreset,
|
2020-01-19 23:31:54 +00:00
|
|
|
getThemes,
|
2020-01-22 21:26:24 +00:00
|
|
|
shadows2to3,
|
|
|
|
colors2to3
|
2020-05-10 03:46:06 +00:00
|
|
|
} from 'src/services/style_setter/style_setter.js'
|
2021-03-08 17:42:24 +00:00
|
|
|
import {
|
|
|
|
newImporter,
|
|
|
|
newExporter
|
|
|
|
} from 'src/services/export_import/export_import.js'
|
2020-01-23 21:19:48 +00:00
|
|
|
import {
|
|
|
|
SLOT_INHERITANCE
|
2020-05-10 03:46:06 +00:00
|
|
|
} from 'src/services/theme_data/pleromafe.js'
|
2020-01-12 15:46:07 +00:00
|
|
|
import {
|
|
|
|
CURRENT_VERSION,
|
2020-01-16 18:53:05 +00:00
|
|
|
OPACITIES,
|
2020-01-16 19:34:33 +00:00
|
|
|
getLayers,
|
|
|
|
getOpacitySlot
|
2020-05-10 03:46:06 +00:00
|
|
|
} from 'src/services/theme_data/theme_data.service.js'
|
|
|
|
import ColorInput from 'src/components/color_input/color_input.vue'
|
|
|
|
import RangeInput from 'src/components/range_input/range_input.vue'
|
|
|
|
import OpacityInput from 'src/components/opacity_input/opacity_input.vue'
|
|
|
|
import ShadowControl from 'src/components/shadow_control/shadow_control.vue'
|
|
|
|
import FontControl from 'src/components/font_control/font_control.vue'
|
|
|
|
import ContrastRatio from 'src/components/contrast_ratio/contrast_ratio.vue'
|
2021-04-18 11:58:02 +00:00
|
|
|
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
2020-05-10 03:46:06 +00:00
|
|
|
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
2021-03-11 14:11:44 +00:00
|
|
|
import Select from 'src/components/select/select.vue'
|
2020-05-10 03:46:06 +00:00
|
|
|
|
2018-12-10 23:46:17 +00:00
|
|
|
import Preview from './preview.vue'
|
2017-11-20 20:45:09 +00:00
|
|
|
|
2018-11-20 17:58:20 +00:00
|
|
|
// List of color values used in v1
|
2018-11-19 17:22:46 +00:00
|
|
|
const v1OnlyNames = [
|
|
|
|
'bg',
|
|
|
|
'fg',
|
|
|
|
'text',
|
|
|
|
'link',
|
|
|
|
'cRed',
|
|
|
|
'cGreen',
|
|
|
|
'cBlue',
|
|
|
|
'cOrange'
|
|
|
|
].map(_ => _ + 'ColorLocal')
|
|
|
|
|
2022-07-17 13:13:51 +00:00
|
|
|
// if color doesn't match regex, it's not a color
|
|
|
|
const isColor = (color) => /^#[0-9a-f]{6}$/i.test(color)
|
|
|
|
|
2019-12-29 22:45:48 +00:00
|
|
|
const colorConvert = (color) => {
|
2022-07-17 13:13:51 +00:00
|
|
|
if (color.startsWith('--') || color === 'transparent' || !isColor(color)) {
|
2019-12-29 22:45:48 +00:00
|
|
|
return color
|
|
|
|
} else {
|
|
|
|
return hex2rgb(color)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-16 17:57:03 +00:00
|
|
|
export default {
|
2017-02-17 17:21:02 +00:00
|
|
|
data () {
|
|
|
|
return {
|
2021-03-08 17:42:24 +00:00
|
|
|
themeImporter: newImporter({
|
|
|
|
validator: this.importValidator,
|
|
|
|
onImport: this.onImport,
|
|
|
|
onImportFailure: this.onImportFailure
|
|
|
|
}),
|
|
|
|
themeExporter: newExporter({
|
|
|
|
filename: 'pleroma_theme',
|
|
|
|
getExportedObject: () => this.exportedTheme
|
|
|
|
}),
|
2017-02-17 17:21:02 +00:00
|
|
|
availableStyles: [],
|
2021-06-07 20:48:46 +00:00
|
|
|
selected: '',
|
|
|
|
selectedTheme: this.$store.getters.mergedConfig.theme,
|
2020-01-21 22:37:19 +00:00
|
|
|
themeWarning: undefined,
|
|
|
|
tempImportFile: undefined,
|
2020-02-11 22:45:37 +00:00
|
|
|
engineVersion: 0,
|
2018-10-02 18:43:58 +00:00
|
|
|
|
2018-11-25 16:12:38 +00:00
|
|
|
previewShadows: {},
|
|
|
|
previewColors: {},
|
|
|
|
previewRadii: {},
|
2018-11-25 18:48:16 +00:00
|
|
|
previewFonts: {},
|
2018-11-25 16:12:38 +00:00
|
|
|
|
|
|
|
shadowsInvalid: true,
|
|
|
|
colorsInvalid: true,
|
|
|
|
radiiInvalid: true,
|
|
|
|
|
2018-12-11 13:36:06 +00:00
|
|
|
keepColor: false,
|
2018-11-23 05:24:55 +00:00
|
|
|
keepShadows: false,
|
2018-11-23 07:17:01 +00:00
|
|
|
keepOpacity: false,
|
2018-11-23 05:24:55 +00:00
|
|
|
keepRoundness: false,
|
2018-11-25 18:48:16 +00:00
|
|
|
keepFonts: false,
|
2018-11-23 05:24:55 +00:00
|
|
|
|
2020-01-12 15:46:07 +00:00
|
|
|
...Object.keys(SLOT_INHERITANCE)
|
|
|
|
.map(key => [key, ''])
|
|
|
|
.reduce((acc, [key, val]) => ({ ...acc, [ key + 'ColorLocal' ]: val }), {}),
|
2018-10-07 16:59:22 +00:00
|
|
|
|
2020-01-16 18:53:05 +00:00
|
|
|
...Object.keys(OPACITIES)
|
2020-01-19 22:34:49 +00:00
|
|
|
.map(key => [key, ''])
|
2020-01-12 15:46:07 +00:00
|
|
|
.reduce((acc, [key, val]) => ({ ...acc, [ key + 'OpacityLocal' ]: val }), {}),
|
2018-10-02 18:43:58 +00:00
|
|
|
|
2018-11-19 17:22:46 +00:00
|
|
|
shadowSelected: undefined,
|
|
|
|
shadowsLocal: {},
|
2018-11-25 18:48:16 +00:00
|
|
|
fontsLocal: {},
|
2018-11-19 17:22:46 +00:00
|
|
|
|
2018-04-07 23:39:39 +00:00
|
|
|
btnRadiusLocal: '',
|
2018-04-15 04:25:59 +00:00
|
|
|
inputRadiusLocal: '',
|
2018-11-23 04:28:53 +00:00
|
|
|
checkboxRadiusLocal: '',
|
2018-04-07 23:39:39 +00:00
|
|
|
panelRadiusLocal: '',
|
|
|
|
avatarRadiusLocal: '',
|
|
|
|
avatarAltRadiusLocal: '',
|
|
|
|
attachmentRadiusLocal: '',
|
2020-05-07 13:10:53 +00:00
|
|
|
tooltipRadiusLocal: '',
|
|
|
|
chatMessageRadiusLocal: ''
|
2017-02-17 17:21:02 +00:00
|
|
|
}
|
|
|
|
},
|
2017-01-16 17:57:03 +00:00
|
|
|
created () {
|
|
|
|
const self = this
|
2017-11-17 15:24:42 +00:00
|
|
|
|
2020-01-16 22:27:46 +00:00
|
|
|
getThemes()
|
|
|
|
.then((promises) => {
|
|
|
|
return Promise.all(
|
|
|
|
Object.entries(promises)
|
|
|
|
.map(([k, v]) => v.then(res => [k, res]))
|
|
|
|
)
|
|
|
|
})
|
|
|
|
.then(themes => themes.reduce((acc, [k, v]) => {
|
|
|
|
if (v) {
|
|
|
|
return {
|
|
|
|
...acc,
|
|
|
|
[k]: v
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return acc
|
|
|
|
}
|
|
|
|
}, {}))
|
|
|
|
.then((themesComplete) => {
|
|
|
|
self.availableStyles = themesComplete
|
|
|
|
})
|
2017-11-17 15:24:42 +00:00
|
|
|
},
|
2017-11-18 11:13:51 +00:00
|
|
|
mounted () {
|
2020-01-21 22:37:19 +00:00
|
|
|
this.loadThemeFromLocalStorage()
|
2018-11-20 20:25:38 +00:00
|
|
|
if (typeof this.shadowSelected === 'undefined') {
|
|
|
|
this.shadowSelected = this.shadowsAvailable[0]
|
|
|
|
}
|
2018-10-02 18:43:58 +00:00
|
|
|
},
|
|
|
|
computed: {
|
2020-01-21 22:37:19 +00:00
|
|
|
themeWarningHelp () {
|
|
|
|
if (!this.themeWarning) return
|
|
|
|
const t = this.$t
|
|
|
|
const pre = 'settings.style.switcher.help.'
|
|
|
|
const {
|
|
|
|
origin,
|
|
|
|
themeEngineVersion,
|
|
|
|
type,
|
|
|
|
noActionsPossible
|
|
|
|
} = this.themeWarning
|
|
|
|
if (origin === 'file') {
|
|
|
|
// Loaded v2 theme from file
|
|
|
|
if (themeEngineVersion === 2 && type === 'wrong_version') {
|
|
|
|
return t(pre + 'v2_imported')
|
|
|
|
}
|
|
|
|
if (themeEngineVersion > CURRENT_VERSION) {
|
|
|
|
return t(pre + 'future_version_imported') + ' ' +
|
|
|
|
(
|
|
|
|
noActionsPossible
|
|
|
|
? t(pre + 'snapshot_missing')
|
|
|
|
: t(pre + 'snapshot_present')
|
|
|
|
)
|
|
|
|
}
|
|
|
|
if (themeEngineVersion < CURRENT_VERSION) {
|
|
|
|
return t(pre + 'future_version_imported') + ' ' +
|
|
|
|
(
|
|
|
|
noActionsPossible
|
|
|
|
? t(pre + 'snapshot_missing')
|
|
|
|
: t(pre + 'snapshot_present')
|
|
|
|
)
|
|
|
|
}
|
|
|
|
} else if (origin === 'localStorage') {
|
2020-01-22 00:44:39 +00:00
|
|
|
if (type === 'snapshot_source_mismatch') {
|
|
|
|
return t(pre + 'snapshot_source_mismatch')
|
|
|
|
}
|
2020-01-21 22:37:19 +00:00
|
|
|
// FE upgraded from v2
|
|
|
|
if (themeEngineVersion === 2) {
|
2020-01-21 23:28:05 +00:00
|
|
|
return t(pre + 'upgraded_from_v2')
|
2020-01-21 22:37:19 +00:00
|
|
|
}
|
|
|
|
// Admin downgraded FE
|
|
|
|
if (themeEngineVersion > CURRENT_VERSION) {
|
2020-01-21 22:53:51 +00:00
|
|
|
return t(pre + 'fe_downgraded') + ' ' +
|
|
|
|
(
|
|
|
|
noActionsPossible
|
|
|
|
? t(pre + 'migration_snapshot_ok')
|
|
|
|
: t(pre + 'migration_snapshot_gone')
|
|
|
|
)
|
2020-01-21 22:37:19 +00:00
|
|
|
}
|
|
|
|
// Admin upgraded FE
|
|
|
|
if (themeEngineVersion < CURRENT_VERSION) {
|
2020-01-21 22:53:51 +00:00
|
|
|
return t(pre + 'fe_upgraded') + ' ' +
|
|
|
|
(
|
|
|
|
noActionsPossible
|
|
|
|
? t(pre + 'migration_snapshot_ok')
|
|
|
|
: t(pre + 'migration_snapshot_gone')
|
|
|
|
)
|
2020-01-21 22:37:19 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
2018-10-03 18:21:48 +00:00
|
|
|
selectedVersion () {
|
2021-06-07 20:48:46 +00:00
|
|
|
return Array.isArray(this.selectedTheme) ? 1 : 2
|
2018-10-03 18:21:48 +00:00
|
|
|
},
|
2018-11-19 17:22:46 +00:00
|
|
|
currentColors () {
|
2020-01-12 15:46:07 +00:00
|
|
|
return Object.keys(SLOT_INHERITANCE)
|
|
|
|
.map(key => [key, this[key + 'ColorLocal']])
|
|
|
|
.reduce((acc, [key, val]) => ({ ...acc, [ key ]: val }), {})
|
2018-10-02 18:43:58 +00:00
|
|
|
},
|
2018-11-19 17:22:46 +00:00
|
|
|
currentOpacity () {
|
2020-01-16 18:53:05 +00:00
|
|
|
return Object.keys(OPACITIES)
|
2020-01-19 22:34:49 +00:00
|
|
|
.map(key => [key, this[key + 'OpacityLocal']])
|
2020-01-13 00:08:39 +00:00
|
|
|
.reduce((acc, [key, val]) => ({ ...acc, [ key ]: val }), {})
|
2018-11-19 17:22:46 +00:00
|
|
|
},
|
|
|
|
currentRadii () {
|
|
|
|
return {
|
|
|
|
btn: this.btnRadiusLocal,
|
|
|
|
input: this.inputRadiusLocal,
|
2018-11-23 04:28:53 +00:00
|
|
|
checkbox: this.checkboxRadiusLocal,
|
2018-11-19 17:22:46 +00:00
|
|
|
panel: this.panelRadiusLocal,
|
|
|
|
avatar: this.avatarRadiusLocal,
|
|
|
|
avatarAlt: this.avatarAltRadiusLocal,
|
|
|
|
tooltip: this.tooltipRadiusLocal,
|
2020-05-07 13:10:53 +00:00
|
|
|
attachment: this.attachmentRadiusLocal,
|
|
|
|
chatMessage: this.chatMessageRadiusLocal
|
2018-11-19 17:22:46 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
preview () {
|
2018-11-25 18:48:16 +00:00
|
|
|
return composePreset(this.previewColors, this.previewRadii, this.previewShadows, this.previewFonts)
|
2018-11-19 17:22:46 +00:00
|
|
|
},
|
2018-10-04 15:16:14 +00:00
|
|
|
previewTheme () {
|
2018-11-25 18:48:16 +00:00
|
|
|
if (!this.preview.theme.colors) return { colors: {}, opacity: {}, radii: {}, shadows: {}, fonts: {} }
|
2018-10-04 15:16:14 +00:00
|
|
|
return this.preview.theme
|
|
|
|
},
|
2018-11-20 20:25:38 +00:00
|
|
|
// This needs optimization maybe
|
2018-10-09 21:07:28 +00:00
|
|
|
previewContrast () {
|
2020-01-19 23:31:54 +00:00
|
|
|
try {
|
|
|
|
if (!this.previewTheme.colors.bg) return {}
|
|
|
|
const colors = this.previewTheme.colors
|
|
|
|
const opacity = this.previewTheme.opacity
|
|
|
|
if (!colors.bg) return {}
|
2022-07-17 13:13:51 +00:00
|
|
|
if (!isColor(colors.bg)) return {}
|
2020-01-19 23:31:54 +00: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
|
|
|
|
})
|
|
|
|
const colorsConverted = Object.entries(colors).reduce((acc, [key, value]) => ({ ...acc, [key]: colorConvert(value) }), {})
|
|
|
|
|
|
|
|
const ratios = Object.entries(SLOT_INHERITANCE).reduce((acc, [key, value]) => {
|
|
|
|
const slotIsBaseText = key === 'text' || key === 'link'
|
|
|
|
const slotIsText = slotIsBaseText || (
|
|
|
|
typeof value === 'object' && value !== null && value.textColor
|
|
|
|
)
|
|
|
|
if (!slotIsText) return acc
|
|
|
|
const { layer, variant } = slotIsBaseText ? { layer: 'bg' } : value
|
|
|
|
const background = variant || layer
|
2020-01-22 22:35:56 +00:00
|
|
|
const opacitySlot = getOpacitySlot(background)
|
2020-01-19 23:31:54 +00:00
|
|
|
const textColors = [
|
|
|
|
key,
|
|
|
|
...(background === 'bg' ? ['cRed', 'cGreen', 'cBlue', 'cOrange'] : [])
|
|
|
|
]
|
|
|
|
|
|
|
|
const layers = getLayers(
|
|
|
|
layer,
|
|
|
|
variant || layer,
|
|
|
|
opacitySlot,
|
|
|
|
colorsConverted,
|
|
|
|
opacity
|
|
|
|
)
|
2020-01-12 15:46:07 +00:00
|
|
|
|
2020-01-19 23:31:54 +00:00
|
|
|
return {
|
|
|
|
...acc,
|
|
|
|
...textColors.reduce((acc, textColorKey) => {
|
|
|
|
const newKey = slotIsBaseText
|
2020-01-19 23:45:48 +00:00
|
|
|
? 'bg' + textColorKey[0].toUpperCase() + textColorKey.slice(1)
|
|
|
|
: textColorKey
|
2020-01-19 23:31:54 +00:00
|
|
|
return {
|
|
|
|
...acc,
|
|
|
|
[newKey]: getContrastRatioLayers(
|
|
|
|
colorsConverted[textColorKey],
|
|
|
|
layers,
|
|
|
|
colorsConverted[textColorKey]
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}, {})
|
|
|
|
}
|
|
|
|
}, {})
|
2018-10-09 21:07:28 +00:00
|
|
|
|
2020-01-19 23:31:54 +00:00
|
|
|
return Object.entries(ratios).reduce((acc, [k, v]) => { acc[k] = hints(v); return acc }, {})
|
|
|
|
} catch (e) {
|
|
|
|
console.warn('Failure computing contrasts', e)
|
|
|
|
}
|
2018-10-09 21:07:28 +00:00
|
|
|
},
|
2018-10-04 15:16:14 +00:00
|
|
|
previewRules () {
|
2018-11-19 17:22:46 +00:00
|
|
|
if (!this.preview.rules) return ''
|
2018-11-25 18:48:16 +00:00
|
|
|
return [
|
|
|
|
...Object.values(this.preview.rules),
|
|
|
|
'color: var(--text)',
|
|
|
|
'font-family: var(--interfaceFont, sans-serif)'
|
|
|
|
].join(';')
|
2018-11-19 01:40:25 +00:00
|
|
|
},
|
|
|
|
shadowsAvailable () {
|
2020-01-19 22:34:49 +00:00
|
|
|
return Object.keys(DEFAULT_SHADOWS).sort()
|
2018-11-19 01:40:25 +00:00
|
|
|
},
|
2018-11-19 15:15:27 +00:00
|
|
|
currentShadowOverriden: {
|
|
|
|
get () {
|
2018-11-19 17:22:46 +00:00
|
|
|
return !!this.currentShadow
|
2018-11-19 15:15:27 +00:00
|
|
|
},
|
|
|
|
set (val) {
|
|
|
|
if (val) {
|
2021-04-25 10:24:08 +00:00
|
|
|
this.shadowsLocal[this.shadowSelected] = this.currentShadowFallback.map(_ => Object.assign({}, _))
|
2018-11-19 15:15:27 +00:00
|
|
|
} else {
|
2021-04-25 10:24:08 +00:00
|
|
|
delete this.shadowsLocal[this.shadowSelected]
|
2018-11-19 15:15:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
currentShadowFallback () {
|
2020-01-19 22:34:49 +00:00
|
|
|
return (this.previewTheme.shadows || {})[this.shadowSelected]
|
2018-11-19 15:15:27 +00:00
|
|
|
},
|
|
|
|
currentShadow: {
|
|
|
|
get () {
|
|
|
|
return this.shadowsLocal[this.shadowSelected]
|
|
|
|
},
|
|
|
|
set (v) {
|
2021-04-25 10:24:08 +00:00
|
|
|
this.shadowsLocal[this.shadowSelected] = v
|
2018-11-19 15:15:27 +00:00
|
|
|
}
|
2018-11-25 16:12:38 +00:00
|
|
|
},
|
|
|
|
themeValid () {
|
|
|
|
return !this.shadowsInvalid && !this.colorsInvalid && !this.radiiInvalid
|
2018-12-10 23:46:17 +00:00
|
|
|
},
|
|
|
|
exportedTheme () {
|
2018-12-11 13:36:06 +00:00
|
|
|
const saveEverything = (
|
|
|
|
!this.keepFonts &&
|
|
|
|
!this.keepShadows &&
|
|
|
|
!this.keepOpacity &&
|
|
|
|
!this.keepRoundness &&
|
|
|
|
!this.keepColor
|
|
|
|
)
|
|
|
|
|
2020-01-02 18:36:10 +00:00
|
|
|
const source = {
|
|
|
|
themeEngineVersion: CURRENT_VERSION
|
|
|
|
}
|
2018-12-11 13:36:06 +00:00
|
|
|
|
|
|
|
if (this.keepFonts || saveEverything) {
|
2020-01-02 18:36:10 +00:00
|
|
|
source.fonts = this.fontsLocal
|
2018-11-26 18:07:22 +00:00
|
|
|
}
|
2018-12-11 13:36:06 +00:00
|
|
|
if (this.keepShadows || saveEverything) {
|
2020-01-02 18:36:10 +00:00
|
|
|
source.shadows = this.shadowsLocal
|
2018-11-26 18:07:22 +00:00
|
|
|
}
|
2018-12-11 13:36:06 +00:00
|
|
|
if (this.keepOpacity || saveEverything) {
|
2020-01-02 18:36:10 +00:00
|
|
|
source.opacity = this.currentOpacity
|
2018-11-26 18:07:22 +00:00
|
|
|
}
|
2018-12-11 13:36:06 +00:00
|
|
|
if (this.keepColor || saveEverything) {
|
2020-01-02 18:36:10 +00:00
|
|
|
source.colors = this.currentColors
|
2018-11-26 18:07:22 +00:00
|
|
|
}
|
2018-12-11 13:36:06 +00:00
|
|
|
if (this.keepRoundness || saveEverything) {
|
2020-01-02 18:36:10 +00:00
|
|
|
source.radii = this.currentRadii
|
2018-11-26 18:07:22 +00:00
|
|
|
}
|
|
|
|
|
2020-01-22 00:44:39 +00:00
|
|
|
const theme = {
|
|
|
|
themeEngineVersion: CURRENT_VERSION,
|
|
|
|
...this.previewTheme
|
|
|
|
}
|
2020-01-02 18:36:10 +00:00
|
|
|
|
2018-12-10 23:46:17 +00:00
|
|
|
return {
|
2020-01-02 18:36:10 +00:00
|
|
|
// To separate from other random JSON files and possible future source formats
|
|
|
|
_pleroma_theme_version: 2, theme, source
|
2018-12-10 23:46:17 +00:00
|
|
|
}
|
2022-03-24 22:01:20 +00:00
|
|
|
},
|
|
|
|
isActive () {
|
|
|
|
const tabSwitcher = this.$parent
|
|
|
|
return tabSwitcher ? tabSwitcher.isActive('theme') : false
|
2018-12-10 23:46:17 +00:00
|
|
|
}
|
|
|
|
},
|
|
|
|
components: {
|
|
|
|
ColorInput,
|
|
|
|
OpacityInput,
|
|
|
|
RangeInput,
|
|
|
|
ContrastRatio,
|
|
|
|
ShadowControl,
|
|
|
|
FontControl,
|
|
|
|
TabSwitcher,
|
|
|
|
Preview,
|
2021-03-11 14:11:44 +00:00
|
|
|
Checkbox,
|
|
|
|
Select
|
2018-12-10 23:46:17 +00:00
|
|
|
},
|
|
|
|
methods: {
|
2020-01-21 22:37:19 +00:00
|
|
|
loadTheme (
|
|
|
|
{
|
|
|
|
theme,
|
|
|
|
source,
|
|
|
|
_pleroma_theme_version: fileVersion
|
|
|
|
},
|
|
|
|
origin,
|
|
|
|
forceUseSource = false
|
|
|
|
) {
|
2020-02-11 23:26:01 +00:00
|
|
|
this.dismissWarning()
|
2020-01-21 22:37:19 +00:00
|
|
|
if (!source && !theme) {
|
|
|
|
throw new Error('Can\'t load theme: empty')
|
|
|
|
}
|
2020-01-23 20:04:05 +00:00
|
|
|
const version = (origin === 'localStorage' && !theme.colors)
|
2020-01-21 22:37:19 +00:00
|
|
|
? 'l1'
|
|
|
|
: fileVersion
|
2020-01-22 00:44:39 +00:00
|
|
|
const snapshotEngineVersion = (theme || {}).themeEngineVersion
|
2020-01-21 22:37:19 +00:00
|
|
|
const themeEngineVersion = (source || {}).themeEngineVersion || 2
|
|
|
|
const versionsMatch = themeEngineVersion === CURRENT_VERSION
|
2020-01-22 00:44:39 +00:00
|
|
|
const sourceSnapshotMismatch = (
|
|
|
|
theme !== undefined &&
|
|
|
|
source !== undefined &&
|
|
|
|
themeEngineVersion !== snapshotEngineVersion
|
|
|
|
)
|
2020-01-21 22:37:19 +00:00
|
|
|
// Force loading of source if user requested it or if snapshot
|
|
|
|
// is unavailable
|
|
|
|
const forcedSourceLoad = (source && forceUseSource) || !theme
|
2020-01-22 00:44:39 +00:00
|
|
|
if (!(versionsMatch && !sourceSnapshotMismatch) &&
|
2020-01-21 22:37:19 +00:00
|
|
|
!forcedSourceLoad &&
|
|
|
|
version !== 'l1' &&
|
|
|
|
origin !== 'defaults'
|
|
|
|
) {
|
2020-01-23 20:04:05 +00:00
|
|
|
if (sourceSnapshotMismatch && origin === 'localStorage') {
|
2020-01-22 00:44:39 +00:00
|
|
|
this.themeWarning = {
|
|
|
|
origin,
|
|
|
|
themeEngineVersion,
|
|
|
|
type: 'snapshot_source_mismatch'
|
|
|
|
}
|
|
|
|
} else if (!theme) {
|
2020-01-21 22:37:19 +00:00
|
|
|
this.themeWarning = {
|
|
|
|
origin,
|
|
|
|
noActionsPossible: true,
|
|
|
|
themeEngineVersion,
|
|
|
|
type: 'no_snapshot_old_version'
|
|
|
|
}
|
|
|
|
} else if (!versionsMatch) {
|
|
|
|
this.themeWarning = {
|
|
|
|
origin,
|
|
|
|
noActionsPossible: !source,
|
|
|
|
themeEngineVersion,
|
|
|
|
type: 'wrong_version'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
this.normalizeLocalState(theme, version, source, forcedSourceLoad)
|
|
|
|
},
|
|
|
|
forceLoadLocalStorage () {
|
|
|
|
this.loadThemeFromLocalStorage(true)
|
|
|
|
},
|
|
|
|
dismissWarning () {
|
|
|
|
this.themeWarning = undefined
|
|
|
|
this.tempImportFile = undefined
|
|
|
|
},
|
|
|
|
forceLoad () {
|
|
|
|
const { origin } = this.themeWarning
|
|
|
|
switch (origin) {
|
2020-01-22 00:53:40 +00:00
|
|
|
case 'localStorage':
|
2020-01-21 22:37:19 +00:00
|
|
|
this.loadThemeFromLocalStorage(true)
|
|
|
|
break
|
|
|
|
case 'file':
|
|
|
|
this.onImport(this.tempImportFile, true)
|
|
|
|
break
|
|
|
|
}
|
2020-01-21 23:28:05 +00:00
|
|
|
this.dismissWarning()
|
2020-01-21 22:37:19 +00:00
|
|
|
},
|
2020-01-22 00:53:40 +00:00
|
|
|
forceSnapshot () {
|
2020-01-22 00:44:39 +00:00
|
|
|
const { origin } = this.themeWarning
|
|
|
|
switch (origin) {
|
2020-01-22 00:53:40 +00:00
|
|
|
case 'localStorage':
|
2020-01-22 00:44:39 +00:00
|
|
|
this.loadThemeFromLocalStorage(false, true)
|
|
|
|
break
|
|
|
|
case 'file':
|
2021-06-12 17:42:17 +00:00
|
|
|
console.error('Forcing snapshot from file is not supported yet')
|
2020-01-22 00:44:39 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
this.dismissWarning()
|
|
|
|
},
|
|
|
|
loadThemeFromLocalStorage (confirmLoadSource = false, forceSnapshot = false) {
|
2020-01-21 22:37:19 +00:00
|
|
|
const {
|
|
|
|
customTheme: theme,
|
|
|
|
customThemeSource: source
|
|
|
|
} = this.$store.getters.mergedConfig
|
|
|
|
if (!theme && !source) {
|
|
|
|
// Anon user or never touched themes
|
|
|
|
this.loadTheme(
|
|
|
|
this.$store.state.instance.themeData,
|
|
|
|
'defaults',
|
|
|
|
confirmLoadSource
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
this.loadTheme(
|
2020-01-22 00:44:39 +00:00
|
|
|
{
|
|
|
|
theme,
|
|
|
|
source: forceSnapshot ? theme : source
|
|
|
|
},
|
2020-01-21 22:37:19 +00:00
|
|
|
'localStorage',
|
|
|
|
confirmLoadSource
|
|
|
|
)
|
|
|
|
}
|
|
|
|
},
|
2017-11-17 15:24:42 +00:00
|
|
|
setCustomTheme () {
|
2018-10-02 18:43:58 +00:00
|
|
|
this.$store.dispatch('setOption', {
|
|
|
|
name: 'customTheme',
|
2020-01-22 00:44:39 +00:00
|
|
|
value: {
|
|
|
|
themeEngineVersion: CURRENT_VERSION,
|
|
|
|
...this.previewTheme
|
|
|
|
}
|
2020-01-21 22:37:19 +00:00
|
|
|
})
|
|
|
|
this.$store.dispatch('setOption', {
|
|
|
|
name: 'customThemeSource',
|
2018-11-19 15:15:27 +00:00
|
|
|
value: {
|
2020-01-21 22:37:19 +00:00
|
|
|
themeEngineVersion: CURRENT_VERSION,
|
2018-11-19 17:22:46 +00:00
|
|
|
shadows: this.shadowsLocal,
|
2018-11-25 18:48:16 +00:00
|
|
|
fonts: this.fontsLocal,
|
2018-11-19 17:22:46 +00:00
|
|
|
opacity: this.currentOpacity,
|
|
|
|
colors: this.currentColors,
|
|
|
|
radii: this.currentRadii
|
2018-11-19 15:15:27 +00:00
|
|
|
}
|
2018-10-02 18:43:58 +00:00
|
|
|
})
|
2018-06-28 00:07:50 +00:00
|
|
|
},
|
2020-01-19 22:34:49 +00:00
|
|
|
updatePreviewColorsAndShadows () {
|
|
|
|
this.previewColors = generateColors({
|
|
|
|
opacity: this.currentOpacity,
|
|
|
|
colors: this.currentColors
|
|
|
|
})
|
|
|
|
this.previewShadows = generateShadows(
|
2020-02-11 22:45:37 +00:00
|
|
|
{ shadows: this.shadowsLocal, opacity: this.previewTheme.opacity, themeEngineVersion: this.engineVersion },
|
2020-01-19 22:34:49 +00:00
|
|
|
this.previewColors.theme.colors,
|
|
|
|
this.previewColors.mod
|
|
|
|
)
|
|
|
|
},
|
2021-03-08 17:42:24 +00:00
|
|
|
importTheme () { this.themeImporter.importData() },
|
|
|
|
exportTheme () { this.themeExporter.exportData() },
|
2020-01-21 22:37:19 +00:00
|
|
|
onImport (parsed, forceSource = false) {
|
|
|
|
this.tempImportFile = parsed
|
|
|
|
this.loadTheme(parsed, 'file', forceSource)
|
2018-12-10 23:46:17 +00:00
|
|
|
},
|
2021-03-08 17:42:24 +00:00
|
|
|
onImportFailure (result) {
|
|
|
|
this.$store.dispatch('pushGlobalNotice', { messageKey: 'settings.invalid_theme_imported', level: 'error' })
|
|
|
|
},
|
2018-12-10 23:46:17 +00:00
|
|
|
importValidator (parsed) {
|
|
|
|
const version = parsed._pleroma_theme_version
|
|
|
|
return version >= 1 || version <= 2
|
|
|
|
},
|
2018-11-23 08:36:36 +00:00
|
|
|
clearAll () {
|
2020-01-21 22:37:19 +00:00
|
|
|
this.loadThemeFromLocalStorage()
|
2018-11-23 08:36:36 +00:00
|
|
|
},
|
|
|
|
|
2018-11-19 17:22:46 +00:00
|
|
|
// Clears all the extra stuff when loading V1 theme
|
2018-10-03 18:21:48 +00:00
|
|
|
clearV1 () {
|
2018-11-19 17:22:46 +00:00
|
|
|
Object.keys(this.$data)
|
|
|
|
.filter(_ => _.endsWith('ColorLocal') || _.endsWith('OpacityLocal'))
|
|
|
|
.filter(_ => !v1OnlyNames.includes(_))
|
|
|
|
.forEach(key => {
|
2021-04-25 10:24:08 +00:00
|
|
|
this.$data[key] = undefined
|
2018-11-19 17:22:46 +00:00
|
|
|
})
|
2018-10-03 18:21:48 +00:00
|
|
|
},
|
|
|
|
|
2018-11-23 05:24:55 +00:00
|
|
|
clearRoundness () {
|
|
|
|
Object.keys(this.$data)
|
|
|
|
.filter(_ => _.endsWith('RadiusLocal'))
|
|
|
|
.forEach(key => {
|
2021-04-25 10:24:08 +00:00
|
|
|
this.$data[key] = undefined
|
2018-11-23 05:24:55 +00:00
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2018-11-23 07:17:01 +00:00
|
|
|
clearOpacity () {
|
|
|
|
Object.keys(this.$data)
|
|
|
|
.filter(_ => _.endsWith('OpacityLocal'))
|
|
|
|
.forEach(key => {
|
2021-04-25 10:24:08 +00:00
|
|
|
this.$data[key] = undefined
|
2018-11-23 07:17:01 +00:00
|
|
|
})
|
|
|
|
},
|
|
|
|
|
2018-11-23 05:24:55 +00:00
|
|
|
clearShadows () {
|
|
|
|
this.shadowsLocal = {}
|
|
|
|
},
|
|
|
|
|
2018-11-25 18:48:16 +00:00
|
|
|
clearFonts () {
|
|
|
|
this.fontsLocal = {}
|
|
|
|
},
|
|
|
|
|
2018-10-04 15:16:14 +00:00
|
|
|
/**
|
2018-11-26 18:07:22 +00:00
|
|
|
* This applies stored theme data onto form. Supports three versions of data:
|
2020-01-02 18:36:10 +00:00
|
|
|
* v3 (version >= 3) - newest version of themes which supports snapshots for better compatiblity
|
2018-11-26 18:07:22 +00:00
|
|
|
* 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.
|
2020-01-02 18:36:10 +00:00
|
|
|
* @param {Object} theme - theme data (snapshot)
|
2018-11-26 18:07:22 +00:00
|
|
|
* @param {Number} version - version of data. 0 means try to guess based on data. "l1" means v1, locastorage type
|
2020-01-02 18:36:10 +00:00
|
|
|
* @param {Object} source - theme source - this will be used if compatible
|
|
|
|
* @param {Boolean} source - by default source won't be used if version doesn't match since it might render differently
|
|
|
|
* this allows importing source anyway
|
2018-10-04 15:16:14 +00:00
|
|
|
*/
|
2020-01-02 18:36:10 +00:00
|
|
|
normalizeLocalState (theme, version = 0, source, forceSource = false) {
|
2019-12-28 15:02:34 +00:00
|
|
|
let input
|
2020-01-02 18:36:10 +00:00
|
|
|
if (typeof source !== 'undefined') {
|
|
|
|
if (forceSource || source.themeEngineVersion === CURRENT_VERSION) {
|
|
|
|
input = source
|
|
|
|
version = source.themeEngineVersion
|
|
|
|
} else {
|
|
|
|
input = theme
|
|
|
|
}
|
2019-12-28 15:02:34 +00:00
|
|
|
} else {
|
2020-01-02 18:36:10 +00:00
|
|
|
input = theme
|
2019-12-28 15:02:34 +00:00
|
|
|
}
|
|
|
|
|
2018-10-02 18:43:58 +00:00
|
|
|
const radii = input.radii || input
|
2018-11-23 07:17:01 +00:00
|
|
|
const opacity = input.opacity
|
2018-11-19 01:40:25 +00:00
|
|
|
const shadows = input.shadows || {}
|
2018-11-25 18:48:16 +00:00
|
|
|
const fonts = input.fonts || {}
|
2020-01-22 21:26:24 +00:00
|
|
|
const colors = !input.themeEngineVersion
|
2020-01-23 20:26:49 +00:00
|
|
|
? colors2to3(input.colors || input)
|
2020-01-22 21:26:24 +00:00
|
|
|
: input.colors || input
|
2018-10-02 18:43:58 +00:00
|
|
|
|
2018-10-07 16:59:22 +00: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 18:43:58 +00:00
|
|
|
|
2020-02-11 22:45:37 +00:00
|
|
|
this.engineVersion = version
|
|
|
|
|
2018-10-07 16:59:22 +00:00
|
|
|
// Stuff that differs between V1 and V2
|
2018-10-03 18:21:48 +00:00
|
|
|
if (version === 1) {
|
2018-10-07 16:59:22 +00:00
|
|
|
this.fgColorLocal = rgb2hex(colors.btn)
|
|
|
|
this.textColorLocal = rgb2hex(colors.fg)
|
2018-10-03 18:21:48 +00:00
|
|
|
}
|
|
|
|
|
2018-12-11 13:36:06 +00:00
|
|
|
if (!this.keepColor) {
|
|
|
|
this.clearV1()
|
2020-02-11 23:19:48 +00:00
|
|
|
const keys = new Set(version !== 1 ? Object.keys(SLOT_INHERITANCE) : [])
|
2018-12-11 13:36:06 +00:00
|
|
|
if (version === 1 || version === 'l1') {
|
|
|
|
keys
|
|
|
|
.add('bg')
|
|
|
|
.add('link')
|
|
|
|
.add('cRed')
|
|
|
|
.add('cBlue')
|
|
|
|
.add('cGreen')
|
|
|
|
.add('cOrange')
|
|
|
|
}
|
2018-11-26 18:07:22 +00:00
|
|
|
|
2018-12-11 13:36:06 +00:00
|
|
|
keys.forEach(key => {
|
2020-01-12 23:56:29 +00:00
|
|
|
const color = colors[key]
|
|
|
|
const hex = rgb2hex(colors[key])
|
|
|
|
this[key + 'ColorLocal'] = hex === '#aN' ? color : hex
|
2018-12-11 13:36:06 +00:00
|
|
|
})
|
|
|
|
}
|
2018-06-28 00:07:50 +00:00
|
|
|
|
2020-01-19 22:34:49 +00: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
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2018-11-23 05:24:55 +00:00
|
|
|
if (!this.keepRoundness) {
|
|
|
|
this.clearRoundness()
|
2018-11-23 06:02:10 +00: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-23 05:24:55 +00:00
|
|
|
}
|
2018-10-07 19:03:34 +00:00
|
|
|
|
2018-11-23 05:24:55 +00:00
|
|
|
if (!this.keepShadows) {
|
|
|
|
this.clearShadows()
|
2020-01-19 23:31:54 +00:00
|
|
|
if (version === 2) {
|
2020-02-11 22:45:37 +00:00
|
|
|
this.shadowsLocal = shadows2to3(shadows, this.previewTheme.opacity)
|
2020-01-19 23:31:54 +00:00
|
|
|
} else {
|
|
|
|
this.shadowsLocal = shadows
|
|
|
|
}
|
2018-11-23 05:24:55 +00:00
|
|
|
this.shadowSelected = this.shadowsAvailable[0]
|
|
|
|
}
|
2018-11-19 01:40:25 +00:00
|
|
|
|
2018-11-25 18:48:16 +00:00
|
|
|
if (!this.keepFonts) {
|
|
|
|
this.clearFonts()
|
|
|
|
this.fontsLocal = fonts
|
|
|
|
}
|
2017-11-17 15:24:42 +00:00
|
|
|
}
|
2017-01-16 17:57:03 +00:00
|
|
|
},
|
|
|
|
watch: {
|
2018-11-25 16:12:38 +00:00
|
|
|
currentRadii () {
|
|
|
|
try {
|
|
|
|
this.previewRadii = generateRadii({ radii: this.currentRadii })
|
|
|
|
this.radiiInvalid = false
|
|
|
|
} catch (e) {
|
|
|
|
this.radiiInvalid = true
|
|
|
|
console.warn(e)
|
|
|
|
}
|
|
|
|
},
|
2018-11-25 18:48:16 +00:00
|
|
|
shadowsLocal: {
|
|
|
|
handler () {
|
2020-01-19 22:34:49 +00:00
|
|
|
if (Object.getOwnPropertyNames(this.previewColors).length === 1) return
|
2018-11-25 18:48:16 +00:00
|
|
|
try {
|
2020-01-19 22:34:49 +00:00
|
|
|
this.updatePreviewColorsAndShadows()
|
2018-11-25 18:48:16 +00:00
|
|
|
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 16:12:38 +00:00
|
|
|
},
|
|
|
|
currentColors () {
|
|
|
|
try {
|
2020-01-19 22:34:49 +00:00
|
|
|
this.updatePreviewColorsAndShadows()
|
2018-11-25 16:12:38 +00:00
|
|
|
this.colorsInvalid = false
|
2020-01-22 00:15:47 +00:00
|
|
|
this.shadowsInvalid = false
|
2018-11-25 16:12:38 +00:00
|
|
|
} catch (e) {
|
|
|
|
this.colorsInvalid = true
|
2020-01-22 00:15:47 +00:00
|
|
|
this.shadowsInvalid = true
|
2018-11-25 16:12:38 +00:00
|
|
|
console.warn(e)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
currentOpacity () {
|
|
|
|
try {
|
2020-01-19 22:34:49 +00:00
|
|
|
this.updatePreviewColorsAndShadows()
|
2018-11-25 16:12:38 +00:00
|
|
|
} catch (e) {
|
|
|
|
console.warn(e)
|
|
|
|
}
|
|
|
|
},
|
2017-01-16 17:57:03 +00:00
|
|
|
selected () {
|
2021-06-07 20:48:46 +00:00
|
|
|
this.selectedTheme = Object.entries(this.availableStyles).find(([k, s]) => {
|
|
|
|
if (Array.isArray(s)) {
|
|
|
|
console.log(s[0] === this.selected, this.selected)
|
|
|
|
return s[0] === this.selected
|
|
|
|
} else {
|
|
|
|
return s.name === this.selected
|
|
|
|
}
|
|
|
|
})[1]
|
|
|
|
},
|
|
|
|
selectedTheme () {
|
2020-02-11 23:26:01 +00:00
|
|
|
this.dismissWarning()
|
2018-10-03 18:21:48 +00:00
|
|
|
if (this.selectedVersion === 1) {
|
2018-11-23 05:24:55 +00:00
|
|
|
if (!this.keepRoundness) {
|
|
|
|
this.clearRoundness()
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!this.keepShadows) {
|
|
|
|
this.clearShadows()
|
|
|
|
}
|
|
|
|
|
2018-11-23 07:17:01 +00:00
|
|
|
if (!this.keepOpacity) {
|
|
|
|
this.clearOpacity()
|
|
|
|
}
|
|
|
|
|
2018-12-11 13:36:06 +00:00
|
|
|
if (!this.keepColor) {
|
|
|
|
this.clearV1()
|
|
|
|
|
2021-06-07 20:48:46 +00:00
|
|
|
this.bgColorLocal = this.selectedTheme[1]
|
|
|
|
this.fgColorLocal = this.selectedTheme[2]
|
|
|
|
this.textColorLocal = this.selectedTheme[3]
|
|
|
|
this.linkColorLocal = this.selectedTheme[4]
|
|
|
|
this.cRedColorLocal = this.selectedTheme[5]
|
|
|
|
this.cGreenColorLocal = this.selectedTheme[6]
|
|
|
|
this.cBlueColorLocal = this.selectedTheme[7]
|
|
|
|
this.cOrangeColorLocal = this.selectedTheme[8]
|
2018-12-11 13:36:06 +00:00
|
|
|
}
|
2018-11-22 01:37:49 +00:00
|
|
|
} else if (this.selectedVersion >= 2) {
|
2021-06-07 20:48:46 +00:00
|
|
|
this.normalizeLocalState(this.selectedTheme.theme, 2, this.selectedTheme.source)
|
2018-10-03 18:21:48 +00:00
|
|
|
}
|
2017-01-16 17:57:03 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|