From 068e3e369353375f07845309d78684094f896444 Mon Sep 17 00:00:00 2001 From: Sven Reiser Date: Sun, 21 Jun 2026 12:54:58 +0200 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20replace=20native=20alert()?= =?UTF-8?q?=20error=20popups=20with=20@mind-studio/ui=20Toaster?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Swaps 8 browser alert() calls in DriveBrowser and FilePreview for themed toast.error notifications, and renders at the app root. Co-Authored-By: Claude Opus 4.8 (1M context) --- package-lock.json | 3 ++- package.json | 3 ++- src/app/layout.tsx | 3 ++- src/components/DriveBrowser.tsx | 13 +++++++------ src/components/FilePreview.tsx | 5 +++-- 5 files changed, 16 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3f84098..929b000 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,7 +16,8 @@ "lucide-react": "^0.460.0", "next": "16.2.6", "react": "19.2.4", - "react-dom": "19.2.4" + "react-dom": "19.2.4", + "sonner": "^2.0.7" }, "devDependencies": { "@biomejs/biome": "^2.5.0", diff --git a/package.json b/package.json index b8cde33..8c9ee43 100644 --- a/package.json +++ b/package.json @@ -24,7 +24,8 @@ "lucide-react": "^0.460.0", "next": "16.2.6", "react": "19.2.4", - "react-dom": "19.2.4" + "react-dom": "19.2.4", + "sonner": "^2.0.7" }, "devDependencies": { "@biomejs/biome": "^2.5.0", diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 7953118..b785948 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,4 +1,4 @@ -import { Button, ThemeProvider } from "@mind-studio/ui"; +import { Button, ThemeProvider, Toaster } from "@mind-studio/ui"; import { mind } from "@mind-studio/ui/themes"; import type { Metadata } from "next"; import { Fraunces, Hanken_Grotesk, JetBrains_Mono } from "next/font/google"; @@ -56,6 +56,7 @@ export default function RootLayout({ children }: Readonly<{ children: React.Reac + diff --git a/src/components/DriveBrowser.tsx b/src/components/DriveBrowser.tsx index 1ebc8af..56465fc 100644 --- a/src/components/DriveBrowser.tsx +++ b/src/components/DriveBrowser.tsx @@ -15,6 +15,7 @@ import { import Link from "next/link"; import { useRouter } from "next/navigation"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { toast } from "sonner"; import { ConfirmDialog } from "@/components/ConfirmDialog"; import PassphraseDialog from "@/components/PassphraseDialog"; import { ImageThumbnail, isImageName } from "@/components/Thumbnail"; @@ -462,7 +463,7 @@ function Toolbar({ setCreatingFolder(false); onChanged(); } catch (err) { - alert(`Failed to create folder: ${String(err)}`); + toast.error(`Failed to create folder: ${String(err)}`); } finally { setBusy(false); } @@ -725,7 +726,7 @@ function Tile({ } onChanged(); } catch (err) { - alert(`Delete failed: ${String(err)}`); + toast.error(`Delete failed: ${String(err)}`); } finally { setBusy(false); } @@ -822,7 +823,7 @@ function Row({ } onChanged(); } catch (err) { - alert(`Delete failed: ${String(err)}`); + toast.error(`Delete failed: ${String(err)}`); } finally { setBusy(false); } @@ -843,7 +844,7 @@ function Row({ a.remove(); setTimeout(() => URL.revokeObjectURL(url), 1000); } catch (err) { - alert(`Download failed: ${String(err)}`); + toast.error(`Download failed: ${String(err)}`); } finally { setBusy(false); } @@ -858,7 +859,7 @@ function Row({ return; } if (entry.kind === "container") { - alert("Container rename is not supported in M2 — copy/recreate manually."); + toast.error("Container rename is not supported in M2 — copy/recreate manually."); setRenaming(false); return; } @@ -870,7 +871,7 @@ function Row({ setRenaming(false); onChanged(); } catch (err) { - alert(`Rename failed: ${String(err)}`); + toast.error(`Rename failed: ${String(err)}`); } finally { setBusy(false); } diff --git a/src/components/FilePreview.tsx b/src/components/FilePreview.tsx index 06a3efa..81cc4be 100644 --- a/src/components/FilePreview.tsx +++ b/src/components/FilePreview.tsx @@ -5,6 +5,7 @@ import { ArrowLeft, Download, Pencil, Share2, Trash2 } from "lucide-react"; import Link from "next/link"; import { useRouter } from "next/navigation"; import { useCallback, useEffect, useMemo, useState } from "react"; +import { toast } from "sonner"; import { ConfirmDialog } from "@/components/ConfirmDialog"; import PassphraseDialog from "@/components/PassphraseDialog"; import ShareDialog from "@/components/ShareDialog"; @@ -299,7 +300,7 @@ function Header({ : "/drive/" + parentSegments.map(normalizeSegment).join("/"); router.replace(parentHref); } catch (e) { - alert(`Delete failed: ${String(e)}`); + toast.error(`Delete failed: ${String(e)}`); setBusy(false); } } @@ -323,7 +324,7 @@ function Header({ [...parentSegments.map(normalizeSegment), encodeURIComponent(trimmed)].join("/"); router.replace(href); } catch (err) { - alert(`Rename failed: ${String(err)}`); + toast.error(`Rename failed: ${String(err)}`); setBusy(false); } }