优化模版
This commit is contained in:
		
							parent
							
								
									c1c41300f2
								
							
						
					
					
						commit
						52ee91c20b
					
				| @ -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", | ||||
|  | ||||
| @ -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) | ||||
|  | ||||
| @ -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<Article[]>([]) | ||||
|   const [articleToDelete, setArticleToDelete] = useState<Article | null>(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,6 +141,7 @@ export function ArticleList({ onSelect, currentContent, onNew }: ArticleListProp | ||||
|   } | ||||
| 
 | ||||
|   return ( | ||||
|     <> | ||||
|       <Sheet> | ||||
|         <SheetTrigger asChild> | ||||
|           <Button variant="ghost" size="icon" className="relative"> | ||||
| @ -169,8 +190,8 @@ export function ArticleList({ onSelect, currentContent, onNew }: ArticleListProp | ||||
|                   <Button | ||||
|                     variant="ghost" | ||||
|                     size="icon" | ||||
|                   className="opacity-0 group-hover:opacity-100 transition-opacity" | ||||
|                   onClick={() => deleteArticle(article.id)} | ||||
|                     className="shrink-0 hover:bg-destructive/10 hover:text-destructive transition-colors" | ||||
|                     onClick={() => deleteArticle(article)} | ||||
|                   > | ||||
|                     <Trash2 className="h-4 w-4 text-destructive" /> | ||||
|                     <span className="sr-only">删除</span> | ||||
| @ -186,5 +207,23 @@ export function ArticleList({ onSelect, currentContent, onNew }: ArticleListProp | ||||
|           </ScrollArea> | ||||
|         </SheetContent> | ||||
|       </Sheet> | ||||
| 
 | ||||
|       <AlertDialog open={!!articleToDelete} onOpenChange={() => setArticleToDelete(null)}> | ||||
|         <AlertDialogContent> | ||||
|           <AlertDialogHeader> | ||||
|             <AlertDialogTitle>确认删除</AlertDialogTitle> | ||||
|             <AlertDialogDescription> | ||||
|               确定要删除文章"{articleToDelete?.title}"吗?此操作无法撤销。 | ||||
|             </AlertDialogDescription> | ||||
|           </AlertDialogHeader> | ||||
|           <AlertDialogFooter> | ||||
|             <AlertDialogCancel>取消</AlertDialogCancel> | ||||
|             <AlertDialogAction onClick={confirmDelete} className="bg-destructive text-destructive-foreground hover:bg-destructive/90"> | ||||
|               删除 | ||||
|             </AlertDialogAction> | ||||
|           </AlertDialogFooter> | ||||
|         </AlertDialogContent> | ||||
|       </AlertDialog> | ||||
|     </> | ||||
|   ) | ||||
| }  | ||||
| @ -117,13 +117,7 @@ export function EditorToolbar({ | ||||
|                 currentContent={value} | ||||
|                 onNew={onNewArticle} | ||||
|               /> | ||||
|               <button | ||||
|                 onClick={onNewArticle} | ||||
|                 className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-md text-sm transition-colors justify-center bg-muted text-muted-foreground hover:bg-muted/90" | ||||
|               > | ||||
|                 <Plus className="h-4 w-4" /> | ||||
|                 新建文章 | ||||
|               </button> | ||||
|              | ||||
|               <WechatStylePicker  | ||||
|                 value={selectedTemplate}  | ||||
|                 onSelect={onTemplateSelect}  | ||||
|  | ||||
							
								
								
									
										140
									
								
								src/components/ui/alert-dialog.tsx
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								src/components/ui/alert-dialog.tsx
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,140 @@ | ||||
| "use client" | ||||
| 
 | ||||
| import * as React from "react" | ||||
| import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog" | ||||
| 
 | ||||
| import { cn } from "@/lib/utils" | ||||
| import { buttonVariants } from "@/components/ui/button" | ||||
| 
 | ||||
| const AlertDialog = AlertDialogPrimitive.Root | ||||
| 
 | ||||
| const AlertDialogTrigger = AlertDialogPrimitive.Trigger | ||||
| 
 | ||||
| const AlertDialogPortal = AlertDialogPrimitive.Portal | ||||
| 
 | ||||
| const AlertDialogOverlay = React.forwardRef< | ||||
|   React.ElementRef<typeof AlertDialogPrimitive.Overlay>, | ||||
|   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay> | ||||
| >(({ className, ...props }, ref) => ( | ||||
|   <AlertDialogPrimitive.Overlay | ||||
|     className={cn( | ||||
|       "fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0", | ||||
|       className | ||||
|     )} | ||||
|     {...props} | ||||
|     ref={ref} | ||||
|   /> | ||||
| )) | ||||
| AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName | ||||
| 
 | ||||
| const AlertDialogContent = React.forwardRef< | ||||
|   React.ElementRef<typeof AlertDialogPrimitive.Content>, | ||||
|   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content> | ||||
| >(({ className, ...props }, ref) => ( | ||||
|   <AlertDialogPortal> | ||||
|     <AlertDialogOverlay /> | ||||
|     <AlertDialogPrimitive.Content | ||||
|       ref={ref} | ||||
|       className={cn( | ||||
|         "fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg", | ||||
|         className | ||||
|       )} | ||||
|       {...props} | ||||
|     /> | ||||
|   </AlertDialogPortal> | ||||
| )) | ||||
| AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName | ||||
| 
 | ||||
| const AlertDialogHeader = ({ | ||||
|   className, | ||||
|   ...props | ||||
| }: React.HTMLAttributes<HTMLDivElement>) => ( | ||||
|   <div | ||||
|     className={cn( | ||||
|       "flex flex-col space-y-2 text-center sm:text-left", | ||||
|       className | ||||
|     )} | ||||
|     {...props} | ||||
|   /> | ||||
| ) | ||||
| AlertDialogHeader.displayName = "AlertDialogHeader" | ||||
| 
 | ||||
| const AlertDialogFooter = ({ | ||||
|   className, | ||||
|   ...props | ||||
| }: React.HTMLAttributes<HTMLDivElement>) => ( | ||||
|   <div | ||||
|     className={cn( | ||||
|       "flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", | ||||
|       className | ||||
|     )} | ||||
|     {...props} | ||||
|   /> | ||||
| ) | ||||
| AlertDialogFooter.displayName = "AlertDialogFooter" | ||||
| 
 | ||||
| const AlertDialogTitle = React.forwardRef< | ||||
|   React.ElementRef<typeof AlertDialogPrimitive.Title>, | ||||
|   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title> | ||||
| >(({ className, ...props }, ref) => ( | ||||
|   <AlertDialogPrimitive.Title | ||||
|     ref={ref} | ||||
|     className={cn("text-lg font-semibold", className)} | ||||
|     {...props} | ||||
|   /> | ||||
| )) | ||||
| AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName | ||||
| 
 | ||||
| const AlertDialogDescription = React.forwardRef< | ||||
|   React.ElementRef<typeof AlertDialogPrimitive.Description>, | ||||
|   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description> | ||||
| >(({ className, ...props }, ref) => ( | ||||
|   <AlertDialogPrimitive.Description | ||||
|     ref={ref} | ||||
|     className={cn("text-sm text-muted-foreground", className)} | ||||
|     {...props} | ||||
|   /> | ||||
| )) | ||||
| AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName | ||||
| 
 | ||||
| const AlertDialogAction = React.forwardRef< | ||||
|   React.ElementRef<typeof AlertDialogPrimitive.Action>, | ||||
|   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action> | ||||
| >(({ className, ...props }, ref) => ( | ||||
|   <AlertDialogPrimitive.Action | ||||
|     ref={ref} | ||||
|     className={cn(buttonVariants(), className)} | ||||
|     {...props} | ||||
|   /> | ||||
| )) | ||||
| AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName | ||||
| 
 | ||||
| const AlertDialogCancel = React.forwardRef< | ||||
|   React.ElementRef<typeof AlertDialogPrimitive.Cancel>, | ||||
|   React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel> | ||||
| >(({ className, ...props }, ref) => ( | ||||
|   <AlertDialogPrimitive.Cancel | ||||
|     ref={ref} | ||||
|     className={cn( | ||||
|       buttonVariants({ variant: "outline" }), | ||||
|       "mt-2 sm:mt-0", | ||||
|       className | ||||
|     )} | ||||
|     {...props} | ||||
|   /> | ||||
| )) | ||||
| AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName | ||||
| 
 | ||||
| export { | ||||
|   AlertDialog, | ||||
|   AlertDialogPortal, | ||||
|   AlertDialogOverlay, | ||||
|   AlertDialogTrigger, | ||||
|   AlertDialogContent, | ||||
|   AlertDialogHeader, | ||||
|   AlertDialogFooter, | ||||
|   AlertDialogTitle, | ||||
|   AlertDialogDescription, | ||||
|   AlertDialogAction, | ||||
|   AlertDialogCancel, | ||||
| }  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 tianyaxiang
						tianyaxiang