Neuauftrag: Design angeglichen (Felder, Icons, Theme)
Umrandete, theme-sichere Eingabefelder (sieht aus wie ein Feld, Dark-Mode ok), Section-Koepfe mit Material-Icons statt Emoji, konsistente Buttons (Primaer gefuellt / Sekundaer Umriss), getoente Bereiche mit Haarlinie. Primaerfarbe ueber Theme-Variable. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -12,31 +12,32 @@
|
||||
import { defineComponent, ref, reactive, onMounted, h, resolveComponent, Teleport } from 'vue';
|
||||
import { useApi } from '@directus/extensions-sdk';
|
||||
|
||||
const ACCENT = '#1E50A5';
|
||||
// Weißes, randloses Eingabefeld – hebt sich durch Kontrast + leichten Schatten
|
||||
// vom hellblauen Bereich ab (kein Rahmen).
|
||||
const WFELD = 'background:#fff;border:none;border-radius:8px;padding:9px 12px;font:inherit;font-size:14px;color:#1A1A1A;outline:none;box-shadow:0 1px 2px rgba(0,0,0,.08);';
|
||||
const ACCENT = 'var(--primary,#1E50A5)';
|
||||
// Klar umrandetes, theme-sicheres Eingabefeld (sieht aus wie ein Feld).
|
||||
const WFELD = 'background:var(--background-page);border:1px solid var(--border-normal);border-radius:8px;padding:9px 12px;font:inherit;font-size:14px;color:var(--foreground-normal);outline:none;';
|
||||
const WSELECT = WFELD + 'cursor:pointer;';
|
||||
// Hellblauer Bereich (kein Rahmen).
|
||||
const BEREICH = 'background:rgba(30,80,165,.06);border-radius:12px;padding:18px 20px;';
|
||||
// Getönter Bereich mit Haarlinie.
|
||||
const BEREICH = 'background:var(--background-subdued,#f6f8fb);border:1px solid var(--border-subdued);border-radius:12px;padding:18px 20px;';
|
||||
const STANDARD_PLATZHALTER = ['Anrede', 'Vorname', 'Nachname', 'Strasse', 'PLZ', 'Ort', 'Land', 'Briefnummer'];
|
||||
|
||||
function btn(label, onClick, kind) {
|
||||
const base = 'cursor:pointer;border-radius:8px;padding:8px 16px;font:inherit;font-size:14px;border:none;';
|
||||
const style = kind === 'primary' ? base + `background:${ACCENT};color:#fff;box-shadow:0 1px 3px rgba(0,0,0,.15);`
|
||||
: base + `background:#fff;color:${ACCENT};box-shadow:0 1px 2px rgba(0,0,0,.1);`;
|
||||
return h('button', { type: 'button', onClick, style }, label);
|
||||
// Echtes Directus-Icon (Material Symbols) statt Emoji.
|
||||
const icon = (name, extra = {}) => h(resolveComponent('v-icon'), { name, small: true, ...extra });
|
||||
function btn(label, onClick, kind, ic) {
|
||||
const base = 'cursor:pointer;border-radius:8px;padding:9px 16px;font:inherit;font-size:14px;font-weight:500;display:inline-flex;align-items:center;justify-content:center;gap:6px;border:1px solid;';
|
||||
const style = kind === 'primary' ? base + `border-color:${ACCENT};background:${ACCENT};color:#fff;`
|
||||
: base + 'border-color:var(--border-normal);background:var(--background-page,#fff);color:var(--foreground-normal);';
|
||||
return h('button', { type: 'button', onClick, style }, [ic ? icon(ic) : null, label].filter(Boolean));
|
||||
}
|
||||
function subdued(t, extra) { return h('div', { style: `color:var(--foreground-subdued);font-size:13px;${extra || ''}` }, t); }
|
||||
function segToggle(value, opts, onSel) {
|
||||
return h('div', { style: 'display:flex;width:100%;border-radius:8px;overflow:hidden;background:#fff;box-shadow:0 1px 2px rgba(0,0,0,.08);' },
|
||||
return h('div', { style: 'display:flex;width:100%;border-radius:8px;overflow:hidden;border:1px solid var(--border-normal);background:var(--background-page,#fff);' },
|
||||
opts.map((o) => h('button', {
|
||||
type: 'button', onClick: () => onSel(o.key),
|
||||
style: `flex:1;padding:10px 8px;font:inherit;font-size:13px;text-align:center;cursor:pointer;border:none;`
|
||||
+ (value === o.key ? `background:${ACCENT};color:#fff;font-weight:700;` : `background:transparent;color:${ACCENT};`),
|
||||
+ (value === o.key ? `background:${ACCENT};color:#fff;font-weight:500;` : `background:transparent;color:var(--foreground-normal);`),
|
||||
}, o.label)));
|
||||
}
|
||||
function bereichKopf(txt) { return h('div', { style: `font-size:15px;font-weight:800;color:${ACCENT};margin-bottom:14px;` }, txt); }
|
||||
function bereichKopf(ic, txt) { return h('div', { style: 'display:flex;align-items:center;gap:7px;font-size:16px;font-weight:500;color:var(--foreground-normal);margin-bottom:14px;' }, [icon(ic), txt]); }
|
||||
function label(txt) { return h('label', { style: 'display:block;font-size:11px;text-transform:uppercase;letter-spacing:.04em;color:var(--foreground-subdued);margin-bottom:4px;' }, txt); }
|
||||
|
||||
const NeuAuftrag = defineComponent({
|
||||
@@ -564,7 +565,7 @@ const NeuAuftrag = defineComponent({
|
||||
|
||||
// Bereich 1 – Produkt
|
||||
const b1 = h('div', { style: BEREICH }, [
|
||||
bereichKopf('📄 Produkt'),
|
||||
bereichKopf('description', 'Produkt'),
|
||||
h('div', { style: 'display:grid;grid-template-columns:repeat(3,1fr);gap:12px;' }, [
|
||||
h('div', {}, [label('Produkt'), sel(neu.product, produkte.value.map((p) => ({ v: p.key, t: p.name })), (e) => { neu.product = e.target.value; neu.format = neuFormate()[0]?.key || ''; neu.previewSession = null; })]),
|
||||
h('div', {}, [label('Format'), sel(neu.format, neuFormate().map((f) => ({ v: f.key, t: f.name })), (e) => { neu.format = e.target.value; neu.previewSession = null; })]),
|
||||
@@ -594,7 +595,7 @@ const NeuAuftrag = defineComponent({
|
||||
// Bereich 2 – Kuvert (Empfängertabelle)
|
||||
const b2 = h('div', { style: BEREICH }, [
|
||||
h('div', { style: 'display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:14px;' }, [
|
||||
bereichKopf('✉ Kuvert'),
|
||||
bereichKopf('mail', 'Kuvert'),
|
||||
identischModus() ? null : h('div', { style: 'width:420px;max-width:100%;' }, [segToggle(neu.adressModus, [{ key: '5zeilen', label: '5 Zeilen' }, { key: 'felder', label: 'Einzelfelder' }, { key: 'individuell', label: 'Ind. Text' }], (k) => { neu.adressModus = k; neu.previewSession = null; })]),
|
||||
]),
|
||||
// Ohne Kuvert & ohne eigene Platzhalter genügt eine Stückzahl (identische
|
||||
@@ -663,7 +664,7 @@ const NeuAuftrag = defineComponent({
|
||||
// Bereich 3 – Text (Mustertext-Dropdown direkt darüber)
|
||||
const b3 = h('div', { style: BEREICH }, [
|
||||
h('div', { style: 'display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:14px;' }, [
|
||||
bereichKopf('✍ Text'),
|
||||
bereichKopf('edit', 'Text'),
|
||||
h('select', { style: WSELECT + 'font-size:13px;padding:7px 10px;width:auto;', onChange: (e) => { if (e.target.value) { musterEinfuegen(e.target.value); e.target.value = ''; } } },
|
||||
[h('option', { value: '' }, 'Mustertext einfügen …')].concat(
|
||||
musterListe.value.length
|
||||
@@ -717,7 +718,7 @@ const NeuAuftrag = defineComponent({
|
||||
|
||||
// Bereich 4 – Kunde
|
||||
const b4 = h('div', { style: BEREICH }, [
|
||||
bereichKopf('👤 Kunde'),
|
||||
bereichKopf('person', 'Kunde'),
|
||||
h('div', { style: 'display:flex;gap:16px;flex-wrap:wrap;' }, [
|
||||
h('div', { style: 'flex:1 1 280px;max-width:420px;' }, [
|
||||
label('Auftragsname (optional)'),
|
||||
@@ -763,7 +764,7 @@ const NeuAuftrag = defineComponent({
|
||||
// Vorschau rechts daneben (eigener hellblauer Bereich).
|
||||
const rechts = h('div', { style: BEREICH + 'flex:0 0 340px;position:sticky;top:20px;align-self:flex-start;' }, [
|
||||
h('div', { style: 'display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;' }, [
|
||||
bereichKopf('👁 Vorschau'),
|
||||
bereichKopf('visibility', 'Vorschau'),
|
||||
btn(neu.pLaedt ? '…' : 'Aktualisieren', preview),
|
||||
]),
|
||||
neu.pLaedt ? subdued('Wird erzeugt …')
|
||||
@@ -900,7 +901,7 @@ const NeuAuftrag = defineComponent({
|
||||
]);
|
||||
const b1 = h('div', { style: BEREICH }, [
|
||||
h('div', { style: 'display:flex;justify-content:space-between;align-items:center;gap:10px;flex-wrap:wrap;margin-bottom:12px;' }, [
|
||||
bereichKopf('✍ Unterschriften'),
|
||||
bereichKopf('draw', 'Unterschriften'),
|
||||
h('div', { style: 'width:280px;' }, [segToggle(sig.modus, [{ key: 'auftrag', label: 'Aus Auftrag' }, { key: 'manuell', label: 'Manuell' }], (k) => { sig.modus = k; sig.pdf = ''; })]),
|
||||
]),
|
||||
sig.modus === 'auftrag'
|
||||
@@ -918,7 +919,7 @@ const NeuAuftrag = defineComponent({
|
||||
]),
|
||||
]);
|
||||
const b2 = h('div', { style: BEREICH }, [
|
||||
bereichKopf('Unterschriften & Position'),
|
||||
bereichKopf('tune', 'Unterschriften & Position'),
|
||||
subdued(sig.modus === 'auftrag'
|
||||
? 'Aus dem Kundenkonto vorbelegt (Marker + Feinjustierung), hier überschreibbar. Weitere Unterschrift-SVGs sind ergänzbar.'
|
||||
: 'Unterschrift(en) als SVG hochladen und Marker/Position setzen.', 'margin-bottom:10px;'),
|
||||
@@ -969,7 +970,7 @@ const NeuAuftrag = defineComponent({
|
||||
const links = h('div', { style: 'flex:1;min-width:0;display:flex;flex-direction:column;gap:16px;' }, [b1, b2, meldung]);
|
||||
const rechts = h('div', { style: BEREICH + 'flex:0 0 420px;position:sticky;top:20px;align-self:flex-start;min-height:200px;' }, [
|
||||
h('div', { style: 'display:flex;justify-content:space-between;align-items:center;gap:8px;' }, [
|
||||
bereichKopf('👁 Vorschau'),
|
||||
bereichKopf('visibility', 'Vorschau'),
|
||||
sig.pdf ? h('a', { href: sig.pdf, target: '_blank', rel: 'noopener', style: `font-size:12px;color:${ACCENT};text-decoration:none;white-space:nowrap;` }, '↗ Neuer Tab') : null,
|
||||
]),
|
||||
sig.pdf
|
||||
|
||||
Reference in New Issue
Block a user