"use client"; import { Icon } from "@/components/icons"; import { Field, Notice, TextInput, cx } from "@/components/ui"; import { evaluateContrast } from "@/lib/qr/contrast"; import { COLOR_PRESETS, EC_LEVELS, EC_LEVEL_LABELS, MAX_SIZE, MIN_SIZE, type EcLevel, type QrDesign, } from "@/lib/qr/design"; const HEX_INPUT = /^#[0-9a-fA-F]{6}$/; function ColorField({ label, value, onChange, id, }: { label: string; value: string; onChange: (value: string) => void; id: string; }) { const valid = HEX_INPUT.test(value); return (
onChange(event.target.value.toUpperCase())} className="size-10 shrink-0 cursor-pointer rounded-lg border border-slate-300 bg-surface p-1" /> { const next = event.target.value.trim(); onChange(next.startsWith("#") ? next.toUpperCase() : `#${next.toUpperCase()}`); }} className="font-mono uppercase" />
); } export function DesignPanel({ design, onChange, }: { design: QrDesign; onChange: (design: QrDesign) => void; }) { const patch = (changes: Partial) => onChange({ ...design, ...changes }); const contrast = evaluateContrast(design.fgColor, design.bgColor); return (
patch({ fgColor })} /> patch({ bgColor })} />
{COLOR_PRESETS.map((preset) => ( ))}
{contrast.message ? ( {contrast.message} Kontrastverhältnis: {contrast.ratio.toFixed(1)} : 1 ) : null}
patch({ size: Number(event.target.value) })} className="h-2 w-full cursor-pointer appearance-none rounded-full bg-slate-200 accent-indigo-600" /> { const raw = Number(event.target.value); if (Number.isNaN(raw)) return; patch({ size: Math.min(MAX_SIZE, Math.max(MIN_SIZE, Math.round(raw))) }); }} className="w-24 shrink-0 rounded-lg border border-slate-300 bg-surface px-2.5 py-2 text-sm tabular-nums shadow-sm" />
{EC_LEVELS.map((level: EcLevel) => ( ))}
patch({ margin: Number(event.target.value) })} className="h-2 w-full cursor-pointer appearance-none rounded-full bg-slate-200 accent-indigo-600" />
); }