@ginia/ui 0.1.8 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. package/dist/components/domain/resume/resume-preview/resume-preview.cjs +2 -3
  2. package/dist/components/domain/resume/resume-preview/resume-preview.cjs.map +1 -1
  3. package/dist/components/domain/resume/resume-preview/resume-preview.js +2 -3
  4. package/dist/components/domain/resume/resume-preview/resume-preview.js.map +1 -1
  5. package/dist/components/domain/resume/resume-preview/sections/experience-education.cjs +6 -13
  6. package/dist/components/domain/resume/resume-preview/sections/experience-education.cjs.map +1 -1
  7. package/dist/components/domain/resume/resume-preview/sections/experience-education.js +6 -13
  8. package/dist/components/domain/resume/resume-preview/sections/experience-education.js.map +1 -1
  9. package/dist/components/domain/resume/resume-preview/sections/header-preview.cjs +17 -2
  10. package/dist/components/domain/resume/resume-preview/sections/header-preview.cjs.map +1 -1
  11. package/dist/components/domain/resume/resume-preview/sections/header-preview.js +17 -2
  12. package/dist/components/domain/resume/resume-preview/sections/header-preview.js.map +1 -1
  13. package/dist/components/domain/resume/resume.cjs +6 -1
  14. package/dist/components/domain/resume/resume.cjs.map +1 -1
  15. package/dist/components/domain/resume/resume.js +6 -1
  16. package/dist/components/domain/resume/resume.js.map +1 -1
  17. package/dist/components/domain/resume/types.cjs.map +1 -1
  18. package/dist/components/domain/resume/types.d.cts +1 -0
  19. package/dist/components/domain/resume/types.d.ts +1 -0
  20. package/package.json +1 -1
@@ -70,10 +70,9 @@ const ResumePreview = React.forwardRef(
70
70
  hideFields
71
71
  }
72
72
  ),
73
- /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-8 grid grid-cols-1 gap-10 lg:grid-cols-12", children: [
73
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-8 mb-8 grid grid-cols-1 gap-10 lg:grid-cols-12", children: [
74
74
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "space-y-8 lg:col-span-4 lg:pr-6", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_contact_skills.ContactSkills, { data, hideFields, hideSections }) }),
75
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "absolute bottom-16 left-[33.33%] top-48 hidden w-px bg-border/40 lg:block" }),
76
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "space-y-8 lg:col-span-8", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
75
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "space-y-8 lg:col-span-8 lg:border-l lg:border-border/40 lg:pl-8", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
77
76
  import_experience_education.ExperienceEducation,
78
77
  {
79
78
  data,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/components/domain/resume/resume-preview/resume-preview.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { CandidateProfile } from \"../types\";\nimport { Background } from \"../../../ui\";\nimport { cn } from \"../../../../lib/utils\";\nimport { HeaderPreview } from \"./sections/header-preview\";\nimport { ContactSkills } from \"./sections/contact-skills\";\nimport { ExperienceEducation } from \"./sections/experience-education\";\nimport { FooterPreview } from \"./sections/footer-preview\";\n\nexport interface ResumePreviewProps {\n data: CandidateProfile;\n headerSlot?: React.ReactNode;\n theme?: string;\n hideFields?: string[];\n hideSections?: string[];\n showTopBar?: boolean;\n className?: string;\n}\n\nexport const ResumePreview = React.forwardRef<HTMLDivElement, ResumePreviewProps>(\n function ResumePreview(\n { data, headerSlot, theme, hideFields = [], hideSections = [], showTopBar = true, className },\n ref,\n ) {\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div\n ref={ref}\n id=\"resume-capture-area\"\n className={cn(\n \"relative mx-auto flex min-h-[1056px] w-full flex-col rounded-sm border border-border bg-card p-8 text-card-foreground shadow-2xl sm:p-12 md:p-14\",\n className,\n )}\n >\n <Background />\n {showTopBar && (\n <div\n className={`absolute left-0 top-0 h-2 w-full ${theme ? \"\" : \"bg-gradient-to-r from-primary to-primary/50\"}`}\n style={themeStyle}\n />\n )}\n {/* Content layer — above background */}\n <div className=\"relative z-10\">\n {/* Subtle decorative top bar */}\n\n\n {/* Header Profile */}\n {!hideSections.includes(\"Información personal\") && (\n <HeaderPreview\n data={data}\n headerSlot={headerSlot}\n theme={theme}\n hideFields={hideFields}\n />\n )}\n\n {/* Main Content Layout */}\n <div className=\"mt-8 grid grid-cols-1 gap-10 lg:grid-cols-12\">\n {/* Left Column (4/12) */}\n <div className=\"space-y-8 lg:col-span-4 lg:pr-6\">\n <ContactSkills data={data} hideFields={hideFields} hideSections={hideSections} />\n </div>\n\n {/* Vertical Divider for desktop */}\n <div className=\"absolute bottom-16 left-[33.33%] top-48 hidden w-px bg-border/40 lg:block\" />\n\n {/* Right Column (8/12) */}\n <div className=\"space-y-8 lg:col-span-8\">\n <ExperienceEducation\n data={data}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n />\n </div>\n </div>\n\n <FooterPreview />\n </div>\n </div>\n );\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCQ;AAnCR,YAAuB;AAEvB,gBAA2B;AAC3B,mBAAmB;AACnB,4BAA8B;AAC9B,4BAA8B;AAC9B,kCAAoC;AACpC,4BAA8B;AAYvB,MAAM,gBAAgB,MAAM;AAAA,EACjC,SAASA,eACP,EAAE,MAAM,YAAY,OAAO,aAAa,CAAC,GAAG,eAAe,CAAC,GAAG,aAAa,MAAM,UAAU,GAC5F,KACA;AACA,UAAM,aAAa,QAAQ,EAAE,iBAAiB,MAAM,IAAI;AAExD,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,IAAG;AAAA,QACH,eAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QAEA;AAAA,sDAAC,wBAAW;AAAA,UACX,cACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,oCAAoC,QAAQ,KAAK,6CAA6C;AAAA,cACzG,OAAO;AAAA;AAAA,UACT;AAAA,UAGF,6CAAC,SAAI,WAAU,iBAKZ;AAAA,aAAC,aAAa,SAAS,yBAAsB,KAC5C;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA;AAAA,YACF;AAAA,YAIF,6CAAC,SAAI,WAAU,gDAEb;AAAA,0DAAC,SAAI,WAAU,mCACb,sDAAC,uCAAc,MAAY,YAAwB,cAA4B,GACjF;AAAA,cAGA,4CAAC,SAAI,WAAU,6EAA4E;AAAA,cAG3F,4CAAC,SAAI,WAAU,2BACb;AAAA,gBAAC;AAAA;AAAA,kBACC;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA;AAAA,cACF,GACF;AAAA,eACF;AAAA,YAEA,4CAAC,uCAAc;AAAA,aACjB;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;","names":["ResumePreview"]}
1
+ {"version":3,"sources":["../../../../../src/components/domain/resume/resume-preview/resume-preview.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { CandidateProfile } from \"../types\";\nimport { Background } from \"../../../ui\";\nimport { cn } from \"../../../../lib/utils\";\nimport { HeaderPreview } from \"./sections/header-preview\";\nimport { ContactSkills } from \"./sections/contact-skills\";\nimport { ExperienceEducation } from \"./sections/experience-education\";\nimport { FooterPreview } from \"./sections/footer-preview\";\n\nexport interface ResumePreviewProps {\n data: CandidateProfile;\n headerSlot?: React.ReactNode;\n theme?: string;\n hideFields?: string[];\n hideSections?: string[];\n showTopBar?: boolean;\n className?: string;\n}\n\nexport const ResumePreview = React.forwardRef<HTMLDivElement, ResumePreviewProps>(\n function ResumePreview(\n { data, headerSlot, theme, hideFields = [], hideSections = [], showTopBar = true, className },\n ref,\n ) {\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div\n ref={ref}\n id=\"resume-capture-area\"\n className={cn(\n \"relative mx-auto flex min-h-[1056px] w-full flex-col rounded-sm border border-border bg-card p-8 text-card-foreground shadow-2xl sm:p-12 md:p-14\",\n className,\n )}\n >\n <Background />\n {showTopBar && (\n <div\n className={`absolute left-0 top-0 h-2 w-full ${theme ? \"\" : \"bg-gradient-to-r from-primary to-primary/50\"}`}\n style={themeStyle}\n />\n )}\n {/* Content layer — above background */}\n <div className=\"relative z-10\">\n {/* Subtle decorative top bar */}\n\n\n {/* Header Profile */}\n {!hideSections.includes(\"Información personal\") && (\n <HeaderPreview\n data={data}\n headerSlot={headerSlot}\n theme={theme}\n hideFields={hideFields}\n />\n )}\n\n {/* Main Content Layout */}\n <div className=\"mt-8 mb-8 grid grid-cols-1 gap-10 lg:grid-cols-12\">\n {/* Left Column (4/12) */}\n <div className=\"space-y-8 lg:col-span-4 lg:pr-6\">\n <ContactSkills data={data} hideFields={hideFields} hideSections={hideSections} />\n </div>\n\n {/* Right Column (8/12) - border-l acts as divider, avoids overlap with long content */}\n <div className=\"space-y-8 lg:col-span-8 lg:border-l lg:border-border/40 lg:pl-8\">\n <ExperienceEducation\n data={data}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n />\n </div>\n </div>\n\n <FooterPreview />\n </div>\n </div>\n );\n },\n);\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAmCQ;AAnCR,YAAuB;AAEvB,gBAA2B;AAC3B,mBAAmB;AACnB,4BAA8B;AAC9B,4BAA8B;AAC9B,kCAAoC;AACpC,4BAA8B;AAYvB,MAAM,gBAAgB,MAAM;AAAA,EACjC,SAASA,eACP,EAAE,MAAM,YAAY,OAAO,aAAa,CAAC,GAAG,eAAe,CAAC,GAAG,aAAa,MAAM,UAAU,GAC5F,KACA;AACA,UAAM,aAAa,QAAQ,EAAE,iBAAiB,MAAM,IAAI;AAExD,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,IAAG;AAAA,QACH,eAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QAEA;AAAA,sDAAC,wBAAW;AAAA,UACX,cACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,oCAAoC,QAAQ,KAAK,6CAA6C;AAAA,cACzG,OAAO;AAAA;AAAA,UACT;AAAA,UAGF,6CAAC,SAAI,WAAU,iBAKZ;AAAA,aAAC,aAAa,SAAS,yBAAsB,KAC5C;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA;AAAA,YACF;AAAA,YAIF,6CAAC,SAAI,WAAU,qDAEb;AAAA,0DAAC,SAAI,WAAU,mCACb,sDAAC,uCAAc,MAAY,YAAwB,cAA4B,GACjF;AAAA,cAGA,4CAAC,SAAI,WAAU,mEACb;AAAA,gBAAC;AAAA;AAAA,kBACC;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA;AAAA,cACF,GACF;AAAA,eACF;AAAA,YAEA,4CAAC,uCAAc;AAAA,aACjB;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;","names":["ResumePreview"]}
@@ -37,10 +37,9 @@ const ResumePreview = React.forwardRef(
37
37
  hideFields
38
38
  }
39
39
  ),
40
- /* @__PURE__ */ jsxs("div", { className: "mt-8 grid grid-cols-1 gap-10 lg:grid-cols-12", children: [
40
+ /* @__PURE__ */ jsxs("div", { className: "mt-8 mb-8 grid grid-cols-1 gap-10 lg:grid-cols-12", children: [
41
41
  /* @__PURE__ */ jsx("div", { className: "space-y-8 lg:col-span-4 lg:pr-6", children: /* @__PURE__ */ jsx(ContactSkills, { data, hideFields, hideSections }) }),
42
- /* @__PURE__ */ jsx("div", { className: "absolute bottom-16 left-[33.33%] top-48 hidden w-px bg-border/40 lg:block" }),
43
- /* @__PURE__ */ jsx("div", { className: "space-y-8 lg:col-span-8", children: /* @__PURE__ */ jsx(
42
+ /* @__PURE__ */ jsx("div", { className: "space-y-8 lg:col-span-8 lg:border-l lg:border-border/40 lg:pl-8", children: /* @__PURE__ */ jsx(
44
43
  ExperienceEducation,
45
44
  {
46
45
  data,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../src/components/domain/resume/resume-preview/resume-preview.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { CandidateProfile } from \"../types\";\nimport { Background } from \"../../../ui\";\nimport { cn } from \"../../../../lib/utils\";\nimport { HeaderPreview } from \"./sections/header-preview\";\nimport { ContactSkills } from \"./sections/contact-skills\";\nimport { ExperienceEducation } from \"./sections/experience-education\";\nimport { FooterPreview } from \"./sections/footer-preview\";\n\nexport interface ResumePreviewProps {\n data: CandidateProfile;\n headerSlot?: React.ReactNode;\n theme?: string;\n hideFields?: string[];\n hideSections?: string[];\n showTopBar?: boolean;\n className?: string;\n}\n\nexport const ResumePreview = React.forwardRef<HTMLDivElement, ResumePreviewProps>(\n function ResumePreview(\n { data, headerSlot, theme, hideFields = [], hideSections = [], showTopBar = true, className },\n ref,\n ) {\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div\n ref={ref}\n id=\"resume-capture-area\"\n className={cn(\n \"relative mx-auto flex min-h-[1056px] w-full flex-col rounded-sm border border-border bg-card p-8 text-card-foreground shadow-2xl sm:p-12 md:p-14\",\n className,\n )}\n >\n <Background />\n {showTopBar && (\n <div\n className={`absolute left-0 top-0 h-2 w-full ${theme ? \"\" : \"bg-gradient-to-r from-primary to-primary/50\"}`}\n style={themeStyle}\n />\n )}\n {/* Content layer — above background */}\n <div className=\"relative z-10\">\n {/* Subtle decorative top bar */}\n\n\n {/* Header Profile */}\n {!hideSections.includes(\"Información personal\") && (\n <HeaderPreview\n data={data}\n headerSlot={headerSlot}\n theme={theme}\n hideFields={hideFields}\n />\n )}\n\n {/* Main Content Layout */}\n <div className=\"mt-8 grid grid-cols-1 gap-10 lg:grid-cols-12\">\n {/* Left Column (4/12) */}\n <div className=\"space-y-8 lg:col-span-4 lg:pr-6\">\n <ContactSkills data={data} hideFields={hideFields} hideSections={hideSections} />\n </div>\n\n {/* Vertical Divider for desktop */}\n <div className=\"absolute bottom-16 left-[33.33%] top-48 hidden w-px bg-border/40 lg:block\" />\n\n {/* Right Column (8/12) */}\n <div className=\"space-y-8 lg:col-span-8\">\n <ExperienceEducation\n data={data}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n />\n </div>\n </div>\n\n <FooterPreview />\n </div>\n </div>\n );\n },\n);\n"],"mappings":"AAmCQ,cAuBE,YAvBF;AAnCR,YAAY,WAAW;AAEvB,SAAS,kBAAkB;AAC3B,SAAS,UAAU;AACnB,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,qBAAqB;AAYvB,MAAM,gBAAgB,MAAM;AAAA,EACjC,SAASA,eACP,EAAE,MAAM,YAAY,OAAO,aAAa,CAAC,GAAG,eAAe,CAAC,GAAG,aAAa,MAAM,UAAU,GAC5F,KACA;AACA,UAAM,aAAa,QAAQ,EAAE,iBAAiB,MAAM,IAAI;AAExD,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,IAAG;AAAA,QACH,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QAEA;AAAA,8BAAC,cAAW;AAAA,UACX,cACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,oCAAoC,QAAQ,KAAK,6CAA6C;AAAA,cACzG,OAAO;AAAA;AAAA,UACT;AAAA,UAGF,qBAAC,SAAI,WAAU,iBAKZ;AAAA,aAAC,aAAa,SAAS,yBAAsB,KAC5C;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA;AAAA,YACF;AAAA,YAIF,qBAAC,SAAI,WAAU,gDAEb;AAAA,kCAAC,SAAI,WAAU,mCACb,8BAAC,iBAAc,MAAY,YAAwB,cAA4B,GACjF;AAAA,cAGA,oBAAC,SAAI,WAAU,6EAA4E;AAAA,cAG3F,oBAAC,SAAI,WAAU,2BACb;AAAA,gBAAC;AAAA;AAAA,kBACC;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA;AAAA,cACF,GACF;AAAA,eACF;AAAA,YAEA,oBAAC,iBAAc;AAAA,aACjB;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;","names":["ResumePreview"]}
1
+ {"version":3,"sources":["../../../../../src/components/domain/resume/resume-preview/resume-preview.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { CandidateProfile } from \"../types\";\nimport { Background } from \"../../../ui\";\nimport { cn } from \"../../../../lib/utils\";\nimport { HeaderPreview } from \"./sections/header-preview\";\nimport { ContactSkills } from \"./sections/contact-skills\";\nimport { ExperienceEducation } from \"./sections/experience-education\";\nimport { FooterPreview } from \"./sections/footer-preview\";\n\nexport interface ResumePreviewProps {\n data: CandidateProfile;\n headerSlot?: React.ReactNode;\n theme?: string;\n hideFields?: string[];\n hideSections?: string[];\n showTopBar?: boolean;\n className?: string;\n}\n\nexport const ResumePreview = React.forwardRef<HTMLDivElement, ResumePreviewProps>(\n function ResumePreview(\n { data, headerSlot, theme, hideFields = [], hideSections = [], showTopBar = true, className },\n ref,\n ) {\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div\n ref={ref}\n id=\"resume-capture-area\"\n className={cn(\n \"relative mx-auto flex min-h-[1056px] w-full flex-col rounded-sm border border-border bg-card p-8 text-card-foreground shadow-2xl sm:p-12 md:p-14\",\n className,\n )}\n >\n <Background />\n {showTopBar && (\n <div\n className={`absolute left-0 top-0 h-2 w-full ${theme ? \"\" : \"bg-gradient-to-r from-primary to-primary/50\"}`}\n style={themeStyle}\n />\n )}\n {/* Content layer — above background */}\n <div className=\"relative z-10\">\n {/* Subtle decorative top bar */}\n\n\n {/* Header Profile */}\n {!hideSections.includes(\"Información personal\") && (\n <HeaderPreview\n data={data}\n headerSlot={headerSlot}\n theme={theme}\n hideFields={hideFields}\n />\n )}\n\n {/* Main Content Layout */}\n <div className=\"mt-8 mb-8 grid grid-cols-1 gap-10 lg:grid-cols-12\">\n {/* Left Column (4/12) */}\n <div className=\"space-y-8 lg:col-span-4 lg:pr-6\">\n <ContactSkills data={data} hideFields={hideFields} hideSections={hideSections} />\n </div>\n\n {/* Right Column (8/12) - border-l acts as divider, avoids overlap with long content */}\n <div className=\"space-y-8 lg:col-span-8 lg:border-l lg:border-border/40 lg:pl-8\">\n <ExperienceEducation\n data={data}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n />\n </div>\n </div>\n\n <FooterPreview />\n </div>\n </div>\n );\n },\n);\n"],"mappings":"AAmCQ,cAuBE,YAvBF;AAnCR,YAAY,WAAW;AAEvB,SAAS,kBAAkB;AAC3B,SAAS,UAAU;AACnB,SAAS,qBAAqB;AAC9B,SAAS,qBAAqB;AAC9B,SAAS,2BAA2B;AACpC,SAAS,qBAAqB;AAYvB,MAAM,gBAAgB,MAAM;AAAA,EACjC,SAASA,eACP,EAAE,MAAM,YAAY,OAAO,aAAa,CAAC,GAAG,eAAe,CAAC,GAAG,aAAa,MAAM,UAAU,GAC5F,KACA;AACA,UAAM,aAAa,QAAQ,EAAE,iBAAiB,MAAM,IAAI;AAExD,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,IAAG;AAAA,QACH,WAAW;AAAA,UACT;AAAA,UACA;AAAA,QACF;AAAA,QAEA;AAAA,8BAAC,cAAW;AAAA,UACX,cACC;AAAA,YAAC;AAAA;AAAA,cACC,WAAW,oCAAoC,QAAQ,KAAK,6CAA6C;AAAA,cACzG,OAAO;AAAA;AAAA,UACT;AAAA,UAGF,qBAAC,SAAI,WAAU,iBAKZ;AAAA,aAAC,aAAa,SAAS,yBAAsB,KAC5C;AAAA,cAAC;AAAA;AAAA,gBACC;AAAA,gBACA;AAAA,gBACA;AAAA,gBACA;AAAA;AAAA,YACF;AAAA,YAIF,qBAAC,SAAI,WAAU,qDAEb;AAAA,kCAAC,SAAI,WAAU,mCACb,8BAAC,iBAAc,MAAY,YAAwB,cAA4B,GACjF;AAAA,cAGA,oBAAC,SAAI,WAAU,mEACb;AAAA,gBAAC;AAAA;AAAA,kBACC;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA;AAAA,cACF,GACF;AAAA,eACF;AAAA,YAEA,oBAAC,iBAAc;AAAA,aACjB;AAAA;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;","names":["ResumePreview"]}
@@ -83,7 +83,7 @@ function ExperienceEducation({
83
83
  !hideFields.includes("experience.title") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { className: "text-lg font-bold text-foreground", children: exp.title }),
84
84
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
85
85
  !hideFields.includes("experience.institution_name") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-base font-semibold text-primary", children: exp.institution_name }),
86
- (!hideFields.includes("experience.start_date") || !hideFields.includes("experience.end_date")) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0", children: [
86
+ (!hideFields.includes("experience.start_date") || !hideFields.includes("experience.end_date")) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge", children: [
87
87
  !hideFields.includes("experience.start_date") && exp.start_date,
88
88
  !hideFields.includes("experience.end_date") && exp.end_date && exp.end_date.toLowerCase() !== "presente" ? `- ${exp.end_date}` : null
89
89
  ].filter(Boolean).join(" ") })
@@ -114,7 +114,7 @@ function ExperienceEducation({
114
114
  !hideFields.includes("education.title") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { className: "text-lg font-bold text-foreground", children: edu.title }),
115
115
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
116
116
  !hideFields.includes("education.institution_name") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-base font-semibold text-primary", children: edu.institution_name }),
117
- (!hideFields.includes("education.start_date") || !hideFields.includes("education.end_date")) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0", children: [
117
+ (!hideFields.includes("education.start_date") || !hideFields.includes("education.end_date")) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge", children: [
118
118
  !hideFields.includes("education.start_date") && edu.start_date,
119
119
  !hideFields.includes("education.end_date") && edu.end_date && edu.end_date.toLowerCase() !== "presente" ? `- ${edu.end_date}` : null
120
120
  ].filter(Boolean).join(" ") })
@@ -145,7 +145,7 @@ function ExperienceEducation({
145
145
  !hideFields.includes("activities.title") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { className: "text-lg font-bold text-foreground", children: act.title }),
146
146
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
147
147
  !hideFields.includes("activities.institution_name") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-base font-semibold text-primary", children: act.institution_name }),
148
- (!hideFields.includes("activities.start_date") || !hideFields.includes("activities.end_date")) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0", children: [
148
+ (!hideFields.includes("activities.start_date") || !hideFields.includes("activities.end_date")) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge", children: [
149
149
  !hideFields.includes("activities.start_date") && act.start_date,
150
150
  !hideFields.includes("activities.end_date") && act.end_date && act.end_date.toLowerCase() !== "presente" ? `- ${act.end_date}` : null
151
151
  ].filter(Boolean).join(" ") })
@@ -161,22 +161,15 @@ function ExperienceEducation({
161
161
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_lucide_react.Award, { className: "h-6 w-6 text-primary" }),
162
162
  "Certificaciones"
163
163
  ] }),
164
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: certifications.map((cert) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
164
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "grid grid-cols-1 gap-4", children: certifications.map((cert) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
165
165
  "div",
166
166
  {
167
167
  className: "rounded-lg border border-border/60 bg-card p-4 shadow-sm transition-colors hover:border-primary/30 hover:shadow-md",
168
168
  children: [
169
- !hideFields.includes("certifications.title") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
170
- "h4",
171
- {
172
- className: "line-clamp-1 text-base font-bold text-foreground",
173
- title: cert.title,
174
- children: cert.title
175
- }
176
- ),
169
+ !hideFields.includes("certifications.title") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { className: "break-words text-base font-bold text-foreground", children: cert.title }),
177
170
  !hideFields.includes("certifications.institution_name") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mt-1 line-clamp-1 text-sm text-muted-foreground", children: cert.institution_name }),
178
171
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-4 flex items-center justify-between", children: [
179
- !hideFields.includes("certifications.date_awarded") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rounded-md bg-muted/50 px-2 py-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: cert.date_awarded }),
172
+ !hideFields.includes("certifications.date_awarded") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "rounded-md bg-muted/50 px-2 py-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground pdf-badge", children: cert.date_awarded }),
180
173
  cert.verified && !hideFields.includes("certifications.verified") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
181
174
  "span",
182
175
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/components/domain/resume/resume-preview/sections/experience-education.tsx"],"sourcesContent":["import { CandidateProfile } from \"../../types\";\nimport type { CVExperienceBaseItem, CVCertificationItem } from \"../../types\";\nimport { GraduationCap, Briefcase, Trophy, Award } from \"lucide-react\";\n\n/** Parsea una fecha (MM/YYYY, YYYY-MM o YYYY) a un valor numérico para ordenar (mayor = más reciente) */\nfunction parseDateToSortValue(dateStr: string | undefined): number {\n if (!dateStr || dateStr.toLowerCase() === \"presente\") return 0;\n // MM/YYYY\n const mmYyyy = dateStr.match(/^(\\d{1,2})\\/(\\d{4})$/);\n if (mmYyyy) return parseInt(mmYyyy[2], 10) * 12 + parseInt(mmYyyy[1], 10);\n // YYYY-MM o YYYY-MM-DD\n const yyyyMm = dateStr.match(/^(\\d{4})-(\\d{1,2})/);\n if (yyyyMm) return parseInt(yyyyMm[1], 10) * 12 + parseInt(yyyyMm[2], 10);\n // Solo año\n const year = dateStr.match(/\\d{4}/);\n if (year) return parseInt(year[0], 10) * 12;\n return 0;\n}\n\n/** Ordena descendente por fecha de fin; si no hay end_date (Presente), usa start_date y prioriza como más reciente */\nfunction sortByDateDesc<T extends CVExperienceBaseItem>(items: T[]): T[] {\n return [...items].sort((a, b) => {\n const aEnd = a.end_date?.toLowerCase();\n const bEnd = b.end_date?.toLowerCase();\n const aOngoing = !a.end_date || aEnd === \"presente\";\n const bOngoing = !b.end_date || bEnd === \"presente\";\n const aVal = aOngoing ? parseDateToSortValue(a.start_date) + 9999 * 12 : parseDateToSortValue(a.end_date);\n const bVal = bOngoing ? parseDateToSortValue(b.start_date) + 9999 * 12 : parseDateToSortValue(b.end_date);\n return bVal - aVal;\n });\n}\n\n/** Ordena certificaciones descendente por date_awarded */\nfunction sortCertificationsByDateDesc(items: CVCertificationItem[]): CVCertificationItem[] {\n return [...items].sort((a, b) => {\n const aVal = parseDateToSortValue(a.date_awarded);\n const bVal = parseDateToSortValue(b.date_awarded);\n return bVal - aVal;\n });\n}\n\ninterface ExperienceEducationProps {\n data: CandidateProfile;\n theme?: string;\n hideFields?: string[];\n hideSections?: string[];\n}\n\nexport function ExperienceEducation({\n data,\n theme,\n hideFields = [],\n hideSections = [],\n}: ExperienceEducationProps) {\n const experiences = sortByDateDesc(data.work_experience || []);\n const education = sortByDateDesc(data.education || []);\n const activities = sortByDateDesc(data.activities || []);\n const certifications = sortCertificationsByDateDesc(data.certifications || []);\n\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div className=\"space-y-12\">\n {/* Experience */}\n {experiences.length > 0 && !hideSections.includes(\"Experiencia laboral\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Briefcase className=\"h-6 w-6 text-primary\" />\n Experiencia Laboral\n </h3>\n <div className=\"space-y-8\">\n {experiences.map((exp) => (\n <div\n key={exp.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"experience.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{exp.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"experience.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {exp.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"experience.start_date\") ||\n !hideFields.includes(\"experience.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0\">\n {[\n !hideFields.includes(\"experience.start_date\") && exp.start_date,\n !hideFields.includes(\"experience.end_date\") &&\n exp.end_date &&\n exp.end_date.toLowerCase() !== \"presente\"\n ? `- ${exp.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {exp.description && !hideFields.includes(\"experience.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {exp.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Education */}\n {education.length > 0 && !hideSections.includes(\"Educación\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <GraduationCap className=\"h-6 w-6 text-primary\" />\n Educación\n </h3>\n <div className=\"space-y-8\">\n {education.map((edu) => (\n <div\n key={edu.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"education.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{edu.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"education.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {edu.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"education.start_date\") ||\n !hideFields.includes(\"education.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0\">\n {[\n !hideFields.includes(\"education.start_date\") && edu.start_date,\n !hideFields.includes(\"education.end_date\") &&\n edu.end_date &&\n edu.end_date.toLowerCase() !== \"presente\"\n ? `- ${edu.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {edu.description && !hideFields.includes(\"education.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {edu.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Activities */}\n {activities.length > 0 && !hideSections.includes(\"Actividades y Logros\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Trophy className=\"h-6 w-6 text-primary\" />\n Actividades y Logros\n </h3>\n <div className=\"space-y-8\">\n {activities.map((act) => (\n <div\n key={act.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"activities.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{act.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"activities.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {act.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"activities.start_date\") ||\n !hideFields.includes(\"activities.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0\">\n {[\n !hideFields.includes(\"activities.start_date\") && act.start_date,\n !hideFields.includes(\"activities.end_date\") &&\n act.end_date &&\n act.end_date.toLowerCase() !== \"presente\"\n ? `- ${act.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {act.description && !hideFields.includes(\"activities.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {act.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Certifications */}\n {certifications.length > 0 && !hideSections.includes(\"Certificaciones\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Award className=\"h-6 w-6 text-primary\" />\n Certificaciones\n </h3>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n {certifications.map((cert) => (\n <div\n key={cert.id}\n className=\"rounded-lg border border-border/60 bg-card p-4 shadow-sm transition-colors hover:border-primary/30 hover:shadow-md\"\n >\n {!hideFields.includes(\"certifications.title\") && (\n <h4\n className=\"line-clamp-1 text-base font-bold text-foreground\"\n title={cert.title}\n >\n {cert.title}\n </h4>\n )}\n {!hideFields.includes(\"certifications.institution_name\") && (\n <p className=\"mt-1 line-clamp-1 text-sm text-muted-foreground\">\n {cert.institution_name}\n </p>\n )}\n <div className=\"mt-4 flex items-center justify-between\">\n {!hideFields.includes(\"certifications.date_awarded\") && (\n <span className=\"rounded-md bg-muted/50 px-2 py-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground\">\n {cert.date_awarded}\n </span>\n )}\n {cert.verified && !hideFields.includes(\"certifications.verified\") && (\n <span\n className=\"pdf-badge rounded-full border px-2.5 py-1 text-xs font-bold transition-colors\"\n style={{\n backgroundColor: theme?.startsWith(\"#\") ? `${theme}15` : undefined,\n color: theme,\n borderColor: theme?.startsWith(\"#\") ? `${theme}30` : theme,\n }}\n >\n Verificado\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../../src/components/domain/resume/resume-preview/sections/experience-education.tsx"],"sourcesContent":["import { CandidateProfile } from \"../../types\";\nimport type { CVExperienceBaseItem, CVCertificationItem } from \"../../types\";\nimport { GraduationCap, Briefcase, Trophy, Award } from \"lucide-react\";\n\n/** Parsea una fecha (MM/YYYY, YYYY-MM o YYYY) a un valor numérico para ordenar (mayor = más reciente) */\nfunction parseDateToSortValue(dateStr: string | undefined): number {\n if (!dateStr || dateStr.toLowerCase() === \"presente\") return 0;\n // MM/YYYY\n const mmYyyy = dateStr.match(/^(\\d{1,2})\\/(\\d{4})$/);\n if (mmYyyy) return parseInt(mmYyyy[2], 10) * 12 + parseInt(mmYyyy[1], 10);\n // YYYY-MM o YYYY-MM-DD\n const yyyyMm = dateStr.match(/^(\\d{4})-(\\d{1,2})/);\n if (yyyyMm) return parseInt(yyyyMm[1], 10) * 12 + parseInt(yyyyMm[2], 10);\n // Solo año\n const year = dateStr.match(/\\d{4}/);\n if (year) return parseInt(year[0], 10) * 12;\n return 0;\n}\n\n/** Ordena descendente por fecha de fin; si no hay end_date (Presente), usa start_date y prioriza como más reciente */\nfunction sortByDateDesc<T extends CVExperienceBaseItem>(items: T[]): T[] {\n return [...items].sort((a, b) => {\n const aEnd = a.end_date?.toLowerCase();\n const bEnd = b.end_date?.toLowerCase();\n const aOngoing = !a.end_date || aEnd === \"presente\";\n const bOngoing = !b.end_date || bEnd === \"presente\";\n const aVal = aOngoing ? parseDateToSortValue(a.start_date) + 9999 * 12 : parseDateToSortValue(a.end_date);\n const bVal = bOngoing ? parseDateToSortValue(b.start_date) + 9999 * 12 : parseDateToSortValue(b.end_date);\n return bVal - aVal;\n });\n}\n\n/** Ordena certificaciones descendente por date_awarded */\nfunction sortCertificationsByDateDesc(items: CVCertificationItem[]): CVCertificationItem[] {\n return [...items].sort((a, b) => {\n const aVal = parseDateToSortValue(a.date_awarded);\n const bVal = parseDateToSortValue(b.date_awarded);\n return bVal - aVal;\n });\n}\n\ninterface ExperienceEducationProps {\n data: CandidateProfile;\n theme?: string;\n hideFields?: string[];\n hideSections?: string[];\n}\n\nexport function ExperienceEducation({\n data,\n theme,\n hideFields = [],\n hideSections = [],\n}: ExperienceEducationProps) {\n const experiences = sortByDateDesc(data.work_experience || []);\n const education = sortByDateDesc(data.education || []);\n const activities = sortByDateDesc(data.activities || []);\n const certifications = sortCertificationsByDateDesc(data.certifications || []);\n\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div className=\"space-y-12\">\n {/* Experience */}\n {experiences.length > 0 && !hideSections.includes(\"Experiencia laboral\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Briefcase className=\"h-6 w-6 text-primary\" />\n Experiencia Laboral\n </h3>\n <div className=\"space-y-8\">\n {experiences.map((exp) => (\n <div\n key={exp.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"experience.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{exp.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"experience.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {exp.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"experience.start_date\") ||\n !hideFields.includes(\"experience.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge\">\n {[\n !hideFields.includes(\"experience.start_date\") && exp.start_date,\n !hideFields.includes(\"experience.end_date\") &&\n exp.end_date &&\n exp.end_date.toLowerCase() !== \"presente\"\n ? `- ${exp.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {exp.description && !hideFields.includes(\"experience.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {exp.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Education */}\n {education.length > 0 && !hideSections.includes(\"Educación\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <GraduationCap className=\"h-6 w-6 text-primary\" />\n Educación\n </h3>\n <div className=\"space-y-8\">\n {education.map((edu) => (\n <div\n key={edu.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"education.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{edu.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"education.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {edu.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"education.start_date\") ||\n !hideFields.includes(\"education.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge\">\n {[\n !hideFields.includes(\"education.start_date\") && edu.start_date,\n !hideFields.includes(\"education.end_date\") &&\n edu.end_date &&\n edu.end_date.toLowerCase() !== \"presente\"\n ? `- ${edu.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {edu.description && !hideFields.includes(\"education.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {edu.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Activities */}\n {activities.length > 0 && !hideSections.includes(\"Actividades y Logros\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Trophy className=\"h-6 w-6 text-primary\" />\n Actividades y Logros\n </h3>\n <div className=\"space-y-8\">\n {activities.map((act) => (\n <div\n key={act.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"activities.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{act.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"activities.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {act.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"activities.start_date\") ||\n !hideFields.includes(\"activities.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge\">\n {[\n !hideFields.includes(\"activities.start_date\") && act.start_date,\n !hideFields.includes(\"activities.end_date\") &&\n act.end_date &&\n act.end_date.toLowerCase() !== \"presente\"\n ? `- ${act.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {act.description && !hideFields.includes(\"activities.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {act.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Certifications */}\n {certifications.length > 0 && !hideSections.includes(\"Certificaciones\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Award className=\"h-6 w-6 text-primary\" />\n Certificaciones\n </h3>\n <div className=\"grid grid-cols-1 gap-4\">\n {certifications.map((cert) => (\n <div\n key={cert.id}\n className=\"rounded-lg border border-border/60 bg-card p-4 shadow-sm transition-colors hover:border-primary/30 hover:shadow-md\"\n >\n {!hideFields.includes(\"certifications.title\") && (\n <h4 className=\"break-words text-base font-bold text-foreground\">\n {cert.title}\n </h4>\n )}\n {!hideFields.includes(\"certifications.institution_name\") && (\n <p className=\"mt-1 line-clamp-1 text-sm text-muted-foreground\">\n {cert.institution_name}\n </p>\n )}\n <div className=\"mt-4 flex items-center justify-between\">\n {!hideFields.includes(\"certifications.date_awarded\") && (\n <span className=\"rounded-md bg-muted/50 px-2 py-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground pdf-badge\">\n {cert.date_awarded}\n </span>\n )}\n {cert.verified && !hideFields.includes(\"certifications.verified\") && (\n <span\n className=\"pdf-badge rounded-full border px-2.5 py-1 text-xs font-bold transition-colors\"\n style={{\n backgroundColor: theme?.startsWith(\"#\") ? `${theme}15` : undefined,\n color: theme,\n borderColor: theme?.startsWith(\"#\") ? `${theme}30` : theme,\n }}\n >\n Verificado\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -60,7 +60,7 @@ function ExperienceEducation({
60
60
  !hideFields.includes("experience.title") && /* @__PURE__ */ jsx("h4", { className: "text-lg font-bold text-foreground", children: exp.title }),
61
61
  /* @__PURE__ */ jsxs("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
62
62
  !hideFields.includes("experience.institution_name") && /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-primary", children: exp.institution_name }),
63
- (!hideFields.includes("experience.start_date") || !hideFields.includes("experience.end_date")) && /* @__PURE__ */ jsx("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0", children: [
63
+ (!hideFields.includes("experience.start_date") || !hideFields.includes("experience.end_date")) && /* @__PURE__ */ jsx("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge", children: [
64
64
  !hideFields.includes("experience.start_date") && exp.start_date,
65
65
  !hideFields.includes("experience.end_date") && exp.end_date && exp.end_date.toLowerCase() !== "presente" ? `- ${exp.end_date}` : null
66
66
  ].filter(Boolean).join(" ") })
@@ -91,7 +91,7 @@ function ExperienceEducation({
91
91
  !hideFields.includes("education.title") && /* @__PURE__ */ jsx("h4", { className: "text-lg font-bold text-foreground", children: edu.title }),
92
92
  /* @__PURE__ */ jsxs("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
93
93
  !hideFields.includes("education.institution_name") && /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-primary", children: edu.institution_name }),
94
- (!hideFields.includes("education.start_date") || !hideFields.includes("education.end_date")) && /* @__PURE__ */ jsx("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0", children: [
94
+ (!hideFields.includes("education.start_date") || !hideFields.includes("education.end_date")) && /* @__PURE__ */ jsx("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge", children: [
95
95
  !hideFields.includes("education.start_date") && edu.start_date,
96
96
  !hideFields.includes("education.end_date") && edu.end_date && edu.end_date.toLowerCase() !== "presente" ? `- ${edu.end_date}` : null
97
97
  ].filter(Boolean).join(" ") })
@@ -122,7 +122,7 @@ function ExperienceEducation({
122
122
  !hideFields.includes("activities.title") && /* @__PURE__ */ jsx("h4", { className: "text-lg font-bold text-foreground", children: act.title }),
123
123
  /* @__PURE__ */ jsxs("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
124
124
  !hideFields.includes("activities.institution_name") && /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-primary", children: act.institution_name }),
125
- (!hideFields.includes("activities.start_date") || !hideFields.includes("activities.end_date")) && /* @__PURE__ */ jsx("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0", children: [
125
+ (!hideFields.includes("activities.start_date") || !hideFields.includes("activities.end_date")) && /* @__PURE__ */ jsx("span", { className: "mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge", children: [
126
126
  !hideFields.includes("activities.start_date") && act.start_date,
127
127
  !hideFields.includes("activities.end_date") && act.end_date && act.end_date.toLowerCase() !== "presente" ? `- ${act.end_date}` : null
128
128
  ].filter(Boolean).join(" ") })
@@ -138,22 +138,15 @@ function ExperienceEducation({
138
138
  /* @__PURE__ */ jsx(Award, { className: "h-6 w-6 text-primary" }),
139
139
  "Certificaciones"
140
140
  ] }),
141
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4 sm:grid-cols-2", children: certifications.map((cert) => /* @__PURE__ */ jsxs(
141
+ /* @__PURE__ */ jsx("div", { className: "grid grid-cols-1 gap-4", children: certifications.map((cert) => /* @__PURE__ */ jsxs(
142
142
  "div",
143
143
  {
144
144
  className: "rounded-lg border border-border/60 bg-card p-4 shadow-sm transition-colors hover:border-primary/30 hover:shadow-md",
145
145
  children: [
146
- !hideFields.includes("certifications.title") && /* @__PURE__ */ jsx(
147
- "h4",
148
- {
149
- className: "line-clamp-1 text-base font-bold text-foreground",
150
- title: cert.title,
151
- children: cert.title
152
- }
153
- ),
146
+ !hideFields.includes("certifications.title") && /* @__PURE__ */ jsx("h4", { className: "break-words text-base font-bold text-foreground", children: cert.title }),
154
147
  !hideFields.includes("certifications.institution_name") && /* @__PURE__ */ jsx("p", { className: "mt-1 line-clamp-1 text-sm text-muted-foreground", children: cert.institution_name }),
155
148
  /* @__PURE__ */ jsxs("div", { className: "mt-4 flex items-center justify-between", children: [
156
- !hideFields.includes("certifications.date_awarded") && /* @__PURE__ */ jsx("span", { className: "rounded-md bg-muted/50 px-2 py-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground", children: cert.date_awarded }),
149
+ !hideFields.includes("certifications.date_awarded") && /* @__PURE__ */ jsx("span", { className: "rounded-md bg-muted/50 px-2 py-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground pdf-badge", children: cert.date_awarded }),
157
150
  cert.verified && !hideFields.includes("certifications.verified") && /* @__PURE__ */ jsx(
158
151
  "span",
159
152
  {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/components/domain/resume/resume-preview/sections/experience-education.tsx"],"sourcesContent":["import { CandidateProfile } from \"../../types\";\nimport type { CVExperienceBaseItem, CVCertificationItem } from \"../../types\";\nimport { GraduationCap, Briefcase, Trophy, Award } from \"lucide-react\";\n\n/** Parsea una fecha (MM/YYYY, YYYY-MM o YYYY) a un valor numérico para ordenar (mayor = más reciente) */\nfunction parseDateToSortValue(dateStr: string | undefined): number {\n if (!dateStr || dateStr.toLowerCase() === \"presente\") return 0;\n // MM/YYYY\n const mmYyyy = dateStr.match(/^(\\d{1,2})\\/(\\d{4})$/);\n if (mmYyyy) return parseInt(mmYyyy[2], 10) * 12 + parseInt(mmYyyy[1], 10);\n // YYYY-MM o YYYY-MM-DD\n const yyyyMm = dateStr.match(/^(\\d{4})-(\\d{1,2})/);\n if (yyyyMm) return parseInt(yyyyMm[1], 10) * 12 + parseInt(yyyyMm[2], 10);\n // Solo año\n const year = dateStr.match(/\\d{4}/);\n if (year) return parseInt(year[0], 10) * 12;\n return 0;\n}\n\n/** Ordena descendente por fecha de fin; si no hay end_date (Presente), usa start_date y prioriza como más reciente */\nfunction sortByDateDesc<T extends CVExperienceBaseItem>(items: T[]): T[] {\n return [...items].sort((a, b) => {\n const aEnd = a.end_date?.toLowerCase();\n const bEnd = b.end_date?.toLowerCase();\n const aOngoing = !a.end_date || aEnd === \"presente\";\n const bOngoing = !b.end_date || bEnd === \"presente\";\n const aVal = aOngoing ? parseDateToSortValue(a.start_date) + 9999 * 12 : parseDateToSortValue(a.end_date);\n const bVal = bOngoing ? parseDateToSortValue(b.start_date) + 9999 * 12 : parseDateToSortValue(b.end_date);\n return bVal - aVal;\n });\n}\n\n/** Ordena certificaciones descendente por date_awarded */\nfunction sortCertificationsByDateDesc(items: CVCertificationItem[]): CVCertificationItem[] {\n return [...items].sort((a, b) => {\n const aVal = parseDateToSortValue(a.date_awarded);\n const bVal = parseDateToSortValue(b.date_awarded);\n return bVal - aVal;\n });\n}\n\ninterface ExperienceEducationProps {\n data: CandidateProfile;\n theme?: string;\n hideFields?: string[];\n hideSections?: string[];\n}\n\nexport function ExperienceEducation({\n data,\n theme,\n hideFields = [],\n hideSections = [],\n}: ExperienceEducationProps) {\n const experiences = sortByDateDesc(data.work_experience || []);\n const education = sortByDateDesc(data.education || []);\n const activities = sortByDateDesc(data.activities || []);\n const certifications = sortCertificationsByDateDesc(data.certifications || []);\n\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div className=\"space-y-12\">\n {/* Experience */}\n {experiences.length > 0 && !hideSections.includes(\"Experiencia laboral\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Briefcase className=\"h-6 w-6 text-primary\" />\n Experiencia Laboral\n </h3>\n <div className=\"space-y-8\">\n {experiences.map((exp) => (\n <div\n key={exp.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"experience.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{exp.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"experience.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {exp.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"experience.start_date\") ||\n !hideFields.includes(\"experience.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0\">\n {[\n !hideFields.includes(\"experience.start_date\") && exp.start_date,\n !hideFields.includes(\"experience.end_date\") &&\n exp.end_date &&\n exp.end_date.toLowerCase() !== \"presente\"\n ? `- ${exp.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {exp.description && !hideFields.includes(\"experience.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {exp.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Education */}\n {education.length > 0 && !hideSections.includes(\"Educación\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <GraduationCap className=\"h-6 w-6 text-primary\" />\n Educación\n </h3>\n <div className=\"space-y-8\">\n {education.map((edu) => (\n <div\n key={edu.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"education.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{edu.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"education.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {edu.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"education.start_date\") ||\n !hideFields.includes(\"education.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0\">\n {[\n !hideFields.includes(\"education.start_date\") && edu.start_date,\n !hideFields.includes(\"education.end_date\") &&\n edu.end_date &&\n edu.end_date.toLowerCase() !== \"presente\"\n ? `- ${edu.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {edu.description && !hideFields.includes(\"education.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {edu.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Activities */}\n {activities.length > 0 && !hideSections.includes(\"Actividades y Logros\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Trophy className=\"h-6 w-6 text-primary\" />\n Actividades y Logros\n </h3>\n <div className=\"space-y-8\">\n {activities.map((act) => (\n <div\n key={act.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"activities.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{act.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"activities.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {act.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"activities.start_date\") ||\n !hideFields.includes(\"activities.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0\">\n {[\n !hideFields.includes(\"activities.start_date\") && act.start_date,\n !hideFields.includes(\"activities.end_date\") &&\n act.end_date &&\n act.end_date.toLowerCase() !== \"presente\"\n ? `- ${act.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {act.description && !hideFields.includes(\"activities.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {act.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Certifications */}\n {certifications.length > 0 && !hideSections.includes(\"Certificaciones\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Award className=\"h-6 w-6 text-primary\" />\n Certificaciones\n </h3>\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-2\">\n {certifications.map((cert) => (\n <div\n key={cert.id}\n className=\"rounded-lg border border-border/60 bg-card p-4 shadow-sm transition-colors hover:border-primary/30 hover:shadow-md\"\n >\n {!hideFields.includes(\"certifications.title\") && (\n <h4\n className=\"line-clamp-1 text-base font-bold text-foreground\"\n title={cert.title}\n >\n {cert.title}\n </h4>\n )}\n {!hideFields.includes(\"certifications.institution_name\") && (\n <p className=\"mt-1 line-clamp-1 text-sm text-muted-foreground\">\n {cert.institution_name}\n </p>\n )}\n <div className=\"mt-4 flex items-center justify-between\">\n {!hideFields.includes(\"certifications.date_awarded\") && (\n <span className=\"rounded-md bg-muted/50 px-2 py-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground\">\n {cert.date_awarded}\n </span>\n )}\n {cert.verified && !hideFields.includes(\"certifications.verified\") && (\n <span\n className=\"pdf-badge rounded-full border px-2.5 py-1 text-xs font-bold transition-colors\"\n style={{\n backgroundColor: theme?.startsWith(\"#\") ? `${theme}15` : undefined,\n color: theme,\n borderColor: theme?.startsWith(\"#\") ? `${theme}30` : theme,\n }}\n >\n Verificado\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../../../../../src/components/domain/resume/resume-preview/sections/experience-education.tsx"],"sourcesContent":["import { CandidateProfile } from \"../../types\";\nimport type { CVExperienceBaseItem, CVCertificationItem } from \"../../types\";\nimport { GraduationCap, Briefcase, Trophy, Award } from \"lucide-react\";\n\n/** Parsea una fecha (MM/YYYY, YYYY-MM o YYYY) a un valor numérico para ordenar (mayor = más reciente) */\nfunction parseDateToSortValue(dateStr: string | undefined): number {\n if (!dateStr || dateStr.toLowerCase() === \"presente\") return 0;\n // MM/YYYY\n const mmYyyy = dateStr.match(/^(\\d{1,2})\\/(\\d{4})$/);\n if (mmYyyy) return parseInt(mmYyyy[2], 10) * 12 + parseInt(mmYyyy[1], 10);\n // YYYY-MM o YYYY-MM-DD\n const yyyyMm = dateStr.match(/^(\\d{4})-(\\d{1,2})/);\n if (yyyyMm) return parseInt(yyyyMm[1], 10) * 12 + parseInt(yyyyMm[2], 10);\n // Solo año\n const year = dateStr.match(/\\d{4}/);\n if (year) return parseInt(year[0], 10) * 12;\n return 0;\n}\n\n/** Ordena descendente por fecha de fin; si no hay end_date (Presente), usa start_date y prioriza como más reciente */\nfunction sortByDateDesc<T extends CVExperienceBaseItem>(items: T[]): T[] {\n return [...items].sort((a, b) => {\n const aEnd = a.end_date?.toLowerCase();\n const bEnd = b.end_date?.toLowerCase();\n const aOngoing = !a.end_date || aEnd === \"presente\";\n const bOngoing = !b.end_date || bEnd === \"presente\";\n const aVal = aOngoing ? parseDateToSortValue(a.start_date) + 9999 * 12 : parseDateToSortValue(a.end_date);\n const bVal = bOngoing ? parseDateToSortValue(b.start_date) + 9999 * 12 : parseDateToSortValue(b.end_date);\n return bVal - aVal;\n });\n}\n\n/** Ordena certificaciones descendente por date_awarded */\nfunction sortCertificationsByDateDesc(items: CVCertificationItem[]): CVCertificationItem[] {\n return [...items].sort((a, b) => {\n const aVal = parseDateToSortValue(a.date_awarded);\n const bVal = parseDateToSortValue(b.date_awarded);\n return bVal - aVal;\n });\n}\n\ninterface ExperienceEducationProps {\n data: CandidateProfile;\n theme?: string;\n hideFields?: string[];\n hideSections?: string[];\n}\n\nexport function ExperienceEducation({\n data,\n theme,\n hideFields = [],\n hideSections = [],\n}: ExperienceEducationProps) {\n const experiences = sortByDateDesc(data.work_experience || []);\n const education = sortByDateDesc(data.education || []);\n const activities = sortByDateDesc(data.activities || []);\n const certifications = sortCertificationsByDateDesc(data.certifications || []);\n\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div className=\"space-y-12\">\n {/* Experience */}\n {experiences.length > 0 && !hideSections.includes(\"Experiencia laboral\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Briefcase className=\"h-6 w-6 text-primary\" />\n Experiencia Laboral\n </h3>\n <div className=\"space-y-8\">\n {experiences.map((exp) => (\n <div\n key={exp.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"experience.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{exp.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"experience.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {exp.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"experience.start_date\") ||\n !hideFields.includes(\"experience.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge\">\n {[\n !hideFields.includes(\"experience.start_date\") && exp.start_date,\n !hideFields.includes(\"experience.end_date\") &&\n exp.end_date &&\n exp.end_date.toLowerCase() !== \"presente\"\n ? `- ${exp.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {exp.description && !hideFields.includes(\"experience.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {exp.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Education */}\n {education.length > 0 && !hideSections.includes(\"Educación\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <GraduationCap className=\"h-6 w-6 text-primary\" />\n Educación\n </h3>\n <div className=\"space-y-8\">\n {education.map((edu) => (\n <div\n key={edu.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"education.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{edu.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"education.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {edu.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"education.start_date\") ||\n !hideFields.includes(\"education.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge\">\n {[\n !hideFields.includes(\"education.start_date\") && edu.start_date,\n !hideFields.includes(\"education.end_date\") &&\n edu.end_date &&\n edu.end_date.toLowerCase() !== \"presente\"\n ? `- ${edu.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {edu.description && !hideFields.includes(\"education.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {edu.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Activities */}\n {activities.length > 0 && !hideSections.includes(\"Actividades y Logros\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Trophy className=\"h-6 w-6 text-primary\" />\n Actividades y Logros\n </h3>\n <div className=\"space-y-8\">\n {activities.map((act) => (\n <div\n key={act.id}\n className=\"relative pl-6 after:absolute after:bottom-[-24px] after:left-[3px] after:top-4 after:w-[2px] after:bg-border last:after:hidden\"\n >\n <div\n className=\"pdf-line-v absolute left-0 top-2 h-2 w-2 rounded-full bg-primary\"\n style={themeStyle}\n />\n {!hideFields.includes(\"activities.title\") && (\n <h4 className=\"text-lg font-bold text-foreground\">{act.title}</h4>\n )}\n <div className=\"mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between\">\n {!hideFields.includes(\"activities.institution_name\") && (\n <span className=\"text-base font-semibold text-primary\">\n {act.institution_name}\n </span>\n )}\n {(!hideFields.includes(\"activities.start_date\") ||\n !hideFields.includes(\"activities.end_date\")) && (\n <span className=\"mt-1 w-fit rounded-md bg-muted/30 px-2 py-0.5 text-sm font-medium text-muted-foreground sm:mt-0 pdf-badge\">\n {[\n !hideFields.includes(\"activities.start_date\") && act.start_date,\n !hideFields.includes(\"activities.end_date\") &&\n act.end_date &&\n act.end_date.toLowerCase() !== \"presente\"\n ? `- ${act.end_date}`\n : null,\n ]\n .filter(Boolean)\n .join(\" \")}\n </span>\n )}\n </div>\n {act.description && !hideFields.includes(\"activities.description\") && (\n <p className=\"mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80\">\n {act.description}\n </p>\n )}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Certifications */}\n {certifications.length > 0 && !hideSections.includes(\"Certificaciones\") && (\n <div className=\"space-y-6\">\n <h3 className=\"flex items-center gap-2 border-b-2 border-primary/20 pb-2 text-2xl font-bold text-primary\">\n <Award className=\"h-6 w-6 text-primary\" />\n Certificaciones\n </h3>\n <div className=\"grid grid-cols-1 gap-4\">\n {certifications.map((cert) => (\n <div\n key={cert.id}\n className=\"rounded-lg border border-border/60 bg-card p-4 shadow-sm transition-colors hover:border-primary/30 hover:shadow-md\"\n >\n {!hideFields.includes(\"certifications.title\") && (\n <h4 className=\"break-words text-base font-bold text-foreground\">\n {cert.title}\n </h4>\n )}\n {!hideFields.includes(\"certifications.institution_name\") && (\n <p className=\"mt-1 line-clamp-1 text-sm text-muted-foreground\">\n {cert.institution_name}\n </p>\n )}\n <div className=\"mt-4 flex items-center justify-between\">\n {!hideFields.includes(\"certifications.date_awarded\") && (\n <span className=\"rounded-md bg-muted/50 px-2 py-1 text-xs font-semibold uppercase tracking-wider text-muted-foreground pdf-badge\">\n {cert.date_awarded}\n </span>\n )}\n {cert.verified && !hideFields.includes(\"certifications.verified\") && (\n <span\n className=\"pdf-badge rounded-full border px-2.5 py-1 text-xs font-bold transition-colors\"\n style={{\n backgroundColor: theme?.startsWith(\"#\") ? `${theme}15` : undefined,\n color: theme,\n borderColor: theme?.startsWith(\"#\") ? `${theme}30` : theme,\n }}\n >\n Verificado\n </span>\n )}\n </div>\n </div>\n ))}\n </div>\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":[]}
@@ -23,7 +23,18 @@ __export(header_preview_exports, {
23
23
  module.exports = __toCommonJS(header_preview_exports);
24
24
  var import_jsx_runtime = require("react/jsx-runtime");
25
25
  var import_ui = require("../../../../ui");
26
+ function formatLastUpdated(value) {
27
+ if (!value) return null;
28
+ try {
29
+ const d = new Date(value);
30
+ if (Number.isNaN(d.getTime())) return value;
31
+ return d.toLocaleDateString("es", { day: "2-digit", month: "2-digit", year: "numeric" });
32
+ } catch {
33
+ return value;
34
+ }
35
+ }
26
36
  function HeaderPreview({ data, headerSlot, theme, hideFields = [] }) {
37
+ const lastUpdated = !hideFields.includes("last_updated") && data.last_updated ? formatLastUpdated(data.last_updated) : null;
27
38
  const getInitials = () => {
28
39
  const f = hideFields.includes("first_name") ? "" : data.first_name?.[0] || "";
29
40
  const l = data.last_name?.[0] || "";
@@ -37,7 +48,7 @@ function HeaderPreview({ data, headerSlot, theme, hideFields = [] }) {
37
48
  ].filter(Boolean).join(" ") || "Sin nombre";
38
49
  const themeStyle = theme ? { backgroundColor: theme } : void 0;
39
50
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-8 flex flex-col items-center gap-6 md:flex-row md:items-start md:gap-6", children: [
40
- !hideFields.includes("photo_url") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ui.Avatar, { className: "h-32 w-32 flex-shrink-0 overflow-hidden rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none shadow-lg", children: [
51
+ !hideFields.includes("photo_url") && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_ui.Avatar, { className: "pdf-header-avatar h-32 w-32 flex-shrink-0 overflow-hidden rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none shadow-lg", children: [
41
52
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_ui.AvatarImage, { src: data.photo_url || void 0, alt: fullName, className: "object-cover" }),
42
53
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
43
54
  import_ui.AvatarFallback,
@@ -51,7 +62,11 @@ function HeaderPreview({ data, headerSlot, theme, hideFields = [] }) {
51
62
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mt-2 flex w-full flex-1 flex-col justify-between text-center md:mt-0 md:text-left", children: [
52
63
  /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
53
64
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: "mb-3 text-3xl font-extrabold tracking-tight text-foreground md:text-4xl", children: fullName }),
54
- data.summary && !hideFields.includes("summary") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-md pdf-summary mx-auto max-w-3xl font-medium leading-relaxed text-muted-foreground md:mx-0", children: data.summary })
65
+ data.summary && !hideFields.includes("summary") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "text-md pdf-summary mx-auto max-w-3xl font-medium leading-relaxed text-muted-foreground md:mx-0", children: data.summary }),
66
+ lastUpdated && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("p", { className: "mt-2 text-xs text-muted-foreground opacity-70", children: [
67
+ "\xDAltima actualizaci\xF3n: ",
68
+ lastUpdated
69
+ ] })
55
70
  ] }),
56
71
  headerSlot && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "pdf-hidden mt-6 flex w-full items-center justify-center md:justify-end", children: headerSlot })
57
72
  ] })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/components/domain/resume/resume-preview/sections/header-preview.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { CandidateProfile } from \"../../types\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"../../../../ui\";\n\ninterface HeaderPreviewProps {\n data: CandidateProfile;\n headerSlot?: React.ReactNode;\n theme?: string;\n hideFields?: string[];\n}\n\nexport function HeaderPreview({ data, headerSlot, theme, hideFields = [] }: HeaderPreviewProps) {\n const getInitials = () => {\n const f = hideFields.includes(\"first_name\") ? \"\" : data.first_name?.[0] || \"\";\n const l = data.last_name?.[0] || \"\";\n return `${f}${l}`.toUpperCase() || \"CN\";\n };\n\n const fullName =\n [\n hideFields.includes(\"first_name\") ? null : data.first_name,\n hideFields.includes(\"middle_name\") ? null : data.middle_name,\n hideFields.includes(\"last_name\") ? null : data.last_name,\n hideFields.includes(\"second_last_name\") ? null : data.second_last_name,\n ]\n .filter(Boolean)\n .join(\" \") || \"Sin nombre\";\n\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div className=\"mt-8 flex flex-col items-center gap-6 md:flex-row md:items-start md:gap-6\">\n {!hideFields.includes(\"photo_url\") && (\n <Avatar className=\"h-32 w-32 flex-shrink-0 overflow-hidden rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none shadow-lg\">\n <AvatarImage src={data.photo_url || undefined} alt={fullName} className=\"object-cover\" />\n <AvatarFallback\n className=\"pdf-header-initials rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none text-3xl font-semibold text-primary-foreground\"\n style={themeStyle || { backgroundColor: \"hsl(var(--primary))\" }}\n >\n {getInitials()}\n </AvatarFallback>\n </Avatar>\n )}\n\n <div className=\"mt-2 flex w-full flex-1 flex-col justify-between text-center md:mt-0 md:text-left\">\n <div>\n <h1 className=\"mb-3 text-3xl font-extrabold tracking-tight text-foreground md:text-4xl\">\n {fullName}\n </h1>\n {data.summary && !hideFields.includes(\"summary\") && (\n <p className=\"text-md pdf-summary mx-auto max-w-3xl font-medium leading-relaxed text-muted-foreground md:mx-0\">\n {data.summary}\n </p>\n )}\n </div>\n\n {headerSlot && (\n <div className=\"pdf-hidden mt-6 flex w-full items-center justify-center md:justify-end\">\n {headerSlot}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiCQ;AA/BR,gBAAoD;AAS7C,SAAS,cAAc,EAAE,MAAM,YAAY,OAAO,aAAa,CAAC,EAAE,GAAuB;AAC9F,QAAM,cAAc,MAAM;AACxB,UAAM,IAAI,WAAW,SAAS,YAAY,IAAI,KAAK,KAAK,aAAa,CAAC,KAAK;AAC3E,UAAM,IAAI,KAAK,YAAY,CAAC,KAAK;AACjC,WAAO,GAAG,CAAC,GAAG,CAAC,GAAG,YAAY,KAAK;AAAA,EACrC;AAEA,QAAM,WACJ;AAAA,IACE,WAAW,SAAS,YAAY,IAAI,OAAO,KAAK;AAAA,IAChD,WAAW,SAAS,aAAa,IAAI,OAAO,KAAK;AAAA,IACjD,WAAW,SAAS,WAAW,IAAI,OAAO,KAAK;AAAA,IAC/C,WAAW,SAAS,kBAAkB,IAAI,OAAO,KAAK;AAAA,EACxD,EACG,OAAO,OAAO,EACd,KAAK,GAAG,KAAK;AAElB,QAAM,aAAa,QAAQ,EAAE,iBAAiB,MAAM,IAAI;AAExD,SACE,6CAAC,SAAI,WAAU,6EACZ;AAAA,KAAC,WAAW,SAAS,WAAW,KAC/B,6CAAC,oBAAO,WAAU,gIAChB;AAAA,kDAAC,yBAAY,KAAK,KAAK,aAAa,QAAW,KAAK,UAAU,WAAU,gBAAe;AAAA,MACvF;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,cAAc,EAAE,iBAAiB,sBAAsB;AAAA,UAE7D,sBAAY;AAAA;AAAA,MACf;AAAA,OACF;AAAA,IAGF,6CAAC,SAAI,WAAU,qFACb;AAAA,mDAAC,SACC;AAAA,oDAAC,QAAG,WAAU,2EACX,oBACH;AAAA,QACC,KAAK,WAAW,CAAC,WAAW,SAAS,SAAS,KAC7C,4CAAC,OAAE,WAAU,mGACV,eAAK,SACR;AAAA,SAEJ;AAAA,MAEC,cACC,4CAAC,SAAI,WAAU,0EACZ,sBACH;AAAA,OAEJ;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../../../src/components/domain/resume/resume-preview/sections/header-preview.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { CandidateProfile } from \"../../types\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"../../../../ui\";\n\ninterface HeaderPreviewProps {\n data: CandidateProfile;\n headerSlot?: React.ReactNode;\n theme?: string;\n hideFields?: string[];\n}\n\nfunction formatLastUpdated(value: string | undefined): string | null {\n if (!value) return null;\n try {\n const d = new Date(value);\n if (Number.isNaN(d.getTime())) return value;\n return d.toLocaleDateString(\"es\", { day: \"2-digit\", month: \"2-digit\", year: \"numeric\" });\n } catch {\n return value;\n }\n}\n\nexport function HeaderPreview({ data, headerSlot, theme, hideFields = [] }: HeaderPreviewProps) {\n const lastUpdated =\n !hideFields.includes(\"last_updated\") && data.last_updated\n ? formatLastUpdated(data.last_updated)\n : null;\n\n const getInitials = () => {\n const f = hideFields.includes(\"first_name\") ? \"\" : data.first_name?.[0] || \"\";\n const l = data.last_name?.[0] || \"\";\n return `${f}${l}`.toUpperCase() || \"CN\";\n };\n\n const fullName =\n [\n hideFields.includes(\"first_name\") ? null : data.first_name,\n hideFields.includes(\"middle_name\") ? null : data.middle_name,\n hideFields.includes(\"last_name\") ? null : data.last_name,\n hideFields.includes(\"second_last_name\") ? null : data.second_last_name,\n ]\n .filter(Boolean)\n .join(\" \") || \"Sin nombre\";\n\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div className=\"mt-8 flex flex-col items-center gap-6 md:flex-row md:items-start md:gap-6\">\n {!hideFields.includes(\"photo_url\") && (\n <Avatar className=\"pdf-header-avatar h-32 w-32 flex-shrink-0 overflow-hidden rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none shadow-lg\">\n <AvatarImage src={data.photo_url || undefined} alt={fullName} className=\"object-cover\" />\n <AvatarFallback\n className=\"pdf-header-initials rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none text-3xl font-semibold text-primary-foreground\"\n style={themeStyle || { backgroundColor: \"hsl(var(--primary))\" }}\n >\n {getInitials()}\n </AvatarFallback>\n </Avatar>\n )}\n\n <div className=\"mt-2 flex w-full flex-1 flex-col justify-between text-center md:mt-0 md:text-left\">\n <div>\n <h1 className=\"mb-3 text-3xl font-extrabold tracking-tight text-foreground md:text-4xl\">\n {fullName}\n </h1>\n {data.summary && !hideFields.includes(\"summary\") && (\n <p className=\"text-md pdf-summary mx-auto max-w-3xl font-medium leading-relaxed text-muted-foreground md:mx-0\">\n {data.summary}\n </p>\n )}\n {lastUpdated && (\n <p className=\"mt-2 text-xs text-muted-foreground opacity-70\">\n Última actualización: {lastUpdated}\n </p>\n )}\n </div>\n\n {headerSlot && (\n <div className=\"pdf-hidden mt-6 flex w-full items-center justify-center md:justify-end\">\n {headerSlot}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiDQ;AA/CR,gBAAoD;AASpD,SAAS,kBAAkB,OAA0C;AACnE,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACF,UAAM,IAAI,IAAI,KAAK,KAAK;AACxB,QAAI,OAAO,MAAM,EAAE,QAAQ,CAAC,EAAG,QAAO;AACtC,WAAO,EAAE,mBAAmB,MAAM,EAAE,KAAK,WAAW,OAAO,WAAW,MAAM,UAAU,CAAC;AAAA,EACzF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,cAAc,EAAE,MAAM,YAAY,OAAO,aAAa,CAAC,EAAE,GAAuB;AAC9F,QAAM,cACJ,CAAC,WAAW,SAAS,cAAc,KAAK,KAAK,eACzC,kBAAkB,KAAK,YAAY,IACnC;AAEN,QAAM,cAAc,MAAM;AACxB,UAAM,IAAI,WAAW,SAAS,YAAY,IAAI,KAAK,KAAK,aAAa,CAAC,KAAK;AAC3E,UAAM,IAAI,KAAK,YAAY,CAAC,KAAK;AACjC,WAAO,GAAG,CAAC,GAAG,CAAC,GAAG,YAAY,KAAK;AAAA,EACrC;AAEA,QAAM,WACJ;AAAA,IACE,WAAW,SAAS,YAAY,IAAI,OAAO,KAAK;AAAA,IAChD,WAAW,SAAS,aAAa,IAAI,OAAO,KAAK;AAAA,IACjD,WAAW,SAAS,WAAW,IAAI,OAAO,KAAK;AAAA,IAC/C,WAAW,SAAS,kBAAkB,IAAI,OAAO,KAAK;AAAA,EACxD,EACG,OAAO,OAAO,EACd,KAAK,GAAG,KAAK;AAElB,QAAM,aAAa,QAAQ,EAAE,iBAAiB,MAAM,IAAI;AAExD,SACE,6CAAC,SAAI,WAAU,6EACZ;AAAA,KAAC,WAAW,SAAS,WAAW,KAC/B,6CAAC,oBAAO,WAAU,kJAChB;AAAA,kDAAC,yBAAY,KAAK,KAAK,aAAa,QAAW,KAAK,UAAU,WAAU,gBAAe;AAAA,MACvF;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,cAAc,EAAE,iBAAiB,sBAAsB;AAAA,UAE7D,sBAAY;AAAA;AAAA,MACf;AAAA,OACF;AAAA,IAGF,6CAAC,SAAI,WAAU,qFACb;AAAA,mDAAC,SACC;AAAA,oDAAC,QAAG,WAAU,2EACX,oBACH;AAAA,QACC,KAAK,WAAW,CAAC,WAAW,SAAS,SAAS,KAC7C,4CAAC,OAAE,WAAU,mGACV,eAAK,SACR;AAAA,QAED,eACC,6CAAC,OAAE,WAAU,iDAAgD;AAAA;AAAA,UACpC;AAAA,WACzB;AAAA,SAEJ;AAAA,MAEC,cACC,4CAAC,SAAI,WAAU,0EACZ,sBACH;AAAA,OAEJ;AAAA,KACF;AAEJ;","names":[]}
@@ -1,6 +1,17 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { Avatar, AvatarFallback, AvatarImage } from "../../../../ui";
3
+ function formatLastUpdated(value) {
4
+ if (!value) return null;
5
+ try {
6
+ const d = new Date(value);
7
+ if (Number.isNaN(d.getTime())) return value;
8
+ return d.toLocaleDateString("es", { day: "2-digit", month: "2-digit", year: "numeric" });
9
+ } catch {
10
+ return value;
11
+ }
12
+ }
3
13
  function HeaderPreview({ data, headerSlot, theme, hideFields = [] }) {
14
+ const lastUpdated = !hideFields.includes("last_updated") && data.last_updated ? formatLastUpdated(data.last_updated) : null;
4
15
  const getInitials = () => {
5
16
  const f = hideFields.includes("first_name") ? "" : data.first_name?.[0] || "";
6
17
  const l = data.last_name?.[0] || "";
@@ -14,7 +25,7 @@ function HeaderPreview({ data, headerSlot, theme, hideFields = [] }) {
14
25
  ].filter(Boolean).join(" ") || "Sin nombre";
15
26
  const themeStyle = theme ? { backgroundColor: theme } : void 0;
16
27
  return /* @__PURE__ */ jsxs("div", { className: "mt-8 flex flex-col items-center gap-6 md:flex-row md:items-start md:gap-6", children: [
17
- !hideFields.includes("photo_url") && /* @__PURE__ */ jsxs(Avatar, { className: "h-32 w-32 flex-shrink-0 overflow-hidden rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none shadow-lg", children: [
28
+ !hideFields.includes("photo_url") && /* @__PURE__ */ jsxs(Avatar, { className: "pdf-header-avatar h-32 w-32 flex-shrink-0 overflow-hidden rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none shadow-lg", children: [
18
29
  /* @__PURE__ */ jsx(AvatarImage, { src: data.photo_url || void 0, alt: fullName, className: "object-cover" }),
19
30
  /* @__PURE__ */ jsx(
20
31
  AvatarFallback,
@@ -28,7 +39,11 @@ function HeaderPreview({ data, headerSlot, theme, hideFields = [] }) {
28
39
  /* @__PURE__ */ jsxs("div", { className: "mt-2 flex w-full flex-1 flex-col justify-between text-center md:mt-0 md:text-left", children: [
29
40
  /* @__PURE__ */ jsxs("div", { children: [
30
41
  /* @__PURE__ */ jsx("h1", { className: "mb-3 text-3xl font-extrabold tracking-tight text-foreground md:text-4xl", children: fullName }),
31
- data.summary && !hideFields.includes("summary") && /* @__PURE__ */ jsx("p", { className: "text-md pdf-summary mx-auto max-w-3xl font-medium leading-relaxed text-muted-foreground md:mx-0", children: data.summary })
42
+ data.summary && !hideFields.includes("summary") && /* @__PURE__ */ jsx("p", { className: "text-md pdf-summary mx-auto max-w-3xl font-medium leading-relaxed text-muted-foreground md:mx-0", children: data.summary }),
43
+ lastUpdated && /* @__PURE__ */ jsxs("p", { className: "mt-2 text-xs text-muted-foreground opacity-70", children: [
44
+ "\xDAltima actualizaci\xF3n: ",
45
+ lastUpdated
46
+ ] })
32
47
  ] }),
33
48
  headerSlot && /* @__PURE__ */ jsx("div", { className: "pdf-hidden mt-6 flex w-full items-center justify-center md:justify-end", children: headerSlot })
34
49
  ] })
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../src/components/domain/resume/resume-preview/sections/header-preview.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { CandidateProfile } from \"../../types\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"../../../../ui\";\n\ninterface HeaderPreviewProps {\n data: CandidateProfile;\n headerSlot?: React.ReactNode;\n theme?: string;\n hideFields?: string[];\n}\n\nexport function HeaderPreview({ data, headerSlot, theme, hideFields = [] }: HeaderPreviewProps) {\n const getInitials = () => {\n const f = hideFields.includes(\"first_name\") ? \"\" : data.first_name?.[0] || \"\";\n const l = data.last_name?.[0] || \"\";\n return `${f}${l}`.toUpperCase() || \"CN\";\n };\n\n const fullName =\n [\n hideFields.includes(\"first_name\") ? null : data.first_name,\n hideFields.includes(\"middle_name\") ? null : data.middle_name,\n hideFields.includes(\"last_name\") ? null : data.last_name,\n hideFields.includes(\"second_last_name\") ? null : data.second_last_name,\n ]\n .filter(Boolean)\n .join(\" \") || \"Sin nombre\";\n\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div className=\"mt-8 flex flex-col items-center gap-6 md:flex-row md:items-start md:gap-6\">\n {!hideFields.includes(\"photo_url\") && (\n <Avatar className=\"h-32 w-32 flex-shrink-0 overflow-hidden rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none shadow-lg\">\n <AvatarImage src={data.photo_url || undefined} alt={fullName} className=\"object-cover\" />\n <AvatarFallback\n className=\"pdf-header-initials rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none text-3xl font-semibold text-primary-foreground\"\n style={themeStyle || { backgroundColor: \"hsl(var(--primary))\" }}\n >\n {getInitials()}\n </AvatarFallback>\n </Avatar>\n )}\n\n <div className=\"mt-2 flex w-full flex-1 flex-col justify-between text-center md:mt-0 md:text-left\">\n <div>\n <h1 className=\"mb-3 text-3xl font-extrabold tracking-tight text-foreground md:text-4xl\">\n {fullName}\n </h1>\n {data.summary && !hideFields.includes(\"summary\") && (\n <p className=\"text-md pdf-summary mx-auto max-w-3xl font-medium leading-relaxed text-muted-foreground md:mx-0\">\n {data.summary}\n </p>\n )}\n </div>\n\n {headerSlot && (\n <div className=\"pdf-hidden mt-6 flex w-full items-center justify-center md:justify-end\">\n {headerSlot}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"AAiCQ,SACE,KADF;AA/BR,SAAS,QAAQ,gBAAgB,mBAAmB;AAS7C,SAAS,cAAc,EAAE,MAAM,YAAY,OAAO,aAAa,CAAC,EAAE,GAAuB;AAC9F,QAAM,cAAc,MAAM;AACxB,UAAM,IAAI,WAAW,SAAS,YAAY,IAAI,KAAK,KAAK,aAAa,CAAC,KAAK;AAC3E,UAAM,IAAI,KAAK,YAAY,CAAC,KAAK;AACjC,WAAO,GAAG,CAAC,GAAG,CAAC,GAAG,YAAY,KAAK;AAAA,EACrC;AAEA,QAAM,WACJ;AAAA,IACE,WAAW,SAAS,YAAY,IAAI,OAAO,KAAK;AAAA,IAChD,WAAW,SAAS,aAAa,IAAI,OAAO,KAAK;AAAA,IACjD,WAAW,SAAS,WAAW,IAAI,OAAO,KAAK;AAAA,IAC/C,WAAW,SAAS,kBAAkB,IAAI,OAAO,KAAK;AAAA,EACxD,EACG,OAAO,OAAO,EACd,KAAK,GAAG,KAAK;AAElB,QAAM,aAAa,QAAQ,EAAE,iBAAiB,MAAM,IAAI;AAExD,SACE,qBAAC,SAAI,WAAU,6EACZ;AAAA,KAAC,WAAW,SAAS,WAAW,KAC/B,qBAAC,UAAO,WAAU,gIAChB;AAAA,0BAAC,eAAY,KAAK,KAAK,aAAa,QAAW,KAAK,UAAU,WAAU,gBAAe;AAAA,MACvF;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,cAAc,EAAE,iBAAiB,sBAAsB;AAAA,UAE7D,sBAAY;AAAA;AAAA,MACf;AAAA,OACF;AAAA,IAGF,qBAAC,SAAI,WAAU,qFACb;AAAA,2BAAC,SACC;AAAA,4BAAC,QAAG,WAAU,2EACX,oBACH;AAAA,QACC,KAAK,WAAW,CAAC,WAAW,SAAS,SAAS,KAC7C,oBAAC,OAAE,WAAU,mGACV,eAAK,SACR;AAAA,SAEJ;AAAA,MAEC,cACC,oBAAC,SAAI,WAAU,0EACZ,sBACH;AAAA,OAEJ;AAAA,KACF;AAEJ;","names":[]}
1
+ {"version":3,"sources":["../../../../../../src/components/domain/resume/resume-preview/sections/header-preview.tsx"],"sourcesContent":["import * as React from \"react\";\nimport { CandidateProfile } from \"../../types\";\nimport { Avatar, AvatarFallback, AvatarImage } from \"../../../../ui\";\n\ninterface HeaderPreviewProps {\n data: CandidateProfile;\n headerSlot?: React.ReactNode;\n theme?: string;\n hideFields?: string[];\n}\n\nfunction formatLastUpdated(value: string | undefined): string | null {\n if (!value) return null;\n try {\n const d = new Date(value);\n if (Number.isNaN(d.getTime())) return value;\n return d.toLocaleDateString(\"es\", { day: \"2-digit\", month: \"2-digit\", year: \"numeric\" });\n } catch {\n return value;\n }\n}\n\nexport function HeaderPreview({ data, headerSlot, theme, hideFields = [] }: HeaderPreviewProps) {\n const lastUpdated =\n !hideFields.includes(\"last_updated\") && data.last_updated\n ? formatLastUpdated(data.last_updated)\n : null;\n\n const getInitials = () => {\n const f = hideFields.includes(\"first_name\") ? \"\" : data.first_name?.[0] || \"\";\n const l = data.last_name?.[0] || \"\";\n return `${f}${l}`.toUpperCase() || \"CN\";\n };\n\n const fullName =\n [\n hideFields.includes(\"first_name\") ? null : data.first_name,\n hideFields.includes(\"middle_name\") ? null : data.middle_name,\n hideFields.includes(\"last_name\") ? null : data.last_name,\n hideFields.includes(\"second_last_name\") ? null : data.second_last_name,\n ]\n .filter(Boolean)\n .join(\" \") || \"Sin nombre\";\n\n const themeStyle = theme ? { backgroundColor: theme } : undefined;\n\n return (\n <div className=\"mt-8 flex flex-col items-center gap-6 md:flex-row md:items-start md:gap-6\">\n {!hideFields.includes(\"photo_url\") && (\n <Avatar className=\"pdf-header-avatar h-32 w-32 flex-shrink-0 overflow-hidden rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none shadow-lg\">\n <AvatarImage src={data.photo_url || undefined} alt={fullName} className=\"object-cover\" />\n <AvatarFallback\n className=\"pdf-header-initials rounded-none rounded-tl-none rounded-tr-2xl rounded-bl-2xl rounded-br-none text-3xl font-semibold text-primary-foreground\"\n style={themeStyle || { backgroundColor: \"hsl(var(--primary))\" }}\n >\n {getInitials()}\n </AvatarFallback>\n </Avatar>\n )}\n\n <div className=\"mt-2 flex w-full flex-1 flex-col justify-between text-center md:mt-0 md:text-left\">\n <div>\n <h1 className=\"mb-3 text-3xl font-extrabold tracking-tight text-foreground md:text-4xl\">\n {fullName}\n </h1>\n {data.summary && !hideFields.includes(\"summary\") && (\n <p className=\"text-md pdf-summary mx-auto max-w-3xl font-medium leading-relaxed text-muted-foreground md:mx-0\">\n {data.summary}\n </p>\n )}\n {lastUpdated && (\n <p className=\"mt-2 text-xs text-muted-foreground opacity-70\">\n Última actualización: {lastUpdated}\n </p>\n )}\n </div>\n\n {headerSlot && (\n <div className=\"pdf-hidden mt-6 flex w-full items-center justify-center md:justify-end\">\n {headerSlot}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"AAiDQ,SACE,KADF;AA/CR,SAAS,QAAQ,gBAAgB,mBAAmB;AASpD,SAAS,kBAAkB,OAA0C;AACnE,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI;AACF,UAAM,IAAI,IAAI,KAAK,KAAK;AACxB,QAAI,OAAO,MAAM,EAAE,QAAQ,CAAC,EAAG,QAAO;AACtC,WAAO,EAAE,mBAAmB,MAAM,EAAE,KAAK,WAAW,OAAO,WAAW,MAAM,UAAU,CAAC;AAAA,EACzF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEO,SAAS,cAAc,EAAE,MAAM,YAAY,OAAO,aAAa,CAAC,EAAE,GAAuB;AAC9F,QAAM,cACJ,CAAC,WAAW,SAAS,cAAc,KAAK,KAAK,eACzC,kBAAkB,KAAK,YAAY,IACnC;AAEN,QAAM,cAAc,MAAM;AACxB,UAAM,IAAI,WAAW,SAAS,YAAY,IAAI,KAAK,KAAK,aAAa,CAAC,KAAK;AAC3E,UAAM,IAAI,KAAK,YAAY,CAAC,KAAK;AACjC,WAAO,GAAG,CAAC,GAAG,CAAC,GAAG,YAAY,KAAK;AAAA,EACrC;AAEA,QAAM,WACJ;AAAA,IACE,WAAW,SAAS,YAAY,IAAI,OAAO,KAAK;AAAA,IAChD,WAAW,SAAS,aAAa,IAAI,OAAO,KAAK;AAAA,IACjD,WAAW,SAAS,WAAW,IAAI,OAAO,KAAK;AAAA,IAC/C,WAAW,SAAS,kBAAkB,IAAI,OAAO,KAAK;AAAA,EACxD,EACG,OAAO,OAAO,EACd,KAAK,GAAG,KAAK;AAElB,QAAM,aAAa,QAAQ,EAAE,iBAAiB,MAAM,IAAI;AAExD,SACE,qBAAC,SAAI,WAAU,6EACZ;AAAA,KAAC,WAAW,SAAS,WAAW,KAC/B,qBAAC,UAAO,WAAU,kJAChB;AAAA,0BAAC,eAAY,KAAK,KAAK,aAAa,QAAW,KAAK,UAAU,WAAU,gBAAe;AAAA,MACvF;AAAA,QAAC;AAAA;AAAA,UACC,WAAU;AAAA,UACV,OAAO,cAAc,EAAE,iBAAiB,sBAAsB;AAAA,UAE7D,sBAAY;AAAA;AAAA,MACf;AAAA,OACF;AAAA,IAGF,qBAAC,SAAI,WAAU,qFACb;AAAA,2BAAC,SACC;AAAA,4BAAC,QAAG,WAAU,2EACX,oBACH;AAAA,QACC,KAAK,WAAW,CAAC,WAAW,SAAS,SAAS,KAC7C,oBAAC,OAAE,WAAU,mGACV,eAAK,SACR;AAAA,QAED,eACC,qBAAC,OAAE,WAAU,iDAAgD;AAAA;AAAA,UACpC;AAAA,WACzB;AAAA,SAEJ;AAAA,MAEC,cACC,oBAAC,SAAI,WAAU,0EACZ,sBACH;AAAA,OAEJ;AAAA,KACF;AAEJ;","names":[]}
@@ -213,11 +213,16 @@ function Resume({
213
213
  div.style.backgroundPosition = "center";
214
214
  div.style.borderRadius = window.getComputedStyle(img).borderRadius;
215
215
  div.className = img.className;
216
- parent2.style.marginTop = "1.33rem";
217
216
  parent2.replaceChild(div, img);
218
217
  }
219
218
  }
220
219
  });
220
+ const headerAvatars = clonedElement.querySelectorAll(".pdf-header-avatar");
221
+ headerAvatars.forEach((el) => {
222
+ if (el instanceof HTMLElement) {
223
+ el.style.marginTop = "1.33rem";
224
+ }
225
+ });
221
226
  const hiddenElements = clonedElement.querySelectorAll(".pdf-hidden");
222
227
  hiddenElements.forEach((el) => {
223
228
  if (el instanceof HTMLElement) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/domain/resume/resume.tsx"],"sourcesContent":["import { useRef, useState } from \"react\";\nimport html2canvas from \"html2canvas\";\nimport { jsPDF } from \"jspdf\";\nimport { CandidateProfile, ResumeProps, ResumeSavePayload, Action } from \"./types\";\nimport { ResumeEditor } from \"./resume-editor/resume-editor\";\nimport { ResumePreview } from \"./resume-preview/resume-preview\";\nimport { Button } from \"../../ui/button\";\nimport { Download, Edit, Loader2, Save, X } from \"lucide-react\";\nimport { Sheet, SheetTrigger, SheetContent, SheetTitle, SheetClose } from \"../../ui/sheet\";\n\nfunction calculateDiffs(original: CandidateProfile, current: CandidateProfile): ResumeSavePayload {\n // Determine diff for candidate table (academic info etc)\n const candidateData: Partial<CandidateProfile> = {};\n if (original.student_education_institution_id !== current.student_education_institution_id)\n candidateData.student_education_institution_id = current.student_education_institution_id;\n if (original.education_institution_id !== current.education_institution_id)\n candidateData.education_institution_id = current.education_institution_id;\n if (original.program_name !== current.program_name)\n candidateData.program_name = current.program_name;\n if (JSON.stringify(original.preferences) !== JSON.stringify(current.preferences))\n candidateData.preferences = current.preferences;\n if (JSON.stringify(original.advanced) !== JSON.stringify(current.advanced))\n candidateData.advanced = current.advanced;\n\n // Determine diff for user table (personal info)\n const userData: Partial<CandidateProfile> = {};\n const userFields: (keyof CandidateProfile)[] = [\n \"first_name\",\n \"middle_name\",\n \"last_name\",\n \"second_last_name\",\n \"phone_number\",\n \"phone_number_2\",\n \"email\",\n \"city\",\n \"address\",\n \"postal_code\",\n \"birth_date\",\n \"photo_url\",\n ];\n userFields.forEach((field) => {\n if (original[field] !== current[field]) {\n // @ts-expect-error - jspdf types are a bit funky\n userData[field] = current[field];\n }\n });\n\n // Helper for array diffs\n const calculateArrayDiff = (origArray: any[] = [], currArray: any[] = []) => {\n const changes: any[] = [];\n const origMap = new Map(origArray.map((item) => [item.id, item]));\n\n currArray.forEach((currItem) => {\n const origItem = origMap.get(currItem.id);\n if (!origItem) {\n // New item\n changes.push({ action: \"create\" as Action, data: currItem });\n } else if (JSON.stringify(origItem) !== JSON.stringify(currItem)) {\n // Updated item\n changes.push({ action: \"update\" as Action, data: currItem, id: currItem.id });\n }\n });\n\n const currMap = new Map(currArray.map((item) => [item.id, item]));\n origArray.forEach((origItem) => {\n if (!currMap.has(origItem.id)) {\n // Deleted item\n changes.push({ action: \"delete\" as Action, id: origItem.id });\n }\n });\n\n return changes;\n };\n\n const experiencesDiff = [\n ...calculateArrayDiff(original.work_experience, current.work_experience),\n ...calculateArrayDiff(original.education, current.education),\n ...calculateArrayDiff(original.activities, current.activities),\n ];\n\n const hwOrig = original.skills?.hard || [];\n const hwCurr = current.skills?.hard || [];\n const swOrig = original.skills?.soft || [];\n const swCurr = current.skills?.soft || [];\n\n const skillsDiff = [...calculateArrayDiff(hwOrig, hwCurr), ...calculateArrayDiff(swOrig, swCurr)];\n\n return {\n candidate: {\n action: Object.keys(candidateData).length > 0 ? \"update\" : \"none\",\n data: candidateData,\n },\n user: {\n action: Object.keys(userData).length > 0 ? \"update\" : \"none\",\n data: userData,\n },\n curriculum: {\n action: original.summary !== current.summary ? \"update\" : \"none\",\n data: { summary: current.summary },\n },\n experiences: experiencesDiff,\n skills: skillsDiff,\n certifications: calculateArrayDiff(original.certifications, current.certifications),\n };\n}\n\nexport function Resume({\n data,\n editable = false,\n headerSlot,\n withDownload = false,\n theme = \"hsl(var(--secondary))\",\n hideFields = [],\n hideSections = [],\n menuSlot = [],\n onSave,\n showTopBar = true,\n className,\n}: ResumeProps) {\n const themeStyle = theme ? ({ \"--cv-theme\": theme } as React.CSSProperties) : undefined;\n const [draftData, setDraftData] = useState<CandidateProfile>(data);\n const [isOpen, setIsOpen] = useState(false);\n const [isDownloading, setIsDownloading] = useState(false);\n const previewRef = useRef<HTMLDivElement>(null);\n\n const handleOpenChange = (open: boolean) => {\n if (open) {\n setDraftData(data);\n }\n setIsOpen(open);\n };\n\n const handleSave = () => {\n if (onSave) {\n const payload = calculateDiffs(data, draftData);\n onSave(payload, draftData);\n }\n setIsOpen(false);\n };\n\n const handleDownload = async () => {\n if (!previewRef.current || isDownloading) return;\n setIsDownloading(true);\n\n try {\n const element = previewRef.current;\n const canvas = await html2canvas(element, {\n scale: 2,\n useCORS: true,\n backgroundColor: \"#ffffff\",\n logging: false,\n windowWidth: 1200, // Force desktop layout breakpoint\n onclone: (clonedDoc) => {\n const clonedElement = clonedDoc.getElementById(\"resume-capture-area\");\n if (clonedElement instanceof HTMLElement) {\n clonedElement.style.height = \"auto\";\n clonedElement.style.overflow = \"visible\";\n clonedElement.style.width = \"1200px\";\n\n // Fix Background: html2canvas doesn't support mask-image. Render gradient to canvas\n // and use as background-image for pixel-perfect PDF output.\n const backgroundGradients = clonedElement.querySelectorAll(\"[data-pdf-background-gradient]\");\n const w = 1200;\n const h = 160;\n const canvas = clonedDoc.createElement(\"canvas\");\n canvas.width = w;\n canvas.height = h;\n const ctx = canvas.getContext(\"2d\");\n if (ctx) {\n const hGrad = ctx.createLinearGradient(0, 0, w, 0);\n hGrad.addColorStop(0, \"#ffffff\");\n hGrad.addColorStop(0.5, \"#f3e8ff\");\n hGrad.addColorStop(1, \"#bfdbfe\");\n ctx.fillStyle = hGrad;\n ctx.fillRect(0, 0, w, h);\n ctx.globalCompositeOperation = \"destination-in\";\n const vGrad = ctx.createLinearGradient(0, 0, 0, h);\n vGrad.addColorStop(0, \"rgba(0,0,0,1)\");\n vGrad.addColorStop(1, \"rgba(0,0,0,0)\");\n ctx.fillStyle = vGrad;\n ctx.fillRect(0, 0, w, h);\n ctx.globalCompositeOperation = \"source-over\";\n }\n const dataUrl = canvas.toDataURL(\"image/png\");\n backgroundGradients.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.maskImage = \"none\";\n el.style.background = \"none\";\n el.style.backgroundImage = `url(${dataUrl})`;\n el.style.backgroundSize = \"100% 100%\";\n el.style.backgroundPosition = \"0 0\";\n }\n });\n\n // Fix for images with object-fit: cover not being respected by html2canvas\n const objectCoverImages = clonedElement.querySelectorAll(\"img.object-cover\");\n objectCoverImages.forEach((img) => {\n if (img instanceof HTMLImageElement) {\n const parent = img.parentElement;\n if (parent) {\n // Replace img with a div that has background-image: cover\n const div = clonedDoc.createElement(\"div\");\n div.style.width = \"100%\";\n div.style.height = \"100%\";\n div.style.backgroundImage = `url(${img.src})`;\n div.style.backgroundSize = \"cover\";\n div.style.backgroundPosition = \"center\";\n div.style.borderRadius = window.getComputedStyle(img).borderRadius;\n div.className = img.className;\n parent.style.marginTop = \"1.33rem\";\n parent.replaceChild(div, img);\n }\n }\n });\n\n // Hide elements marked as hidden for PDF\n const hiddenElements = clonedElement.querySelectorAll(\".pdf-hidden\");\n hiddenElements.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"none\";\n }\n });\n\n // Fix SVG vertical alignment for html2canvas\n // html2canvas doesn't properly handle flex align-items with SVGs\n const svgs = clonedElement.querySelectorAll(\"svg\");\n svgs.forEach((svg) => {\n svg.style.display = \"inline-block\";\n svg.style.verticalAlign = \"middle\";\n svg.style.flexShrink = \"0\";\n svg.style.marginRight = \"0.4rem\";\n svg.style.marginBottom = \"-1.2rem\";\n });\n\n // Fix line-clamp which causes text vertical cut-offs in html2canvas\n const clampElements = clonedElement.querySelectorAll(\n \".line-clamp-1, .line-clamp-2, .line-clamp-3\",\n );\n clampElements.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"block\";\n el.style.webkitLineClamp = \"unset\";\n el.style.webkitBoxOrient = \"unset\";\n el.style.overflow = \"visible\";\n el.style.whiteSpace = \"normal\";\n el.style.lineHeight = \"1.5\";\n }\n });\n\n // Replace generic HTML elements like custom badges with simple spans\n // because html2canvas struggles with flexbox and strict borders inside round pills\n const badges = clonedElement.querySelectorAll(\".pdf-badge\");\n badges.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.paddingTop = \"-10px\";\n el.style.display = \"block\";\n el.style.paddingTop = \"0px\";\n el.style.paddingBottom = \"0.8rem\";\n }\n });\n\n // Fix headers with bottom borders losing padding/margin\n const headersWithBorders = clonedElement.querySelectorAll(\"h1, h2, h3, h4\");\n headersWithBorders.forEach((el) => {\n if (el instanceof HTMLElement) {\n const hasBorder =\n el.className.includes(\"border-b\") || el.style.borderBottomWidth !== \"\";\n if (hasBorder) {\n el.style.paddingBottom = \"1.2rem\";\n }\n }\n });\n\n // Add margin top to pdf-line-v elements\n const verticalLines = clonedElement.querySelectorAll(\".pdf-line-v\");\n verticalLines.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.marginTop = \"0.5rem\";\n el.style.zIndex = \"5\";\n }\n });\n\n // Add margin bottom to initials in header for better alignment in PDF\n const headerInitials = clonedElement.querySelectorAll(\".pdf-header-initials\");\n headerInitials.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.paddingBottom = \"2rem\";\n }\n });\n\n // Add styles to summary for PDF\n const summaries = clonedElement.querySelectorAll(\".pdf-summary\");\n summaries.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.width = \"100%\";\n el.style.maxWidth = \"100%\";\n el.style.marginTop = \"1.5rem\";\n }\n });\n\n // Show footer in PDF and force grayscale for the logo\n const pdfFooters = clonedElement.querySelectorAll(\".pdf-footer\");\n pdfFooters.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"flex\";\n }\n });\n\n // Also make sure parent containers don't restrict height\n let parent = clonedElement.parentElement;\n while (parent) {\n parent.style.height = \"auto\";\n parent.style.overflow = \"visible\";\n parent = parent.parentElement;\n }\n }\n },\n });\n\n const imgData = canvas.toDataURL(\"image/jpeg\", 1);\n const imgWidthPx = canvas.width;\n const imgHeightPx = canvas.height;\n\n // Convert px to mm (at 96 DPI base * scale factor)\n const pxToMm = 25.4 / (96 * 2);\n const pdfWidth = imgWidthPx * pxToMm;\n const pdfHeight = imgHeightPx * pxToMm;\n\n const pdf = new jsPDF({\n orientation: pdfWidth > pdfHeight ? \"landscape\" : \"portrait\",\n unit: \"mm\",\n format: [pdfWidth, pdfHeight],\n });\n\n pdf.addImage(imgData, \"JPEG\", 0, 0, pdfWidth, pdfHeight, undefined, \"FAST\");\n\n const fileName = `CV_${data.first_name}_${data.last_name}`.replace(/\\s+/g, \"_\");\n pdf.save(`${fileName}.pdf`);\n } catch (error) {\n console.error(\"Error generating PDF:\", error);\n } finally {\n setIsDownloading(false);\n }\n };\n\n return (\n <div\n className=\"relative h-full w-full overflow-y-auto bg-muted/20 px-4 py-4 sm:px-8\"\n style={themeStyle}\n >\n {/* Preview Panel - Takes full width, centered like a document */}\n <div className=\"mx-auto h-full w-full max-w-5xl\">\n <ResumePreview\n ref={previewRef}\n data={draftData}\n headerSlot={headerSlot}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n showTopBar={showTopBar}\n className={className}\n />\n </div>\n\n {/* Floating Action Buttons */}\n <div className=\"fixed bottom-6 right-6 z-50 flex flex-col gap-3 sm:flex-row\">\n {editable && (\n <Sheet open={isOpen} onOpenChange={handleOpenChange}>\n <SheetTrigger asChild>\n <Button\n size=\"lg\"\n className=\"flex items-center gap-2 rounded-full bg-primary px-4 text-primary-foreground shadow-xl hover:bg-primary/90\"\n >\n <Edit className=\"h-5 w-5\" />\n <span className=\"hidden font-semibold sm:inline\">Editar</span>\n </Button>\n </SheetTrigger>\n {/* Drawer opens from the right side, taking good width */}\n <SheetContent\n side=\"right\"\n showCloseButton={false}\n className=\"flex w-full flex-col overflow-hidden bg-card p-0 sm:max-w-md md:max-w-2xl\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-6 pb-2\">\n <SheetTitle className=\"text-2xl font-bold text-foreground\">Editar</SheetTitle>\n <SheetClose className=\"rounded-full p-2 opacity-70 transition-colors hover:bg-muted hover:opacity-100\">\n <X className=\"h-6 w-6 text-foreground\" />\n <span className=\"sr-only\">Cerrar</span>\n </SheetClose>\n </div>\n\n {/* Scrollable editor content */}\n <div className=\"flex-1 overflow-y-auto px-6 pb-6 pt-2\">\n <ResumeEditor\n data={draftData}\n onChange={setDraftData}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n menuSlot={menuSlot}\n />\n </div>\n\n {/* Sticky save footer */}\n {onSave && (\n <div className=\"flex justify-end gap-3 p-4\">\n <SheetClose asChild>\n <Button variant=\"outline\">Cancelar</Button>\n </SheetClose>\n <Button onClick={handleSave} className=\"gap-2\">\n <Save className=\"h-4 w-4\" />\n Guardar\n </Button>\n </div>\n )}\n </SheetContent>\n </Sheet>\n )}\n\n {withDownload && (\n <Button\n size=\"lg\"\n variant=\"ghost\"\n disabled={isDownloading}\n onClick={handleDownload}\n className=\"flex items-center gap-2 rounded-full bg-purple-200 px-4 text-purple-100 text-primary shadow-xl\"\n >\n {isDownloading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n <Download className=\"h-5 w-5\" />\n )}\n <span className=\"hidden font-semibold sm:inline\">\n {isDownloading ? \"Generando...\" : \"Descargar\"}\n </span>\n </Button>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["html2canvas","canvas","parent"]}
1
+ {"version":3,"sources":["../../../../src/components/domain/resume/resume.tsx"],"sourcesContent":["import { useRef, useState } from \"react\";\nimport html2canvas from \"html2canvas\";\nimport { jsPDF } from \"jspdf\";\nimport { CandidateProfile, ResumeProps, ResumeSavePayload, Action } from \"./types\";\nimport { ResumeEditor } from \"./resume-editor/resume-editor\";\nimport { ResumePreview } from \"./resume-preview/resume-preview\";\nimport { Button } from \"../../ui/button\";\nimport { Download, Edit, Loader2, Save, X } from \"lucide-react\";\nimport { Sheet, SheetTrigger, SheetContent, SheetTitle, SheetClose } from \"../../ui/sheet\";\n\nfunction calculateDiffs(original: CandidateProfile, current: CandidateProfile): ResumeSavePayload {\n // Determine diff for candidate table (academic info etc)\n const candidateData: Partial<CandidateProfile> = {};\n if (original.student_education_institution_id !== current.student_education_institution_id)\n candidateData.student_education_institution_id = current.student_education_institution_id;\n if (original.education_institution_id !== current.education_institution_id)\n candidateData.education_institution_id = current.education_institution_id;\n if (original.program_name !== current.program_name)\n candidateData.program_name = current.program_name;\n if (JSON.stringify(original.preferences) !== JSON.stringify(current.preferences))\n candidateData.preferences = current.preferences;\n if (JSON.stringify(original.advanced) !== JSON.stringify(current.advanced))\n candidateData.advanced = current.advanced;\n\n // Determine diff for user table (personal info)\n const userData: Partial<CandidateProfile> = {};\n const userFields: (keyof CandidateProfile)[] = [\n \"first_name\",\n \"middle_name\",\n \"last_name\",\n \"second_last_name\",\n \"phone_number\",\n \"phone_number_2\",\n \"email\",\n \"city\",\n \"address\",\n \"postal_code\",\n \"birth_date\",\n \"photo_url\",\n ];\n userFields.forEach((field) => {\n if (original[field] !== current[field]) {\n // @ts-expect-error - jspdf types are a bit funky\n userData[field] = current[field];\n }\n });\n\n // Helper for array diffs\n const calculateArrayDiff = (origArray: any[] = [], currArray: any[] = []) => {\n const changes: any[] = [];\n const origMap = new Map(origArray.map((item) => [item.id, item]));\n\n currArray.forEach((currItem) => {\n const origItem = origMap.get(currItem.id);\n if (!origItem) {\n // New item\n changes.push({ action: \"create\" as Action, data: currItem });\n } else if (JSON.stringify(origItem) !== JSON.stringify(currItem)) {\n // Updated item\n changes.push({ action: \"update\" as Action, data: currItem, id: currItem.id });\n }\n });\n\n const currMap = new Map(currArray.map((item) => [item.id, item]));\n origArray.forEach((origItem) => {\n if (!currMap.has(origItem.id)) {\n // Deleted item\n changes.push({ action: \"delete\" as Action, id: origItem.id });\n }\n });\n\n return changes;\n };\n\n const experiencesDiff = [\n ...calculateArrayDiff(original.work_experience, current.work_experience),\n ...calculateArrayDiff(original.education, current.education),\n ...calculateArrayDiff(original.activities, current.activities),\n ];\n\n const hwOrig = original.skills?.hard || [];\n const hwCurr = current.skills?.hard || [];\n const swOrig = original.skills?.soft || [];\n const swCurr = current.skills?.soft || [];\n\n const skillsDiff = [...calculateArrayDiff(hwOrig, hwCurr), ...calculateArrayDiff(swOrig, swCurr)];\n\n return {\n candidate: {\n action: Object.keys(candidateData).length > 0 ? \"update\" : \"none\",\n data: candidateData,\n },\n user: {\n action: Object.keys(userData).length > 0 ? \"update\" : \"none\",\n data: userData,\n },\n curriculum: {\n action: original.summary !== current.summary ? \"update\" : \"none\",\n data: { summary: current.summary },\n },\n experiences: experiencesDiff,\n skills: skillsDiff,\n certifications: calculateArrayDiff(original.certifications, current.certifications),\n };\n}\n\nexport function Resume({\n data,\n editable = false,\n headerSlot,\n withDownload = false,\n theme = \"hsl(var(--secondary))\",\n hideFields = [],\n hideSections = [],\n menuSlot = [],\n onSave,\n showTopBar = true,\n className,\n}: ResumeProps) {\n const themeStyle = theme ? ({ \"--cv-theme\": theme } as React.CSSProperties) : undefined;\n const [draftData, setDraftData] = useState<CandidateProfile>(data);\n const [isOpen, setIsOpen] = useState(false);\n const [isDownloading, setIsDownloading] = useState(false);\n const previewRef = useRef<HTMLDivElement>(null);\n\n const handleOpenChange = (open: boolean) => {\n if (open) {\n setDraftData(data);\n }\n setIsOpen(open);\n };\n\n const handleSave = () => {\n if (onSave) {\n const payload = calculateDiffs(data, draftData);\n onSave(payload, draftData);\n }\n setIsOpen(false);\n };\n\n const handleDownload = async () => {\n if (!previewRef.current || isDownloading) return;\n setIsDownloading(true);\n\n try {\n const element = previewRef.current;\n const canvas = await html2canvas(element, {\n scale: 2,\n useCORS: true,\n backgroundColor: \"#ffffff\",\n logging: false,\n windowWidth: 1200, // Force desktop layout breakpoint\n onclone: (clonedDoc) => {\n const clonedElement = clonedDoc.getElementById(\"resume-capture-area\");\n if (clonedElement instanceof HTMLElement) {\n clonedElement.style.height = \"auto\";\n clonedElement.style.overflow = \"visible\";\n clonedElement.style.width = \"1200px\";\n\n // Fix Background: html2canvas doesn't support mask-image. Render gradient to canvas\n // and use as background-image for pixel-perfect PDF output.\n const backgroundGradients = clonedElement.querySelectorAll(\"[data-pdf-background-gradient]\");\n const w = 1200;\n const h = 160;\n const canvas = clonedDoc.createElement(\"canvas\");\n canvas.width = w;\n canvas.height = h;\n const ctx = canvas.getContext(\"2d\");\n if (ctx) {\n const hGrad = ctx.createLinearGradient(0, 0, w, 0);\n hGrad.addColorStop(0, \"#ffffff\");\n hGrad.addColorStop(0.5, \"#f3e8ff\");\n hGrad.addColorStop(1, \"#bfdbfe\");\n ctx.fillStyle = hGrad;\n ctx.fillRect(0, 0, w, h);\n ctx.globalCompositeOperation = \"destination-in\";\n const vGrad = ctx.createLinearGradient(0, 0, 0, h);\n vGrad.addColorStop(0, \"rgba(0,0,0,1)\");\n vGrad.addColorStop(1, \"rgba(0,0,0,0)\");\n ctx.fillStyle = vGrad;\n ctx.fillRect(0, 0, w, h);\n ctx.globalCompositeOperation = \"source-over\";\n }\n const dataUrl = canvas.toDataURL(\"image/png\");\n backgroundGradients.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.maskImage = \"none\";\n el.style.background = \"none\";\n el.style.backgroundImage = `url(${dataUrl})`;\n el.style.backgroundSize = \"100% 100%\";\n el.style.backgroundPosition = \"0 0\";\n }\n });\n\n // Fix for images with object-fit: cover not being respected by html2canvas\n const objectCoverImages = clonedElement.querySelectorAll(\"img.object-cover\");\n objectCoverImages.forEach((img) => {\n if (img instanceof HTMLImageElement) {\n const parent = img.parentElement;\n if (parent) {\n // Replace img with a div that has background-image: cover\n const div = clonedDoc.createElement(\"div\");\n div.style.width = \"100%\";\n div.style.height = \"100%\";\n div.style.backgroundImage = `url(${img.src})`;\n div.style.backgroundSize = \"cover\";\n div.style.backgroundPosition = \"center\";\n div.style.borderRadius = window.getComputedStyle(img).borderRadius;\n div.className = img.className;\n parent.replaceChild(div, img);\n }\n }\n });\n\n // Fix Avatar alignment in PDF: apply consistent margin for both image and fallback\n const headerAvatars = clonedElement.querySelectorAll(\".pdf-header-avatar\");\n headerAvatars.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.marginTop = \"1.33rem\";\n }\n });\n\n // Hide elements marked as hidden for PDF\n const hiddenElements = clonedElement.querySelectorAll(\".pdf-hidden\");\n hiddenElements.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"none\";\n }\n });\n\n // Fix SVG vertical alignment for html2canvas\n // html2canvas doesn't properly handle flex align-items with SVGs\n const svgs = clonedElement.querySelectorAll(\"svg\");\n svgs.forEach((svg) => {\n svg.style.display = \"inline-block\";\n svg.style.verticalAlign = \"middle\";\n svg.style.flexShrink = \"0\";\n svg.style.marginRight = \"0.4rem\";\n svg.style.marginBottom = \"-1.2rem\";\n });\n\n // Fix line-clamp which causes text vertical cut-offs in html2canvas\n const clampElements = clonedElement.querySelectorAll(\n \".line-clamp-1, .line-clamp-2, .line-clamp-3\",\n );\n clampElements.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"block\";\n el.style.webkitLineClamp = \"unset\";\n el.style.webkitBoxOrient = \"unset\";\n el.style.overflow = \"visible\";\n el.style.whiteSpace = \"normal\";\n el.style.lineHeight = \"1.5\";\n }\n });\n\n // Replace generic HTML elements like custom badges with simple spans\n // because html2canvas struggles with flexbox and strict borders inside round pills\n const badges = clonedElement.querySelectorAll(\".pdf-badge\");\n badges.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.paddingTop = \"-10px\";\n el.style.display = \"block\";\n el.style.paddingTop = \"0px\";\n el.style.paddingBottom = \"0.8rem\";\n }\n });\n\n // Fix headers with bottom borders losing padding/margin\n const headersWithBorders = clonedElement.querySelectorAll(\"h1, h2, h3, h4\");\n headersWithBorders.forEach((el) => {\n if (el instanceof HTMLElement) {\n const hasBorder =\n el.className.includes(\"border-b\") || el.style.borderBottomWidth !== \"\";\n if (hasBorder) {\n el.style.paddingBottom = \"1.2rem\";\n }\n }\n });\n\n // Add margin top to pdf-line-v elements\n const verticalLines = clonedElement.querySelectorAll(\".pdf-line-v\");\n verticalLines.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.marginTop = \"0.5rem\";\n el.style.zIndex = \"5\";\n }\n });\n\n // Add margin bottom to initials in header for better alignment in PDF\n const headerInitials = clonedElement.querySelectorAll(\".pdf-header-initials\");\n headerInitials.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.paddingBottom = \"2rem\";\n }\n });\n\n // Add styles to summary for PDF\n const summaries = clonedElement.querySelectorAll(\".pdf-summary\");\n summaries.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.width = \"100%\";\n el.style.maxWidth = \"100%\";\n el.style.marginTop = \"1.5rem\";\n }\n });\n\n // Show footer in PDF and force grayscale for the logo\n const pdfFooters = clonedElement.querySelectorAll(\".pdf-footer\");\n pdfFooters.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"flex\";\n }\n });\n\n // Also make sure parent containers don't restrict height\n let parent = clonedElement.parentElement;\n while (parent) {\n parent.style.height = \"auto\";\n parent.style.overflow = \"visible\";\n parent = parent.parentElement;\n }\n }\n },\n });\n\n const imgData = canvas.toDataURL(\"image/jpeg\", 1);\n const imgWidthPx = canvas.width;\n const imgHeightPx = canvas.height;\n\n // Convert px to mm (at 96 DPI base * scale factor)\n const pxToMm = 25.4 / (96 * 2);\n const pdfWidth = imgWidthPx * pxToMm;\n const pdfHeight = imgHeightPx * pxToMm;\n\n const pdf = new jsPDF({\n orientation: pdfWidth > pdfHeight ? \"landscape\" : \"portrait\",\n unit: \"mm\",\n format: [pdfWidth, pdfHeight],\n });\n\n pdf.addImage(imgData, \"JPEG\", 0, 0, pdfWidth, pdfHeight, undefined, \"FAST\");\n\n const fileName = `CV_${data.first_name}_${data.last_name}`.replace(/\\s+/g, \"_\");\n pdf.save(`${fileName}.pdf`);\n } catch (error) {\n console.error(\"Error generating PDF:\", error);\n } finally {\n setIsDownloading(false);\n }\n };\n\n return (\n <div\n className=\"relative h-full w-full overflow-y-auto bg-muted/20 px-4 py-4 sm:px-8\"\n style={themeStyle}\n >\n {/* Preview Panel - Takes full width, centered like a document */}\n <div className=\"mx-auto h-full w-full max-w-5xl\">\n <ResumePreview\n ref={previewRef}\n data={draftData}\n headerSlot={headerSlot}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n showTopBar={showTopBar}\n className={className}\n />\n </div>\n\n {/* Floating Action Buttons */}\n <div className=\"fixed bottom-6 right-6 z-50 flex flex-col gap-3 sm:flex-row\">\n {editable && (\n <Sheet open={isOpen} onOpenChange={handleOpenChange}>\n <SheetTrigger asChild>\n <Button\n size=\"lg\"\n className=\"flex items-center gap-2 rounded-full bg-primary px-4 text-primary-foreground shadow-xl hover:bg-primary/90\"\n >\n <Edit className=\"h-5 w-5\" />\n <span className=\"hidden font-semibold sm:inline\">Editar</span>\n </Button>\n </SheetTrigger>\n {/* Drawer opens from the right side, taking good width */}\n <SheetContent\n side=\"right\"\n showCloseButton={false}\n className=\"flex w-full flex-col overflow-hidden bg-card p-0 sm:max-w-md md:max-w-2xl\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-6 pb-2\">\n <SheetTitle className=\"text-2xl font-bold text-foreground\">Editar</SheetTitle>\n <SheetClose className=\"rounded-full p-2 opacity-70 transition-colors hover:bg-muted hover:opacity-100\">\n <X className=\"h-6 w-6 text-foreground\" />\n <span className=\"sr-only\">Cerrar</span>\n </SheetClose>\n </div>\n\n {/* Scrollable editor content */}\n <div className=\"flex-1 overflow-y-auto px-6 pb-6 pt-2\">\n <ResumeEditor\n data={draftData}\n onChange={setDraftData}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n menuSlot={menuSlot}\n />\n </div>\n\n {/* Sticky save footer */}\n {onSave && (\n <div className=\"flex justify-end gap-3 p-4\">\n <SheetClose asChild>\n <Button variant=\"outline\">Cancelar</Button>\n </SheetClose>\n <Button onClick={handleSave} className=\"gap-2\">\n <Save className=\"h-4 w-4\" />\n Guardar\n </Button>\n </div>\n )}\n </SheetContent>\n </Sheet>\n )}\n\n {withDownload && (\n <Button\n size=\"lg\"\n variant=\"ghost\"\n disabled={isDownloading}\n onClick={handleDownload}\n className=\"flex items-center gap-2 rounded-full bg-purple-200 px-4 text-purple-100 text-primary shadow-xl\"\n >\n {isDownloading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n <Download className=\"h-5 w-5\" />\n )}\n <span className=\"hidden font-semibold sm:inline\">\n {isDownloading ? \"Generando...\" : \"Descargar\"}\n </span>\n </Button>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["html2canvas","canvas","parent"]}
@@ -180,11 +180,16 @@ function Resume({
180
180
  div.style.backgroundPosition = "center";
181
181
  div.style.borderRadius = window.getComputedStyle(img).borderRadius;
182
182
  div.className = img.className;
183
- parent2.style.marginTop = "1.33rem";
184
183
  parent2.replaceChild(div, img);
185
184
  }
186
185
  }
187
186
  });
187
+ const headerAvatars = clonedElement.querySelectorAll(".pdf-header-avatar");
188
+ headerAvatars.forEach((el) => {
189
+ if (el instanceof HTMLElement) {
190
+ el.style.marginTop = "1.33rem";
191
+ }
192
+ });
188
193
  const hiddenElements = clonedElement.querySelectorAll(".pdf-hidden");
189
194
  hiddenElements.forEach((el) => {
190
195
  if (el instanceof HTMLElement) {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/domain/resume/resume.tsx"],"sourcesContent":["import { useRef, useState } from \"react\";\nimport html2canvas from \"html2canvas\";\nimport { jsPDF } from \"jspdf\";\nimport { CandidateProfile, ResumeProps, ResumeSavePayload, Action } from \"./types\";\nimport { ResumeEditor } from \"./resume-editor/resume-editor\";\nimport { ResumePreview } from \"./resume-preview/resume-preview\";\nimport { Button } from \"../../ui/button\";\nimport { Download, Edit, Loader2, Save, X } from \"lucide-react\";\nimport { Sheet, SheetTrigger, SheetContent, SheetTitle, SheetClose } from \"../../ui/sheet\";\n\nfunction calculateDiffs(original: CandidateProfile, current: CandidateProfile): ResumeSavePayload {\n // Determine diff for candidate table (academic info etc)\n const candidateData: Partial<CandidateProfile> = {};\n if (original.student_education_institution_id !== current.student_education_institution_id)\n candidateData.student_education_institution_id = current.student_education_institution_id;\n if (original.education_institution_id !== current.education_institution_id)\n candidateData.education_institution_id = current.education_institution_id;\n if (original.program_name !== current.program_name)\n candidateData.program_name = current.program_name;\n if (JSON.stringify(original.preferences) !== JSON.stringify(current.preferences))\n candidateData.preferences = current.preferences;\n if (JSON.stringify(original.advanced) !== JSON.stringify(current.advanced))\n candidateData.advanced = current.advanced;\n\n // Determine diff for user table (personal info)\n const userData: Partial<CandidateProfile> = {};\n const userFields: (keyof CandidateProfile)[] = [\n \"first_name\",\n \"middle_name\",\n \"last_name\",\n \"second_last_name\",\n \"phone_number\",\n \"phone_number_2\",\n \"email\",\n \"city\",\n \"address\",\n \"postal_code\",\n \"birth_date\",\n \"photo_url\",\n ];\n userFields.forEach((field) => {\n if (original[field] !== current[field]) {\n // @ts-expect-error - jspdf types are a bit funky\n userData[field] = current[field];\n }\n });\n\n // Helper for array diffs\n const calculateArrayDiff = (origArray: any[] = [], currArray: any[] = []) => {\n const changes: any[] = [];\n const origMap = new Map(origArray.map((item) => [item.id, item]));\n\n currArray.forEach((currItem) => {\n const origItem = origMap.get(currItem.id);\n if (!origItem) {\n // New item\n changes.push({ action: \"create\" as Action, data: currItem });\n } else if (JSON.stringify(origItem) !== JSON.stringify(currItem)) {\n // Updated item\n changes.push({ action: \"update\" as Action, data: currItem, id: currItem.id });\n }\n });\n\n const currMap = new Map(currArray.map((item) => [item.id, item]));\n origArray.forEach((origItem) => {\n if (!currMap.has(origItem.id)) {\n // Deleted item\n changes.push({ action: \"delete\" as Action, id: origItem.id });\n }\n });\n\n return changes;\n };\n\n const experiencesDiff = [\n ...calculateArrayDiff(original.work_experience, current.work_experience),\n ...calculateArrayDiff(original.education, current.education),\n ...calculateArrayDiff(original.activities, current.activities),\n ];\n\n const hwOrig = original.skills?.hard || [];\n const hwCurr = current.skills?.hard || [];\n const swOrig = original.skills?.soft || [];\n const swCurr = current.skills?.soft || [];\n\n const skillsDiff = [...calculateArrayDiff(hwOrig, hwCurr), ...calculateArrayDiff(swOrig, swCurr)];\n\n return {\n candidate: {\n action: Object.keys(candidateData).length > 0 ? \"update\" : \"none\",\n data: candidateData,\n },\n user: {\n action: Object.keys(userData).length > 0 ? \"update\" : \"none\",\n data: userData,\n },\n curriculum: {\n action: original.summary !== current.summary ? \"update\" : \"none\",\n data: { summary: current.summary },\n },\n experiences: experiencesDiff,\n skills: skillsDiff,\n certifications: calculateArrayDiff(original.certifications, current.certifications),\n };\n}\n\nexport function Resume({\n data,\n editable = false,\n headerSlot,\n withDownload = false,\n theme = \"hsl(var(--secondary))\",\n hideFields = [],\n hideSections = [],\n menuSlot = [],\n onSave,\n showTopBar = true,\n className,\n}: ResumeProps) {\n const themeStyle = theme ? ({ \"--cv-theme\": theme } as React.CSSProperties) : undefined;\n const [draftData, setDraftData] = useState<CandidateProfile>(data);\n const [isOpen, setIsOpen] = useState(false);\n const [isDownloading, setIsDownloading] = useState(false);\n const previewRef = useRef<HTMLDivElement>(null);\n\n const handleOpenChange = (open: boolean) => {\n if (open) {\n setDraftData(data);\n }\n setIsOpen(open);\n };\n\n const handleSave = () => {\n if (onSave) {\n const payload = calculateDiffs(data, draftData);\n onSave(payload, draftData);\n }\n setIsOpen(false);\n };\n\n const handleDownload = async () => {\n if (!previewRef.current || isDownloading) return;\n setIsDownloading(true);\n\n try {\n const element = previewRef.current;\n const canvas = await html2canvas(element, {\n scale: 2,\n useCORS: true,\n backgroundColor: \"#ffffff\",\n logging: false,\n windowWidth: 1200, // Force desktop layout breakpoint\n onclone: (clonedDoc) => {\n const clonedElement = clonedDoc.getElementById(\"resume-capture-area\");\n if (clonedElement instanceof HTMLElement) {\n clonedElement.style.height = \"auto\";\n clonedElement.style.overflow = \"visible\";\n clonedElement.style.width = \"1200px\";\n\n // Fix Background: html2canvas doesn't support mask-image. Render gradient to canvas\n // and use as background-image for pixel-perfect PDF output.\n const backgroundGradients = clonedElement.querySelectorAll(\"[data-pdf-background-gradient]\");\n const w = 1200;\n const h = 160;\n const canvas = clonedDoc.createElement(\"canvas\");\n canvas.width = w;\n canvas.height = h;\n const ctx = canvas.getContext(\"2d\");\n if (ctx) {\n const hGrad = ctx.createLinearGradient(0, 0, w, 0);\n hGrad.addColorStop(0, \"#ffffff\");\n hGrad.addColorStop(0.5, \"#f3e8ff\");\n hGrad.addColorStop(1, \"#bfdbfe\");\n ctx.fillStyle = hGrad;\n ctx.fillRect(0, 0, w, h);\n ctx.globalCompositeOperation = \"destination-in\";\n const vGrad = ctx.createLinearGradient(0, 0, 0, h);\n vGrad.addColorStop(0, \"rgba(0,0,0,1)\");\n vGrad.addColorStop(1, \"rgba(0,0,0,0)\");\n ctx.fillStyle = vGrad;\n ctx.fillRect(0, 0, w, h);\n ctx.globalCompositeOperation = \"source-over\";\n }\n const dataUrl = canvas.toDataURL(\"image/png\");\n backgroundGradients.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.maskImage = \"none\";\n el.style.background = \"none\";\n el.style.backgroundImage = `url(${dataUrl})`;\n el.style.backgroundSize = \"100% 100%\";\n el.style.backgroundPosition = \"0 0\";\n }\n });\n\n // Fix for images with object-fit: cover not being respected by html2canvas\n const objectCoverImages = clonedElement.querySelectorAll(\"img.object-cover\");\n objectCoverImages.forEach((img) => {\n if (img instanceof HTMLImageElement) {\n const parent = img.parentElement;\n if (parent) {\n // Replace img with a div that has background-image: cover\n const div = clonedDoc.createElement(\"div\");\n div.style.width = \"100%\";\n div.style.height = \"100%\";\n div.style.backgroundImage = `url(${img.src})`;\n div.style.backgroundSize = \"cover\";\n div.style.backgroundPosition = \"center\";\n div.style.borderRadius = window.getComputedStyle(img).borderRadius;\n div.className = img.className;\n parent.style.marginTop = \"1.33rem\";\n parent.replaceChild(div, img);\n }\n }\n });\n\n // Hide elements marked as hidden for PDF\n const hiddenElements = clonedElement.querySelectorAll(\".pdf-hidden\");\n hiddenElements.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"none\";\n }\n });\n\n // Fix SVG vertical alignment for html2canvas\n // html2canvas doesn't properly handle flex align-items with SVGs\n const svgs = clonedElement.querySelectorAll(\"svg\");\n svgs.forEach((svg) => {\n svg.style.display = \"inline-block\";\n svg.style.verticalAlign = \"middle\";\n svg.style.flexShrink = \"0\";\n svg.style.marginRight = \"0.4rem\";\n svg.style.marginBottom = \"-1.2rem\";\n });\n\n // Fix line-clamp which causes text vertical cut-offs in html2canvas\n const clampElements = clonedElement.querySelectorAll(\n \".line-clamp-1, .line-clamp-2, .line-clamp-3\",\n );\n clampElements.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"block\";\n el.style.webkitLineClamp = \"unset\";\n el.style.webkitBoxOrient = \"unset\";\n el.style.overflow = \"visible\";\n el.style.whiteSpace = \"normal\";\n el.style.lineHeight = \"1.5\";\n }\n });\n\n // Replace generic HTML elements like custom badges with simple spans\n // because html2canvas struggles with flexbox and strict borders inside round pills\n const badges = clonedElement.querySelectorAll(\".pdf-badge\");\n badges.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.paddingTop = \"-10px\";\n el.style.display = \"block\";\n el.style.paddingTop = \"0px\";\n el.style.paddingBottom = \"0.8rem\";\n }\n });\n\n // Fix headers with bottom borders losing padding/margin\n const headersWithBorders = clonedElement.querySelectorAll(\"h1, h2, h3, h4\");\n headersWithBorders.forEach((el) => {\n if (el instanceof HTMLElement) {\n const hasBorder =\n el.className.includes(\"border-b\") || el.style.borderBottomWidth !== \"\";\n if (hasBorder) {\n el.style.paddingBottom = \"1.2rem\";\n }\n }\n });\n\n // Add margin top to pdf-line-v elements\n const verticalLines = clonedElement.querySelectorAll(\".pdf-line-v\");\n verticalLines.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.marginTop = \"0.5rem\";\n el.style.zIndex = \"5\";\n }\n });\n\n // Add margin bottom to initials in header for better alignment in PDF\n const headerInitials = clonedElement.querySelectorAll(\".pdf-header-initials\");\n headerInitials.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.paddingBottom = \"2rem\";\n }\n });\n\n // Add styles to summary for PDF\n const summaries = clonedElement.querySelectorAll(\".pdf-summary\");\n summaries.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.width = \"100%\";\n el.style.maxWidth = \"100%\";\n el.style.marginTop = \"1.5rem\";\n }\n });\n\n // Show footer in PDF and force grayscale for the logo\n const pdfFooters = clonedElement.querySelectorAll(\".pdf-footer\");\n pdfFooters.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"flex\";\n }\n });\n\n // Also make sure parent containers don't restrict height\n let parent = clonedElement.parentElement;\n while (parent) {\n parent.style.height = \"auto\";\n parent.style.overflow = \"visible\";\n parent = parent.parentElement;\n }\n }\n },\n });\n\n const imgData = canvas.toDataURL(\"image/jpeg\", 1);\n const imgWidthPx = canvas.width;\n const imgHeightPx = canvas.height;\n\n // Convert px to mm (at 96 DPI base * scale factor)\n const pxToMm = 25.4 / (96 * 2);\n const pdfWidth = imgWidthPx * pxToMm;\n const pdfHeight = imgHeightPx * pxToMm;\n\n const pdf = new jsPDF({\n orientation: pdfWidth > pdfHeight ? \"landscape\" : \"portrait\",\n unit: \"mm\",\n format: [pdfWidth, pdfHeight],\n });\n\n pdf.addImage(imgData, \"JPEG\", 0, 0, pdfWidth, pdfHeight, undefined, \"FAST\");\n\n const fileName = `CV_${data.first_name}_${data.last_name}`.replace(/\\s+/g, \"_\");\n pdf.save(`${fileName}.pdf`);\n } catch (error) {\n console.error(\"Error generating PDF:\", error);\n } finally {\n setIsDownloading(false);\n }\n };\n\n return (\n <div\n className=\"relative h-full w-full overflow-y-auto bg-muted/20 px-4 py-4 sm:px-8\"\n style={themeStyle}\n >\n {/* Preview Panel - Takes full width, centered like a document */}\n <div className=\"mx-auto h-full w-full max-w-5xl\">\n <ResumePreview\n ref={previewRef}\n data={draftData}\n headerSlot={headerSlot}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n showTopBar={showTopBar}\n className={className}\n />\n </div>\n\n {/* Floating Action Buttons */}\n <div className=\"fixed bottom-6 right-6 z-50 flex flex-col gap-3 sm:flex-row\">\n {editable && (\n <Sheet open={isOpen} onOpenChange={handleOpenChange}>\n <SheetTrigger asChild>\n <Button\n size=\"lg\"\n className=\"flex items-center gap-2 rounded-full bg-primary px-4 text-primary-foreground shadow-xl hover:bg-primary/90\"\n >\n <Edit className=\"h-5 w-5\" />\n <span className=\"hidden font-semibold sm:inline\">Editar</span>\n </Button>\n </SheetTrigger>\n {/* Drawer opens from the right side, taking good width */}\n <SheetContent\n side=\"right\"\n showCloseButton={false}\n className=\"flex w-full flex-col overflow-hidden bg-card p-0 sm:max-w-md md:max-w-2xl\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-6 pb-2\">\n <SheetTitle className=\"text-2xl font-bold text-foreground\">Editar</SheetTitle>\n <SheetClose className=\"rounded-full p-2 opacity-70 transition-colors hover:bg-muted hover:opacity-100\">\n <X className=\"h-6 w-6 text-foreground\" />\n <span className=\"sr-only\">Cerrar</span>\n </SheetClose>\n </div>\n\n {/* Scrollable editor content */}\n <div className=\"flex-1 overflow-y-auto px-6 pb-6 pt-2\">\n <ResumeEditor\n data={draftData}\n onChange={setDraftData}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n menuSlot={menuSlot}\n />\n </div>\n\n {/* Sticky save footer */}\n {onSave && (\n <div className=\"flex justify-end gap-3 p-4\">\n <SheetClose asChild>\n <Button variant=\"outline\">Cancelar</Button>\n </SheetClose>\n <Button onClick={handleSave} className=\"gap-2\">\n <Save className=\"h-4 w-4\" />\n Guardar\n </Button>\n </div>\n )}\n </SheetContent>\n </Sheet>\n )}\n\n {withDownload && (\n <Button\n size=\"lg\"\n variant=\"ghost\"\n disabled={isDownloading}\n onClick={handleDownload}\n className=\"flex items-center gap-2 rounded-full bg-purple-200 px-4 text-purple-100 text-primary shadow-xl\"\n >\n {isDownloading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n <Download className=\"h-5 w-5\" />\n )}\n <span className=\"hidden font-semibold sm:inline\">\n {isDownloading ? \"Generando...\" : \"Descargar\"}\n </span>\n </Button>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["canvas","parent"]}
1
+ {"version":3,"sources":["../../../../src/components/domain/resume/resume.tsx"],"sourcesContent":["import { useRef, useState } from \"react\";\nimport html2canvas from \"html2canvas\";\nimport { jsPDF } from \"jspdf\";\nimport { CandidateProfile, ResumeProps, ResumeSavePayload, Action } from \"./types\";\nimport { ResumeEditor } from \"./resume-editor/resume-editor\";\nimport { ResumePreview } from \"./resume-preview/resume-preview\";\nimport { Button } from \"../../ui/button\";\nimport { Download, Edit, Loader2, Save, X } from \"lucide-react\";\nimport { Sheet, SheetTrigger, SheetContent, SheetTitle, SheetClose } from \"../../ui/sheet\";\n\nfunction calculateDiffs(original: CandidateProfile, current: CandidateProfile): ResumeSavePayload {\n // Determine diff for candidate table (academic info etc)\n const candidateData: Partial<CandidateProfile> = {};\n if (original.student_education_institution_id !== current.student_education_institution_id)\n candidateData.student_education_institution_id = current.student_education_institution_id;\n if (original.education_institution_id !== current.education_institution_id)\n candidateData.education_institution_id = current.education_institution_id;\n if (original.program_name !== current.program_name)\n candidateData.program_name = current.program_name;\n if (JSON.stringify(original.preferences) !== JSON.stringify(current.preferences))\n candidateData.preferences = current.preferences;\n if (JSON.stringify(original.advanced) !== JSON.stringify(current.advanced))\n candidateData.advanced = current.advanced;\n\n // Determine diff for user table (personal info)\n const userData: Partial<CandidateProfile> = {};\n const userFields: (keyof CandidateProfile)[] = [\n \"first_name\",\n \"middle_name\",\n \"last_name\",\n \"second_last_name\",\n \"phone_number\",\n \"phone_number_2\",\n \"email\",\n \"city\",\n \"address\",\n \"postal_code\",\n \"birth_date\",\n \"photo_url\",\n ];\n userFields.forEach((field) => {\n if (original[field] !== current[field]) {\n // @ts-expect-error - jspdf types are a bit funky\n userData[field] = current[field];\n }\n });\n\n // Helper for array diffs\n const calculateArrayDiff = (origArray: any[] = [], currArray: any[] = []) => {\n const changes: any[] = [];\n const origMap = new Map(origArray.map((item) => [item.id, item]));\n\n currArray.forEach((currItem) => {\n const origItem = origMap.get(currItem.id);\n if (!origItem) {\n // New item\n changes.push({ action: \"create\" as Action, data: currItem });\n } else if (JSON.stringify(origItem) !== JSON.stringify(currItem)) {\n // Updated item\n changes.push({ action: \"update\" as Action, data: currItem, id: currItem.id });\n }\n });\n\n const currMap = new Map(currArray.map((item) => [item.id, item]));\n origArray.forEach((origItem) => {\n if (!currMap.has(origItem.id)) {\n // Deleted item\n changes.push({ action: \"delete\" as Action, id: origItem.id });\n }\n });\n\n return changes;\n };\n\n const experiencesDiff = [\n ...calculateArrayDiff(original.work_experience, current.work_experience),\n ...calculateArrayDiff(original.education, current.education),\n ...calculateArrayDiff(original.activities, current.activities),\n ];\n\n const hwOrig = original.skills?.hard || [];\n const hwCurr = current.skills?.hard || [];\n const swOrig = original.skills?.soft || [];\n const swCurr = current.skills?.soft || [];\n\n const skillsDiff = [...calculateArrayDiff(hwOrig, hwCurr), ...calculateArrayDiff(swOrig, swCurr)];\n\n return {\n candidate: {\n action: Object.keys(candidateData).length > 0 ? \"update\" : \"none\",\n data: candidateData,\n },\n user: {\n action: Object.keys(userData).length > 0 ? \"update\" : \"none\",\n data: userData,\n },\n curriculum: {\n action: original.summary !== current.summary ? \"update\" : \"none\",\n data: { summary: current.summary },\n },\n experiences: experiencesDiff,\n skills: skillsDiff,\n certifications: calculateArrayDiff(original.certifications, current.certifications),\n };\n}\n\nexport function Resume({\n data,\n editable = false,\n headerSlot,\n withDownload = false,\n theme = \"hsl(var(--secondary))\",\n hideFields = [],\n hideSections = [],\n menuSlot = [],\n onSave,\n showTopBar = true,\n className,\n}: ResumeProps) {\n const themeStyle = theme ? ({ \"--cv-theme\": theme } as React.CSSProperties) : undefined;\n const [draftData, setDraftData] = useState<CandidateProfile>(data);\n const [isOpen, setIsOpen] = useState(false);\n const [isDownloading, setIsDownloading] = useState(false);\n const previewRef = useRef<HTMLDivElement>(null);\n\n const handleOpenChange = (open: boolean) => {\n if (open) {\n setDraftData(data);\n }\n setIsOpen(open);\n };\n\n const handleSave = () => {\n if (onSave) {\n const payload = calculateDiffs(data, draftData);\n onSave(payload, draftData);\n }\n setIsOpen(false);\n };\n\n const handleDownload = async () => {\n if (!previewRef.current || isDownloading) return;\n setIsDownloading(true);\n\n try {\n const element = previewRef.current;\n const canvas = await html2canvas(element, {\n scale: 2,\n useCORS: true,\n backgroundColor: \"#ffffff\",\n logging: false,\n windowWidth: 1200, // Force desktop layout breakpoint\n onclone: (clonedDoc) => {\n const clonedElement = clonedDoc.getElementById(\"resume-capture-area\");\n if (clonedElement instanceof HTMLElement) {\n clonedElement.style.height = \"auto\";\n clonedElement.style.overflow = \"visible\";\n clonedElement.style.width = \"1200px\";\n\n // Fix Background: html2canvas doesn't support mask-image. Render gradient to canvas\n // and use as background-image for pixel-perfect PDF output.\n const backgroundGradients = clonedElement.querySelectorAll(\"[data-pdf-background-gradient]\");\n const w = 1200;\n const h = 160;\n const canvas = clonedDoc.createElement(\"canvas\");\n canvas.width = w;\n canvas.height = h;\n const ctx = canvas.getContext(\"2d\");\n if (ctx) {\n const hGrad = ctx.createLinearGradient(0, 0, w, 0);\n hGrad.addColorStop(0, \"#ffffff\");\n hGrad.addColorStop(0.5, \"#f3e8ff\");\n hGrad.addColorStop(1, \"#bfdbfe\");\n ctx.fillStyle = hGrad;\n ctx.fillRect(0, 0, w, h);\n ctx.globalCompositeOperation = \"destination-in\";\n const vGrad = ctx.createLinearGradient(0, 0, 0, h);\n vGrad.addColorStop(0, \"rgba(0,0,0,1)\");\n vGrad.addColorStop(1, \"rgba(0,0,0,0)\");\n ctx.fillStyle = vGrad;\n ctx.fillRect(0, 0, w, h);\n ctx.globalCompositeOperation = \"source-over\";\n }\n const dataUrl = canvas.toDataURL(\"image/png\");\n backgroundGradients.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.maskImage = \"none\";\n el.style.background = \"none\";\n el.style.backgroundImage = `url(${dataUrl})`;\n el.style.backgroundSize = \"100% 100%\";\n el.style.backgroundPosition = \"0 0\";\n }\n });\n\n // Fix for images with object-fit: cover not being respected by html2canvas\n const objectCoverImages = clonedElement.querySelectorAll(\"img.object-cover\");\n objectCoverImages.forEach((img) => {\n if (img instanceof HTMLImageElement) {\n const parent = img.parentElement;\n if (parent) {\n // Replace img with a div that has background-image: cover\n const div = clonedDoc.createElement(\"div\");\n div.style.width = \"100%\";\n div.style.height = \"100%\";\n div.style.backgroundImage = `url(${img.src})`;\n div.style.backgroundSize = \"cover\";\n div.style.backgroundPosition = \"center\";\n div.style.borderRadius = window.getComputedStyle(img).borderRadius;\n div.className = img.className;\n parent.replaceChild(div, img);\n }\n }\n });\n\n // Fix Avatar alignment in PDF: apply consistent margin for both image and fallback\n const headerAvatars = clonedElement.querySelectorAll(\".pdf-header-avatar\");\n headerAvatars.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.marginTop = \"1.33rem\";\n }\n });\n\n // Hide elements marked as hidden for PDF\n const hiddenElements = clonedElement.querySelectorAll(\".pdf-hidden\");\n hiddenElements.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"none\";\n }\n });\n\n // Fix SVG vertical alignment for html2canvas\n // html2canvas doesn't properly handle flex align-items with SVGs\n const svgs = clonedElement.querySelectorAll(\"svg\");\n svgs.forEach((svg) => {\n svg.style.display = \"inline-block\";\n svg.style.verticalAlign = \"middle\";\n svg.style.flexShrink = \"0\";\n svg.style.marginRight = \"0.4rem\";\n svg.style.marginBottom = \"-1.2rem\";\n });\n\n // Fix line-clamp which causes text vertical cut-offs in html2canvas\n const clampElements = clonedElement.querySelectorAll(\n \".line-clamp-1, .line-clamp-2, .line-clamp-3\",\n );\n clampElements.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"block\";\n el.style.webkitLineClamp = \"unset\";\n el.style.webkitBoxOrient = \"unset\";\n el.style.overflow = \"visible\";\n el.style.whiteSpace = \"normal\";\n el.style.lineHeight = \"1.5\";\n }\n });\n\n // Replace generic HTML elements like custom badges with simple spans\n // because html2canvas struggles with flexbox and strict borders inside round pills\n const badges = clonedElement.querySelectorAll(\".pdf-badge\");\n badges.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.paddingTop = \"-10px\";\n el.style.display = \"block\";\n el.style.paddingTop = \"0px\";\n el.style.paddingBottom = \"0.8rem\";\n }\n });\n\n // Fix headers with bottom borders losing padding/margin\n const headersWithBorders = clonedElement.querySelectorAll(\"h1, h2, h3, h4\");\n headersWithBorders.forEach((el) => {\n if (el instanceof HTMLElement) {\n const hasBorder =\n el.className.includes(\"border-b\") || el.style.borderBottomWidth !== \"\";\n if (hasBorder) {\n el.style.paddingBottom = \"1.2rem\";\n }\n }\n });\n\n // Add margin top to pdf-line-v elements\n const verticalLines = clonedElement.querySelectorAll(\".pdf-line-v\");\n verticalLines.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.marginTop = \"0.5rem\";\n el.style.zIndex = \"5\";\n }\n });\n\n // Add margin bottom to initials in header for better alignment in PDF\n const headerInitials = clonedElement.querySelectorAll(\".pdf-header-initials\");\n headerInitials.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.paddingBottom = \"2rem\";\n }\n });\n\n // Add styles to summary for PDF\n const summaries = clonedElement.querySelectorAll(\".pdf-summary\");\n summaries.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.width = \"100%\";\n el.style.maxWidth = \"100%\";\n el.style.marginTop = \"1.5rem\";\n }\n });\n\n // Show footer in PDF and force grayscale for the logo\n const pdfFooters = clonedElement.querySelectorAll(\".pdf-footer\");\n pdfFooters.forEach((el) => {\n if (el instanceof HTMLElement) {\n el.style.display = \"flex\";\n }\n });\n\n // Also make sure parent containers don't restrict height\n let parent = clonedElement.parentElement;\n while (parent) {\n parent.style.height = \"auto\";\n parent.style.overflow = \"visible\";\n parent = parent.parentElement;\n }\n }\n },\n });\n\n const imgData = canvas.toDataURL(\"image/jpeg\", 1);\n const imgWidthPx = canvas.width;\n const imgHeightPx = canvas.height;\n\n // Convert px to mm (at 96 DPI base * scale factor)\n const pxToMm = 25.4 / (96 * 2);\n const pdfWidth = imgWidthPx * pxToMm;\n const pdfHeight = imgHeightPx * pxToMm;\n\n const pdf = new jsPDF({\n orientation: pdfWidth > pdfHeight ? \"landscape\" : \"portrait\",\n unit: \"mm\",\n format: [pdfWidth, pdfHeight],\n });\n\n pdf.addImage(imgData, \"JPEG\", 0, 0, pdfWidth, pdfHeight, undefined, \"FAST\");\n\n const fileName = `CV_${data.first_name}_${data.last_name}`.replace(/\\s+/g, \"_\");\n pdf.save(`${fileName}.pdf`);\n } catch (error) {\n console.error(\"Error generating PDF:\", error);\n } finally {\n setIsDownloading(false);\n }\n };\n\n return (\n <div\n className=\"relative h-full w-full overflow-y-auto bg-muted/20 px-4 py-4 sm:px-8\"\n style={themeStyle}\n >\n {/* Preview Panel - Takes full width, centered like a document */}\n <div className=\"mx-auto h-full w-full max-w-5xl\">\n <ResumePreview\n ref={previewRef}\n data={draftData}\n headerSlot={headerSlot}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n showTopBar={showTopBar}\n className={className}\n />\n </div>\n\n {/* Floating Action Buttons */}\n <div className=\"fixed bottom-6 right-6 z-50 flex flex-col gap-3 sm:flex-row\">\n {editable && (\n <Sheet open={isOpen} onOpenChange={handleOpenChange}>\n <SheetTrigger asChild>\n <Button\n size=\"lg\"\n className=\"flex items-center gap-2 rounded-full bg-primary px-4 text-primary-foreground shadow-xl hover:bg-primary/90\"\n >\n <Edit className=\"h-5 w-5\" />\n <span className=\"hidden font-semibold sm:inline\">Editar</span>\n </Button>\n </SheetTrigger>\n {/* Drawer opens from the right side, taking good width */}\n <SheetContent\n side=\"right\"\n showCloseButton={false}\n className=\"flex w-full flex-col overflow-hidden bg-card p-0 sm:max-w-md md:max-w-2xl\"\n >\n {/* Header */}\n <div className=\"flex items-center justify-between p-6 pb-2\">\n <SheetTitle className=\"text-2xl font-bold text-foreground\">Editar</SheetTitle>\n <SheetClose className=\"rounded-full p-2 opacity-70 transition-colors hover:bg-muted hover:opacity-100\">\n <X className=\"h-6 w-6 text-foreground\" />\n <span className=\"sr-only\">Cerrar</span>\n </SheetClose>\n </div>\n\n {/* Scrollable editor content */}\n <div className=\"flex-1 overflow-y-auto px-6 pb-6 pt-2\">\n <ResumeEditor\n data={draftData}\n onChange={setDraftData}\n theme={theme}\n hideFields={hideFields}\n hideSections={hideSections}\n menuSlot={menuSlot}\n />\n </div>\n\n {/* Sticky save footer */}\n {onSave && (\n <div className=\"flex justify-end gap-3 p-4\">\n <SheetClose asChild>\n <Button variant=\"outline\">Cancelar</Button>\n </SheetClose>\n <Button onClick={handleSave} className=\"gap-2\">\n <Save className=\"h-4 w-4\" />\n Guardar\n </Button>\n </div>\n )}\n </SheetContent>\n </Sheet>\n )}\n\n {withDownload && (\n <Button\n size=\"lg\"\n variant=\"ghost\"\n disabled={isDownloading}\n onClick={handleDownload}\n className=\"flex items-center gap-2 rounded-full bg-purple-200 px-4 text-purple-100 text-primary shadow-xl\"\n >\n {isDownloading ? (\n <Loader2 className=\"h-5 w-5 animate-spin\" />\n ) : (\n <Download className=\"h-5 w-5\" />\n )}\n <span className=\"hidden font-semibold sm:inline\">\n {isDownloading ? \"Generando...\" : \"Descargar\"}\n </span>\n </Button>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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","names":["canvas","parent"]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/domain/resume/types.ts"],"sourcesContent":["import { ReactNode } from \"react\";\n\nexport type Action = \"create\" | \"update\" | \"delete\" | \"none\";\n\nexport interface CVExperienceBaseItem {\n id: string;\n title: string;\n type: string;\n institution_name?: string;\n institution_id?: string;\n start_date: string;\n end_date?: string;\n description?: string;\n}\n\nexport interface CVEducationItem extends CVExperienceBaseItem {\n _type?: \"education\";\n}\nexport interface CVExperienceItem extends CVExperienceBaseItem {\n _type?: \"experience\";\n}\nexport interface CVActivityItem extends CVExperienceBaseItem {\n _type?: \"activity\";\n}\n\nexport interface ExperienceWithAction extends CVExperienceBaseItem {\n action?: Action;\n}\n\nexport interface CVSkillItem {\n id: string;\n name: string;\n verified?: boolean;\n type?: string;\n}\n\nexport interface SkillWithAction extends CVSkillItem {\n action?: Action;\n}\n\nexport interface CVCertificationItem {\n id: string;\n title: string;\n institution_name?: string;\n institution_id?: string;\n date_awarded?: string;\n verified?: boolean;\n url?: string;\n}\n\nexport interface CertificationWithAction extends CVCertificationItem {\n action?: Action;\n}\n\nexport interface CVDocumentItem {\n id: string;\n document_type?: string;\n document_status?: string;\n document_url?: string;\n appointment_date?: string;\n comments?: string;\n}\n\nexport interface DocumentWithAction extends CVDocumentItem {\n action?: Action;\n}\n\nexport interface CandidateProfile {\n // Información personal (from user table)\n photo_url?: string;\n first_name: string;\n middle_name?: string;\n last_name: string;\n second_last_name?: string;\n phone_number?: string;\n phone_number_2?: string;\n email?: string;\n city?: string;\n address?: string;\n postal_code?: string;\n birth_date?: string;\n\n // Curriculum (from curriculum table)\n summary?: string;\n\n // Información Académica (from candidate table)\n student_education_institution_id?: string;\n education_institution_id?: string; // added this too for autocomplete logic\n program_name?: string;\n\n // Listados estructurados (from experience table, filtered by type)\n education?: CVEducationItem[];\n work_experience?: CVExperienceItem[];\n activities?: CVActivityItem[];\n\n // Habilidades (from skill table, grouped by type: hard/soft)\n skills?: {\n hard?: CVSkillItem[];\n soft?: CVSkillItem[];\n };\n\n // Certificaciones (from certification table)\n certifications?: CVCertificationItem[];\n\n // Requisitos laborales (from document table)\n work_requirements?: {\n documents: CVDocumentItem[];\n };\n\n // Preferencias (from candidate table fields)\n preferences?: {\n candidate_state?: string;\n employment_preference?: string;\n work_study_preference?: string;\n min_expected_salary?: number;\n max_expected_salary?: number;\n desired_role?: string;\n dream_job?: string;\n english_job_interest?: boolean;\n };\n\n // Avanzado\n advanced?: {\n notes?: string;\n };\n}\n\nexport interface ResumeSkill {\n id: string;\n name: string;\n type: \"Técnica\" | \"Interpersonal\";\n verified: boolean;\n}\nexport interface ResumeExperience {\n id: string;\n}\nexport interface ResumeEducation {\n id: string;\n}\nexport interface ResumeAward {\n id: string;\n}\n\nexport interface ResumeMenuSlot {\n title: string;\n node: ReactNode;\n}\n\nexport interface ResumeSavePayload {\n candidate: {\n action: Action;\n data: Partial<CandidateProfile>;\n };\n user: {\n action: Action;\n data: Partial<CandidateProfile>;\n };\n curriculum: {\n action: Action;\n data: {\n summary?: string;\n };\n };\n experiences: {\n action: Action;\n data: Partial<CVExperienceBaseItem>;\n id?: string;\n }[];\n skills: { action: Action; data: Partial<CVSkillItem>; id?: string }[];\n certifications: {\n action: Action;\n data: Partial<CVCertificationItem>;\n id?: string;\n }[];\n}\n\nexport interface ResumeProps {\n /**\n * Data del CV del candidato.\n */\n data: CandidateProfile;\n /**\n * Determina si el panel de edición (botón y drawer) es visible.\n * @default false\n */\n editable?: boolean;\n /**\n * Opciones u acciones extra a renderizar en la cabecera del preview.\n */\n headerSlot?: ReactNode;\n /**\n * Activa el botón flotante de descargar PDF.\n * @default false\n */\n withDownload?: boolean;\n /**\n * Color del tema (Hex, RGB o CSS color) usado para destacar el header, detalles y borde del avatar.\n * @default undefined (usa el primario de ginia-ui)\n */\n theme?: string;\n /**\n * Arreglo con la ruta de los campos a ocultar del editor y preview.\n * Por ejemplo: [\"first_name\", \"education.title\", \"skills.hard.verified\"]\n */\n hideFields?: string[];\n /**\n * Arreglo con los nombres de las secciones a ocultar completamente del editor y preview.\n * Por ejemplo: [\"Avanzado\", \"Preferencias\", \"Educación\"]\n */\n hideSections?: string[];\n /**\n * Slots adicionales para el menú del editor (Accordion).\n */\n menuSlot?: ResumeMenuSlot[];\n /**\n * Callback al guardar los cambios del editor.\n * Recibe el CandidateProfile actualizado y el array estructurado guardado por tipo de items\n */\n onSave?: (payload: ResumeSavePayload, fullProfile: CandidateProfile) => void;\n /**\n * Muestra u oculta la raya superior del preview.\n * @default true\n */\n showTopBar?: boolean;\n /**\n * Clases CSS adicionales para el contenedor del preview.\n */\n className?: string;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
1
+ {"version":3,"sources":["../../../../src/components/domain/resume/types.ts"],"sourcesContent":["import { ReactNode } from \"react\";\n\nexport type Action = \"create\" | \"update\" | \"delete\" | \"none\";\n\nexport interface CVExperienceBaseItem {\n id: string;\n title: string;\n type: string;\n institution_name?: string;\n institution_id?: string;\n start_date: string;\n end_date?: string;\n description?: string;\n}\n\nexport interface CVEducationItem extends CVExperienceBaseItem {\n _type?: \"education\";\n}\nexport interface CVExperienceItem extends CVExperienceBaseItem {\n _type?: \"experience\";\n}\nexport interface CVActivityItem extends CVExperienceBaseItem {\n _type?: \"activity\";\n}\n\nexport interface ExperienceWithAction extends CVExperienceBaseItem {\n action?: Action;\n}\n\nexport interface CVSkillItem {\n id: string;\n name: string;\n verified?: boolean;\n type?: string;\n}\n\nexport interface SkillWithAction extends CVSkillItem {\n action?: Action;\n}\n\nexport interface CVCertificationItem {\n id: string;\n title: string;\n institution_name?: string;\n institution_id?: string;\n date_awarded?: string;\n verified?: boolean;\n url?: string;\n}\n\nexport interface CertificationWithAction extends CVCertificationItem {\n action?: Action;\n}\n\nexport interface CVDocumentItem {\n id: string;\n document_type?: string;\n document_status?: string;\n document_url?: string;\n appointment_date?: string;\n comments?: string;\n}\n\nexport interface DocumentWithAction extends CVDocumentItem {\n action?: Action;\n}\n\nexport interface CandidateProfile {\n // Información personal (from user table)\n photo_url?: string;\n first_name: string;\n middle_name?: string;\n last_name: string;\n second_last_name?: string;\n phone_number?: string;\n phone_number_2?: string;\n email?: string;\n city?: string;\n address?: string;\n postal_code?: string;\n birth_date?: string;\n\n // Curriculum (from curriculum table)\n summary?: string;\n last_updated?: string; // ISO date or formatted string, e.g. \"2025-02-26\"\n\n // Información Académica (from candidate table)\n student_education_institution_id?: string;\n education_institution_id?: string; // added this too for autocomplete logic\n program_name?: string;\n\n // Listados estructurados (from experience table, filtered by type)\n education?: CVEducationItem[];\n work_experience?: CVExperienceItem[];\n activities?: CVActivityItem[];\n\n // Habilidades (from skill table, grouped by type: hard/soft)\n skills?: {\n hard?: CVSkillItem[];\n soft?: CVSkillItem[];\n };\n\n // Certificaciones (from certification table)\n certifications?: CVCertificationItem[];\n\n // Requisitos laborales (from document table)\n work_requirements?: {\n documents: CVDocumentItem[];\n };\n\n // Preferencias (from candidate table fields)\n preferences?: {\n candidate_state?: string;\n employment_preference?: string;\n work_study_preference?: string;\n min_expected_salary?: number;\n max_expected_salary?: number;\n desired_role?: string;\n dream_job?: string;\n english_job_interest?: boolean;\n };\n\n // Avanzado\n advanced?: {\n notes?: string;\n };\n}\n\nexport interface ResumeSkill {\n id: string;\n name: string;\n type: \"Técnica\" | \"Interpersonal\";\n verified: boolean;\n}\nexport interface ResumeExperience {\n id: string;\n}\nexport interface ResumeEducation {\n id: string;\n}\nexport interface ResumeAward {\n id: string;\n}\n\nexport interface ResumeMenuSlot {\n title: string;\n node: ReactNode;\n}\n\nexport interface ResumeSavePayload {\n candidate: {\n action: Action;\n data: Partial<CandidateProfile>;\n };\n user: {\n action: Action;\n data: Partial<CandidateProfile>;\n };\n curriculum: {\n action: Action;\n data: {\n summary?: string;\n };\n };\n experiences: {\n action: Action;\n data: Partial<CVExperienceBaseItem>;\n id?: string;\n }[];\n skills: { action: Action; data: Partial<CVSkillItem>; id?: string }[];\n certifications: {\n action: Action;\n data: Partial<CVCertificationItem>;\n id?: string;\n }[];\n}\n\nexport interface ResumeProps {\n /**\n * Data del CV del candidato.\n */\n data: CandidateProfile;\n /**\n * Determina si el panel de edición (botón y drawer) es visible.\n * @default false\n */\n editable?: boolean;\n /**\n * Opciones u acciones extra a renderizar en la cabecera del preview.\n */\n headerSlot?: ReactNode;\n /**\n * Activa el botón flotante de descargar PDF.\n * @default false\n */\n withDownload?: boolean;\n /**\n * Color del tema (Hex, RGB o CSS color) usado para destacar el header, detalles y borde del avatar.\n * @default undefined (usa el primario de ginia-ui)\n */\n theme?: string;\n /**\n * Arreglo con la ruta de los campos a ocultar del editor y preview.\n * Por ejemplo: [\"first_name\", \"education.title\", \"skills.hard.verified\"]\n */\n hideFields?: string[];\n /**\n * Arreglo con los nombres de las secciones a ocultar completamente del editor y preview.\n * Por ejemplo: [\"Avanzado\", \"Preferencias\", \"Educación\"]\n */\n hideSections?: string[];\n /**\n * Slots adicionales para el menú del editor (Accordion).\n */\n menuSlot?: ResumeMenuSlot[];\n /**\n * Callback al guardar los cambios del editor.\n * Recibe el CandidateProfile actualizado y el array estructurado guardado por tipo de items\n */\n onSave?: (payload: ResumeSavePayload, fullProfile: CandidateProfile) => void;\n /**\n * Muestra u oculta la raya superior del preview.\n * @default true\n */\n showTopBar?: boolean;\n /**\n * Clases CSS adicionales para el contenedor del preview.\n */\n className?: string;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
@@ -69,6 +69,7 @@ interface CandidateProfile {
69
69
  postal_code?: string;
70
70
  birth_date?: string;
71
71
  summary?: string;
72
+ last_updated?: string;
72
73
  student_education_institution_id?: string;
73
74
  education_institution_id?: string;
74
75
  program_name?: string;
@@ -69,6 +69,7 @@ interface CandidateProfile {
69
69
  postal_code?: string;
70
70
  birth_date?: string;
71
71
  summary?: string;
72
+ last_updated?: string;
72
73
  student_education_institution_id?: string;
73
74
  education_institution_id?: string;
74
75
  program_name?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ginia/ui",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Ginia Design System — Unified UI component library for all Ginia hubs",
5
5
  "license": "MIT",
6
6
  "private": false,