Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
33 KB
Referenced Files
None
Subscribers
None
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 cbd25dfc23..f3d44bac5e 100644
--- a/src/components/settings_modal/tabs/style_tab/style_tab.js
+++ b/src/components/settings_modal/tabs/style_tab/style_tab.js
@@ -1,559 +1,575 @@
import { ref, reactive, computed, watch } from 'vue'
import { get, set } from 'lodash'
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 ComponentPreview from 'src/components/component_preview/component_preview.vue'
import StringSetting from '../../helpers/string_setting.vue'
import ShadowControl from 'src/components/shadow_control/shadow_control.vue'
import ColorInput from 'src/components/color_input/color_input.vue'
import PaletteEditor from 'src/components/palette_editor/palette_editor.vue'
import OpacityInput from 'src/components/opacity_input/opacity_input.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import Tooltip from 'src/components/tooltip/tooltip.vue'
import ContrastRatio from 'src/components/contrast_ratio/contrast_ratio.vue'
import { init } from 'src/services/theme_data/theme_data_3.service.js'
import { getCssRules } from 'src/services/theme_data/css_utils.js'
import { serialize } from 'src/services/theme_data/iss_serializer.js'
import { deserialize } from 'src/services/theme_data/iss_deserializer.js'
import {
// rgb2hex,
hex2rgb,
getContrastRatio
} from 'src/services/color_convert/color_convert.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faFloppyDisk, faFolderOpen, faFile } from '@fortawesome/free-solid-svg-icons'
// helper for debugging
// eslint-disable-next-line no-unused-vars
const toValue = (x) => JSON.parse(JSON.stringify(x === undefined ? 'null' : x))
// helper to make states comparable
const normalizeStates = (states) => ['normal', ...(states?.filter(x => x !== 'normal') || [])].join(':')
library.add(
faFile,
faFloppyDisk,
faFolderOpen
)
export default {
components: {
Select,
+ SelectMotion,
Checkbox,
Tooltip,
StringSetting,
ComponentPreview,
TabSwitcher,
ShadowControl,
ColorInput,
PaletteEditor,
OpacityInput,
ContrastRatio
},
setup () {
// ### Meta stuff
const name = ref('')
const author = ref('')
const license = ref('')
const website = ref('')
const metaOut = computed(() => {
return `@meta {
name: ${name.value};
author: ${author.value};
license: ${license.value};
website: ${website.value};
}`
})
// ### Palette stuff
const palettes = reactive({
light: {
bg: '#f2f6f9',
fg: '#d6dfed',
text: '#304055',
underlay: '#5d6086',
accent: '#f55b1b',
cBlue: '#0095ff',
cRed: '#d31014',
cGreen: '#0fa00f',
cOrange: '#ffa500',
border: '#d8e6f9'
},
dark: {
bg: '#121a24',
fg: '#182230',
text: '#b9b9ba',
link: '#d8a070',
accent: '#d8a070',
cRed: '#FF0000',
cBlue: '#0095ff',
cGreen: '#0fa00f',
cOrange: '#ffa500'
}
})
const palettesOut = computed(() => {
return Object.entries(palettes).map(([name, palette]) => {
const entries = Object
.entries(palette)
.map(([slot, data]) => ` ${slot}: ${data};`)
.join('\n')
return `@palette.${name} {\n${entries}\n}`
}).join('\n\n')
})
const editedPalette = ref('dark')
const palette = computed({
get () {
return palettes[editedPalette.value]
},
set (newPalette) {
palettes[editedPalette.value] = newPalette
}
})
+ const getNewPalette = () => ({
+ name: 'new palette',
+ bg: '#121a24',
+ fg: '#182230',
+ text: '#b9b9ba',
+ link: '#d8a070',
+ accent: '#d8a070',
+ cRed: '#FF0000',
+ cBlue: '#0095ff',
+ cGreen: '#0fa00f',
+ cOrange: '#ffa500'
+ })
+
// ### I18n stuff
// The paths in i18n are getting ridicously long, this effectively shortens them
const getI18nPath = (componentName) => `settings.style.themes3.editor.components.${componentName}`
// vue i18n doesn't seem to have (working) mechanic to have a fallback so we have to
// make do ourselves
const fallbackI18n = (translated, fallback) => {
if (translated.startsWith('settings.style.themes3')) {
return fallback
}
return translated
}
const getFriendlyNamePath = (componentName) => getI18nPath(componentName) + '.friendlyName'
const getVariantPath = (componentName, variant) => {
return variant === 'normal'
? 'settings.style.themes3.editor.components.normal.variant'
: `${getI18nPath(componentName)}.variants.${variant}`
}
const getStatePath = (componentName, state) => {
return state === 'normal'
? 'settings.style.themes3.editor.components.normal.state'
: `${getI18nPath(componentName)}.states.${state}`
}
// ### Initialization stuff
// Getting existing components
const componentsContext = require.context('src', true, /\.style.js(on)?$/)
const componentKeysAll = componentsContext.keys()
const componentsMap = new Map(
componentKeysAll
.map(
key => [key, componentsContext(key).default]
).filter(([key, component]) => !component.virtual && !component.notEditable)
)
const componentKeys = [...componentsMap.keys()]
// Initializing selected component and its computed descendants
const selectedComponentKey = ref(componentsMap.keys().next().value)
const selectedComponent = computed(() => componentsMap.get(selectedComponentKey.value))
const selectedComponentName = computed(() => selectedComponent.value.name)
const selectedVariant = ref('normal')
const selectedComponentVariantsAll = computed(() => {
return Object.keys({ normal: null, ...(selectedComponent.value.variants || {}) })
})
const selectedState = reactive(new Set())
const selectedComponentStatesAll = computed(() => {
return Object.keys({ normal: null, ...(selectedComponent.value.states || {}) })
})
const selectedComponentStates = computed(() => {
return selectedComponentStatesAll.value.filter(x => x !== 'normal')
})
const updateSelectedStates = (state, v) => {
if (v) {
selectedState.add(state)
} else {
selectedState.delete(state)
}
}
// ### Preview stuff
const editorHintStyle = computed(() => {
const editorHint = selectedComponent.value.editor
const styles = []
if (editorHint && Object.keys(editorHint).length > 0) {
if (editorHint.aspect != null) {
styles.push(`aspect-ratio: ${editorHint.aspect} !important;`)
}
if (editorHint.border != null) {
styles.push(`border-width: ${editorHint.border}px !important;`)
}
}
return styles.join('; ')
})
// Apart from "hover" we can't really show how component looks like in
// certain states, so we have to fake them.
const simulatePseudoSelectors = css => css
.replace(selectedComponent.value.selector, '.ComponentPreview .preview-block')
.replace(':active', '.preview-active')
.replace(':hover', '.preview-hover')
.replace(':active', '.preview-active')
.replace(':focus', '.preview-focus')
.replace(':focus-within', '.preview-focus-within')
.replace(':disabled', '.preview-disabled')
const previewRules = reactive([])
const previewClass = computed(() => {
const selectors = []
if (!!selectedComponent.value.variants?.normal || selectedVariant.value !== 'normal') {
selectors.push(selectedComponent.value.variants[selectedVariant.value])
}
if (selectedState.size > 0) {
selectedState.forEach(state => {
const original = selectedComponent.value.states[state]
selectors.push(simulatePseudoSelectors(original))
})
}
return selectors.map(x => x.substring(1)).join('')
})
const previewCss = computed(() => {
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
// The native structure of separate rules and the child -> parent
// relation isn't very convenient for editor, we replace the array
// and child -> parent structure with map and parent -> child structure
const editorFriendlyFallbackStructure = computed(() => {
const root = {}
componentKeys.forEach((componentKey) => {
const componentValue = componentsMap.get(componentKey)
const { defaultRules } = componentValue
defaultRules.forEach((rule) => {
const { parent: rParent } = rule
const parent = rParent ?? rule
const hasChildren = !!rParent
const child = hasChildren ? rule : null
const {
component: pComponent,
variant: pVariant = 'normal',
state: pState = [] // no relation to Intel CPUs whatsoever
} = parent
const pPath = `${hasChildren ? pComponent : componentValue.name}.${pVariant}.${normalizeStates(pState)}`
let output = get(root, pPath)
if (!output) {
set(root, pPath, {})
output = get(root, pPath)
}
if (hasChildren) {
output._children = output._children ?? {}
const {
component: cComponent,
variant: cVariant = 'normal',
state: cState = [],
directives
} = child
const cPath = `${cComponent}.${cVariant}.${normalizeStates(cState)}`
set(output._children, cPath, directives)
} else {
output.directives = parent.directives
}
})
})
return root
})
// All rules that are made by editor
const allEditedRules = reactive({})
// Checkging whether component can support some "directives" which
// are actually virtual subcomponents, i.e. Text, Link etc
const componentHas = (subComponent) => {
return !!selectedComponent.value.validInnerComponents?.find(x => x === subComponent)
}
// Path is path for lodash's get and set
const getPath = (component, directive) => {
const pathSuffix = component ? `._children.${component}.normal.normal` : ''
const path = `${selectedComponentName.value}.${selectedVariant.value}.${normalizeStates([...selectedState])}${pathSuffix}.directives.${directive}`
return path
}
// Templates for directives
const isElementPresent = (component, directive, defaultValue = '') => computed({
get () {
return get(allEditedRules, getPath(component, directive)) != null
},
set (value) {
if (value) {
const fallback = get(
editorFriendlyFallbackStructure.value,
getPath(component, directive)
)
set(allEditedRules, getPath(component, directive), fallback ?? defaultValue)
} else {
set(allEditedRules, getPath(component, directive), null)
}
}
})
const getEditedElement = (component, directive) => computed({
get () {
let usedRule
const fallback = editorFriendlyFallbackStructure.value
const real = allEditedRules
const path = getPath(component, directive)
usedRule = get(real, path) // get real
if (!usedRule) {
usedRule = get(fallback, path)
}
return usedRule
},
set (value) {
set(allEditedRules, getPath(component, directive), value)
}
})
// All the editable stuff for the component
const editedBackgroundColor = getEditedElement(null, 'background')
const editedOpacity = getEditedElement(null, 'opacity')
const editedTextColor = getEditedElement('Text', 'textColor')
const editedTextAuto = getEditedElement('Text', 'textAuto')
const editedLinkColor = getEditedElement('Link', 'textColor')
const editedIconColor = getEditedElement('Icon', 'textColor')
const editedShadow = getEditedElement(null, 'shadow')
// Shadow is partially edited outside the ShadowControl
// for better space utilization
const editedSubShadowId = ref(null)
const editedSubShadow = computed(() => {
if (editedShadow.value == null || editedSubShadowId.value == null) return null
return editedShadow.value[editedSubShadowId.value]
})
const updateSubShadow = (axis, value) => {
if (!editedSubShadow.value || editedSubShadowId.value == null) return
const newEditedShadow = [...editedShadow.value]
newEditedShadow[editedSubShadowId.value] = {
...newEditedShadow[editedSubShadowId.value],
[axis]: value
}
editedShadow.value = newEditedShadow
}
const onSubShadow = (id) => {
if (id != null) {
editedSubShadowId.value = id
} else {
editedSubShadow.value = null
}
}
// Whether specific directives present in the edited rule or not
// Somewhat serves double-duty as it creates/removes the directive
// when set
const isBackgroundColorPresent = isElementPresent(null, 'background', '#FFFFFF')
const isOpacityPresent = isElementPresent(null, 'opacity', 1)
const isTextColorPresent = isElementPresent('Text', 'textColor', '#000000')
const isTextAutoPresent = isElementPresent('Text', 'textAuto', '#000000')
const isLinkColorPresent = isElementPresent('Link', 'textColor', '#000080')
const isIconColorPresent = isElementPresent('Icon', 'textColor', '#909090')
const isShadowPresent = isElementPresent(null, 'shadow', [])
const editorFriendlyToOriginal = computed(() => {
const resultRules = []
const convert = (component, data = {}, parent) => {
const variants = Object.entries(data || {})
variants.forEach(([variant, variantData]) => {
const states = Object.entries(variantData)
states.forEach(([jointState, stateData]) => {
const state = jointState.split(/:/g)
const result = {
component,
variant,
state,
directives: stateData.directives || {}
}
if (parent) {
result.parent = {
component: parent
}
}
resultRules.push(result)
// Currently we only support single depth for simplicity's sake
if (!parent) {
Object.entries(stateData._children || {}).forEach(([cName, child]) => convert(cName, child, component))
}
})
})
}
convert(selectedComponentName.value, allEditedRules[selectedComponentName.value])
return resultRules
})
const updatePreview = () => {
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 = () => {
selectedVariant.value = 'normal'
selectedState.clear()
updatePreview()
}
updateSelectedComponent()
watch(
allEditedRules,
updatePreview
)
watch(
palettes,
updatePreview
)
watch(
editedPalette,
updatePreview
)
watch(
selectedComponentName,
updateSelectedComponent
)
// TODO this is VERY primitive right now, need to make it
// support variables, fallbacks etc.
const getContrast = (bg, text) => {
try {
const bgRgb = hex2rgb(bg)
const textRgb = hex2rgb(text)
const ratio = getContrastRatio(bgRgb, textRgb)
return {
// TODO this ideally should be part of <ContractRatio />
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
}
} catch (e) {
console.warn('Failure computing contrast', e)
return { error: e }
}
}
const isShadowTabOpen = ref(false)
const onTabSwitch = (tab) => {
isShadowTabOpen.value = tab === 'shadow'
}
const exportStyle = () => {
console.log('ORIG', toValue(editorFriendlyToOriginal.value))
console.log('SERI', serialize(editorFriendlyToOriginal.value))
const result = [
metaOut.value,
palettesOut.value,
serialize(editorFriendlyToOriginal.value)
].join('\n\n')
console.log('RESULT', result)
console.log('DESERI', deserialize(result))
}
return {
name,
author,
license,
website,
palette,
editedPalette,
+ getNewPalette,
componentKeys,
componentsMap,
selectedComponent,
selectedComponentName,
selectedComponentKey,
selectedComponentVariantsAll,
selectedComponentStates,
selectedVariant,
selectedState,
updateSelectedStates,
editedBackgroundColor,
editedOpacity,
editedTextColor,
editedTextAuto,
editedLinkColor,
editedIconColor,
editedShadow,
editedSubShadow,
onSubShadow,
updateSubShadow,
getContrast,
isBackgroundColorPresent,
isOpacityPresent,
isTextColorPresent,
isTextAutoPresent,
isLinkColorPresent,
isIconColorPresent,
isShadowPresent,
previewCss,
previewClass,
editorHintStyle,
getFriendlyNamePath,
fallbackI18n,
getVariantPath,
getStatePath,
componentHas,
isShadowTabOpen,
onTabSwitch,
exportStyle
}
}
}
diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.scss b/src/components/settings_modal/tabs/style_tab/style_tab.scss
index 0306454fc7..deb087eef1 100644
--- a/src/components/settings_modal/tabs/style_tab/style_tab.scss
+++ b/src/components/settings_modal/tabs/style_tab/style_tab.scss
@@ -1,178 +1,181 @@
.StyleTab {
.style-control {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 0.5em;
.label {
margin-right: 0.5em;
flex: 1 1 0;
line-height: 2;
min-height: 2em;
}
&.suboption {
margin-left: 1em;
}
.color-input {
flex: 0 0 0;
}
input,
select {
min-width: 3em;
margin: 0;
flex: 0;
&[type="number"] {
min-width: 9em;
&.-small {
min-width: 5em;
}
}
&[type="range"] {
flex: 1;
min-width: 9em;
align-self: center;
margin: 0 0.25em;
}
&[type="checkbox"] + i {
height: 1.1em;
align-self: center;
}
}
}
.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;
}
}
}
.palette-editor {
- > .label:not(.Select) {
- font-weight: bold;
- justify-self: right;
+ display: grid;
+
+ .palette-selector {
+ &-label {
+ font-weight: bold;
+ }
}
}
.component-editor {
display: grid;
grid-template-columns: 6fr 3fr 4fr;
grid-template-rows: auto auto 1fr;
grid-gap: 0.5em;
grid-template-areas:
"component component variant"
"state state state"
"preview settings settings";
.component-selector {
grid-area: component;
align-self: center;
}
.component-selector,
.state-selector,
.variant-selector {
display: grid;
grid-template-columns: 1fr minmax(1fr, 10em);
grid-template-rows: auto;
grid-auto-flow: column;
grid-gap: 0.5em;
align-items: baseline;
> label:not(.Select) {
font-weight: bold;
justify-self: right;
}
}
.state-selector {
grid-area: state;
grid-template-columns: minmax(min-content, 7em) 1fr;
}
.variant-selector {
grid-area: variant;
}
.state-selector-list {
display: grid;
list-style: none;
grid-auto-flow: dense;
grid-template-columns: repeat(5, minmax(min-content, 1fr));
grid-auto-rows: 1fr;
grid-gap: 0.5em;
padding: 0;
margin: 0;
}
.preview-container {
--border: none;
--shadow: none;
--roundness: none;
grid-area: preview;
}
.component-settings {
grid-area: settings;
}
.editor-tab {
display: grid;
grid-template-columns: 1fr 2em;
grid-column-gap: 0.5em;
align-items: center;
grid-auto-rows: min-content;
grid-auto-flow: dense;
border-left: 1px solid var(--border);
border-right: 1px solid var(--border);
border-bottom: 1px solid var(--border);
padding: 0.5em;
}
.shadow-tab {
grid-template-columns: 1fr;
justify-items: center;
}
}
}
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 b73732f8aa..9951849aac 100644
--- a/src/components/settings_modal/tabs/style_tab/style_tab.vue
+++ b/src/components/settings_modal/tabs/style_tab/style_tab.vue
@@ -1,292 +1,297 @@
<script src="./style_tab.js">
</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="exportStyle"
>
<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>
<tab-switcher>
<div
key="component"
class="setting-item component-editor"
:label="$t('settings.style.themes3.editor.component_tab')"
>
<div class="component-selector">
<label for="component-selector">
{{ $t('settings.style.themes3.editor.component_selector') }}
{{ ' ' }}
</label>
<Select
id="component-selector"
v-model="selectedComponentKey"
>
<option
v-for="key in componentKeys"
:key="'component-' + key"
:value="key"
>
{{ fallbackI18n($t(getFriendlyNamePath(componentsMap.get(key).name)), componentsMap.get(key).name) }}
</option>
</Select>
</div>
<div
v-if="selectedComponentVariantsAll.length > 1"
class="variant-selector"
>
<label for="variant-selector">
{{ $t('settings.style.themes3.editor.variant_selector') }}
</label>
<Select
v-model="selectedVariant"
>
<option
v-for="variant in selectedComponentVariantsAll"
:key="'component-variant-' + variant"
:value="variant"
>
{{ fallbackI18n($t(getVariantPath(selectedComponentName, variant)), variant) }}
</option>
</Select>
</div>
<div
v-if="selectedComponentStates.length > 0"
class="state-selector"
>
<label>
{{ $t('settings.style.themes3.editor.states_selector') }}
</label>
<ul
class="state-selector-list"
>
<li
v-for="state in selectedComponentStates"
:key="'component-state-' + state"
>
<Checkbox
:value="selectedState.has(state)"
@update:modelValue="(v) => updateSelectedStates(state, v)"
>
{{ fallbackI18n($t(getStatePath(selectedComponentName, state)), state) }}
</Checkbox>
</li>
</ul>
</div>
<div class="preview-container">
<!-- eslint-disable vue/no-v-html vue/no-v-text-v-html-on-component -->
<component
:is="'style'"
v-html="previewCss"
/>
<!-- eslint-enable vue/no-v-html vue/no-v-text-v-html-on-component -->
<ComponentPreview
class="component-preview"
:show-text="componentHas('Text')"
:shadow-control="isShadowTabOpen"
:preview-class="previewClass"
:preview-style="editorHintStyle"
:disabled="!editedSubShadow && typeof editedShadow !== 'string'"
:shadow="editedSubShadow"
@update:shadow="({ axis, value }) => updateSubShadow(axis, value)"
/>
</div>
<tab-switcher
ref="tabSwitcher"
class="component-settings"
:on-switch="onTabSwitch"
>
<div
key="main"
class="editor-tab"
:label="$t('settings.style.themes3.editor.main_tab')"
>
<ColorInput
v-model="editedBackgroundColor"
:disabled="!isBackgroundColorPresent"
:label="$t('settings.style.themes3.editor.background')"
/>
<Tooltip :text="$t('settings.style.themes3.editor.include_in_rule')">
<Checkbox v-model="isBackgroundColorPresent" />
</Tooltip>
<OpacityInput
v-model="editedOpacity"
:disabled="!isOpacityPresent"
:label="$t('settings.style.themes3.editor.opacity')"
/>
<Tooltip :text="$t('settings.style.themes3.editor.include_in_rule')">
<Checkbox v-model="isOpacityPresent" />
</Tooltip>
<ColorInput
v-if="componentHas('Text')"
v-model="editedTextColor"
:label="$t('settings.style.themes3.editor.text_color')"
:disabled="!isTextColorPresent"
/>
<Tooltip
v-if="componentHas('Text')"
:text="$t('settings.style.themes3.editor.include_in_rule')"
>
<Checkbox v-model="isTextColorPresent" />
</Tooltip>
<div class="style-control suboption">
<label
for="textAuto"
class="label"
:class="{ faint: !isTextAutoPresent }"
>
{{ $t('settings.style.themes3.editor.text_auto.label') }}
</label>
<Select
id="textAuto"
v-model="editedTextAuto"
:disabled="!isTextAutoPresent"
>
<option value="no-preserve">
{{ $t('settings.style.themes3.editor.text_auto.no-preserve') }}
</option>
<option value="no-auto">
{{ $t('settings.style.themes3.editor.text_auto.no-auto') }}
</option>
<option value="preserve">
{{ $t('settings.style.themes3.editor.text_auto.preserve') }}
</option>
</Select>
</div>
<Tooltip
v-if="componentHas('Text')"
:text="$t('settings.style.themes3.editor.include_in_rule')"
>
<Checkbox v-model="isTextAutoPresent" />
</Tooltip>
<div>
<ContrastRatio :contrast="getContrast(editedBackgroundColor, editedTextColor)" />
</div>
<div>
<!-- spacer for missing checkbox -->
</div>
<ColorInput
v-if="componentHas('Link')"
v-model="editedLinkColor"
:label="$t('settings.style.themes3.editor.link_color')"
:disabled="!isLinkColorPresent"
/>
<Tooltip
v-if="componentHas('Link')"
:text="$t('settings.style.themes3.editor.include_in_rule')"
>
<Checkbox v-model="isLinkColorPresent" />
</Tooltip>
<ColorInput
v-if="componentHas('Icon')"
v-model="editedIconColor"
:label="$t('settings.style.themes3.editor.icon_color')"
:disabled="!isIconColorPresent"
/>
<Tooltip
v-if="componentHas('Icon')"
:text="$t('settings.style.themes3.editor.include_in_rule')"
>
<Checkbox v-model="isIconColorPresent" />
</Tooltip>
</div>
<div
key="shadow"
class="editor-tab shadow-tab"
:label="$t('settings.style.themes3.editor.shadows_tab')"
>
<Checkbox
v-model="isShadowPresent"
class="style-control"
>
{{ $t('settings.style.themes3.editor.include_in_rule') }}
</checkbox>
<ShadowControl
v-model="editedShadow"
:disabled="!isShadowPresent"
:no-preview="true"
:separate-inset="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'"
@subShadowSelected="onSubShadow"
/>
</div>
</tab-switcher>
</div>
<div
key="palette"
:label="$t('settings.style.themes3.editor.palette_tab')"
class="setting-item palette-editor"
>
- <div class="label">
- <label for="palette-selector">
+ <label
+ class="palette-selector-label"
+ for="palette-selector"
+ >
{{ $t('settings.style.themes3.palette.label') }}
{{ ' ' }}
</label>
<Select
id="palette-selector"
v-model="editedPalette"
+ class="palette-list"
+ size="10"
>
<option
- key="dark"
- value="dark"
- >
- {{ $t('settings.style.themes3.palette.dark') }}
- </option>
- <option
- key="light"
- value="light"
+ v-for="(p, index) in palettes"
+ :key="p"
+ :value="index"
>
- {{ $t('settings.style.themes3.palette.light') }}
+ {{ p }}
</option>
</Select>
- </div>
+ <SelectMotion
+ class="palette-list-movement"
+ v-model="palettes"
+ :selected-id="editedPalette"
+ :get-add-value="getNewPalette"
+ @update:selectedId="e => editecPalette = e"
+ />
<PaletteEditor v-model="palette" />
</div>
</tab-switcher>
</div>
</template>
<style src="./style_tab.scss" lang="scss"></style>

File Metadata

Mime Type
text/x-diff
Expires
Sun, Nov 1, 9:01 AM (5 h, 45 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1802881
Default Alt Text
(33 KB)

Event Timeline