@takuhon/ui 0.1.1 → 0.2.0

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.
@@ -0,0 +1,70 @@
1
+ .section {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--takuhon-space-3);
5
+ margin-top: var(--takuhon-space-5);
6
+ }
7
+
8
+ .heading {
9
+ margin: 0;
10
+ font-size: var(--takuhon-font-size-xl);
11
+ color: var(--takuhon-color-text);
12
+ }
13
+
14
+ .list {
15
+ list-style: none;
16
+ margin: 0;
17
+ padding: 0;
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: var(--takuhon-space-3);
21
+ }
22
+
23
+ .item {
24
+ display: flex;
25
+ flex-direction: column;
26
+ gap: var(--takuhon-space-1);
27
+ padding: var(--takuhon-space-3);
28
+ background-color: var(--takuhon-color-surface);
29
+ border: 1px solid var(--takuhon-color-border);
30
+ border-radius: var(--takuhon-radius-md);
31
+ }
32
+
33
+ .title {
34
+ margin: 0;
35
+ font-weight: 600;
36
+ color: var(--takuhon-color-text);
37
+ font-size: var(--takuhon-font-size-base);
38
+ }
39
+
40
+ .link {
41
+ color: inherit;
42
+ text-decoration: none;
43
+ }
44
+
45
+ .link:hover,
46
+ .link:focus-visible {
47
+ text-decoration: underline;
48
+ color: var(--takuhon-color-primary);
49
+ }
50
+
51
+ .link:focus-visible {
52
+ outline: 2px solid var(--takuhon-color-primary);
53
+ outline-offset: 2px;
54
+ }
55
+
56
+ .issuer {
57
+ margin: 0;
58
+ font-size: var(--takuhon-font-size-sm);
59
+ color: var(--takuhon-color-text-muted);
60
+ }
61
+
62
+ .range {
63
+ margin: 0;
64
+ font-size: var(--takuhon-font-size-sm);
65
+ color: var(--takuhon-color-text-muted);
66
+ }
67
+
68
+ .tag {
69
+ font-style: italic;
70
+ }
@@ -0,0 +1,93 @@
1
+ .section {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--takuhon-space-3);
5
+ margin-top: var(--takuhon-space-5);
6
+ }
7
+
8
+ .heading {
9
+ margin: 0;
10
+ font-size: var(--takuhon-font-size-xl);
11
+ color: var(--takuhon-color-text);
12
+ }
13
+
14
+ .list {
15
+ list-style: none;
16
+ margin: 0;
17
+ padding-inline-start: var(--takuhon-space-4);
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: var(--takuhon-space-4);
21
+ border-inline-start: 2px solid var(--takuhon-color-border);
22
+ }
23
+
24
+ .item {
25
+ display: grid;
26
+ grid-template-columns: auto 1fr;
27
+ gap: var(--takuhon-space-3);
28
+ position: relative;
29
+ }
30
+
31
+ .timelineMarker {
32
+ width: 12px;
33
+ height: 12px;
34
+ border-radius: var(--takuhon-radius-full);
35
+ background-color: var(--takuhon-color-primary);
36
+ margin-inline-start: calc(-1 * var(--takuhon-space-4) - 6px);
37
+ margin-block-start: var(--takuhon-space-2);
38
+ flex-shrink: 0;
39
+ }
40
+
41
+ .content {
42
+ display: flex;
43
+ flex-direction: column;
44
+ gap: var(--takuhon-space-1);
45
+ }
46
+
47
+ .institution {
48
+ margin: 0;
49
+ font-weight: 600;
50
+ color: var(--takuhon-color-text);
51
+ font-size: var(--takuhon-font-size-base);
52
+ }
53
+
54
+ .link {
55
+ color: inherit;
56
+ text-decoration: none;
57
+ }
58
+
59
+ .link:hover,
60
+ .link:focus-visible {
61
+ text-decoration: underline;
62
+ color: var(--takuhon-color-primary);
63
+ }
64
+
65
+ .link:focus-visible {
66
+ outline: 2px solid var(--takuhon-color-primary);
67
+ outline-offset: 2px;
68
+ }
69
+
70
+ .study {
71
+ margin: 0;
72
+ font-size: var(--takuhon-font-size-sm);
73
+ color: var(--takuhon-color-text);
74
+ }
75
+
76
+ .range {
77
+ margin: 0;
78
+ font-size: var(--takuhon-font-size-sm);
79
+ color: var(--takuhon-color-text-muted);
80
+ }
81
+
82
+ .grade {
83
+ margin: 0;
84
+ font-size: var(--takuhon-font-size-sm);
85
+ color: var(--takuhon-color-text-muted);
86
+ }
87
+
88
+ .description {
89
+ margin: 0;
90
+ font-size: var(--takuhon-font-size-base);
91
+ line-height: var(--takuhon-line-height);
92
+ color: var(--takuhon-color-text);
93
+ }
@@ -0,0 +1,63 @@
1
+ .section {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--takuhon-space-3);
5
+ margin-top: var(--takuhon-space-5);
6
+ }
7
+
8
+ .heading {
9
+ margin: 0;
10
+ font-size: var(--takuhon-font-size-xl);
11
+ color: var(--takuhon-color-text);
12
+ }
13
+
14
+ .list {
15
+ list-style: none;
16
+ margin: 0;
17
+ padding: 0;
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: var(--takuhon-space-3);
21
+ }
22
+
23
+ .item {
24
+ display: flex;
25
+ flex-direction: column;
26
+ gap: var(--takuhon-space-1);
27
+ }
28
+
29
+ .title {
30
+ margin: 0;
31
+ font-weight: 600;
32
+ color: var(--takuhon-color-text);
33
+ font-size: var(--takuhon-font-size-base);
34
+ }
35
+
36
+ .link {
37
+ color: inherit;
38
+ text-decoration: none;
39
+ }
40
+
41
+ .link:hover,
42
+ .link:focus-visible {
43
+ text-decoration: underline;
44
+ color: var(--takuhon-color-primary);
45
+ }
46
+
47
+ .link:focus-visible {
48
+ outline: 2px solid var(--takuhon-color-primary);
49
+ outline-offset: 2px;
50
+ }
51
+
52
+ .meta {
53
+ margin: 0;
54
+ font-size: var(--takuhon-font-size-sm);
55
+ color: var(--takuhon-color-text-muted);
56
+ }
57
+
58
+ .description {
59
+ margin: 0;
60
+ font-size: var(--takuhon-font-size-base);
61
+ line-height: var(--takuhon-line-height);
62
+ color: var(--takuhon-color-text);
63
+ }
@@ -0,0 +1,45 @@
1
+ .section {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: var(--takuhon-space-3);
5
+ margin-top: var(--takuhon-space-5);
6
+ }
7
+
8
+ .heading {
9
+ margin: 0;
10
+ font-size: var(--takuhon-font-size-xl);
11
+ color: var(--takuhon-color-text);
12
+ }
13
+
14
+ .list {
15
+ list-style: none;
16
+ margin: 0;
17
+ padding: 0;
18
+ display: flex;
19
+ flex-direction: column;
20
+ gap: var(--takuhon-space-2);
21
+ }
22
+
23
+ .item {
24
+ display: flex;
25
+ align-items: baseline;
26
+ gap: var(--takuhon-space-3);
27
+ padding-block: var(--takuhon-space-2);
28
+ border-bottom: 1px solid var(--takuhon-color-border);
29
+ }
30
+
31
+ .item:last-child {
32
+ border-bottom: none;
33
+ }
34
+
35
+ .name {
36
+ font-weight: 600;
37
+ color: var(--takuhon-color-text);
38
+ font-size: var(--takuhon-font-size-base);
39
+ }
40
+
41
+ .proficiency {
42
+ font-size: var(--takuhon-font-size-sm);
43
+ color: var(--takuhon-color-text-muted);
44
+ margin-inline-start: auto;
45
+ }
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { LocalizedTakuhon, LocalizedProfile, LocalizedLink, LocalizedCareer, LocalizedProject, Skill, Contact, LocaleTag } from '@takuhon/core';
1
+ import { LocalizedTakuhon, LocalizedProfile, LocalizedLink, LocalizedCareer, LocalizedEducation, LocalizedCertification, LocalizedHonor, LocalizedLanguage, LocalizedProject, Skill, Contact, LocaleTag } from '@takuhon/core';
2
2
 
3
3
  interface TakuhonProfileProps {
4
4
  data: LocalizedTakuhon;
@@ -20,6 +20,26 @@ interface CareerTimelineProps {
20
20
  }
21
21
  declare function CareerTimeline({ careers }: CareerTimelineProps): React.JSX.Element | null;
22
22
 
23
+ interface EducationTimelineProps {
24
+ education: LocalizedEducation[];
25
+ }
26
+ declare function EducationTimeline({ education }: EducationTimelineProps): React.JSX.Element | null;
27
+
28
+ interface CertificationsProps {
29
+ certifications: LocalizedCertification[];
30
+ }
31
+ declare function Certifications({ certifications }: CertificationsProps): React.JSX.Element | null;
32
+
33
+ interface HonorsListProps {
34
+ honors: LocalizedHonor[];
35
+ }
36
+ declare function HonorsList({ honors }: HonorsListProps): React.JSX.Element | null;
37
+
38
+ interface LanguagesProps {
39
+ languages: LocalizedLanguage[];
40
+ }
41
+ declare function Languages({ languages }: LanguagesProps): React.JSX.Element | null;
42
+
23
43
  interface ProjectsListProps {
24
44
  projects: LocalizedProject[];
25
45
  }
@@ -53,4 +73,4 @@ interface TakuhonHeadProps {
53
73
  }
54
74
  declare function TakuhonHead({ data, siteUrl, pageUrl }: TakuhonHeadProps): React.JSX.Element;
55
75
 
56
- export { CareerTimeline, type CareerTimelineProps, ContactInfo, type ContactInfoProps, Footer, LinksList, type LinksListProps, LocaleSwitcher, type LocaleSwitcherProps, ProfileHeader, type ProfileHeaderProps, ProjectsList, type ProjectsListProps, SkillsList, type SkillsListProps, TakuhonHead, type TakuhonHeadProps, TakuhonProfile, type TakuhonProfileProps };
76
+ export { CareerTimeline, type CareerTimelineProps, Certifications, type CertificationsProps, ContactInfo, type ContactInfoProps, EducationTimeline, type EducationTimelineProps, Footer, HonorsList, type HonorsListProps, Languages, type LanguagesProps, LinksList, type LinksListProps, LocaleSwitcher, type LocaleSwitcherProps, ProfileHeader, type ProfileHeaderProps, ProjectsList, type ProjectsListProps, SkillsList, type SkillsListProps, TakuhonHead, type TakuhonHeadProps, TakuhonProfile, type TakuhonProfileProps };
package/dist/index.js CHANGED
@@ -53,20 +53,59 @@ function CareerTimeline({ careers }) {
53
53
  ] });
54
54
  }
55
55
 
56
+ // src/components/Certifications.tsx
57
+ import styles2 from "./Certifications.module-2NMKPWLM.module.css";
58
+ import { Fragment as Fragment2, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
59
+ function sortCerts(certs) {
60
+ return [...certs].sort((a, b) => {
61
+ const aOrder = a.order ?? Number.POSITIVE_INFINITY;
62
+ const bOrder = b.order ?? Number.POSITIVE_INFINITY;
63
+ if (aOrder !== bOrder) return aOrder - bOrder;
64
+ return b.issueDate.localeCompare(a.issueDate);
65
+ });
66
+ }
67
+ function Certifications({ certifications }) {
68
+ if (certifications.length === 0) return null;
69
+ const ordered = sortCerts(certifications);
70
+ return /* @__PURE__ */ jsxs2("section", { className: styles2.section, "aria-labelledby": "takuhon-certifications-heading", children: [
71
+ /* @__PURE__ */ jsx2("h2", { id: "takuhon-certifications-heading", className: styles2.heading, children: "Certifications" }),
72
+ /* @__PURE__ */ jsx2("ul", { className: styles2.list, children: ordered.map((cert) => /* @__PURE__ */ jsxs2("li", { className: styles2.item, children: [
73
+ /* @__PURE__ */ jsx2("p", { className: styles2.title, children: cert.url ? /* @__PURE__ */ jsx2(
74
+ "a",
75
+ {
76
+ className: styles2.link,
77
+ href: cert.url,
78
+ target: "_blank",
79
+ rel: "noopener noreferrer",
80
+ children: cert.title
81
+ }
82
+ ) : cert.title }),
83
+ /* @__PURE__ */ jsx2("p", { className: styles2.issuer, children: cert.issuingOrganization }),
84
+ /* @__PURE__ */ jsxs2("p", { className: styles2.range, children: [
85
+ /* @__PURE__ */ jsx2("time", { dateTime: cert.issueDate, children: cert.issueDate }),
86
+ cert.expirationDate === null ? /* @__PURE__ */ jsx2("span", { className: styles2.tag, children: " \xB7 No expiration" }) : cert.expirationDate !== void 0 ? /* @__PURE__ */ jsxs2(Fragment2, { children: [
87
+ " \u2013 ",
88
+ /* @__PURE__ */ jsx2("time", { dateTime: cert.expirationDate, children: cert.expirationDate })
89
+ ] }) : null
90
+ ] })
91
+ ] }, cert.id)) })
92
+ ] });
93
+ }
94
+
56
95
  // src/components/ContactInfo.tsx
57
- import styles2 from "./ContactInfo.module-7SO24KHC.module.css";
58
- import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
96
+ import styles3 from "./ContactInfo.module-7SO24KHC.module.css";
97
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
59
98
  function ContactInfo({ contact }) {
60
99
  const showEmail = contact.showEmail === true && contact.email !== void 0;
61
100
  if (!showEmail && contact.formUrl === void 0) return null;
62
- return /* @__PURE__ */ jsxs2("section", { className: styles2.section, "aria-labelledby": "takuhon-contact-heading", children: [
63
- /* @__PURE__ */ jsx2("h2", { id: "takuhon-contact-heading", className: styles2.heading, children: "Contact" }),
64
- /* @__PURE__ */ jsxs2("ul", { className: styles2.list, children: [
65
- showEmail && contact.email !== void 0 ? /* @__PURE__ */ jsx2("li", { className: styles2.item, children: /* @__PURE__ */ jsx2("a", { className: styles2.link, href: `mailto:${contact.email}`, children: contact.email }) }) : null,
66
- contact.formUrl !== void 0 ? /* @__PURE__ */ jsx2("li", { className: styles2.item, children: /* @__PURE__ */ jsx2(
101
+ return /* @__PURE__ */ jsxs3("section", { className: styles3.section, "aria-labelledby": "takuhon-contact-heading", children: [
102
+ /* @__PURE__ */ jsx3("h2", { id: "takuhon-contact-heading", className: styles3.heading, children: "Contact" }),
103
+ /* @__PURE__ */ jsxs3("ul", { className: styles3.list, children: [
104
+ showEmail && contact.email !== void 0 ? /* @__PURE__ */ jsx3("li", { className: styles3.item, children: /* @__PURE__ */ jsx3("a", { className: styles3.link, href: `mailto:${contact.email}`, children: contact.email }) }) : null,
105
+ contact.formUrl !== void 0 ? /* @__PURE__ */ jsx3("li", { className: styles3.item, children: /* @__PURE__ */ jsx3(
67
106
  "a",
68
107
  {
69
- className: styles2.link,
108
+ className: styles3.link,
70
109
  href: contact.formUrl,
71
110
  target: "_blank",
72
111
  rel: "noopener noreferrer",
@@ -77,17 +116,71 @@ function ContactInfo({ contact }) {
77
116
  ] });
78
117
  }
79
118
 
119
+ // src/components/EducationTimeline.tsx
120
+ import styles4 from "./EducationTimeline.module-7YQTH6QU.module.css";
121
+ import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
122
+ function sortEducation(entries) {
123
+ return [...entries].sort((a, b) => {
124
+ const aOrder = a.order ?? Number.POSITIVE_INFINITY;
125
+ const bOrder = b.order ?? Number.POSITIVE_INFINITY;
126
+ if (aOrder !== bOrder) return aOrder - bOrder;
127
+ return b.startDate.localeCompare(a.startDate);
128
+ });
129
+ }
130
+ function isOngoing2(entry) {
131
+ return entry.isCurrent === true || entry.endDate === null || entry.endDate === void 0;
132
+ }
133
+ function composeStudyLine(entry) {
134
+ if (entry.degree !== void 0 && entry.fieldOfStudy !== void 0) {
135
+ return `${entry.degree} \xB7 ${entry.fieldOfStudy}`;
136
+ }
137
+ return entry.degree ?? entry.fieldOfStudy;
138
+ }
139
+ function EducationTimeline({ education }) {
140
+ if (education.length === 0) return null;
141
+ const ordered = sortEducation(education);
142
+ return /* @__PURE__ */ jsxs4("section", { className: styles4.section, "aria-labelledby": "takuhon-education-heading", children: [
143
+ /* @__PURE__ */ jsx4("h2", { id: "takuhon-education-heading", className: styles4.heading, children: "Education" }),
144
+ /* @__PURE__ */ jsx4("ol", { className: styles4.list, children: ordered.map((entry) => {
145
+ const study = composeStudyLine(entry);
146
+ return /* @__PURE__ */ jsxs4("li", { className: styles4.item, children: [
147
+ /* @__PURE__ */ jsx4("div", { className: styles4.timelineMarker, "aria-hidden": "true" }),
148
+ /* @__PURE__ */ jsxs4("div", { className: styles4.content, children: [
149
+ /* @__PURE__ */ jsx4("p", { className: styles4.institution, children: entry.url ? /* @__PURE__ */ jsx4(
150
+ "a",
151
+ {
152
+ className: styles4.link,
153
+ href: entry.url,
154
+ target: "_blank",
155
+ rel: "noopener noreferrer",
156
+ children: entry.institution
157
+ }
158
+ ) : entry.institution }),
159
+ study ? /* @__PURE__ */ jsx4("p", { className: styles4.study, children: study }) : null,
160
+ /* @__PURE__ */ jsxs4("p", { className: styles4.range, children: [
161
+ /* @__PURE__ */ jsx4("time", { dateTime: entry.startDate, children: entry.startDate }),
162
+ " \u2013 ",
163
+ isOngoing2(entry) ? "Present" : /* @__PURE__ */ jsx4("time", { dateTime: entry.endDate, children: entry.endDate })
164
+ ] }),
165
+ entry.grade ? /* @__PURE__ */ jsx4("p", { className: styles4.grade, children: entry.grade }) : null,
166
+ entry.description ? /* @__PURE__ */ jsx4("p", { className: styles4.description, children: entry.description }) : null
167
+ ] })
168
+ ] }, entry.id);
169
+ }) })
170
+ ] });
171
+ }
172
+
80
173
  // src/components/Footer.tsx
81
- import styles3 from "./Footer.module-HLC5GXVI.module.css";
82
- import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
174
+ import styles5 from "./Footer.module-HLC5GXVI.module.css";
175
+ import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
83
176
  function Footer() {
84
- return /* @__PURE__ */ jsx3("footer", { className: styles3.footer, children: /* @__PURE__ */ jsxs3("p", { className: styles3.line, children: [
177
+ return /* @__PURE__ */ jsx5("footer", { className: styles5.footer, children: /* @__PURE__ */ jsxs5("p", { className: styles5.line, children: [
85
178
  "Powered by",
86
179
  " ",
87
- /* @__PURE__ */ jsx3(
180
+ /* @__PURE__ */ jsx5(
88
181
  "a",
89
182
  {
90
- className: styles3.link,
183
+ className: styles5.link,
91
184
  href: "https://github.com/takuhon-dev/takuhon",
92
185
  target: "_blank",
93
186
  rel: "noopener noreferrer",
@@ -97,9 +190,75 @@ function Footer() {
97
190
  ] }) });
98
191
  }
99
192
 
193
+ // src/components/HonorsList.tsx
194
+ import styles6 from "./HonorsList.module-AQN3CT7O.module.css";
195
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
196
+ function sortHonors(honors) {
197
+ return [...honors].sort((a, b) => {
198
+ const aOrder = a.order ?? Number.POSITIVE_INFINITY;
199
+ const bOrder = b.order ?? Number.POSITIVE_INFINITY;
200
+ if (aOrder !== bOrder) return aOrder - bOrder;
201
+ return b.date.localeCompare(a.date);
202
+ });
203
+ }
204
+ function HonorsList({ honors }) {
205
+ if (honors.length === 0) return null;
206
+ const ordered = sortHonors(honors);
207
+ return /* @__PURE__ */ jsxs6("section", { className: styles6.section, "aria-labelledby": "takuhon-honors-heading", children: [
208
+ /* @__PURE__ */ jsx6("h2", { id: "takuhon-honors-heading", className: styles6.heading, children: "Honors & Awards" }),
209
+ /* @__PURE__ */ jsx6("ul", { className: styles6.list, children: ordered.map((honor) => /* @__PURE__ */ jsxs6("li", { className: styles6.item, children: [
210
+ /* @__PURE__ */ jsx6("p", { className: styles6.title, children: honor.url ? /* @__PURE__ */ jsx6(
211
+ "a",
212
+ {
213
+ className: styles6.link,
214
+ href: honor.url,
215
+ target: "_blank",
216
+ rel: "noopener noreferrer",
217
+ children: honor.title
218
+ }
219
+ ) : honor.title }),
220
+ /* @__PURE__ */ jsxs6("p", { className: styles6.meta, children: [
221
+ honor.issuer,
222
+ " \xB7 ",
223
+ /* @__PURE__ */ jsx6("time", { dateTime: honor.date, children: honor.date })
224
+ ] }),
225
+ honor.description ? /* @__PURE__ */ jsx6("p", { className: styles6.description, children: honor.description }) : null
226
+ ] }, honor.id)) })
227
+ ] });
228
+ }
229
+
230
+ // src/components/Languages.tsx
231
+ import styles7 from "./Languages.module-X6RQNFRY.module.css";
232
+ import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
233
+ var PROFICIENCY_LABEL = {
234
+ native: "Native",
235
+ fluent: "Fluent",
236
+ professional: "Professional working",
237
+ intermediate: "Intermediate",
238
+ basic: "Basic"
239
+ };
240
+ function sortLanguages(languages) {
241
+ return [...languages].sort((a, b) => {
242
+ const aOrder = a.order ?? Number.POSITIVE_INFINITY;
243
+ const bOrder = b.order ?? Number.POSITIVE_INFINITY;
244
+ return aOrder - bOrder;
245
+ });
246
+ }
247
+ function Languages({ languages }) {
248
+ if (languages.length === 0) return null;
249
+ const ordered = sortLanguages(languages);
250
+ return /* @__PURE__ */ jsxs7("section", { className: styles7.section, "aria-labelledby": "takuhon-languages-heading", children: [
251
+ /* @__PURE__ */ jsx7("h2", { id: "takuhon-languages-heading", className: styles7.heading, children: "Languages" }),
252
+ /* @__PURE__ */ jsx7("ul", { className: styles7.list, children: ordered.map((entry) => /* @__PURE__ */ jsxs7("li", { className: styles7.item, children: [
253
+ /* @__PURE__ */ jsx7("span", { className: styles7.name, lang: entry.language, children: entry.displayName ?? entry.language }),
254
+ /* @__PURE__ */ jsx7("span", { className: styles7.proficiency, children: PROFICIENCY_LABEL[entry.proficiency] })
255
+ ] }, entry.id)) })
256
+ ] });
257
+ }
258
+
100
259
  // src/components/LinksList.tsx
101
- import styles4 from "./LinksList.module-QPSFPOF3.module.css";
102
- import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
260
+ import styles8 from "./LinksList.module-QPSFPOF3.module.css";
261
+ import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
103
262
  function sortLinks(links) {
104
263
  return [...links].sort((a, b) => {
105
264
  const aFeatured = a.featured ? 1 : 0;
@@ -118,32 +277,32 @@ function formatLinkLabel(link) {
118
277
  function LinksList({ links }) {
119
278
  if (links.length === 0) return null;
120
279
  const ordered = sortLinks(links);
121
- return /* @__PURE__ */ jsx4("nav", { "aria-label": "Profile links", className: styles4.nav, children: /* @__PURE__ */ jsx4("ul", { className: styles4.list, children: ordered.map((link) => /* @__PURE__ */ jsx4("li", { className: styles4.item, children: /* @__PURE__ */ jsxs4(
280
+ return /* @__PURE__ */ jsx8("nav", { "aria-label": "Profile links", className: styles8.nav, children: /* @__PURE__ */ jsx8("ul", { className: styles8.list, children: ordered.map((link) => /* @__PURE__ */ jsx8("li", { className: styles8.item, children: /* @__PURE__ */ jsxs8(
122
281
  "a",
123
282
  {
124
- className: styles4.link,
283
+ className: styles8.link,
125
284
  href: link.url,
126
285
  target: "_blank",
127
286
  rel: "noopener noreferrer",
128
287
  "data-featured": link.featured ? "true" : void 0,
129
288
  children: [
130
- link.iconUrl ? /* @__PURE__ */ jsx4("img", { className: styles4.icon, src: link.iconUrl, alt: "" }) : null,
131
- /* @__PURE__ */ jsx4("span", { className: styles4.label, children: formatLinkLabel(link) })
289
+ link.iconUrl ? /* @__PURE__ */ jsx8("img", { className: styles8.icon, src: link.iconUrl, alt: "" }) : null,
290
+ /* @__PURE__ */ jsx8("span", { className: styles8.label, children: formatLinkLabel(link) })
132
291
  ]
133
292
  }
134
293
  ) }, link.id)) }) });
135
294
  }
136
295
 
137
296
  // src/components/ProfileHeader.tsx
138
- import styles5 from "./ProfileHeader.module-EK27UTZL.module.css";
139
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
297
+ import styles9 from "./ProfileHeader.module-EK27UTZL.module.css";
298
+ import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
140
299
  function ProfileHeader({ profile }) {
141
300
  const locationLabel = profile.location?.display ?? profile.location?.locality;
142
- return /* @__PURE__ */ jsxs5("header", { className: styles5.header, children: [
143
- profile.avatar ? /* @__PURE__ */ jsx5(
301
+ return /* @__PURE__ */ jsxs9("header", { className: styles9.header, children: [
302
+ profile.avatar ? /* @__PURE__ */ jsx9(
144
303
  "img",
145
304
  {
146
- className: styles5.avatar,
305
+ className: styles9.avatar,
147
306
  src: profile.avatar.url,
148
307
  alt: profile.avatar.alt ?? "",
149
308
  width: 128,
@@ -152,16 +311,16 @@ function ProfileHeader({ profile }) {
152
311
  decoding: "async"
153
312
  }
154
313
  ) : null,
155
- /* @__PURE__ */ jsx5("h1", { className: styles5.displayName, children: profile.displayName }),
156
- profile.tagline ? /* @__PURE__ */ jsx5("p", { className: styles5.tagline, children: profile.tagline }) : null,
157
- locationLabel ? /* @__PURE__ */ jsx5("p", { className: styles5.location, children: locationLabel }) : null,
158
- profile.bio ? /* @__PURE__ */ jsx5("p", { className: styles5.bio, children: profile.bio }) : null
314
+ /* @__PURE__ */ jsx9("h1", { className: styles9.displayName, children: profile.displayName }),
315
+ profile.tagline ? /* @__PURE__ */ jsx9("p", { className: styles9.tagline, children: profile.tagline }) : null,
316
+ locationLabel ? /* @__PURE__ */ jsx9("p", { className: styles9.location, children: locationLabel }) : null,
317
+ profile.bio ? /* @__PURE__ */ jsx9("p", { className: styles9.bio, children: profile.bio }) : null
159
318
  ] });
160
319
  }
161
320
 
162
321
  // src/components/ProjectsList.tsx
163
- import styles6 from "./ProjectsList.module-JKGGZRKO.module.css";
164
- import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
322
+ import styles10 from "./ProjectsList.module-JKGGZRKO.module.css";
323
+ import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
165
324
  function sortProjects(projects) {
166
325
  return [...projects].sort((a, b) => {
167
326
  const aHighlighted = a.highlighted ? 1 : 0;
@@ -175,31 +334,31 @@ function sortProjects(projects) {
175
334
  function ProjectsList({ projects }) {
176
335
  if (projects.length === 0) return null;
177
336
  const ordered = sortProjects(projects);
178
- return /* @__PURE__ */ jsxs6("section", { className: styles6.section, "aria-labelledby": "takuhon-projects-heading", children: [
179
- /* @__PURE__ */ jsx6("h2", { id: "takuhon-projects-heading", className: styles6.heading, children: "Projects" }),
180
- /* @__PURE__ */ jsx6("ul", { className: styles6.list, children: ordered.map((project) => /* @__PURE__ */ jsxs6(
337
+ return /* @__PURE__ */ jsxs10("section", { className: styles10.section, "aria-labelledby": "takuhon-projects-heading", children: [
338
+ /* @__PURE__ */ jsx10("h2", { id: "takuhon-projects-heading", className: styles10.heading, children: "Projects" }),
339
+ /* @__PURE__ */ jsx10("ul", { className: styles10.list, children: ordered.map((project) => /* @__PURE__ */ jsxs10(
181
340
  "li",
182
341
  {
183
- className: styles6.item,
342
+ className: styles10.item,
184
343
  "data-highlighted": project.highlighted ? "true" : void 0,
185
344
  children: [
186
- /* @__PURE__ */ jsx6("p", { className: styles6.title, children: project.url ? /* @__PURE__ */ jsx6(
345
+ /* @__PURE__ */ jsx10("p", { className: styles10.title, children: project.url ? /* @__PURE__ */ jsx10(
187
346
  "a",
188
347
  {
189
- className: styles6.titleLink,
348
+ className: styles10.titleLink,
190
349
  href: project.url,
191
350
  target: "_blank",
192
351
  rel: "noopener noreferrer",
193
352
  children: project.title
194
353
  }
195
354
  ) : project.title }),
196
- project.startDate !== void 0 ? /* @__PURE__ */ jsxs6("p", { className: styles6.range, children: [
197
- /* @__PURE__ */ jsx6("time", { dateTime: project.startDate, children: project.startDate }),
355
+ project.startDate !== void 0 ? /* @__PURE__ */ jsxs10("p", { className: styles10.range, children: [
356
+ /* @__PURE__ */ jsx10("time", { dateTime: project.startDate, children: project.startDate }),
198
357
  " \u2013 ",
199
- project.endDate ? /* @__PURE__ */ jsx6("time", { dateTime: project.endDate, children: project.endDate }) : "Present"
358
+ project.endDate ? /* @__PURE__ */ jsx10("time", { dateTime: project.endDate, children: project.endDate }) : "Present"
200
359
  ] }) : null,
201
- project.description ? /* @__PURE__ */ jsx6("p", { className: styles6.description, children: project.description }) : null,
202
- project.tags && project.tags.length > 0 ? /* @__PURE__ */ jsx6("ul", { className: styles6.tags, "aria-label": "Tags", children: project.tags.map((tag) => /* @__PURE__ */ jsx6("li", { className: styles6.tag, children: tag }, tag)) }) : null
360
+ project.description ? /* @__PURE__ */ jsx10("p", { className: styles10.description, children: project.description }) : null,
361
+ project.tags && project.tags.length > 0 ? /* @__PURE__ */ jsx10("ul", { className: styles10.tags, "aria-label": "Tags", children: project.tags.map((tag) => /* @__PURE__ */ jsx10("li", { className: styles10.tag, children: tag }, tag)) }) : null
203
362
  ]
204
363
  },
205
364
  project.id
@@ -208,8 +367,8 @@ function ProjectsList({ projects }) {
208
367
  }
209
368
 
210
369
  // src/components/SkillsList.tsx
211
- import styles7 from "./SkillsList.module-XIAWE55H.module.css";
212
- import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
370
+ import styles11 from "./SkillsList.module-XIAWE55H.module.css";
371
+ import { jsx as jsx11, jsxs as jsxs11 } from "react/jsx-runtime";
213
372
  function groupSkills(skills) {
214
373
  const sorted = [...skills].sort((a, b) => {
215
374
  const aOrder = a.order ?? Number.POSITIVE_INFINITY;
@@ -231,34 +390,38 @@ function groupSkills(skills) {
231
390
  function SkillsList({ skills }) {
232
391
  if (skills.length === 0) return null;
233
392
  const groups = groupSkills(skills);
234
- return /* @__PURE__ */ jsxs7("section", { className: styles7.section, "aria-labelledby": "takuhon-skills-heading", children: [
235
- /* @__PURE__ */ jsx7("h2", { id: "takuhon-skills-heading", className: styles7.heading, children: "Skills" }),
236
- /* @__PURE__ */ jsx7("div", { className: styles7.groups, children: groups.map((group) => /* @__PURE__ */ jsxs7("div", { className: styles7.group, children: [
237
- /* @__PURE__ */ jsx7("h3", { className: styles7.category, children: group.category }),
238
- /* @__PURE__ */ jsx7("ul", { className: styles7.list, "aria-label": `${group.category} skills`, children: group.skills.map((skill) => /* @__PURE__ */ jsx7("li", { className: styles7.item, children: skill.label }, skill.id)) })
393
+ return /* @__PURE__ */ jsxs11("section", { className: styles11.section, "aria-labelledby": "takuhon-skills-heading", children: [
394
+ /* @__PURE__ */ jsx11("h2", { id: "takuhon-skills-heading", className: styles11.heading, children: "Skills" }),
395
+ /* @__PURE__ */ jsx11("div", { className: styles11.groups, children: groups.map((group) => /* @__PURE__ */ jsxs11("div", { className: styles11.group, children: [
396
+ /* @__PURE__ */ jsx11("h3", { className: styles11.category, children: group.category }),
397
+ /* @__PURE__ */ jsx11("ul", { className: styles11.list, "aria-label": `${group.category} skills`, children: group.skills.map((skill) => /* @__PURE__ */ jsx11("li", { className: styles11.item, children: skill.label }, skill.id)) })
239
398
  ] }, group.category)) })
240
399
  ] });
241
400
  }
242
401
 
243
402
  // src/components/TakuhonProfile.tsx
244
- import styles8 from "./TakuhonProfile.module-QUEORIHA.module.css";
245
- import { jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
403
+ import styles12 from "./TakuhonProfile.module-QUEORIHA.module.css";
404
+ import { jsx as jsx12, jsxs as jsxs12 } from "react/jsx-runtime";
246
405
  function TakuhonProfile({ data }) {
247
406
  const showFooter = data.settings.showPoweredBy !== false;
248
- return /* @__PURE__ */ jsxs8("article", { className: styles8.root, children: [
249
- /* @__PURE__ */ jsx8(ProfileHeader, { profile: data.profile }),
250
- /* @__PURE__ */ jsx8(LinksList, { links: data.links }),
251
- /* @__PURE__ */ jsx8(CareerTimeline, { careers: data.careers }),
252
- /* @__PURE__ */ jsx8(ProjectsList, { projects: data.projects }),
253
- /* @__PURE__ */ jsx8(SkillsList, { skills: data.skills }),
254
- /* @__PURE__ */ jsx8(ContactInfo, { contact: data.contact }),
255
- showFooter ? /* @__PURE__ */ jsx8(Footer, {}) : null
407
+ return /* @__PURE__ */ jsxs12("article", { className: styles12.root, children: [
408
+ /* @__PURE__ */ jsx12(ProfileHeader, { profile: data.profile }),
409
+ /* @__PURE__ */ jsx12(LinksList, { links: data.links }),
410
+ /* @__PURE__ */ jsx12(EducationTimeline, { education: data.education }),
411
+ /* @__PURE__ */ jsx12(CareerTimeline, { careers: data.careers }),
412
+ /* @__PURE__ */ jsx12(Certifications, { certifications: data.certifications }),
413
+ /* @__PURE__ */ jsx12(ProjectsList, { projects: data.projects }),
414
+ /* @__PURE__ */ jsx12(HonorsList, { honors: data.honors }),
415
+ /* @__PURE__ */ jsx12(SkillsList, { skills: data.skills }),
416
+ /* @__PURE__ */ jsx12(Languages, { languages: data.languages }),
417
+ /* @__PURE__ */ jsx12(ContactInfo, { contact: data.contact }),
418
+ showFooter ? /* @__PURE__ */ jsx12(Footer, {}) : null
256
419
  ] });
257
420
  }
258
421
 
259
422
  // src/components/LocaleSwitcher.tsx
260
- import styles9 from "./LocaleSwitcher.module-QVLPVGLG.module.css";
261
- import { jsx as jsx9 } from "react/jsx-runtime";
423
+ import styles13 from "./LocaleSwitcher.module-QVLPVGLG.module.css";
424
+ import { jsx as jsx13 } from "react/jsx-runtime";
262
425
  var DEFAULT_ARIA_LABEL = "Select language";
263
426
  function LocaleSwitcher({
264
427
  availableLocales,
@@ -269,16 +432,16 @@ function LocaleSwitcher({
269
432
  }) {
270
433
  const label = ariaLabel ?? DEFAULT_ARIA_LABEL;
271
434
  const format = formatLocale ?? ((locale) => locale);
272
- return /* @__PURE__ */ jsx9("div", { className: styles9.wrapper, children: /* @__PURE__ */ jsx9(
435
+ return /* @__PURE__ */ jsx13("div", { className: styles13.wrapper, children: /* @__PURE__ */ jsx13(
273
436
  "select",
274
437
  {
275
- className: styles9.select,
438
+ className: styles13.select,
276
439
  "aria-label": label,
277
440
  value: currentLocale,
278
441
  onChange: (event) => {
279
442
  onSelect(event.target.value);
280
443
  },
281
- children: availableLocales.map((locale) => /* @__PURE__ */ jsx9("option", { value: locale, children: format(locale) }, locale))
444
+ children: availableLocales.map((locale) => /* @__PURE__ */ jsx13("option", { value: locale, children: format(locale) }, locale))
282
445
  }
283
446
  ) });
284
447
  }
@@ -286,7 +449,7 @@ function LocaleSwitcher({
286
449
  // src/components/TakuhonHead.tsx
287
450
  import { generateJsonLd } from "@takuhon/core";
288
451
  import { useEffect } from "react";
289
- import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
452
+ import { Fragment as Fragment3, jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
290
453
  function buildLocaleUrl(pageUrl, locale) {
291
454
  try {
292
455
  const url = new URL(pageUrl);
@@ -353,26 +516,30 @@ function TakuhonHead({ data, siteUrl, pageUrl }) {
353
516
  script.remove();
354
517
  };
355
518
  }, [jsonLdPayload]);
356
- return /* @__PURE__ */ jsxs9(Fragment2, { children: [
357
- /* @__PURE__ */ jsx10("title", { children: profile.displayName }),
358
- description ? /* @__PURE__ */ jsx10("meta", { name: "description", content: description }) : null,
359
- canonical ? /* @__PURE__ */ jsx10("link", { rel: "canonical", href: canonical }) : null,
360
- /* @__PURE__ */ jsx10("meta", { property: "og:title", content: profile.displayName }),
361
- ogDescription ? /* @__PURE__ */ jsx10("meta", { property: "og:description", content: ogDescription }) : null,
362
- canonical ? /* @__PURE__ */ jsx10("meta", { property: "og:url", content: canonical }) : null,
363
- ogImage ? /* @__PURE__ */ jsx10("meta", { property: "og:image", content: ogImage }) : null,
364
- /* @__PURE__ */ jsx10("meta", { property: "og:type", content: "profile" }),
365
- /* @__PURE__ */ jsx10("meta", { property: "og:locale", content: resolvedLocale }),
366
- ogAlternates.map((loc) => /* @__PURE__ */ jsx10("meta", { property: "og:locale:alternate", content: loc }, loc)),
367
- /* @__PURE__ */ jsx10("meta", { name: "twitter:card", content: twitterCard }),
368
- alternates.map(({ locale, href }) => /* @__PURE__ */ jsx10("link", { rel: "alternate", hrefLang: locale, href }, locale)),
369
- xDefaultHref ? /* @__PURE__ */ jsx10("link", { rel: "alternate", hrefLang: "x-default", href: xDefaultHref }) : null
519
+ return /* @__PURE__ */ jsxs13(Fragment3, { children: [
520
+ /* @__PURE__ */ jsx14("title", { children: profile.displayName }),
521
+ description ? /* @__PURE__ */ jsx14("meta", { name: "description", content: description }) : null,
522
+ canonical ? /* @__PURE__ */ jsx14("link", { rel: "canonical", href: canonical }) : null,
523
+ /* @__PURE__ */ jsx14("meta", { property: "og:title", content: profile.displayName }),
524
+ ogDescription ? /* @__PURE__ */ jsx14("meta", { property: "og:description", content: ogDescription }) : null,
525
+ canonical ? /* @__PURE__ */ jsx14("meta", { property: "og:url", content: canonical }) : null,
526
+ ogImage ? /* @__PURE__ */ jsx14("meta", { property: "og:image", content: ogImage }) : null,
527
+ /* @__PURE__ */ jsx14("meta", { property: "og:type", content: "profile" }),
528
+ /* @__PURE__ */ jsx14("meta", { property: "og:locale", content: resolvedLocale }),
529
+ ogAlternates.map((loc) => /* @__PURE__ */ jsx14("meta", { property: "og:locale:alternate", content: loc }, loc)),
530
+ /* @__PURE__ */ jsx14("meta", { name: "twitter:card", content: twitterCard }),
531
+ alternates.map(({ locale, href }) => /* @__PURE__ */ jsx14("link", { rel: "alternate", hrefLang: locale, href }, locale)),
532
+ xDefaultHref ? /* @__PURE__ */ jsx14("link", { rel: "alternate", hrefLang: "x-default", href: xDefaultHref }) : null
370
533
  ] });
371
534
  }
372
535
  export {
373
536
  CareerTimeline,
537
+ Certifications,
374
538
  ContactInfo,
539
+ EducationTimeline,
375
540
  Footer,
541
+ HonorsList,
542
+ Languages,
376
543
  LinksList,
377
544
  LocaleSwitcher,
378
545
  ProfileHeader,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/components/TakuhonProfile.tsx","../src/components/CareerTimeline.tsx","../src/components/ContactInfo.tsx","../src/components/Footer.tsx","../src/components/LinksList.tsx","../src/components/ProfileHeader.tsx","../src/components/ProjectsList.tsx","../src/components/SkillsList.tsx","../src/components/LocaleSwitcher.tsx","../src/components/TakuhonHead.tsx"],"sourcesContent":["import type { LocalizedTakuhon } from '@takuhon/core';\n\nimport '../styles/tokens.css';\n\nimport { CareerTimeline } from './CareerTimeline.js';\nimport { ContactInfo } from './ContactInfo.js';\nimport { Footer } from './Footer.js';\nimport { LinksList } from './LinksList.js';\nimport { ProfileHeader } from './ProfileHeader.js';\nimport { ProjectsList } from './ProjectsList.js';\nimport { SkillsList } from './SkillsList.js';\nimport styles from './TakuhonProfile.module.css';\n\nexport interface TakuhonProfileProps {\n data: LocalizedTakuhon;\n}\n\nexport function TakuhonProfile({ data }: TakuhonProfileProps): React.JSX.Element {\n const showFooter = data.settings.showPoweredBy !== false;\n\n return (\n <article className={styles.root}>\n <ProfileHeader profile={data.profile} />\n <LinksList links={data.links} />\n <CareerTimeline careers={data.careers} />\n <ProjectsList projects={data.projects} />\n <SkillsList skills={data.skills} />\n <ContactInfo contact={data.contact} />\n {showFooter ? <Footer /> : null}\n </article>\n );\n}\n","import type { LocalizedCareer } from '@takuhon/core';\n\nimport styles from './CareerTimeline.module.css';\n\nexport interface CareerTimelineProps {\n careers: LocalizedCareer[];\n}\n\nfunction sortCareers(careers: LocalizedCareer[]): LocalizedCareer[] {\n return [...careers].sort((a, b) => {\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n if (aOrder !== bOrder) return aOrder - bOrder;\n return b.startDate.localeCompare(a.startDate);\n });\n}\n\nfunction isOngoing(career: LocalizedCareer): boolean {\n return career.isCurrent === true || career.endDate === null || career.endDate === undefined;\n}\n\nexport function CareerTimeline({ careers }: CareerTimelineProps): React.JSX.Element | null {\n if (careers.length === 0) return null;\n const ordered = sortCareers(careers);\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-career-heading\">\n <h2 id=\"takuhon-career-heading\" className={styles.heading}>\n Career\n </h2>\n <ol className={styles.list}>\n {ordered.map((career) => (\n <li key={career.id} className={styles.item}>\n <div className={styles.timelineMarker} aria-hidden=\"true\" />\n <div className={styles.content}>\n <p className={styles.role}>\n {career.url ? (\n <a\n className={styles.organizationLink}\n href={career.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {career.role} · {career.organization}\n </a>\n ) : (\n <>\n {career.role} · {career.organization}\n </>\n )}\n </p>\n <p className={styles.range}>\n <time dateTime={career.startDate}>{career.startDate}</time>\n {' – '}\n {isOngoing(career) ? (\n 'Present'\n ) : (\n <time dateTime={career.endDate!}>{career.endDate}</time>\n )}\n </p>\n {career.location?.display ? (\n <p className={styles.location}>{career.location.display}</p>\n ) : null}\n {career.description ? (\n <p className={styles.description}>{career.description}</p>\n ) : null}\n </div>\n </li>\n ))}\n </ol>\n </section>\n );\n}\n","import type { Contact } from '@takuhon/core';\n\nimport styles from './ContactInfo.module.css';\n\nexport interface ContactInfoProps {\n contact: Contact;\n}\n\nexport function ContactInfo({ contact }: ContactInfoProps): React.JSX.Element | null {\n const showEmail = contact.showEmail === true && contact.email !== undefined;\n if (!showEmail && contact.formUrl === undefined) return null;\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-contact-heading\">\n <h2 id=\"takuhon-contact-heading\" className={styles.heading}>\n Contact\n </h2>\n <ul className={styles.list}>\n {showEmail && contact.email !== undefined ? (\n <li className={styles.item}>\n <a className={styles.link} href={`mailto:${contact.email}`}>\n {contact.email}\n </a>\n </li>\n ) : null}\n {contact.formUrl !== undefined ? (\n <li className={styles.item}>\n <a\n className={styles.link}\n href={contact.formUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Contact form\n </a>\n </li>\n ) : null}\n </ul>\n </section>\n );\n}\n","import styles from './Footer.module.css';\n\nexport function Footer(): React.JSX.Element {\n return (\n <footer className={styles.footer}>\n <p className={styles.line}>\n Powered by{' '}\n <a\n className={styles.link}\n href=\"https://github.com/takuhon-dev/takuhon\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n takuhon\n </a>\n </p>\n </footer>\n );\n}\n","import type { LocalizedLink } from '@takuhon/core';\n\nimport styles from './LinksList.module.css';\n\nexport interface LinksListProps {\n links: LocalizedLink[];\n}\n\nfunction sortLinks(links: LocalizedLink[]): LocalizedLink[] {\n return [...links].sort((a, b) => {\n const aFeatured = a.featured ? 1 : 0;\n const bFeatured = b.featured ? 1 : 0;\n if (aFeatured !== bFeatured) return bFeatured - aFeatured;\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n return aOrder - bOrder;\n });\n}\n\nfunction formatLinkLabel(link: LocalizedLink): string {\n if (link.label) return link.label;\n if (link.type === 'custom') return link.id;\n return link.type;\n}\n\nexport function LinksList({ links }: LinksListProps): React.JSX.Element | null {\n if (links.length === 0) return null;\n\n const ordered = sortLinks(links);\n\n return (\n <nav aria-label=\"Profile links\" className={styles.nav}>\n <ul className={styles.list}>\n {ordered.map((link) => (\n <li key={link.id} className={styles.item}>\n <a\n className={styles.link}\n href={link.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n data-featured={link.featured ? 'true' : undefined}\n >\n {link.iconUrl ? <img className={styles.icon} src={link.iconUrl} alt=\"\" /> : null}\n <span className={styles.label}>{formatLinkLabel(link)}</span>\n </a>\n </li>\n ))}\n </ul>\n </nav>\n );\n}\n","import type { LocalizedProfile } from '@takuhon/core';\n\nimport styles from './ProfileHeader.module.css';\n\nexport interface ProfileHeaderProps {\n profile: LocalizedProfile;\n}\n\nexport function ProfileHeader({ profile }: ProfileHeaderProps): React.JSX.Element {\n const locationLabel = profile.location?.display ?? profile.location?.locality;\n\n return (\n <header className={styles.header}>\n {profile.avatar ? (\n <img\n className={styles.avatar}\n src={profile.avatar.url}\n alt={profile.avatar.alt ?? ''}\n width={128}\n height={128}\n loading=\"eager\"\n decoding=\"async\"\n />\n ) : null}\n <h1 className={styles.displayName}>{profile.displayName}</h1>\n {profile.tagline ? <p className={styles.tagline}>{profile.tagline}</p> : null}\n {locationLabel ? <p className={styles.location}>{locationLabel}</p> : null}\n {profile.bio ? <p className={styles.bio}>{profile.bio}</p> : null}\n </header>\n );\n}\n","import type { LocalizedProject } from '@takuhon/core';\n\nimport styles from './ProjectsList.module.css';\n\nexport interface ProjectsListProps {\n projects: LocalizedProject[];\n}\n\nfunction sortProjects(projects: LocalizedProject[]): LocalizedProject[] {\n return [...projects].sort((a, b) => {\n const aHighlighted = a.highlighted ? 1 : 0;\n const bHighlighted = b.highlighted ? 1 : 0;\n if (aHighlighted !== bHighlighted) return bHighlighted - aHighlighted;\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n return aOrder - bOrder;\n });\n}\n\nexport function ProjectsList({ projects }: ProjectsListProps): React.JSX.Element | null {\n if (projects.length === 0) return null;\n const ordered = sortProjects(projects);\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-projects-heading\">\n <h2 id=\"takuhon-projects-heading\" className={styles.heading}>\n Projects\n </h2>\n <ul className={styles.list}>\n {ordered.map((project) => (\n <li\n key={project.id}\n className={styles.item}\n data-highlighted={project.highlighted ? 'true' : undefined}\n >\n <p className={styles.title}>\n {project.url ? (\n <a\n className={styles.titleLink}\n href={project.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {project.title}\n </a>\n ) : (\n project.title\n )}\n </p>\n {project.startDate !== undefined ? (\n <p className={styles.range}>\n <time dateTime={project.startDate}>{project.startDate}</time>\n {' – '}\n {project.endDate ? (\n <time dateTime={project.endDate}>{project.endDate}</time>\n ) : (\n 'Present'\n )}\n </p>\n ) : null}\n {project.description ? (\n <p className={styles.description}>{project.description}</p>\n ) : null}\n {project.tags && project.tags.length > 0 ? (\n <ul className={styles.tags} aria-label=\"Tags\">\n {project.tags.map((tag) => (\n <li key={tag} className={styles.tag}>\n {tag}\n </li>\n ))}\n </ul>\n ) : null}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n","import type { Skill } from '@takuhon/core';\n\nimport styles from './SkillsList.module.css';\n\nexport interface SkillsListProps {\n skills: Skill[];\n}\n\ninterface SkillGroup {\n category: string;\n skills: Skill[];\n}\n\nfunction groupSkills(skills: Skill[]): SkillGroup[] {\n const sorted = [...skills].sort((a, b) => {\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n return aOrder - bOrder;\n });\n const groups = new Map<string, Skill[]>();\n for (const skill of sorted) {\n const key = skill.category ?? 'other';\n const bucket = groups.get(key);\n if (bucket) {\n bucket.push(skill);\n } else {\n groups.set(key, [skill]);\n }\n }\n return [...groups.entries()].map(([category, items]) => ({ category, skills: items }));\n}\n\nexport function SkillsList({ skills }: SkillsListProps): React.JSX.Element | null {\n if (skills.length === 0) return null;\n const groups = groupSkills(skills);\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-skills-heading\">\n <h2 id=\"takuhon-skills-heading\" className={styles.heading}>\n Skills\n </h2>\n <div className={styles.groups}>\n {groups.map((group) => (\n <div key={group.category} className={styles.group}>\n <h3 className={styles.category}>{group.category}</h3>\n <ul className={styles.list} aria-label={`${group.category} skills`}>\n {group.skills.map((skill) => (\n <li key={skill.id} className={styles.item}>\n {skill.label}\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n </section>\n );\n}\n","import type { LocaleTag } from '@takuhon/core';\n\nimport styles from './LocaleSwitcher.module.css';\n\nexport interface LocaleSwitcherProps {\n availableLocales: LocaleTag[];\n currentLocale: LocaleTag;\n onSelect: (locale: LocaleTag) => void;\n ariaLabel?: string;\n formatLocale?: (locale: LocaleTag) => string;\n}\n\nconst DEFAULT_ARIA_LABEL = 'Select language';\n\nexport function LocaleSwitcher({\n availableLocales,\n currentLocale,\n onSelect,\n ariaLabel,\n formatLocale,\n}: LocaleSwitcherProps): React.JSX.Element {\n const label = ariaLabel ?? DEFAULT_ARIA_LABEL;\n const format = formatLocale ?? ((locale: LocaleTag) => locale);\n return (\n <div className={styles.wrapper}>\n <select\n className={styles.select}\n aria-label={label}\n value={currentLocale}\n onChange={(event) => {\n onSelect(event.target.value);\n }}\n >\n {availableLocales.map((locale) => (\n <option key={locale} value={locale}>\n {format(locale)}\n </option>\n ))}\n </select>\n </div>\n );\n}\n","import { generateJsonLd, type LocalizedTakuhon } from '@takuhon/core';\nimport { useEffect } from 'react';\n\nexport interface TakuhonHeadProps {\n data: LocalizedTakuhon;\n siteUrl?: string;\n pageUrl?: string;\n}\n\nfunction buildLocaleUrl(pageUrl: string, locale: string): string {\n try {\n const url = new URL(pageUrl);\n url.searchParams.set('lang', locale);\n return url.toString();\n } catch {\n return pageUrl;\n }\n}\n\nfunction stripLangParam(pageUrl: string): string {\n try {\n const url = new URL(pageUrl);\n url.searchParams.delete('lang');\n return url.toString();\n } catch {\n return pageUrl;\n }\n}\n\nfunction absolutizeUrl(url: string | undefined, base: string | undefined): string | undefined {\n if (!url) return undefined;\n if (!base) return url;\n try {\n return new URL(url, base).toString();\n } catch {\n return url;\n }\n}\n\nfunction detectSiteUrl(explicit: string | undefined): string | undefined {\n if (explicit) return explicit;\n if (typeof window !== 'undefined') return window.location.origin;\n return undefined;\n}\n\nfunction detectPageUrl(\n explicit: string | undefined,\n siteUrl: string | undefined,\n): string | undefined {\n if (explicit) return stripLangParam(explicit);\n if (typeof window !== 'undefined') {\n return window.location.origin + window.location.pathname;\n }\n return siteUrl;\n}\n\nexport function TakuhonHead({ data, siteUrl, pageUrl }: TakuhonHeadProps): React.JSX.Element {\n const resolvedSiteUrl = detectSiteUrl(siteUrl);\n const resolvedPageUrl = detectPageUrl(pageUrl, resolvedSiteUrl);\n\n const { profile, settings, resolvedLocale } = data;\n const description = profile.bio ?? profile.tagline;\n const ogDescription = profile.tagline ?? profile.bio;\n const ogImage = absolutizeUrl(profile.avatar?.url, resolvedSiteUrl);\n const twitterCard = profile.avatar ? 'summary_large_image' : 'summary';\n\n const canonical = resolvedPageUrl ? buildLocaleUrl(resolvedPageUrl, resolvedLocale) : undefined;\n const alternates = resolvedPageUrl\n ? settings.availableLocales.map((loc) => ({\n locale: loc,\n href: buildLocaleUrl(resolvedPageUrl, loc),\n }))\n : [];\n const xDefaultHref = resolvedPageUrl\n ? buildLocaleUrl(resolvedPageUrl, settings.defaultLocale)\n : undefined;\n\n const ogAlternates = settings.availableLocales.filter((loc) => loc !== resolvedLocale);\n\n const emitJsonLd = settings.enableJsonLd !== false;\n const jsonLdPayload = emitJsonLd ? JSON.stringify(generateJsonLd(data)) : null;\n\n useEffect(() => {\n if (!jsonLdPayload) return;\n const script = document.createElement('script');\n script.type = 'application/ld+json';\n script.textContent = jsonLdPayload;\n document.head.appendChild(script);\n return () => {\n script.remove();\n };\n }, [jsonLdPayload]);\n\n return (\n <>\n <title>{profile.displayName}</title>\n {description ? <meta name=\"description\" content={description} /> : null}\n {canonical ? <link rel=\"canonical\" href={canonical} /> : null}\n\n <meta property=\"og:title\" content={profile.displayName} />\n {ogDescription ? <meta property=\"og:description\" content={ogDescription} /> : null}\n {canonical ? <meta property=\"og:url\" content={canonical} /> : null}\n {ogImage ? <meta property=\"og:image\" content={ogImage} /> : null}\n <meta property=\"og:type\" content=\"profile\" />\n <meta property=\"og:locale\" content={resolvedLocale} />\n {ogAlternates.map((loc) => (\n <meta key={loc} property=\"og:locale:alternate\" content={loc} />\n ))}\n\n <meta name=\"twitter:card\" content={twitterCard} />\n\n {alternates.map(({ locale, href }) => (\n <link key={locale} rel=\"alternate\" hrefLang={locale} href={href} />\n ))}\n {xDefaultHref ? <link rel=\"alternate\" hrefLang=\"x-default\" href={xDefaultHref} /> : null}\n </>\n );\n}\n"],"mappings":"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","names":["styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","Fragment","jsx","jsxs"]}
1
+ {"version":3,"sources":["../src/components/TakuhonProfile.tsx","../src/components/CareerTimeline.tsx","../src/components/Certifications.tsx","../src/components/ContactInfo.tsx","../src/components/EducationTimeline.tsx","../src/components/Footer.tsx","../src/components/HonorsList.tsx","../src/components/Languages.tsx","../src/components/LinksList.tsx","../src/components/ProfileHeader.tsx","../src/components/ProjectsList.tsx","../src/components/SkillsList.tsx","../src/components/LocaleSwitcher.tsx","../src/components/TakuhonHead.tsx"],"sourcesContent":["import type { LocalizedTakuhon } from '@takuhon/core';\n\nimport '../styles/tokens.css';\n\nimport { CareerTimeline } from './CareerTimeline.js';\nimport { Certifications } from './Certifications.js';\nimport { ContactInfo } from './ContactInfo.js';\nimport { EducationTimeline } from './EducationTimeline.js';\nimport { Footer } from './Footer.js';\nimport { HonorsList } from './HonorsList.js';\nimport { Languages } from './Languages.js';\nimport { LinksList } from './LinksList.js';\nimport { ProfileHeader } from './ProfileHeader.js';\nimport { ProjectsList } from './ProjectsList.js';\nimport { SkillsList } from './SkillsList.js';\nimport styles from './TakuhonProfile.module.css';\n\nexport interface TakuhonProfileProps {\n data: LocalizedTakuhon;\n}\n\nexport function TakuhonProfile({ data }: TakuhonProfileProps): React.JSX.Element {\n const showFooter = data.settings.showPoweredBy !== false;\n\n return (\n <article className={styles.root}>\n <ProfileHeader profile={data.profile} />\n <LinksList links={data.links} />\n <EducationTimeline education={data.education} />\n <CareerTimeline careers={data.careers} />\n <Certifications certifications={data.certifications} />\n <ProjectsList projects={data.projects} />\n <HonorsList honors={data.honors} />\n <SkillsList skills={data.skills} />\n <Languages languages={data.languages} />\n <ContactInfo contact={data.contact} />\n {showFooter ? <Footer /> : null}\n </article>\n );\n}\n","import type { LocalizedCareer } from '@takuhon/core';\n\nimport styles from './CareerTimeline.module.css';\n\nexport interface CareerTimelineProps {\n careers: LocalizedCareer[];\n}\n\nfunction sortCareers(careers: LocalizedCareer[]): LocalizedCareer[] {\n return [...careers].sort((a, b) => {\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n if (aOrder !== bOrder) return aOrder - bOrder;\n return b.startDate.localeCompare(a.startDate);\n });\n}\n\nfunction isOngoing(career: LocalizedCareer): boolean {\n return career.isCurrent === true || career.endDate === null || career.endDate === undefined;\n}\n\nexport function CareerTimeline({ careers }: CareerTimelineProps): React.JSX.Element | null {\n if (careers.length === 0) return null;\n const ordered = sortCareers(careers);\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-career-heading\">\n <h2 id=\"takuhon-career-heading\" className={styles.heading}>\n Career\n </h2>\n <ol className={styles.list}>\n {ordered.map((career) => (\n <li key={career.id} className={styles.item}>\n <div className={styles.timelineMarker} aria-hidden=\"true\" />\n <div className={styles.content}>\n <p className={styles.role}>\n {career.url ? (\n <a\n className={styles.organizationLink}\n href={career.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {career.role} · {career.organization}\n </a>\n ) : (\n <>\n {career.role} · {career.organization}\n </>\n )}\n </p>\n <p className={styles.range}>\n <time dateTime={career.startDate}>{career.startDate}</time>\n {' – '}\n {isOngoing(career) ? (\n 'Present'\n ) : (\n <time dateTime={career.endDate!}>{career.endDate}</time>\n )}\n </p>\n {career.location?.display ? (\n <p className={styles.location}>{career.location.display}</p>\n ) : null}\n {career.description ? (\n <p className={styles.description}>{career.description}</p>\n ) : null}\n </div>\n </li>\n ))}\n </ol>\n </section>\n );\n}\n","import type { LocalizedCertification } from '@takuhon/core';\n\nimport styles from './Certifications.module.css';\n\nexport interface CertificationsProps {\n certifications: LocalizedCertification[];\n}\n\nfunction sortCerts(certs: LocalizedCertification[]): LocalizedCertification[] {\n return [...certs].sort((a, b) => {\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n if (aOrder !== bOrder) return aOrder - bOrder;\n return b.issueDate.localeCompare(a.issueDate);\n });\n}\n\nexport function Certifications({ certifications }: CertificationsProps): React.JSX.Element | null {\n if (certifications.length === 0) return null;\n const ordered = sortCerts(certifications);\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-certifications-heading\">\n <h2 id=\"takuhon-certifications-heading\" className={styles.heading}>\n Certifications\n </h2>\n <ul className={styles.list}>\n {ordered.map((cert) => (\n <li key={cert.id} className={styles.item}>\n <p className={styles.title}>\n {cert.url ? (\n <a\n className={styles.link}\n href={cert.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {cert.title}\n </a>\n ) : (\n cert.title\n )}\n </p>\n <p className={styles.issuer}>{cert.issuingOrganization}</p>\n <p className={styles.range}>\n <time dateTime={cert.issueDate}>{cert.issueDate}</time>\n {cert.expirationDate === null ? (\n <span className={styles.tag}> · No expiration</span>\n ) : cert.expirationDate !== undefined ? (\n <>\n {' – '}\n <time dateTime={cert.expirationDate}>{cert.expirationDate}</time>\n </>\n ) : null}\n </p>\n {/* credentialId is intentionally not rendered by default — the API\n privacy filter strips it for public responses unless\n meta.privacy.hideCredentialIds is explicitly false. */}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n","import type { Contact } from '@takuhon/core';\n\nimport styles from './ContactInfo.module.css';\n\nexport interface ContactInfoProps {\n contact: Contact;\n}\n\nexport function ContactInfo({ contact }: ContactInfoProps): React.JSX.Element | null {\n const showEmail = contact.showEmail === true && contact.email !== undefined;\n if (!showEmail && contact.formUrl === undefined) return null;\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-contact-heading\">\n <h2 id=\"takuhon-contact-heading\" className={styles.heading}>\n Contact\n </h2>\n <ul className={styles.list}>\n {showEmail && contact.email !== undefined ? (\n <li className={styles.item}>\n <a className={styles.link} href={`mailto:${contact.email}`}>\n {contact.email}\n </a>\n </li>\n ) : null}\n {contact.formUrl !== undefined ? (\n <li className={styles.item}>\n <a\n className={styles.link}\n href={contact.formUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n Contact form\n </a>\n </li>\n ) : null}\n </ul>\n </section>\n );\n}\n","import type { LocalizedEducation } from '@takuhon/core';\n\nimport styles from './EducationTimeline.module.css';\n\nexport interface EducationTimelineProps {\n education: LocalizedEducation[];\n}\n\nfunction sortEducation(entries: LocalizedEducation[]): LocalizedEducation[] {\n return [...entries].sort((a, b) => {\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n if (aOrder !== bOrder) return aOrder - bOrder;\n return b.startDate.localeCompare(a.startDate);\n });\n}\n\nfunction isOngoing(entry: LocalizedEducation): boolean {\n return entry.isCurrent === true || entry.endDate === null || entry.endDate === undefined;\n}\n\nfunction composeStudyLine(entry: LocalizedEducation): string | undefined {\n if (entry.degree !== undefined && entry.fieldOfStudy !== undefined) {\n return `${entry.degree} · ${entry.fieldOfStudy}`;\n }\n return entry.degree ?? entry.fieldOfStudy;\n}\n\nexport function EducationTimeline({ education }: EducationTimelineProps): React.JSX.Element | null {\n if (education.length === 0) return null;\n const ordered = sortEducation(education);\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-education-heading\">\n <h2 id=\"takuhon-education-heading\" className={styles.heading}>\n Education\n </h2>\n <ol className={styles.list}>\n {ordered.map((entry) => {\n const study = composeStudyLine(entry);\n return (\n <li key={entry.id} className={styles.item}>\n <div className={styles.timelineMarker} aria-hidden=\"true\" />\n <div className={styles.content}>\n <p className={styles.institution}>\n {entry.url ? (\n <a\n className={styles.link}\n href={entry.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {entry.institution}\n </a>\n ) : (\n entry.institution\n )}\n </p>\n {study ? <p className={styles.study}>{study}</p> : null}\n <p className={styles.range}>\n <time dateTime={entry.startDate}>{entry.startDate}</time>\n {' – '}\n {isOngoing(entry) ? (\n 'Present'\n ) : (\n <time dateTime={entry.endDate!}>{entry.endDate}</time>\n )}\n </p>\n {entry.grade ? <p className={styles.grade}>{entry.grade}</p> : null}\n {entry.description ? (\n <p className={styles.description}>{entry.description}</p>\n ) : null}\n </div>\n </li>\n );\n })}\n </ol>\n </section>\n );\n}\n","import styles from './Footer.module.css';\n\nexport function Footer(): React.JSX.Element {\n return (\n <footer className={styles.footer}>\n <p className={styles.line}>\n Powered by{' '}\n <a\n className={styles.link}\n href=\"https://github.com/takuhon-dev/takuhon\"\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n takuhon\n </a>\n </p>\n </footer>\n );\n}\n","import type { LocalizedHonor } from '@takuhon/core';\n\nimport styles from './HonorsList.module.css';\n\nexport interface HonorsListProps {\n honors: LocalizedHonor[];\n}\n\nfunction sortHonors(honors: LocalizedHonor[]): LocalizedHonor[] {\n return [...honors].sort((a, b) => {\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n if (aOrder !== bOrder) return aOrder - bOrder;\n return b.date.localeCompare(a.date);\n });\n}\n\nexport function HonorsList({ honors }: HonorsListProps): React.JSX.Element | null {\n if (honors.length === 0) return null;\n const ordered = sortHonors(honors);\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-honors-heading\">\n <h2 id=\"takuhon-honors-heading\" className={styles.heading}>\n Honors &amp; Awards\n </h2>\n <ul className={styles.list}>\n {ordered.map((honor) => (\n <li key={honor.id} className={styles.item}>\n <p className={styles.title}>\n {honor.url ? (\n <a\n className={styles.link}\n href={honor.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {honor.title}\n </a>\n ) : (\n honor.title\n )}\n </p>\n <p className={styles.meta}>\n {honor.issuer}\n {' · '}\n <time dateTime={honor.date}>{honor.date}</time>\n </p>\n {honor.description ? (\n <p className={styles.description}>{honor.description}</p>\n ) : null}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n","import type { LanguageProficiency, LocalizedLanguage } from '@takuhon/core';\n\nimport styles from './Languages.module.css';\n\nexport interface LanguagesProps {\n languages: LocalizedLanguage[];\n}\n\nconst PROFICIENCY_LABEL: Record<LanguageProficiency, string> = {\n native: 'Native',\n fluent: 'Fluent',\n professional: 'Professional working',\n intermediate: 'Intermediate',\n basic: 'Basic',\n};\n\nfunction sortLanguages(languages: LocalizedLanguage[]): LocalizedLanguage[] {\n return [...languages].sort((a, b) => {\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n return aOrder - bOrder;\n });\n}\n\nexport function Languages({ languages }: LanguagesProps): React.JSX.Element | null {\n if (languages.length === 0) return null;\n const ordered = sortLanguages(languages);\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-languages-heading\">\n <h2 id=\"takuhon-languages-heading\" className={styles.heading}>\n Languages\n </h2>\n <ul className={styles.list}>\n {ordered.map((entry) => (\n <li key={entry.id} className={styles.item}>\n <span className={styles.name} lang={entry.language}>\n {entry.displayName ?? entry.language}\n </span>\n <span className={styles.proficiency}>{PROFICIENCY_LABEL[entry.proficiency]}</span>\n </li>\n ))}\n </ul>\n </section>\n );\n}\n","import type { LocalizedLink } from '@takuhon/core';\n\nimport styles from './LinksList.module.css';\n\nexport interface LinksListProps {\n links: LocalizedLink[];\n}\n\nfunction sortLinks(links: LocalizedLink[]): LocalizedLink[] {\n return [...links].sort((a, b) => {\n const aFeatured = a.featured ? 1 : 0;\n const bFeatured = b.featured ? 1 : 0;\n if (aFeatured !== bFeatured) return bFeatured - aFeatured;\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n return aOrder - bOrder;\n });\n}\n\nfunction formatLinkLabel(link: LocalizedLink): string {\n if (link.label) return link.label;\n if (link.type === 'custom') return link.id;\n return link.type;\n}\n\nexport function LinksList({ links }: LinksListProps): React.JSX.Element | null {\n if (links.length === 0) return null;\n\n const ordered = sortLinks(links);\n\n return (\n <nav aria-label=\"Profile links\" className={styles.nav}>\n <ul className={styles.list}>\n {ordered.map((link) => (\n <li key={link.id} className={styles.item}>\n <a\n className={styles.link}\n href={link.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n data-featured={link.featured ? 'true' : undefined}\n >\n {link.iconUrl ? <img className={styles.icon} src={link.iconUrl} alt=\"\" /> : null}\n <span className={styles.label}>{formatLinkLabel(link)}</span>\n </a>\n </li>\n ))}\n </ul>\n </nav>\n );\n}\n","import type { LocalizedProfile } from '@takuhon/core';\n\nimport styles from './ProfileHeader.module.css';\n\nexport interface ProfileHeaderProps {\n profile: LocalizedProfile;\n}\n\nexport function ProfileHeader({ profile }: ProfileHeaderProps): React.JSX.Element {\n const locationLabel = profile.location?.display ?? profile.location?.locality;\n\n return (\n <header className={styles.header}>\n {profile.avatar ? (\n <img\n className={styles.avatar}\n src={profile.avatar.url}\n alt={profile.avatar.alt ?? ''}\n width={128}\n height={128}\n loading=\"eager\"\n decoding=\"async\"\n />\n ) : null}\n <h1 className={styles.displayName}>{profile.displayName}</h1>\n {profile.tagline ? <p className={styles.tagline}>{profile.tagline}</p> : null}\n {locationLabel ? <p className={styles.location}>{locationLabel}</p> : null}\n {profile.bio ? <p className={styles.bio}>{profile.bio}</p> : null}\n </header>\n );\n}\n","import type { LocalizedProject } from '@takuhon/core';\n\nimport styles from './ProjectsList.module.css';\n\nexport interface ProjectsListProps {\n projects: LocalizedProject[];\n}\n\nfunction sortProjects(projects: LocalizedProject[]): LocalizedProject[] {\n return [...projects].sort((a, b) => {\n const aHighlighted = a.highlighted ? 1 : 0;\n const bHighlighted = b.highlighted ? 1 : 0;\n if (aHighlighted !== bHighlighted) return bHighlighted - aHighlighted;\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n return aOrder - bOrder;\n });\n}\n\nexport function ProjectsList({ projects }: ProjectsListProps): React.JSX.Element | null {\n if (projects.length === 0) return null;\n const ordered = sortProjects(projects);\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-projects-heading\">\n <h2 id=\"takuhon-projects-heading\" className={styles.heading}>\n Projects\n </h2>\n <ul className={styles.list}>\n {ordered.map((project) => (\n <li\n key={project.id}\n className={styles.item}\n data-highlighted={project.highlighted ? 'true' : undefined}\n >\n <p className={styles.title}>\n {project.url ? (\n <a\n className={styles.titleLink}\n href={project.url}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n >\n {project.title}\n </a>\n ) : (\n project.title\n )}\n </p>\n {project.startDate !== undefined ? (\n <p className={styles.range}>\n <time dateTime={project.startDate}>{project.startDate}</time>\n {' – '}\n {project.endDate ? (\n <time dateTime={project.endDate}>{project.endDate}</time>\n ) : (\n 'Present'\n )}\n </p>\n ) : null}\n {project.description ? (\n <p className={styles.description}>{project.description}</p>\n ) : null}\n {project.tags && project.tags.length > 0 ? (\n <ul className={styles.tags} aria-label=\"Tags\">\n {project.tags.map((tag) => (\n <li key={tag} className={styles.tag}>\n {tag}\n </li>\n ))}\n </ul>\n ) : null}\n </li>\n ))}\n </ul>\n </section>\n );\n}\n","import type { Skill } from '@takuhon/core';\n\nimport styles from './SkillsList.module.css';\n\nexport interface SkillsListProps {\n skills: Skill[];\n}\n\ninterface SkillGroup {\n category: string;\n skills: Skill[];\n}\n\nfunction groupSkills(skills: Skill[]): SkillGroup[] {\n const sorted = [...skills].sort((a, b) => {\n const aOrder = a.order ?? Number.POSITIVE_INFINITY;\n const bOrder = b.order ?? Number.POSITIVE_INFINITY;\n return aOrder - bOrder;\n });\n const groups = new Map<string, Skill[]>();\n for (const skill of sorted) {\n const key = skill.category ?? 'other';\n const bucket = groups.get(key);\n if (bucket) {\n bucket.push(skill);\n } else {\n groups.set(key, [skill]);\n }\n }\n return [...groups.entries()].map(([category, items]) => ({ category, skills: items }));\n}\n\nexport function SkillsList({ skills }: SkillsListProps): React.JSX.Element | null {\n if (skills.length === 0) return null;\n const groups = groupSkills(skills);\n\n return (\n <section className={styles.section} aria-labelledby=\"takuhon-skills-heading\">\n <h2 id=\"takuhon-skills-heading\" className={styles.heading}>\n Skills\n </h2>\n <div className={styles.groups}>\n {groups.map((group) => (\n <div key={group.category} className={styles.group}>\n <h3 className={styles.category}>{group.category}</h3>\n <ul className={styles.list} aria-label={`${group.category} skills`}>\n {group.skills.map((skill) => (\n <li key={skill.id} className={styles.item}>\n {skill.label}\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n </section>\n );\n}\n","import type { LocaleTag } from '@takuhon/core';\n\nimport styles from './LocaleSwitcher.module.css';\n\nexport interface LocaleSwitcherProps {\n availableLocales: LocaleTag[];\n currentLocale: LocaleTag;\n onSelect: (locale: LocaleTag) => void;\n ariaLabel?: string;\n formatLocale?: (locale: LocaleTag) => string;\n}\n\nconst DEFAULT_ARIA_LABEL = 'Select language';\n\nexport function LocaleSwitcher({\n availableLocales,\n currentLocale,\n onSelect,\n ariaLabel,\n formatLocale,\n}: LocaleSwitcherProps): React.JSX.Element {\n const label = ariaLabel ?? DEFAULT_ARIA_LABEL;\n const format = formatLocale ?? ((locale: LocaleTag) => locale);\n return (\n <div className={styles.wrapper}>\n <select\n className={styles.select}\n aria-label={label}\n value={currentLocale}\n onChange={(event) => {\n onSelect(event.target.value);\n }}\n >\n {availableLocales.map((locale) => (\n <option key={locale} value={locale}>\n {format(locale)}\n </option>\n ))}\n </select>\n </div>\n );\n}\n","import { generateJsonLd, type LocalizedTakuhon } from '@takuhon/core';\nimport { useEffect } from 'react';\n\nexport interface TakuhonHeadProps {\n data: LocalizedTakuhon;\n siteUrl?: string;\n pageUrl?: string;\n}\n\nfunction buildLocaleUrl(pageUrl: string, locale: string): string {\n try {\n const url = new URL(pageUrl);\n url.searchParams.set('lang', locale);\n return url.toString();\n } catch {\n return pageUrl;\n }\n}\n\nfunction stripLangParam(pageUrl: string): string {\n try {\n const url = new URL(pageUrl);\n url.searchParams.delete('lang');\n return url.toString();\n } catch {\n return pageUrl;\n }\n}\n\nfunction absolutizeUrl(url: string | undefined, base: string | undefined): string | undefined {\n if (!url) return undefined;\n if (!base) return url;\n try {\n return new URL(url, base).toString();\n } catch {\n return url;\n }\n}\n\nfunction detectSiteUrl(explicit: string | undefined): string | undefined {\n if (explicit) return explicit;\n if (typeof window !== 'undefined') return window.location.origin;\n return undefined;\n}\n\nfunction detectPageUrl(\n explicit: string | undefined,\n siteUrl: string | undefined,\n): string | undefined {\n if (explicit) return stripLangParam(explicit);\n if (typeof window !== 'undefined') {\n return window.location.origin + window.location.pathname;\n }\n return siteUrl;\n}\n\nexport function TakuhonHead({ data, siteUrl, pageUrl }: TakuhonHeadProps): React.JSX.Element {\n const resolvedSiteUrl = detectSiteUrl(siteUrl);\n const resolvedPageUrl = detectPageUrl(pageUrl, resolvedSiteUrl);\n\n const { profile, settings, resolvedLocale } = data;\n const description = profile.bio ?? profile.tagline;\n const ogDescription = profile.tagline ?? profile.bio;\n const ogImage = absolutizeUrl(profile.avatar?.url, resolvedSiteUrl);\n const twitterCard = profile.avatar ? 'summary_large_image' : 'summary';\n\n const canonical = resolvedPageUrl ? buildLocaleUrl(resolvedPageUrl, resolvedLocale) : undefined;\n const alternates = resolvedPageUrl\n ? settings.availableLocales.map((loc) => ({\n locale: loc,\n href: buildLocaleUrl(resolvedPageUrl, loc),\n }))\n : [];\n const xDefaultHref = resolvedPageUrl\n ? buildLocaleUrl(resolvedPageUrl, settings.defaultLocale)\n : undefined;\n\n const ogAlternates = settings.availableLocales.filter((loc) => loc !== resolvedLocale);\n\n const emitJsonLd = settings.enableJsonLd !== false;\n const jsonLdPayload = emitJsonLd ? JSON.stringify(generateJsonLd(data)) : null;\n\n useEffect(() => {\n if (!jsonLdPayload) return;\n const script = document.createElement('script');\n script.type = 'application/ld+json';\n script.textContent = jsonLdPayload;\n document.head.appendChild(script);\n return () => {\n script.remove();\n };\n }, [jsonLdPayload]);\n\n return (\n <>\n <title>{profile.displayName}</title>\n {description ? <meta name=\"description\" content={description} /> : null}\n {canonical ? <link rel=\"canonical\" href={canonical} /> : null}\n\n <meta property=\"og:title\" content={profile.displayName} />\n {ogDescription ? <meta property=\"og:description\" content={ogDescription} /> : null}\n {canonical ? <meta property=\"og:url\" content={canonical} /> : null}\n {ogImage ? <meta property=\"og:image\" content={ogImage} /> : null}\n <meta property=\"og:type\" content=\"profile\" />\n <meta property=\"og:locale\" content={resolvedLocale} />\n {ogAlternates.map((loc) => (\n <meta key={loc} property=\"og:locale:alternate\" content={loc} />\n ))}\n\n <meta name=\"twitter:card\" content={twitterCard} />\n\n {alternates.map(({ locale, href }) => (\n <link key={locale} rel=\"alternate\" hrefLang={locale} href={href} />\n ))}\n {xDefaultHref ? <link rel=\"alternate\" hrefLang=\"x-default\" href={xDefaultHref} /> : null}\n </>\n );\n}\n"],"mappings":"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","names":["styles","Fragment","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","isOngoing","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","jsxs","styles","jsx","Fragment","jsx","jsxs"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takuhon/ui",
3
- "version": "0.1.1",
3
+ "version": "0.2.0",
4
4
  "description": "React mobile-first profile UI and minimal admin editor components for takuhon",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Takuhon contributors",
@@ -42,7 +42,7 @@
42
42
  "node": ">=22.0.0"
43
43
  },
44
44
  "dependencies": {
45
- "@takuhon/core": "0.1.1"
45
+ "@takuhon/core": "0.2.0"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "react": ">=19",