commit: f4d29b5d5ec741991a5228c478f2dc4a7e24f2d1
parent 21b17f333dd9e24b51d14f63795e27216c970385
Author: Henry Jameson <me@hjkos.com>
Date: Fri, 18 Oct 2024 13:43:33 +0300
use draft logic for virtualDirective to catch errors
Diffstat:
6 files changed, 73 insertions(+), 37 deletions(-)
diff --git a/src/components/select/select_motion.vue b/src/components/select/select_motion.vue
@@ -4,7 +4,7 @@
>
<button
class="btn button-default"
- :disabled="disabled || shadowsAreNull"
+ :disabled="disabled"
@click="add"
>
<FAIcon
diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.js b/src/components/settings_modal/tabs/style_tab/style_tab.js
@@ -21,7 +21,7 @@ import {
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 { deserializeShadow, deserialize } from 'src/services/theme_data/iss_deserializer.js'
import {
rgb2hex,
hex2rgb,
@@ -371,7 +371,11 @@ export default {
return shadow
}
if (typeof shadow === 'string') {
- return parseShadow(shadow)
+ try {
+ return deserializeShadow(shadow)
+ } catch (e) {
+ console.warn(e)
+ }
}
return null
})
@@ -580,6 +584,7 @@ export default {
const selectedVirtualDirectiveId = ref(0)
exports.selectedVirtualDirectiveId = selectedVirtualDirectiveId
+
const selectedVirtualDirective = computed({
get () {
return virtualDirectives[selectedVirtualDirectiveId.value]
@@ -589,6 +594,7 @@ export default {
}
})
exports.selectedVirtualDirective = selectedVirtualDirective
+
exports.selectedVirtualDirectiveValType = computed({
get () {
return virtualDirectives[selectedVirtualDirectiveId.value].valType
@@ -607,35 +613,56 @@ export default {
}
}
})
- exports.selectedVirtualDirectiveParsed = computed({
- get () {
- switch (selectedVirtualDirective.value.valType) {
+
+ const draftVirtualDirectiveValid = ref(true)
+ const draftVirtualDirective = ref({})
+ exports.draftVirtualDirective = draftVirtualDirective
+
+ watch(
+ selectedVirtualDirective,
+ (directive) => {
+ switch (directive.valType) {
case 'shadow': {
- const directiveValue = selectedVirtualDirective.value.value
- if (Array.isArray(directiveValue)) {
- return normalizeShadows(directiveValue)
+ if (Array.isArray(directive.value)) {
+ draftVirtualDirective.value = normalizeShadows(directive.value)
} else {
- const splitShadow = directiveValue.split(/,/g).map(x => x.trim())
- return normalizeShadows(splitShadow)
+ const splitShadow = directive.value.split(/,/g).map(x => x.trim())
+ draftVirtualDirective.value = normalizeShadows(splitShadow)
}
+ break
}
case 'color':
- return selectedVirtualDirective.value.value
+ draftVirtualDirective.value = directive.value
+ break
default:
- return selectedVirtualDirective.value.value
+ draftVirtualDirective.value = directive.value
+ break
}
},
- set (value) {
- switch (selectedVirtualDirective.value.valType) {
- case 'shadow': {
- virtualDirectives[selectedVirtualDirectiveId.value].value = value.map(x => serializeShadow(x)).join(', ')
- break
+ { immediate: true }
+ )
+
+ watch(
+ draftVirtualDirective,
+ (directive) => {
+ try {
+ switch (selectedVirtualDirective.value.valType) {
+ case 'shadow': {
+ virtualDirectives[selectedVirtualDirectiveId.value].value =
+ directive.map(x => serializeShadow(x)).join(', ')
+ break
+ }
+ default:
+ virtualDirectives[selectedVirtualDirectiveId.value].value = directive
}
- default:
- virtualDirectives[selectedVirtualDirectiveId.value].value = value
+ draftVirtualDirectiveValid.value = true
+ } catch (e) {
+ console.error('Invalid virtual directive value', e)
+ draftVirtualDirectiveValid.value = false
}
- }
- })
+ },
+ { immediate: true }
+ )
exports.getNewVirtualDirective = () => ({
name: 'newDirective',
diff --git a/src/components/settings_modal/tabs/style_tab/style_tab.vue b/src/components/settings_modal/tabs/style_tab/style_tab.vue
@@ -285,7 +285,7 @@
:disabled="!isShadowPresent"
:no-preview="true"
:compact="true"
- :separate-inset="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'"
+ :compute-color="computeColor"
@subShadowSelected="onSubShadow"
/>
</div>
@@ -408,14 +408,14 @@
</div>
<ShadowControl
v-if="selectedVirtualDirectiveValType === 'shadow'"
- v-model="selectedVirtualDirectiveParsed"
- :computeColor="computeColor"
+ v-model="draftVirtualDirective"
+ :compute-color="computeColor"
:compact="true"
/>
<ColorInput
v-if="selectedVirtualDirectiveValType === 'color'"
- v-model="selectedVirtualDirectiveParsed"
- :fallback="computeColor(selectedVirtualDirectiveParsed)"
+ v-model="draftVirtualDirective"
+ :fallback="computeColor(draftVirtualDirective)"
:label="$t('settings.style.themes3.editor.variables.virtual_color')"
/>
</div>
diff --git a/src/services/theme_data/iss_deserializer.js b/src/services/theme_data/iss_deserializer.js
@@ -1,10 +1,11 @@
import { flattenDeep } from 'lodash'
-export const parseShadow = string => {
- const modes = ['_full', 'inset', 'x', 'y', 'blur', 'spread', 'color', 'alpha']
+export const deserializeShadow = string => {
+ const modes = ['_full', 'inset', 'x', 'y', 'blur', 'spread', 'color', 'alpha', 'name']
const regexPrep = [
// inset keyword (optional)
- '^(?:(inset)\\s+)?',
+ '^',
+ '(?:(inset)\\s+)?',
// x
'(?:(-?[0-9]+(?:\\.[0-9]+)?)\\s+)',
// y
@@ -16,7 +17,10 @@ export const parseShadow = string => {
// either hex, variable or function
'(#[0-9a-f]{6}|--[a-z\\-_]+|\\$[a-z\\-()_]+)',
// opacity (optional)
- '(?:\\s+\\/\\s+([0-9]+(?:\\.[0-9]+)?)\\s*)?$'
+ '(?:\\s+\\/\\s+([0-9]+(?:\\.[0-9]+)?)\\s*)?',
+ // name
+ '(?:\\s+#(\\w+)\\s*)?',
+ '$'
].join('')
const regex = new RegExp(regexPrep, 'gis') // global, (stable) indices, single-string
const result = regex.exec(string)
@@ -28,7 +32,7 @@ export const parseShadow = 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) => {
+ const { x, y, blur, spread, alpha, inset, color, name } = Object.fromEntries(modes.map((mode, i) => {
if (numeric.has(mode)) {
const number = Number(result[i])
if (Number.isNaN(number)) {
@@ -43,7 +47,7 @@ export const parseShadow = string => {
}
}).filter(([k, v]) => v !== false).slice(1))
- return { x, y, blur, spread, color, alpha, inset }
+ return { x, y, blur, spread, color, alpha, inset, name }
}
}
// this works nearly the same as HTML tree converter
@@ -150,7 +154,7 @@ export const deserialize = (input) => {
if (realValue === 'none') {
realValue = []
} else {
- realValue = value.split(',').map(v => parseShadow(v.trim()))
+ realValue = value.split(',').map(v => deserializeShadow(v.trim()))
}
} if (!Number.isNaN(Number(value))) {
realValue = Number(value)
diff --git a/src/services/theme_data/iss_serializer.js b/src/services/theme_data/iss_serializer.js
@@ -1,8 +1,13 @@
import { unroll } from './iss_utils.js'
+import { deserializeShadow } from './iss_deserializer.js'
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}`
+ const inset = s.inset ? 'inset ' : ''
+ const name = s.name ? ` #${s.name} ` : ''
+ const result = `${inset}${s.x} ${s.y} ${s.blur} ${s.spread} ${s.color} / ${s.alpha}${name}`
+ deserializeShadow(result) // Verify that output is valid and parseable
+ return result
} else {
return s
}
diff --git a/src/services/theme_data/theme_data_3.service.js b/src/services/theme_data/theme_data_3.service.js
@@ -22,7 +22,7 @@ import {
normalizeCombination,
findRules
} from './iss_utils.js'
-import { parseShadow } from './iss_deserializer.js'
+import { deserializeShadow } from './iss_deserializer.js'
// Ensuring the order of components
const components = {
@@ -48,7 +48,7 @@ const findShadow = (shadows, { dynamicVars, staticVars }) => {
const variableSlot = shadow.substring(2)
return findShadow(staticVars[variableSlot], { dynamicVars, staticVars })
} else {
- targetShadow = parseShadow(shadow)
+ targetShadow = deserializeShadow(shadow)
}
} else {
targetShadow = shadow