mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-08-24 15:22:20 +10:00
Squashed commit of the following:
commit b2b0470a1d9267d042ec0ac66523c6635bf5b199
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Tue May 19 13:13:38 2026 +0200
chore: update .gitignore to include .vite-hooks and modify pnpm-lock.yaml for dependencies
commit d28fadb5cd8706c874e616102878b4a394ec84c1
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Tue May 19 13:08:04 2026 +0200
fix: remove timestamp conflict guard
commit c6998d9dbab19d09d3c8054feef1d2e4117555eb
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Tue May 19 12:11:51 2026 +0200
chore(release): v5.1.5
commit f33d168711804880e1f12e88d24290aae16cc258
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Tue May 19 11:58:35 2026 +0200
revert: compose.yml
commit d961e6535811a10c335525fb33a08d03e737278d
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Tue May 19 11:58:08 2026 +0200
refactor(agent): replace 'revert' terminology with 'restore' for clarity, resolves #3086
commit 17f351171be218e33f01c469d95e4164d4c8dc57
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Tue May 19 11:10:41 2026 +0200
refactor(pdf): simplify sidebar section filtering and update summary feature logic
commit d55179b9d76879e3204de185e8b53fadd0a107ed
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Tue May 19 09:53:37 2026 +0200
chore: update pnpm-lock.yaml and turbo.json
commit 7cade6980e1a04352536bd44ef773f338c4ef599
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Tue May 19 09:38:30 2026 +0200
fix(polyfill): add tested polyfill for Map Upsert methods
commit 26d175bb9c53d93225d1e907678445252c13d660
Merge: 1cf33dc6c 5b1297fa2
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Tue May 19 09:23:29 2026 +0200
Merge remote-tracking branch 'origin/main' into feat/explore-hono-orpc-migration
# Conflicts:
# packages/api/src/services/agent-url.ts
# packages/runtime-externals/package.json
commit 1cf33dc6c9d81735730ad656e16dab6501c6d6a1
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Tue May 19 09:22:12 2026 +0200
chore: preserve branch changes before main sync
commit b380a4b00fdbcdd81ff4f8ef72b330fd027ccda5
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Mon May 18 07:50:28 2026 +0200
chore: lot of fixes for monorepo migration
commit 8fcf0ec64e1c29572ebaff494338368bfcf75760
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 13:57:17 2026 +0200
chore: update knip version and refine web app routing with new SEO endpoints
commit 234e68086ff15610a93877354c98e2c020364533
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 12:10:06 2026 +0200
refactor(auth): update OAuth routes to include API prefix and remove unused schema endpoint
commit 91c84b9a8496b0ce21d71cae9f8b2a027638c9ac
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 11:54:29 2026 +0200
chore: update dependencies and enhance PWA metadata in web app
commit 150117d4a5a9dd6cd92c64891aad8cae90f6a7af
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 11:12:35 2026 +0200
docs: revise manifest-only pwa testing scope
commit 6b939a55661aec9dd8122b184e4b60a5c7325fb5
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 11:11:33 2026 +0200
docs: add manifest-only pwa design
commit 1422e1fc96c400948b273210a1067251087d15d4
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 11:05:04 2026 +0200
chore(dev): simplify server proxy config
commit bc2ff5a9f6fda41e6c40333c8f163aa23a6c5e48
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 11:04:50 2026 +0200
docs: add unsafe oauth redirect plan
commit 445359ebe9b96c1515bf1c4c3f73ba8a8448ec12
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 11:04:34 2026 +0200
feat(auth): add unsafe oauth redirect flag
commit 73fffdd24598e56b2793f7657919bc794835892e
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 10:55:02 2026 +0200
docs: design unsafe oauth redirect flag
commit c0066aa19c15fc8a4c8e5179ed49889c117519f4
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 10:22:04 2026 +0200
chore: update translation source paths
commit 9033da082418d252aafd6c2eed72f71f014be3d9
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 10:09:25 2026 +0200
refactor(arch): react spa + hono migration
commit 6f27936c11bda895977dc63ee550c3346d4ce24b
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Fri May 15 01:10:47 2026 +0200
docs: add docker nightly tagging design
commit ecc1fd9a88a0ee1dca2f1977dfc17f74527fe1da
Author: Amruth Pillai <im.amruth@gmail.com>
Date: Thu May 14 20:05:44 2026 +0200
feat: migrate to hono spa server
This commit is contained in:
@@ -20,14 +20,14 @@ import { useCallback, useMemo, useState } from "react";
|
||||
import { useControls } from "react-zoom-pan-pinch";
|
||||
import { toast } from "sonner";
|
||||
import { useCopyToClipboard } from "usehooks-ts";
|
||||
import { buildDocx } from "@reactive-resume/docx";
|
||||
import { Button } from "@reactive-resume/ui/components/button";
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from "@reactive-resume/ui/components/tooltip";
|
||||
import { downloadWithAnchor, generateFilename } from "@reactive-resume/utils/file";
|
||||
import { buildDocx } from "@reactive-resume/utils/resume/docx";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume } from "@/features/resume/builder/draft";
|
||||
import { createResumePdfBlob } from "@/features/resume/export/pdf-document";
|
||||
import { authClient } from "@/libs/auth/client";
|
||||
import { createResumePdfBlob } from "@/libs/resume/pdf-document";
|
||||
|
||||
type BuilderDockProps = {
|
||||
pageLayout: BuilderPreviewPageLayout;
|
||||
|
||||
@@ -21,8 +21,8 @@ import {
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from "@reactive-resume/ui/components/dropdown-menu";
|
||||
import { useCurrentResume, usePatchResume } from "@/components/resume/builder-resume-draft";
|
||||
import { useDialogStore } from "@/dialogs/store";
|
||||
import { useCurrentResume, usePatchResume } from "@/features/resume/builder/draft";
|
||||
import { useConfirm } from "@/hooks/use-confirm";
|
||||
import { getResumeErrorMessage } from "@/libs/error-message";
|
||||
import { orpc } from "@/libs/orpc/client";
|
||||
|
||||
@@ -5,7 +5,7 @@ import { Suspense, useState } from "react";
|
||||
import { TransformComponent, TransformWrapper } from "react-zoom-pan-pinch";
|
||||
import { toast } from "sonner";
|
||||
import { LoadingScreen } from "@/components/layout/loading-screen";
|
||||
import { ResumePreview } from "@/components/resume/preview";
|
||||
import { ResumePreview } from "@/features/resume/preview/preview";
|
||||
import { BuilderDock } from "./dock";
|
||||
import { DEFAULT_BUILDER_PREVIEW_PAGE_LAYOUT, getNextBuilderPreviewPageLayout } from "./page-layout";
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ import { Button } from "@reactive-resume/ui/components/button";
|
||||
import { ScrollArea } from "@reactive-resume/ui/components/scroll-area";
|
||||
import { Separator } from "@reactive-resume/ui/components/separator";
|
||||
import { getInitials } from "@reactive-resume/utils/string";
|
||||
import { UserDropdownMenu } from "@/components/user/dropdown-menu";
|
||||
import { UserDropdownMenu } from "@/features/user/dropdown-menu";
|
||||
import { getSectionIcon, getSectionTitle, leftSidebarSections } from "@/libs/resume/section";
|
||||
import { BuilderSidebarEdge } from "../../-components/edge";
|
||||
import { useBuilderSidebar } from "../../-store/sidebar";
|
||||
|
||||
@@ -3,7 +3,7 @@ import type z from "zod";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { basicsSchema } from "@reactive-resume/schema/resume/data";
|
||||
import { FormControl, FormItem, FormLabel, FormMessage } from "@reactive-resume/ui/components/form";
|
||||
import { Input } from "@reactive-resume/ui/components/input";
|
||||
import { URLInput } from "@/components/input/url-input";
|
||||
import { useCurrentBuilderResumeSelector, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentBuilderResumeSelector, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { useSyncFormValues } from "@/hooks/use-sync-form-values";
|
||||
import { useAppForm } from "@/libs/tanstack-form";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
|
||||
@@ -3,7 +3,7 @@ import type z from "zod";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -32,8 +32,8 @@ import {
|
||||
} from "@reactive-resume/ui/components/dropdown-menu";
|
||||
import { stripHtml } from "@reactive-resume/utils/string";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useDialogStore } from "@/dialogs/store";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { useConfirm } from "@/hooks/use-confirm";
|
||||
import { getSectionTitle } from "@/libs/resume/section";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ const experienceItems = vi.hoisted(() => [
|
||||
},
|
||||
]);
|
||||
|
||||
vi.mock("@/components/resume/builder-resume-draft", () => ({
|
||||
vi.mock("@/features/resume/builder/draft", () => ({
|
||||
useCurrentResume: () => ({
|
||||
data: {
|
||||
sections: {
|
||||
|
||||
@@ -3,7 +3,7 @@ import type z from "zod";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { plural } from "@lingui/core/macro";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import type z from "zod";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import type z from "zod";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -72,7 +72,7 @@ const sections = vi.hoisted(() => ({
|
||||
],
|
||||
}));
|
||||
|
||||
vi.mock("@/components/resume/builder-resume-draft", () => ({
|
||||
vi.mock("@/features/resume/builder/draft", () => ({
|
||||
useCurrentResume: () => ({
|
||||
data: {
|
||||
sections: {
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
InputGroupText,
|
||||
} from "@reactive-resume/ui/components/input-group";
|
||||
import { ColorPicker } from "@/components/input/color-picker";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { useSyncFormValues } from "@/hooks/use-sync-form-values";
|
||||
import { getReadableErrorMessage } from "@/libs/error-message";
|
||||
import { orpc } from "@/libs/orpc/client";
|
||||
|
||||
@@ -26,7 +26,7 @@ const sectionItems = vi.hoisted(() => [
|
||||
},
|
||||
]);
|
||||
|
||||
vi.mock("@/components/resume/builder-resume-draft", () => ({
|
||||
vi.mock("@/features/resume/builder/draft", () => ({
|
||||
useCurrentResume: () => ({
|
||||
data: {
|
||||
sections: { profiles: { title: "Profiles", columns: 1, hidden: false, items: sectionItems } },
|
||||
|
||||
@@ -3,7 +3,7 @@ import type z from "zod";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ const items = vi.hoisted(() => [
|
||||
},
|
||||
]);
|
||||
|
||||
vi.mock("@/components/resume/builder-resume-draft", () => ({
|
||||
vi.mock("@/features/resume/builder/draft", () => ({
|
||||
useCurrentResume: () => ({
|
||||
data: { sections: { projects: { title: "Projects", columns: 1, hidden: false, items } } },
|
||||
}),
|
||||
|
||||
@@ -3,7 +3,7 @@ import type z from "zod";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import type z from "zod";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import type z from "zod";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ const sectionItems = vi.hoisted(() => [
|
||||
{ id: "s2", name: "Go", proficiency: "Intermediate", level: 3, keywords: [], description: "", hidden: false },
|
||||
]);
|
||||
|
||||
vi.mock("@/components/resume/builder-resume-draft", () => ({
|
||||
vi.mock("@/features/resume/builder/draft", () => ({
|
||||
useCurrentResume: () => ({
|
||||
data: { sections: { skills: { title: "Skills", columns: 1, hidden: false, items: sectionItems } } },
|
||||
}),
|
||||
|
||||
@@ -3,7 +3,7 @@ import type z from "zod";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RichInput } from "@/components/input/rich-input";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
|
||||
export function SummarySectionBuilder() {
|
||||
|
||||
@@ -3,7 +3,7 @@ import type z from "zod";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { AnimatePresence, Reorder } from "motion/react";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { CaretDownIcon } from "@phosphor-icons/react";
|
||||
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "@reactive-resume/ui/components/accordion";
|
||||
import { Button } from "@reactive-resume/ui/components/button";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume } from "@/features/resume/builder/draft";
|
||||
import { getSectionIcon, getSectionTitle } from "@/libs/resume/section";
|
||||
import { useSectionStore } from "../../../-store/section";
|
||||
import { SectionDropdownMenu } from "./section-menu";
|
||||
|
||||
@@ -36,8 +36,8 @@ import {
|
||||
DropdownMenuTrigger,
|
||||
} from "@reactive-resume/ui/components/dropdown-menu";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useDialogStore } from "@/dialogs/store";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { useConfirm } from "@/hooks/use-confirm";
|
||||
import {
|
||||
addItemToSection,
|
||||
|
||||
@@ -24,8 +24,8 @@ import {
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuTrigger,
|
||||
} from "@reactive-resume/ui/components/dropdown-menu";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useDialogStore } from "@/dialogs/store";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { useConfirm } from "@/hooks/use-confirm";
|
||||
import { usePrompt } from "@/hooks/use-prompt";
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import { ColorPicker } from "@/components/input/color-picker";
|
||||
import { IconPicker } from "@/components/input/icon-picker";
|
||||
import { LevelTypeCombobox } from "@/components/level/combobox";
|
||||
import { LevelDisplay } from "@/components/level/display";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { useSyncFormValues } from "@/hooks/use-sync-form-values";
|
||||
import { useAppForm } from "@/libs/tanstack-form";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
|
||||
@@ -17,9 +17,9 @@ vi.mock("@reactive-resume/utils/file", () => ({
|
||||
downloadWithAnchor,
|
||||
generateFilename: (name: string, ext: string) => `${name}.${ext}`,
|
||||
}));
|
||||
vi.mock("@reactive-resume/utils/resume/docx", () => ({ buildDocx }));
|
||||
vi.mock("@/libs/resume/pdf-document", () => ({ createResumePdfBlob }));
|
||||
vi.mock("@/components/resume/builder-resume-draft", () => ({
|
||||
vi.mock("@reactive-resume/docx", () => ({ buildDocx }));
|
||||
vi.mock("@/features/resume/export/pdf-document", () => ({ createResumePdfBlob }));
|
||||
vi.mock("@/features/resume/builder/draft", () => ({
|
||||
useResume: () => ({ id: "r1", name: "My Resume", data: defaultResumeData }),
|
||||
}));
|
||||
|
||||
|
||||
@@ -3,11 +3,11 @@ import { Trans } from "@lingui/react/macro";
|
||||
import { CircleNotchIcon, FileDocIcon, FileJsIcon, FilePdfIcon } from "@phosphor-icons/react";
|
||||
import { useCallback, useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import { buildDocx } from "@reactive-resume/docx";
|
||||
import { Button } from "@reactive-resume/ui/components/button";
|
||||
import { downloadWithAnchor, generateFilename } from "@reactive-resume/utils/file";
|
||||
import { buildDocx } from "@reactive-resume/utils/resume/docx";
|
||||
import { useResume } from "@/components/resume/builder-resume-draft";
|
||||
import { createResumePdfBlob } from "@/libs/resume/pdf-document";
|
||||
import { useResume } from "@/features/resume/builder/draft";
|
||||
import { createResumePdfBlob } from "@/features/resume/export/pdf-document";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
|
||||
export function ExportSectionBuilder() {
|
||||
|
||||
@@ -9,7 +9,7 @@ import {
|
||||
InputGroupText,
|
||||
} from "@reactive-resume/ui/components/input-group";
|
||||
import { Slider } from "@reactive-resume/ui/components/slider";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { useSyncFormValues } from "@/hooks/use-sync-form-values";
|
||||
import { useAppForm } from "@/libs/tanstack-form";
|
||||
import { SectionBase } from "../../shared/section-base";
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import type { DragEndEvent, DragStartEvent } from "@dnd-kit/core";
|
||||
import type { SectionType } from "@reactive-resume/schema/resume/data";
|
||||
import type { CSSProperties, HTMLAttributes } from "react";
|
||||
import {
|
||||
closestCorners,
|
||||
@@ -20,9 +19,9 @@ import { match } from "ts-pattern";
|
||||
import { Button } from "@reactive-resume/ui/components/button";
|
||||
import { Switch } from "@reactive-resume/ui/components/switch";
|
||||
import { cn } from "@reactive-resume/utils/style";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { templates } from "@/dialogs/resume/template/data";
|
||||
import { getSectionTitle } from "@/libs/resume/section";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { resolveLayoutSectionTitle } from "./title";
|
||||
import { filterVisibleLayoutSectionIds } from "./visibility";
|
||||
|
||||
type ColumnId = "main" | "sidebar";
|
||||
@@ -403,15 +402,7 @@ type LayoutItemContentProps = HTMLAttributes<HTMLDivElement> & {
|
||||
const LayoutItemContent = forwardRef<HTMLDivElement, LayoutItemContentProps>(
|
||||
({ id, isDragging, isOverlay, className, style, ...rest }, ref) => {
|
||||
const resume = useCurrentResume();
|
||||
const title = (() => {
|
||||
if (!resume) return id;
|
||||
if (id === "summary") return resume.data.summary.title || getSectionTitle("summary");
|
||||
if (id in resume.data.sections)
|
||||
return resume.data.sections[id as SectionType].title || getSectionTitle(id as SectionType);
|
||||
const customSection = resume.data.customSections.find((section) => section.id === id);
|
||||
if (customSection) return customSection.title;
|
||||
return id;
|
||||
})();
|
||||
const title = resume ? resolveLayoutSectionTitle(resume.data, id) : id;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import type { ResumeData } from "@reactive-resume/schema/resume/data";
|
||||
import { beforeAll, describe, expect, it } from "vitest";
|
||||
import { i18n } from "@lingui/core";
|
||||
import { defaultResumeData } from "@reactive-resume/schema/resume/default";
|
||||
import { resolveLayoutSectionTitle } from "./title";
|
||||
|
||||
const createResumeData = (): ResumeData => structuredClone(defaultResumeData);
|
||||
|
||||
beforeAll(() => {
|
||||
i18n.loadAndActivate({ locale: "en", messages: {} });
|
||||
});
|
||||
|
||||
describe("resolveLayoutSectionTitle", () => {
|
||||
it("uses a custom section title when present", () => {
|
||||
const data = createResumeData();
|
||||
data.customSections = [
|
||||
{
|
||||
id: "custom-awards",
|
||||
type: "awards",
|
||||
title: "Industry Recognition",
|
||||
columns: 1,
|
||||
hidden: false,
|
||||
items: [],
|
||||
},
|
||||
] as never;
|
||||
|
||||
expect(resolveLayoutSectionTitle(data, "custom-awards")).toBe("Industry Recognition");
|
||||
});
|
||||
|
||||
it("falls back to the custom section type title when the custom title is empty", () => {
|
||||
const data = createResumeData();
|
||||
data.customSections = [
|
||||
{
|
||||
id: "custom-awards",
|
||||
type: "awards",
|
||||
title: "",
|
||||
columns: 1,
|
||||
hidden: false,
|
||||
items: [],
|
||||
},
|
||||
] as never;
|
||||
|
||||
expect(resolveLayoutSectionTitle(data, "custom-awards")).toBe("Awards");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,24 @@
|
||||
import type { CustomSectionType, ResumeData, SectionType } from "@reactive-resume/schema/resume/data";
|
||||
import { getSectionTitle } from "@/libs/resume/section";
|
||||
|
||||
const hasTitle = (title: string): boolean => title.trim().length > 0;
|
||||
|
||||
export const resolveLayoutSectionTitle = (data: ResumeData, sectionId: string): string => {
|
||||
if (sectionId === "summary") return hasTitle(data.summary.title) ? data.summary.title : getSectionTitle("summary");
|
||||
|
||||
if (sectionId in data.sections) {
|
||||
const section = data.sections[sectionId as SectionType];
|
||||
|
||||
return hasTitle(section.title) ? section.title : getSectionTitle(sectionId as SectionType);
|
||||
}
|
||||
|
||||
const customSection = data.customSections.find((section) => section.id === sectionId);
|
||||
|
||||
if (customSection) {
|
||||
return hasTitle(customSection.title)
|
||||
? customSection.title
|
||||
: getSectionTitle(customSection.type as CustomSectionType);
|
||||
}
|
||||
|
||||
return sectionId;
|
||||
};
|
||||
@@ -21,7 +21,7 @@ vi.mock("@/components/input/rich-input", () => ({
|
||||
return <textarea data-testid="rich-input" value={props.value} readOnly />;
|
||||
},
|
||||
}));
|
||||
vi.mock("@/components/resume/builder-resume-draft", () => ({
|
||||
vi.mock("@/features/resume/builder/draft", () => ({
|
||||
useCurrentResume: () => ({
|
||||
data: { metadata: { notes: "saved notes" } },
|
||||
}),
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { RichInput } from "@/components/input/rich-input";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
|
||||
export function NotesSectionBuilder() {
|
||||
|
||||
@@ -10,9 +10,9 @@ import {
|
||||
InputGroupText,
|
||||
} from "@reactive-resume/ui/components/input-group";
|
||||
import { Switch } from "@reactive-resume/ui/components/switch";
|
||||
import { getLocaleOptions } from "@/components/locale/combobox";
|
||||
import { useResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { Combobox } from "@/components/ui/combobox";
|
||||
import { getLocaleOptions } from "@/features/locale/combobox";
|
||||
import { useResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { useSyncFormValues } from "@/hooks/use-sync-form-values";
|
||||
import { useAppForm } from "@/libs/tanstack-form";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
|
||||
@@ -9,7 +9,7 @@ import { match } from "ts-pattern";
|
||||
import { Alert, AlertDescription } from "@reactive-resume/ui/components/alert";
|
||||
import { Badge } from "@reactive-resume/ui/components/badge";
|
||||
import { Button } from "@reactive-resume/ui/components/button";
|
||||
import { useResume } from "@/components/resume/builder-resume-draft";
|
||||
import { useResume } from "@/features/resume/builder/draft";
|
||||
import { getOrpcErrorMessage } from "@/libs/error-message";
|
||||
import { orpc } from "@/libs/orpc/client";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
|
||||
@@ -10,7 +10,7 @@ import { Button } from "@reactive-resume/ui/components/button";
|
||||
import { Input } from "@reactive-resume/ui/components/input";
|
||||
import { Label } from "@reactive-resume/ui/components/label";
|
||||
import { Switch } from "@reactive-resume/ui/components/switch";
|
||||
import { useCurrentResume, usePatchResume } from "@/components/resume/builder-resume-draft";
|
||||
import { useCurrentResume, usePatchResume } from "@/features/resume/builder/draft";
|
||||
import { useConfirm } from "@/hooks/use-confirm";
|
||||
import { usePrompt } from "@/hooks/use-prompt";
|
||||
import { authClient } from "@/libs/auth/client";
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useDialogStore } from "@/dialogs/store";
|
||||
vi.mock("../shared/section-base", () => ({
|
||||
SectionBase: ({ children }: { children: React.ReactNode }) => <div>{children}</div>,
|
||||
}));
|
||||
vi.mock("@/components/resume/builder-resume-draft", () => ({
|
||||
vi.mock("@/features/resume/builder/draft", () => ({
|
||||
useCurrentResume: () => ({
|
||||
data: { metadata: { template: "ditto" } },
|
||||
}),
|
||||
|
||||
@@ -2,9 +2,9 @@ import { useLingui } from "@lingui/react";
|
||||
import { SwapIcon } from "@phosphor-icons/react";
|
||||
import { Badge } from "@reactive-resume/ui/components/badge";
|
||||
import { Button } from "@reactive-resume/ui/components/button";
|
||||
import { useCurrentResume } from "@/components/resume/builder-resume-draft";
|
||||
import { templates } from "@/dialogs/resume/template/data";
|
||||
import { useDialogStore } from "@/dialogs/store";
|
||||
import { useCurrentResume } from "@/features/resume/builder/draft";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
|
||||
export function TemplateSectionBuilder() {
|
||||
|
||||
@@ -10,8 +10,8 @@ import {
|
||||
InputGroupText,
|
||||
} from "@reactive-resume/ui/components/input-group";
|
||||
import { Separator } from "@reactive-resume/ui/components/separator";
|
||||
import { useResume, useUpdateResumeData } from "@/components/resume/builder-resume-draft";
|
||||
import { FontFamilyCombobox, FontWeightCombobox, getNextWeights } from "@/components/typography/combobox";
|
||||
import { useResume, useUpdateResumeData } from "@/features/resume/builder/draft";
|
||||
import { useSyncFormValues } from "@/hooks/use-sync-form-values";
|
||||
import { useAppForm } from "@/libs/tanstack-form";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
|
||||
@@ -2,5 +2,4 @@ import { createFileRoute, lazyRouteComponent } from "@tanstack/react-router";
|
||||
|
||||
export const Route = createFileRoute("/builder/$resumeId/")({
|
||||
component: lazyRouteComponent(() => import("./-components/preview-page"), "PreviewPage"),
|
||||
ssr: false,
|
||||
});
|
||||
|
||||
@@ -3,8 +3,7 @@ import type { Layout } from "react-resizable-panels";
|
||||
import type { BuilderLayout } from "./-store/sidebar";
|
||||
import { useSuspenseQuery } from "@tanstack/react-query";
|
||||
import { createFileRoute, Outlet, redirect } from "@tanstack/react-router";
|
||||
import { createServerFn } from "@tanstack/react-start";
|
||||
import { getCookie, setCookie } from "@tanstack/react-start/server";
|
||||
import Cookies from "js-cookie";
|
||||
import { useEffect, useRef } from "react";
|
||||
import { usePanelRef } from "react-resizable-panels";
|
||||
import { ResizableGroup, ResizablePanel, ResizableSeparator } from "@reactive-resume/ui/components/resizable";
|
||||
@@ -14,9 +13,10 @@ import {
|
||||
useResumeCleanup,
|
||||
useResumeStore,
|
||||
useResumeUpdateSubscription,
|
||||
} from "@/components/resume/builder-resume-draft";
|
||||
} from "@/features/resume/builder/draft";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { orpc } from "@/libs/orpc/client";
|
||||
import { createNoindexFollowMeta } from "@/libs/seo";
|
||||
import { BuilderHeader } from "./-components/header";
|
||||
import { BuilderSidebarLeft } from "./-sidebar/left";
|
||||
import { BuilderSidebarRight } from "./-sidebar/right";
|
||||
@@ -37,14 +37,16 @@ export const Route = createFileRoute("/builder/$resumeId")({
|
||||
},
|
||||
loader: async ({ params, context }) => {
|
||||
const [layout, resume] = await Promise.all([
|
||||
getBuilderLayoutServerFn(),
|
||||
getBuilderLayout(),
|
||||
context.queryClient.ensureQueryData(orpc.resume.getById.queryOptions({ input: { id: params.resumeId } })),
|
||||
]);
|
||||
|
||||
return { layout, name: resume.name };
|
||||
},
|
||||
head: ({ loaderData }) => ({
|
||||
meta: loaderData ? [{ title: `${loaderData.name} - Reactive Resume` }] : undefined,
|
||||
meta: loaderData
|
||||
? [{ title: `${loaderData.name} - Reactive Resume` }, createNoindexFollowMeta()]
|
||||
: [createNoindexFollowMeta()],
|
||||
}),
|
||||
});
|
||||
|
||||
@@ -116,7 +118,7 @@ function BuilderLayoutShell({ initialLayout }: BuilderLayoutShellProps) {
|
||||
const nextLayout = mapPanelLayoutToBuilderLayout(layout);
|
||||
if (!canPersistLayoutRef.current) return;
|
||||
setLayout(nextLayout);
|
||||
void setBuilderLayoutServerFn({ data: nextLayout });
|
||||
setBuilderLayout(nextLayout);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
@@ -171,14 +173,13 @@ function BuilderLayoutShell({ initialLayout }: BuilderLayoutShellProps) {
|
||||
);
|
||||
}
|
||||
|
||||
const setBuilderLayoutServerFn = createServerFn({ method: "POST" })
|
||||
.inputValidator((data): BuilderLayout => parseBuilderLayoutCookie(JSON.stringify(data)))
|
||||
.handler(async ({ data }) => {
|
||||
setCookie(BUILDER_LAYOUT_COOKIE_NAME, JSON.stringify(data), { path: "/" });
|
||||
});
|
||||
const setBuilderLayout = (data: BuilderLayout) => {
|
||||
const layout = parseBuilderLayoutCookie(JSON.stringify(data));
|
||||
Cookies.set(BUILDER_LAYOUT_COOKIE_NAME, JSON.stringify(layout), { path: "/" });
|
||||
};
|
||||
|
||||
const getBuilderLayoutServerFn = createServerFn({ method: "GET" }).handler(async (): Promise<BuilderLayout> => {
|
||||
const layout = getCookie(BUILDER_LAYOUT_COOKIE_NAME);
|
||||
const getBuilderLayout = (): BuilderLayout => {
|
||||
const layout = Cookies.get(BUILDER_LAYOUT_COOKIE_NAME);
|
||||
if (!layout) return DEFAULT_BUILDER_LAYOUT;
|
||||
return parseBuilderLayoutCookie(layout);
|
||||
});
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user