From 4c0cc947a2cdd2d75345850573183561275c6416 Mon Sep 17 00:00:00 2001 From: abhas20 Date: Fri, 24 Oct 2025 18:38:52 +0530 Subject: [PATCH] updated(builder-page): added collapsible feature for each section --- .../left/sections/shared/section-base.tsx | 172 ++++++++++-------- .../sidebars/left/sections/summary.tsx | 61 +++++-- apps/client/src/stores/resume.ts | 17 ++ 3 files changed, 162 insertions(+), 88 deletions(-) diff --git a/apps/client/src/pages/builder/sidebars/left/sections/shared/section-base.tsx b/apps/client/src/pages/builder/sidebars/left/sections/shared/section-base.tsx index 850d98fc..bdf1c4d0 100644 --- a/apps/client/src/pages/builder/sidebars/left/sections/shared/section-base.tsx +++ b/apps/client/src/pages/builder/sidebars/left/sections/shared/section-base.tsx @@ -15,7 +15,7 @@ import { verticalListSortingStrategy, } from "@dnd-kit/sortable"; import { t } from "@lingui/macro"; -import { PlusIcon } from "@phosphor-icons/react"; +import { CaretDownIcon, CaretRightIcon, PlusIcon } from "@phosphor-icons/react"; import type { SectionItem, SectionKey, SectionWithItem } from "@reactive-resume/schema"; import { Button } from "@reactive-resume/ui"; import { cn } from "@reactive-resume/utils"; @@ -38,10 +38,13 @@ type Props = { export const SectionBase = ({ id, title, description }: Props) => { const { open } = useDialog(id); + const collapsed = useResumeStore((state) => state.collapsedSections[id] ?? false); + const toggleSectionCollapse = useResumeStore((state) => state.toggleSectionCollapsed); + const setValue = useResumeStore((state) => state.setValue); - const section = useResumeStore((state) => - get(state.resume.data.sections, id), - ) as SectionWithItem; + const section = useResumeStore( + (state) => get(state.resume.data.sections, id) as SectionWithItem, + ); const sensors = useSensors( useSensor(PointerSensor), @@ -97,7 +100,17 @@ export const SectionBase = ({ id, title, description }: P className="grid gap-y-6" >
-
+
+ +

{section.name}

@@ -107,74 +120,91 @@ export const SectionBase = ({ id, title, description }: P
-
- {section.items.length === 0 && ( - +
+ {section.items.length === 0 && ( + + )} + + + + + {section.items.map((item, index) => ( + { + onUpdate(item as T); + }} + onDelete={() => { + onDelete(item as T); + }} + onDuplicate={() => { + onDuplicate(item as T); + }} + onToggleVisibility={() => { + onToggleVisibility(index); + }} + /> + ))} + + + +
+ + {section.items.length > 0 && ( +
+ +
+ )} + )} - - - - - {section.items.map((item, index) => ( - { - onUpdate(item as T); - }} - onDelete={() => { - onDelete(item as T); - }} - onDuplicate={() => { - onDuplicate(item as T); - }} - onToggleVisibility={() => { - onToggleVisibility(index); - }} - /> - ))} - - - -
- - {section.items.length > 0 && ( -
- -
- )} + ); }; diff --git a/apps/client/src/pages/builder/sidebars/left/sections/summary.tsx b/apps/client/src/pages/builder/sidebars/left/sections/summary.tsx index 0e9feeef..c6042a4b 100644 --- a/apps/client/src/pages/builder/sidebars/left/sections/summary.tsx +++ b/apps/client/src/pages/builder/sidebars/left/sections/summary.tsx @@ -1,6 +1,9 @@ +import { t } from "@lingui/macro"; +import { CaretDownIcon, CaretRightIcon } from "@phosphor-icons/react"; import { defaultSections } from "@reactive-resume/schema"; import { RichInput } from "@reactive-resume/ui"; import { cn } from "@reactive-resume/utils"; +import { AnimatePresence, motion } from "framer-motion"; import { AiActions } from "@/client/components/ai-actions"; import { useResumeStore } from "@/client/stores/resume"; @@ -14,11 +17,23 @@ export const SummarySection = () => { // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition (state) => state.resume.data.sections.summary ?? defaultSections.summary, ); + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + const collapsed = useResumeStore((state) => state.collapsedSections.summary ?? false); + const toogleSectionCollapse = useResumeStore((state) => state.toggleSectionCollapsed); return (
+

{section.name}

@@ -28,23 +43,35 @@ export const SummarySection = () => {
-
- ( - { - editor.commands.setContent(value, true); - setValue("sections.summary.content", value); - }} - /> - )} - onChange={(value) => { - setValue("sections.summary.content", value); - }} - /> -
+ + {!collapsed && ( + +
+ ( + { + editor.commands.setContent(value, true); + setValue("sections.summary.content", value); + }} + /> + )} + onChange={(value) => { + setValue("sections.summary.content", value); + }} + /> +
+
+ )} +
); }; diff --git a/apps/client/src/stores/resume.ts b/apps/client/src/stores/resume.ts index 74fc0df8..045b2c53 100644 --- a/apps/client/src/stores/resume.ts +++ b/apps/client/src/stores/resume.ts @@ -23,6 +23,10 @@ type ResumeStore = { // Custom Section Actions addSection: () => void; removeSection: (sectionId: SectionKey) => void; + + collapsedSections: Record; + toggleSectionCollapsed: (id: string) => void; + setSectionCollapsed: (id: string, collapsed: boolean) => void; }; export const useResumeStore = create()( @@ -69,6 +73,19 @@ export const useResumeStore = create()( }); } }, + collapsedSections: {}, + + toggleSectionCollapsed: (id) => { + set((state) => { + state.collapsedSections[id] = !state.collapsedSections[id]; + }); + }, + + setSectionCollapsed: (id, collapsed) => { + set((state) => { + state.collapsedSections[id] = collapsed; + }); + }, })), { limit: 100,