diff --git a/package.json b/package.json index 019aa26..9b221bc 100644 --- a/package.json +++ b/package.json @@ -19,9 +19,11 @@ "clsx": "^2.1.1", "lucide-react": "^0.548.0", "nanoid": "^5.1.6", + "next-themes": "^0.4.6", "react": "^19.1.1", "react-dom": "^19.1.1", "react-router-dom": "^7.9.4", + "sonner": "^2.0.7", "tailwind-merge": "^3.3.1", "tailwindcss": "^4.1.16", "uuid": "^13.0.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bca26d2..b195b49 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -38,6 +38,9 @@ importers: nanoid: specifier: ^5.1.6 version: 5.1.6 + next-themes: + specifier: ^0.4.6 + version: 0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react: specifier: ^19.1.1 version: 19.2.0 @@ -47,6 +50,9 @@ importers: react-router-dom: specifier: ^7.9.4 version: 7.9.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + sonner: + specifier: ^2.0.7 + version: 2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0) tailwind-merge: specifier: ^3.3.1 version: 3.3.1 @@ -1280,6 +1286,12 @@ packages: natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + node-releases@2.0.26: resolution: {integrity: sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==} @@ -1472,6 +1484,12 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + 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-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} @@ -2702,6 +2720,11 @@ snapshots: natural-compare@1.4.0: {} + next-themes@0.4.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + node-releases@2.0.26: {} optionator@0.9.4: @@ -2854,6 +2877,11 @@ snapshots: shebang-regex@3.0.0: {} + sonner@2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + source-map-js@1.2.1: {} strip-json-comments@3.1.1: {} diff --git a/src/components/ui/sonner.tsx b/src/components/ui/sonner.tsx new file mode 100644 index 0000000..9f46e06 --- /dev/null +++ b/src/components/ui/sonner.tsx @@ -0,0 +1,38 @@ +import { + CircleCheckIcon, + InfoIcon, + Loader2Icon, + OctagonXIcon, + TriangleAlertIcon, +} from "lucide-react" +import { useTheme } from "next-themes" +import { Toaster as Sonner, type ToasterProps } from "sonner" + +const Toaster = ({ ...props }: ToasterProps) => { + const { theme = "system" } = useTheme() + + return ( + , + info: , + warning: , + error: , + loading: , + }} + style={ + { + "--normal-bg": "var(--popover)", + "--normal-text": "var(--popover-foreground)", + "--normal-border": "var(--border)", + "--border-radius": "var(--radius)", + } as React.CSSProperties + } + {...props} + /> + ) +} + +export { Toaster } diff --git a/src/main.tsx b/src/main.tsx index 72ea416..b5a9d99 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -1,10 +1,14 @@ import { StrictMode } from 'react' import { createRoot } from 'react-dom/client' + +import { Toaster } from '@/components/ui/sonner' + import './index.css' import { AppRouter } from './router' createRoot(document.getElementById('root')!).render( + )