@ginia/ui 0.1.16 → 0.1.18
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.
- package/dist/components/domain/resume/resume-preview/sections/experience-education.cjs +33 -19
- package/dist/components/domain/resume/resume-preview/sections/experience-education.cjs.map +1 -1
- package/dist/components/domain/resume/resume-preview/sections/experience-education.js +33 -19
- package/dist/components/domain/resume/resume-preview/sections/experience-education.js.map +1 -1
- package/package.json +14 -14
|
@@ -30,19 +30,21 @@ function parseDateToTimestamp(dateStr) {
|
|
|
30
30
|
const isoMatch = dateStr.match(/^(\d{4})-(\d{1,2})(?:-(\d{1,2}))?/);
|
|
31
31
|
if (isoMatch) {
|
|
32
32
|
const [, y, m, d] = isoMatch;
|
|
33
|
-
const
|
|
34
|
-
|
|
33
|
+
const year2 = Number(y);
|
|
34
|
+
const monthIndex = Number(m) - 1;
|
|
35
|
+
const day = Number(d || "1");
|
|
36
|
+
return new Date(year2, monthIndex, day).getTime();
|
|
35
37
|
}
|
|
36
38
|
const mmYyyy = dateStr.match(/^(\d{1,2})\/(\d{4})$/);
|
|
37
39
|
if (mmYyyy) {
|
|
38
40
|
const [, m, y] = mmYyyy;
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
+
const year2 = Number(y);
|
|
42
|
+
const monthIndex = Number(m) - 1;
|
|
43
|
+
return new Date(year2, monthIndex, 1).getTime();
|
|
41
44
|
}
|
|
42
45
|
const year = dateStr.match(/\d{4}/);
|
|
43
46
|
if (year) {
|
|
44
|
-
|
|
45
|
-
return date.getTime();
|
|
47
|
+
return new Date(Number(year[0]), 0, 1).getTime();
|
|
46
48
|
}
|
|
47
49
|
return 0;
|
|
48
50
|
}
|
|
@@ -51,7 +53,13 @@ function formatDisplayDate(dateStr) {
|
|
|
51
53
|
if (!/\d{4}/.test(dateStr)) return dateStr;
|
|
52
54
|
const ts = parseDateToTimestamp(dateStr);
|
|
53
55
|
if (!ts) return dateStr;
|
|
54
|
-
return (0, import_date_fns.format)(new Date(ts), "
|
|
56
|
+
return (0, import_date_fns.format)(new Date(ts), "MMM yyyy", { locale: import_locale.es });
|
|
57
|
+
}
|
|
58
|
+
function formatDateRange(opts) {
|
|
59
|
+
const startText = opts.hideStart ? "" : formatDisplayDate(opts.start);
|
|
60
|
+
const endText = opts.hideEnd ? "" : formatDisplayDate(opts.end);
|
|
61
|
+
if (startText && endText) return `${startText} - ${endText}`;
|
|
62
|
+
return startText || endText || "";
|
|
55
63
|
}
|
|
56
64
|
function sortByDateDesc(items) {
|
|
57
65
|
return [...items].sort((a, b) => {
|
|
@@ -102,10 +110,12 @@ function ExperienceEducation({
|
|
|
102
110
|
!hideFields.includes("experience.title") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { className: "text-lg font-bold text-foreground", children: exp.title }),
|
|
103
111
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
|
|
104
112
|
!hideFields.includes("experience.institution_name") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-base font-semibold text-primary", children: exp.institution_name }),
|
|
105
|
-
(!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:
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
113
|
+
(!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: formatDateRange({
|
|
114
|
+
start: exp.start_date,
|
|
115
|
+
end: exp.end_date,
|
|
116
|
+
hideStart: hideFields.includes("experience.start_date"),
|
|
117
|
+
hideEnd: hideFields.includes("experience.end_date")
|
|
118
|
+
}) })
|
|
109
119
|
] }),
|
|
110
120
|
exp.description && !hideFields.includes("experience.description") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80", children: exp.description })
|
|
111
121
|
]
|
|
@@ -133,10 +143,12 @@ function ExperienceEducation({
|
|
|
133
143
|
!hideFields.includes("education.title") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { className: "text-lg font-bold text-foreground", children: edu.title }),
|
|
134
144
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
|
|
135
145
|
!hideFields.includes("education.institution_name") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-base font-semibold text-primary", children: edu.institution_name }),
|
|
136
|
-
(!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:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
146
|
+
(!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: formatDateRange({
|
|
147
|
+
start: edu.start_date,
|
|
148
|
+
end: edu.end_date,
|
|
149
|
+
hideStart: hideFields.includes("education.start_date"),
|
|
150
|
+
hideEnd: hideFields.includes("education.end_date")
|
|
151
|
+
}) })
|
|
140
152
|
] }),
|
|
141
153
|
edu.description && !hideFields.includes("education.description") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80", children: edu.description })
|
|
142
154
|
]
|
|
@@ -164,10 +176,12 @@ function ExperienceEducation({
|
|
|
164
176
|
!hideFields.includes("activities.title") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h4", { className: "text-lg font-bold text-foreground", children: act.title }),
|
|
165
177
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
|
|
166
178
|
!hideFields.includes("activities.institution_name") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "text-base font-semibold text-primary", children: act.institution_name }),
|
|
167
|
-
(!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:
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
179
|
+
(!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: formatDateRange({
|
|
180
|
+
start: act.start_date,
|
|
181
|
+
end: act.end_date,
|
|
182
|
+
hideStart: hideFields.includes("activities.start_date"),
|
|
183
|
+
hideEnd: hideFields.includes("activities.end_date")
|
|
184
|
+
}) })
|
|
171
185
|
] }),
|
|
172
186
|
act.description && !hideFields.includes("activities.description") && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80", children: act.description })
|
|
173
187
|
]
|
|
@@ -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\";\nimport { format } from \"date-fns\";\nimport { es } from \"date-fns/locale\";\n\n/** Parsea una fecha a timestamp. Soporta ISO (YYYY-MM-DD), MM/YYYY, YYYY-MM, YYYY. */\nfunction parseDateToTimestamp(dateStr: string | undefined): number {\n if (!dateStr) return 0;\n const isoMatch = dateStr.match(/^(\\d{4})-(\\d{1,2})(?:-(\\d{1,2}))?/);\n if (isoMatch) {\n const [, y, m, d] = isoMatch;\n const date = new Date(`${y}-${m.padStart(2, \"0\")}-${(d || \"01\").padStart(2, \"0\")}T00:00:00.000Z`);\n return date.getTime();\n }\n const mmYyyy = dateStr.match(/^(\\d{1,2})\\/(\\d{4})$/);\n if (mmYyyy) {\n const [, m, y] = mmYyyy;\n const date = new Date(`${y}-${m.padStart(2, \"0\")}-01T00:00:00.000Z`);\n return date.getTime();\n }\n const year = dateStr.match(/\\d{4}/);\n if (year) {\n const date = new Date(`${year[0]}-01-01T00:00:00.000Z`);\n return date.getTime();\n }\n return 0;\n}\n\n/** Formatea una fecha ISO/string a \"mes año\" en español, ej: \"agosto 2020\". */\nfunction formatDisplayDate(dateStr: string | undefined): string {\n if (!dateStr) return \"\";\n // Si es un valor semántico como \"Presente\", lo retorna tal cual\n if (!/\\d{4}/.test(dateStr)) return dateStr;\n const ts = parseDateToTimestamp(dateStr);\n if (!ts) return dateStr;\n return format(new Date(ts), \"MMMM yyyy\", { locale: es });\n}\n\n/** Ordena descendente por fecha (más reciente primero). Usa end_date o start_date si no hay end. */\nfunction sortByDateDesc<T extends CVExperienceBaseItem>(items: T[]): T[] {\n return [...items].sort((a, b) => {\n const dateA = a.end_date || a.start_date;\n const dateB = b.end_date || b.start_date;\n if (!dateA && !dateB) return 0;\n if (!dateA) return 1;\n if (!dateB) return -1;\n return parseDateToTimestamp(dateB) - parseDateToTimestamp(dateA);\n });\n}\n\n/** Ordena certificaciones descendente por date_awarded */\nfunction sortCertificationsByDateDesc(items: CVCertificationItem[]): CVCertificationItem[] {\n return [...items].sort((a, b) => {\n const tsA = parseDateToTimestamp(a.date_awarded);\n const tsB = parseDateToTimestamp(b.date_awarded);\n return tsB - tsA;\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\") && formatDisplayDate(exp.start_date),\n !hideFields.includes(\"experience.end_date\") &&\n exp.end_date &&\n exp.end_date.toLowerCase() !== \"presente\"\n ? `- ${formatDisplayDate(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\") && formatDisplayDate(edu.start_date),\n !hideFields.includes(\"education.end_date\") &&\n edu.end_date &&\n edu.end_date.toLowerCase() !== \"presente\"\n ? `- ${formatDisplayDate(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\") && formatDisplayDate(act.start_date),\n !hideFields.includes(\"activities.end_date\") &&\n act.end_date &&\n act.end_date.toLowerCase() !== \"presente\"\n ? `- ${formatDisplayDate(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":[]}
|
|
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\";\nimport { format } from \"date-fns\";\nimport { es } from \"date-fns/locale\";\n\n/** Parsea una fecha a timestamp. Soporta ISO (YYYY-MM-DD), MM/YYYY, YYYY-MM, YYYY. */\nfunction parseDateToTimestamp(dateStr: string | undefined): number {\n if (!dateStr) return 0;\n const isoMatch = dateStr.match(/^(\\d{4})-(\\d{1,2})(?:-(\\d{1,2}))?/);\n if (isoMatch) {\n const [, y, m, d] = isoMatch;\n // Importante: interpretar como fecha \"local\" para evitar corrimientos por zona horaria\n // (p.ej. 2024-08-01 en UTC puede formatearse como julio en zonas negativas).\n const year = Number(y);\n const monthIndex = Number(m) - 1; // JS Date usa meses 0-based\n const day = Number(d || \"1\");\n return new Date(year, monthIndex, day).getTime();\n }\n const mmYyyy = dateStr.match(/^(\\d{1,2})\\/(\\d{4})$/);\n if (mmYyyy) {\n const [, m, y] = mmYyyy;\n const year = Number(y);\n const monthIndex = Number(m) - 1;\n return new Date(year, monthIndex, 1).getTime();\n }\n const year = dateStr.match(/\\d{4}/);\n if (year) {\n return new Date(Number(year[0]), 0, 1).getTime();\n }\n return 0;\n}\n\n/** Formatea una fecha ISO/string a \"mes año\" en español, ej: \"agosto 2020\". */\nfunction formatDisplayDate(dateStr: string | undefined): string {\n if (!dateStr) return \"\";\n // Si es un valor semántico como \"Presente\", lo retorna tal cual\n if (!/\\d{4}/.test(dateStr)) return dateStr;\n const ts = parseDateToTimestamp(dateStr);\n if (!ts) return dateStr;\n return format(new Date(ts), \"MMM yyyy\", { locale: es });\n}\n\nfunction formatDateRange(opts: {\n start?: string;\n end?: string;\n hideStart?: boolean;\n hideEnd?: boolean;\n}): string {\n const startText = opts.hideStart ? \"\" : formatDisplayDate(opts.start);\n const endText = opts.hideEnd ? \"\" : formatDisplayDate(opts.end);\n\n if (startText && endText) return `${startText} - ${endText}`;\n return startText || endText || \"\";\n}\n\n/** Ordena descendente por fecha (más reciente primero). Usa end_date o start_date si no hay end. */\nfunction sortByDateDesc<T extends CVExperienceBaseItem>(items: T[]): T[] {\n return [...items].sort((a, b) => {\n const dateA = a.end_date || a.start_date;\n const dateB = b.end_date || b.start_date;\n if (!dateA && !dateB) return 0;\n if (!dateA) return 1;\n if (!dateB) return -1;\n return parseDateToTimestamp(dateB) - parseDateToTimestamp(dateA);\n });\n}\n\n/** Ordena certificaciones descendente por date_awarded */\nfunction sortCertificationsByDateDesc(items: CVCertificationItem[]): CVCertificationItem[] {\n return [...items].sort((a, b) => {\n const tsA = parseDateToTimestamp(a.date_awarded);\n const tsB = parseDateToTimestamp(b.date_awarded);\n return tsB - tsA;\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 {formatDateRange({\n start: exp.start_date,\n end: exp.end_date,\n hideStart: hideFields.includes(\"experience.start_date\"),\n hideEnd: hideFields.includes(\"experience.end_date\"),\n })}\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 {formatDateRange({\n start: edu.start_date,\n end: edu.end_date,\n hideStart: hideFields.includes(\"education.start_date\"),\n hideEnd: hideFields.includes(\"education.end_date\"),\n })}\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 {formatDateRange({\n start: act.start_date,\n end: act.end_date,\n hideStart: hideFields.includes(\"activities.start_date\"),\n hideEnd: hideFields.includes(\"activities.end_date\"),\n })}\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":["year"]}
|
|
@@ -7,19 +7,21 @@ function parseDateToTimestamp(dateStr) {
|
|
|
7
7
|
const isoMatch = dateStr.match(/^(\d{4})-(\d{1,2})(?:-(\d{1,2}))?/);
|
|
8
8
|
if (isoMatch) {
|
|
9
9
|
const [, y, m, d] = isoMatch;
|
|
10
|
-
const
|
|
11
|
-
|
|
10
|
+
const year2 = Number(y);
|
|
11
|
+
const monthIndex = Number(m) - 1;
|
|
12
|
+
const day = Number(d || "1");
|
|
13
|
+
return new Date(year2, monthIndex, day).getTime();
|
|
12
14
|
}
|
|
13
15
|
const mmYyyy = dateStr.match(/^(\d{1,2})\/(\d{4})$/);
|
|
14
16
|
if (mmYyyy) {
|
|
15
17
|
const [, m, y] = mmYyyy;
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
+
const year2 = Number(y);
|
|
19
|
+
const monthIndex = Number(m) - 1;
|
|
20
|
+
return new Date(year2, monthIndex, 1).getTime();
|
|
18
21
|
}
|
|
19
22
|
const year = dateStr.match(/\d{4}/);
|
|
20
23
|
if (year) {
|
|
21
|
-
|
|
22
|
-
return date.getTime();
|
|
24
|
+
return new Date(Number(year[0]), 0, 1).getTime();
|
|
23
25
|
}
|
|
24
26
|
return 0;
|
|
25
27
|
}
|
|
@@ -28,7 +30,13 @@ function formatDisplayDate(dateStr) {
|
|
|
28
30
|
if (!/\d{4}/.test(dateStr)) return dateStr;
|
|
29
31
|
const ts = parseDateToTimestamp(dateStr);
|
|
30
32
|
if (!ts) return dateStr;
|
|
31
|
-
return format(new Date(ts), "
|
|
33
|
+
return format(new Date(ts), "MMM yyyy", { locale: es });
|
|
34
|
+
}
|
|
35
|
+
function formatDateRange(opts) {
|
|
36
|
+
const startText = opts.hideStart ? "" : formatDisplayDate(opts.start);
|
|
37
|
+
const endText = opts.hideEnd ? "" : formatDisplayDate(opts.end);
|
|
38
|
+
if (startText && endText) return `${startText} - ${endText}`;
|
|
39
|
+
return startText || endText || "";
|
|
32
40
|
}
|
|
33
41
|
function sortByDateDesc(items) {
|
|
34
42
|
return [...items].sort((a, b) => {
|
|
@@ -79,10 +87,12 @@ function ExperienceEducation({
|
|
|
79
87
|
!hideFields.includes("experience.title") && /* @__PURE__ */ jsx("h4", { className: "text-lg font-bold text-foreground", children: exp.title }),
|
|
80
88
|
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
|
|
81
89
|
!hideFields.includes("experience.institution_name") && /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-primary", children: exp.institution_name }),
|
|
82
|
-
(!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:
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
90
|
+
(!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: formatDateRange({
|
|
91
|
+
start: exp.start_date,
|
|
92
|
+
end: exp.end_date,
|
|
93
|
+
hideStart: hideFields.includes("experience.start_date"),
|
|
94
|
+
hideEnd: hideFields.includes("experience.end_date")
|
|
95
|
+
}) })
|
|
86
96
|
] }),
|
|
87
97
|
exp.description && !hideFields.includes("experience.description") && /* @__PURE__ */ jsx("p", { className: "mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80", children: exp.description })
|
|
88
98
|
]
|
|
@@ -110,10 +120,12 @@ function ExperienceEducation({
|
|
|
110
120
|
!hideFields.includes("education.title") && /* @__PURE__ */ jsx("h4", { className: "text-lg font-bold text-foreground", children: edu.title }),
|
|
111
121
|
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
|
|
112
122
|
!hideFields.includes("education.institution_name") && /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-primary", children: edu.institution_name }),
|
|
113
|
-
(!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:
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
123
|
+
(!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: formatDateRange({
|
|
124
|
+
start: edu.start_date,
|
|
125
|
+
end: edu.end_date,
|
|
126
|
+
hideStart: hideFields.includes("education.start_date"),
|
|
127
|
+
hideEnd: hideFields.includes("education.end_date")
|
|
128
|
+
}) })
|
|
117
129
|
] }),
|
|
118
130
|
edu.description && !hideFields.includes("education.description") && /* @__PURE__ */ jsx("p", { className: "mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80", children: edu.description })
|
|
119
131
|
]
|
|
@@ -141,10 +153,12 @@ function ExperienceEducation({
|
|
|
141
153
|
!hideFields.includes("activities.title") && /* @__PURE__ */ jsx("h4", { className: "text-lg font-bold text-foreground", children: act.title }),
|
|
142
154
|
/* @__PURE__ */ jsxs("div", { className: "mb-2 flex flex-col sm:flex-row sm:items-center sm:justify-between", children: [
|
|
143
155
|
!hideFields.includes("activities.institution_name") && /* @__PURE__ */ jsx("span", { className: "text-base font-semibold text-primary", children: act.institution_name }),
|
|
144
|
-
(!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:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
156
|
+
(!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: formatDateRange({
|
|
157
|
+
start: act.start_date,
|
|
158
|
+
end: act.end_date,
|
|
159
|
+
hideStart: hideFields.includes("activities.start_date"),
|
|
160
|
+
hideEnd: hideFields.includes("activities.end_date")
|
|
161
|
+
}) })
|
|
148
162
|
] }),
|
|
149
163
|
act.description && !hideFields.includes("activities.description") && /* @__PURE__ */ jsx("p", { className: "mt-3 whitespace-pre-wrap text-base leading-relaxed text-foreground/80", children: act.description })
|
|
150
164
|
]
|
|
@@ -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\";\nimport { format } from \"date-fns\";\nimport { es } from \"date-fns/locale\";\n\n/** Parsea una fecha a timestamp. Soporta ISO (YYYY-MM-DD), MM/YYYY, YYYY-MM, YYYY. */\nfunction parseDateToTimestamp(dateStr: string | undefined): number {\n if (!dateStr) return 0;\n const isoMatch = dateStr.match(/^(\\d{4})-(\\d{1,2})(?:-(\\d{1,2}))?/);\n if (isoMatch) {\n const [, y, m, d] = isoMatch;\n const date = new Date(`${y}-${m.padStart(2, \"0\")}-${(d || \"01\").padStart(2, \"0\")}T00:00:00.000Z`);\n return date.getTime();\n }\n const mmYyyy = dateStr.match(/^(\\d{1,2})\\/(\\d{4})$/);\n if (mmYyyy) {\n const [, m, y] = mmYyyy;\n const date = new Date(`${y}-${m.padStart(2, \"0\")}-01T00:00:00.000Z`);\n return date.getTime();\n }\n const year = dateStr.match(/\\d{4}/);\n if (year) {\n const date = new Date(`${year[0]}-01-01T00:00:00.000Z`);\n return date.getTime();\n }\n return 0;\n}\n\n/** Formatea una fecha ISO/string a \"mes año\" en español, ej: \"agosto 2020\". */\nfunction formatDisplayDate(dateStr: string | undefined): string {\n if (!dateStr) return \"\";\n // Si es un valor semántico como \"Presente\", lo retorna tal cual\n if (!/\\d{4}/.test(dateStr)) return dateStr;\n const ts = parseDateToTimestamp(dateStr);\n if (!ts) return dateStr;\n return format(new Date(ts), \"MMMM yyyy\", { locale: es });\n}\n\n/** Ordena descendente por fecha (más reciente primero). Usa end_date o start_date si no hay end. */\nfunction sortByDateDesc<T extends CVExperienceBaseItem>(items: T[]): T[] {\n return [...items].sort((a, b) => {\n const dateA = a.end_date || a.start_date;\n const dateB = b.end_date || b.start_date;\n if (!dateA && !dateB) return 0;\n if (!dateA) return 1;\n if (!dateB) return -1;\n return parseDateToTimestamp(dateB) - parseDateToTimestamp(dateA);\n });\n}\n\n/** Ordena certificaciones descendente por date_awarded */\nfunction sortCertificationsByDateDesc(items: CVCertificationItem[]): CVCertificationItem[] {\n return [...items].sort((a, b) => {\n const tsA = parseDateToTimestamp(a.date_awarded);\n const tsB = parseDateToTimestamp(b.date_awarded);\n return tsB - tsA;\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\") && formatDisplayDate(exp.start_date),\n !hideFields.includes(\"experience.end_date\") &&\n exp.end_date &&\n exp.end_date.toLowerCase() !== \"presente\"\n ? `- ${formatDisplayDate(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\") && formatDisplayDate(edu.start_date),\n !hideFields.includes(\"education.end_date\") &&\n edu.end_date &&\n edu.end_date.toLowerCase() !== \"presente\"\n ? `- ${formatDisplayDate(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\") && formatDisplayDate(act.start_date),\n !hideFields.includes(\"activities.end_date\") &&\n act.end_date &&\n act.end_date.toLowerCase() !== \"presente\"\n ? `- ${formatDisplayDate(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":[]}
|
|
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\";\nimport { format } from \"date-fns\";\nimport { es } from \"date-fns/locale\";\n\n/** Parsea una fecha a timestamp. Soporta ISO (YYYY-MM-DD), MM/YYYY, YYYY-MM, YYYY. */\nfunction parseDateToTimestamp(dateStr: string | undefined): number {\n if (!dateStr) return 0;\n const isoMatch = dateStr.match(/^(\\d{4})-(\\d{1,2})(?:-(\\d{1,2}))?/);\n if (isoMatch) {\n const [, y, m, d] = isoMatch;\n // Importante: interpretar como fecha \"local\" para evitar corrimientos por zona horaria\n // (p.ej. 2024-08-01 en UTC puede formatearse como julio en zonas negativas).\n const year = Number(y);\n const monthIndex = Number(m) - 1; // JS Date usa meses 0-based\n const day = Number(d || \"1\");\n return new Date(year, monthIndex, day).getTime();\n }\n const mmYyyy = dateStr.match(/^(\\d{1,2})\\/(\\d{4})$/);\n if (mmYyyy) {\n const [, m, y] = mmYyyy;\n const year = Number(y);\n const monthIndex = Number(m) - 1;\n return new Date(year, monthIndex, 1).getTime();\n }\n const year = dateStr.match(/\\d{4}/);\n if (year) {\n return new Date(Number(year[0]), 0, 1).getTime();\n }\n return 0;\n}\n\n/** Formatea una fecha ISO/string a \"mes año\" en español, ej: \"agosto 2020\". */\nfunction formatDisplayDate(dateStr: string | undefined): string {\n if (!dateStr) return \"\";\n // Si es un valor semántico como \"Presente\", lo retorna tal cual\n if (!/\\d{4}/.test(dateStr)) return dateStr;\n const ts = parseDateToTimestamp(dateStr);\n if (!ts) return dateStr;\n return format(new Date(ts), \"MMM yyyy\", { locale: es });\n}\n\nfunction formatDateRange(opts: {\n start?: string;\n end?: string;\n hideStart?: boolean;\n hideEnd?: boolean;\n}): string {\n const startText = opts.hideStart ? \"\" : formatDisplayDate(opts.start);\n const endText = opts.hideEnd ? \"\" : formatDisplayDate(opts.end);\n\n if (startText && endText) return `${startText} - ${endText}`;\n return startText || endText || \"\";\n}\n\n/** Ordena descendente por fecha (más reciente primero). Usa end_date o start_date si no hay end. */\nfunction sortByDateDesc<T extends CVExperienceBaseItem>(items: T[]): T[] {\n return [...items].sort((a, b) => {\n const dateA = a.end_date || a.start_date;\n const dateB = b.end_date || b.start_date;\n if (!dateA && !dateB) return 0;\n if (!dateA) return 1;\n if (!dateB) return -1;\n return parseDateToTimestamp(dateB) - parseDateToTimestamp(dateA);\n });\n}\n\n/** Ordena certificaciones descendente por date_awarded */\nfunction sortCertificationsByDateDesc(items: CVCertificationItem[]): CVCertificationItem[] {\n return [...items].sort((a, b) => {\n const tsA = parseDateToTimestamp(a.date_awarded);\n const tsB = parseDateToTimestamp(b.date_awarded);\n return tsB - tsA;\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 {formatDateRange({\n start: exp.start_date,\n end: exp.end_date,\n hideStart: hideFields.includes(\"experience.start_date\"),\n hideEnd: hideFields.includes(\"experience.end_date\"),\n })}\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 {formatDateRange({\n start: edu.start_date,\n end: edu.end_date,\n hideStart: hideFields.includes(\"education.start_date\"),\n hideEnd: hideFields.includes(\"education.end_date\"),\n })}\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 {formatDateRange({\n start: act.start_date,\n end: act.end_date,\n hideStart: hideFields.includes(\"activities.start_date\"),\n hideEnd: hideFields.includes(\"activities.end_date\"),\n })}\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":"AAsGU,SACE,KADF;AApGV,SAAS,eAAe,WAAW,QAAQ,aAAa;AACxD,SAAS,cAAc;AACvB,SAAS,UAAU;AAGnB,SAAS,qBAAqB,SAAqC;AACjE,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,WAAW,QAAQ,MAAM,mCAAmC;AAClE,MAAI,UAAU;AACZ,UAAM,CAAC,EAAE,GAAG,GAAG,CAAC,IAAI;AAGpB,UAAMA,QAAO,OAAO,CAAC;AACrB,UAAM,aAAa,OAAO,CAAC,IAAI;AAC/B,UAAM,MAAM,OAAO,KAAK,GAAG;AAC3B,WAAO,IAAI,KAAKA,OAAM,YAAY,GAAG,EAAE,QAAQ;AAAA,EACjD;AACA,QAAM,SAAS,QAAQ,MAAM,sBAAsB;AACnD,MAAI,QAAQ;AACV,UAAM,CAAC,EAAE,GAAG,CAAC,IAAI;AACjB,UAAMA,QAAO,OAAO,CAAC;AACrB,UAAM,aAAa,OAAO,CAAC,IAAI;AAC/B,WAAO,IAAI,KAAKA,OAAM,YAAY,CAAC,EAAE,QAAQ;AAAA,EAC/C;AACA,QAAM,OAAO,QAAQ,MAAM,OAAO;AAClC,MAAI,MAAM;AACR,WAAO,IAAI,KAAK,OAAO,KAAK,CAAC,CAAC,GAAG,GAAG,CAAC,EAAE,QAAQ;AAAA,EACjD;AACA,SAAO;AACT;AAGA,SAAS,kBAAkB,SAAqC;AAC9D,MAAI,CAAC,QAAS,QAAO;AAErB,MAAI,CAAC,QAAQ,KAAK,OAAO,EAAG,QAAO;AACnC,QAAM,KAAK,qBAAqB,OAAO;AACvC,MAAI,CAAC,GAAI,QAAO;AAChB,SAAO,OAAO,IAAI,KAAK,EAAE,GAAG,YAAY,EAAE,QAAQ,GAAG,CAAC;AACxD;AAEA,SAAS,gBAAgB,MAKd;AACT,QAAM,YAAY,KAAK,YAAY,KAAK,kBAAkB,KAAK,KAAK;AACpE,QAAM,UAAU,KAAK,UAAU,KAAK,kBAAkB,KAAK,GAAG;AAE9D,MAAI,aAAa,QAAS,QAAO,GAAG,SAAS,MAAM,OAAO;AAC1D,SAAO,aAAa,WAAW;AACjC;AAGA,SAAS,eAA+C,OAAiB;AACvE,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM;AAC/B,UAAM,QAAQ,EAAE,YAAY,EAAE;AAC9B,UAAM,QAAQ,EAAE,YAAY,EAAE;AAC9B,QAAI,CAAC,SAAS,CAAC,MAAO,QAAO;AAC7B,QAAI,CAAC,MAAO,QAAO;AACnB,QAAI,CAAC,MAAO,QAAO;AACnB,WAAO,qBAAqB,KAAK,IAAI,qBAAqB,KAAK;AAAA,EACjE,CAAC;AACH;AAGA,SAAS,6BAA6B,OAAqD;AACzF,SAAO,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,GAAG,MAAM;AAC/B,UAAM,MAAM,qBAAqB,EAAE,YAAY;AAC/C,UAAM,MAAM,qBAAqB,EAAE,YAAY;AAC/C,WAAO,MAAM;AAAA,EACf,CAAC;AACH;AASO,SAAS,oBAAoB;AAAA,EAClC;AAAA,EACA;AAAA,EACA,aAAa,CAAC;AAAA,EACd,eAAe,CAAC;AAClB,GAA6B;AAC3B,QAAM,cAAc,eAAe,KAAK,mBAAmB,CAAC,CAAC;AAC7D,QAAM,YAAY,eAAe,KAAK,aAAa,CAAC,CAAC;AACrD,QAAM,aAAa,eAAe,KAAK,cAAc,CAAC,CAAC;AACvD,QAAM,iBAAiB,6BAA6B,KAAK,kBAAkB,CAAC,CAAC;AAE7E,QAAM,aAAa,QAAQ,EAAE,iBAAiB,MAAM,IAAI;AAExD,SACE,qBAAC,SAAI,WAAU,cAEZ;AAAA,gBAAY,SAAS,KAAK,CAAC,aAAa,SAAS,qBAAqB,KACrE,qBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,QAAG,WAAU,6FACZ;AAAA,4BAAC,aAAU,WAAU,wBAAuB;AAAA,QAAE;AAAA,SAEhD;AAAA,MACA,oBAAC,SAAI,WAAU,aACZ,sBAAY,IAAI,CAAC,QAChB;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAEV;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO;AAAA;AAAA,YACT;AAAA,YACC,CAAC,WAAW,SAAS,kBAAkB,KACtC,oBAAC,QAAG,WAAU,qCAAqC,cAAI,OAAM;AAAA,YAE/D,qBAAC,SAAI,WAAU,qEACZ;AAAA,eAAC,WAAW,SAAS,6BAA6B,KACjD,oBAAC,UAAK,WAAU,wCACb,cAAI,kBACP;AAAA,eAEA,CAAC,WAAW,SAAS,uBAAuB,KAC5C,CAAC,WAAW,SAAS,qBAAqB,MACxC,oBAAC,UAAK,WAAU,6GACb,0BAAgB;AAAA,gBACf,OAAO,IAAI;AAAA,gBACX,KAAK,IAAI;AAAA,gBACT,WAAW,WAAW,SAAS,uBAAuB;AAAA,gBACtD,SAAS,WAAW,SAAS,qBAAqB;AAAA,cACpD,CAAC,GACH;AAAA,eAEN;AAAA,YACC,IAAI,eAAe,CAAC,WAAW,SAAS,wBAAwB,KAC/D,oBAAC,OAAE,WAAU,yEACV,cAAI,aACP;AAAA;AAAA;AAAA,QA/BG,IAAI;AAAA,MAiCX,CACD,GACH;AAAA,OACF;AAAA,IAID,UAAU,SAAS,KAAK,CAAC,aAAa,SAAS,cAAW,KACzD,qBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,QAAG,WAAU,6FACZ;AAAA,4BAAC,iBAAc,WAAU,wBAAuB;AAAA,QAAE;AAAA,SAEpD;AAAA,MACA,oBAAC,SAAI,WAAU,aACZ,oBAAU,IAAI,CAAC,QACd;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAEV;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO;AAAA;AAAA,YACT;AAAA,YACC,CAAC,WAAW,SAAS,iBAAiB,KACrC,oBAAC,QAAG,WAAU,qCAAqC,cAAI,OAAM;AAAA,YAE/D,qBAAC,SAAI,WAAU,qEACZ;AAAA,eAAC,WAAW,SAAS,4BAA4B,KAChD,oBAAC,UAAK,WAAU,wCACb,cAAI,kBACP;AAAA,eAEA,CAAC,WAAW,SAAS,sBAAsB,KAC3C,CAAC,WAAW,SAAS,oBAAoB,MACvC,oBAAC,UAAK,WAAU,6GACb,0BAAgB;AAAA,gBACf,OAAO,IAAI;AAAA,gBACX,KAAK,IAAI;AAAA,gBACT,WAAW,WAAW,SAAS,sBAAsB;AAAA,gBACrD,SAAS,WAAW,SAAS,oBAAoB;AAAA,cACnD,CAAC,GACH;AAAA,eAEN;AAAA,YACC,IAAI,eAAe,CAAC,WAAW,SAAS,uBAAuB,KAC9D,oBAAC,OAAE,WAAU,yEACV,cAAI,aACP;AAAA;AAAA;AAAA,QA/BG,IAAI;AAAA,MAiCX,CACD,GACH;AAAA,OACF;AAAA,IAID,WAAW,SAAS,KAAK,CAAC,aAAa,SAAS,sBAAsB,KACrE,qBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,QAAG,WAAU,6FACZ;AAAA,4BAAC,UAAO,WAAU,wBAAuB;AAAA,QAAE;AAAA,SAE7C;AAAA,MACA,oBAAC,SAAI,WAAU,aACZ,qBAAW,IAAI,CAAC,QACf;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAEV;AAAA;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO;AAAA;AAAA,YACT;AAAA,YACC,CAAC,WAAW,SAAS,kBAAkB,KACtC,oBAAC,QAAG,WAAU,qCAAqC,cAAI,OAAM;AAAA,YAE/D,qBAAC,SAAI,WAAU,qEACZ;AAAA,eAAC,WAAW,SAAS,6BAA6B,KACjD,oBAAC,UAAK,WAAU,wCACb,cAAI,kBACP;AAAA,eAEA,CAAC,WAAW,SAAS,uBAAuB,KAC5C,CAAC,WAAW,SAAS,qBAAqB,MACxC,oBAAC,UAAK,WAAU,6GACb,0BAAgB;AAAA,gBACf,OAAO,IAAI;AAAA,gBACX,KAAK,IAAI;AAAA,gBACT,WAAW,WAAW,SAAS,uBAAuB;AAAA,gBACtD,SAAS,WAAW,SAAS,qBAAqB;AAAA,cACpD,CAAC,GACH;AAAA,eAEN;AAAA,YACC,IAAI,eAAe,CAAC,WAAW,SAAS,wBAAwB,KAC/D,oBAAC,OAAE,WAAU,yEACV,cAAI,aACP;AAAA;AAAA;AAAA,QA/BG,IAAI;AAAA,MAiCX,CACD,GACH;AAAA,OACF;AAAA,IAID,eAAe,SAAS,KAAK,CAAC,aAAa,SAAS,iBAAiB,KACpE,qBAAC,SAAI,WAAU,aACb;AAAA,2BAAC,QAAG,WAAU,6FACZ;AAAA,4BAAC,SAAM,WAAU,wBAAuB;AAAA,QAAE;AAAA,SAE5C;AAAA,MACA,oBAAC,SAAI,WAAU,0BACZ,yBAAe,IAAI,CAAC,SACnB;AAAA,QAAC;AAAA;AAAA,UAEC,WAAU;AAAA,UAET;AAAA,aAAC,WAAW,SAAS,sBAAsB,KAC1C,oBAAC,QAAG,WAAU,mDACX,eAAK,OACR;AAAA,YAED,CAAC,WAAW,SAAS,iCAAiC,KACrD,oBAAC,OAAE,WAAU,mDACV,eAAK,kBACR;AAAA,YAEF,qBAAC,SAAI,WAAU,0CACZ;AAAA,eAAC,WAAW,SAAS,6BAA6B,KACjD,oBAAC,UAAK,WAAU,mHACb,eAAK,cACR;AAAA,cAED,KAAK,YAAY,CAAC,WAAW,SAAS,yBAAyB,KAC9D;AAAA,gBAAC;AAAA;AAAA,kBACC,WAAU;AAAA,kBACV,OAAO;AAAA,oBACL,iBAAiB,OAAO,WAAW,GAAG,IAAI,GAAG,KAAK,OAAO;AAAA,oBACzD,OAAO;AAAA,oBACP,aAAa,OAAO,WAAW,GAAG,IAAI,GAAG,KAAK,OAAO;AAAA,kBACvD;AAAA,kBACD;AAAA;AAAA,cAED;AAAA,eAEJ;AAAA;AAAA;AAAA,QA/BK,KAAK;AAAA,MAgCZ,CACD,GACH;AAAA,OACF;AAAA,KAEJ;AAEJ;","names":["year"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ginia/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.18",
|
|
4
4
|
"description": "Ginia Design System — Unified UI component library for all Ginia hubs",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -34,18 +34,6 @@
|
|
|
34
34
|
"require": "./dist/icons.cjs"
|
|
35
35
|
}
|
|
36
36
|
},
|
|
37
|
-
"scripts": {
|
|
38
|
-
"build": "NODE_OPTIONS=--max-old-space-size=8192 tsup",
|
|
39
|
-
"dev": "tsup --watch",
|
|
40
|
-
"clean": "rm -rf dist",
|
|
41
|
-
"typecheck": "tsc --noEmit",
|
|
42
|
-
"lint": "eslint src/",
|
|
43
|
-
"lint:fix": "eslint src/ --fix",
|
|
44
|
-
"format": "prettier --write 'src/**/*.{ts,tsx,css,json}'",
|
|
45
|
-
"format:check": "prettier --check 'src/**/*.{ts,tsx,css,json}'",
|
|
46
|
-
"storybook": "storybook dev -p 6006",
|
|
47
|
-
"build-storybook": "storybook build"
|
|
48
|
-
},
|
|
49
37
|
"peerDependencies": {
|
|
50
38
|
"react": ">=18",
|
|
51
39
|
"react-dom": ">=18",
|
|
@@ -137,5 +125,17 @@
|
|
|
137
125
|
"typescript-eslint": "^8.56.1",
|
|
138
126
|
"vite": "^5.4.0",
|
|
139
127
|
"zod": "^4.3.6"
|
|
128
|
+
},
|
|
129
|
+
"scripts": {
|
|
130
|
+
"build": "NODE_OPTIONS=--max-old-space-size=8192 tsup",
|
|
131
|
+
"dev": "tsup --watch",
|
|
132
|
+
"clean": "rm -rf dist",
|
|
133
|
+
"typecheck": "tsc --noEmit",
|
|
134
|
+
"lint": "eslint src/",
|
|
135
|
+
"lint:fix": "eslint src/ --fix",
|
|
136
|
+
"format": "prettier --write 'src/**/*.{ts,tsx,css,json}'",
|
|
137
|
+
"format:check": "prettier --check 'src/**/*.{ts,tsx,css,json}'",
|
|
138
|
+
"storybook": "storybook dev -p 6006",
|
|
139
|
+
"build-storybook": "storybook build"
|
|
140
140
|
}
|
|
141
|
-
}
|
|
141
|
+
}
|