Qsl
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
Select, SelectContent, SelectItem, SelectTrigger, SelectValue,
|
||||
} from '@/components/ui/select';
|
||||
import { Separator } from '@/components/ui/separator';
|
||||
import { cn } from '@/lib/utils';
|
||||
import type { CardTemplate, CardElement, QSOBox, QSLPresetInfo, StyleParams } from './qslTypes';
|
||||
import type { CardSelection } from './CardPreview';
|
||||
import { StylePresetPicker, NumberField } from './StylePresetPicker';
|
||||
@@ -21,16 +22,29 @@ interface Props {
|
||||
onPatchElement: (idx: number, patch: Partial<CardElement>) => void;
|
||||
onPatchBox: (patch: Partial<QSOBox>) => void;
|
||||
onScrim: (enabled: boolean) => void;
|
||||
onSelect?: (sel: CardSelection) => void;
|
||||
}
|
||||
|
||||
const TYPE_LABELS: Record<string, string> = {
|
||||
callsign: 'Callsign',
|
||||
operator: 'Operator name',
|
||||
info_line: 'Info line',
|
||||
country: 'Country block',
|
||||
country: 'Country + flag',
|
||||
insert: 'Photo insert',
|
||||
};
|
||||
|
||||
// A readable layer name, disambiguating the two info lines and numbering inserts.
|
||||
function layerLabel(el: CardElement, i: number, all: CardElement[]): string {
|
||||
if (el.type === 'info_line') {
|
||||
return /rig|antenna|ant\b/i.test(el.text ?? '') ? 'Station (rig / ant)' : 'Info line (zones)';
|
||||
}
|
||||
if (el.type === 'insert') {
|
||||
const n = all.slice(0, i + 1).filter((x) => x.type === 'insert').length;
|
||||
return `Photo insert ${n}`;
|
||||
}
|
||||
return TYPE_LABELS[el.type] ?? el.type;
|
||||
}
|
||||
|
||||
function TextControls({ e, idx, presets, fontFamilies, onPatch }: {
|
||||
e: CardElement; idx: number; presets: QSLPresetInfo[]; fontFamilies: string[];
|
||||
onPatch: (idx: number, patch: Partial<CardElement>) => void;
|
||||
@@ -71,12 +85,12 @@ function TextControls({ e, idx, presets, fontFamilies, onPatch }: {
|
||||
);
|
||||
}
|
||||
|
||||
export function EditorPanel({ template, sel, presets, fontFamilies, onPatchElement, onPatchBox, onScrim }: Props) {
|
||||
export function EditorPanel({ template, sel, presets, fontFamilies, onPatchElement, onPatchBox, onScrim, onSelect }: Props) {
|
||||
const e = typeof sel === 'number' ? template.elements[sel] : undefined;
|
||||
const box = template.qso_box;
|
||||
|
||||
return (
|
||||
<div className="flex w-72 shrink-0 flex-col gap-3 overflow-y-auto pr-1 text-sm">
|
||||
<div className="flex w-80 shrink-0 flex-col gap-3 overflow-y-auto pr-1 text-sm">
|
||||
<div className="space-y-2 rounded-md border border-border p-3">
|
||||
<div className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">Card</div>
|
||||
<label className="flex items-center gap-2 text-sm">
|
||||
@@ -88,6 +102,27 @@ export function EditorPanel({ template, sel, presets, fontFamilies, onPatchEleme
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Layers: show/hide each piece, click a name to edit it. */}
|
||||
<div className="space-y-1 rounded-md border border-border p-3">
|
||||
<div className="mb-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground">Show on card</div>
|
||||
{template.elements.map((el, i) => (
|
||||
<div key={i} className={cn('flex items-center gap-2 rounded px-1 py-0.5', sel === i && 'bg-muted')}>
|
||||
<Checkbox checked={!el.hidden} onCheckedChange={(v) => onPatchElement(i, { hidden: v !== true })} />
|
||||
<button type="button" className="flex-1 truncate text-left text-sm" onClick={() => onSelect?.(i)}>
|
||||
{layerLabel(el, i, template.elements)}
|
||||
</button>
|
||||
</div>
|
||||
))}
|
||||
{box && (
|
||||
<div className={cn('flex items-center gap-2 rounded px-1 py-0.5', sel === 'box' && 'bg-muted')}>
|
||||
<Checkbox checked={box.enabled} onCheckedChange={(v) => onPatchBox({ enabled: v === true })} />
|
||||
<button type="button" className="flex-1 truncate text-left text-sm" onClick={() => onSelect?.('box')}>
|
||||
QSO info box
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 rounded-md border border-border p-3">
|
||||
<div className="text-xs font-semibold uppercase tracking-wider text-muted-foreground">
|
||||
{e ? TYPE_LABELS[e.type] ?? e.type : sel === 'box' ? 'QSO box' : 'Selection'}
|
||||
|
||||
Reference in New Issue
Block a user