@ginia/ui 0.1.16 → 0.1.17

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.
@@ -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 date = /* @__PURE__ */ new Date(`${y}-${m.padStart(2, "0")}-${(d || "01").padStart(2, "0")}T00:00:00.000Z`);
34
- return date.getTime();
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 date = /* @__PURE__ */ new Date(`${y}-${m.padStart(2, "0")}-01T00:00:00.000Z`);
40
- return date.getTime();
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
- const date = /* @__PURE__ */ new Date(`${year[0]}-01-01T00:00:00.000Z`);
45
- return date.getTime();
47
+ return new Date(Number(year[0]), 0, 1).getTime();
46
48
  }
47
49
  return 0;
48
50
  }
@@ -53,6 +55,12 @@ function formatDisplayDate(dateStr) {
53
55
  if (!ts) return dateStr;
54
56
  return (0, import_date_fns.format)(new Date(ts), "MMMM yyyy", { locale: import_locale.es });
55
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 || "";
63
+ }
56
64
  function sortByDateDesc(items) {
57
65
  return [...items].sort((a, b) => {
58
66
  const dateA = a.end_date || a.start_date;
@@ -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
- !hideFields.includes("experience.start_date") && formatDisplayDate(exp.start_date),
107
- !hideFields.includes("experience.end_date") && exp.end_date && exp.end_date.toLowerCase() !== "presente" ? `- ${formatDisplayDate(exp.end_date)}` : null
108
- ].filter(Boolean).join(" ") })
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
- !hideFields.includes("education.start_date") && formatDisplayDate(edu.start_date),
138
- !hideFields.includes("education.end_date") && edu.end_date && edu.end_date.toLowerCase() !== "presente" ? `- ${formatDisplayDate(edu.end_date)}` : null
139
- ].filter(Boolean).join(" ") })
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
- !hideFields.includes("activities.start_date") && formatDisplayDate(act.start_date),
169
- !hideFields.includes("activities.end_date") && act.end_date && act.end_date.toLowerCase() !== "presente" ? `- ${formatDisplayDate(act.end_date)}` : null
170
- ].filter(Boolean).join(" ") })
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), \"MMMM 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 date = /* @__PURE__ */ new Date(`${y}-${m.padStart(2, "0")}-${(d || "01").padStart(2, "0")}T00:00:00.000Z`);
11
- return date.getTime();
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 date = /* @__PURE__ */ new Date(`${y}-${m.padStart(2, "0")}-01T00:00:00.000Z`);
17
- return date.getTime();
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
- const date = /* @__PURE__ */ new Date(`${year[0]}-01-01T00:00:00.000Z`);
22
- return date.getTime();
24
+ return new Date(Number(year[0]), 0, 1).getTime();
23
25
  }
24
26
  return 0;
25
27
  }
@@ -30,6 +32,12 @@ function formatDisplayDate(dateStr) {
30
32
  if (!ts) return dateStr;
31
33
  return format(new Date(ts), "MMMM yyyy", { locale: es });
32
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 || "";
40
+ }
33
41
  function sortByDateDesc(items) {
34
42
  return [...items].sort((a, b) => {
35
43
  const dateA = a.end_date || a.start_date;
@@ -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
- !hideFields.includes("experience.start_date") && formatDisplayDate(exp.start_date),
84
- !hideFields.includes("experience.end_date") && exp.end_date && exp.end_date.toLowerCase() !== "presente" ? `- ${formatDisplayDate(exp.end_date)}` : null
85
- ].filter(Boolean).join(" ") })
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
- !hideFields.includes("education.start_date") && formatDisplayDate(edu.start_date),
115
- !hideFields.includes("education.end_date") && edu.end_date && edu.end_date.toLowerCase() !== "presente" ? `- ${formatDisplayDate(edu.end_date)}` : null
116
- ].filter(Boolean).join(" ") })
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
- !hideFields.includes("activities.start_date") && formatDisplayDate(act.start_date),
146
- !hideFields.includes("activities.end_date") && act.end_date && act.end_date.toLowerCase() !== "presente" ? `- ${formatDisplayDate(act.end_date)}` : null
147
- ].filter(Boolean).join(" ") })
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), \"MMMM 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,aAAa,EAAE,QAAQ,GAAG,CAAC;AACzD;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.16",
3
+ "version": "0.1.17",
4
4
  "description": "Ginia Design System — Unified UI component library for all Ginia hubs",
5
5
  "license": "MIT",
6
6
  "private": false,