diff --git a/src/boot/after_store.js b/src/boot/after_store.js index 60113c6f1..638b1a807 100644 --- a/src/boot/after_store.js +++ b/src/boot/after_store.js @@ -351,7 +351,12 @@ const afterStoreSetup = async ({ store, i18n }) => { store.dispatch('setInstanceOption', { name: 'server', value: server }) await setConfig({ store }) - await store.dispatch('applyTheme', { recompile: false }) + document.querySelector('#status').textContent = i18n.global.t('splash.theme') + try { + await store.dispatch('applyTheme').catch((e) => { console.error('Error setting theme', e) }) + } catch (e) { + return Promise.reject(e) + } applyConfig(store.state.config) diff --git a/src/components/select/select_motion.vue b/src/components/select/select_motion.vue new file mode 100644 index 000000000..be42b040d --- /dev/null +++ b/src/components/select/select_motion.vue @@ -0,0 +1,115 @@ + + + + + diff --git a/src/components/settings_modal/tabs/appearance_tab.js b/src/components/settings_modal/tabs/appearance_tab.js index 1e48c7e88..bba4647c6 100644 --- a/src/components/settings_modal/tabs/appearance_tab.js +++ b/src/components/settings_modal/tabs/appearance_tab.js @@ -34,7 +34,7 @@ const AppearanceTab = { return { availableStyles: [], availablePalettes: [], - themeImporter: newImporter({ + fileImporter: newImporter({ accept: '.json, .piss', validator: this.importValidator, onImport: this.onImport, @@ -179,6 +179,10 @@ const AppearanceTab = { this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val }) } }, + customThemeVersion () { + const { themeVersion } = this.$store.state.interface + return themeVersion + }, isCustomThemeUsed () { const { theme } = this.mergedConfig return theme === 'custom' @@ -202,8 +206,8 @@ const AppearanceTab = { } }) }, - importTheme () { - this.themeImporter.importData() + importFile () { + this.fileImporter.importData() }, onImport (parsed, filename) { if (filename.endsWith('.json')) { @@ -234,14 +238,18 @@ const AppearanceTab = { const { palette } = this.mergedConfig return key === palette }, - importStyle () { - + setStyle (name) { + this.$store.dispatch('resetThemeV2') + this.$store.dispatch('setTheme', name) + this.$store.dispatch('applyTheme') }, setTheme (name) { + this.$store.dispatch('resetThemeV3') this.$store.dispatch('setTheme', name) this.$store.dispatch('applyTheme') }, setPalette (name) { + this.$store.dispatch('resetThemeV2') this.$store.dispatch('setPalette', name) this.$store.dispatch('applyTheme') }, diff --git a/src/components/settings_modal/tabs/appearance_tab.scss b/src/components/settings_modal/tabs/appearance_tab.scss index 77d668ecb..b95ef07db 100644 --- a/src/components/settings_modal/tabs/appearance_tab.scss +++ b/src/components/settings_modal/tabs/appearance_tab.scss @@ -24,6 +24,10 @@ display: grid; grid-template-columns: 1fr 1fr; grid-gap: 0.5em; + + .unsupported-theme-v2 { + grid-column: 1 / span 2; + } } .palette-entry { diff --git a/src/components/settings_modal/tabs/appearance_tab.vue b/src/components/settings_modal/tabs/appearance_tab.vue index d27f43fe1..32f6f1a72 100644 --- a/src/components/settings_modal/tabs/appearance_tab.vue +++ b/src/components/settings_modal/tabs/appearance_tab.vue @@ -7,7 +7,7 @@

{{ $t('settings.theme') }}

+ +
diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.js b/src/components/settings_modal/tabs/style_tab/style_tab.js index ecddf9d56..cbd25dfc2 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.js +++ b/src/components/settings_modal/tabs/style_tab/style_tab.js @@ -219,9 +219,13 @@ export default { return selectors.map(x => x.substring(1)).join('') }) const previewCss = computed(() => { - const scoped = getCssRules(previewRules) - .map(simulatePseudoSelectors) - return scoped.join('\n') + try { + const scoped = getCssRules(previewRules).map(simulatePseudoSelectors) + return scoped.join('\n') + } catch (e) { + console.error('Invalid ruleset', e) + return null + } }) // ### Rules stuff aka meat and potatoes @@ -415,17 +419,22 @@ export default { }) const updatePreview = () => { - previewRules.splice(0, previewRules.length) - previewRules.push(...init({ - inputRuleset: editorFriendlyToOriginal.value, - initialStaticVars: { - ...palette.value - }, - ultimateBackgroundColor: '#000000', - rootComponentName: selectedComponentName.value, - editMode: true, - debug: true - }).eager) + try { + const rules = init({ + inputRuleset: editorFriendlyToOriginal.value, + initialStaticVars: { + ...palette.value + }, + ultimateBackgroundColor: '#000000', + rootComponentName: selectedComponentName.value, + editMode: true, + debug: true + }).eager + previewRules.splice(0, previewRules.length) + previewRules.push(...rules) + } catch (e) { + console.error('Could not compile preview theme', e) + } } const updateSelectedComponent = () => { diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.vue b/src/components/settings_modal/tabs/style_tab/style_tab.vue index cd9d3e474..b73732f8a 100644 --- a/src/components/settings_modal/tabs/style_tab/style_tab.vue +++ b/src/components/settings_modal/tabs/style_tab/style_tab.vue @@ -51,231 +51,241 @@
-
-
- - -
+
- - - {{ fallbackI18n($t(getVariantPath(selectedComponentName, variant)), variant) }} - - -
-
- -
    + {{ fallbackI18n($t(getFriendlyNamePath(componentsMap.get(key).name)), componentsMap.get(key).name) }} + + +
+
-
  • + {{ $t('settings.style.themes3.editor.variant_selector') }} + + +
  • +
    + +
      +
    • + + {{ fallbackI18n($t(getStatePath(selectedComponentName, state)), state) }} + +
    • +
    +
    +
    + + + + +
    + +
    + + + + + + + + + + + + +
    + + +
    + + + +
    + +
    +
    + +
    + + + + + + + + +
    +
    - {{ fallbackI18n($t(getStatePath(selectedComponentName, state)), state) }} - - - + {{ $t('settings.style.themes3.editor.include_in_rule') }} + + +
    +
    -
    - - - - -
    - -
    - - - - - - - - - - + + + - - - -
    - - - -
    - -
    -
    - -
    - - - - - - - - + {{ $t('settings.style.themes3.palette.light') }} + + -
    - - {{ $t('settings.style.themes3.editor.include_in_rule') }} - - -
    -
    - -
    -
    - - +
    - -
    + diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js index 4521305ea..fc227b5be 100644 --- a/src/components/shadow_control/shadow_control.js +++ b/src/components/shadow_control/shadow_control.js @@ -1,6 +1,7 @@ import ColorInput from 'src/components/color_input/color_input.vue' import OpacityInput from 'src/components/opacity_input/opacity_input.vue' import Select from 'src/components/select/select.vue' +import SelectMotion from 'src/components/select/select_motion.vue' import Checkbox from 'src/components/checkbox/checkbox.vue' import Popover from 'src/components/popover/popover.vue' import ComponentPreview from 'src/components/component_preview/component_preview.vue' @@ -21,16 +22,22 @@ library.add( faPlus ) -const toModel = (object = {}) => ({ - x: 0, - y: 0, - blur: 0, - spread: 0, - inset: false, - color: '#000000', - alpha: 1, - ...object -}) +const toModel = (input) => { + if (typeof input === 'object') { + return { + x: 0, + y: 0, + blur: 0, + spread: 0, + inset: false, + color: '#000000', + alpha: 1, + ...input + } + } else if (typeof input === 'string') { + return input + } +} export default { props: [ @@ -48,20 +55,34 @@ export default { ColorInput, OpacityInput, Select, + SelectMotion, Checkbox, Popover, ComponentPreview }, - beforeUpdate () { - this.cValue = (this.modelValue ?? this.fallback ?? []).map(toModel) - }, computed: { - selected () { - const selected = this.cValue[this.selectedId] - if (selected) { - return { ...selected } + selectedType: { + get () { + return typeof this.selected + }, + set (newType) { + this.selected = toModel(newType === 'object' ? {} : '') + } + }, + selected: { + get () { + const selected = this.cValue[this.selectedId] + if (selected && typeof selected === 'object') { + return { ...selected } + } else if (typeof selected === 'string') { + return selected + } + return null + }, + set (value) { + this.cValue[this.selectedId] = toModel(value) + this.$emit('update:modelValue', this.cValue) } - return null }, present () { return this.selected != null && !this.usingFallback @@ -72,61 +93,55 @@ export default { currentFallback () { return this.fallback?.[this.selectedId] }, - moveUpValid () { - return this.selectedId > 0 - }, - moveDnValid () { - return this.selectedId < this.cValue.length - 1 - }, usingFallback () { return this.modelValue == null }, style () { - if (this.separateInset) { - return { - filter: getCssShadowFilter(this.cValue), - boxShadow: getCssShadow(this.cValue, true) + try { + if (this.separateInset) { + return { + filter: getCssShadowFilter(this.cValue), + boxShadow: getCssShadow(this.cValue, true) + } + } + return { + boxShadow: getCssShadow(this.cValue) + } + } catch (e) { + return { + border: '1px solid red' } - } - return { - boxShadow: getCssShadow(this.cValue) } } }, watch: { + modelValue (value) { + if (!value) this.cValue = (this.modelValue ?? this.fallback ?? []).map(toModel) + }, selected (value) { this.$emit('subShadowSelected', this.selectedId) } }, methods: { + getNewSubshadow () { + return toModel(this.selected) + }, + onSelectChange (id) { + this.selectedId = id + }, + getSubshadowLabel (shadow, index) { + if (typeof shadow === 'object') { + return shadow?.name ?? this.$t('settings.style.shadows.shadow_id', { value: index }) + } else if (typeof shadow === 'string') { + return shadow || this.$t('settings.style.shadows.empty_expression') + } + }, updateProperty: throttle(function (prop, value) { this.cValue[this.selectedId][prop] = value if (prop === 'inset' && value === false && this.separateInset) { this.cValue[this.selectedId].spread = 0 } this.$emit('update:modelValue', this.cValue) - }, 100), - add () { - this.cValue.push(toModel(this.selected)) - this.selectedId = Math.max(this.cValue.length - 1, 0) - this.$emit('update:modelValue', this.cValue) - }, - del () { - this.cValue.splice(this.selectedId, 1) - this.selectedId = this.cValue.length === 0 ? undefined : Math.max(this.selectedId - 1, 0) - this.$emit('update:modelValue', this.cValue) - }, - moveUp () { - const movable = this.cValue.splice(this.selectedId, 1)[0] - this.cValue.splice(this.selectedId - 1, 0, movable) - this.selectedId -= 1 - this.$emit('update:modelValue', this.cValue) - }, - moveDn () { - const movable = this.cValue.splice(this.selectedId, 1)[0] - this.cValue.splice(this.selectedId + 1, 0, movable) - this.selectedId += 1 - this.$emit('update:modelValue', this.cValue) - } + }, 100) } } diff --git a/src/components/shadow_control/shadow_control.scss b/src/components/shadow_control/shadow_control.scss index dd0490235..de4159c11 100644 --- a/src/components/shadow_control/shadow_control.scss +++ b/src/components/shadow_control/shadow_control.scss @@ -4,6 +4,7 @@ justify-content: stretch; grid-gap: 0.25em; margin-bottom: 1em; + width: 100%; .shadow-switcher { order: 1; @@ -16,19 +17,6 @@ .shadow-list { flex: 1 0 auto; } - - .arrange-buttons { - flex: 0 0 auto; - display: grid; - grid-auto-columns: 1fr; - grid-auto-flow: column; - margin-top: 0.25em; - - .button-default { - margin: 0; - padding: 0; - } - } } .shadow-tweak { @@ -37,6 +25,9 @@ min-width: 10em; margin-left: 0.125em; margin-right: 0.125em; + display: grid; + grid-template-rows: auto 1fr; + grid-gap: 0.25em; /* hack */ .input-boolean { @@ -52,6 +43,11 @@ flex: 1 0 5em; } + .shadow-expression { + width: 100%; + height: 100%; + } + .id-control { align-items: stretch; @@ -100,6 +96,5 @@ } .inset-tooltip { - padding: 0.5em; max-width: 30em; } diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue index e1d201914..29adfff4a 100644 --- a/src/components/shadow_control/shadow_control.vue +++ b/src/components/shadow_control/shadow_control.vue @@ -8,7 +8,6 @@ class="shadow-preview" :shadow-control="true" :shadow="selected" - :preview-style="style" :disabled="disabled || !present" @update:shadow="({ axis, value }) => updateProperty(axis, value)" /> @@ -18,7 +17,7 @@ v-model="selectedId" class="shadow-list" size="10" - :disabled="shadowsAreNull" + :disabled="disabled || shadowsAreNull" > -
    - - - - -
    +
    -
    - - + {{ $t('settings.style.shadows.raw') }} + + + +