97 lines
4.2 KiB
Vue
97 lines
4.2 KiB
Vue
<script setup lang="ts">
|
||
import { ref, watch } from 'vue';
|
||
import { usePrimaryColor } from '@/composables/usePrimaryColor';
|
||
|
||
const active = ref<'appearance'|'theme'|'layout'>('appearance');
|
||
|
||
// Accent color state using global composable
|
||
const { primaryColor, updatePrimaryColor } = usePrimaryColor();
|
||
|
||
// Local hex input model to allow free typing without instantly rejecting partial values
|
||
const hexInput = ref<string>(primaryColor.value || '#ff007a');
|
||
|
||
watch(primaryColor, (val) => {
|
||
if (val && val.toLowerCase() !== hexInput.value.toLowerCase()) {
|
||
hexInput.value = val;
|
||
}
|
||
});
|
||
|
||
function onPickColor(e: Event) {
|
||
const value = (e.target as HTMLInputElement).value;
|
||
hexInput.value = value;
|
||
updatePrimaryColor(value);
|
||
}
|
||
|
||
function onHexInput(e: Event) {
|
||
const value = (e.target as HTMLInputElement).value.trim();
|
||
hexInput.value = value;
|
||
}
|
||
|
||
function applyHex() {
|
||
// Accept #RGB or #RRGGBB; auto-add leading # if missing
|
||
let v = hexInput.value.trim();
|
||
if (!v.startsWith('#')) v = `#${v}`;
|
||
const isValid = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/.test(v);
|
||
if (isValid) {
|
||
hexInput.value = v.toLowerCase();
|
||
updatePrimaryColor(hexInput.value);
|
||
}
|
||
}
|
||
|
||
function resetToDefault() {
|
||
const def = '#ff007a';
|
||
hexInput.value = def;
|
||
updatePrimaryColor(def);
|
||
}
|
||
</script>
|
||
|
||
<template>
|
||
<div class="appearance-tabs">
|
||
<div class="tabs">
|
||
<button :class="{active: active==='appearance'}" @click="active='appearance'">Appearance</button>
|
||
<button :class="{active: active==='theme'}" @click="active='theme'">Theme</button>
|
||
<button :class="{active: active==='layout'}" @click="active='layout'">Layout</button>
|
||
</div>
|
||
<div class="panel">
|
||
<div v-if="active==='appearance'" class="section">
|
||
<div class="row">
|
||
<div class="label"><i data-lucide="palette"></i> Accent color</div>
|
||
<div class="controls">
|
||
<input class="color" type="color" :value="primaryColor" @input="onPickColor" />
|
||
<input class="hex" type="text" v-model="hexInput" @input="onHexInput" placeholder="#ff007a" />
|
||
<button class="apply" @click="applyHex">Apply</button>
|
||
<button class="reset" @click="resetToDefault">Reset</button>
|
||
</div>
|
||
</div>
|
||
<div class="hint">Tipp: Du kannst entweder den Farbwähler benutzen oder einen HEX‑Wert eingeben (z. B. #00aaff).</div>
|
||
<div class="preview">
|
||
<div class="swatch" :style="{ background: primaryColor }"></div>
|
||
<span class="code">{{ primaryColor }}</span>
|
||
</div>
|
||
</div>
|
||
<p v-else-if="active==='theme'">Theme settings coming soon.</p>
|
||
<p v-else>Layout settings coming soon.</p>
|
||
</div>
|
||
</div>
|
||
</template>
|
||
|
||
<style scoped>
|
||
.appearance-tabs { background:#0a0a0a; border:1px solid #151515; border-radius:12px; padding:12px; }
|
||
.tabs { display:flex; gap:8px; margin-bottom:10px; }
|
||
.tabs button { background:#0a0a0a; border:1px solid #1a1a1a; color:#fff; padding:8px 10px; border-radius:10px; font-size:12px; font-weight:900; cursor:pointer; }
|
||
.tabs button.active { background:#121212; border-color:#333; }
|
||
.panel { color:#aaa; font-size:12px; }
|
||
.section { display:flex; flex-direction:column; gap:10px; }
|
||
.row { display:flex; align-items:center; justify-content:space-between; gap:10px; }
|
||
.label { display:flex; align-items:center; gap:8px; color:#fff; font-weight:800; font-size:13px; }
|
||
.controls { display:flex; align-items:center; gap:8px; }
|
||
.color { width: 34px; height: 24px; border:1px solid #222; background:#111; border-radius:6px; padding:0; cursor:pointer; }
|
||
.hex { width:120px; background:#0a0a0a; border:1px solid #1a1a1a; color:#fff; padding:6px 8px; border-radius:8px; font-size:12px; font-weight:700; }
|
||
.apply, .reset { background:#0a0a0a; border:1px solid #1a1a1a; color:#fff; padding:6px 10px; border-radius:8px; font-size:12px; font-weight:800; cursor:pointer; }
|
||
.apply:hover, .reset:hover { border-color:#333; }
|
||
.hint { font-size:12px; color:#888; }
|
||
.preview { display:flex; align-items:center; gap:10px; }
|
||
.swatch { width:28px; height:18px; border-radius:6px; border:1px solid #222; }
|
||
.code { font-size:12px; color:#ccc; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace; }
|
||
</style>
|