From f44b837499d31ebbeb0f64f7de567f2f0a2fca38 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Apr 2026 04:09:40 +0000
Subject: [PATCH 1/2] chore: updated plan with multi-line input requirement
Agent-Logs-Url: https://github.com/slhmy/dev-tools-web/sessions/90663cc3-6968-45d9-b368-f90bd86a12ce
Co-authored-by: slhmy <31381093+slhmy@users.noreply.github.com>
---
package-lock.json | 11 +++++++++++
package.json | 1 +
2 files changed, 12 insertions(+)
diff --git a/package-lock.json b/package-lock.json
index 87a0e50..27425e9 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
"react-dom": "^19.2.4",
"react-router-dom": "^7.14.1",
"shadcn": "^4.2.0",
+ "sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"tailwindcss": "^4.2.1",
"tw-animate-css": "^1.4.0"
@@ -8323,6 +8324,16 @@
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==",
"license": "MIT"
},
+ "node_modules/sonner": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/sonner/-/sonner-2.0.7.tgz",
+ "integrity": "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==",
+ "license": "MIT",
+ "peerDependencies": {
+ "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc",
+ "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc"
+ }
+ },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
diff --git a/package.json b/package.json
index 06e4fb5..c828cce 100644
--- a/package.json
+++ b/package.json
@@ -22,6 +22,7 @@
"react-dom": "^19.2.4",
"react-router-dom": "^7.14.1",
"shadcn": "^4.2.0",
+ "sonner": "^2.0.7",
"tailwind-merge": "^3.5.0",
"tailwindcss": "^4.2.1",
"tw-animate-css": "^1.4.0"
From 68592ae7663ffc2b00eec771d364172c56e3c7eb Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Thu, 16 Apr 2026 04:12:33 +0000
Subject: [PATCH 2/2] feat: base64 error toast + multi-line input; multi-format
timestamp conversion
Agent-Logs-Url: https://github.com/slhmy/dev-tools-web/sessions/90663cc3-6968-45d9-b368-f90bd86a12ce
Co-authored-by: slhmy <31381093+slhmy@users.noreply.github.com>
---
src/App.tsx | 38 +++++-----
src/components/ui/textarea.tsx | 18 +++++
src/pages/base64.tsx | 23 +++---
src/pages/timestamp.tsx | 135 +++++++++++++++++++++------------
4 files changed, 138 insertions(+), 76 deletions(-)
create mode 100644 src/components/ui/textarea.tsx
diff --git a/src/App.tsx b/src/App.tsx
index 093c591..68bbbc5 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,4 +1,5 @@
import { BrowserRouter, Route, Routes } from "react-router-dom"
+import { Toaster } from "sonner"
import { AppSidebar } from "@/components/app-sidebar"
import {
@@ -12,23 +13,26 @@ import { TimestampPage } from "@/pages/timestamp"
export function App() {
return (
-
-
-
-
-
-
-
- } />
- } />
- } />
-
-
-
-
-
+ <>
+
+
+
+
+
+
+
+ } />
+ } />
+ } />
+
+
+
+
+
+
+ >
)
}
diff --git a/src/components/ui/textarea.tsx b/src/components/ui/textarea.tsx
new file mode 100644
index 0000000..13ebbee
--- /dev/null
+++ b/src/components/ui/textarea.tsx
@@ -0,0 +1,18 @@
+import * as React from "react"
+
+import { cn } from "@/lib/utils"
+
+function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
+ return (
+
+ )
+}
+
+export { Textarea }
diff --git a/src/pages/base64.tsx b/src/pages/base64.tsx
index c1980ac..97da8a2 100644
--- a/src/pages/base64.tsx
+++ b/src/pages/base64.tsx
@@ -1,21 +1,20 @@
import { useState } from "react"
+import { toast } from "sonner"
import { Button } from "@/components/ui/button"
-import { Input } from "@/components/ui/input"
+import { Textarea } from "@/components/ui/textarea"
export function Base64Page() {
const [input, setInput] = useState("")
const [output, setOutput] = useState("")
- const [error, setError] = useState("")
function encode() {
try {
const bytes = new TextEncoder().encode(input)
const binary = String.fromCharCode(...bytes)
setOutput(btoa(binary))
- setError("")
} catch {
- setError("Encoding failed. Make sure the input is valid text.")
+ toast.error("Encoding failed. Make sure the input is valid text.")
}
}
@@ -24,9 +23,8 @@ export function Base64Page() {
const binary = atob(input)
const bytes = Uint8Array.from(binary, (c) => c.charCodeAt(0))
setOutput(new TextDecoder().decode(bytes))
- setError("")
} catch {
- setError("Decoding failed. Make sure the input is valid Base64.")
+ toast.error("Decoding failed. Make sure the input is valid Base64.")
}
}
@@ -40,7 +38,8 @@ export function Base64Page() {
- setInput(e.target.value)}
placeholder="Enter text or Base64 string..."
@@ -52,13 +51,15 @@ export function Base64Page() {
- {error && {error}
}
{output && (
-
- {output}
-
+
{tsError && {tsError}
}
- {tsResult && (
-
-
- {tsResult}
-
-
-
- )}
+ {tsResult && }
{/* Date → Timestamp */}
@@ -100,21 +121,39 @@ export function TimestampPage() {
{dateError && {dateError}
}
- {dateResult && (
-
-
- {dateResult}
-
-
-
- )}
+ {dateResult && }
)
}
+
+function TimestampResultTable({ result }: { result: TimestampFormats }) {
+ const rows: { label: string; value: string }[] = [
+ { label: "ISO 8601", value: result.iso },
+ { label: "Unix (s)", value: result.unix },
+ { label: "Unix Milli (ms)", value: result.unixMilli },
+ { label: "Unix Nano (ns)", value: result.unixNano },
+ ]
+
+ return (
+
+ {rows.map(({ label, value }) => (
+
+
+ {label}
+
+
+ {value}
+
+
+
+ ))}
+
+ )
+}