@@ -75,15 +85,41 @@ export default function Home() {
>
- {/* 桌面端布局 */}
-
-
-
-
+
+ {/* 桌面端布局 */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
{/* 移动端布局 */}
-
+
{isPreviewMode ? (
void;
}
+interface DeleteConfirmDialogProps {
+ projectName: string;
+ onDelete: () => void;
+}
+
+const DeleteConfirmDialog: React.FC = ({
+ projectName,
+ onDelete
+}) => {
+ const theme = useResumeStore((state) => state.theme);
+
+ return (
+
+
+
+
+ e.stopPropagation()} // 添加这行
+ >
+
+
+ 确认删除项目
+
+
+ 您确定要删除项目 {projectName} 吗?此操作无法撤销。
+
+
+
+
+ 取消
+
+ void }) => {
+ e.preventDefault();
+ onDelete();
+ }}
+ className={cn(
+ theme === "dark"
+ ? "bg-red-600 hover:bg-red-700 text-white"
+ : "bg-red-600 hover:bg-red-700 text-white"
+ )}
+ >
+ 删除
+
+
+
+
+ );
+};
+
const ProjectEditor: React.FC = ({
project,
onSave,
@@ -86,23 +187,11 @@ const ProjectEditor: React.FC = ({
);
};
-// ProjectEditor 组件用于编辑单个项目
-interface Project {
- id: string;
- name: string;
- role: string;
- date: string;
- description: string;
- technologies: string;
- responsibilities: string;
- achievements: string;
-}
-
const ProjectItem = ({ project }: { project: Project }) => {
const dragControls = useDragControls();
const [expandedId, setExpandedId] = useState(null);
-
const { theme, updateProjects, deleteProject } = useResumeStore();
+
return (
{
-
+ />
,
+ 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,
+}
diff --git a/apps/fronted/src/components/ui/button.tsx b/apps/fronted/src/components/ui/button.tsx
index 6ecff44..36496a2 100644
--- a/apps/fronted/src/components/ui/button.tsx
+++ b/apps/fronted/src/components/ui/button.tsx
@@ -1,11 +1,11 @@
-import * as React from "react";
-import { Slot } from "@radix-ui/react-slot";
-import { cva, type VariantProps } from "class-variance-authority";
+import * as React from "react"
+import { Slot } from "@radix-ui/react-slot"
+import { cva, type VariantProps } from "class-variance-authority"
-import { cn } from "@/lib/utils";
+import { cn } from "@/lib/utils"
const buttonVariants = cva(
- "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
{
variants: {
variant: {
@@ -17,40 +17,40 @@ const buttonVariants = cva(
secondary:
"bg-secondary text-secondary-foreground hover:bg-secondary/80",
ghost: "hover:bg-accent hover:text-accent-foreground",
- link: "text-primary underline-offset-4 hover:underline"
+ link: "text-primary underline-offset-4 hover:underline",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-9 rounded-md px-3",
lg: "h-11 rounded-md px-8",
- icon: "h-10 w-10"
- }
+ icon: "h-10 w-10",
+ },
},
defaultVariants: {
variant: "default",
- size: "default"
- }
+ size: "default",
+ },
}
-);
+)
export interface ButtonProps
extends React.ButtonHTMLAttributes,
VariantProps {
- asChild?: boolean;
+ asChild?: boolean
}
const Button = React.forwardRef(
({ className, variant, size, asChild = false, ...props }, ref) => {
- const Comp = asChild ? Slot : "button";
+ const Comp = asChild ? Slot : "button"
return (
- );
+ )
}
-);
-Button.displayName = "Button";
+)
+Button.displayName = "Button"
-export { Button, buttonVariants };
+export { Button, buttonVariants }
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index a3817dc..7d9a41d 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -95,6 +95,9 @@ importers:
'@radix-ui/react-accordion':
specifier: ^1.2.1
version: 1.2.1(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1)
+ '@radix-ui/react-alert-dialog':
+ specifier: ^1.1.2
+ version: 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1)
'@radix-ui/react-label':
specifier: ^2.1.0
version: 2.1.0(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1)
@@ -1473,6 +1476,31 @@ packages:
react-dom: 18.3.1(react@18.3.1)
dev: false
+ /@radix-ui/react-alert-dialog@1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1):
+ resolution: {integrity: sha512-eGSlLzPhKO+TErxkiGcCZGuvbVMnLA1MTnyBksGOeGRGkxHiiJUujsjmNTdWTm4iHVSRaUao9/4Ur671auMghQ==}
+ 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
+ dependencies:
+ '@radix-ui/primitive': 1.1.0
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.2)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@18.3.2)(react@18.3.1)
+ '@radix-ui/react-dialog': 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1)
+ '@radix-ui/react-slot': 1.1.0(@types/react@18.3.2)(react@18.3.1)
+ '@types/react': 18.3.2
+ '@types/react-dom': 18.3.0
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ dev: false
+
/@radix-ui/react-arrow@1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1):
resolution: {integrity: sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==}
peerDependencies:
@@ -1596,6 +1624,39 @@ packages:
react: 18.3.1
dev: false
+ /@radix-ui/react-dialog@1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1):
+ resolution: {integrity: sha512-Yj4dZtqa2o+kG61fzB0H2qUvmwBA2oyQroGLyNtBj1beo1khoQ3q1a2AO8rrQYjd8256CO9+N8L9tvsS+bnIyA==}
+ 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
+ dependencies:
+ '@radix-ui/primitive': 1.1.0
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.3.2)(react@18.3.1)
+ '@radix-ui/react-context': 1.1.1(@types/react@18.3.2)(react@18.3.1)
+ '@radix-ui/react-dismissable-layer': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1)
+ '@radix-ui/react-focus-guards': 1.1.1(@types/react@18.3.2)(react@18.3.1)
+ '@radix-ui/react-focus-scope': 1.1.0(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1)
+ '@radix-ui/react-id': 1.1.0(@types/react@18.3.2)(react@18.3.1)
+ '@radix-ui/react-portal': 1.1.2(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1)
+ '@radix-ui/react-presence': 1.1.1(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1)
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.3.0)(@types/react@18.3.2)(react-dom@18.3.1)(react@18.3.1)
+ '@radix-ui/react-slot': 1.1.0(@types/react@18.3.2)(react@18.3.1)
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.3.2)(react@18.3.1)
+ '@types/react': 18.3.2
+ '@types/react-dom': 18.3.0
+ aria-hidden: 1.2.4
+ react: 18.3.1
+ react-dom: 18.3.1(react@18.3.1)
+ react-remove-scroll: 2.6.0(@types/react@18.3.2)(react@18.3.1)
+ dev: false
+
/@radix-ui/react-direction@1.1.0(@types/react@18.3.2)(react@18.3.1):
resolution: {integrity: sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==}
peerDependencies: