Files
dwg-dxf-viewer-hm/src/components/OptionsPanel.tsx
T
minsung c7a782f19c fix: use HM Label instead of bare <label> for switch fields
ai-generation-guard.mjs flagged REUSE-004 on 5 native <label>
wrappers around Switch controls in Toolbar/OptionsPanel; swapped to
@hm-design/ui's Label per AGENTS.md field-label rule. Remaining guard
findings (hidden file input, dynamic panel geometry, per-entity CAD
layer color) are documented exceptions with no matching HM component.

Refs #1
2026-10-12 17:46:07 +09:00

169 lines
5.0 KiB
TypeScript

import { Button, Input, Label, Slider, Switch } from '@hm-design/ui';
import { RotateCcw } from 'lucide-react';
import { DraggablePanel } from './DraggablePanel';
import { SlidersHorizontal } from 'lucide-react';
import type { PersistedOptions } from '../hooks/useDwgViewer';
function SliderNumberRow({
label,
value,
min,
max,
step,
unit,
onChange,
}: {
label: string;
value: number;
min: number;
max: number;
step: number;
unit?: string;
onChange: (v: number) => void;
}) {
return (
<div className="space-y-1.5">
<div className="flex items-center justify-between">
<Label className="text-xs text-muted-foreground">{label}</Label>
<div className="flex items-center gap-1">
<Input
type="number"
min={min}
max={max}
step={step}
value={value}
size="small"
className="w-20"
onChange={(e) => {
const v = Number(e.target.value);
if (Number.isFinite(v)) onChange(v);
}}
/>
{unit && <span className="text-xs text-muted-foreground">{unit}</span>}
</div>
</div>
<Slider
value={[value]}
min={min}
max={max}
step={step}
aria-label={label}
onValueChange={([v]) => onChange(v)}
/>
</div>
);
}
export interface OptionsPanelProps {
open: boolean;
onClose: () => void;
options: PersistedOptions;
is25D: boolean;
lineweightClasses: number[];
onSetGrid: (on: boolean) => void;
onSetZoomSpeed: (v: number) => void;
onSetZScale: (v: number) => void;
onSetLineweightOn: (on: boolean | null) => void;
onSetLineweightScale: (v: number | null) => void;
onSet25D: (on: boolean) => void;
onReset: () => void;
}
export function OptionsPanel({
open,
onClose,
options,
is25D,
lineweightClasses,
onSetGrid,
onSetZoomSpeed,
onSetZScale,
onSetLineweightOn,
onSetLineweightScale,
onSet25D,
onReset,
}: OptionsPanelProps) {
const lwScale = options.lineweightScale ?? 11;
const lwPreview =
lineweightClasses.length > 0
? lineweightClasses.map((mm) => `${mm.toFixed(2)}mm → ${(mm * lwScale).toFixed(1)}px`).join(' · ')
: `이 도면에는 굵은 선이 없습니다 (0.50mm 였다면 ${(0.5 * lwScale).toFixed(1)}px)`;
return (
<DraggablePanel
title="옵션"
icon={<SlidersHorizontal className="size-4" />}
initial={{ left: window.innerWidth - 676, top: 56 }}
width={340}
height={520}
open={open}
onClose={onClose}
headerActions={
<Button type="button" variant="ghost" size="icon-xs" title="기본값으로" aria-label="기본값으로" onClick={onReset}>
<RotateCcw />
</Button>
}
>
<div className="space-y-5">
<section className="space-y-3">
<h4 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">선가중치</h4>
<Label className="w-full justify-between text-sm">
표시 사용
<Switch
checked={options.lineweightOn ?? false}
onCheckedChange={(on) => onSetLineweightOn(on)}
/>
</Label>
<SliderNumberRow
label="표시 배율 (px/mm)"
value={lwScale}
min={2}
max={60}
step={0.5}
onChange={onSetLineweightScale}
/>
<p className="text-xs text-muted-foreground">{lwPreview}</p>
<p className="text-xs text-muted-foreground">AutoCAD의 "선가중치 설정 → 표시 배율"과 동일합니다.</p>
</section>
<section className="space-y-3 border-t pt-4">
<h4 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">표시</h4>
<Label className="w-full justify-between text-sm">
그리드
<Switch checked={options.grid} onCheckedChange={onSetGrid} />
</Label>
<SliderNumberRow
label="줌 속도"
value={options.zoomSpeed}
min={0.2}
max={3}
step={0.1}
onChange={onSetZoomSpeed}
/>
</section>
<section className="space-y-3 border-t pt-4">
<h4 className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">2.5D</h4>
<Label className="w-full justify-between text-sm">
2.5D 보기
<Switch checked={is25D} onCheckedChange={onSet25D} />
</Label>
<div className={is25D ? '' : 'pointer-events-none opacity-50'}>
<SliderNumberRow
label="Z 높이 배율"
value={options.zScale}
min={1}
max={50}
step={0.5}
onChange={onSetZScale}
/>
</div>
<p className="text-xs text-muted-foreground">
좌클릭 드래그로 회전, 중간/우클릭 드래그로 이동합니다.
</p>
</section>
</div>
</DraggablePanel>
);
}