diff --git a/src/features/base64/Base64Page.tsx b/src/features/base64/Base64Page.tsx index 763976d..0528be2 100644 --- a/src/features/base64/Base64Page.tsx +++ b/src/features/base64/Base64Page.tsx @@ -1,66 +1,168 @@ -import type { JSX } from "react"; +import type { JSX, ReactNode } from "react"; import { useMemo, useState } from "react"; -import { ArrowLeftRight, Copy, RotateCcw } from "lucide-react"; +import { + ArrowLeftRight, + CheckCircle2, + Copy, + Download, + FileCode2, + RotateCcw, + TextCursorInput, + ToggleLeft, + ToggleRight, + TriangleAlert, +} from "lucide-react"; +import { cn } from "@/shared/lib/cn"; import { Button } from "@/shared/ui/button"; import { Tooltip } from "@/shared/ui/tooltip"; +import { PaneHeader, ToolSurface, ToolToolbar } from "@/shared/components/ToolSurface"; import { - PaneHeader, - ToolOutput, - ToolSurface, - ToolTextarea, - ToolToolbar, - ToolTitle, -} from "@/shared/components/ToolSurface"; -import { decodeBase64, encodeBase64 } from "./base64.service"; + detectBase64Variant, + transformBase64, + type Base64Mode, + type Base64Result, + type Base64TextEncoding, + type Base64Variant, +} from "./base64.service"; -export function Base64Page(): JSX.Element { - const [mode, setMode] = useState<"encode" | "decode">("encode"); - const [input, setInput] = useState("Forge developer workstation"); - const result = useMemo(() => { - if (mode === "encode") { - return { value: encodeBase64(input) }; - } +const sampleText = `Forge developer workstation +Local-first tools, polished workflows, and UTF-8 text. +Symbols: / ? & = + - _ Vietnamese: Xin chao Forge`; - return decodeBase64(input); - }, [input, mode]); +export function Base64Page(): JSX.Element { + const [mode, setMode] = useState("encode"); + const [input, setInput] = useState(sampleText); + const [variant, setVariant] = useState("standard"); + const [padding, setPadding] = useState(true); + const [lineWrap, setLineWrap] = useState(false); + const [textEncoding, setTextEncoding] = useState("utf-8"); + const result = useMemo( + () => + transformBase64(input, mode, { + lineWrap, + padding, + textEncoding, + variant, + }), + [input, lineWrap, mode, padding, textEncoding, variant], + ); function swapMode(): void { - setMode((value) => (value === "encode" ? "decode" : "encode")); - setInput(result.value); + setMode((current) => (current === "encode" ? "decode" : "encode")); + if (result.value) { + setInput(result.value); + if (mode === "encode") { + setVariant(detectBase64Variant(result.value)); + } + } } async function copyOutput(): Promise { await navigator.clipboard.writeText(result.value); } + function downloadOutput(): void { + const blob = new Blob([result.value], { type: "text/plain;charset=utf-8" }); + const url = URL.createObjectURL(blob); + const anchor = document.createElement("a"); + + anchor.href = url; + anchor.download = mode === "encode" ? "forge-base64.txt" : "forge-decoded.txt"; + anchor.click(); + URL.revokeObjectURL(url); + } + return ( - - - +
+