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 ( - +