@prosophia/personal-cv 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js ADDED
@@ -0,0 +1,383 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ About: () => About,
34
+ CVSection: () => CVSection,
35
+ Footer: () => Footer,
36
+ Header: () => Header,
37
+ Projects: () => Projects,
38
+ Publications: () => Publications
39
+ });
40
+ module.exports = __toCommonJS(index_exports);
41
+
42
+ // src/components/About.tsx
43
+ var import_About = __toESM(require("@/styles/About.module.css"));
44
+ var import_jsx_runtime = require("react/jsx-runtime");
45
+ var socialIcons = {
46
+ scholar: "school",
47
+ linkedin: "group",
48
+ twitter: "chat",
49
+ github: "code",
50
+ orcid: "fingerprint",
51
+ researchgate: "science"
52
+ };
53
+ var socialLabels = {
54
+ scholar: "Google Scholar",
55
+ linkedin: "LinkedIn",
56
+ twitter: "Twitter",
57
+ github: "GitHub",
58
+ orcid: "ORCID",
59
+ researchgate: "ResearchGate"
60
+ };
61
+ function About({
62
+ greeting,
63
+ title,
64
+ bio,
65
+ profileImageUrl,
66
+ socialLinks = []
67
+ }) {
68
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("section", { className: import_About.default.about, id: "about", children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: import_About.default.card, children: [
69
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: import_About.default.imageWrapper, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
70
+ "div",
71
+ {
72
+ className: import_About.default.profileImage,
73
+ style: {
74
+ backgroundImage: profileImageUrl ? `url("${profileImageUrl}")` : void 0,
75
+ backgroundColor: profileImageUrl ? void 0 : "#e5e7eb"
76
+ },
77
+ role: "img",
78
+ "aria-label": "Profile photo"
79
+ }
80
+ ) }),
81
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: import_About.default.content, children: [
82
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
83
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", { className: import_About.default.greeting, children: greeting }),
84
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: import_About.default.title, children: title }),
85
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: import_About.default.bio, children: bio })
86
+ ] }),
87
+ socialLinks.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: import_About.default.socialLinks, children: socialLinks.map((link) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
88
+ "a",
89
+ {
90
+ href: link.url,
91
+ target: "_blank",
92
+ rel: "noopener noreferrer",
93
+ className: import_About.default.socialLink,
94
+ "aria-label": socialLabels[link.platform] || link.platform,
95
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "material-symbols-outlined", children: socialIcons[link.platform] || "link" })
96
+ },
97
+ link.platform
98
+ )) })
99
+ ] })
100
+ ] }) });
101
+ }
102
+
103
+ // src/components/CVSection.tsx
104
+ var import_CVSection = __toESM(require("@/styles/CVSection.module.css"));
105
+ var import_jsx_runtime2 = require("react/jsx-runtime");
106
+ function CVSection({
107
+ heading,
108
+ description,
109
+ buttonText,
110
+ cvFileUrl
111
+ }) {
112
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("section", { className: import_CVSection.default.cv, id: "cv", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: import_CVSection.default.card, children: [
113
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: import_CVSection.default.content, children: [
114
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: import_CVSection.default.iconWrapper, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "material-symbols-outlined", children: "history_edu" }) }),
115
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: import_CVSection.default.textContent, children: [
116
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { className: import_CVSection.default.title, children: heading }),
117
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: import_CVSection.default.description, children: description })
118
+ ] }),
119
+ cvFileUrl ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
120
+ "a",
121
+ {
122
+ href: cvFileUrl,
123
+ target: "_blank",
124
+ rel: "noopener noreferrer",
125
+ className: import_CVSection.default.downloadBtn,
126
+ children: [
127
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "material-symbols-outlined", children: "download" }),
128
+ buttonText
129
+ ]
130
+ }
131
+ ) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { className: import_CVSection.default.downloadBtn, disabled: true, children: [
132
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "material-symbols-outlined", children: "download" }),
133
+ buttonText
134
+ ] })
135
+ ] }),
136
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: import_CVSection.default.background })
137
+ ] }) });
138
+ }
139
+
140
+ // src/components/Footer.tsx
141
+ var import_Footer = __toESM(require("@/styles/Footer.module.css"));
142
+ var import_jsx_runtime3 = require("react/jsx-runtime");
143
+ function Footer({ footerText, email }) {
144
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("footer", { className: import_Footer.default.footer, children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: import_Footer.default.content, children: [
145
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: import_Footer.default.copyright, children: footerText }),
146
+ email && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: import_Footer.default.emailWrapper, children: [
147
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "material-symbols-outlined", children: "mail" }),
148
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("a", { href: `mailto:${email}`, className: import_Footer.default.email, children: email })
149
+ ] })
150
+ ] }) });
151
+ }
152
+
153
+ // src/components/Header.tsx
154
+ var import_react = require("react");
155
+ var import_link = __toESM(require("next/link"));
156
+ var import_Header = __toESM(require("@/styles/Header.module.css"));
157
+ var import_ThemeContext = require("@/context/ThemeContext");
158
+ var import_jsx_runtime4 = require("react/jsx-runtime");
159
+ function Header({
160
+ siteName,
161
+ navLinks,
162
+ showContactButton = true,
163
+ contactButtonText = "Contact",
164
+ contactEmail = ""
165
+ }) {
166
+ const [mobileMenuOpen, setMobileMenuOpen] = (0, import_react.useState)(false);
167
+ const { theme, toggleTheme, mounted } = (0, import_ThemeContext.useTheme)();
168
+ const toggleMobileMenu = () => {
169
+ setMobileMenuOpen(!mobileMenuOpen);
170
+ };
171
+ const closeMobileMenu = () => {
172
+ setMobileMenuOpen(false);
173
+ };
174
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
175
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("header", { className: import_Header.default.header, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: import_Header.default.headerInner, children: [
176
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_link.default, { href: "/", className: import_Header.default.logo, children: [
177
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: import_Header.default.logoIcon, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "material-symbols-outlined", children: "hexagon" }) }),
178
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: import_Header.default.siteName, children: siteName })
179
+ ] }),
180
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: import_Header.default.desktopNav, children: [
181
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("nav", { className: import_Header.default.navLinks, children: navLinks.map((link) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
182
+ import_link.default,
183
+ {
184
+ href: link.href,
185
+ className: import_Header.default.navLink,
186
+ children: link.label
187
+ },
188
+ link.href
189
+ )) }),
190
+ mounted && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
191
+ "button",
192
+ {
193
+ className: import_Header.default.themeToggle,
194
+ onClick: toggleTheme,
195
+ "aria-label": `Switch to ${theme === "light" ? "dark" : "light"} mode`,
196
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "material-symbols-outlined", children: theme === "light" ? "dark_mode" : "light_mode" })
197
+ }
198
+ ),
199
+ showContactButton && contactEmail && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
200
+ "a",
201
+ {
202
+ href: `mailto:${contactEmail}`,
203
+ className: import_Header.default.contactBtn,
204
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: contactButtonText })
205
+ }
206
+ )
207
+ ] }),
208
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: import_Header.default.mobileActions, children: [
209
+ mounted && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
210
+ "button",
211
+ {
212
+ className: import_Header.default.mobileThemeToggle,
213
+ onClick: toggleTheme,
214
+ "aria-label": `Switch to ${theme === "light" ? "dark" : "light"} mode`,
215
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "material-symbols-outlined", children: theme === "light" ? "dark_mode" : "light_mode" })
216
+ }
217
+ ),
218
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
219
+ "button",
220
+ {
221
+ className: import_Header.default.mobileMenuBtn,
222
+ onClick: toggleMobileMenu,
223
+ "aria-label": "Toggle menu",
224
+ children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "material-symbols-outlined", children: mobileMenuOpen ? "close" : "menu" })
225
+ }
226
+ )
227
+ ] })
228
+ ] }) }),
229
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `${import_Header.default.mobileMenu} ${mobileMenuOpen ? import_Header.default.open : ""}`, children: [
230
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("nav", { className: import_Header.default.mobileNavLinks, children: navLinks.map((link) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
231
+ import_link.default,
232
+ {
233
+ href: link.href,
234
+ className: import_Header.default.mobileNavLink,
235
+ onClick: closeMobileMenu,
236
+ children: link.label
237
+ },
238
+ link.href
239
+ )) }),
240
+ showContactButton && contactEmail && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
241
+ "a",
242
+ {
243
+ href: `mailto:${contactEmail}`,
244
+ className: import_Header.default.mobileContactBtn,
245
+ children: contactButtonText
246
+ }
247
+ )
248
+ ] })
249
+ ] });
250
+ }
251
+
252
+ // src/components/Projects.tsx
253
+ var import_link2 = __toESM(require("next/link"));
254
+ var import_Projects = __toESM(require("@/styles/Projects.module.css"));
255
+ var import_jsx_runtime5 = require("react/jsx-runtime");
256
+ function Projects({
257
+ projects,
258
+ showViewAll = true,
259
+ viewAllUrl = "#"
260
+ }) {
261
+ return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { className: import_Projects.default.projects, id: "projects", children: [
262
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: import_Projects.default.header, children: [
263
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h2", { className: import_Projects.default.title, children: "Selected Projects" }),
264
+ showViewAll && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(import_link2.default, { href: viewAllUrl, className: import_Projects.default.viewAllLink, children: "View all projects" })
265
+ ] }),
266
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: import_Projects.default.grid, children: projects.map((project) => {
267
+ const projectUrl = project.slug?.current ? `/projects/${project.slug.current}` : project.caseStudyUrl;
268
+ const CardContent = /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
269
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: import_Projects.default.imageWrapper, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
270
+ "div",
271
+ {
272
+ className: import_Projects.default.image,
273
+ style: {
274
+ backgroundImage: project.imageUrl ? `url("${project.imageUrl}")` : void 0,
275
+ backgroundColor: project.imageUrl ? void 0 : "#e5e7eb"
276
+ },
277
+ role: "img",
278
+ "aria-label": project.imageAlt || project.title
279
+ }
280
+ ) }),
281
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: import_Projects.default.content, children: [
282
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("h3", { className: import_Projects.default.projectTitle, children: project.title }),
283
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("p", { className: import_Projects.default.description, children: project.description }),
284
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("span", { className: import_Projects.default.caseStudyLink, children: [
285
+ "View Project",
286
+ " ",
287
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "material-symbols-outlined", children: "arrow_forward" })
288
+ ] })
289
+ ] })
290
+ ] });
291
+ return project.slug?.current ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
292
+ import_link2.default,
293
+ {
294
+ href: projectUrl,
295
+ className: import_Projects.default.card,
296
+ children: CardContent
297
+ },
298
+ project._id
299
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { className: import_Projects.default.card, children: CardContent }, project._id);
300
+ }) })
301
+ ] });
302
+ }
303
+
304
+ // src/components/Publications.tsx
305
+ var import_Publications = __toESM(require("@/styles/Publications.module.css"));
306
+ var import_jsx_runtime6 = require("react/jsx-runtime");
307
+ function Publications({ publications }) {
308
+ return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { className: import_Publications.default.publications, id: "publications", children: [
309
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: import_Publications.default.header, children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h2", { className: import_Publications.default.title, children: "Recent Publications" }) }),
310
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { className: import_Publications.default.list, children: publications.map((pub) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: import_Publications.default.item, children: [
311
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: import_Publications.default.itemHeader, children: [
312
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("h3", { className: import_Publications.default.pubTitle, children: pub.title }),
313
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: import_Publications.default.year, children: pub.year })
314
+ ] }),
315
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: import_Publications.default.authors, children: pub.authors }),
316
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: import_Publications.default.venue, children: pub.venue }),
317
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: import_Publications.default.links, children: [
318
+ pub.pdfUrl && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
319
+ "a",
320
+ {
321
+ href: pub.pdfUrl,
322
+ target: "_blank",
323
+ rel: "noopener noreferrer",
324
+ className: import_Publications.default.linkBtn,
325
+ children: [
326
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "material-symbols-outlined", children: "description" }),
327
+ "PDF"
328
+ ]
329
+ }
330
+ ),
331
+ pub.codeUrl && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
332
+ "a",
333
+ {
334
+ href: pub.codeUrl,
335
+ target: "_blank",
336
+ rel: "noopener noreferrer",
337
+ className: import_Publications.default.linkBtn,
338
+ children: [
339
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "material-symbols-outlined", children: "code" }),
340
+ "Code"
341
+ ]
342
+ }
343
+ ),
344
+ pub.videoUrl && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
345
+ "a",
346
+ {
347
+ href: pub.videoUrl,
348
+ target: "_blank",
349
+ rel: "noopener noreferrer",
350
+ className: import_Publications.default.linkBtn,
351
+ children: [
352
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "material-symbols-outlined", children: "videocam" }),
353
+ "Video"
354
+ ]
355
+ }
356
+ ),
357
+ pub.bibtex && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
358
+ "button",
359
+ {
360
+ onClick: () => {
361
+ navigator.clipboard.writeText(pub.bibtex || "");
362
+ alert("BibTeX copied to clipboard!");
363
+ },
364
+ className: import_Publications.default.linkBtn,
365
+ children: [
366
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "material-symbols-outlined", children: "format_quote" }),
367
+ "BibTeX"
368
+ ]
369
+ }
370
+ )
371
+ ] })
372
+ ] }, pub._id)) })
373
+ ] });
374
+ }
375
+ // Annotate the CommonJS export names for ESM import in node:
376
+ 0 && (module.exports = {
377
+ About,
378
+ CVSection,
379
+ Footer,
380
+ Header,
381
+ Projects,
382
+ Publications
383
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,341 @@
1
+ // src/components/About.tsx
2
+ import styles from "@/styles/About.module.css";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ var socialIcons = {
5
+ scholar: "school",
6
+ linkedin: "group",
7
+ twitter: "chat",
8
+ github: "code",
9
+ orcid: "fingerprint",
10
+ researchgate: "science"
11
+ };
12
+ var socialLabels = {
13
+ scholar: "Google Scholar",
14
+ linkedin: "LinkedIn",
15
+ twitter: "Twitter",
16
+ github: "GitHub",
17
+ orcid: "ORCID",
18
+ researchgate: "ResearchGate"
19
+ };
20
+ function About({
21
+ greeting,
22
+ title,
23
+ bio,
24
+ profileImageUrl,
25
+ socialLinks = []
26
+ }) {
27
+ return /* @__PURE__ */ jsx("section", { className: styles.about, id: "about", children: /* @__PURE__ */ jsxs("div", { className: styles.card, children: [
28
+ /* @__PURE__ */ jsx("div", { className: styles.imageWrapper, children: /* @__PURE__ */ jsx(
29
+ "div",
30
+ {
31
+ className: styles.profileImage,
32
+ style: {
33
+ backgroundImage: profileImageUrl ? `url("${profileImageUrl}")` : void 0,
34
+ backgroundColor: profileImageUrl ? void 0 : "#e5e7eb"
35
+ },
36
+ role: "img",
37
+ "aria-label": "Profile photo"
38
+ }
39
+ ) }),
40
+ /* @__PURE__ */ jsxs("div", { className: styles.content, children: [
41
+ /* @__PURE__ */ jsxs("div", { children: [
42
+ /* @__PURE__ */ jsx("h1", { className: styles.greeting, children: greeting }),
43
+ /* @__PURE__ */ jsx("p", { className: styles.title, children: title }),
44
+ /* @__PURE__ */ jsx("p", { className: styles.bio, children: bio })
45
+ ] }),
46
+ socialLinks.length > 0 && /* @__PURE__ */ jsx("div", { className: styles.socialLinks, children: socialLinks.map((link) => /* @__PURE__ */ jsx(
47
+ "a",
48
+ {
49
+ href: link.url,
50
+ target: "_blank",
51
+ rel: "noopener noreferrer",
52
+ className: styles.socialLink,
53
+ "aria-label": socialLabels[link.platform] || link.platform,
54
+ children: /* @__PURE__ */ jsx("span", { className: "material-symbols-outlined", children: socialIcons[link.platform] || "link" })
55
+ },
56
+ link.platform
57
+ )) })
58
+ ] })
59
+ ] }) });
60
+ }
61
+
62
+ // src/components/CVSection.tsx
63
+ import styles2 from "@/styles/CVSection.module.css";
64
+ import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
65
+ function CVSection({
66
+ heading,
67
+ description,
68
+ buttonText,
69
+ cvFileUrl
70
+ }) {
71
+ return /* @__PURE__ */ jsx2("section", { className: styles2.cv, id: "cv", children: /* @__PURE__ */ jsxs2("div", { className: styles2.card, children: [
72
+ /* @__PURE__ */ jsxs2("div", { className: styles2.content, children: [
73
+ /* @__PURE__ */ jsx2("span", { className: styles2.iconWrapper, children: /* @__PURE__ */ jsx2("span", { className: "material-symbols-outlined", children: "history_edu" }) }),
74
+ /* @__PURE__ */ jsxs2("div", { className: styles2.textContent, children: [
75
+ /* @__PURE__ */ jsx2("h2", { className: styles2.title, children: heading }),
76
+ /* @__PURE__ */ jsx2("p", { className: styles2.description, children: description })
77
+ ] }),
78
+ cvFileUrl ? /* @__PURE__ */ jsxs2(
79
+ "a",
80
+ {
81
+ href: cvFileUrl,
82
+ target: "_blank",
83
+ rel: "noopener noreferrer",
84
+ className: styles2.downloadBtn,
85
+ children: [
86
+ /* @__PURE__ */ jsx2("span", { className: "material-symbols-outlined", children: "download" }),
87
+ buttonText
88
+ ]
89
+ }
90
+ ) : /* @__PURE__ */ jsxs2("button", { className: styles2.downloadBtn, disabled: true, children: [
91
+ /* @__PURE__ */ jsx2("span", { className: "material-symbols-outlined", children: "download" }),
92
+ buttonText
93
+ ] })
94
+ ] }),
95
+ /* @__PURE__ */ jsx2("div", { className: styles2.background })
96
+ ] }) });
97
+ }
98
+
99
+ // src/components/Footer.tsx
100
+ import styles3 from "@/styles/Footer.module.css";
101
+ import { jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
102
+ function Footer({ footerText, email }) {
103
+ return /* @__PURE__ */ jsx3("footer", { className: styles3.footer, children: /* @__PURE__ */ jsxs3("div", { className: styles3.content, children: [
104
+ /* @__PURE__ */ jsx3("p", { className: styles3.copyright, children: footerText }),
105
+ email && /* @__PURE__ */ jsxs3("div", { className: styles3.emailWrapper, children: [
106
+ /* @__PURE__ */ jsx3("span", { className: "material-symbols-outlined", children: "mail" }),
107
+ /* @__PURE__ */ jsx3("a", { href: `mailto:${email}`, className: styles3.email, children: email })
108
+ ] })
109
+ ] }) });
110
+ }
111
+
112
+ // src/components/Header.tsx
113
+ import { useState } from "react";
114
+ import Link from "next/link";
115
+ import styles4 from "@/styles/Header.module.css";
116
+ import { useTheme } from "@/context/ThemeContext";
117
+ import { Fragment, jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
118
+ function Header({
119
+ siteName,
120
+ navLinks,
121
+ showContactButton = true,
122
+ contactButtonText = "Contact",
123
+ contactEmail = ""
124
+ }) {
125
+ const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
126
+ const { theme, toggleTheme, mounted } = useTheme();
127
+ const toggleMobileMenu = () => {
128
+ setMobileMenuOpen(!mobileMenuOpen);
129
+ };
130
+ const closeMobileMenu = () => {
131
+ setMobileMenuOpen(false);
132
+ };
133
+ return /* @__PURE__ */ jsxs4(Fragment, { children: [
134
+ /* @__PURE__ */ jsx4("header", { className: styles4.header, children: /* @__PURE__ */ jsxs4("div", { className: styles4.headerInner, children: [
135
+ /* @__PURE__ */ jsxs4(Link, { href: "/", className: styles4.logo, children: [
136
+ /* @__PURE__ */ jsx4("div", { className: styles4.logoIcon, children: /* @__PURE__ */ jsx4("span", { className: "material-symbols-outlined", children: "hexagon" }) }),
137
+ /* @__PURE__ */ jsx4("h2", { className: styles4.siteName, children: siteName })
138
+ ] }),
139
+ /* @__PURE__ */ jsxs4("div", { className: styles4.desktopNav, children: [
140
+ /* @__PURE__ */ jsx4("nav", { className: styles4.navLinks, children: navLinks.map((link) => /* @__PURE__ */ jsx4(
141
+ Link,
142
+ {
143
+ href: link.href,
144
+ className: styles4.navLink,
145
+ children: link.label
146
+ },
147
+ link.href
148
+ )) }),
149
+ mounted && /* @__PURE__ */ jsx4(
150
+ "button",
151
+ {
152
+ className: styles4.themeToggle,
153
+ onClick: toggleTheme,
154
+ "aria-label": `Switch to ${theme === "light" ? "dark" : "light"} mode`,
155
+ children: /* @__PURE__ */ jsx4("span", { className: "material-symbols-outlined", children: theme === "light" ? "dark_mode" : "light_mode" })
156
+ }
157
+ ),
158
+ showContactButton && contactEmail && /* @__PURE__ */ jsx4(
159
+ "a",
160
+ {
161
+ href: `mailto:${contactEmail}`,
162
+ className: styles4.contactBtn,
163
+ children: /* @__PURE__ */ jsx4("span", { children: contactButtonText })
164
+ }
165
+ )
166
+ ] }),
167
+ /* @__PURE__ */ jsxs4("div", { className: styles4.mobileActions, children: [
168
+ mounted && /* @__PURE__ */ jsx4(
169
+ "button",
170
+ {
171
+ className: styles4.mobileThemeToggle,
172
+ onClick: toggleTheme,
173
+ "aria-label": `Switch to ${theme === "light" ? "dark" : "light"} mode`,
174
+ children: /* @__PURE__ */ jsx4("span", { className: "material-symbols-outlined", children: theme === "light" ? "dark_mode" : "light_mode" })
175
+ }
176
+ ),
177
+ /* @__PURE__ */ jsx4(
178
+ "button",
179
+ {
180
+ className: styles4.mobileMenuBtn,
181
+ onClick: toggleMobileMenu,
182
+ "aria-label": "Toggle menu",
183
+ children: /* @__PURE__ */ jsx4("span", { className: "material-symbols-outlined", children: mobileMenuOpen ? "close" : "menu" })
184
+ }
185
+ )
186
+ ] })
187
+ ] }) }),
188
+ /* @__PURE__ */ jsxs4("div", { className: `${styles4.mobileMenu} ${mobileMenuOpen ? styles4.open : ""}`, children: [
189
+ /* @__PURE__ */ jsx4("nav", { className: styles4.mobileNavLinks, children: navLinks.map((link) => /* @__PURE__ */ jsx4(
190
+ Link,
191
+ {
192
+ href: link.href,
193
+ className: styles4.mobileNavLink,
194
+ onClick: closeMobileMenu,
195
+ children: link.label
196
+ },
197
+ link.href
198
+ )) }),
199
+ showContactButton && contactEmail && /* @__PURE__ */ jsx4(
200
+ "a",
201
+ {
202
+ href: `mailto:${contactEmail}`,
203
+ className: styles4.mobileContactBtn,
204
+ children: contactButtonText
205
+ }
206
+ )
207
+ ] })
208
+ ] });
209
+ }
210
+
211
+ // src/components/Projects.tsx
212
+ import Link2 from "next/link";
213
+ import styles5 from "@/styles/Projects.module.css";
214
+ import { Fragment as Fragment2, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
215
+ function Projects({
216
+ projects,
217
+ showViewAll = true,
218
+ viewAllUrl = "#"
219
+ }) {
220
+ return /* @__PURE__ */ jsxs5("section", { className: styles5.projects, id: "projects", children: [
221
+ /* @__PURE__ */ jsxs5("div", { className: styles5.header, children: [
222
+ /* @__PURE__ */ jsx5("h2", { className: styles5.title, children: "Selected Projects" }),
223
+ showViewAll && /* @__PURE__ */ jsx5(Link2, { href: viewAllUrl, className: styles5.viewAllLink, children: "View all projects" })
224
+ ] }),
225
+ /* @__PURE__ */ jsx5("div", { className: styles5.grid, children: projects.map((project) => {
226
+ const projectUrl = project.slug?.current ? `/projects/${project.slug.current}` : project.caseStudyUrl;
227
+ const CardContent = /* @__PURE__ */ jsxs5(Fragment2, { children: [
228
+ /* @__PURE__ */ jsx5("div", { className: styles5.imageWrapper, children: /* @__PURE__ */ jsx5(
229
+ "div",
230
+ {
231
+ className: styles5.image,
232
+ style: {
233
+ backgroundImage: project.imageUrl ? `url("${project.imageUrl}")` : void 0,
234
+ backgroundColor: project.imageUrl ? void 0 : "#e5e7eb"
235
+ },
236
+ role: "img",
237
+ "aria-label": project.imageAlt || project.title
238
+ }
239
+ ) }),
240
+ /* @__PURE__ */ jsxs5("div", { className: styles5.content, children: [
241
+ /* @__PURE__ */ jsx5("h3", { className: styles5.projectTitle, children: project.title }),
242
+ /* @__PURE__ */ jsx5("p", { className: styles5.description, children: project.description }),
243
+ /* @__PURE__ */ jsxs5("span", { className: styles5.caseStudyLink, children: [
244
+ "View Project",
245
+ " ",
246
+ /* @__PURE__ */ jsx5("span", { className: "material-symbols-outlined", children: "arrow_forward" })
247
+ ] })
248
+ ] })
249
+ ] });
250
+ return project.slug?.current ? /* @__PURE__ */ jsx5(
251
+ Link2,
252
+ {
253
+ href: projectUrl,
254
+ className: styles5.card,
255
+ children: CardContent
256
+ },
257
+ project._id
258
+ ) : /* @__PURE__ */ jsx5("div", { className: styles5.card, children: CardContent }, project._id);
259
+ }) })
260
+ ] });
261
+ }
262
+
263
+ // src/components/Publications.tsx
264
+ import styles6 from "@/styles/Publications.module.css";
265
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
266
+ function Publications({ publications }) {
267
+ return /* @__PURE__ */ jsxs6("section", { className: styles6.publications, id: "publications", children: [
268
+ /* @__PURE__ */ jsx6("div", { className: styles6.header, children: /* @__PURE__ */ jsx6("h2", { className: styles6.title, children: "Recent Publications" }) }),
269
+ /* @__PURE__ */ jsx6("div", { className: styles6.list, children: publications.map((pub) => /* @__PURE__ */ jsxs6("div", { className: styles6.item, children: [
270
+ /* @__PURE__ */ jsxs6("div", { className: styles6.itemHeader, children: [
271
+ /* @__PURE__ */ jsx6("h3", { className: styles6.pubTitle, children: pub.title }),
272
+ /* @__PURE__ */ jsx6("span", { className: styles6.year, children: pub.year })
273
+ ] }),
274
+ /* @__PURE__ */ jsx6("p", { className: styles6.authors, children: pub.authors }),
275
+ /* @__PURE__ */ jsx6("p", { className: styles6.venue, children: pub.venue }),
276
+ /* @__PURE__ */ jsxs6("div", { className: styles6.links, children: [
277
+ pub.pdfUrl && /* @__PURE__ */ jsxs6(
278
+ "a",
279
+ {
280
+ href: pub.pdfUrl,
281
+ target: "_blank",
282
+ rel: "noopener noreferrer",
283
+ className: styles6.linkBtn,
284
+ children: [
285
+ /* @__PURE__ */ jsx6("span", { className: "material-symbols-outlined", children: "description" }),
286
+ "PDF"
287
+ ]
288
+ }
289
+ ),
290
+ pub.codeUrl && /* @__PURE__ */ jsxs6(
291
+ "a",
292
+ {
293
+ href: pub.codeUrl,
294
+ target: "_blank",
295
+ rel: "noopener noreferrer",
296
+ className: styles6.linkBtn,
297
+ children: [
298
+ /* @__PURE__ */ jsx6("span", { className: "material-symbols-outlined", children: "code" }),
299
+ "Code"
300
+ ]
301
+ }
302
+ ),
303
+ pub.videoUrl && /* @__PURE__ */ jsxs6(
304
+ "a",
305
+ {
306
+ href: pub.videoUrl,
307
+ target: "_blank",
308
+ rel: "noopener noreferrer",
309
+ className: styles6.linkBtn,
310
+ children: [
311
+ /* @__PURE__ */ jsx6("span", { className: "material-symbols-outlined", children: "videocam" }),
312
+ "Video"
313
+ ]
314
+ }
315
+ ),
316
+ pub.bibtex && /* @__PURE__ */ jsxs6(
317
+ "button",
318
+ {
319
+ onClick: () => {
320
+ navigator.clipboard.writeText(pub.bibtex || "");
321
+ alert("BibTeX copied to clipboard!");
322
+ },
323
+ className: styles6.linkBtn,
324
+ children: [
325
+ /* @__PURE__ */ jsx6("span", { className: "material-symbols-outlined", children: "format_quote" }),
326
+ "BibTeX"
327
+ ]
328
+ }
329
+ )
330
+ ] })
331
+ ] }, pub._id)) })
332
+ ] });
333
+ }
334
+ export {
335
+ About,
336
+ CVSection,
337
+ Footer,
338
+ Header,
339
+ Projects,
340
+ Publications
341
+ };
package/package.json ADDED
@@ -0,0 +1,44 @@
1
+ {
2
+ "name": "@prosophia/personal-cv",
3
+ "version": "0.0.1",
4
+ "description": "Personal academic CV template for Prosophia",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.mjs",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.mjs",
11
+ "require": "./dist/index.js",
12
+ "types": "./dist/index.d.ts"
13
+ },
14
+ "./styles": "./dist/styles/index.css"
15
+ },
16
+ "files": [
17
+ "dist"
18
+ ],
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "dev": "tsup --watch",
22
+ "lint": "eslint src/"
23
+ },
24
+ "peerDependencies": {
25
+ "next": "^14.0.0",
26
+ "react": "^18.0.0",
27
+ "react-dom": "^18.0.0"
28
+ },
29
+ "devDependencies": {
30
+ "@types/react": "^18.0.0",
31
+ "@types/react-dom": "^18.0.0",
32
+ "tsup": "^8.0.0",
33
+ "typescript": "^5.0.0"
34
+ },
35
+ "publishConfig": {
36
+ "access": "public"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/prosophia/prosophia-templates.git",
41
+ "directory": "packages/personal-cv"
42
+ },
43
+ "license": "MIT"
44
+ }