2023-12-23 18:21:12 +01:00
|
|
|
import { Page, Text, View, Document } from "@react-pdf/renderer";
|
2023-11-13 12:33:50 +01:00
|
|
|
import ReactPDF from "@react-pdf/renderer";
|
|
|
|
import fs from "fs";
|
2023-12-23 18:21:12 +01:00
|
|
|
import { svg, tw } from "./theme/lib";
|
|
|
|
import SvgLink from "./theme/link";
|
|
|
|
import Experience, { Exp } from "./theme/experience";
|
|
|
|
import Education, { Edu } from "./theme/education";
|
|
|
|
import Certificate, { Cert } from "./theme/certificate";
|
2023-11-13 12:33:50 +01:00
|
|
|
|
2023-11-13 19:45:59 +01:00
|
|
|
const divider = (
|
2023-11-13 19:45:09 +01:00
|
|
|
<View style={tw("w-full mt-4")}>
|
|
|
|
<View style={tw("w-full border-slate-50 border-b-[.2px]")}></View>
|
|
|
|
</View>
|
2023-11-13 19:45:59 +01:00
|
|
|
);
|
2023-11-13 19:45:09 +01:00
|
|
|
|
2023-12-23 18:21:12 +01:00
|
|
|
type CV = {
|
|
|
|
name: string;
|
|
|
|
description: string;
|
|
|
|
title: string;
|
|
|
|
email: string;
|
|
|
|
github?: string;
|
|
|
|
website?: string;
|
|
|
|
upwork?: string;
|
|
|
|
phone?: string;
|
|
|
|
experience?: Exp[];
|
|
|
|
education?: Edu[];
|
|
|
|
certificates?: Cert[];
|
|
|
|
};
|
|
|
|
|
|
|
|
let data: CV = {} as CV;
|
|
|
|
|
|
|
|
const Cv = () => (
|
2023-11-13 14:10:39 +01:00
|
|
|
<Document
|
|
|
|
title="CV"
|
2023-12-23 18:21:12 +01:00
|
|
|
author={data.name}
|
2023-11-13 14:10:39 +01:00
|
|
|
subject="My professional resume"
|
2023-12-23 18:21:12 +01:00
|
|
|
creator={`${data.name} with react-pdf`}
|
|
|
|
producer={`${data.name} with react-pdf`}
|
|
|
|
keywords={`${data.name} ${data.title}`}
|
2023-11-13 14:10:39 +01:00
|
|
|
>
|
2023-12-23 18:21:12 +01:00
|
|
|
<Page
|
|
|
|
size="A4"
|
|
|
|
style={tw(
|
|
|
|
"w-full h-full text-slate-50 bg-gray-900 flex flex-col p-12 text-base"
|
|
|
|
)}
|
|
|
|
>
|
|
|
|
<View style={tw("text-center border-2 border-slate-50 rounded-full")}>
|
|
|
|
<Text style={tw("text-5xl")}>{data.name}</Text>
|
|
|
|
<Text>{data.title}</Text>
|
|
|
|
<View
|
|
|
|
style={tw("flex flex-row gap-4 w-full text-sm justify-center p-4")}
|
|
|
|
>
|
|
|
|
{data.github && (
|
|
|
|
<SvgLink
|
|
|
|
text="GitHub"
|
|
|
|
href={`https://github.com/${data.github}`}
|
|
|
|
icon={svg.github as any}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{data.upwork && (
|
|
|
|
<SvgLink
|
|
|
|
text="Upwork"
|
|
|
|
href={`https://www.upwork.com/freelancers/${data.upwork}`}
|
|
|
|
icon={svg.link as any}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
<SvgLink
|
|
|
|
text={data.email}
|
|
|
|
href={`mailto:${data.email}`}
|
|
|
|
icon={svg.email as any}
|
|
|
|
/>
|
|
|
|
{data.phone && (
|
|
|
|
<SvgLink
|
|
|
|
text={data.phone}
|
|
|
|
href={`tel:${data.phone}`}
|
|
|
|
icon={svg.phone as any}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
{data.website && (
|
|
|
|
<SvgLink
|
|
|
|
text={data.website}
|
|
|
|
href={`https://${data.website}`}
|
|
|
|
icon={svg.globe as any}
|
|
|
|
/>
|
|
|
|
)}
|
|
|
|
</View>
|
2023-11-17 09:39:33 +01:00
|
|
|
</View>
|
|
|
|
<View style={tw("my-auto")}>
|
2023-12-23 18:21:12 +01:00
|
|
|
{divider}
|
|
|
|
<Text style={tw("text-2xl mt-2 text-violet-500")}>Experience</Text>
|
|
|
|
{data.experience?.map((e, i) => (
|
|
|
|
<Experience
|
|
|
|
key={i}
|
|
|
|
to={e.to}
|
|
|
|
from={e.from}
|
|
|
|
links={e.links}
|
|
|
|
company={e.company}
|
|
|
|
location={e.location}
|
|
|
|
position={e.position}
|
|
|
|
feedback={e.feedback}
|
|
|
|
description={e.description}
|
|
|
|
/>
|
|
|
|
))}
|
2023-11-13 16:58:00 +01:00
|
|
|
{divider}
|
2023-11-29 12:06:05 +01:00
|
|
|
<Text style={tw("text-2xl mt-2 text-violet-500")}>Education</Text>
|
2023-12-23 18:21:12 +01:00
|
|
|
{data.education?.map((e, i) => (
|
|
|
|
<Education
|
|
|
|
key={i}
|
|
|
|
to={e.to}
|
|
|
|
from={e.from}
|
|
|
|
links={e.links}
|
|
|
|
institution={e.institution}
|
|
|
|
location={e.location}
|
|
|
|
field={e.field}
|
|
|
|
degree={e.degree}
|
|
|
|
summary={e.summary}
|
|
|
|
/>
|
|
|
|
))}
|
2023-11-15 17:06:03 +01:00
|
|
|
{divider}
|
2023-11-29 12:06:05 +01:00
|
|
|
<Text style={tw("text-2xl mt-2 text-violet-500")}>Certificates</Text>
|
2023-12-23 18:21:12 +01:00
|
|
|
{data.certificates?.map((c, i) => (
|
|
|
|
<Certificate
|
|
|
|
key={i}
|
|
|
|
date={c.date}
|
|
|
|
links={c.links}
|
|
|
|
name={c.name}
|
|
|
|
description={c.description}
|
|
|
|
issuer={c.issuer}
|
|
|
|
/>
|
|
|
|
))}
|
2023-11-13 16:58:00 +01:00
|
|
|
</View>
|
|
|
|
</Page>
|
2023-11-12 18:07:31 +01:00
|
|
|
</Document>
|
|
|
|
);
|
|
|
|
|
2023-12-23 18:21:12 +01:00
|
|
|
const parseData = () => {
|
|
|
|
const d = fs.readFileSync("./cv.json", { encoding: "utf8" });
|
|
|
|
const json: CV = JSON.parse(d);
|
|
|
|
json.experience = json.experience?.map((e) => ({
|
|
|
|
...e,
|
|
|
|
from: new Date(e.from),
|
|
|
|
to: new Date(e.to),
|
|
|
|
}));
|
|
|
|
json.education = json.education?.map((e) => ({
|
|
|
|
...e,
|
|
|
|
from: new Date(e.from),
|
|
|
|
to: new Date(e.to),
|
|
|
|
}));
|
|
|
|
json.certificates = json.certificates?.map((c) => ({
|
|
|
|
...c,
|
|
|
|
date: new Date(c.date),
|
|
|
|
}));
|
|
|
|
data = json;
|
|
|
|
};
|
|
|
|
|
2023-11-13 19:45:59 +01:00
|
|
|
const outDir = process.env.out || "./";
|
|
|
|
const pname = process.env.pname || "cv";
|
2023-11-12 18:07:31 +01:00
|
|
|
|
|
|
|
if (!fs.existsSync(outDir)) {
|
2023-11-13 19:45:59 +01:00
|
|
|
fs.mkdirSync(outDir, { recursive: true });
|
2023-11-12 18:07:31 +01:00
|
|
|
}
|
|
|
|
|
2023-12-23 18:21:12 +01:00
|
|
|
parseData();
|
|
|
|
|
|
|
|
ReactPDF.render(<Cv />, `${outDir}/${pname}.pdf`);
|