proper fallbacks and contrast ratio for component style editor

This commit is contained in:
Henry Jameson 2024-10-22 17:06:22 +03:00
parent 7e4fe93c7f
commit 030a2127ee
7 changed files with 101 additions and 42 deletions

View file

@ -11,7 +11,7 @@
{{ label }} {{ label }}
</label> </label>
<Checkbox <Checkbox
v-if="typeof fallback !== 'undefined' && showOptionalTickbox" v-if="typeof fallback !== 'undefined' && showOptionalCheckbox && !hideOptionalCheckbox"
:model-value="present" :model-value="present"
:disabled="disabled" :disabled="disabled"
class="opt" class="opt"
@ -112,10 +112,16 @@ export default {
default: false default: false
}, },
// Show "optional" tickbox, for when value might become mandatory // Show "optional" tickbox, for when value might become mandatory
showOptionalTickbox: { showOptionalCheckbox: {
required: false, required: false,
type: Boolean, type: Boolean,
default: true default: true
},
// Force "optional" tickbox to hide
hideOptionalCheckbox: {
required: false,
type: Boolean,
default: false
} }
}, },
emits: ['update:modelValue'], emits: ['update:modelValue'],

View file

@ -3,39 +3,44 @@
v-if="contrast" v-if="contrast"
class="contrast-ratio" class="contrast-ratio"
> >
<span <span v-if="showRatio">
:title="hint" {{ contrast.text }}
</span>
<Tooltip
:text="hint"
class="rating" class="rating"
> >
<span v-if="contrast.aaa"> <span v-if="contrast.aaa">
<FAIcon icon="thumbs-up" /> <FAIcon icon="thumbs-up" :size="showRatio ? 'lg' : ''" />
</span> </span>
<span v-if="!contrast.aaa && contrast.aa"> <span v-if="!contrast.aaa && contrast.aa">
<FAIcon icon="adjust" /> <FAIcon icon="adjust" :size="showRatio ? 'lg' : ''" />
</span> </span>
<span v-if="!contrast.aaa && !contrast.aa"> <span v-if="!contrast.aaa && !contrast.aa">
<FAIcon icon="exclamation-triangle" /> <FAIcon icon="exclamation-triangle" :size="showRatio ? 'lg' : ''" />
</span> </span>
</span> </Tooltip>
<span <Tooltip
v-if="contrast && large" v-if="contrast && large"
:text="hint_18pt"
class="rating" class="rating"
:title="hint_18pt"
> >
<span v-if="contrast.laaa"> <span v-if="contrast.laaa">
<FAIcon icon="thumbs-up" /> <FAIcon icon="thumbs-up" :size="showRatio ? 'large' : ''" />
</span> </span>
<span v-if="!contrast.laaa && contrast.laa"> <span v-if="!contrast.laaa && contrast.laa">
<FAIcon icon="adjust" /> <FAIcon icon="adjust" :size="showRatio ? 'lg' : ''" />
</span> </span>
<span v-if="!contrast.laaa && !contrast.laa"> <span v-if="!contrast.laaa && !contrast.laa">
<FAIcon icon="exclamation-triangle" /> <FAIcon icon="exclamation-triangle" :size="showRatio ? 'lg' : ''" />
</span>
</span> </span>
</Tooltip>
</span> </span>
</template> </template>
<script> <script>
import Tooltip from 'src/components/tooltip/tooltip.vue'
import { library } from '@fortawesome/fontawesome-svg-core' import { library } from '@fortawesome/fontawesome-svg-core'
import { import {
faAdjust, faAdjust,
@ -62,8 +67,16 @@ export default {
required: false, required: false,
type: Object, type: Object,
default: () => ({}) default: () => ({})
},
showRatio: {
required: false,
type: Boolean,
default: false
} }
}, },
components: {
Tooltip
},
computed: { computed: {
hint () { hint () {
const levelVal = this.contrast.aaa ? 'aaa' : (this.contrast.aa ? 'aa' : 'bad') const levelVal = this.contrast.aaa ? 'aaa' : (this.contrast.aa ? 'aa' : 'bad')
@ -87,8 +100,7 @@ export default {
.contrast-ratio { .contrast-ratio {
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
margin-top: -4px; align-items: baseline;
margin-bottom: 5px;
.label { .label {
margin-right: 1em; margin-right: 1em;
@ -96,7 +108,6 @@ export default {
.rating { .rating {
display: inline-block; display: inline-block;
text-align: center;
margin-left: 0.5em; margin-left: 0.5em;
} }
} }

View file

@ -340,9 +340,7 @@ export default {
exports.editedBorderColor = getEditedElement('Border', 'textColor') exports.editedBorderColor = getEditedElement('Border', 'textColor')
exports.isBorderColorPresent = isElementPresent('Border', 'textColor', '#909090') exports.isBorderColorPresent = isElementPresent('Border', 'textColor', '#909090')
// TODO this is VERY primitive right now, need to make it const getContrast = (bg, text) => {
// support variables, fallbacks etc.
exports.getContrast = (bg, text) => {
try { try {
const bgRgb = hex2rgb(bg) const bgRgb = hex2rgb(bg)
const textRgb = hex2rgb(text) const textRgb = hex2rgb(text)
@ -464,6 +462,24 @@ export default {
return null return null
} }
}) })
const applicablePreviewRules = computed(() => {
return previewRules.filter(rule => {
const filterable = rule.parent ? rule.parent : rule
const variantMatches = filterable.variant === selectedVariant.value
const stateMatches = filterable.state.filter(x => x !== 'normal').every(x => selectedState.has(x))
return variantMatches && stateMatches
})
})
const previewColors = computed(() => ({
text: applicablePreviewRules.value.find(r => r.component === 'Text').virtualDirectives['--text'],
link: applicablePreviewRules.value.find(r => r.component === 'Link').virtualDirectives['--link'],
border: applicablePreviewRules.value.find(r => r.component === 'Border').virtualDirectives['--border'],
icon: applicablePreviewRules.value.find(r => r.component === 'Icon').virtualDirectives['--icon'],
background: applicablePreviewRules.value.find(r => r.parent == null).dynamicVars.stacked
}))
exports.previewColors = previewColors
const editorFriendlyToOriginal = computed(() => { const editorFriendlyToOriginal = computed(() => {
const resultRules = [] const resultRules = []
@ -678,6 +694,14 @@ export default {
return null return null
} }
exports.contrast = computed(() => {
console.log('APR', applicablePreviewRules.value)
return getContrast(
exports.computeColor(previewColors.value.background),
exports.computeColor(previewColors.value.text)
)
})
const overallPreviewRules = ref() const overallPreviewRules = ref()
exports.overallPreviewRules = overallPreviewRules exports.overallPreviewRules = overallPreviewRules
exports.updateOverallPreview = () => { exports.updateOverallPreview = () => {

View file

@ -166,27 +166,21 @@
> >
<ColorInput <ColorInput
v-model="editedBackgroundColor" v-model="editedBackgroundColor"
:fallback="computeColor(editedBackgroundColor)" :fallback="computeColor(editedBackgroundColor) ?? previewColors.background"
:disabled="!isBackgroundColorPresent" :disabled="!isBackgroundColorPresent"
:label="$t('settings.style.themes3.editor.background')" :label="$t('settings.style.themes3.editor.background')"
:hide-optional-checkbox="true"
/> />
<Tooltip :text="$t('settings.style.themes3.editor.include_in_rule')"> <Tooltip :text="$t('settings.style.themes3.editor.include_in_rule')">
<Checkbox v-model="isBackgroundColorPresent" /> <Checkbox v-model="isBackgroundColorPresent" />
</Tooltip> </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 <ColorInput
v-if="componentHas('Text')" v-if="componentHas('Text')"
v-model="editedTextColor" v-model="editedTextColor"
:fallback="computeColor(editedTextColor)" :fallback="computeColor(editedTextColor) ?? previewColors.text"
:label="$t('settings.style.themes3.editor.text_color')" :label="$t('settings.style.themes3.editor.text_color')"
:disabled="!isTextColorPresent" :disabled="!isTextColorPresent"
:hide-optional-checkbox="true"
/> />
<Tooltip <Tooltip
v-if="componentHas('Text')" v-if="componentHas('Text')"
@ -194,7 +188,10 @@
> >
<Checkbox v-model="isTextColorPresent" /> <Checkbox v-model="isTextColorPresent" />
</Tooltip> </Tooltip>
<div class="style-control suboption"> <div
v-if="componentHas('Text')"
class="style-control suboption"
>
<label <label
for="textAuto" for="textAuto"
class="label" class="label"
@ -224,18 +221,27 @@
> >
<Checkbox v-model="isTextAutoPresent" /> <Checkbox v-model="isTextAutoPresent" />
</Tooltip> </Tooltip>
<div> <div
<ContrastRatio :contrast="getContrast(editedBackgroundColor, editedTextColor)" /> class="style-control suboption"
v-if="componentHas('Text')"
>
<label class="label">
{{$t('settings.style.themes3.editor.contrast') }}
</label>
<ContrastRatio
:show-ratio="true"
:contrast="contrast"
/>
</div> </div>
<div> <div v-if="componentHas('Text')">
<!-- spacer for missing checkbox -->
</div> </div>
<ColorInput <ColorInput
v-if="componentHas('Link')" v-if="componentHas('Link')"
v-model="editedLinkColor" v-model="editedLinkColor"
:fallback="computeColor(editedLinkColor)" :fallback="computeColor(editedLinkColor) ?? previewColors.link"
:label="$t('settings.style.themes3.editor.link_color')" :label="$t('settings.style.themes3.editor.link_color')"
:disabled="!isLinkColorPresent" :disabled="!isLinkColorPresent"
:hide-optional-checkbox="true"
/> />
<Tooltip <Tooltip
v-if="componentHas('Link')" v-if="componentHas('Link')"
@ -246,9 +252,10 @@
<ColorInput <ColorInput
v-if="componentHas('Icon')" v-if="componentHas('Icon')"
v-model="editedIconColor" v-model="editedIconColor"
:fallback="computeColor(editedIconColor)" :fallback="computeColor(editedIconColor) ?? previewColors.icon"
:label="$t('settings.style.themes3.editor.icon_color')" :label="$t('settings.style.themes3.editor.icon_color')"
:disabled="!isIconColorPresent" :disabled="!isIconColorPresent"
:hide-optional-checkbox="true"
/> />
<Tooltip <Tooltip
v-if="componentHas('Icon')" v-if="componentHas('Icon')"
@ -259,9 +266,10 @@
<ColorInput <ColorInput
v-if="componentHas('Border')" v-if="componentHas('Border')"
v-model="editedBorderColor" v-model="editedBorderColor"
:fallback="computeColor(editedBorderColor)" :fallback="computeColor(editedBorderColor) ?? previewColors.border"
:label="$t('settings.style.themes3.editor.Border_color')" :label="$t('settings.style.themes3.editor.border_color')"
:disabled="!isBorderColorPresent" :disabled="!isBorderColorPresent"
:hide-optional-checkbox="true"
/> />
<Tooltip <Tooltip
v-if="componentHas('Border')" v-if="componentHas('Border')"
@ -269,6 +277,14 @@
> >
<Checkbox v-model="isBorderColorPresent" /> <Checkbox v-model="isBorderColorPresent" />
</Tooltip> </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>
</div> </div>
<div <div
key="shadow" key="shadow"
@ -418,6 +434,7 @@
v-model="draftVirtualDirective" v-model="draftVirtualDirective"
:fallback="computeColor(draftVirtualDirective)" :fallback="computeColor(draftVirtualDirective)"
:label="$t('settings.style.themes3.editor.variables.virtual_color')" :label="$t('settings.style.themes3.editor.variables.virtual_color')"
:hide-optional-checkbox="true"
/> />
</div> </div>
</div> </div>

View file

@ -187,14 +187,14 @@
name="accentColor" name="accentColor"
:fallback="previewTheme.colors?.link" :fallback="previewTheme.colors?.link"
:label="$t('settings.accent')" :label="$t('settings.accent')"
:show-optional-tickbox="typeof linkColorLocal !== 'undefined'" :show-optional-checkbox="typeof linkColorLocal !== 'undefined'"
/> />
<ColorInput <ColorInput
v-model="linkColorLocal" v-model="linkColorLocal"
name="linkColor" name="linkColor"
:fallback="previewTheme.colors?.accent" :fallback="previewTheme.colors?.accent"
:label="$t('settings.links')" :label="$t('settings.links')"
:show-optional-tickbox="typeof accentColorLocal !== 'undefined'" :show-optional-checkbox="typeof accentColorLocal !== 'undefined'"
/> />
<ContrastRatio :contrast="previewContrast.bgLink" /> <ContrastRatio :contrast="previewContrast.bgLink" />
</div> </div>

View file

@ -168,7 +168,7 @@
:disabled="disabled || !present" :disabled="disabled || !present"
:label="$t('settings.style.common.color')" :label="$t('settings.style.common.color')"
:fallback="getColorFallback" :fallback="getColorFallback"
:show-optional-tickbox="false" :show-optional-checkbox="false"
name="shadow" name="shadow"
@update:modelValue="e => updateProperty('color', e)" @update:modelValue="e => updateProperty('color', e)"
/> />

View file

@ -793,6 +793,7 @@
"text_color": "Text color", "text_color": "Text color",
"icon_color": "Icon color", "icon_color": "Icon color",
"link_color": "Link color", "link_color": "Link color",
"contrast": "Text contrast",
"border_color": "Border color", "border_color": "Border color",
"include_in_rule": "Add to rule", "include_in_rule": "Add to rule",
"test_string": "TEST", "test_string": "TEST",