diff --git a/apps/fronted/src/components/editor/SidePanel.tsx b/apps/fronted/src/components/editor/SidePanel.tsx
index 32dc66d..e5dd3f1 100644
--- a/apps/fronted/src/components/editor/SidePanel.tsx
+++ b/apps/fronted/src/components/editor/SidePanel.tsx
@@ -1,18 +1,8 @@
"use client";
-
-import { motion, Reorder } from "framer-motion";
-import {
- GripVertical,
- Eye,
- EyeOff,
- Layout,
- Type,
- SpaceIcon,
- Palette,
- Plus,
- Trash2,
-} from "lucide-react";
-import { useResumeStore } from "@/store/useResumeStore";
+import { useMemo } from "react";
+import { motion } from "framer-motion";
+import { Layout, Type, SpaceIcon, Palette } from "lucide-react";
+import debounce from "lodash/debounce";
import {
Select,
SelectContent,
@@ -22,12 +12,12 @@ import {
} from "@/components/ui/select";
import { Slider } from "@/components/ui/slider";
import { Label } from "@/components/ui/label";
+import { Switch } from "@/components/ui/switch";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
+import LayoutSetting from "./layout/LayoutSetting";
+import { useResumeStore } from "@/store/useResumeStore";
import { cn } from "@/lib/utils";
import { THEME_COLORS } from "@/types/resume";
-import debounce from "lodash/debounce";
-import { useMemo } from "react";
-import { Switch } from "../ui/switch";
const fontOptions = [
{ value: "sans", label: "无衬线体" },
@@ -133,128 +123,15 @@ export function SidePanel() {
>
- {menuSections
- .filter((item) => item.id === "basic")
- .map((item) => (
-
-
-
- {item.icon}
-
- setActiveSection(item.id)}
- >
- {item.title}
-
-
-
- ))}
+
-
- {menuSections
- .filter((item) => item.id !== "basic")
- .map((item) => (
-
-
-
-
- {item.icon}
-
- setActiveSection(item.id)}
- >
- {item.title}
-
- toggleSectionVisibility(item.id)}
- className={cn(
- "p-1.5 rounded-md",
- "dark:hover:bg-neutral-700 dark:text-neutral-300",
- "hover:bg-gray-100 text-gray-600"
- )}
- >
- {item.enabled ? (
-
- ) : (
-
- )}
-
-
- {
- updateMenuSections(
- menuSections.filter(
- (section) => section.id !== item.id
- )
- );
- setActiveSection(
- menuSections[
- menuSections.findIndex((s) => s.id === item.id) - 1
- ].id
- );
- }}
- className={cn(
- "p-1.5 rounded-md text-primary",
- "dark:hover:bg-neutral-700 dark:text-neutral-300",
- "hover:bg-gray-100 text-gray-600"
- )}
- >
-
-
-
-
- ))}
-
void;
+ toggleSectionVisibility: (id: string) => void;
+ updateMenuSections: (sections: MenuSection[]) => void;
+ menuSections: MenuSection[];
+}
+
+const LayoutItem = ({
+ item,
+ isBasic = false,
+ activeSection,
+ setActiveSection,
+ toggleSectionVisibility,
+ updateMenuSections,
+ menuSections,
+}: LayoutItemProps) => {
+ const dragControls = useDragControls();
+
+ if (isBasic) {
+ return (
+
+
+
+ {item.icon}
+
+ setActiveSection(item.id)}
+ >
+ {item.title}
+
+
+
+ );
+ }
+
+ return (
+
+ {
+ dragControls.start(event);
+ }}
+ className={cn(
+ "w-8 flex items-center justify-center touch-none shrink-0",
+ "border-gray-100 dark:border-neutral-800",
+ "cursor-grab hover:bg-gray-50 dark:hover:bg-neutral-800/50"
+ )}
+ >
+
+
+
+
+
+
+ {item.icon}
+
+ setActiveSection(item.id)}
+ >
+ {item.title}
+
+ toggleSectionVisibility(item.id)}
+ className={cn(
+ "p-1.5 rounded-md mr-2",
+ "dark:hover:bg-neutral-700 dark:text-neutral-300",
+ "hover:bg-gray-100 text-gray-600"
+ )}
+ >
+ {item.enabled ? (
+
+ ) : (
+
+ )}
+
+
+ {
+ updateMenuSections(
+ menuSections.filter((section) => section.id !== item.id)
+ );
+ setActiveSection(
+ menuSections[
+ menuSections.findIndex((s) => s.id === item.id) - 1
+ ].id
+ );
+ }}
+ className={cn(
+ "p-1.5 rounded-md text-primary",
+ "dark:hover:bg-neutral-700 dark:text-neutral-300",
+ "hover:bg-gray-100 text-gray-600"
+ )}
+ >
+
+
+
+
+
+ );
+};
+
+export default LayoutItem;
diff --git a/apps/fronted/src/components/editor/layout/LayoutSetting.tsx b/apps/fronted/src/components/editor/layout/LayoutSetting.tsx
new file mode 100644
index 0000000..70daf89
--- /dev/null
+++ b/apps/fronted/src/components/editor/layout/LayoutSetting.tsx
@@ -0,0 +1,68 @@
+"use client";
+import { Reorder } from "framer-motion";
+import { MenuSection } from "@/types/resume";
+import LayoutItem from "./LayoutItem";
+
+interface LayoutPanelProps {
+ menuSections: MenuSection[];
+ activeSection: string;
+ setActiveSection: (id: string) => void;
+ toggleSectionVisibility: (id: string) => void;
+ updateMenuSections: (sections: MenuSection[]) => void;
+ reorderSections: (sections: MenuSection[]) => void;
+}
+
+const LayoutSetting = ({
+ menuSections,
+ activeSection,
+ setActiveSection,
+ toggleSectionVisibility,
+ updateMenuSections,
+ reorderSections,
+}: LayoutPanelProps) => {
+ const basicSection = menuSections.find((item) => item.id === "basic");
+ const draggableSections = menuSections.filter((item) => item.id !== "basic");
+
+ return (
+
+ {basicSection && (
+
+ )}
+
+ {
+ const updatedSections = [
+ ...menuSections.filter((item) => item.id === "basic"),
+ ...newOrder,
+ ];
+ reorderSections(updatedSections);
+ }}
+ className="space-y-2"
+ >
+ {draggableSections.map((item) => (
+
+ ))}
+
+
+ );
+};
+
+export default LayoutSetting;