From e815f4ebd29d518e4ee1e541ad013c4ba4468e2a Mon Sep 17 00:00:00 2001 From: anuphilipp3 Date: Fri, 21 Aug 2026 19:15:53 +0530 Subject: [PATCH] feat(converters): migrate all 15 Converters onto the shared tool kit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Phase 2 of the tool-consistency pass. Every Converter now renders through ToolShell + IOPanel/ToolTextArea (IO-style) or ToolShell + kit-surface panels (form-style), instead of hand-rolled Cards + raw textareas — so they share one visual language with the Formatters and base64. IO-style (input → output): url-encode, escape-encode, url-parser, string-inspector, string-case-converter, line-sort-dedupe, image-to-base64, token-counter (base64 was already migrated in Phase 0) Form-style (fields → computed result): number-base-converter, timestamp-converter, unit-converter, chmod-calculator, csv-excel-json, timezone-converter Also: IOPanel now omits its header row when a panel has neither label nor actions (avoids an empty header strip; string-inspector's results panel). Logic preserved (state, handlers, useMemo, i18n, drag-drop, file upload, mode toggles). 0 type errors; all 15 pages render. Co-Authored-By: Claude Opus 4.8 --- .../chmod-calculator-layout.tsx | 32 +-- .../csv-excel-json/csv-excel-json-tool.tsx | 242 +++++++++--------- .../escape-encode/escape-encode-layout.tsx | 177 ++++++------- .../image-to-base64-layout.tsx | 183 ++++++------- .../line-sort-dedupe-layout.tsx | 162 ++++++------ .../number-base-converter-layout.tsx | 173 +++++++------ .../string-case-converter-layout.tsx | 72 ++---- .../string-inspector-layout.tsx | 68 ++--- .../timestamp-converter-layout.tsx | 107 ++++---- .../timezone-converter-layout.tsx | 40 ++- .../token-counter/token-counter-layout.tsx | 123 +++++---- .../src/components/tools/io-panel.tsx | 16 +- .../unit-converter/unit-converter-layout.tsx | 100 ++++---- .../url-encode/url-encode-layout.tsx | 170 +++++------- .../url-parser/url-parser-layout.tsx | 170 ++++++------ 15 files changed, 826 insertions(+), 1009 deletions(-) diff --git a/apps/desktop-ui/src/components/chmod-calculator/chmod-calculator-layout.tsx b/apps/desktop-ui/src/components/chmod-calculator/chmod-calculator-layout.tsx index 4ac72c46..6c8c0c14 100644 --- a/apps/desktop-ui/src/components/chmod-calculator/chmod-calculator-layout.tsx +++ b/apps/desktop-ui/src/components/chmod-calculator/chmod-calculator-layout.tsx @@ -4,15 +4,12 @@ import React, { useCallback, useState } from 'react' import { useTranslations } from 'next-intl' import { useCopyToClipboard } from '@/hooks/use-copy-to-clipboard' import { Button } from '@/components/ui/button' -import { Card } from '@/components/ui/card' import { Checkbox } from '@/components/ui/checkbox' import { Input } from '@/components/ui/input' import { Label } from '@/components/ui/label' import { Check, Copy, SquareTerminal } from 'lucide-react' import { IconLockAccess } from '@tabler/icons-react' -import { ToolPageHeader } from '@/components/tools/tool-page-header' -import { RevealItem } from '@/components/dashboard/dashboard-reveal' -import { CATEGORY_ACCENT } from '@/components/dashboard/types' +import { ToolShell } from '@/components/tools/tool-shell' import { CHMOD_PRESETS, PERMISSION_CLASSES, @@ -82,22 +79,11 @@ export function ChmodCalculatorLayout() { } return ( -
-
- - - - - +
{/* Checkbox grid */} - +
@@ -174,11 +160,11 @@ export function ChmodCalculatorLayout() { {!symbolicValid &&

{t('symbolic.invalid')}

}
- +
{/* Output */} - +
- +
{/* Presets */} - +
@@ -239,10 +225,10 @@ export function ChmodCalculatorLayout() {
-
+
- + ) } diff --git a/apps/desktop-ui/src/components/csv-excel-json/csv-excel-json-tool.tsx b/apps/desktop-ui/src/components/csv-excel-json/csv-excel-json-tool.tsx index 091ee925..509b4dd7 100644 --- a/apps/desktop-ui/src/components/csv-excel-json/csv-excel-json-tool.tsx +++ b/apps/desktop-ui/src/components/csv-excel-json/csv-excel-json-tool.tsx @@ -13,14 +13,10 @@ import { IconUpload, } from "@tabler/icons-react"; import { toast } from "sonner"; -import { Card, CardContent } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; -import { Textarea } from "@/components/ui/textarea"; -import { Label } from "@/components/ui/label"; import { ToolPinButton } from "@/components/tools/tool-header"; -import { ToolPageHeader } from "@/components/tools/tool-page-header"; -import { RevealItem } from "@/components/dashboard/dashboard-reveal"; -import { CATEGORY_ACCENT } from "@/components/dashboard/types"; +import { ToolShell } from "@/components/tools/tool-shell"; +import { IOPanel, ToolTextArea } from "@/components/tools/io-panel"; import { useToolUsage } from "@/hooks/use-tool-usage"; import { cn } from "@/lib/utils"; import { @@ -152,143 +148,141 @@ export function CsvExcelJsonTool() { }; return ( -
-
- - -
- +
-
- - - -
{ - if (e.key === "Enter" || e.key === " ") { - e.preventDefault(); - fileRef.current?.click(); - } - }} - onDragEnter={(e) => { - e.preventDefault(); - setDragOver(true); - }} - onDragLeave={(e) => { + } + contentClassName="overflow-auto" + > +
+
{ + if (e.key === "Enter" || e.key === " ") { e.preventDefault(); - setDragOver(false); + fileRef.current?.click(); + } + }} + onDragEnter={(e) => { + e.preventDefault(); + setDragOver(true); + }} + onDragLeave={(e) => { + e.preventDefault(); + setDragOver(false); + }} + onDragOver={(e) => e.preventDefault()} + onDrop={onDrop} + className={cn( + "rounded-xl border-2 border-dashed p-8 text-center transition-colors", + dragOver + ? "border-primary bg-primary/5" + : "border-muted-foreground/25 bg-muted/20" + )} + > + +

{t("dropTitle")}

+

{t("dropHint")}

+ { + const f = e.target.files?.[0]; + if (f) void handleFile(f); + e.target.value = ""; }} - onDragOver={(e) => e.preventDefault()} - onDrop={onDrop} - className={cn( - "rounded-xl border-2 border-dashed p-8 text-center transition-colors", - dragOver - ? "border-primary bg-primary/5" - : "border-muted-foreground/25 bg-muted/20" - )} + /> + +
+ + fileRef.current?.click()} + variant="ghost" + size="sm" + className="h-7 text-xs" + onClick={loadSample} > - - {t("chooseFile")} + {t("loadSample")} -
- -
-
- - -
-