Files
kit-ui/components/qrcode/QROptions.tsx
Sebastian Krüger 998ac641f9 refactor: externalize shared primitives, remove shadcn mixing in tools
Shared components (components/ui/):
- slider-row.tsx: SliderRow — label + display value + Slider, replaces
  inline slider blocks in FileConverter, QROptions
- color-input.tsx: ColorInput — color swatch + hex text input pair,
  replaces repeated inline patterns in QROptions, KeyframeProperties,
  FaviconGenerator

Media tool (FileConverter.tsx):
- Remove all shadcn Select/SelectTrigger/SelectContent/SelectItem
- Replace with native <select> + selectCls (matches AnimationSettings
  and all other tools)
- Use SliderRow for video/audio bitrate and image quality sliders
- Net: -6 shadcn Select trees, consistent with every other tool

QROptions.tsx:
- Use SliderRow for margin slider (remove raw Slider import)
- Use ColorInput for foreground + background color pairs

KeyframeProperties.tsx:
- Use ColorInput for background color pair (keep local SliderRow which
  has a different layout with number input)

FaviconGenerator.tsx:
- Use ColorInput for background + theme color pairs

AnimationSettings.tsx:
- Remove dead bg-[#1a1a2e] per-option className (global CSS handles
  select option styling via bg-popover)

Delete:
- components/media/ConversionOptions.tsx — dead code (no imports),
  contained the shadcn Label/Input/Select/Slider patterns being replaced

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-01 13:08:58 +01:00

114 lines
3.7 KiB
TypeScript

'use client';
import { SliderRow } from '@/components/ui/slider-row';
import { ColorInput } from '@/components/ui/color-input';
import { cn } from '@/lib/utils/cn';
import type { ErrorCorrectionLevel } from '@/types/qrcode';
interface QROptionsProps {
errorCorrection: ErrorCorrectionLevel;
foregroundColor: string;
backgroundColor: string;
margin: number;
onErrorCorrectionChange: (ec: ErrorCorrectionLevel) => void;
onForegroundColorChange: (color: string) => void;
onBackgroundColorChange: (color: string) => void;
onMarginChange: (margin: number) => void;
}
const EC_OPTIONS: { value: ErrorCorrectionLevel; label: string; desc: string }[] = [
{ value: 'L', label: 'L', desc: '7%' },
{ value: 'M', label: 'M', desc: '15%' },
{ value: 'Q', label: 'Q', desc: '25%' },
{ value: 'H', label: 'H', desc: '30%' },
];
export function QROptions({
errorCorrection,
foregroundColor,
backgroundColor,
margin,
onErrorCorrectionChange,
onForegroundColorChange,
onBackgroundColorChange,
onMarginChange,
}: QROptionsProps) {
const isTransparent = backgroundColor === '#00000000';
return (
<div className="space-y-5">
{/* Error Correction */}
<div>
<span className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest block mb-2">
Error Correction
</span>
<div className="flex gap-1.5">
{EC_OPTIONS.map((opt) => (
<button
key={opt.value}
onClick={() => onErrorCorrectionChange(opt.value)}
className={cn(
'flex-1 flex flex-col items-center py-2 rounded-lg border text-xs font-mono transition-all',
errorCorrection === opt.value
? 'bg-primary/10 border-primary/40 text-primary'
: 'border-border/30 text-muted-foreground hover:border-primary/30 hover:text-foreground'
)}
>
<span className="font-semibold">{opt.label}</span>
<span className="text-[9px] opacity-50 mt-0.5">{opt.desc}</span>
</button>
))}
</div>
</div>
{/* Colors */}
<div className="space-y-3">
<span className="text-[10px] font-semibold text-muted-foreground uppercase tracking-widest block">
Colors
</span>
{/* Foreground */}
<div>
<label className="text-[9px] text-muted-foreground/50 font-mono block mb-1.5">Foreground</label>
<ColorInput value={foregroundColor} onChange={onForegroundColorChange} />
</div>
{/* Background */}
<div>
<div className="flex items-center justify-between mb-1.5">
<label className="text-[9px] text-muted-foreground/50 font-mono">Background</label>
<button
onClick={() => onBackgroundColorChange(isTransparent ? '#ffffff' : '#00000000')}
className={cn(
'text-[9px] font-mono px-1.5 py-0.5 rounded border transition-all',
isTransparent
? 'border-primary/40 text-primary bg-primary/10'
: 'border-border/30 text-muted-foreground/50 hover:border-primary/30 hover:text-primary'
)}
>
Transparent
</button>
</div>
<ColorInput
value={isTransparent ? '#ffffff' : backgroundColor}
onChange={onBackgroundColorChange}
disabled={isTransparent}
/>
</div>
</div>
{/* Margin */}
<SliderRow
label="Margin"
display={String(margin)}
value={margin}
min={0}
max={8}
step={1}
onChange={onMarginChange}
/>
</div>
);
}