diff --git a/package.json b/package.json index 56461f78d..088deb953 100644 --- a/package.json +++ b/package.json @@ -43,7 +43,6 @@ "@octokit/graphql": "^9.0.3", "@radix-ui/react-dialog": "^1.1.15", "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-toast": "^1.2.15", "@radix-ui/react-tooltip": "^1.2.8", "@react-three/drei": "^10.7.7", "@react-three/fiber": "^9.5.0", @@ -110,6 +109,7 @@ "react-instantsearch": "^7.29.0", "remove-markdown": "^0.6.3", "resend": "^6.10.0", + "sonner": "^2.0.7", "streamdown": "^2.5.0", "tailwind-merge": "^3.5.0", "tar-stream": "^3.1.8", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d935d005a..8d2a7cb49 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -45,9 +45,6 @@ importers: '@radix-ui/react-dropdown-menu': specifier: ^2.1.16 version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-toast': - specifier: ^1.2.15 - version: 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-tooltip': specifier: ^1.2.8 version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -246,6 +243,9 @@ importers: resend: specifier: ^6.10.0 version: 6.10.0 + sonner: + specifier: ^2.0.7 + version: 2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3) streamdown: specifier: ^2.5.0 version: 2.5.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -2569,19 +2569,6 @@ packages: '@types/react': optional: true - '@radix-ui/react-toast@1.2.15': - resolution: {integrity: sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-tooltip@1.2.8': resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} peerDependencies: @@ -6402,6 +6389,12 @@ packages: solid-js@1.9.12: resolution: {integrity: sha512-QzKaSJq2/iDrWR1As6MHZQ8fQkdOBf8GReYb7L5iKwMGceg7HxDcaOHk0at66tNgn9U2U7dXo8ZZpLIAmGMzgw==} + sonner@2.0.7: + resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + source-map-explorer@2.5.3: resolution: {integrity: sha512-qfUGs7UHsOBE5p/lGfQdaAj/5U/GWYBw2imEpD6UQNkqElYonkow8t+HBL1qqIl3CuGZx7n8/CQo4x1HwSHhsg==} engines: {node: '>=12'} @@ -8926,26 +8919,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.14 - '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.14)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.14)(react@19.2.3) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.14)(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.14)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.14)(react@19.2.3) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.14 - '@types/react-dom': 19.2.3(@types/react@19.2.14) - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.14))(@types/react@19.2.14)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -13369,6 +13342,11 @@ snapshots: seroval: 1.5.4 seroval-plugins: 1.5.4(seroval@1.5.4) + sonner@2.0.7(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + source-map-explorer@2.5.3: dependencies: btoa: 1.2.1 diff --git a/src/components/ToastProvider.tsx b/src/components/ToastProvider.tsx index e34d4889e..e61cde9ce 100644 --- a/src/components/ToastProvider.tsx +++ b/src/components/ToastProvider.tsx @@ -1,16 +1,11 @@ import * as React from 'react' -import * as Toast from '@radix-ui/react-toast' +import { Toaster, toast } from 'sonner' +import { useTheme } from '~/components/ThemeProvider' type ToastOptions = { durationMs?: number } -type ToastItem = { - id: string - content: React.ReactNode - durationMs: number -} - type ToastContextValue = { notify: (content: React.ReactNode, options?: ToastOptions) => string } @@ -30,22 +25,16 @@ export function ToastProvider({ }: { children: React.ReactNode }): React.ReactElement { - const [toasts, setToasts] = React.useState([]) + const { resolvedTheme } = useTheme() const notify = React.useCallback( (content: React.ReactNode, options?: ToastOptions) => { - const id = Math.random().toString(36).slice(2) - const durationMs = options?.durationMs ?? 2500 - setToasts((prev) => [...prev, { id, content, durationMs }]) - return id + const id = toast(content, { duration: options?.durationMs ?? 2500 }) + return String(id) }, [], ) - const removeToast = React.useCallback((id: string) => { - setToasts((prev) => prev.filter((t) => t.id !== id)) - }, []) - const contextValue = React.useMemo( () => ({ notify }), [notify], @@ -53,23 +42,22 @@ export function ToastProvider({ return ( - - {children} - {toasts.map((t) => ( - { - if (!open) removeToast(t.id) - }} - className="relative z-[60] rounded-md border border-gray-200 bg-white px-3 py-2 text-sm text-gray-900 shadow-lg outline-none dark:border-gray-700 dark:bg-gray-800 dark:text-gray-50" - > -
{t.content}
-
- ))} - -
+ {children} +
) }