Skip to content

Commit 06dc73a

Browse files
fix(frontend): satisfy react-hooks lint in PreviewPanel and ScreenshotEditor
Move inline Row/ToolButton components to module scope and avoid reading canvasRef.current during render so CI eslint passes. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent a02b277 commit 06dc73a

2 files changed

Lines changed: 122 additions & 66 deletions

File tree

core/frontend/src/components/PreviewPanel.tsx

Lines changed: 56 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,47 @@ interface Props {
1818
entry: ListEntry | null;
1919
}
2020

21+
function BrunoDetailRow({
22+
k,
23+
v,
24+
accent,
25+
}: {
26+
k: string;
27+
v: string;
28+
accent?: boolean;
29+
}) {
30+
return (
31+
<div
32+
className={
33+
"flex items-baseline justify-between border-b border-[var(--color-border)] py-1.5 last:border-b-0 " +
34+
(accent ? "font-semibold text-[var(--color-fg)]" : "text-[var(--color-muted)]")
35+
}
36+
>
37+
<span>{k}</span>
38+
<span className="font-[var(--font-mono)] tabular-nums">{v}</span>
39+
</div>
40+
);
41+
}
42+
43+
const BRUNO_STATE_LABELS: Record<string, string> = {
44+
bw: "Baden-Württemberg",
45+
by: "Bayern",
46+
be: "Berlin",
47+
bb: "Brandenburg",
48+
hb: "Bremen",
49+
hh: "Hamburg",
50+
he: "Hessen",
51+
mv: "Mecklenburg-Vorp.",
52+
ni: "Niedersachsen",
53+
nw: "Nordrhein-Westfalen",
54+
rp: "Rheinland-Pfalz",
55+
sl: "Saarland",
56+
sn: "Sachsen",
57+
st: "Sachsen-Anhalt",
58+
sh: "Schleswig-Holstein",
59+
th: "Thüringen",
60+
};
61+
2162
export function PreviewPanel({ entry }: Props) {
2263
const parsedFiles = useMemo<string[] | null>(() => {
2364
if (!entry || entry.kind !== "clip" || entry.data.content_type !== "files") return null;
@@ -233,24 +274,6 @@ export function PreviewPanel({ entry }: Props) {
233274
maximumFractionDigits: 1,
234275
});
235276
const d = entry.data;
236-
const Row = ({ k, v, accent }: { k: string; v: string; accent?: boolean }) => (
237-
<div
238-
className={
239-
"flex items-baseline justify-between border-b border-[var(--color-border)] py-1.5 last:border-b-0 " +
240-
(accent ? "font-semibold text-[var(--color-fg)]" : "text-[var(--color-muted)]")
241-
}
242-
>
243-
<span>{k}</span>
244-
<span className="font-[var(--font-mono)] tabular-nums">{v}</span>
245-
</div>
246-
);
247-
const STATE_LABELS: Record<string, string> = {
248-
bw: "Baden-Württemberg", by: "Bayern", be: "Berlin", bb: "Brandenburg",
249-
hb: "Bremen", hh: "Hamburg", he: "Hessen", mv: "Mecklenburg-Vorp.",
250-
ni: "Niedersachsen", nw: "Nordrhein-Westfalen", rp: "Rheinland-Pfalz",
251-
sl: "Saarland", sn: "Sachsen", st: "Sachsen-Anhalt",
252-
sh: "Schleswig-Holstein", th: "Thüringen",
253-
};
254277
return (
255278
<div className="flex h-full flex-col gap-3 overflow-auto p-4">
256279
<div className="text-[11px] uppercase tracking-wide text-[var(--color-muted)]">
@@ -261,7 +284,7 @@ export function PreviewPanel({ entry }: Props) {
261284
Annahmen
262285
</div>
263286
<div className="text-[12px] leading-tight text-[var(--color-fg)]">
264-
Klasse {d.taxClass} · {STATE_LABELS[d.state] ?? d.state.toUpperCase()} ·{" "}
287+
Klasse {d.taxClass} · {BRUNO_STATE_LABELS[d.state] ?? d.state.toUpperCase()} ·{" "}
265288
{d.children === 0 ? "kinderlos" : `${d.children} Kind${d.children === 1 ? "" : "er"}`}{" "}
266289
· {d.isChurchMember ? "kirchensteuerpflichtig" : "keine Kirchensteuer"}
267290
</div>
@@ -271,23 +294,23 @@ export function PreviewPanel({ entry }: Props) {
271294
</div>
272295

273296
<div className="rounded-xl border border-[var(--color-border)] bg-[var(--color-surface)] p-4">
274-
<Row k="Brutto / Jahr" v={eur.format(d.yearlyGross)} />
275-
<Row k="Brutto / Monat" v={eur.format(d.yearlyGross / 12)} />
276-
<Row k="Krankenversicherung" v={"− " + eurExact.format(d.social.health)} />
277-
<Row k="Pflegeversicherung" v={"− " + eurExact.format(d.social.care)} />
278-
<Row k="Rentenversicherung" v={"− " + eurExact.format(d.social.pension)} />
279-
<Row k="Arbeitslosenversicherung" v={"− " + eurExact.format(d.social.unemployment)} />
280-
<Row k="Einkommensteuer" v={"− " + eurExact.format(d.incomeTax)} />
281-
{d.soli > 0 && <Row k="Solidaritätszuschlag" v={"− " + eurExact.format(d.soli)} />}
282-
{d.churchTax > 0 && <Row k="Kirchensteuer" v={"− " + eurExact.format(d.churchTax)} />}
283-
<Row k="Summe Abgaben" v={eur.format(d.totalDeductions)} />
284-
<Row k="Abgabenquote" v={pct.format(d.deductionRate)} />
285-
<Row k="Grenzsteuersatz" v={pct.format(d.marginalRate)} />
297+
<BrunoDetailRow k="Brutto / Jahr" v={eur.format(d.yearlyGross)} />
298+
<BrunoDetailRow k="Brutto / Monat" v={eur.format(d.yearlyGross / 12)} />
299+
<BrunoDetailRow k="Krankenversicherung" v={"− " + eurExact.format(d.social.health)} />
300+
<BrunoDetailRow k="Pflegeversicherung" v={"− " + eurExact.format(d.social.care)} />
301+
<BrunoDetailRow k="Rentenversicherung" v={"− " + eurExact.format(d.social.pension)} />
302+
<BrunoDetailRow k="Arbeitslosenversicherung" v={"− " + eurExact.format(d.social.unemployment)} />
303+
<BrunoDetailRow k="Einkommensteuer" v={"− " + eurExact.format(d.incomeTax)} />
304+
{d.soli > 0 && <BrunoDetailRow k="Solidaritätszuschlag" v={"− " + eurExact.format(d.soli)} />}
305+
{d.churchTax > 0 && <BrunoDetailRow k="Kirchensteuer" v={"− " + eurExact.format(d.churchTax)} />}
306+
<BrunoDetailRow k="Summe Abgaben" v={eur.format(d.totalDeductions)} />
307+
<BrunoDetailRow k="Abgabenquote" v={pct.format(d.deductionRate)} />
308+
<BrunoDetailRow k="Grenzsteuersatz" v={pct.format(d.marginalRate)} />
286309
</div>
287310

288311
<div className="rounded-xl border border-[var(--color-accent)]/40 bg-[var(--color-accent)]/5 p-4">
289-
<Row k="Netto / Monat" v={eurExact.format(d.netMonth)} accent />
290-
<Row k="Netto / Jahr" v={eurExact.format(d.netYear)} accent />
312+
<BrunoDetailRow k="Netto / Monat" v={eurExact.format(d.netMonth)} accent />
313+
<BrunoDetailRow k="Netto / Jahr" v={eurExact.format(d.netYear)} accent />
291314
</div>
292315

293316
<div className="font-[var(--font-mono)] text-[11px] text-[var(--color-muted)]">

core/frontend/src/components/ScreenshotEditor.tsx

Lines changed: 66 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ const COLOR_PRESETS = ["#ef4444", "#facc15", "#ffffff", "#000000"] as const;
9696

9797
export function ScreenshotEditor() {
9898
const canvasRef = useRef<HTMLCanvasElement>(null);
99+
const [canvasEl, setCanvasEl] = useState<HTMLCanvasElement | null>(null);
99100
/** The decoded screenshot image. Kept in a ref because we need it
100101
* for every redraw (background) and for blur (sampling source
101102
* pixels). State would re-create the Image on every render. */
@@ -409,7 +410,10 @@ export function ScreenshotEditor() {
409410
{imgReady ? (
410411
<div className="relative">
411412
<canvas
412-
ref={canvasRef}
413+
ref={(el) => {
414+
canvasRef.current = el;
415+
setCanvasEl(el);
416+
}}
413417
onMouseDown={onCanvasMouseDown}
414418
onMouseMove={onCanvasMouseMove}
415419
onMouseUp={onCanvasMouseUp}
@@ -426,7 +430,7 @@ export function ScreenshotEditor() {
426430
/>
427431
{textInput && (
428432
<TextInputOverlay
429-
canvas={canvasRef.current}
433+
canvas={canvasEl}
430434
input={textInput}
431435
color={color}
432436
fontSize={Math.max(14, strokeWidth * 4)}
@@ -451,6 +455,35 @@ export function ScreenshotEditor() {
451455

452456
// ── Toolbar component ───────────────────────────────────────────────
453457

458+
function ToolButton({
459+
active,
460+
onSelect,
461+
icon,
462+
label,
463+
shortcut,
464+
}: {
465+
active: boolean;
466+
onSelect: () => void;
467+
icon: React.ReactNode;
468+
label: string;
469+
shortcut: string;
470+
}) {
471+
return (
472+
<button
473+
onClick={onSelect}
474+
title={`${label} (${shortcut})`}
475+
className={
476+
"flex h-10 w-10 items-center justify-center rounded-md border transition-colors " +
477+
(active
478+
? "border-[var(--color-accent)] bg-[var(--color-accent)]/15 text-[var(--color-accent)]"
479+
: "border-[var(--color-border)] hover:bg-[var(--color-bg)]")
480+
}
481+
>
482+
{icon}
483+
</button>
484+
);
485+
}
486+
454487
function Toolbar({
455488
tool,
456489
setTool,
@@ -466,43 +499,43 @@ function Toolbar({
466499
strokeWidth: number;
467500
setStrokeWidth: (n: number) => void;
468501
}) {
469-
const Btn = ({
470-
t,
471-
icon,
472-
label,
473-
shortcut,
474-
}: {
475-
t: Tool;
476-
icon: React.ReactNode;
477-
label: string;
478-
shortcut: string;
479-
}) => (
480-
<button
481-
onClick={() => setTool(t)}
482-
title={`${label} (${shortcut})`}
483-
className={
484-
"flex h-10 w-10 items-center justify-center rounded-md border transition-colors " +
485-
(tool === t
486-
? "border-[var(--color-accent)] bg-[var(--color-accent)]/15 text-[var(--color-accent)]"
487-
: "border-[var(--color-border)] hover:bg-[var(--color-bg)]")
488-
}
489-
>
490-
{icon}
491-
</button>
492-
);
493-
494502
return (
495503
<div className="flex w-14 shrink-0 flex-col items-center gap-1.5 border-r border-[var(--color-border)] bg-[var(--color-surface)] p-2">
496-
<Btn t="arrow" icon={<ArrowUpRight size={16} />} label="Arrow" shortcut="A" />
497-
<Btn t="text" icon={<Type size={16} />} label="Text" shortcut="T" />
498-
<Btn t="rect" icon={<Square size={16} />} label="Rectangle" shortcut="R" />
499-
<Btn
500-
t="highlight"
504+
<ToolButton
505+
active={tool === "arrow"}
506+
onSelect={() => setTool("arrow")}
507+
icon={<ArrowUpRight size={16} />}
508+
label="Arrow"
509+
shortcut="A"
510+
/>
511+
<ToolButton
512+
active={tool === "text"}
513+
onSelect={() => setTool("text")}
514+
icon={<Type size={16} />}
515+
label="Text"
516+
shortcut="T"
517+
/>
518+
<ToolButton
519+
active={tool === "rect"}
520+
onSelect={() => setTool("rect")}
521+
icon={<Square size={16} />}
522+
label="Rectangle"
523+
shortcut="R"
524+
/>
525+
<ToolButton
526+
active={tool === "highlight"}
527+
onSelect={() => setTool("highlight")}
501528
icon={<Highlighter size={16} />}
502529
label="Highlight"
503530
shortcut="H"
504531
/>
505-
<Btn t="blur" icon={<Droplets size={16} />} label="Blur" shortcut="B" />
532+
<ToolButton
533+
active={tool === "blur"}
534+
onSelect={() => setTool("blur")}
535+
icon={<Droplets size={16} />}
536+
label="Blur"
537+
shortcut="B"
538+
/>
506539

507540
<div className="mt-3 flex flex-col items-center gap-1.5">
508541
{COLOR_PRESETS.map((c) => (

0 commit comments

Comments
 (0)