diff --git a/src/components/resume/shared/items/awards-item.tsx b/src/components/resume/shared/items/awards-item.tsx index ff7005fe1..a7e26f960 100644 --- a/src/components/resume/shared/items/awards-item.tsx +++ b/src/components/resume/shared/items/awards-item.tsx @@ -15,10 +15,10 @@ export function AwardsItem({ className, ...item }: AwardsItemProps) {

{item.title}

-

{item.date}

+

{item.date}

-

{item.awarder}

+

{item.awarder}

diff --git a/src/components/resume/shared/items/certifications-item.tsx b/src/components/resume/shared/items/certifications-item.tsx index 63feee165..347ab96c6 100644 --- a/src/components/resume/shared/items/certifications-item.tsx +++ b/src/components/resume/shared/items/certifications-item.tsx @@ -15,10 +15,10 @@ export function CertificationsItem({ className, ...item }: CertificationsItemPro

{item.title}

-

{item.date}

+

{item.date}

-

{item.issuer}

+

{item.issuer}

diff --git a/src/components/resume/shared/items/education-item.tsx b/src/components/resume/shared/items/education-item.tsx index c7af6591c..ec390c4e7 100644 --- a/src/components/resume/shared/items/education-item.tsx +++ b/src/components/resume/shared/items/education-item.tsx @@ -15,13 +15,13 @@ export function EducationItem({ className, ...item }: EducationItemProps) {

{item.school}

-

+

{[item.degree, item.grade].filter(Boolean).join(" • ")}

-

{item.area}

-

+

{item.area}

+

{[item.location, item.period].filter(Boolean).join(" • ")}

diff --git a/src/components/resume/shared/items/experience-item.tsx b/src/components/resume/shared/items/experience-item.tsx index c630de67f..438b3ca11 100644 --- a/src/components/resume/shared/items/experience-item.tsx +++ b/src/components/resume/shared/items/experience-item.tsx @@ -15,11 +15,11 @@ export function ExperienceItem({ className, ...item }: ExperienceItemProps) {

{item.company}

-

{item.location}

+

{item.location}

-

{item.position}

-

{item.period}

+

{item.position}

+

{item.period}

diff --git a/src/components/resume/shared/items/interests-item.tsx b/src/components/resume/shared/items/interests-item.tsx index 1ea09f7b3..b85fcf16c 100644 --- a/src/components/resume/shared/items/interests-item.tsx +++ b/src/components/resume/shared/items/interests-item.tsx @@ -11,7 +11,7 @@ export function InterestsItem({ className, ...item }: InterestsItemProps) {
-

+

{item.name}

diff --git a/src/components/resume/shared/items/languages-item.tsx b/src/components/resume/shared/items/languages-item.tsx index 893c1f111..1e29fdb4b 100644 --- a/src/components/resume/shared/items/languages-item.tsx +++ b/src/components/resume/shared/items/languages-item.tsx @@ -10,10 +10,10 @@ export function LanguagesItem({ className, ...item }: LanguagesItemProps) { return (
-

+

{item.language}

-

{item.fluency}

+

{item.fluency}

diff --git a/src/components/resume/shared/items/profiles-item.tsx b/src/components/resume/shared/items/profiles-item.tsx index 91bd3bc45..23d4e55fc 100644 --- a/src/components/resume/shared/items/profiles-item.tsx +++ b/src/components/resume/shared/items/profiles-item.tsx @@ -12,7 +12,7 @@ export function ProfilesItem({ className, ...item }: ProfilesItemProps) {
-

+

{item.network}

diff --git a/src/components/resume/shared/items/projects-item.tsx b/src/components/resume/shared/items/projects-item.tsx index e62963585..05586106c 100644 --- a/src/components/resume/shared/items/projects-item.tsx +++ b/src/components/resume/shared/items/projects-item.tsx @@ -15,7 +15,7 @@ export function ProjectsItem({ className, ...item }: ProjectsItemProps) {

{item.name}

-

{item.period}

+

{item.period}

diff --git a/src/components/resume/shared/items/publications-item.tsx b/src/components/resume/shared/items/publications-item.tsx index a238fca34..3c35dc4f9 100644 --- a/src/components/resume/shared/items/publications-item.tsx +++ b/src/components/resume/shared/items/publications-item.tsx @@ -15,10 +15,10 @@ export function PublicationsItem({ className, ...item }: PublicationsItemProps)

{item.title}

-

{item.date}

+

{item.date}

-

{item.publisher}

+

{item.publisher}

diff --git a/src/components/resume/shared/items/references-item.tsx b/src/components/resume/shared/items/references-item.tsx index fef55eebe..f85cd4e41 100644 --- a/src/components/resume/shared/items/references-item.tsx +++ b/src/components/resume/shared/items/references-item.tsx @@ -12,17 +12,17 @@ export function ReferencesItem({ className, ...item }: ReferencesItemProps) {
-

+

{item.name}

-

{item.position}

+

{item.position}

-
{item.phone}
+

{item.phone}

diff --git a/src/components/resume/shared/items/skills-item.tsx b/src/components/resume/shared/items/skills-item.tsx index 2e4ece104..78cbed476 100644 --- a/src/components/resume/shared/items/skills-item.tsx +++ b/src/components/resume/shared/items/skills-item.tsx @@ -12,13 +12,13 @@ export function SkillsItem({ className, ...item }: SkillsItemProps) {
-

+

{item.name}

-

{item.proficiency}

+

{item.proficiency}

{item.keywords.join(", ")}
diff --git a/src/components/resume/shared/items/volunteer-item.tsx b/src/components/resume/shared/items/volunteer-item.tsx index ff3740a48..4cc1e9187 100644 --- a/src/components/resume/shared/items/volunteer-item.tsx +++ b/src/components/resume/shared/items/volunteer-item.tsx @@ -15,10 +15,10 @@ export function VolunteerItem({ className, ...item }: VolunteerItemProps) {

{item.organization}

-

{item.period}

+

{item.period}

-

{item.location}

+

{item.location}

diff --git a/src/integrations/import/reactive-resume-v4-json.tsx b/src/integrations/import/reactive-resume-v4-json.tsx index db37cfadf..9a278d186 100644 --- a/src/integrations/import/reactive-resume-v4-json.tsx +++ b/src/integrations/import/reactive-resume-v4-json.tsx @@ -236,8 +236,8 @@ type V4ResumeData = { items: Array<{ id: string; visible: boolean; - language?: string; - fluency?: string; + name?: string; + description?: string; level?: number; }>; }; @@ -391,6 +391,20 @@ type V4ResumeData = { }; }; +// Transform layout section ID from V4 format to new format +// V4 uses "custom.{id}" for custom sections, new format just uses "{id}" +const transformLayoutSectionId = (id: string): string => { + if (id.startsWith("custom.")) return id.slice(7); + return id; +}; + +// Transform layout column by stripping "custom." prefix from section IDs +const transformLayoutColumn = (column: string[]): string[] => { + return column + .filter((id) => id !== "summary") // Summary is handled separately + .map(transformLayoutSectionId); +}; + export class ReactiveResumeV4JSONImporter { parse(json: string): ResumeData { try { @@ -532,12 +546,12 @@ export class ReactiveResumeV4JSONImporter { columns: v4Data.sections.languages?.columns ?? 1, hidden: !(v4Data.sections.languages?.visible ?? true), items: (v4Data.sections.languages?.items ?? []) - .filter((item) => item.language && item.language.length > 0) + .filter((item) => item.name && item.name.length > 0) .map((item) => ({ id: item.id ?? generateId(), hidden: !(item.visible ?? true), - language: item.language!, - fluency: item.fluency ?? "", + language: item.name!, + fluency: item.description ?? "", level: clampLevel(item.level ?? 0), })), }, @@ -680,12 +694,12 @@ export class ReactiveResumeV4JSONImporter { layout: { sidebarWidth: clampSidebarWidth(35), pages: (v4Data.metadata.layout ?? []).map((page) => { - const main = page[0] ?? []; - const sidebar = page[1] ?? []; + const main = transformLayoutColumn(page[0] ?? []); + const sidebar = transformLayoutColumn(page[1] ?? []); return { fullWidth: sidebar.length === 0, - main: main.filter((id) => id !== "summary"), - sidebar: sidebar, + main, + sidebar, }; }), }, diff --git a/src/integrations/orpc/services/resume.ts b/src/integrations/orpc/services/resume.ts index c09dbd576..3da5e5bbd 100644 --- a/src/integrations/orpc/services/resume.ts +++ b/src/integrations/orpc/services/resume.ts @@ -147,13 +147,19 @@ export const resumeService = { if (!resume) throw new ORPCError("NOT_FOUND"); - // Convert picture URL to base64 data, so there's no fetching required on the client. - const url = resume.data.picture.url.replace(env.APP_URL, "http://localhost:3000"); - const base64 = await fetch(url) - .then((res) => res.arrayBuffer()) - .then((buffer) => Buffer.from(buffer).toString("base64")); + try { + if (!resume.data.picture.url) throw new Error("Picture is not available"); - resume.data.picture.url = `data:image/jpeg;base64,${base64}`; + // Convert picture URL to base64 data, so there's no fetching required on the client. + const url = resume.data.picture.url.replace(env.APP_URL, "http://localhost:3000"); + const base64 = await fetch(url) + .then((res) => res.arrayBuffer()) + .then((buffer) => Buffer.from(buffer).toString("base64")); + + resume.data.picture.url = `data:image/jpeg;base64,${base64}`; + } catch { + // Ignore errors, as the picture is not always available + } return resume; },