refactor
This commit is contained in:
parent
d76877b674
commit
8b7770a7aa
142
cv.tsx
142
cv.tsx
@ -2,10 +2,13 @@ import { Page, Text, View, Document, Link, Svg, Path } from "@react-pdf/renderer
|
|||||||
import ReactPDF from "@react-pdf/renderer";
|
import ReactPDF from "@react-pdf/renderer";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import { createTw } from "react-pdf-tailwind";
|
import { createTw } from "react-pdf-tailwind";
|
||||||
|
const tw = createTw({
|
||||||
|
});
|
||||||
|
|
||||||
type A = {
|
type A = {
|
||||||
text: string
|
text: string
|
||||||
href: string
|
href: string
|
||||||
|
icon?: string[]
|
||||||
}
|
}
|
||||||
|
|
||||||
type Experience = {
|
type Experience = {
|
||||||
@ -31,39 +34,6 @@ type Education = {
|
|||||||
links?: A[]
|
links?: A[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const tw = createTw({
|
|
||||||
});
|
|
||||||
|
|
||||||
const linkStyles = "no-underline text-slate-50 flex flex-row gap-1"
|
|
||||||
const pageStyles = "w-full h-full text-slate-50 bg-slate-950 flex flex-col p-12 text-base"
|
|
||||||
const sectionStyles = "w-full flex flex-col"
|
|
||||||
const svg = (paths: string[]) =>
|
|
||||||
<Svg style={tw("w-4 h-4")} viewBox="0 0 19 19">
|
|
||||||
{paths.map(p => (
|
|
||||||
<Path key={p} fill="#99f6e4" d={p} />
|
|
||||||
))}
|
|
||||||
</Svg>
|
|
||||||
const linkPath = "M11.013 7.962a3.519 3.519 0 0 0-4.975 0l-3.554 3.554a3.518 3.518 0 0 0 4.975 4.975l.461-.46m-.461-4.515a3.518 3.518 0 0 0 4.975 0l3.553-3.554a3.518 3.518 0 0 0-4.974-4.975L10.3 3.7"
|
|
||||||
const githubPath = "M10 .333A9.911 9.911 0 0 0 6.866 19.65c.5.092.678-.215.678-.477 0-.237-.01-1.017-.014-1.845-2.757.6-3.338-1.169-3.338-1.169a2.627 2.627 0 0 0-1.1-1.451c-.9-.615.07-.6.07-.6a2.084 2.084 0 0 1 1.518 1.021 2.11 2.11 0 0 0 2.884.823c.044-.503.268-.973.63-1.325-2.2-.25-4.516-1.1-4.516-4.9A3.832 3.832 0 0 1 4.7 7.068a3.56 3.56 0 0 1 .095-2.623s.832-.266 2.726 1.016a9.409 9.409 0 0 1 4.962 0c1.89-1.282 2.717-1.016 2.717-1.016.366.83.402 1.768.1 2.623a3.827 3.827 0 0 1 1.02 2.659c0 3.807-2.319 4.644-4.525 4.889a2.366 2.366 0 0 1 .673 1.834c0 1.326-.012 2.394-.012 2.72 0 .263.18.572.681.475A9.911 9.911 0 0 0 10 .333Z"
|
|
||||||
const emailPath1 = "m10.036 8.278 9.258-7.79A1.979 1.979 0 0 0 18 0H2A1.987 1.987 0 0 0 .641.541l9.395 7.737Z"
|
|
||||||
const emailPath2 = "M11.241 9.817c-.36.275-.801.425-1.255.427-.428 0-.845-.138-1.187-.395L0 2.6V14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2.5l-8.759 7.317Z"
|
|
||||||
const globePath = "M6.487 1.746c0 4.192 3.592 1.66 4.592 5.754 0 .828 1 1.5 2 1.5s2-.672 2-1.5a1.5 1.5 0 0 1 1.5-1.5h1.5m-16.02.471c4.02 2.248 1.776 4.216 4.878 5.645C10.18 13.61 9 19 9 19m9.366-6h-2.287a3 3 0 0 0-3 3v2m6-8a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"
|
|
||||||
|
|
||||||
const divider =
|
|
||||||
<View style={tw("w-full mt-4")}>
|
|
||||||
<View style={tw("w-full border-slate-50 border-b-[.2px]")}></View>
|
|
||||||
</View>
|
|
||||||
|
|
||||||
|
|
||||||
const github =
|
|
||||||
<Link src="https://github.com/ivandimitrov8080" style={tw(linkStyles)}>{svg([githubPath])}<Text>github/ivandimitrov8080</Text></Link>
|
|
||||||
const upwork =
|
|
||||||
<Link src="https://www.upwork.com/freelancers/idimitrov" style={tw(linkStyles)}>{svg([linkPath])}<Text>upwork/freelancers/idimitrov</Text></Link>
|
|
||||||
const resume =
|
|
||||||
<Link src="https://www.idimitrov.dev" style={tw(linkStyles)}>{svg([globePath])}<Text>idimitrov.dev</Text></Link>
|
|
||||||
const email =
|
|
||||||
<Link src="mailto:ivan@idimitrov.dev" style={tw(linkStyles)}>{svg([emailPath1, emailPath2])}<Text>ivan@idimitrov.dev</Text></Link>
|
|
||||||
|
|
||||||
const tech = {
|
const tech = {
|
||||||
android: [
|
android: [
|
||||||
"Android",
|
"Android",
|
||||||
@ -189,42 +159,33 @@ const tech = {
|
|||||||
"PDF",
|
"PDF",
|
||||||
"Email",
|
"Email",
|
||||||
],
|
],
|
||||||
|
} as const
|
||||||
|
|
||||||
|
const techKeys = Object.keys(tech) as Array<keyof typeof tech>
|
||||||
|
|
||||||
|
type TechKeys = keyof typeof tech
|
||||||
|
|
||||||
|
const skills = (skills: TechKeys[]): string[] => {
|
||||||
|
return skills.map(s => tech[s]).flat()
|
||||||
}
|
}
|
||||||
|
|
||||||
const techKeys = [...Object.keys(tech)] as const
|
const skillsInverted = (skills: TechKeys[]): string[] => {
|
||||||
|
return techKeys.filter(k => !skills.includes(k)).map(s => tech[s]).flat()
|
||||||
const filterKeysIncl = (obj: readonly string[], keys: string[]) => {
|
|
||||||
return obj.filter(e => keys.includes(e))
|
|
||||||
}
|
|
||||||
const filterKeysExcl = (obj: readonly string[], keys: string[]) => {
|
|
||||||
return obj.filter(e => !keys.includes(e))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const cnetTech: string[] = filterKeysExcl(techKeys,
|
const createSvg = (paths: string[]) =>
|
||||||
["hybris", "payment", "dataIntegration", "python", "nextjs", "styles"]
|
<Svg style={tw("w-4 h-4")} viewBox="0 0 19 19">
|
||||||
)
|
{paths.map(p => (
|
||||||
// @ts-ignore
|
<Path key={p} fill="#99f6e4" d={p} />
|
||||||
.map(e => tech[e]).flat()
|
))}
|
||||||
const raTech: string[] = filterKeysExcl(techKeys,
|
</Svg>
|
||||||
["dataIntegration", "python", "nextjs", "styles"]
|
|
||||||
)
|
const svg = {
|
||||||
// @ts-ignore
|
github: createSvg(["M10 .333A9.911 9.911 0 0 0 6.866 19.65c.5.092.678-.215.678-.477 0-.237-.01-1.017-.014-1.845-2.757.6-3.338-1.169-3.338-1.169a2.627 2.627 0 0 0-1.1-1.451c-.9-.615.07-.6.07-.6a2.084 2.084 0 0 1 1.518 1.021 2.11 2.11 0 0 0 2.884.823c.044-.503.268-.973.63-1.325-2.2-.25-4.516-1.1-4.516-4.9A3.832 3.832 0 0 1 4.7 7.068a3.56 3.56 0 0 1 .095-2.623s.832-.266 2.726 1.016a9.409 9.409 0 0 1 4.962 0c1.89-1.282 2.717-1.016 2.717-1.016.366.83.402 1.768.1 2.623a3.827 3.827 0 0 1 1.02 2.659c0 3.807-2.319 4.644-4.525 4.889a2.366 2.366 0 0 1 .673 1.834c0 1.326-.012 2.394-.012 2.72 0 .263.18.572.681.475A9.911 9.911 0 0 0 10 .333Z"]),
|
||||||
.map(e => tech[e]).flat()
|
link: createSvg(["M11.013 7.962a3.519 3.519 0 0 0-4.975 0l-3.554 3.554a3.518 3.518 0 0 0 4.975 4.975l.461-.46m-.461-4.515a3.518 3.518 0 0 0 4.975 0l3.553-3.554a3.518 3.518 0 0 0-4.974-4.975L10.3 3.7"]),
|
||||||
const ncTech: string[] = filterKeysIncl(techKeys,
|
email: createSvg(["m10.036 8.278 9.258-7.79A1.979 1.979 0 0 0 18 0H2A1.987 1.987 0 0 0 .641.541l9.395 7.737Z", "M11.241 9.817c-.36.275-.801.425-1.255.427-.428 0-.845-.138-1.187-.395L0 2.6V14a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V2.5l-8.759 7.317Z"]),
|
||||||
["java", "dataIntegration", "git"]
|
globe: createSvg(["M6.487 1.746c0 4.192 3.592 1.66 4.592 5.754 0 .828 1 1.5 2 1.5s2-.672 2-1.5a1.5 1.5 0 0 1 1.5-1.5h1.5m-16.02.471c4.02 2.248 1.776 4.216 4.878 5.645C10.18 13.61 9 19 9 19m9.366-6h-2.287a3 3 0 0 0-3 3v2m6-8a9 9 0 1 1-18 0 9 9 0 0 1 18 0Z"])
|
||||||
)
|
}
|
||||||
// @ts-ignore
|
|
||||||
.map(e => tech[e]).flat()
|
|
||||||
const hoi2Tech: string[] = filterKeysIncl(techKeys,
|
|
||||||
["python", "nextjs", "styles", "linux", "git", "general"]
|
|
||||||
)
|
|
||||||
// @ts-ignore
|
|
||||||
.map(e => tech[e]).flat().concat(["Wix", "Fuse.js"])
|
|
||||||
const stepsyTech: string[] = filterKeysIncl(techKeys,
|
|
||||||
["nextjs", "styles", "linux", "git", "general"]
|
|
||||||
)
|
|
||||||
// @ts-ignore
|
|
||||||
.map(e => tech[e]).flat().concat(["googleapis", "Fuse.js", "Interact.js"])
|
|
||||||
|
|
||||||
const experience = ({
|
const experience = ({
|
||||||
company,
|
company,
|
||||||
@ -237,7 +198,7 @@ const experience = ({
|
|||||||
links,
|
links,
|
||||||
feedback
|
feedback
|
||||||
}: Experience) =>
|
}: Experience) =>
|
||||||
<View style={tw(sectionStyles)}>
|
<View style={tw("w-full flex flex-col")}>
|
||||||
<View style={tw("w-full flex flex-col mt-2 border-2 border-slate-50 p-4 rounded-2xl")}>
|
<View style={tw("w-full flex flex-col mt-2 border-2 border-slate-50 p-4 rounded-2xl")}>
|
||||||
<View style={tw("flex flex-row flex-wrap gap-1")}>
|
<View style={tw("flex flex-row flex-wrap gap-1")}>
|
||||||
<Text>{position}</Text>
|
<Text>{position}</Text>
|
||||||
@ -251,9 +212,8 @@ const experience = ({
|
|||||||
{links && (
|
{links && (
|
||||||
<View style={tw("flex flex-row flex-wrap w-full gap-2 justify-center")}>
|
<View style={tw("flex flex-row flex-wrap w-full gap-2 justify-center")}>
|
||||||
{links.map(l => (
|
{links.map(l => (
|
||||||
<View key={l.href} style={tw("flex flex-row gap-2")}>
|
<View key={l.href} style={tw("flex flex-row gap-2 text-sm")}>
|
||||||
{svg([linkPath])}
|
{link(l)}
|
||||||
<Text style={tw("text-sm")}>{l.text}</Text>
|
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
@ -263,13 +223,13 @@ const experience = ({
|
|||||||
</View>
|
</View>
|
||||||
{feedback && (
|
{feedback && (
|
||||||
<View style={tw("w-full m-auto mb-1")}>
|
<View style={tw("w-full m-auto mb-1")}>
|
||||||
<Text>Result: "{feedback}"</Text>
|
<Text>Feedback: "{feedback}"</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
<View style={tw("flex flex-row flex-wrap m-2")}>
|
<View style={tw("flex flex-row flex-wrap m-2")}>
|
||||||
{technologies.map(t => (
|
{technologies.map(t => (
|
||||||
<View key={t} style={tw("flex flex-row")}>
|
<View key={t} style={tw("flex flex-row")}>
|
||||||
<View style={tw("border-2 border-teal-200 h-1 mx-1 mt-1 rounded-full")}></View>
|
<View style={tw("border-2 border-green-300 h-1 mx-1 mt-1 rounded-full")}></View>
|
||||||
<Text style={tw("text-xs")}>{t}</Text>
|
<Text style={tw("text-xs")}>{t}</Text>
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
@ -287,7 +247,7 @@ const education = ({
|
|||||||
summary,
|
summary,
|
||||||
links
|
links
|
||||||
}: Education) =>
|
}: Education) =>
|
||||||
<View style={tw(sectionStyles)}>
|
<View style={tw("w-full flex flex-col")}>
|
||||||
<View style={tw("w-full flex flex-col mt-2 border-2 border-slate-50 p-4 rounded-2xl")}>
|
<View style={tw("w-full flex flex-col mt-2 border-2 border-slate-50 p-4 rounded-2xl")}>
|
||||||
<View style={tw("flex flex-row flex-wrap gap-1")}>
|
<View style={tw("flex flex-row flex-wrap gap-1")}>
|
||||||
<Text>Studied {degree} of {field}</Text>
|
<Text>Studied {degree} of {field}</Text>
|
||||||
@ -302,8 +262,7 @@ const education = ({
|
|||||||
<View style={tw("flex flex-row flex-wrap w-full gap-2 justify-center")}>
|
<View style={tw("flex flex-row flex-wrap w-full gap-2 justify-center")}>
|
||||||
{links.map(l => (
|
{links.map(l => (
|
||||||
<View key={l.href} style={tw("flex flex-row gap-2")}>
|
<View key={l.href} style={tw("flex flex-row gap-2")}>
|
||||||
{svg([linkPath])}
|
{link(l)}
|
||||||
<Text style={tw("text-sm")}>{l.text}</Text>
|
|
||||||
</View>
|
</View>
|
||||||
))}
|
))}
|
||||||
</View>
|
</View>
|
||||||
@ -313,12 +272,14 @@ const education = ({
|
|||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
|
||||||
|
const link = ({ text, href, icon }: A) => <Link src={href} style={tw("no-underline text-slate-50 flex flex-row gap-1")}>{icon || svg.link}<Text>{text}</Text></Link>
|
||||||
const Links = () => (
|
const Links = () => (
|
||||||
<View style={tw("flex flex-row gap-4 w-full text-sm justify-center p-4")}>
|
<View style={tw("flex flex-row gap-4 w-full text-sm justify-center p-4")}>
|
||||||
{github}
|
{link({ text: "GitHub", href: "https://github.com/ivandimitrov8080", icon: svg.github as any })}
|
||||||
{upwork}
|
{link({ text: "Upwork", href: "https://www.upwork.com/freelancers/idimitrov", icon: svg.link as any })}
|
||||||
{email}
|
{link({ text: "ivan@idimitrov.dev", href: "mailto:ivan@idimitrov.dev", icon: svg.email as any })}
|
||||||
{resume}
|
{link({ text: "idimitrov.dev", href: "https://www.idimitrov.dev", icon: svg.globe as any })}
|
||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -330,6 +291,12 @@ const Intro = () => (
|
|||||||
</View>
|
</View>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const pageStyles = tw("w-full h-full text-slate-50 bg-slate-950 flex flex-col p-12 text-base")
|
||||||
|
const divider =
|
||||||
|
<View style={tw("w-full mt-4")}>
|
||||||
|
<View style={tw("w-full border-slate-50 border-b-[.2px]")}></View>
|
||||||
|
</View>
|
||||||
|
|
||||||
const CV = () => (
|
const CV = () => (
|
||||||
<Document
|
<Document
|
||||||
title="CV"
|
title="CV"
|
||||||
@ -341,7 +308,7 @@ const CV = () => (
|
|||||||
>
|
>
|
||||||
<Page
|
<Page
|
||||||
size="A4"
|
size="A4"
|
||||||
style={tw(pageStyles)}>
|
style={(pageStyles)}>
|
||||||
<Intro />
|
<Intro />
|
||||||
{divider}
|
{divider}
|
||||||
<Text style={tw("text-2xl mt-2")}>Experience</Text>
|
<Text style={tw("text-2xl mt-2")}>Experience</Text>
|
||||||
@ -353,7 +320,7 @@ const CV = () => (
|
|||||||
from: new Date("21 Sep 2023"),
|
from: new Date("21 Sep 2023"),
|
||||||
to: new Date("5 Nov 2023"),
|
to: new Date("5 Nov 2023"),
|
||||||
description: "Diagnosed and analyzed a faulty LUKS encrypted drive on a remote server.",
|
description: "Diagnosed and analyzed a faulty LUKS encrypted drive on a remote server.",
|
||||||
technologies: tech.linux,
|
technologies: [...tech.linux],
|
||||||
feedback: "Ivan was great to work with. Bought his own ideas and expertise, and workshopped a solution with me. Has a wealth of knowledge and I'd very happily work with him again."
|
feedback: "Ivan was great to work with. Bought his own ideas and expertise, and workshopped a solution with me. Has a wealth of knowledge and I'd very happily work with him again."
|
||||||
})}
|
})}
|
||||||
{experience({
|
{experience({
|
||||||
@ -363,7 +330,8 @@ const CV = () => (
|
|||||||
from: new Date("29 Jul 2023"),
|
from: new Date("29 Jul 2023"),
|
||||||
to: new Date("5 Nov 2023"),
|
to: new Date("5 Nov 2023"),
|
||||||
description: "Created a multi-tenant knowledge base website based on Google APIs",
|
description: "Created a multi-tenant knowledge base website based on Google APIs",
|
||||||
technologies: stepsyTech,
|
technologies: skills(["nextjs", "styles", "linux", "git", "general"])
|
||||||
|
.concat(["googleapis", "Fuse.js", "Interact.js"]),
|
||||||
links: [
|
links: [
|
||||||
{ text: "Case Study", href: "https://www.idimitrov.dev/c/cases/stepsy.wiki.md" }
|
{ text: "Case Study", href: "https://www.idimitrov.dev/c/cases/stepsy.wiki.md" }
|
||||||
],
|
],
|
||||||
@ -376,14 +344,14 @@ const CV = () => (
|
|||||||
from: new Date("22 Jun 2023"),
|
from: new Date("22 Jun 2023"),
|
||||||
to: new Date("27 Jun 2023"),
|
to: new Date("27 Jun 2023"),
|
||||||
description: "Scraped an old wiki website with over 500 pages and created a new static site generated using Markdown and NextJS.",
|
description: "Scraped an old wiki website with over 500 pages and created a new static site generated using Markdown and NextJS.",
|
||||||
technologies: hoi2Tech,
|
technologies: skills(["python", "nextjs", "styles", "linux", "git", "general"]),
|
||||||
feedback: "Ivan went above and beyond to make sure I was happy with the final result"
|
feedback: "Ivan went above and beyond to make sure I was happy with the final result"
|
||||||
})}
|
})}
|
||||||
</View>
|
</View>
|
||||||
</Page>
|
</Page>
|
||||||
<Page
|
<Page
|
||||||
size="A4"
|
size="A4"
|
||||||
style={tw(pageStyles)}
|
style={(pageStyles)}
|
||||||
>
|
>
|
||||||
<View style={tw("my-auto")}>
|
<View style={tw("my-auto")}>
|
||||||
{experience({
|
{experience({
|
||||||
@ -393,7 +361,7 @@ const CV = () => (
|
|||||||
from: new Date("25 May 2023"),
|
from: new Date("25 May 2023"),
|
||||||
to: new Date("20 Jun 2023"),
|
to: new Date("20 Jun 2023"),
|
||||||
description: "Wrote technical documentation and content for the DataPipeline library by NorthConcepts.",
|
description: "Wrote technical documentation and content for the DataPipeline library by NorthConcepts.",
|
||||||
technologies: ncTech,
|
technologies: skills(["java", "dataIntegration", "git"]).concat("WordPress"),
|
||||||
feedback: "Ivan is a talented developer and was able to understand and write about our developer framework without difficulty."
|
feedback: "Ivan is a talented developer and was able to understand and write about our developer framework without difficulty."
|
||||||
})}
|
})}
|
||||||
{experience({
|
{experience({
|
||||||
@ -403,7 +371,7 @@ const CV = () => (
|
|||||||
from: new Date("Dec 2020"),
|
from: new Date("Dec 2020"),
|
||||||
to: new Date("20 Jan 2023"),
|
to: new Date("20 Jan 2023"),
|
||||||
description: "Worked on seven international eCommerce web apps serving customers in the US and Europe.",
|
description: "Worked on seven international eCommerce web apps serving customers in the US and Europe.",
|
||||||
technologies: raTech,
|
technologies: skillsInverted(["dataIntegration", "python", "nextjs"]),
|
||||||
links: [
|
links: [
|
||||||
{ text: "RA Creative", href: "https://racreative.co.uk/" },
|
{ text: "RA Creative", href: "https://racreative.co.uk/" },
|
||||||
{ text: "Parcel Lab", href: "https://parcellab.com/" },
|
{ text: "Parcel Lab", href: "https://parcellab.com/" },
|
||||||
@ -417,13 +385,13 @@ const CV = () => (
|
|||||||
from: new Date("May 2016"),
|
from: new Date("May 2016"),
|
||||||
to: new Date("May 2020"),
|
to: new Date("May 2020"),
|
||||||
description: "Developed a full-stack web + android app helping students book exams, browse resources, see events, news and more.",
|
description: "Developed a full-stack web + android app helping students book exams, browse resources, see events, news and more.",
|
||||||
technologies: cnetTech
|
technologies: skillsInverted(["hybris", "payment", "dataIntegration", "python", "nextjs", "styles"])
|
||||||
})}
|
})}
|
||||||
</View>
|
</View>
|
||||||
</Page>
|
</Page>
|
||||||
<Page
|
<Page
|
||||||
size="A4"
|
size="A4"
|
||||||
style={tw(pageStyles)}
|
style={(pageStyles)}
|
||||||
>
|
>
|
||||||
<View style={tw("my-2")}>
|
<View style={tw("my-2")}>
|
||||||
{divider}
|
{divider}
|
||||||
|
@ -14,5 +14,11 @@
|
|||||||
"@types/react": "^18.2.37",
|
"@types/react": "^18.2.37",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-pdf-tailwind": "^2.1.0"
|
"react-pdf-tailwind": "^2.1.0"
|
||||||
|
},
|
||||||
|
"prettier": {
|
||||||
|
"trailingComma": "es5",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user