shadow editor now can display shadow information

This commit is contained in:
Henry Jameson 2024-09-26 01:06:14 +03:00
parent b4a1bcd070
commit ef795becf6
4 changed files with 195 additions and 64 deletions

View file

@ -4,6 +4,8 @@ import Select from 'src/components/select/select.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue' import Checkbox from 'src/components/checkbox/checkbox.vue'
import ComponentPreview from 'src/components/component_preview/component_preview.vue' import ComponentPreview from 'src/components/component_preview/component_preview.vue'
import StringSetting from '../../helpers/string_setting.vue' import StringSetting from '../../helpers/string_setting.vue'
import ShadowControl from 'src/components/shadow_control/shadow_control.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import { init } from 'src/services/theme_data/theme_data_3.service.js' import { init } from 'src/services/theme_data/theme_data_3.service.js'
import { getCssRules } from 'src/services/theme_data/css_utils.js' import { getCssRules } from 'src/services/theme_data/css_utils.js'
@ -11,6 +13,8 @@ import { getCssRules } from 'src/services/theme_data/css_utils.js'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { faFloppyDisk, faFolderOpen, faFile } from '@fortawesome/free-solid-svg-icons' import { faFloppyDisk, faFolderOpen, faFile } from '@fortawesome/free-solid-svg-icons'
const toValue = (x) => JSON.parse(JSON.stringify(x === undefined ? '"lol"' : x))
library.add( library.add(
faFile, faFile,
faFloppyDisk, faFloppyDisk,
@ -22,14 +26,18 @@ export default {
Select, Select,
Checkbox, Checkbox,
StringSetting, StringSetting,
ComponentPreview ComponentPreview,
TabSwitcher,
ShadowControl
}, },
setup () { setup () {
// Meta stuff
const name = ref('') const name = ref('')
const author = ref('') const author = ref('')
const license = ref('') const license = ref('')
const website = ref('') const website = ref('')
// Initialization stuff
const palette = { const palette = {
// These are here just to establish order, // These are here just to establish order,
// themes should override those // themes should override those
@ -61,43 +69,54 @@ export default {
// Getting existing components // Getting existing components
const componentsContext = require.context('src', true, /\.style.js(on)?$/) const componentsContext = require.context('src', true, /\.style.js(on)?$/)
const componentKeysRaw = componentsContext.keys() const componentKeysAll = componentsContext.keys()
const componentsMap = new Map( const componentsMap = new Map(
componentKeysRaw componentKeysAll
.map( .map(
key => [key, componentsContext(key).default] key => [key, componentsContext(key).default]
).filter(([key, component]) => !component.virtual && !component.notEditable) ).filter(([key, component]) => !component.virtual && !component.notEditable)
) )
const componentKeys = [...componentsMap.keys()] const componentKeys = [...componentsMap.keys()]
// const componentValues = componentsMap.values()
// Initializing selected component and its computed descendants // Initializing selected component and its computed descendants
const selectedComponentKey = ref(componentKeys[0]) const selectedComponentKey = ref(componentsMap.keys().next().value)
const selectedComponentValue = computed(() => componentsMap.get(selectedComponentKey.value)) const selectedComponent = computed(() => componentsMap.get(selectedComponentKey.value))
const selectedComponentName = computed(() => selectedComponent.value.name)
const selectedComponentName = computed(() => selectedComponentValue.value.name)
const selectedComponentVariants = computed(() => {
return new Set(['normal', ...(Object.keys(selectedComponentValue.value.variants || {}))])
})
const selectedComponentStates = computed(() => {
return new Set([...(Object.keys(selectedComponentValue.value.states || {}).filter(x => x !== 'normal'))])
})
const selectedVariant = ref('normal') const selectedVariant = ref('normal')
const selectedStates = reactive(new Set()) const selectedComponentVariantsAll = computed(() => {
return Object.keys({ normal: null, ...(selectedComponent.value.variants || {}) })
})
// const selectedComponentVariants = computed(() => {
// return selectedComponentVariantsAll.value.filter(x => x !== 'normal')
// })
const updateSelectedStates = (state, v) => { const selectedStates = reactive(new Set())
if (v) { const selectedComponentStatesAll = computed(() => {
selectedStates.add(state) return Object.keys({ normal: null, ...(selectedComponent.value.states || {}) })
} else { })
selectedStates.delete(state) const selectedComponentStates = computed(() => {
return selectedComponentStatesAll.value.filter(x => x !== 'normal')
})
// 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('; ')
})
const simulatePseudoSelectors = css => css const simulatePseudoSelectors = css => css
.replace(selectedComponentValue.value.selector, '.ComponentPreview .preview-block') .replace(selectedComponent.value.selector, '.ComponentPreview .preview-block')
.replace(':active', '.preview-active') .replace(':active', '.preview-active')
.replace(':hover', '.preview-hover') .replace(':hover', '.preview-hover')
.replace(':active', '.preview-active') .replace(':active', '.preview-active')
@ -108,44 +127,70 @@ export default {
const previewRules = reactive([]) const previewRules = reactive([])
const previewClass = computed(() => { const previewClass = computed(() => {
const selectors = [] const selectors = []
if (!!selectedComponentValue.value.variants?.normal || selectedVariant.value !== 'normal') { if (!!selectedComponent.value.variants?.normal || selectedVariant.value !== 'normal') {
selectors.push(selectedComponentValue.value.variants[selectedVariant.value]) selectors.push(selectedComponent.value.variants[selectedVariant.value])
} }
if (selectedStates.size > 0) { if (selectedStates.size > 0) {
selectedStates.forEach(state => { selectedStates.forEach(state => {
const original = selectedComponentValue.value.states[state] const original = selectedComponent.value.states[state]
selectors.push(simulatePseudoSelectors(original)) selectors.push(simulatePseudoSelectors(original))
}) })
} }
return selectors.map(x => x.substring(1)).join('') return selectors.map(x => x.substring(1)).join('')
}) })
const editorHintStyle = computed(() => {
const editorHint = selectedComponentValue.value.editor
const styles = []
if (editorHint && Object.keys(editorHint).length > 0) {
console.log('EH', editorHint)
if (editorHint.aspect != null) {
styles.push(`aspect-ratio: ${editorHint.aspect} !important;`)
}
if (editorHint.border != null) {
styles.push(`border-width: ${editorHint.border}px !important;`)
}
}
console.log('EH', styles)
return styles.join('; ')
})
const previewCss = computed(() => { const previewCss = computed(() => {
const scoped = getCssRules(previewRules) const scoped = getCssRules(previewRules)
.map(simulatePseudoSelectors) .map(simulatePseudoSelectors)
return scoped.join('\n') return scoped.join('\n')
}) })
// Rules stuff
const selectedComponentRulesList = reactive([])
const selectedComponentRulesObject = computed(() => {
const result = {}
selectedComponentRulesList.forEach(
(rule) => {
const component = rule.component
const { variant = 'normal', state = [] } = rule
result[component] = result[component] || {}
result[component][variant] = result[component][variant] || {}
result[component][variant][state.join(':')] = rule
}
)
return result
})
// Edited rule
const editedRuleFallback = computed(() => {
const component = selectedComponentName.value
const variant = selectedVariant.value
const states = ['normal', ...selectedStates.keys()].join(':')
return selectedComponentRulesObject.value[component]?.[variant]?.[states]
})
const editedShadow = computed(() => {
return editedRuleFallback.value?.directives.shadow
})
const updateSelectedComponent = () => { const updateSelectedComponent = () => {
selectedVariant.value = 'normal' selectedVariant.value = 'normal'
selectedStates.clear() selectedStates.clear()
const processedRulesList = selectedComponent.value.defaultRules.map(r => {
const rule = {
component: selectedComponentName.value,
variant: 'normal',
...r,
state: ['normal', ...(r.state || []).filter(x => x !== 'normal')]
}
return rule
})
selectedComponentRulesList.splice(0, selectedComponentRulesList.length)
selectedComponentRulesList.push(...processedRulesList)
console.log('FALLBACK', toValue(editedRuleFallback.value))
previewRules.splice(0, previewRules.length) previewRules.splice(0, previewRules.length)
previewRules.push(...init({ previewRules.push(...init({
inputRuleset: [{ inputRuleset: [{
@ -175,21 +220,29 @@ export default {
website, website,
componentKeys, componentKeys,
componentsMap, componentsMap,
selectedComponent,
selectedComponentValue,
selectedComponentName, selectedComponentName,
selectedComponentKey, selectedComponentKey,
selectedComponentVariants, selectedComponentVariantsAll,
selectedComponentStates, selectedComponentStates,
updateSelectedStates, selectedComponentRulesObject,
selectedVariant, selectedVariant,
selectedStates, selectedStates,
getFriendlyNamePath, updateSelectedStates (state, v) {
getStatePath, if (v) {
getVariantPath, selectedStates.add(state)
editorHintStyle, } else {
selectedStates.delete(state)
}
},
editedRuleFallback,
editedShadow,
previewCss, previewCss,
previewClass, previewClass,
editorHintStyle,
getFriendlyNamePath,
getVariantPath,
getStatePath,
fallbackI18n (translated, fallback) { fallbackI18n (translated, fallback) {
if (translated.startsWith('settings.style.themes3')) { if (translated.startsWith('settings.style.themes3')) {
return fallback return fallback

View file

@ -1,4 +1,48 @@
.StyleTab { .StyleTab {
.style-control {
display: flex;
flex-wrap: wrap;
align-items: baseline;
margin-bottom: 0.5em;
.label {
margin-right: 1em;
flex: 1 1 10em;
line-height: 2;
}
.opt {
margin: 0.5em;
}
.color-input {
flex: 0 0 0;
}
input,
select {
min-width: 3em;
margin: 0;
flex: 0;
&[type="number"] {
min-width: 5em;
}
&[type="range"] {
flex: 1;
min-width: 2em;
align-self: center;
margin: 0 0.5em;
}
&[type="checkbox"] + i {
height: 1.1em;
align-self: center;
}
}
}
.setting-item { .setting-item {
padding-bottom: 0; padding-bottom: 0;
@ -74,6 +118,8 @@
.state-selector { .state-selector {
grid-area: state; grid-area: state;
align-content: flex-start;
align-items: flex-start;
} }
.variant-selector { .variant-selector {
@ -96,5 +142,12 @@
.component-settings { .component-settings {
grid-area: settings; grid-area: settings;
} }
.editor-tab {
border-left: 1px solid var(--border);
border-right: 1px solid var(--border);
border-bottom: 1px solid var(--border);
padding: 0.5em;
}
} }
} }

View file

@ -83,44 +83,44 @@
{{ $t('settings.style.themes3.editor.variant_selector') }} {{ $t('settings.style.themes3.editor.variant_selector') }}
</label> </label>
<Select <Select
v-if="selectedComponentVariants.size > 1" v-if="selectedComponentVariantsAll.length > 1"
v-model="selectedVariant" v-model="selectedVariant"
> >
<option <option
v-for="variant in selectedComponentVariants" v-for="variant in selectedComponentVariantsAll"
:value="variant" :value="variant"
:key="'component-variant-' + variant" :key="'component-variant-' + variant"
> >
{{ fallbackI18n($t(getVariantPath(selectedComponentName, variant)), variant) }} {{ fallbackI18n($t(getVariantPath(selectedComponentName, variant)), variant) }}
</option> </option>
</Select> </Select>
<p v-else> <div v-else>
{{ $t('settings.style.themes3.editor.only_variant') }} {{ $t('settings.style.themes3.editor.only_variant') }}
</p> </div>
</div> </div>
<div class="state-selector"> <div class="state-selector">
<label for="variant-selector"> <label for="variant-selector">
{{ $t('settings.style.themes3.editor.states_selector') }} {{ $t('settings.style.themes3.editor.states_selector') }}
</label> </label>
<ul <ul
v-if="selectedComponentStates.size > 0" v-if="selectedComponentStates.length > 0"
class="state-selector-list" class="state-selector-list"
> >
<li <li
v-for="state in selectedComponentStates" v-for="state in selectedComponentStates"
:key="'component-variant-' + state" :key="'component-variant-' + state"
> >
<Checkbox <Checkbox
:value="selectedStates.has(state)" :value="selectedStates.has(state)"
@update:modelValue="(v) => updateSelectedStates(state, v)" @update:modelValue="(v) => updateSelectedStates(state, v)"
> >
{{ fallbackI18n($t(getStatePath(selectedComponentName, state)), state) }} {{ fallbackI18n($t(getStatePath(selectedComponentName, state)), state) }}
</Checkbox> </Checkbox>
</li> </li>
</ul> </ul>
<p v-else> <div v-else>
{{ $t('settings.style.themes3.editor.only_state') }} {{ $t('settings.style.themes3.editor.only_state') }}
</p> </div>
</div> </div>
<div class="preview-container"> <div class="preview-container">
<!-- eslint-disable vue/no-v-html vue/no-v-text-v-html-on-component --> <!-- eslint-disable vue/no-v-html vue/no-v-text-v-html-on-component -->
@ -136,8 +136,31 @@
@update:shadow="({ axis, value }) => updateProperty(axis, value)" @update:shadow="({ axis, value }) => updateProperty(axis, value)"
/> />
</div> </div>
<div class="component-setting"> <tab-switcher
</div> ref="tabSwitcher"
class="component-settings"
:on-switch="onTabSwitch"
>
<div
class="editor-tab"
:label="$t('settings.style.themes3.editor.main_tab')"
:data-tab-name="main"
>
lol
</div>
<div
class="editor-tab"
:label="$t('settings.style.themes3.editor.shadows_tab')"
:data-tab-name="shadow"
>
<ShadowControl
v-model="editedShadow"
:no-preview="true"
:separate-inset="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'"
:fallback="currentShadowFallback"
/>
</div>
</tab-switcher>
</div> </div>
</div> </div>
</template> </template>

View file

@ -767,6 +767,8 @@
"states_selector": "States", "states_selector": "States",
"only_variant": "Component doesn't have any variants", "only_variant": "Component doesn't have any variants",
"only_state": "Component only has default state", "only_state": "Component only has default state",
"main_tab": "Main",
"shadows_tab": "Shadows",
"components": { "components": {
"normal": { "normal": {
"state": "Normal", "state": "Normal",