- Export dialog goes wide (xl modal) and splits into two columns:
Project & code on the left (.ruw, runtime.js, animation.js,
example.html), Media on the right with the per-export size + fps
inputs followed by MP4 / WebM / GIF / APNG / APNG preview. Skip-
hidden toggle still spans the full width up top. Single-column
fallback below 720px.
- Welcome dialog reworked:
- Always auto-loads the last edited project on boot. The welcome
dialog opens on top only when the new "Show on start"
preference is enabled, or unconditionally when there are no
recents (first-run flow).
- Two-column body: Recent (max 5 thumbnail tiles, was 8) on the
left, Archive (compact list view, no thumbnails) on the right.
- Footer toggle binds to the new useShowWelcomeOnStart shared
ref so the user can opt out of the boot dialog inline.
- Document settings → Interface tab grows a matching "Show welcome
screen on start" toggle so users who turned it off can flip it
back on without diving into localStorage.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
742 lines
18 KiB
Vue
742 lines
18 KiB
Vue
<script setup lang="ts">
|
|
import { computed, ref, watch } from 'vue'
|
|
import {
|
|
PhFolder,
|
|
PhMoon,
|
|
PhSlidersHorizontal,
|
|
PhSun,
|
|
} from '@phosphor-icons/vue'
|
|
import { useClipartStore } from '@/stores/clipart'
|
|
import { useTheme } from '@/composables/useTheme'
|
|
import type { Theme } from '@/composables/useTheme'
|
|
import { useTooltipPref } from '@/composables/useTooltipPref'
|
|
import { useAssetThumbsPref } from '@/composables/useAssetThumbsPref'
|
|
import { useShowWelcomeOnStart } from '@/composables/useShowWelcomeOnStart'
|
|
import { showLocked } from '@/composables/useShowLocked'
|
|
import { Modal } from '@/components/ui'
|
|
import { setLocale, t, useI18n } from '@/i18n'
|
|
import type { Locale } from '@/i18n'
|
|
|
|
const props = defineProps<{ modelValue: boolean }>()
|
|
const emit = defineEmits<{ 'update:modelValue': [value: boolean] }>()
|
|
|
|
const clipart = useClipartStore()
|
|
const { theme, setTheme } = useTheme()
|
|
const { enabled: tooltipsEnabled } = useTooltipPref()
|
|
const { enabled: thumbsEnabled } = useAssetThumbsPref()
|
|
const { enabled: welcomeOnStart } = useShowWelcomeOnStart()
|
|
const { locale } = useI18n()
|
|
|
|
// Re-check the stored clipart folder whenever settings opens — covers the
|
|
// case where initial App.vue init raced ahead of IDB or the user opens
|
|
// settings before the drawer ever mounted.
|
|
watch(
|
|
() => props.modelValue,
|
|
(open) => {
|
|
if (open) void clipart.initialize()
|
|
},
|
|
)
|
|
|
|
type TabId = 'clipart' | 'interface'
|
|
|
|
const tabs: { id: TabId; labelKey: string; icon: typeof PhFolder }[] = [
|
|
{ id: 'clipart', labelKey: 'settings.tab.clipart', icon: PhFolder },
|
|
{ id: 'interface', labelKey: 'settings.tab.interface', icon: PhSlidersHorizontal },
|
|
]
|
|
|
|
const activeTab = ref<TabId>('clipart')
|
|
|
|
const selectedLocale = computed({
|
|
get: () => locale.value,
|
|
set: (value: Locale) => setLocale(value),
|
|
})
|
|
|
|
function close() {
|
|
emit('update:modelValue', false)
|
|
}
|
|
|
|
function applyTheme(t: Theme) {
|
|
setTheme(t)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<Modal
|
|
:model-value="modelValue"
|
|
:title="t('settings.title')"
|
|
size="lg"
|
|
:dialog-style="{
|
|
width: 'min(920px, calc(100% - 32px))',
|
|
height: 'min(620px, calc(100vh - 48px))',
|
|
}"
|
|
:body-style="{
|
|
display: 'flex',
|
|
overflow: 'hidden',
|
|
minHeight: 0,
|
|
}"
|
|
@update:model-value="emit('update:modelValue', $event)"
|
|
>
|
|
<div class="body">
|
|
<nav class="tabs">
|
|
<button
|
|
v-for="tab in tabs"
|
|
:key="tab.id"
|
|
class="tab"
|
|
:class="{ active: activeTab === tab.id }"
|
|
@click="activeTab = tab.id"
|
|
>
|
|
<component :is="tab.icon" :size="14" />
|
|
{{ t(tab.labelKey) }}
|
|
</button>
|
|
</nav>
|
|
|
|
<div class="content">
|
|
<section v-if="activeTab === 'clipart'">
|
|
<h3>{{ t('settings.tab.clipart') }}</h3>
|
|
<div class="clipart-row">
|
|
<div class="clipart-label">{{ t('clipart.folderLabel') }}</div>
|
|
<ul v-if="clipart.hasAnyFolder" class="clipart-folder-list">
|
|
<li
|
|
v-for="(h, i) in clipart.handles"
|
|
:key="h.name + i"
|
|
class="clipart-value"
|
|
>
|
|
<PhFolder :size="13" />
|
|
<span class="clipart-folder-name">{{ h.name }}</span>
|
|
<button
|
|
class="ghost-btn small"
|
|
v-tooltip="t('clipart.removeFolder')"
|
|
@click="clipart.removeFolder(i)"
|
|
>
|
|
{{ t('clipart.clearFolder') }}
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
<div v-else class="clipart-value">
|
|
<PhFolder :size="13" />
|
|
<span class="clipart-folder-empty">{{ t('clipart.noFolder') }}</span>
|
|
</div>
|
|
</div>
|
|
<div class="clipart-actions">
|
|
<button
|
|
class="primary-btn"
|
|
:disabled="!clipart.supported"
|
|
@click="clipart.addFolder()"
|
|
>
|
|
{{ t('clipart.addFolder') }}
|
|
</button>
|
|
</div>
|
|
<p v-if="!clipart.supported" class="error-line">
|
|
{{ t('clipart.unsupported') }}
|
|
</p>
|
|
<p v-if="clipart.error" class="error-line">{{ clipart.error }}</p>
|
|
<p class="hint">{{ t('clipart.settingsHint') }}</p>
|
|
</section>
|
|
|
|
<section v-else-if="activeTab === 'interface'">
|
|
<h3>{{ t('settings.tab.interface') }}</h3>
|
|
<div class="setting-block">
|
|
<div class="setting-heading">{{ t('settings.languageTitle') }}</div>
|
|
<div class="setting-desc">{{ t('settings.languageDesc') }}</div>
|
|
<label class="setting-select">
|
|
<span class="setting-label">{{ t('settings.languageLabel') }}</span>
|
|
<select v-model="selectedLocale">
|
|
<option value="en">{{ t('settings.languageEnglish') }}</option>
|
|
<option value="de">{{ t('settings.languageGerman') }}</option>
|
|
</select>
|
|
</label>
|
|
</div>
|
|
|
|
<label class="row-toggle">
|
|
<span class="switch" :class="{ on: tooltipsEnabled }">
|
|
<input type="checkbox" v-model="tooltipsEnabled" />
|
|
</span>
|
|
<div class="row-toggle-text">
|
|
<div class="row-toggle-label">{{ t('settings.tooltipsLabel') }}</div>
|
|
<div class="row-toggle-desc">{{ t('settings.tooltipsDesc') }}</div>
|
|
</div>
|
|
</label>
|
|
|
|
<label class="row-toggle">
|
|
<span class="switch" :class="{ on: showLocked }">
|
|
<input type="checkbox" v-model="showLocked" />
|
|
</span>
|
|
<div class="row-toggle-text">
|
|
<div class="row-toggle-label">{{ t('settings.showLockedLabel') }}</div>
|
|
<div class="row-toggle-desc">{{ t('settings.showLockedDesc') }}</div>
|
|
</div>
|
|
</label>
|
|
|
|
<label class="row-toggle">
|
|
<span class="switch" :class="{ on: thumbsEnabled }">
|
|
<input type="checkbox" v-model="thumbsEnabled" />
|
|
</span>
|
|
<div class="row-toggle-text">
|
|
<div class="row-toggle-label">{{ t('settings.assetThumbsLabel') }}</div>
|
|
<div class="row-toggle-desc">{{ t('settings.assetThumbsDesc') }}</div>
|
|
</div>
|
|
</label>
|
|
|
|
<label class="row-toggle">
|
|
<span class="switch" :class="{ on: welcomeOnStart }">
|
|
<input type="checkbox" v-model="welcomeOnStart" />
|
|
</span>
|
|
<div class="row-toggle-text">
|
|
<div class="row-toggle-label">{{ t('settings.welcomeOnStartLabel') }}</div>
|
|
<div class="row-toggle-desc">{{ t('settings.welcomeOnStartDesc') }}</div>
|
|
</div>
|
|
</label>
|
|
|
|
<div class="setting-block">
|
|
<div class="setting-heading">{{ t('settings.appearanceTitle') }}</div>
|
|
<div class="setting-desc">{{ t('settings.themeHint') }}</div>
|
|
<div class="theme-grid">
|
|
<button
|
|
class="theme-card"
|
|
:class="{ active: theme === 'dark' }"
|
|
@click="applyTheme('dark')"
|
|
>
|
|
<div class="theme-preview theme-preview-dark">
|
|
<div class="tp-panel"></div>
|
|
<div class="tp-accent"></div>
|
|
</div>
|
|
<div class="theme-label">
|
|
<PhMoon :size="14" />
|
|
<span>{{ t('settings.themeDark') }}</span>
|
|
</div>
|
|
</button>
|
|
<button
|
|
class="theme-card"
|
|
:class="{ active: theme === 'light' }"
|
|
@click="applyTheme('light')"
|
|
>
|
|
<div class="theme-preview theme-preview-light">
|
|
<div class="tp-panel"></div>
|
|
<div class="tp-accent"></div>
|
|
</div>
|
|
<div class="theme-label">
|
|
<PhSun :size="14" />
|
|
<span>{{ t('settings.themeLight') }}</span>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
</div>
|
|
</div>
|
|
<template #footer>
|
|
<button class="primary" @click="close">{{ t('settings.done') }}</button>
|
|
</template>
|
|
</Modal>
|
|
</template>
|
|
|
|
<style scoped>
|
|
.body {
|
|
display: flex;
|
|
flex: 1 1 auto;
|
|
min-height: 0;
|
|
}
|
|
|
|
.tabs {
|
|
width: 150px;
|
|
flex-shrink: 0;
|
|
border-right: 1px solid var(--border);
|
|
padding: 10px 8px;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 2px;
|
|
background: var(--panel-alt);
|
|
min-height: 0;
|
|
}
|
|
|
|
.tab {
|
|
justify-content: flex-start;
|
|
padding: 8px 10px;
|
|
background: transparent;
|
|
border: 1px solid transparent;
|
|
color: var(--text-dim);
|
|
font-size: 12px;
|
|
border-radius: var(--radius-sm);
|
|
}
|
|
|
|
.tab:hover:not(:disabled) {
|
|
background: var(--panel-hover);
|
|
color: var(--text);
|
|
}
|
|
|
|
.tab.active {
|
|
background: var(--accent-soft);
|
|
color: var(--accent);
|
|
border-color: var(--accent);
|
|
}
|
|
|
|
.content {
|
|
flex: 1;
|
|
padding: 16px 20px;
|
|
overflow: auto;
|
|
min-width: 0;
|
|
min-height: 0;
|
|
}
|
|
|
|
section {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 12px;
|
|
}
|
|
|
|
section h3 {
|
|
margin: 0;
|
|
font-size: 13px;
|
|
text-transform: uppercase;
|
|
color: var(--text-dim-strong);
|
|
letter-spacing: 0.08em;
|
|
font-weight: 600;
|
|
}
|
|
|
|
/* A second h3 inside the same section (e.g. "Timing" under the
|
|
Document tab) needs breathing room so it reads as its own subgroup
|
|
rather than colliding with the preceding hint paragraph. */
|
|
section h3.sub-heading {
|
|
margin-top: 12px;
|
|
}
|
|
|
|
.row {
|
|
display: flex;
|
|
gap: 10px;
|
|
}
|
|
|
|
label {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
font-size: 10px;
|
|
color: var(--text-dim);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
flex: 1 1 0;
|
|
min-width: 0;
|
|
}
|
|
|
|
label.stacked {
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
input[type='number'] {
|
|
width: 100%;
|
|
background: var(--bg);
|
|
border: 1px solid var(--border);
|
|
color: var(--text);
|
|
padding: 6px 8px;
|
|
border-radius: var(--radius-sm);
|
|
font: inherit;
|
|
font-size: 12px;
|
|
text-transform: none;
|
|
letter-spacing: 0;
|
|
}
|
|
|
|
.presets {
|
|
display: flex;
|
|
gap: 6px;
|
|
flex-wrap: wrap;
|
|
}
|
|
|
|
.preset {
|
|
padding: 4px 10px;
|
|
font-size: 11px;
|
|
background: var(--panel-alt);
|
|
border: 1px solid var(--border);
|
|
color: var(--text-dim);
|
|
border-radius: 999px;
|
|
}
|
|
|
|
.preset:hover:not(:disabled) {
|
|
background: var(--panel-hover);
|
|
color: var(--text);
|
|
}
|
|
|
|
.preset.active {
|
|
background: var(--accent-soft);
|
|
border-color: var(--accent);
|
|
color: var(--accent);
|
|
}
|
|
|
|
.color-row {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 10px;
|
|
padding: 4px 0;
|
|
}
|
|
|
|
.color-swatch {
|
|
width: 36px;
|
|
height: 24px;
|
|
padding: 0;
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
background: transparent;
|
|
cursor: pointer;
|
|
flex-shrink: 0;
|
|
}
|
|
|
|
.color-swatch::-webkit-color-swatch-wrapper {
|
|
padding: 0;
|
|
}
|
|
.color-swatch::-webkit-color-swatch {
|
|
border: none;
|
|
border-radius: 3px;
|
|
}
|
|
.color-swatch::-moz-color-swatch {
|
|
border: none;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.hex {
|
|
font-size: 12px;
|
|
font-variant-numeric: tabular-nums;
|
|
color: var(--text-dim-strong);
|
|
}
|
|
|
|
.hint {
|
|
font-size: 13px;
|
|
line-height: 1.45;
|
|
color: var(--text-dim-strong);
|
|
margin: 0;
|
|
}
|
|
|
|
.setting-block {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 8px;
|
|
padding: 12px;
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
background: var(--panel-alt);
|
|
}
|
|
|
|
.setting-heading {
|
|
font-size: 13px;
|
|
font-weight: 600;
|
|
color: var(--text);
|
|
}
|
|
|
|
.setting-desc {
|
|
font-size: 12px;
|
|
line-height: 1.45;
|
|
color: var(--text-dim);
|
|
}
|
|
|
|
.setting-select {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 6px;
|
|
flex: 0 0 auto;
|
|
font-size: 11px;
|
|
color: var(--text-dim);
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
}
|
|
|
|
.setting-label {
|
|
color: var(--text-dim);
|
|
}
|
|
|
|
.setting-select select {
|
|
width: 100%;
|
|
background: var(--bg);
|
|
border: 1px solid var(--border);
|
|
color: var(--text);
|
|
padding: 8px 10px;
|
|
border-radius: var(--radius-sm);
|
|
font: inherit;
|
|
font-size: 13px;
|
|
text-transform: none;
|
|
letter-spacing: normal;
|
|
}
|
|
|
|
/* Switch + two-line label. Defensive resets defeat the scoped
|
|
blanket `label { flex-direction: column; text-transform: uppercase;
|
|
font-size: 10px; flex: 1 1 0; }` that form-row labels in this file
|
|
depend on — without the reset that rule would stack the switch on
|
|
top of the text and uppercase everything inside. */
|
|
.row-toggle {
|
|
display: flex;
|
|
flex-direction: row;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 10px 12px;
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius);
|
|
background: var(--panel-alt);
|
|
cursor: pointer;
|
|
user-select: none;
|
|
-webkit-user-select: none;
|
|
font-size: 13px;
|
|
text-transform: none;
|
|
letter-spacing: normal;
|
|
color: var(--text);
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
.row-toggle-text {
|
|
flex: 1 1 auto;
|
|
min-width: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 3px;
|
|
text-transform: none;
|
|
}
|
|
|
|
.row-toggle-label {
|
|
font-size: 13px;
|
|
font-weight: 500;
|
|
color: var(--text);
|
|
letter-spacing: normal;
|
|
text-transform: none;
|
|
}
|
|
|
|
.row-toggle-desc {
|
|
font-size: 12px;
|
|
color: var(--text-dim);
|
|
line-height: 1.4;
|
|
letter-spacing: normal;
|
|
text-transform: none;
|
|
}
|
|
|
|
.row-toggle .switch {
|
|
position: relative;
|
|
width: 32px;
|
|
height: 18px;
|
|
flex-shrink: 0;
|
|
background: var(--border);
|
|
border-radius: 999px;
|
|
transition: background 140ms var(--ease);
|
|
}
|
|
|
|
.row-toggle .switch.on {
|
|
background: var(--accent);
|
|
}
|
|
|
|
.row-toggle .switch input {
|
|
position: absolute;
|
|
inset: 0;
|
|
width: 100%;
|
|
height: 100%;
|
|
margin: 0;
|
|
opacity: 0;
|
|
cursor: inherit;
|
|
}
|
|
|
|
.row-toggle .switch::after {
|
|
content: '';
|
|
position: absolute;
|
|
top: 2px;
|
|
left: 2px;
|
|
width: 14px;
|
|
height: 14px;
|
|
background: #fff;
|
|
border-radius: 50%;
|
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
transition: transform 140ms var(--ease);
|
|
}
|
|
|
|
.row-toggle .switch.on::after {
|
|
transform: translateX(14px);
|
|
}
|
|
|
|
.clipart-row {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
margin-bottom: 12px;
|
|
}
|
|
|
|
.clipart-label {
|
|
font-size: 10px;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.05em;
|
|
color: var(--text-dim);
|
|
}
|
|
|
|
.clipart-value {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
padding: 8px 10px;
|
|
background: var(--panel-alt);
|
|
border: 1px solid var(--border);
|
|
border-radius: var(--radius-sm);
|
|
color: var(--text);
|
|
font-size: 12px;
|
|
}
|
|
|
|
.clipart-folder-name {
|
|
flex: 1 1 auto;
|
|
font-variant-numeric: tabular-nums;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.clipart-folder-empty {
|
|
color: var(--text-dim);
|
|
font-style: italic;
|
|
}
|
|
|
|
.clipart-folder-list {
|
|
list-style: none;
|
|
margin: 0;
|
|
padding: 0;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 4px;
|
|
}
|
|
|
|
.ghost-btn.small {
|
|
padding: 2px 8px;
|
|
font-size: 11px;
|
|
}
|
|
|
|
.clipart-actions {
|
|
display: flex;
|
|
gap: 8px;
|
|
margin-bottom: 10px;
|
|
}
|
|
|
|
.primary-btn {
|
|
padding: 6px 12px;
|
|
border-radius: var(--radius-sm);
|
|
background: var(--accent);
|
|
color: var(--accent-text, #fff);
|
|
border: 1px solid transparent;
|
|
font-size: 12px;
|
|
font-weight: 500;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.primary-btn:hover:not(:disabled) {
|
|
filter: brightness(1.1);
|
|
}
|
|
|
|
.primary-btn:disabled {
|
|
opacity: 0.5;
|
|
cursor: not-allowed;
|
|
}
|
|
|
|
.ghost-btn {
|
|
padding: 6px 12px;
|
|
border-radius: var(--radius-sm);
|
|
background: transparent;
|
|
color: var(--text);
|
|
border: 1px solid var(--border);
|
|
font-size: 12px;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.ghost-btn:hover {
|
|
background: var(--panel-alt);
|
|
}
|
|
|
|
.error-line {
|
|
margin: 0 0 8px;
|
|
color: var(--danger);
|
|
font-size: 11px;
|
|
}
|
|
|
|
.theme-grid {
|
|
display: grid;
|
|
grid-template-columns: 1fr 1fr;
|
|
gap: 10px;
|
|
}
|
|
|
|
.theme-card {
|
|
flex-direction: column;
|
|
padding: 12px;
|
|
gap: 10px;
|
|
background: var(--panel-alt);
|
|
border: 2px solid var(--border);
|
|
border-radius: var(--radius);
|
|
align-items: stretch;
|
|
}
|
|
|
|
.theme-card:hover:not(:disabled) {
|
|
background: var(--panel-hover);
|
|
border-color: var(--border-strong);
|
|
}
|
|
|
|
.theme-card.active {
|
|
border-color: var(--accent);
|
|
background: var(--accent-soft);
|
|
}
|
|
|
|
.theme-preview {
|
|
height: 74px;
|
|
border-radius: var(--radius-sm);
|
|
display: flex;
|
|
align-items: stretch;
|
|
gap: 6px;
|
|
padding: 8px;
|
|
}
|
|
|
|
.theme-preview-dark {
|
|
background: #17171b;
|
|
border: 1px solid #2e2e37;
|
|
}
|
|
|
|
.theme-preview-dark .tp-panel {
|
|
background: #272730;
|
|
flex: 1;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.theme-preview-dark .tp-accent {
|
|
background: #6ea8ff;
|
|
width: 22px;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.theme-preview-light {
|
|
background: #f3f3f6;
|
|
border: 1px solid #e2e2e7;
|
|
}
|
|
|
|
.theme-preview-light .tp-panel {
|
|
background: #ffffff;
|
|
flex: 1;
|
|
border-radius: 3px;
|
|
border: 1px solid #e2e2e7;
|
|
}
|
|
|
|
.theme-preview-light .tp-accent {
|
|
background: #2b6af5;
|
|
width: 22px;
|
|
border-radius: 3px;
|
|
}
|
|
|
|
.theme-label {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 6px;
|
|
font-size: 12px;
|
|
color: var(--text);
|
|
font-weight: 500;
|
|
justify-content: center;
|
|
}
|
|
|
|
.theme-card.active .theme-label {
|
|
color: var(--accent);
|
|
}
|
|
|
|
.primary {
|
|
padding: 6px 14px;
|
|
background: var(--accent-soft);
|
|
border: 1px solid var(--accent);
|
|
color: var(--accent);
|
|
border-radius: var(--radius-sm);
|
|
font-weight: 500;
|
|
}
|
|
|
|
.primary:hover:not(:disabled) {
|
|
background: var(--accent-soft-strong);
|
|
}
|
|
</style>
|