mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2026-07-16 07:58:10 +10:00
Feature: Implement a new custom section type: summary (#2657)
* feat: add summaryItemSchema for custom summary section type * feat: add CreateSummaryItemDialog and UpdateSummaryItemDialog * feat: register summary item dialog types in store * feat: route summary item dialogs in manager * feat: add SummaryItem render component * feat: handle summary type in renderItemByType and hide title for summary sections * feat: handle summary type in sidebar helpers * feat: add summary to custom section type options * fix: update type definitions to support CustomSectionType for summary sections * chore: extract new i18n strings for summary section * style: apply biome formatting fixes * chore: remove TODO.md file containing outdated feature specifications
This commit is contained in:
@@ -27,14 +27,25 @@ import {
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { useDialogStore } from "@/dialogs/store";
|
||||
import { useConfirm } from "@/hooks/use-confirm";
|
||||
import type { CustomSection, CustomSectionItem as CustomSectionItemType, SectionType } from "@/schema/resume/data";
|
||||
import type {
|
||||
CustomSection,
|
||||
CustomSectionItem as CustomSectionItemType,
|
||||
CustomSectionType,
|
||||
} from "@/schema/resume/data";
|
||||
import { getSectionTitle } from "@/utils/resume/section";
|
||||
import { cn } from "@/utils/style";
|
||||
import { SectionBase } from "../shared/section-base";
|
||||
import { SectionAddItemButton, SectionItem } from "../shared/section-item";
|
||||
|
||||
function getItemTitle(type: SectionType, item: CustomSectionItemType): string {
|
||||
function getItemTitle(type: CustomSectionType, item: CustomSectionItemType): string {
|
||||
return match(type)
|
||||
.with("summary", () => {
|
||||
if ("content" in item) {
|
||||
const stripped = item.content.replace(/<[^>]*>/g, "").trim();
|
||||
return stripped.length > 50 ? `${stripped.slice(0, 50)}...` : stripped || "Summary";
|
||||
}
|
||||
return "Summary";
|
||||
})
|
||||
.with("profiles", () => ("network" in item ? item.network : ""))
|
||||
.with("experience", () => ("company" in item ? item.company : ""))
|
||||
.with("education", () => ("school" in item ? item.school : ""))
|
||||
@@ -50,8 +61,9 @@ function getItemTitle(type: SectionType, item: CustomSectionItemType): string {
|
||||
.exhaustive();
|
||||
}
|
||||
|
||||
function getItemSubtitle(type: SectionType, item: CustomSectionItemType): string | undefined {
|
||||
function getItemSubtitle(type: CustomSectionType, item: CustomSectionItemType): string | undefined {
|
||||
return match(type)
|
||||
.with("summary", () => undefined)
|
||||
.with("profiles", () => ("username" in item ? item.username : undefined))
|
||||
.with("experience", () => ("position" in item ? item.position : undefined))
|
||||
.with("education", () => ("degree" in item ? item.degree : undefined))
|
||||
|
||||
@@ -30,7 +30,12 @@ import {
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import { useDialogStore } from "@/dialogs/store";
|
||||
import { useConfirm } from "@/hooks/use-confirm";
|
||||
import type { SectionItem as SectionItemType, SectionType } from "@/schema/resume/data";
|
||||
import type {
|
||||
CustomSectionItem,
|
||||
CustomSectionType,
|
||||
SectionItem as SectionItemType,
|
||||
SectionType,
|
||||
} from "@/schema/resume/data";
|
||||
import {
|
||||
addItemToSection,
|
||||
createCustomSectionWithItem,
|
||||
@@ -46,8 +51,8 @@ import { cn } from "@/utils/style";
|
||||
// ============================================================================
|
||||
|
||||
type MoveItemSubmenuProps = {
|
||||
type: SectionType;
|
||||
item: SectionItemType;
|
||||
type: CustomSectionType;
|
||||
item: CustomSectionItem | SectionItemType;
|
||||
customSectionId?: string;
|
||||
};
|
||||
|
||||
@@ -153,15 +158,21 @@ function MoveItemSubmenu({ type, item, customSectionId }: MoveItemSubmenuProps)
|
||||
// SectionItem Component
|
||||
// ============================================================================
|
||||
|
||||
type Props<T extends SectionItemType> = {
|
||||
type: SectionType;
|
||||
type Props<T extends CustomSectionItem | SectionItemType> = {
|
||||
type: CustomSectionType;
|
||||
item: T;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
customSectionId?: string;
|
||||
};
|
||||
|
||||
export function SectionItem<T extends SectionItemType>({ type, item, title, subtitle, customSectionId }: Props<T>) {
|
||||
export function SectionItem<T extends CustomSectionItem | SectionItemType>({
|
||||
type,
|
||||
item,
|
||||
title,
|
||||
subtitle,
|
||||
customSectionId,
|
||||
}: Props<T>) {
|
||||
const confirm = useConfirm();
|
||||
const controls = useDragControls();
|
||||
const { openDialog } = useDialogStore();
|
||||
@@ -176,7 +187,8 @@ export function SectionItem<T extends SectionItemType>({ type, item, title, subt
|
||||
if (index === -1) return;
|
||||
section.items[index].hidden = !section.items[index].hidden;
|
||||
} else {
|
||||
const section = draft.sections[type];
|
||||
// Type assertion: when customSectionId is not provided, type is always a built-in SectionType
|
||||
const section = draft.sections[type as SectionType];
|
||||
if (!("items" in section)) return;
|
||||
const index = section.items.findIndex((_item) => _item.id === item.id);
|
||||
if (index === -1) return;
|
||||
@@ -211,7 +223,8 @@ export function SectionItem<T extends SectionItemType>({ type, item, title, subt
|
||||
if (index === -1) return;
|
||||
section.items.splice(index, 1);
|
||||
} else {
|
||||
const section = draft.sections[type];
|
||||
// Type assertion: when customSectionId is not provided, type is always a built-in SectionType
|
||||
const section = draft.sections[type as SectionType];
|
||||
if (!("items" in section)) return;
|
||||
const index = section.items.findIndex((_item) => _item.id === item.id);
|
||||
if (index === -1) return;
|
||||
@@ -298,7 +311,7 @@ export function SectionItem<T extends SectionItemType>({ type, item, title, subt
|
||||
}
|
||||
|
||||
type AddButtonProps = Omit<ButtonProps, "type"> & {
|
||||
type: SectionType | "custom";
|
||||
type: CustomSectionType | "custom";
|
||||
customSectionId?: string;
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user