fix: clean up files section and add KB/MB unit selector to compress

- Remove duplicate "Files" heading (section header + inline count)
- Space "Show more" and "Clear all" apart on the same row
- Replace bare number input with number + KB/MB dropdown for target
  size, defaulting to KB; MB values are converted to KB for the API
- Hide native number input spin buttons for a cleaner look
This commit is contained in:
SnapOtter
2026-05-11 16:54:13 +08:00
parent 0c8e8c075c
commit 72de10b844
2 changed files with 45 additions and 28 deletions
@@ -5,6 +5,7 @@ import { useToolProcessor } from "@/hooks/use-tool-processor";
import { useFileStore } from "@/stores/file-store"; import { useFileStore } from "@/stores/file-store";
type CompressMode = "quality" | "targetSize"; type CompressMode = "quality" | "targetSize";
type SizeUnit = "KB" | "MB";
export interface CompressControlsProps { export interface CompressControlsProps {
settings?: Record<string, unknown>; settings?: Record<string, unknown>;
@@ -14,7 +15,8 @@ export interface CompressControlsProps {
export function CompressControls({ settings: initialSettings, onChange }: CompressControlsProps) { export function CompressControls({ settings: initialSettings, onChange }: CompressControlsProps) {
const [mode, setMode] = useState<CompressMode>("targetSize"); const [mode, setMode] = useState<CompressMode>("targetSize");
const [quality, setQuality] = useState(75); const [quality, setQuality] = useState(75);
const [targetSizeKb, setTargetSizeKb] = useState(""); const [targetSizeValue, setTargetSizeValue] = useState("");
const [sizeUnit, setSizeUnit] = useState<SizeUnit>("KB");
const initializedRef = useRef(false); const initializedRef = useRef(false);
useEffect(() => { useEffect(() => {
@@ -22,7 +24,8 @@ export function CompressControls({ settings: initialSettings, onChange }: Compre
initializedRef.current = true; initializedRef.current = true;
if (initialSettings.mode != null) setMode(initialSettings.mode as CompressMode); if (initialSettings.mode != null) setMode(initialSettings.mode as CompressMode);
if (initialSettings.quality != null) setQuality(Number(initialSettings.quality)); if (initialSettings.quality != null) setQuality(Number(initialSettings.quality));
if (initialSettings.targetSizeKb != null) setTargetSizeKb(String(initialSettings.targetSizeKb)); if (initialSettings.targetSizeKb != null)
setTargetSizeValue(String(initialSettings.targetSizeKb));
}, [initialSettings]); }, [initialSettings]);
const onChangeRef = useRef(onChange); const onChangeRef = useRef(onChange);
@@ -34,9 +37,11 @@ export function CompressControls({ settings: initialSettings, onChange }: Compre
if (mode === "quality") { if (mode === "quality") {
onChangeRef.current?.({ mode, quality }); onChangeRef.current?.({ mode, quality });
} else { } else {
onChangeRef.current?.({ mode, targetSizeKb: Number(targetSizeKb) }); const valueNum = Number(targetSizeValue);
const targetSizeKb = sizeUnit === "MB" ? valueNum * 1024 : valueNum;
onChangeRef.current?.({ mode, targetSizeKb });
} }
}, [mode, quality, targetSizeKb]); }, [mode, quality, targetSizeValue, sizeUnit]);
return ( return (
<div className="space-y-4"> <div className="space-y-4">
@@ -64,17 +69,27 @@ export function CompressControls({ settings: initialSettings, onChange }: Compre
{mode === "targetSize" ? ( {mode === "targetSize" ? (
<div> <div>
<label htmlFor="compress-target-size" className="text-xs text-muted-foreground"> <label htmlFor="compress-target-size" className="text-xs text-muted-foreground">
Target Size (KB) Target Size
</label> </label>
<div className="flex gap-1.5 mt-0.5">
<input <input
id="compress-target-size" id="compress-target-size"
type="number" type="number"
value={targetSizeKb} value={targetSizeValue}
onChange={(e) => setTargetSizeKb(e.target.value)} onChange={(e) => setTargetSizeValue(e.target.value)}
min={1} min={1}
placeholder="e.g. 200" placeholder={sizeUnit === "KB" ? "e.g. 200" : "e.g. 2"}
className="w-full mt-0.5 px-2 py-1.5 rounded border border-border bg-background text-sm text-foreground" className="flex-1 min-w-0 px-2 py-1.5 rounded border border-border bg-background text-sm text-foreground tabular-nums [appearance:textfield] [&::-webkit-inner-spin-button]:appearance-none [&::-webkit-outer-spin-button]:appearance-none"
/> />
<select
value={sizeUnit}
onChange={(e) => setSizeUnit(e.target.value as SizeUnit)}
className="px-2 py-1.5 rounded border border-border bg-background text-sm text-foreground"
>
<option value="KB">KB</option>
<option value="MB">MB</option>
</select>
</div>
</div> </div>
) : ( ) : (
<div> <div>
+5 -3
View File
@@ -123,7 +123,8 @@ function FileSelectionInfo({
})} })}
</div> </div>
{showToggle && ( <div className="flex items-center justify-between">
{showToggle ? (
<button <button
type="button" type="button"
onClick={() => setExpanded(!expanded)} onClick={() => setExpanded(!expanded)}
@@ -131,8 +132,9 @@ function FileSelectionInfo({
> >
{expanded ? "Show less" : `Show ${files.length - COLLAPSED_LIMIT} more`} {expanded ? "Show less" : `Show ${files.length - COLLAPSED_LIMIT} more`}
</button> </button>
) : (
<span />
)} )}
<button <button
type="button" type="button"
onClick={onClear} onClick={onClear}
@@ -141,6 +143,7 @@ function FileSelectionInfo({
Clear all Clear all
</button> </button>
</div> </div>
</div>
); );
} }
@@ -643,7 +646,6 @@ export function ToolPage() {
<> <>
{!isNoDropzone && ( {!isNoDropzone && (
<div className="space-y-2"> <div className="space-y-2">
<h3 className="text-sm font-medium text-muted-foreground">Files</h3>
<FileSelectionInfo <FileSelectionInfo
files={files} files={files}
selectedIndex={selectedIndex} selectedIndex={selectedIndex}