From 52ee91c20b87556005b6c18107edefb5ddab9190 Mon Sep 17 00:00:00 2001 From: tianyaxiang Date: Sat, 1 Feb 2025 16:05:06 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=E6=A8=A1=E7=89=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 1 + pnpm-lock.yaml | 30 +++ src/components/editor/ArticleList.tsx | 173 +++++++++++------- .../editor/components/EditorToolbar.tsx | 8 +- src/components/ui/alert-dialog.tsx | 140 ++++++++++++++ 5 files changed, 278 insertions(+), 74 deletions(-) create mode 100644 src/components/ui/alert-dialog.tsx diff --git a/package.json b/package.json index 49bd30a..7b53c0d 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@radix-ui/react-alert-dialog": "^1.1.5", "@radix-ui/react-dialog": "^1.1.5", "@radix-ui/react-dropdown-menu": "^2.1.5", "@radix-ui/react-label": "^2.1.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bf1a238..fff5f1d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,9 @@ importers: .: dependencies: + '@radix-ui/react-alert-dialog': + specifier: ^1.1.5 + version: 1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) '@radix-ui/react-dialog': specifier: ^1.1.5 version: 1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) @@ -247,6 +250,19 @@ packages: '@radix-ui/primitive@1.1.1': resolution: {integrity: sha512-SJ31y+Q/zAyShtXJc8x83i9TYdbAfHZ++tUZnvjJJqFjzsdUnKsxPL6IEtBlxKkU7yzer//GQtZSV4GbldL3YA==} + '@radix-ui/react-alert-dialog@1.1.5': + resolution: {integrity: sha512-1Y2sI17QzSZP58RjGtrklfSGIf3AF7U/HkD3aAcAnhOUJrm7+7GG1wRDFaUlSe0nW5B/t4mYd/+7RNbP2Wexug==} + 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-arrow@1.1.1': resolution: {integrity: sha512-NaVpZfmv8SKeZbn4ijN2V3jlHA9ngBG16VnIIm22nUR0Yk8KUALyBxT3KYEUnNuch9sTE8UTsS3whzBgKOL30w==} peerDependencies: @@ -1807,6 +1823,20 @@ snapshots: '@radix-ui/primitive@1.1.1': {} + '@radix-ui/react-alert-dialog@1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + dependencies: + '@radix-ui/primitive': 1.1.1 + '@radix-ui/react-compose-refs': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-context': 1.1.1(@types/react@18.3.18)(react@18.3.1) + '@radix-ui/react-dialog': 1.1.5(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) + '@radix-ui/react-slot': 1.1.1(@types/react@18.3.18)(react@18.3.1) + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.18 + '@types/react-dom': 18.3.5(@types/react@18.3.18) + '@radix-ui/react-arrow@1.1.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': dependencies: '@radix-ui/react-primitive': 2.0.1(@types/react-dom@18.3.5(@types/react@18.3.18))(@types/react@18.3.18)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) diff --git a/src/components/editor/ArticleList.tsx b/src/components/editor/ArticleList.tsx index 8881e75..acc4de4 100644 --- a/src/components/editor/ArticleList.tsx +++ b/src/components/editor/ArticleList.tsx @@ -11,6 +11,17 @@ import { SheetTitle, SheetTrigger, } from '@/components/ui/sheet' +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@/components/ui/alert-dialog" import { ScrollArea } from '@/components/ui/scroll-area' import { FileText, Trash2, Menu, Plus, Save } from 'lucide-react' import { useToast } from '@/components/ui/use-toast' @@ -34,6 +45,7 @@ interface ArticleListProps { export function ArticleList({ onSelect, currentContent, onNew }: ArticleListProps) { const { toast } = useToast() const [articles, setArticles] = useState([]) + const [articleToDelete, setArticleToDelete] = useState
(null) // 加载文章列表 useEffect(() => { @@ -82,14 +94,22 @@ export function ArticleList({ onSelect, currentContent, onNew }: ArticleListProp } // 删除文章 - const deleteArticle = (id: string) => { - const updatedArticles = articles.filter(article => article.id !== id) + const deleteArticle = (article: Article) => { + setArticleToDelete(article) + } + + // 确认删除文章 + const confirmDelete = () => { + if (!articleToDelete) return + + const updatedArticles = articles.filter(article => article.id !== articleToDelete.id) setArticles(updatedArticles) localStorage.setItem('wechat_articles', JSON.stringify(updatedArticles)) + setArticleToDelete(null) toast({ title: "删除成功", - description: "文章已删除", + description: `文章"${articleToDelete.title}"已删除`, duration: 2000 }) } @@ -121,70 +141,89 @@ export function ArticleList({ onSelect, currentContent, onNew }: ArticleListProp } return ( - - - - - - - 文章列表 - - - - - - -
- {articles.map(article => ( -
- - -
- ))} - {articles.length === 0 && ( -
- 暂无保存的文章 -
+ <> + + +
-
-
-
+ + + + + 文章列表 + + + + + + +
+ {articles.map(article => ( +
+ + +
+ ))} + {articles.length === 0 && ( +
+ 暂无保存的文章 +
+ )} +
+
+
+ + + setArticleToDelete(null)}> + + + 确认删除 + + 确定要删除文章"{articleToDelete?.title}"吗?此操作无法撤销。 + + + + 取消 + + 删除 + + + + + ) } \ No newline at end of file diff --git a/src/components/editor/components/EditorToolbar.tsx b/src/components/editor/components/EditorToolbar.tsx index 30be352..1d49ed2 100644 --- a/src/components/editor/components/EditorToolbar.tsx +++ b/src/components/editor/components/EditorToolbar.tsx @@ -117,13 +117,7 @@ export function EditorToolbar({ currentContent={value} onNew={onNewArticle} /> - + , + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName + +const AlertDialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + +)) +AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName + +const AlertDialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +AlertDialogHeader.displayName = "AlertDialogHeader" + +const AlertDialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+) +AlertDialogFooter.displayName = "AlertDialogFooter" + +const AlertDialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName + +const AlertDialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName + +const AlertDialogAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName + +const AlertDialogCancel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +} \ No newline at end of file