some initial work on theme editor
This commit is contained in:
parent
a8092de638
commit
144d426864
|
@ -10,9 +10,13 @@ export default {
|
|||
ProfileSettingIndicator
|
||||
},
|
||||
props: {
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: null
|
||||
},
|
||||
path: {
|
||||
type: [String, Array],
|
||||
required: true
|
||||
required: false
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
|
@ -68,7 +72,7 @@ export default {
|
|||
}
|
||||
},
|
||||
created () {
|
||||
if (this.realDraftMode && this.realSource !== 'admin') {
|
||||
if (this.realDraftMode && (this.realSource !== 'admin' || this.path == null)) {
|
||||
this.draft = this.state
|
||||
}
|
||||
},
|
||||
|
@ -76,14 +80,14 @@ export default {
|
|||
draft: {
|
||||
// TODO allow passing shared draft object?
|
||||
get () {
|
||||
if (this.realSource === 'admin') {
|
||||
if (this.realSource === 'admin' || this.path == null) {
|
||||
return get(this.$store.state.adminSettings.draft, this.canonPath)
|
||||
} else {
|
||||
return this.localDraft
|
||||
}
|
||||
},
|
||||
set (value) {
|
||||
if (this.realSource === 'admin') {
|
||||
if (this.realSource === 'admin' || this.path == null) {
|
||||
this.$store.commit('updateAdminDraft', { path: this.canonPath, value })
|
||||
} else {
|
||||
this.localDraft = value
|
||||
|
@ -91,6 +95,9 @@ export default {
|
|||
}
|
||||
},
|
||||
state () {
|
||||
if (this.path == null) {
|
||||
return this.modelValue
|
||||
}
|
||||
const value = get(this.configSource, this.canonPath)
|
||||
if (value === undefined) {
|
||||
return this.defaultState
|
||||
|
@ -145,6 +152,9 @@ export default {
|
|||
return this.backendDescription?.suggestions
|
||||
},
|
||||
shouldBeDisabled () {
|
||||
if (this.path == null) {
|
||||
return this.disabled
|
||||
}
|
||||
const parentValue = this.parentPath !== undefined ? get(this.configSource, this.parentPath) : null
|
||||
return this.disabled || (parentValue !== null ? (this.parentInvert ? parentValue : !parentValue) : false)
|
||||
},
|
||||
|
@ -159,6 +169,9 @@ export default {
|
|||
}
|
||||
},
|
||||
configSink () {
|
||||
if (this.path == null) {
|
||||
return (k, v) => this.$emit('modelValue:update', v)
|
||||
}
|
||||
switch (this.realSource) {
|
||||
case 'profile':
|
||||
return (k, v) => this.$store.dispatch('setProfileOption', { name: k, value: v })
|
||||
|
@ -184,6 +197,7 @@ export default {
|
|||
return this.realSource === 'profile'
|
||||
},
|
||||
isChanged () {
|
||||
if (this.path == null) return false
|
||||
switch (this.realSource) {
|
||||
case 'profile':
|
||||
case 'admin':
|
||||
|
@ -193,9 +207,11 @@ export default {
|
|||
}
|
||||
},
|
||||
canonPath () {
|
||||
if (this.path == null) return null
|
||||
return Array.isArray(this.path) ? this.path : this.path.split('.')
|
||||
},
|
||||
isDirty () {
|
||||
if (this.path == null) return false
|
||||
if (this.realSource === 'admin' && this.canonPath.length > 3) {
|
||||
return false // should not show draft buttons for "grouped" values
|
||||
} else {
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
</template>
|
||||
<slot v-else />
|
||||
</label>
|
||||
{{ ' ' }}
|
||||
<input
|
||||
:id="path"
|
||||
class="input string-input"
|
||||
|
|
|
@ -10,6 +10,10 @@
|
|||
list-style-type: none;
|
||||
padding-left: 2em;
|
||||
|
||||
.btn:not(.dropdown-button) {
|
||||
padding: 0 2em;
|
||||
}
|
||||
|
||||
li {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
@ -54,10 +58,6 @@
|
|||
.btn {
|
||||
min-height: 2em;
|
||||
}
|
||||
|
||||
.btn:not(.dropdown-button) {
|
||||
padding: 0 2em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import GeneralTab from './tabs/general_tab.vue'
|
|||
import AppearanceTab from './tabs/appearance_tab.vue'
|
||||
import VersionTab from './tabs/version_tab.vue'
|
||||
import ThemeTab from './tabs/theme_tab/theme_tab.vue'
|
||||
import StyleTab from './tabs/style_tab/style_tab.vue'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
|
@ -17,6 +18,7 @@ import {
|
|||
faUser,
|
||||
faFilter,
|
||||
faPaintBrush,
|
||||
faPalette,
|
||||
faBell,
|
||||
faDownload,
|
||||
faEyeSlash,
|
||||
|
@ -29,6 +31,7 @@ library.add(
|
|||
faUser,
|
||||
faFilter,
|
||||
faPaintBrush,
|
||||
faPalette,
|
||||
faBell,
|
||||
faDownload,
|
||||
faEyeSlash,
|
||||
|
@ -48,6 +51,7 @@ const SettingsModalContent = {
|
|||
ProfileTab,
|
||||
GeneralTab,
|
||||
AppearanceTab,
|
||||
StyleTab,
|
||||
VersionTab,
|
||||
ThemeTab
|
||||
},
|
||||
|
|
|
@ -20,6 +20,13 @@
|
|||
>
|
||||
<AppearanceTab />
|
||||
</div>
|
||||
<div
|
||||
:label="$t('settings.style.themes3.editor.title')"
|
||||
icon="palette"
|
||||
data-tab-name="style"
|
||||
>
|
||||
<StyleTab />
|
||||
</div>
|
||||
<div
|
||||
:label="$t('settings.theme')"
|
||||
icon="paint-brush"
|
||||
|
|
40
src/components/settings_modal/tabs/style_tab/style_tab.js
Normal file
40
src/components/settings_modal/tabs/style_tab/style_tab.js
Normal file
|
@ -0,0 +1,40 @@
|
|||
// import {
|
||||
// rgb2hex,
|
||||
// hex2rgb,
|
||||
// getContrastRatioLayers,
|
||||
// relativeLuminance
|
||||
// } from 'src/services/color_convert/color_convert.js'
|
||||
|
||||
// import {
|
||||
// getThemes
|
||||
// } from 'src/services/style_setter/style_setter.js'
|
||||
|
||||
// import {
|
||||
// newImporter,
|
||||
// newExporter
|
||||
// } from 'src/services/export_import/export_import.js'
|
||||
|
||||
// import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
||||
// import { init } from 'src/services/theme_data/theme_data_3.service.js'
|
||||
// import {
|
||||
// getCssRules,
|
||||
// getScopedVersion
|
||||
// } from 'src/services/theme_data/css_utils.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'
|
||||
// import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
|
||||
// import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
import Select from 'src/components/select/select.vue'
|
||||
import Preview from './theme_preview.vue'
|
||||
|
||||
import { defineOptions, ref } from 'vue'
|
||||
const componentsContext = require.context('src', true, /\.style.js(on)?$/)
|
||||
const componentNames = componentsContext.keys()
|
||||
const componentName = ref(componentNames[0])
|
59
src/components/settings_modal/tabs/style_tab/style_tab.scss
Normal file
59
src/components/settings_modal/tabs/style_tab/style_tab.scss
Normal file
|
@ -0,0 +1,59 @@
|
|||
.StyleTab {
|
||||
.setting-item {
|
||||
padding-bottom: 0;
|
||||
|
||||
.btn {
|
||||
padding: 0 0.5em;
|
||||
}
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
&:not(:last-child) {
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
&.heading {
|
||||
display: grid;
|
||||
align-items: baseline;
|
||||
grid-template-columns: 1fr auto auto auto;
|
||||
grid-gap: 0.5em;
|
||||
|
||||
h2 {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
&.metadata {
|
||||
display: flex;
|
||||
|
||||
.setting-item {
|
||||
flex: 2 0 auto;
|
||||
}
|
||||
|
||||
li {
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.component-editor {
|
||||
display: grid;
|
||||
grid-template-columns: 10em, 1fr, 2fr;
|
||||
grid-template-rows: auto 1fr;
|
||||
grid-template-areas:
|
||||
"variant" "preview" "controls",
|
||||
"state" "preview" "controls";
|
||||
|
||||
.state-selector {
|
||||
grid-area: state;
|
||||
}
|
||||
|
||||
.variant-selector {
|
||||
grid-area: variant;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
}
|
138
src/components/settings_modal/tabs/style_tab/style_tab.vue
Normal file
138
src/components/settings_modal/tabs/style_tab/style_tab.vue
Normal file
|
@ -0,0 +1,138 @@
|
|||
<script setup>
|
||||
import { ref, computed } from 'vue'
|
||||
|
||||
import Select from 'src/components/select/select.vue'
|
||||
import Checkbox from 'src/components/checkbox/checkbox.vue'
|
||||
import StringSetting from '../../helpers/string_setting.vue'
|
||||
// import Preview from '../theme_tab/theme_preview.vue'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faFloppyDisk, faFolderOpen, faFile } from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faFile,
|
||||
faFloppyDisk,
|
||||
faFolderOpen
|
||||
)
|
||||
|
||||
const name = ref('')
|
||||
const author = ref('')
|
||||
const license = ref('')
|
||||
const website = ref('')
|
||||
|
||||
// Getting existing components
|
||||
const componentsContext = require.context('src', true, /\.style.js(on)?$/)
|
||||
const componentKeys = componentsContext.keys()
|
||||
|
||||
const componentsMap = new Map(
|
||||
componentKeys
|
||||
.map(
|
||||
key => [key, componentsContext(key).default]
|
||||
)
|
||||
)
|
||||
// const componentValues = componentsMap.values()
|
||||
|
||||
// Initializing selected component and its computed descendants
|
||||
const selectedComponentKey = ref(componentKeys[0])
|
||||
const selectedComponentValue = computed(() => componentsMap.get(selectedComponentKey.value))
|
||||
|
||||
// const selectedComponentName = computed(() => selectedComponent.value.name)
|
||||
const selectedComponentVariants = computed(() => {
|
||||
return new Set([...(Object.keys(selectedComponentValue.value.variants || {})), 'normal'])
|
||||
})
|
||||
const selectedComponentStates = computed(() => {
|
||||
return new Set([...(Object.keys(selectedComponentValue.value.states || {})), 'normal'])
|
||||
})
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="StyleTab">
|
||||
<div class="setting-item heading">
|
||||
<h2>{{ $t('settings.style.themes3.editor.title') }}</h2>
|
||||
<button
|
||||
class="btn button-default"
|
||||
@click="clearTheme"
|
||||
>
|
||||
<FAIcon icon="file" />
|
||||
{{ $t('settings.style.themes3.editor.new_style') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn button-default"
|
||||
@click="importStyle"
|
||||
>
|
||||
<FAIcon icon="folder-open" />
|
||||
{{ $t('settings.style.themes3.editor.load_style') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn button-default"
|
||||
@click="exportTheme"
|
||||
>
|
||||
<FAIcon icon="floppy-disk" />
|
||||
{{ $t('settings.style.themes3.editor.save_style') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="setting-item metadata">
|
||||
<ul class="setting-list">
|
||||
<li>
|
||||
<StringSetting v-model="name">
|
||||
{{ $t('settings.style.themes3.editor.style_name') }}
|
||||
</StringSetting>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting v-model="author">
|
||||
{{ $t('settings.style.themes3.editor.style_author') }}
|
||||
</StringSetting>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting v-model="license">
|
||||
{{ $t('settings.style.themes3.editor.style_license') }}
|
||||
</StringSetting>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting v-model="website">
|
||||
{{ $t('settings.style.themes3.editor.style_website') }}
|
||||
</StringSetting>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="setting-item">
|
||||
<Select v-model="selectedComponentKey">
|
||||
<option
|
||||
v-for="key in componentKeys"
|
||||
:key="'component-' + key"
|
||||
:value="key"
|
||||
>
|
||||
{{ componentsMap.get(key).name }}
|
||||
</option>
|
||||
</Select>
|
||||
<div class="component-editor">
|
||||
<Select
|
||||
v-model="selectedComponentVariant"
|
||||
class="variant-selector"
|
||||
>
|
||||
<option
|
||||
v-for="variant in selectedComponentVariants"
|
||||
:key="'component-variant-' + variant"
|
||||
>
|
||||
{{ variant }}
|
||||
</option>
|
||||
</Select>
|
||||
<ul class="state-selector">
|
||||
<li
|
||||
v-for="state in selectedComponentStates"
|
||||
:key="'component-variant-' + state"
|
||||
>
|
||||
<Checkbox
|
||||
v-model="selectedComponentStates"
|
||||
>
|
||||
{{ state }}
|
||||
</Checkbox>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style src="./style_tab.scss" lang="scss"></style>
|
|
@ -753,6 +753,16 @@
|
|||
"update_preview": "Update preview",
|
||||
"themes3": {
|
||||
"define": "Override",
|
||||
"editor": {
|
||||
"title": "Style",
|
||||
"new_style": "New",
|
||||
"load_style": "Open",
|
||||
"save_style": "Save",
|
||||
"style_name": "Stylesheet name",
|
||||
"style_author": "Made by",
|
||||
"style_license": "License",
|
||||
"style_website": "Website"
|
||||
},
|
||||
"hacks": {
|
||||
"underlay_overrides": "Change underlay",
|
||||
"underlay_override_mode_none": "Theme default",
|
||||
|
|
Loading…
Reference in a new issue