Merge branch 'themes3-grand-finale-maybe' into shigusegubu-themes3
This commit is contained in:
commit
eac63e0c57
17 changed files with 477 additions and 254 deletions
|
@ -130,7 +130,7 @@ export default {
|
|||
return this.modelValue === 'transparent'
|
||||
},
|
||||
computedColor () {
|
||||
return this.modelValue && this.modelValue.startsWith('--')
|
||||
return this.modelValue && (this.modelValue.startsWith('--') || this.modelValue.startsWith('$'))
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
:class="previewClass"
|
||||
:style="previewStyle"
|
||||
>
|
||||
TEST
|
||||
{{ $t('settings.style.themes3.editor.test_string') }}
|
||||
</div>
|
||||
</div>
|
||||
<input
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<script setup>
|
||||
import ColorInput from 'src/components/color_input/color_input.vue'
|
||||
import {
|
||||
// newImporter,
|
||||
newImporter,
|
||||
newExporter
|
||||
} from 'src/services/export_import/export_import.js'
|
||||
|
||||
|
@ -46,23 +46,23 @@ library.add(
|
|||
const props = defineProps(['modelValue'])
|
||||
const emit = defineEmits(['update:modelValue'])
|
||||
const paletteExporter = newExporter({
|
||||
filename: 'pleroma.palette.json',
|
||||
filename: 'pleroma_palette',
|
||||
extension: 'json',
|
||||
getExportedObject: () => props.modelValue
|
||||
})
|
||||
/*
|
||||
const themeImporter = newImporter({
|
||||
validator: importValidator,
|
||||
onImport,
|
||||
onImportFailure,
|
||||
})
|
||||
*/
|
||||
const paletteImporter = newImporter({
|
||||
accept: '.json',
|
||||
onImport (parsed, filename) {
|
||||
emit('update:modelValue', parsed)
|
||||
}
|
||||
})
|
||||
|
||||
const exportPalette = () => {
|
||||
paletteExporter.exportData()
|
||||
}
|
||||
|
||||
const importPalette = () => {
|
||||
// TODO
|
||||
paletteImporter.importData()
|
||||
}
|
||||
|
||||
const paletteKeys = [
|
||||
|
|
|
@ -49,6 +49,7 @@ label.Select {
|
|||
option {
|
||||
background-color: transparent;
|
||||
|
||||
&:checked,
|
||||
&.-active {
|
||||
color: var(--selectionText);
|
||||
background-color: var(--selectionBackground);
|
||||
|
|
|
@ -170,7 +170,7 @@ export default {
|
|||
},
|
||||
configSink () {
|
||||
if (this.path == null) {
|
||||
return (k, v) => this.$emit('modelValue:update', v)
|
||||
return (k, v) => this.$emit('update:modelValue', v)
|
||||
}
|
||||
switch (this.realSource) {
|
||||
case 'profile':
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
>
|
||||
<label
|
||||
:for="path"
|
||||
class="setting-label"
|
||||
:class="{ 'faint': shouldBeDisabled }"
|
||||
>
|
||||
<template v-if="backendDescriptionLabel">
|
||||
|
|
|
@ -13,23 +13,33 @@ 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 Preview from '../theme_tab/theme_preview.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 { parseShadow /* , deserialize */ } from 'src/services/theme_data/iss_deserializer.js'
|
||||
import { init, findColor } from 'src/services/theme_data/theme_data_3.service.js'
|
||||
import {
|
||||
// rgb2hex,
|
||||
getCssRules,
|
||||
getScopedVersion
|
||||
} from 'src/services/theme_data/css_utils.js'
|
||||
import { serializeShadow, serialize } from 'src/services/theme_data/iss_serializer.js'
|
||||
import { parseShadow, deserialize } from 'src/services/theme_data/iss_deserializer.js'
|
||||
import {
|
||||
rgb2hex,
|
||||
hex2rgb,
|
||||
getContrastRatio
|
||||
} from 'src/services/color_convert/color_convert.js'
|
||||
import {
|
||||
// newImporter,
|
||||
newImporter,
|
||||
newExporter
|
||||
} from 'src/services/export_import/export_import.js'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import { faFloppyDisk, faFolderOpen, faFile } from '@fortawesome/free-solid-svg-icons'
|
||||
import {
|
||||
faFloppyDisk,
|
||||
faFolderOpen,
|
||||
faFile,
|
||||
faArrowsRotate,
|
||||
faCheck
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
// helper for debugging
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
|
@ -41,7 +51,9 @@ const normalizeStates = (states) => ['normal', ...(states?.filter(x => x !== 'no
|
|||
library.add(
|
||||
faFile,
|
||||
faFloppyDisk,
|
||||
faFolderOpen
|
||||
faFolderOpen,
|
||||
faArrowsRotate,
|
||||
faCheck
|
||||
)
|
||||
|
||||
export default {
|
||||
|
@ -57,25 +69,27 @@ export default {
|
|||
ColorInput,
|
||||
PaletteEditor,
|
||||
OpacityInput,
|
||||
ContrastRatio
|
||||
ContrastRatio,
|
||||
Preview
|
||||
},
|
||||
setup () {
|
||||
const exports = {}
|
||||
// All rules that are made by editor
|
||||
const allEditedRules = reactive({})
|
||||
|
||||
// ## Meta stuff
|
||||
const name = ref('')
|
||||
const author = ref('')
|
||||
const license = ref('')
|
||||
const website = ref('')
|
||||
exports.name = ref('')
|
||||
exports.author = ref('')
|
||||
exports.license = ref('')
|
||||
exports.website = ref('')
|
||||
|
||||
const metaOut = computed(() => {
|
||||
return [
|
||||
'@meta {',
|
||||
` name: ${name.value};`,
|
||||
` author: ${author.value};`,
|
||||
` license: ${license.value};`,
|
||||
` website: ${website.value};`,
|
||||
` name: ${exports.name.value};`,
|
||||
` author: ${exports.author.value};`,
|
||||
` license: ${exports.license.value};`,
|
||||
` website: ${exports.website.value};`,
|
||||
'}'
|
||||
].join('\n')
|
||||
})
|
||||
|
@ -108,6 +122,20 @@ export default {
|
|||
border: '#d8e6f9'
|
||||
}
|
||||
])
|
||||
exports.palettes = palettes
|
||||
|
||||
// This is kinda dumb but you cannot "replace" reactive() object
|
||||
// and so v-model simply fails when you try to chage (increase only?)
|
||||
// length of the array. Since linter complains about mutating modelValue
|
||||
// inside SelectMotion, the next best thing is to just wipe existing array
|
||||
// and replace it with new one.
|
||||
|
||||
const onPalettesUpdate = (e) => {
|
||||
palettes.splice(0, palettes.length)
|
||||
palettes.push(...e)
|
||||
}
|
||||
exports.onPalettesUpdate = onPalettesUpdate
|
||||
|
||||
const selectedPaletteId = ref(0)
|
||||
const selectedPalette = computed({
|
||||
get () {
|
||||
|
@ -117,7 +145,10 @@ export default {
|
|||
palettes[selectedPaletteId.value] = newPalette
|
||||
}
|
||||
})
|
||||
const getNewPalette = () => ({
|
||||
exports.selectedPaletteId = selectedPaletteId
|
||||
exports.selectedPalette = selectedPalette
|
||||
|
||||
exports.getNewPalette = () => ({
|
||||
name: 'new palette',
|
||||
bg: '#121a24',
|
||||
fg: '#182230',
|
||||
|
@ -151,26 +182,31 @@ export default {
|
|||
key => [key, componentsContext(key).default]
|
||||
).filter(([key, component]) => !component.virtual && !component.notEditable)
|
||||
)
|
||||
exports.componentsMap = componentsMap
|
||||
const componentKeys = [...componentsMap.keys()]
|
||||
exports.componentKeys = componentKeys
|
||||
|
||||
// selection basis
|
||||
const selectedComponentKey = ref(componentsMap.keys().next().value)
|
||||
exports.selectedComponentKey = selectedComponentKey
|
||||
const selectedComponent = computed(() => componentsMap.get(selectedComponentKey.value))
|
||||
const selectedComponentName = computed(() => selectedComponent.value.name)
|
||||
const selectedComponentVariants = computed(() => {
|
||||
exports.selectedComponentVariants = computed(() => {
|
||||
return Object.keys({ normal: null, ...(selectedComponent.value.variants || {}) })
|
||||
})
|
||||
const selectedComponentStatesAll = computed(() => {
|
||||
return Object.keys({ normal: null, ...(selectedComponent.value.states || {}) })
|
||||
})
|
||||
const selectedComponentStates = computed(() => {
|
||||
exports.selectedComponentStates = computed(() => {
|
||||
return selectedComponentStatesAll.value.filter(x => x !== 'normal')
|
||||
})
|
||||
|
||||
// selection
|
||||
const selectedVariant = ref('normal')
|
||||
exports.selectedVariant = selectedVariant
|
||||
const selectedState = reactive(new Set())
|
||||
const updateSelectedStates = (state, v) => {
|
||||
exports.selectedState = selectedState
|
||||
exports.updateSelectedStates = (state, v) => {
|
||||
if (v) {
|
||||
selectedState.add(state)
|
||||
} else {
|
||||
|
@ -182,47 +218,53 @@ export default {
|
|||
// 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 rulesToEditorFriendly = (rules, root = {}) => rules.reduce((acc, rule) => {
|
||||
const { parent: rParent, component: rComponent } = 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 : rComponent}.${pVariant}.${normalizeStates(pState)}`
|
||||
|
||||
let output = get(acc, pPath)
|
||||
if (!output) {
|
||||
set(acc, pPath, {})
|
||||
output = get(acc, pPath)
|
||||
}
|
||||
|
||||
if (hasChildren) {
|
||||
acc._children = acc._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 acc
|
||||
}, root)
|
||||
|
||||
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
|
||||
}
|
||||
})
|
||||
const { defaultRules, name } = componentValue
|
||||
rulesToEditorFriendly(
|
||||
defaultRules.map((rule) => ({ ...rule, component: name })),
|
||||
root
|
||||
)
|
||||
})
|
||||
|
||||
return root
|
||||
|
@ -230,7 +272,7 @@ export default {
|
|||
|
||||
// Checkging whether component can support some "directives" which
|
||||
// are actually virtual subcomponents, i.e. Text, Link etc
|
||||
const componentHas = (subComponent) => {
|
||||
exports.componentHas = (subComponent) => {
|
||||
return !!selectedComponent.value.validInnerComponents?.find(x => x === subComponent)
|
||||
}
|
||||
|
||||
|
@ -283,21 +325,24 @@ export default {
|
|||
})
|
||||
|
||||
// All the editable stuff for the component
|
||||
const editedBackgroundColor = getEditedElement(null, 'background')
|
||||
const isBackgroundColorPresent = isElementPresent(null, 'background', '#FFFFFF')
|
||||
const editedOpacity = getEditedElement(null, 'opacity')
|
||||
const isOpacityPresent = isElementPresent(null, 'opacity', 1)
|
||||
const editedTextColor = getEditedElement('Text', 'textColor')
|
||||
const isTextColorPresent = isElementPresent('Text', 'textColor', '#000000')
|
||||
const editedTextAuto = getEditedElement('Text', 'textAuto')
|
||||
const isTextAutoPresent = isElementPresent('Text', 'textAuto', '#000000')
|
||||
const editedLinkColor = getEditedElement('Link', 'textColor')
|
||||
const isLinkColorPresent = isElementPresent('Link', 'textColor', '#000080')
|
||||
const editedIconColor = getEditedElement('Icon', 'textColor')
|
||||
const isIconColorPresent = isElementPresent('Icon', 'textColor', '#909090')
|
||||
exports.editedBackgroundColor = getEditedElement(null, 'background')
|
||||
exports.isBackgroundColorPresent = isElementPresent(null, 'background', '#FFFFFF')
|
||||
exports.editedOpacity = getEditedElement(null, 'opacity')
|
||||
exports.isOpacityPresent = isElementPresent(null, 'opacity', 1)
|
||||
exports.editedTextColor = getEditedElement('Text', 'textColor')
|
||||
exports.isTextColorPresent = isElementPresent('Text', 'textColor', '#000000')
|
||||
exports.editedTextAuto = getEditedElement('Text', 'textAuto')
|
||||
exports.isTextAutoPresent = isElementPresent('Text', 'textAuto', '#000000')
|
||||
exports.editedLinkColor = getEditedElement('Link', 'textColor')
|
||||
exports.isLinkColorPresent = isElementPresent('Link', 'textColor', '#000080')
|
||||
exports.editedIconColor = getEditedElement('Icon', 'textColor')
|
||||
exports.isIconColorPresent = isElementPresent('Icon', 'textColor', '#909090')
|
||||
exports.editedBorderColor = getEditedElement('Border', 'textColor')
|
||||
exports.isBorderColorPresent = isElementPresent('Border', 'textColor', '#909090')
|
||||
|
||||
// TODO this is VERY primitive right now, need to make it
|
||||
// support variables, fallbacks etc.
|
||||
const getContrast = (bg, text) => {
|
||||
exports.getContrast = (bg, text) => {
|
||||
try {
|
||||
const bgRgb = hex2rgb(bg)
|
||||
const textRgb = hex2rgb(text)
|
||||
|
@ -321,7 +366,6 @@ export default {
|
|||
}
|
||||
|
||||
const normalizeShadows = (shadows) => {
|
||||
console.log('NORMALIZE')
|
||||
return shadows?.map(shadow => {
|
||||
if (typeof shadow === 'object') {
|
||||
return shadow
|
||||
|
@ -336,20 +380,23 @@ export default {
|
|||
// Shadow is partially edited outside the ShadowControl
|
||||
// for better space utilization
|
||||
const editedShadow = getEditedElement(null, 'shadow', normalizeShadows)
|
||||
exports.editedShadow = editedShadow
|
||||
const editedSubShadowId = ref(null)
|
||||
exports.editedSubShadowId = editedSubShadowId
|
||||
const editedSubShadow = computed(() => {
|
||||
if (editedShadow.value == null || editedSubShadowId.value == null) return null
|
||||
return editedShadow.value[editedSubShadowId.value]
|
||||
})
|
||||
const isShadowPresent = isElementPresent(null, 'shadow', [])
|
||||
const onSubShadow = (id) => {
|
||||
exports.editedSubShadow = editedSubShadow
|
||||
exports.isShadowPresent = isElementPresent(null, 'shadow', [])
|
||||
exports.onSubShadow = (id) => {
|
||||
if (id != null) {
|
||||
editedSubShadowId.value = id
|
||||
} else {
|
||||
editedSubShadow.value = null
|
||||
}
|
||||
}
|
||||
const updateSubShadow = (axis, value) => {
|
||||
exports.updateSubShadow = (axis, value) => {
|
||||
if (!editedSubShadow.value || editedSubShadowId.value == null) return
|
||||
const newEditedShadow = [...editedShadow.value]
|
||||
|
||||
|
@ -360,13 +407,13 @@ export default {
|
|||
|
||||
editedShadow.value = newEditedShadow
|
||||
}
|
||||
const isShadowTabOpen = ref(false)
|
||||
const onTabSwitch = (tab) => {
|
||||
isShadowTabOpen.value = tab === 'shadow'
|
||||
exports.isShadowTabOpen = ref(false)
|
||||
exports.onTabSwitch = (tab) => {
|
||||
exports.isShadowTabOpen.value = tab === 'shadow'
|
||||
}
|
||||
|
||||
// component preview
|
||||
const editorHintStyle = computed(() => {
|
||||
exports.editorHintStyle = computed(() => {
|
||||
const editorHint = selectedComponent.value.editor
|
||||
const styles = []
|
||||
if (editorHint && Object.keys(editorHint).length > 0) {
|
||||
|
@ -389,7 +436,7 @@ export default {
|
|||
.replace(':focus', '.preview-focus')
|
||||
.replace(':focus-within', '.preview-focus-within')
|
||||
.replace(':disabled', '.preview-disabled')
|
||||
const previewClass = computed(() => {
|
||||
exports.previewClass = computed(() => {
|
||||
const selectors = []
|
||||
if (!!selectedComponent.value.variants?.normal || selectedVariant.value !== 'normal') {
|
||||
selectors.push(selectedComponent.value.variants[selectedVariant.value])
|
||||
|
@ -403,7 +450,8 @@ export default {
|
|||
return selectors.map(x => x.substring(1)).join('')
|
||||
})
|
||||
const previewRules = reactive([])
|
||||
const previewCss = computed(() => {
|
||||
exports.previewRules = previewRules
|
||||
exports.previewCss = computed(() => {
|
||||
try {
|
||||
const scoped = getCssRules(previewRules).map(simulatePseudoSelectors)
|
||||
return scoped.join('\n')
|
||||
|
@ -523,9 +571,43 @@ export default {
|
|||
}
|
||||
})
|
||||
const virtualDirectives = reactive(allCustomVirtualDirectives)
|
||||
exports.virtualDirectives = virtualDirectives
|
||||
|
||||
exports.onVirtualDirectivesUpdate = (e) => {
|
||||
virtualDirectives.splice(0, virtualDirectives.length)
|
||||
virtualDirectives.push(...e)
|
||||
}
|
||||
|
||||
const selectedVirtualDirectiveId = ref(0)
|
||||
const selectedVirtualDirective = computed(() => virtualDirectives[selectedVirtualDirectiveId.value])
|
||||
const selectedVirtualDirectiveParsed = computed({
|
||||
exports.selectedVirtualDirectiveId = selectedVirtualDirectiveId
|
||||
const selectedVirtualDirective = computed({
|
||||
get () {
|
||||
return virtualDirectives[selectedVirtualDirectiveId.value]
|
||||
},
|
||||
set (value) {
|
||||
virtualDirectives[selectedVirtualDirectiveId.value].value = value
|
||||
}
|
||||
})
|
||||
exports.selectedVirtualDirective = selectedVirtualDirective
|
||||
exports.selectedVirtualDirectiveValType = computed({
|
||||
get () {
|
||||
return virtualDirectives[selectedVirtualDirectiveId.value].valType
|
||||
},
|
||||
set (value) {
|
||||
virtualDirectives[selectedVirtualDirectiveId.value].valType = value
|
||||
switch (value) {
|
||||
case 'shadow':
|
||||
virtualDirectives[selectedVirtualDirectiveId.value].value = '0 0 0 #000000'
|
||||
break
|
||||
case 'color':
|
||||
virtualDirectives[selectedVirtualDirectiveId.value].value = '#000000'
|
||||
break
|
||||
default:
|
||||
virtualDirectives[selectedVirtualDirectiveId.value].value = 'none'
|
||||
}
|
||||
}
|
||||
})
|
||||
exports.selectedVirtualDirectiveParsed = computed({
|
||||
get () {
|
||||
switch (selectedVirtualDirective.value.valType) {
|
||||
case 'shadow': {
|
||||
|
@ -537,25 +619,109 @@ export default {
|
|||
return normalizeShadows(splitShadow)
|
||||
}
|
||||
}
|
||||
case 'color':
|
||||
return selectedVirtualDirective.value.value
|
||||
default:
|
||||
return null
|
||||
return selectedVirtualDirective.value.value
|
||||
}
|
||||
},
|
||||
set (value) {
|
||||
switch (selectedVirtualDirective.value.valType) {
|
||||
case 'shadow': {
|
||||
virtualDirectives[selectedVirtualDirectiveId.value].value = value.map(x => serializeShadow(x)).join(', ')
|
||||
break
|
||||
}
|
||||
default:
|
||||
virtualDirectives[selectedVirtualDirectiveId.value].value = value
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const getNewDirective = () => ({
|
||||
exports.getNewVirtualDirective = () => ({
|
||||
name: 'newDirective',
|
||||
valType: 'generic',
|
||||
value: 'foobar'
|
||||
})
|
||||
|
||||
exports.computeColor = (color) => {
|
||||
const computedColor = findColor(color, { dynamicVars: {}, staticVars: selectedPalette.value })
|
||||
if (computedColor) {
|
||||
return rgb2hex(computedColor)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
const overallPreviewRules = ref()
|
||||
exports.overallPreviewRules = overallPreviewRules
|
||||
exports.updateOverallPreview = () => {
|
||||
try {
|
||||
// This normally would be handled by Root but since we pass something
|
||||
// else we have to make do ourselves
|
||||
|
||||
const { name, ...rest } = selectedPalette.value
|
||||
const paletteRule = {
|
||||
component: 'Root',
|
||||
directives: Object
|
||||
.entries(rest)
|
||||
.map(([k, v]) => ['--' + k, v])
|
||||
.reduce((acc, [k, v]) => ({ ...acc, [k]: `color | ${v}` }), {})
|
||||
}
|
||||
|
||||
const rules = init({
|
||||
inputRuleset: [
|
||||
...editorFriendlyToOriginal.value,
|
||||
paletteRule
|
||||
],
|
||||
ultimateBackgroundColor: '#000000',
|
||||
liteMode: true,
|
||||
debug: true
|
||||
}).eager
|
||||
|
||||
overallPreviewRules.value = getScopedVersion(
|
||||
getCssRules(rules),
|
||||
'#edited-style-preview'
|
||||
).join('\n')
|
||||
} catch (e) {
|
||||
console.error('Could not compile preview theme', e)
|
||||
}
|
||||
}
|
||||
|
||||
// ## Export and Import
|
||||
const styleExporter = newExporter({
|
||||
filename: name.value || 'pleroma_theme',
|
||||
filename: () => exports.name.value ?? 'pleroma_theme',
|
||||
mime: 'text/plain',
|
||||
extension: 'piss',
|
||||
getExportedObject: () => exportStyleData.value
|
||||
})
|
||||
|
||||
const styleImporter = newImporter({
|
||||
accept: '.piss',
|
||||
parser: (string) => deserialize(string),
|
||||
onImport (parsed, filename) {
|
||||
const editorComponents = parsed.filter(x => x.component.startsWith('@'))
|
||||
const rules = parsed.filter(x => !x.component.startsWith('@'))
|
||||
const metaIn = editorComponents.find(x => x.component === '@meta').directives
|
||||
const palettesIn = editorComponents.filter(x => x.component === '@palette')
|
||||
|
||||
exports.name.value = metaIn.name
|
||||
exports.license.value = metaIn.license
|
||||
exports.author.value = metaIn.author
|
||||
exports.website.value = metaIn.website
|
||||
|
||||
onPalettesUpdate(palettesIn.map(x => ({ name: x.variant, ...x.directives })))
|
||||
console.log('PALETTES', palettesIn)
|
||||
|
||||
Object.keys(allEditedRules).forEach((k) => delete allEditedRules[k])
|
||||
|
||||
rules.forEach(rule => {
|
||||
rulesToEditorFriendly(
|
||||
[rule],
|
||||
allEditedRules
|
||||
)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const exportStyleData = computed(() => {
|
||||
return [
|
||||
metaOut.value,
|
||||
|
@ -563,80 +729,15 @@ export default {
|
|||
serialize(editorFriendlyToOriginal.value)
|
||||
].join('\n\n')
|
||||
})
|
||||
const exportStyle = () => {
|
||||
|
||||
exports.exportStyle = () => {
|
||||
styleExporter.exportData()
|
||||
}
|
||||
|
||||
return {
|
||||
// ## Meta
|
||||
name,
|
||||
author,
|
||||
license,
|
||||
website,
|
||||
|
||||
// ## Palette
|
||||
palettes,
|
||||
selectedPalette,
|
||||
selectedPaletteId,
|
||||
getNewPalette,
|
||||
|
||||
// ## Components
|
||||
componentKeys,
|
||||
componentsMap,
|
||||
|
||||
// selection basis
|
||||
selectedComponent,
|
||||
selectedComponentName,
|
||||
selectedComponentKey,
|
||||
selectedComponentVariants,
|
||||
selectedComponentStates,
|
||||
|
||||
// selection
|
||||
selectedVariant,
|
||||
selectedState,
|
||||
updateSelectedStates,
|
||||
|
||||
// component directives
|
||||
componentHas,
|
||||
|
||||
// component colors
|
||||
editedBackgroundColor,
|
||||
isBackgroundColorPresent,
|
||||
editedOpacity,
|
||||
isOpacityPresent,
|
||||
editedTextColor,
|
||||
isTextColorPresent,
|
||||
editedTextAuto,
|
||||
isTextAutoPresent,
|
||||
editedLinkColor,
|
||||
isLinkColorPresent,
|
||||
editedIconColor,
|
||||
isIconColorPresent,
|
||||
getContrast,
|
||||
|
||||
// component shadow
|
||||
editedShadow,
|
||||
editedSubShadow,
|
||||
isShadowPresent,
|
||||
onSubShadow,
|
||||
updateSubShadow,
|
||||
isShadowTabOpen,
|
||||
onTabSwitch,
|
||||
|
||||
// component preview
|
||||
editorHintStyle,
|
||||
previewCss,
|
||||
previewClass,
|
||||
|
||||
// ## Variables
|
||||
virtualDirectives,
|
||||
selectedVirtualDirective,
|
||||
selectedVirtualDirectiveId,
|
||||
selectedVirtualDirectiveParsed,
|
||||
getNewDirective,
|
||||
|
||||
// ## Export and Import
|
||||
exportStyle
|
||||
exports.importStyle = () => {
|
||||
styleImporter.importData()
|
||||
}
|
||||
|
||||
return exports
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,24 +65,60 @@
|
|||
|
||||
&.heading {
|
||||
display: grid;
|
||||
align-items: baseline;
|
||||
grid-template-columns: 1fr auto auto auto;
|
||||
grid-template:
|
||||
"meta meta preview preview"
|
||||
"meta meta preview preview"
|
||||
"meta meta preview preview"
|
||||
"meta meta preview preview"
|
||||
"new new preview preview"
|
||||
"load save refresh apply";
|
||||
grid-gap: 0.5em;
|
||||
grid-template-columns: min-content min-content 6fr max-content;
|
||||
grid-template-rows: repeat(4, min-content) repeat(2, 2em);
|
||||
|
||||
h2 {
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
}
|
||||
ul.setting-list {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
grid-template-rows: subgrid;
|
||||
grid-area: meta;
|
||||
|
||||
&.metadata {
|
||||
display: flex;
|
||||
> li {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.setting-item {
|
||||
flex: 2 0 auto;
|
||||
.meta-field {
|
||||
margin: 0;
|
||||
|
||||
.setting-label {
|
||||
display: inline-block;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
li {
|
||||
text-align: right;
|
||||
#edited-style-preview {
|
||||
grid-area: preview;
|
||||
}
|
||||
|
||||
.button-save {
|
||||
grid-area: save;
|
||||
}
|
||||
|
||||
.button-load {
|
||||
grid-area: load;
|
||||
}
|
||||
|
||||
.button-new {
|
||||
grid-area: new;
|
||||
}
|
||||
|
||||
.button-refresh {
|
||||
grid-area: refresh;
|
||||
}
|
||||
|
||||
.button-apply {
|
||||
grid-area: apply;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -119,9 +155,18 @@
|
|||
}
|
||||
}
|
||||
|
||||
.palettes-editor {
|
||||
.palette-editor {
|
||||
width: min-content;
|
||||
|
||||
.list-edit-area {
|
||||
display: grid;
|
||||
align-self: baseline;
|
||||
grid-template-rows: subgrid;
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.palette-editor-single {
|
||||
grid-row: 2 / span 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -4,49 +4,66 @@
|
|||
<template>
|
||||
<div class="StyleTab">
|
||||
<div class="setting-item heading">
|
||||
<!-- TODO: This needs to go -->
|
||||
<h2>{{ $t('settings.style.themes3.editor.title') }}</h2>
|
||||
<!-- eslint-disable vue/no-v-text-v-html-on-component -->
|
||||
<component
|
||||
:is="'style'"
|
||||
v-html="overallPreviewRules"
|
||||
/>
|
||||
<!-- eslint-enable vue/no-v-text-v-html-on-component -->
|
||||
<Preview id="edited-style-preview" />
|
||||
<button
|
||||
class="btn button-default"
|
||||
class="btn button-default button-new"
|
||||
@click="clearTheme"
|
||||
>
|
||||
<FAIcon icon="file" />
|
||||
{{ $t('settings.style.themes3.editor.new_style') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn button-default"
|
||||
class="btn button-default button-load"
|
||||
@click="importStyle"
|
||||
>
|
||||
<FAIcon icon="folder-open" />
|
||||
{{ $t('settings.style.themes3.editor.load_style') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn button-default"
|
||||
class="btn button-default button-save"
|
||||
@click="exportStyle"
|
||||
>
|
||||
<FAIcon icon="floppy-disk" />
|
||||
{{ $t('settings.style.themes3.editor.save_style') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="setting-item metadata">
|
||||
<ul class="setting-list">
|
||||
<button
|
||||
class="btn button-default button-refresh"
|
||||
@click="updateOverallPreview"
|
||||
>
|
||||
<FAIcon icon="arrows-rotate" />
|
||||
{{ $t('settings.style.themes3.editor.refresh_preview') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn button-default button-apply"
|
||||
@click="applyTheme"
|
||||
>
|
||||
<FAIcon icon="check" />
|
||||
{{ $t('settings.style.themes3.editor.apply_preview') }}
|
||||
</button>
|
||||
<ul class="setting-list style-metadata">
|
||||
<li>
|
||||
<StringSetting v-model="name">
|
||||
<StringSetting class="meta-field" v-model="name">
|
||||
{{ $t('settings.style.themes3.editor.style_name') }}
|
||||
</StringSetting>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting v-model="author">
|
||||
<StringSetting class="meta-field" v-model="author">
|
||||
{{ $t('settings.style.themes3.editor.style_author') }}
|
||||
</StringSetting>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting v-model="license">
|
||||
<StringSetting class="meta-field" v-model="license">
|
||||
{{ $t('settings.style.themes3.editor.style_license') }}
|
||||
</StringSetting>
|
||||
</li>
|
||||
<li>
|
||||
<StringSetting v-model="website">
|
||||
<StringSetting class="meta-field" v-model="website">
|
||||
{{ $t('settings.style.themes3.editor.style_website') }}
|
||||
</StringSetting>
|
||||
</li>
|
||||
|
@ -148,6 +165,7 @@
|
|||
>
|
||||
<ColorInput
|
||||
v-model="editedBackgroundColor"
|
||||
:fallback="computeColor(editedBackgroundColor)"
|
||||
:disabled="!isBackgroundColorPresent"
|
||||
:label="$t('settings.style.themes3.editor.background')"
|
||||
/>
|
||||
|
@ -165,6 +183,7 @@
|
|||
<ColorInput
|
||||
v-if="componentHas('Text')"
|
||||
v-model="editedTextColor"
|
||||
:fallback="computeColor(editedTextColor)"
|
||||
:label="$t('settings.style.themes3.editor.text_color')"
|
||||
:disabled="!isTextColorPresent"
|
||||
/>
|
||||
|
@ -213,6 +232,7 @@
|
|||
<ColorInput
|
||||
v-if="componentHas('Link')"
|
||||
v-model="editedLinkColor"
|
||||
:fallback="computeColor(editedLinkColor)"
|
||||
:label="$t('settings.style.themes3.editor.link_color')"
|
||||
:disabled="!isLinkColorPresent"
|
||||
/>
|
||||
|
@ -225,6 +245,7 @@
|
|||
<ColorInput
|
||||
v-if="componentHas('Icon')"
|
||||
v-model="editedIconColor"
|
||||
:fallback="computeColor(editedIconColor)"
|
||||
:label="$t('settings.style.themes3.editor.icon_color')"
|
||||
:disabled="!isIconColorPresent"
|
||||
/>
|
||||
|
@ -234,6 +255,19 @@
|
|||
>
|
||||
<Checkbox v-model="isIconColorPresent" />
|
||||
</Tooltip>
|
||||
<ColorInput
|
||||
v-if="componentHas('Border')"
|
||||
v-model="editedBorderColor"
|
||||
:fallback="computeColor(editedBorderColor)"
|
||||
:label="$t('settings.style.themes3.editor.Border_color')"
|
||||
:disabled="!isBorderColorPresent"
|
||||
/>
|
||||
<Tooltip
|
||||
v-if="componentHas('Border')"
|
||||
:text="$t('settings.style.themes3.editor.include_in_rule')"
|
||||
>
|
||||
<Checkbox v-model="isBorderColorPresent" />
|
||||
</Tooltip>
|
||||
</div>
|
||||
<div
|
||||
key="shadow"
|
||||
|
@ -262,38 +296,47 @@
|
|||
:label="$t('settings.style.themes3.editor.palette_tab')"
|
||||
class="setting-item list-editor palette-editor"
|
||||
>
|
||||
<label
|
||||
class="list-select-label"
|
||||
for="palette-selector"
|
||||
<label
|
||||
class="list-select-label"
|
||||
for="palette-selector"
|
||||
>
|
||||
{{ $t('settings.style.themes3.palette.label') }}
|
||||
{{ ' ' }}
|
||||
</label>
|
||||
<Select
|
||||
id="palette-selector"
|
||||
v-model="selectedPaletteId"
|
||||
class="list-select"
|
||||
size="4"
|
||||
>
|
||||
<option
|
||||
v-for="(p, index) in palettes"
|
||||
:key="p.name"
|
||||
:value="index"
|
||||
>
|
||||
{{ $t('settings.style.themes3.palette.label') }}
|
||||
{{ ' ' }}
|
||||
</label>
|
||||
<Select
|
||||
id="palette-selector"
|
||||
v-model="selectedPaletteId"
|
||||
class="list-select"
|
||||
size="4"
|
||||
>
|
||||
<option
|
||||
v-for="(p, index) in palettes"
|
||||
:key="p.name"
|
||||
:value="index"
|
||||
>
|
||||
{{ p.name }}
|
||||
</option>
|
||||
</Select>
|
||||
<SelectMotion
|
||||
class="list-select-movement"
|
||||
v-model="palettes"
|
||||
:get-add-value="getNewPalette"
|
||||
:selected-id="selectedPaletteId"
|
||||
@update:selectedId="e => selectedPaletteId = e"
|
||||
/>
|
||||
<PaletteEditor
|
||||
class="list-edit-area"
|
||||
v-model="selectedPalette"
|
||||
{{ p.name }}
|
||||
</option>
|
||||
</Select>
|
||||
<SelectMotion
|
||||
class="list-select-movement"
|
||||
:modelValue="palettes"
|
||||
@update:modelValue="onPalettesUpdate"
|
||||
:selected-id="selectedPaletteId"
|
||||
:get-add-value="getNewPalette"
|
||||
@update:selectedId="e => selectedPaletteId = e"
|
||||
/>
|
||||
<div class="list-edit-area">
|
||||
<StringSetting
|
||||
class="palette-name-input"
|
||||
v-model="selectedPalette.name"
|
||||
>
|
||||
{{ $t('settings.style.themes3.palette.name_label') }}
|
||||
</StringSetting>
|
||||
<PaletteEditor
|
||||
class="palette-editor-single"
|
||||
v-model="selectedPalette"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
key="variables"
|
||||
|
@ -304,14 +347,14 @@
|
|||
class="list-select-label"
|
||||
for="variables-selector"
|
||||
>
|
||||
{{ $t('settings.style.themes3.variables.label') }}
|
||||
{{ $t('settings.style.themes3.editor.variables.label') }}
|
||||
{{ ' ' }}
|
||||
</label>
|
||||
<Select
|
||||
id="variables-selector"
|
||||
v-model="selectedVirtualDirectiveId"
|
||||
class="list-select"
|
||||
size="9"
|
||||
size="20"
|
||||
>
|
||||
<option
|
||||
v-for="(p, index) in virtualDirectives"
|
||||
|
@ -323,7 +366,8 @@
|
|||
</Select>
|
||||
<SelectMotion
|
||||
class="list-select-movement"
|
||||
v-model="virtualDirectives"
|
||||
:modelValue="virtualDirectives"
|
||||
@update:modelValue="onVirtualDirectivesUpdate"
|
||||
:selected-id="selectedVirtualDirectiveId"
|
||||
:get-add-value="getNewVirtualDirective"
|
||||
@update:selectedId="e => selectedVirtualDirectiveId = e"
|
||||
|
@ -334,7 +378,7 @@
|
|||
class="variable-name-label"
|
||||
for="variables-selector"
|
||||
>
|
||||
{{ $t('settings.style.themes3.variables.name_label') }}
|
||||
{{ $t('settings.style.themes3.editor.variables.name_label') }}
|
||||
{{ ' ' }}
|
||||
</label>
|
||||
<input
|
||||
|
@ -345,25 +389,36 @@
|
|||
class="variable-type-label"
|
||||
for="variables-selector"
|
||||
>
|
||||
{{ $t('settings.style.themes3.variables.type_label') }}
|
||||
{{ $t('settings.style.themes3.editor.variables.type_label') }}
|
||||
{{ ' ' }}
|
||||
</label>
|
||||
<Select
|
||||
v-model="selectedVirtualDirective.valType"
|
||||
v-model="selectedVirtualDirectiveValType"
|
||||
>
|
||||
<option value='shadow'>
|
||||
{{ $t('settings.style.themes3.variables.type_label') }}
|
||||
shadow</option>
|
||||
<option value='shadow'>color</option>
|
||||
<option value='shadow'>generic</option>
|
||||
{{ $t('settings.style.themes3.editor.variables.type_shadow') }}
|
||||
</option>
|
||||
<option value='color'>
|
||||
{{ $t('settings.style.themes3.editor.variables.type_color') }}
|
||||
</option>
|
||||
<option value='generic'>
|
||||
{{ $t('settings.style.themes3.editor.variables.type_generic') }}
|
||||
</option>
|
||||
</Select>
|
||||
</div>
|
||||
<ShadowControl
|
||||
v-if="selectedVirtualDirective.valType === 'shadow'"
|
||||
v-if="selectedVirtualDirectiveValType === 'shadow'"
|
||||
v-model="selectedVirtualDirectiveParsed"
|
||||
:computeColor="computeColor"
|
||||
:compact="true"
|
||||
/>
|
||||
</div>
|
||||
<ColorInput
|
||||
v-if="selectedVirtualDirectiveValType === 'color'"
|
||||
v-model="selectedVirtualDirectiveParsed"
|
||||
:fallback="computeColor(selectedVirtualDirectiveParsed)"
|
||||
:label="$t('settings.style.themes3.editor.variables.virtual_color')"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</tab-switcher>
|
||||
</div>
|
||||
|
|
|
@ -46,6 +46,7 @@ export default {
|
|||
'separateInset',
|
||||
'noPreview',
|
||||
'disabled',
|
||||
'computeColor',
|
||||
'compact'
|
||||
],
|
||||
emits: ['update:modelValue', 'subShadowSelected'],
|
||||
|
@ -107,6 +108,13 @@ export default {
|
|||
usingFallback () {
|
||||
return this.modelValue == null
|
||||
},
|
||||
getFallback () {
|
||||
if (typeof this.computeColor === 'function' && this.selected?.color) {
|
||||
return this.computeColor(this.selected.color)
|
||||
} else {
|
||||
return this.currentFallback?.color
|
||||
}
|
||||
},
|
||||
style () {
|
||||
try {
|
||||
if (this.separateInset) {
|
||||
|
|
|
@ -5,8 +5,6 @@
|
|||
grid-template-areas: "selector preview tweak";
|
||||
grid-gap: 0.5em;
|
||||
justify-content: stretch;
|
||||
margin-bottom: 1em;
|
||||
width: 100%;
|
||||
|
||||
&.-compact {
|
||||
grid-template-columns: 10em 1fr;
|
||||
|
@ -112,7 +110,7 @@
|
|||
|
||||
.shadow-preview {
|
||||
grid-area: preview;
|
||||
min-width: 10em;
|
||||
min-width: 25em;
|
||||
margin-left: 0.125em;
|
||||
align-self: start;
|
||||
justify-self: center;
|
||||
|
|
|
@ -165,7 +165,7 @@
|
|||
:model-value="selected?.color"
|
||||
:disabled="disabled || !present"
|
||||
:label="$t('settings.style.common.color')"
|
||||
:fallback="currentFallback?.color"
|
||||
:fallback="getFallback"
|
||||
:show-optional-tickbox="false"
|
||||
name="shadow"
|
||||
@update:modelValue="e => updateProperty('color', e)"
|
||||
|
|
|
@ -757,7 +757,8 @@
|
|||
"themes3": {
|
||||
"define": "Override",
|
||||
"palette": {
|
||||
"label": "Palettes",
|
||||
"label": "Color schemes",
|
||||
"name_label": "Color scheme name",
|
||||
"import": "Import",
|
||||
"export": "Export",
|
||||
"bg": "Panel background",
|
||||
|
@ -774,11 +775,6 @@
|
|||
"extra3": "Extra 3",
|
||||
"v2_unsupported": "Older v2 themes don't support palettes. Switch to v3 theme to make use of palettes"
|
||||
},
|
||||
"variables": {
|
||||
"label": "Variables",
|
||||
"name_label": "Name:",
|
||||
"type_label": "Type:"
|
||||
},
|
||||
"editor": {
|
||||
"title": "Style",
|
||||
"new_style": "New",
|
||||
|
@ -798,6 +794,9 @@
|
|||
"icon_color": "Icon color",
|
||||
"link_color": "Link color",
|
||||
"include_in_rule": "Add to rule",
|
||||
"test_string": "TEST",
|
||||
"refresh_preview": "Refresh preview",
|
||||
"apply_preview": "Apply",
|
||||
"text_auto": {
|
||||
"label": "Auto-contrast",
|
||||
"no-preserve": "Black or White",
|
||||
|
@ -805,8 +804,17 @@
|
|||
"no-auto": "Disabled"
|
||||
},
|
||||
"component_tab": "Components style",
|
||||
"palette_tab": "Color presets",
|
||||
"variables_tab": "Variables (Advanced)"
|
||||
"palette_tab": "Color schemes",
|
||||
"variables_tab": "Variables (Advanced)",
|
||||
"variables": {
|
||||
"label": "Variables",
|
||||
"name_label": "Name:",
|
||||
"type_label": "Type:",
|
||||
"type_shadow": "Shadow",
|
||||
"type_color": "Color",
|
||||
"type_generic": "Generic",
|
||||
"virtual_color": "Variable color value"
|
||||
},
|
||||
},
|
||||
"hacks": {
|
||||
"underlay_overrides": "Change underlay",
|
||||
|
|
|
@ -16,7 +16,8 @@ export const newExporter = ({
|
|||
|
||||
// Create an invisible link with a data url and simulate a click
|
||||
const e = document.createElement('a')
|
||||
e.setAttribute('download', `${filename}.${extension}`)
|
||||
const realFilename = typeof filename === 'function' ? filename() : filename
|
||||
e.setAttribute('download', `${realFilename}.${extension}`)
|
||||
e.setAttribute('href', `data:${mime};base64, ${window.btoa(stringified)}`)
|
||||
e.style.display = 'none'
|
||||
|
||||
|
@ -28,6 +29,7 @@ export const newExporter = ({
|
|||
|
||||
export const newImporter = ({
|
||||
accept = '.json',
|
||||
parser = (string) => JSON.parse(string),
|
||||
onImport,
|
||||
onImportFailure,
|
||||
validator = () => true
|
||||
|
@ -44,7 +46,7 @@ export const newImporter = ({
|
|||
const reader = new FileReader()
|
||||
reader.onload = ({ target }) => {
|
||||
try {
|
||||
const parsed = JSON.parse(target.result)
|
||||
const parsed = parser(target.result)
|
||||
const validationResult = validator(parsed, filename)
|
||||
if (validationResult === true) {
|
||||
onImport(parsed, filename)
|
||||
|
|
|
@ -21,7 +21,11 @@ export const parseShadow = string => {
|
|||
const regex = new RegExp(regexPrep, 'gis') // global, (stable) indices, single-string
|
||||
const result = regex.exec(string)
|
||||
if (result == null) {
|
||||
return string
|
||||
if (string.startsWith('$') || string.startsWith('--')) {
|
||||
return string
|
||||
} else {
|
||||
throw new Error(`Invalid shadow definition: ${string}`)
|
||||
}
|
||||
} else {
|
||||
const numeric = new Set(['x', 'y', 'blur', 'spread', 'alpha'])
|
||||
const { x, y, blur, spread, alpha, inset, color } = Object.fromEntries(modes.map((mode, i) => {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { unroll } from './iss_utils.js'
|
||||
|
||||
const serializeShadow = s => {
|
||||
export const serializeShadow = (s, throwOnInvalid) => {
|
||||
if (typeof s === 'object') {
|
||||
return `${s.inset ? 'inset ' : ''}${s.x} ${s.y} ${s.blur} ${s.spread} ${s.color} / ${s.alpha}`
|
||||
} else {
|
||||
|
|
|
@ -62,7 +62,7 @@ const findShadow = (shadows, { dynamicVars, staticVars }) => {
|
|||
})
|
||||
}
|
||||
|
||||
const findColor = (color, { dynamicVars, staticVars }) => {
|
||||
export const findColor = (color, { dynamicVars, staticVars }) => {
|
||||
if (typeof color !== 'string' || (!color.startsWith('--') && !color.startsWith('$'))) return color
|
||||
let targetColor = null
|
||||
if (color.startsWith('--')) {
|
||||
|
|
Loading…
Add table
Reference in a new issue