diff --git a/apps/fronted/src/app/workbench/[id]/page.tsx b/apps/fronted/src/app/workbench/[id]/page.tsx
index 10f0bc4..054bc15 100644
--- a/apps/fronted/src/app/workbench/[id]/page.tsx
+++ b/apps/fronted/src/app/workbench/[id]/page.tsx
@@ -24,10 +24,8 @@ import {
const LAYOUT_CONFIG = {
DEFAULT: [20, 32, 48],
SIDE_COLLAPSED: [50, 50],
- EDIT_FOCUSED_WITH_SIDE: [18, 82, 0],
- PREVIEW_FOCUSED_WITH_SIDE: [18, 0, 82],
- EDIT_FOCUSED_NO_SIDE: [100, 0],
- PREVIEW_FOCUSED_NO_SIDE: [0, 100],
+ EDIT_FOCUSED: [20, 80],
+ PREVIEW_FOCUSED: [20, 80],
};
const DragHandle = ({ show = true }) => {
@@ -59,14 +57,18 @@ const DragHandle = ({ show = true }) => {
const LayoutControls = memo(
({
sidePanelCollapsed,
- focusedPanel,
+ editPanelCollapsed,
+ previewPanelCollapsed,
toggleSidePanel,
- togglePanelFocus,
+ toggleEditPanel,
+ togglePreviewPanel,
}: {
sidePanelCollapsed: boolean;
- focusedPanel: null | "edit" | "preview";
+ editPanelCollapsed: boolean;
+ previewPanelCollapsed: boolean;
toggleSidePanel: () => void;
- togglePanelFocus: (panel: "edit" | "preview") => void;
+ toggleEditPanel: () => void;
+ togglePreviewPanel: () => void;
}) => (
- {focusedPanel === "edit" ? "退出编辑模式" : "专注编辑"}
+ {editPanelCollapsed ? "展开编辑面板" : "收起编辑面板"}
@@ -126,21 +128,21 @@ const LayoutControls = memo(
- {focusedPanel === "preview" ? "退出预览模式" : "专注预览"}
+ {previewPanelCollapsed ? "展开预览面板" : "收起预览面板"}
@@ -153,117 +155,76 @@ LayoutControls.displayName = "LayoutControls";
export default function Home() {
const [sidePanelCollapsed, setSidePanelCollapsed] = useState(false);
- const [focusedPanel, setFocusedPanel] = useState
(
- null
- );
-
- const [showMobileSidebar, setShowMobileSidebar] = useState(false);
- const [isMobilePreview, setIsMobilePreview] = useState(false);
- const [panelSizes, setPanelSizes] = useState(LAYOUT_CONFIG.DEFAULT);
- const [layoutKey, setLayoutKey] = useState(0);
-
- const updateLayout = (newSizes: number[]) => {
- setPanelSizes(newSizes);
- setLayoutKey((prev) => prev + 1);
- };
-
- useEffect(() => {
- let newSizes;
- if (sidePanelCollapsed) {
- if (focusedPanel === "edit") {
- newSizes = [100, 0];
- } else if (focusedPanel === "preview") {
- newSizes = [0, 100];
- } else {
- newSizes = [50, 50];
- }
- } else {
- if (focusedPanel === "edit") {
- newSizes = [18, 82, 0];
- } else if (focusedPanel === "preview") {
- newSizes = [18, 0, 82];
- } else {
- newSizes = [20, 32, 48];
- }
- }
- updateLayout([...newSizes]);
- }, [sidePanelCollapsed, focusedPanel]);
+ const [editPanelCollapsed, setEditPanelCollapsed] = useState(false);
+ const [previewPanelCollapsed, setPreviewPanelCollapsed] = useState(false);
+ const [panelSizes, setPanelSizes] = useState(LAYOUT_CONFIG.DEFAULT);
const toggleSidePanel = () => {
setSidePanelCollapsed(!sidePanelCollapsed);
};
- const togglePanelFocus = (panel: "edit" | "preview") => {
- setFocusedPanel(focusedPanel === panel ? null : panel);
+ const toggleEditPanel = () => {
+ setEditPanelCollapsed(!editPanelCollapsed);
};
- // 移动端控制栏
- const MobileControls = () => (
-
- setShowMobileSidebar(true)}
- >
-
-
- setIsMobilePreview(!isMobilePreview)}
- >
- {isMobilePreview ? (
-
- ) : (
-
- )}
-
-
- );
+ const togglePreviewPanel = () => {
+ setPreviewPanelCollapsed(!previewPanelCollapsed);
+ };
- // 移动端侧边栏
- const MobileSidebar = () => (
-
- {showMobileSidebar && (
- <>
- setShowMobileSidebar(false)}
- />
-
-
-
- >
- )}
-
- );
+ const updateLayout = (sizes: number[]) => {
+ setPanelSizes(sizes);
+ };
+
+ useEffect(() => {
+ let newSizes = [];
+
+ // 侧边栏尺寸
+ newSizes.push(sidePanelCollapsed ? 0 : 20);
+
+ // 编辑区尺寸
+ if (editPanelCollapsed) {
+ newSizes.push(0);
+ } else {
+ if (sidePanelCollapsed) {
+ newSizes.push(50);
+ } else {
+ if (previewPanelCollapsed) {
+ newSizes.push(80);
+ } else {
+ newSizes.push(32);
+ }
+ }
+ }
+
+ // 预览区尺寸
+ if (previewPanelCollapsed) {
+ newSizes.push(0);
+ } else {
+ if (editPanelCollapsed && sidePanelCollapsed) {
+ newSizes.push(100);
+ } else {
+ if (editPanelCollapsed) {
+ newSizes.push(80);
+ } else {
+ newSizes.push(48);
+ }
+ }
+ }
+
+ // 确保总和为 100
+ const total = newSizes.reduce((a, b) => a + b, 0);
+ if (total < 100) {
+ const lastNonZeroIndex = newSizes
+ .map((size, index) => ({ size, index }))
+ .filter(({ size }) => size > 0)
+ .pop()?.index;
+
+ if (lastNonZeroIndex !== undefined) {
+ newSizes[lastNonZeroIndex] += 100 - total;
+ }
+ }
+ updateLayout([...newSizes]);
+ }, [sidePanelCollapsed, editPanelCollapsed, previewPanelCollapsed]);
return (
-
-
-
-
-
+ {!editPanelCollapsed && (
+ <>
+
+
+
+
+
+
+ >
+ )}
{/* 预览面板 */}
-
-
-
+ {!previewPanelCollapsed && (
+
+
+
+ )}
-
-
{/* 移动端布局 */}
- {isMobilePreview ? (
-
-
-
- ) : (
+ {previewPanelCollapsed ? (
+ ) : (
+
+
+
)}
-
-
-
);
}
diff --git a/apps/fronted/src/components/magicui/dock.tsx b/apps/fronted/src/components/magicui/dock.tsx
index a022471..d492fb5 100644
--- a/apps/fronted/src/components/magicui/dock.tsx
+++ b/apps/fronted/src/components/magicui/dock.tsx
@@ -2,14 +2,15 @@ import { cn } from "@/lib/utils";
import React, { PropsWithChildren } from "react";
import { motion } from "framer-motion";
-interface DockProps extends PropsWithChildren> {
+interface DockProps
+ extends PropsWithChildren> {
className?: string;
}
export function Dock({ children, className, ...props }: DockProps) {
// Convert children to array to handle them
const childrenArray = React.Children.toArray(children);
-
+
// Find the index of TemplateSheet for splitting
const templateSheetIndex = childrenArray.findIndex((child) => {
if (React.isValidElement(child)) {
@@ -22,7 +23,9 @@ export function Dock({ children, className, ...props }: DockProps) {
const content = trigger.props.children;
if (React.isValidElement(content)) {
const icon = content.props.children;
- return React.isValidElement(icon) && icon.type?.name === "TemplateSheet";
+ return (
+ React.isValidElement(icon) && icon.type?.name === "TemplateSheet"
+ );
}
}
}
@@ -36,7 +39,7 @@ export function Dock({ children, className, ...props }: DockProps) {
@@ -95,7 +98,7 @@ export function DockIcon({ children, className, onClick }: DockIconProps) {
whileHover={{ scale: 1.2 }}
whileTap={{ scale: 0.95 }}
className={cn(
- "flex size-10 items-center justify-center rounded-lg bg-white text-neutral-700 shadow-sm transition-colors hover:bg-gray-100 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700 dark:shadow-slate-900/20",
+ "flex size-8 items-center justify-center rounded-sm bg-white text-neutral-700 shadow-sm transition-colors hover:bg-gray-100 dark:bg-slate-800 dark:text-slate-200 dark:hover:bg-slate-700 dark:shadow-slate-900/20",
className
)}
onClick={onClick}
diff --git a/apps/fronted/src/components/preview/PreviewDock.tsx b/apps/fronted/src/components/preview/PreviewDock.tsx
new file mode 100644
index 0000000..ad2a205
--- /dev/null
+++ b/apps/fronted/src/components/preview/PreviewDock.tsx
@@ -0,0 +1,140 @@
+"use client";
+import React from "react";
+import { Edit2, PanelRightClose, PanelRightOpen } from "lucide-react";
+import { Dock, DockIcon } from "@/components/magicui/dock";
+import {
+ Tooltip,
+ TooltipContent,
+ TooltipProvider,
+ TooltipTrigger,
+} from "@/components/ui/tooltip";
+import TemplateSheet from "@/components/shared/TemplateSheet";
+import { GITHUB_REPO_URL } from "@/config";
+import { cn } from "@/lib/utils";
+
+export type IconProps = React.HTMLAttributes
;
+
+interface PreviewDockProps {
+ sidePanelCollapsed: boolean;
+ editPanelCollapsed: boolean;
+ toggleSidePanel: () => void;
+ toggleEditPanel: () => void;
+}
+
+const Icons = {
+ gitHub: (props: IconProps) => (
+
+ ),
+};
+
+export const PreviewDock = ({
+ sidePanelCollapsed,
+ editPanelCollapsed,
+ toggleSidePanel,
+ toggleEditPanel,
+}: PreviewDockProps) => {
+ const handleGoGitHub = () => {
+ window.open(GITHUB_REPO_URL, "_blank");
+ };
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+ 切换模版
+
+
+
+
+
+
+
+
+
+
+ {sidePanelCollapsed ? "展开侧边栏" : "收起侧边栏"}
+
+
+
+
+
+
+
+
+
+ {editPanelCollapsed ? "展开编辑面板" : "收起编辑面板"}
+
+
+
+
+
+
+
+
+
+
+ GitHub
+
+
+
+
+
+
+ );
+};
diff --git a/apps/fronted/src/components/preview/index.tsx b/apps/fronted/src/components/preview/index.tsx
index 96bc83c..9df1c17 100644
--- a/apps/fronted/src/components/preview/index.tsx
+++ b/apps/fronted/src/components/preview/index.tsx
@@ -1,36 +1,22 @@
"use client";
+
import React, { useEffect, useMemo, useState, useRef } from "react";
import { throttle } from "lodash";
-import TemplateSheet from "@/components/shared/TemplateSheet";
-import { Dock, DockIcon } from "@/components/magicui/dock";
-import ResumeTemplateComponent from "../templates";
-import { DEFAULT_TEMPLATES, GITHUB_REPO_URL } from "@/config";
+import { DEFAULT_TEMPLATES } from "@/config";
import { cn } from "@/lib/utils";
import { useResumeStore } from "@/store/useResumeStore";
-import {
- Tooltip,
- TooltipContent,
- TooltipProvider,
- TooltipTrigger,
-} from "@/components/ui/tooltip";
+import ResumeTemplateComponent from "../templates";
+import { PreviewDock } from "./PreviewDock";
-export type IconProps = React.HTMLAttributes;
-const getFontFamilyClass = (fontFamily: string) => {
- switch (fontFamily) {
- case "serif":
- return "font-serif";
- case "mono":
- return "font-mono";
- default:
- return "font-sans";
- }
-};
-
-interface PageBreakLineProps {
- pageNumber: number;
+interface PreviewPanelProps {
+ sidePanelCollapsed: boolean;
+ editPanelCollapsed: boolean;
+ previewPanelCollapsed: boolean;
+ toggleSidePanel: () => void;
+ toggleEditPanel: () => void;
}
-const PageBreakLine = React.memo(({ pageNumber }: PageBreakLineProps) => {
+const PageBreakLine = React.memo(({ pageNumber }: { pageNumber: number }) => {
const { activeResume } = useResumeStore();
const { globalSettings } = activeResume || {};
if (!globalSettings?.pagePadding) return;
@@ -62,18 +48,12 @@ const PageBreakLine = React.memo(({ pageNumber }: PageBreakLineProps) => {
PageBreakLine.displayName = "PageBreakLine";
-const Icons = {
- gitHub: (props: IconProps) => (
-
- ),
-};
-
-const PreviewPanel = () => {
+const PreviewPanel = ({
+ sidePanelCollapsed,
+ editPanelCollapsed,
+ toggleSidePanel,
+ toggleEditPanel,
+}: PreviewPanelProps) => {
const { activeResume } = useResumeStore();
const template = useMemo(() => {
return (
@@ -83,7 +63,6 @@ const PreviewPanel = () => {
}, [activeResume?.templateId]);
const startRef = useRef(null);
- const endRef = useRef(null);
const previewRef = React.useRef(null);
const resumeContentRef = React.useRef(null);
@@ -119,16 +98,12 @@ const PreviewPanel = () => {
if (!activeResume) return null;
- const handleGoGitHub = () => {
- window.open(GITHUB_REPO_URL, "_blank");
- };
-
return (
-
+
-
-
-
-
-
-
-
-
-
-
-
- Go GitHub
-
-
-
-
-
-
-
-
-
-
-
- 切换模版
-
-
-
-
-
-
+
);
};
diff --git a/apps/fronted/src/components/shared/TemplateSheet.tsx b/apps/fronted/src/components/shared/TemplateSheet.tsx
index f968e66..56fd157 100644
--- a/apps/fronted/src/components/shared/TemplateSheet.tsx
+++ b/apps/fronted/src/components/shared/TemplateSheet.tsx
@@ -32,7 +32,7 @@ const TemplateSheet = () => {
return (
-
+