feat: add Sonner Toaster component and update dependencies

- Introduced a new Toaster component using Sonner for notifications.
- Integrated Toaster into the main application layout.
- Added 'next-themes' and 'sonner' dependencies in package.json and updated pnpm-lock.yaml.
This commit is contained in:
typist
2025-10-28 03:42:31 +08:00
parent 9009b9a1c6
commit 1bc10d5272
4 changed files with 72 additions and 0 deletions

View File

@@ -19,9 +19,11 @@
"clsx": "^2.1.1", "clsx": "^2.1.1",
"lucide-react": "^0.548.0", "lucide-react": "^0.548.0",
"nanoid": "^5.1.6", "nanoid": "^5.1.6",
"next-themes": "^0.4.6",
"react": "^19.1.1", "react": "^19.1.1",
"react-dom": "^19.1.1", "react-dom": "^19.1.1",
"react-router-dom": "^7.9.4", "react-router-dom": "^7.9.4",
"sonner": "^2.0.7",
"tailwind-merge": "^3.3.1", "tailwind-merge": "^3.3.1",
"tailwindcss": "^4.1.16", "tailwindcss": "^4.1.16",
"uuid": "^13.0.0" "uuid": "^13.0.0"

28
pnpm-lock.yaml generated
View File

@@ -38,6 +38,9 @@ importers:
nanoid: nanoid:
specifier: ^5.1.6 specifier: ^5.1.6
version: 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: react:
specifier: ^19.1.1 specifier: ^19.1.1
version: 19.2.0 version: 19.2.0
@@ -47,6 +50,9 @@ importers:
react-router-dom: react-router-dom:
specifier: ^7.9.4 specifier: ^7.9.4
version: 7.9.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) 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: tailwind-merge:
specifier: ^3.3.1 specifier: ^3.3.1
version: 3.3.1 version: 3.3.1
@@ -1280,6 +1286,12 @@ packages:
natural-compare@1.4.0: natural-compare@1.4.0:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} 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: node-releases@2.0.26:
resolution: {integrity: sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==} resolution: {integrity: sha512-S2M9YimhSjBSvYnlr5/+umAnPHE++ODwt5e2Ij6FoX45HA/s4vHdkDx1eax2pAPeAOqu4s9b7ppahsyEFdVqQA==}
@@ -1472,6 +1484,12 @@ packages:
resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
engines: {node: '>=8'} 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: source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'} engines: {node: '>=0.10.0'}
@@ -2702,6 +2720,11 @@ snapshots:
natural-compare@1.4.0: {} 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: {} node-releases@2.0.26: {}
optionator@0.9.4: optionator@0.9.4:
@@ -2854,6 +2877,11 @@ snapshots:
shebang-regex@3.0.0: {} 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: {} source-map-js@1.2.1: {}
strip-json-comments@3.1.1: {} strip-json-comments@3.1.1: {}

View File

@@ -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 (
<Sonner
theme={theme as ToasterProps["theme"]}
className="toaster group"
icons={{
success: <CircleCheckIcon className="size-4" />,
info: <InfoIcon className="size-4" />,
warning: <TriangleAlertIcon className="size-4" />,
error: <OctagonXIcon className="size-4" />,
loading: <Loader2Icon className="size-4 animate-spin" />,
}}
style={
{
"--normal-bg": "var(--popover)",
"--normal-text": "var(--popover-foreground)",
"--normal-border": "var(--border)",
"--border-radius": "var(--radius)",
} as React.CSSProperties
}
{...props}
/>
)
}
export { Toaster }

View File

@@ -1,10 +1,14 @@
import { StrictMode } from 'react' import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client' import { createRoot } from 'react-dom/client'
import { Toaster } from '@/components/ui/sonner'
import './index.css' import './index.css'
import { AppRouter } from './router' import { AppRouter } from './router'
createRoot(document.getElementById('root')!).render( createRoot(document.getElementById('root')!).render(
<StrictMode> <StrictMode>
<AppRouter /> <AppRouter />
<Toaster />
</StrictMode> </StrictMode>
) )