aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/boot/after_store.js32
-rw-r--r--src/components/style_switcher/style_switcher.js153
-rw-r--r--src/components/style_switcher/style_switcher.scss4
-rw-r--r--src/components/style_switcher/style_switcher.vue79
-rw-r--r--src/i18n/en.json12
-rw-r--r--src/modules/config.js7
-rw-r--r--src/modules/instance.js17
-rw-r--r--src/services/style_setter/style_setter.js27
8 files changed, 259 insertions, 72 deletions
diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 228a0497..6c4f0e1b 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -5,6 +5,8 @@ import App from '../App.vue'
import { windowWidth } from '../services/window_utils/window_utils'
import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
+import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
+import { applyTheme } from '../services/style_setter/style_setter.js'
const getStatusnetConfig = async ({ store }) => {
try {
@@ -261,7 +263,7 @@ const checkOAuthToken = async ({ store }) => {
try {
await store.dispatch('loginUser', store.getters.getUserToken())
} catch (e) {
- console.log(e)
+ console.error(e)
}
}
resolve()
@@ -269,23 +271,29 @@ const checkOAuthToken = async ({ store }) => {
}
const afterStoreSetup = async ({ store, i18n }) => {
- if (store.state.config.customTheme) {
- // This is a hack to deal with async loading of config.json and themes
- // See: style_setter.js, setPreset()
- window.themeLoaded = true
- store.dispatch('setOption', {
- name: 'customTheme',
- value: store.state.config.customTheme
- })
- }
-
const width = windowWidth()
store.dispatch('setMobileLayout', width <= 800)
+ await setConfig({ store })
+
+ const { customTheme, customThemeSource } = store.state.config
+ const { theme } = store.state.instance
+ const customThemePresent = customThemeSource || customTheme
+
+ if (customThemePresent) {
+ if (customThemeSource && customThemeSource.version === CURRENT_VERSION) {
+ applyTheme(customThemeSource)
+ } else {
+ applyTheme(customTheme)
+ }
+ } else if (theme) {
+ // do nothing, it will load asynchronously
+ } else {
+ console.error('Failed to load any theme!')
+ }
// Now we can try getting the server settings and logging in
await Promise.all([
checkOAuthToken({ store }),
- setConfig({ store }),
getTOS({ store }),
getInstancePanel({ store }),
getStickers({ store }),
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 799646b1..0ef02f39 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -57,6 +57,8 @@ export default {
return {
availableStyles: [],
selected: this.$store.getters.mergedConfig.theme,
+ themeWarning: undefined,
+ tempImportFile: undefined,
previewShadows: {},
previewColors: {},
@@ -120,12 +122,62 @@ export default {
})
},
mounted () {
- this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme)
+ this.loadThemeFromLocalStorage()
if (typeof this.shadowSelected === 'undefined') {
this.shadowSelected = this.shadowsAvailable[0]
}
},
computed: {
+ 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') {
+ // FE upgraded from v2
+ if (themeEngineVersion === 2) {
+ return 'upgraded_from_v2'
+ }
+ // Admin downgraded FE
+ if (themeEngineVersion > CURRENT_VERSION) {
+ return noActionsPossible
+ ? 'downgraded_theme'
+ : 'downgraded_theme_missing_snapshot'
+ }
+ // Admin upgraded FE
+ if (themeEngineVersion < CURRENT_VERSION) {
+ return noActionsPossible
+ ? 'upgraded_theme'
+ : 'upgraded_theme_missing_snapshot'
+ }
+ }
+ },
selectedVersion () {
return Array.isArray(this.selected) ? 1 : 2
},
@@ -308,10 +360,96 @@ export default {
Checkbox
},
methods: {
+ loadTheme (
+ {
+ theme,
+ source,
+ _pleroma_theme_version: fileVersion
+ },
+ origin,
+ forceUseSource = false
+ ) {
+ if (!source && !theme) {
+ throw new Error('Can\'t load theme: empty')
+ }
+ const version = (origin === 'localstorage' && !theme.colors)
+ ? 'l1'
+ : fileVersion
+ const themeEngineVersion = (source || {}).themeEngineVersion || 2
+ const versionsMatch = themeEngineVersion === CURRENT_VERSION
+ // Force loading of source if user requested it or if snapshot
+ // is unavailable
+ const forcedSourceLoad = (source && forceUseSource) || !theme
+ if (!versionsMatch &&
+ !forcedSourceLoad &&
+ version !== 'l1' &&
+ origin !== 'defaults'
+ ) {
+ if (!theme) {
+ 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) {
+ case 'localstorage':
+ this.loadThemeFromLocalStorage(true)
+ break
+ case 'file':
+ this.onImport(this.tempImportFile, true)
+ break
+ }
+ },
+ loadThemeFromLocalStorage (confirmLoadSource = false) {
+ 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(
+ { theme, source },
+ 'localStorage',
+ confirmLoadSource
+ )
+ }
+ },
setCustomTheme () {
this.$store.dispatch('setOption', {
name: 'customTheme',
+ value: this.previewTheme
+ })
+ this.$store.dispatch('setOption', {
+ name: 'customThemeSource',
value: {
+ themeEngineVersion: CURRENT_VERSION,
shadows: this.shadowsLocal,
fonts: this.fontsLocal,
opacity: this.currentOpacity,
@@ -331,21 +469,16 @@ export default {
this.previewColors.mod
)
},
- onImport (parsed) {
- if (parsed._pleroma_theme_version === 1) {
- this.normalizeLocalState(parsed, 1)
- } else if (parsed._pleroma_theme_version >= 2) {
- this.normalizeLocalState(parsed.theme, 2, parsed.source)
- }
+ onImport (parsed, forceSource = false) {
+ this.tempImportFile = parsed
+ this.loadTheme(parsed, 'file', forceSource)
},
importValidator (parsed) {
const version = parsed._pleroma_theme_version
return version >= 1 || version <= 2
},
clearAll () {
- const state = this.$store.getters.mergedConfig.customTheme
- const version = state.colors ? 2 : 'l1'
- this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme, version, this.$store.getters.mergedConfig.customThemeSource)
+ this.loadThemeFromLocalStorage()
},
// Clears all the extra stuff when loading V1 theme
diff --git a/src/components/style_switcher/style_switcher.scss b/src/components/style_switcher/style_switcher.scss
index 987245a2..71d0f05e 100644
--- a/src/components/style_switcher/style_switcher.scss
+++ b/src/components/style_switcher/style_switcher.scss
@@ -1,5 +1,9 @@
@import '../../_variables.scss';
.style-switcher {
+ .theme-warning {
+ display: flex;
+ align-items: baseline;
+ }
.preset-switcher {
margin-right: 1em;
}
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 287d31b7..61f8800a 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -1,31 +1,60 @@
<template>
- <div class="style-switcher">
- <div class="presets-container">
- <div class="save-load">
- <ExportImport
- :export-object="exportedTheme"
- :export-label="$t(&quot;settings.export_theme&quot;)"
- :import-label="$t(&quot;settings.import_theme&quot;)"
- :import-failed-text="$t(&quot;settings.invalid_theme_imported&quot;)"
- :on-import="onImport"
- :validator="importValidator"
- >
- <template slot="before">
- <div class="presets">
- {{ $t('settings.presets') }}
- <label
- for="preset-switcher"
- class="select"
+<div class="style-switcher">
+ <div class="presets-container">
+ <div class="save-load">
+ <div class="theme-warning" v-if="themeWarning">
+ <div class="alert warning">
+ {{ themeWarningHelp }}
+ </div>
+ <div class="buttons">
+ <template v-if="themeWarning.noActionsPossible">
+ <button
+ class="btn"
+ @click="dismissWarning"
+ >
+ {{ $t('general.dismiss') }}
+ </button>
+ </template>
+ <template v-else>
+ <button
+ class="btn"
+ @click="forceLoad"
+ >
+ {{ $t('settings.style.switcher.load_theme') }}
+ </button>
+ <button
+ class="btn"
+ @click="dismissWarning"
+ >
+ {{ $t('settings.style.switcher.use_snapshot') }}
+ </button>
+ </template>
+ </div>
+ </div>
+ <ExportImport
+ :export-object="exportedTheme"
+ :export-label="$t(&quot;settings.export_theme&quot;)"
+ :import-label="$t(&quot;settings.import_theme&quot;)"
+ :import-failed-text="$t(&quot;settings.invalid_theme_imported&quot;)"
+ :on-import="onImport"
+ :validator="importValidator"
+ >
+ <template slot="before">
+ <div class="presets">
+ {{ $t('settings.presets') }}
+ <label
+ for="preset-switcher"
+ class="select"
>
- <select
- id="preset-switcher"
- v-model="selected"
- class="preset-switcher"
+ <select
+ id="preset-switcher"
+ v-model="selected"
+ class="preset-switcher"
>
- <option
- v-for="style in availableStyles"
- :key="style.name"
- :value="style"
+ <option
+ v-for="style in availableStyles"
+ :key="style.name"
+ :value="style"
:style="{
backgroundColor: style[1] || (style.theme || style.source).colors.bg,
color: style[3] || (style.theme || style.source).colors.text
diff --git a/src/i18n/en.json b/src/i18n/en.json
index f624a1c5..6994d62f 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -46,6 +46,7 @@
"optional": "optional",
"show_more": "Show more",
"show_less": "Show less",
+ "dismiss": "Dismiss",
"cancel": "Cancel",
"disable": "Disable",
"enable": "Enable",
@@ -394,7 +395,16 @@
"save_load_hint": "\"Keep\" options preserve currently set options when selecting or loading themes, it also stores said options when exporting a theme. When all checkboxes unset, exporting theme will save everything.",
"reset": "Reset",
"clear_all": "Clear all",
- "clear_opacity": "Clear opacity"
+ "clear_opacity": "Clear opacity",
+ "load_theme": "Load theme",
+ "use_snapshot": "Keep as is",
+ "help": {
+ "v2_imported": "File you imported was made for older FE. We try to maximize compatibility but there still could be inconsitencies.",
+ "snapshot_present": "Theme snapshot is loaded, so all values are overriden. You can load theme's actual data instead.",
+ "snapshot_missing": "No theme snapshot was in the file so it could look different than originally envisioned.",
+ "future_version_imported": "File you imported was made in newer version of FE.",
+ "older_version_imported": "File you imported was made in older version of FE."
+ }
},
"common": {
"color": "Color",
diff --git a/src/modules/config.js b/src/modules/config.js
index 74025db1..ee474b16 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -5,6 +5,9 @@ const browserLocale = (window.navigator.language || 'en').split('-')[0]
export const defaultState = {
colors: {},
+ theme: undefined,
+ customTheme: undefined,
+ customThemeSource: undefined,
hideISP: false,
// bad name: actually hides posts of muted USERS
hideMutedPosts: undefined, // instance default
@@ -93,10 +96,10 @@ const config = {
commit('setOption', { name, value })
switch (name) {
case 'theme':
- setPreset(value, commit)
+ setPreset(value)
break
case 'customTheme':
- applyTheme(value, commit)
+ applyTheme(value)
}
}
}
diff --git a/src/modules/instance.js b/src/modules/instance.js
index 625323b9..8781646d 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -1,5 +1,5 @@
import { set } from 'vue'
-import { setPreset } from '../services/style_setter/style_setter.js'
+import { getPreset, applyTheme } from '../services/style_setter/style_setter.js'
import { instanceDefaultProperties } from './config.js'
const defaultState = {
@@ -10,6 +10,7 @@ const defaultState = {
textlimit: 5000,
server: 'http://localhost:4040/',
theme: 'pleroma-dark',
+ themeData: undefined,
background: '/static/aurora_borealis.jpg',
logo: '/static/logo.png',
logoMask: true,
@@ -96,6 +97,9 @@ const instance = {
dispatch('initializeSocket')
}
break
+ case 'theme':
+ dispatch('setTheme', value)
+ break
}
},
async getStaticEmoji ({ commit }) {
@@ -147,9 +151,16 @@ const instance = {
}
},
- setTheme ({ commit }, themeName) {
+ setTheme ({ commit, rootState }, themeName) {
commit('setInstanceOption', { name: 'theme', value: themeName })
- return setPreset(themeName, commit)
+ getPreset(themeName)
+ .then(themeData => {
+ commit('setInstanceOption', { name: 'themeData', value: themeData })
+ // No need to apply theme if there's user theme already
+ const { customTheme } = rootState.config
+ if (customTheme) return
+ applyTheme(themeData.theme)
+ })
},
fetchEmoji ({ dispatch, state }) {
if (!state.customEmojiFetched) {
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index ee264c49..9610d799 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -7,7 +7,7 @@ import { getColors, computeDynamicColor } from '../theme_data/theme_data.service
// styles that aren't just colors, so user can pick from a few different distinct
// styles as well as set their own colors in the future.
-export const setStyle = (href, commit) => {
+export const setStyle = (href) => {
/***
What's going on here?
I want to make it easy for admins to style this application. To have
@@ -53,8 +53,8 @@ export const setStyle = (href, commit) => {
cssEl.addEventListener('load', setDynamic)
}
-export const applyTheme = (input, commit) => {
- const { rules, theme } = generatePreset(input)
+export const applyTheme = (input) => {
+ const { rules } = generatePreset(input)
const head = document.head
const body = document.body
body.classList.add('hidden')
@@ -69,11 +69,6 @@ export const applyTheme = (input, commit) => {
styleSheet.insertRule(`body { ${rules.shadows} }`, 'index-max')
styleSheet.insertRule(`body { ${rules.fonts} }`, 'index-max')
body.classList.remove('hidden')
-
- // commit('setOption', { name: 'colors', value: htmlColors })
- // commit('setOption', { name: 'radii', value: radii })
- commit('setOption', { name: 'customTheme', value: input })
- commit('setOption', { name: 'colors', value: theme.colors })
}
export const getCssShadow = (input, usesDropShadow) => {
@@ -387,7 +382,7 @@ export const getThemes = () => {
*/
export const shadows2to3 = (shadows) => {
return Object.entries(shadows).reduce((shadowsAcc, [slotName, shadowDefs]) => {
- const isDynamic = ({ color }) => console.log(color) || color.startsWith('--')
+ const isDynamic = ({ color }) => color.startsWith('--')
const newShadow = shadowDefs.reduce((shadowAcc, def) => [
...shadowAcc,
{
@@ -399,7 +394,7 @@ export const shadows2to3 = (shadows) => {
}, {})
}
-export const setPreset = (val, commit) => {
+export const getPreset = (val) => {
return getThemes()
.then((themes) => themes[val] ? themes[val] : themes['pleroma-dark'])
.then((theme) => {
@@ -420,14 +415,8 @@ export const setPreset = (val, commit) => {
data.colors = { bg, fg, text, link, cRed, cBlue, cGreen, cOrange }
}
- // This is a hack, this function is only called during initial load.
- // We want to cancel loading the theme from config.json if we're already
- // loading a theme from the persisted state.
- // Needed some way of dealing with the async way of things.
- // load config -> set preset -> wait for styles.json to load ->
- // load persisted state -> set colors -> styles.json loaded -> set colors
- if (!window.themeLoaded) {
- applyTheme(data, commit)
- }
+ return { theme: data, source: theme.source }
})
}
+
+export const setPreset = (val) => getPreset(val).then(data => applyTheme(data.theme))