This commit is contained in:
Ivan Dimitrov 2023-11-29 13:06:05 +02:00
parent ba524cf739
commit 59e5d22a5a
3 changed files with 159 additions and 190 deletions

208
cv.tsx
View File

@ -25,7 +25,6 @@ type Experience = {
from: Date; from: Date;
to: Date; to: Date;
description: string; description: string;
technologies: string[];
links?: A[]; links?: A[];
feedback?: string; feedback?: string;
}; };
@ -49,124 +48,6 @@ type Certificate = {
links?: A[]; links?: A[];
}; };
const tech = {
android: ["Android", "Android Studio"],
architectures: [
"Microservices",
"MVC",
"Layered architecture",
"DDD",
"EDA",
"Publish-subscribe",
"Client-server",
"REST",
"Pipes and filters",
],
java: [
"Java",
"JPA",
"Hibernate",
"Spring Framework",
"Spring Boot",
"Lombok",
"Spring MVC",
"Thymeleaf",
"JSP",
"JSTL",
"XML",
"Spring Security",
"OAuth2",
"H2",
"Spring Boot Actuator",
"Maven",
"Gradle",
"Ant",
],
web: ["JavaScript", "HTML", "CSS"],
api: ["REST", "SOAP"],
db: ["MySQL", "PostgreSQL"],
linux: [
"Linux",
"Bash",
"coreutils",
"Ubuntu",
"CentOS",
"RHEL",
"SSH",
"iptables",
"systemd",
"vim",
"Monit",
"CLI",
"pandoc",
"LUKS",
"hexdump",
"dd",
],
git: ["git", "GitHub", "GitLab", "BitBucket"],
hybris: ["SAP hybris", "ZK Framework"],
payment: ["PayPal", "Adyen", "V12", "Wells Fargo Open Banking APIs"],
dataIntegration: [
"Spring Batch",
"Data Pipeline",
"Scriptella",
"Easy Batch",
"GETL",
"Apache Camel",
"Apache Samza",
"Apache Flink",
"Apache Storm",
"Apache Spark",
"Apache NiFi",
],
python: [
"python",
"BeautifulSoup4",
"requests",
"pypandoc",
"markdownify",
"html2text",
"Poetry",
],
javascript: ["TypeScript", "React"],
nextjs: [
"NextJS 12",
"NextJS 13",
"NextJS 14",
"NextAuth",
"Prisma",
"Vercel",
"Vercel Postgres",
"Formik",
"Framer Motion",
],
styles: [
"CSS",
"SASS",
"TailwindCSS",
"DaisyUI",
"tailwind-scrollbar",
"FontAwesome",
"nProgress",
],
general: ["Markdown", "Google", "DuckDuckGo", "PDF", "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 skillsInverted = (skills: TechKeys[]): string[] => {
return techKeys
.filter((k) => !skills.includes(k))
.map((s) => tech[s])
.flat();
};
const createSvg = (paths: string[]) => ( const createSvg = (paths: string[]) => (
<Svg style={tw("w-4 h-4")} viewBox="0 0 19 19"> <Svg style={tw("w-4 h-4")} viewBox="0 0 19 19">
{paths.map((p) => ( {paths.map((p) => (
@ -198,7 +79,6 @@ const experience = ({
from, from,
to, to,
description, description,
technologies,
links, links,
feedback, feedback,
}: Experience) => ( }: Experience) => (
@ -209,15 +89,15 @@ const experience = ({
)} )}
> >
<View style={tw("flex flex-row flex-wrap gap-1")}> <View style={tw("flex flex-row flex-wrap gap-1")}>
<Text>{position}</Text> <Text style={tw("text-amber-500")}>{position}</Text>
<Text>at</Text> <Text>at</Text>
<Text> <Text style={tw("text-blue-500")}>
{company}, {location} {company}, {location}
</Text> </Text>
<Text>from</Text> <Text>from</Text>
<Text>{from.toDateString()}</Text> <Text style={tw("text-lime-500")}>{from.toDateString()}</Text>
<Text>to</Text> <Text>to</Text>
<Text>{to > new Date() ? "present" : to.toDateString()}</Text> <Text style={tw("text-lime-500")}>{to > new Date() ? "present" : to.toDateString()}</Text>
</View> </View>
{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")}>
@ -229,23 +109,17 @@ const experience = ({
</View> </View>
)} )}
<View style={tw("m-4")}> <View style={tw("m-4")}>
<Text>{description}</Text> <Text style={tw("text-neutral-400")}>{description}</Text>
</View> </View>
{feedback && ( {feedback && (
<View style={tw("w-full m-auto mb-1")}> <Text style={tw("w-full m-auto mb-1")}>
<Text>Feedback: "{feedback}"</Text> <Text style={tw("text-amber-500")}>let </Text>
</View> <Text>clientFeedback</Text>
<Text style={tw("text-amber-500")}> = </Text>
<Text style={tw("text-green-500")}>"{feedback}"</Text>
<Text>;</Text>
</Text>
)} )}
<View style={tw("flex flex-row flex-wrap m-2")}>
{technologies.map((t) => (
<View key={t} style={tw("flex flex-row")}>
<View
style={tw("border-2 border-green-300 h-1 mx-1 mt-1 rounded-full")}
></View>
<Text style={tw("text-xs")}>{t}</Text>
</View>
))}
</View>
</View> </View>
</View> </View>
); );
@ -267,17 +141,17 @@ const education = ({
)} )}
> >
<View style={tw("flex flex-row flex-wrap gap-1")}> <View style={tw("flex flex-row flex-wrap gap-1")}>
<Text> <Text style={tw("text-amber-500")}>
Studied {degree} of {field} Studied {degree} of {field}
</Text> </Text>
<Text>at</Text> <Text>at</Text>
<Text> <Text style={tw("text-blue-500")}>
{institution}, {location} {institution}, {location}
</Text> </Text>
<Text>from</Text> <Text>from</Text>
<Text>{from.toDateString()}</Text> <Text style={tw("text-lime-500")}>{from.toDateString()}</Text>
<Text>to</Text> <Text>to</Text>
<Text>{to.toDateString()}</Text> <Text style={tw("text-lime-500")}>{to.toDateString()}</Text>
</View> </View>
{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")}>
@ -289,7 +163,7 @@ const education = ({
</View> </View>
)} )}
<View style={tw("m-4")}> <View style={tw("m-4")}>
<Text style={tw("text-md")}>{summary}</Text> <Text style={tw("text-neutral-400")}>{summary}</Text>
</View> </View>
</View> </View>
</View> </View>
@ -309,11 +183,11 @@ const certificate = ({
)} )}
> >
<View style={tw("flex flex-row flex-wrap gap-1")}> <View style={tw("flex flex-row flex-wrap gap-1")}>
<Text>{name}</Text> <Text style={tw("text-amber-500")}>{name}</Text>
<Text>from</Text> <Text>from</Text>
<Text>{issuer}</Text> <Text style={tw("text-blue-500")}>{issuer}</Text>
<Text>on</Text> <Text>on</Text>
<Text>{date.toDateString()}</Text> <Text style={tw("text-lime-500")}>{date.toDateString()}</Text>
</View> </View>
{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")}>
@ -325,7 +199,7 @@ const certificate = ({
</View> </View>
)} )}
<View style={tw("m-4")}> <View style={tw("m-4")}>
<Text style={tw("text-md")}>{description}</Text> <Text style={tw("text-neutral-400")}>{description}</Text>
</View> </View>
</View> </View>
</View> </View>
@ -365,13 +239,13 @@ const Links = () => (
const Intro = () => ( const Intro = () => (
<View style={tw("text-center border-2 border-slate-50 rounded-full")}> <View style={tw("text-center border-2 border-slate-50 rounded-full")}>
<Text style={tw("text-5xl")}>Ivan K. Dimitrov</Text> <Text style={tw("text-5xl")}>Ivan K. Dimitrov</Text>
<Text style={tw("text-sm")}>Software Developer</Text> <Text>Software Developer</Text>
<Links /> <Links />
</View> </View>
); );
const pageStyles = tw( const pageStyles = tw(
"w-full h-full text-slate-50 bg-slate-950 flex flex-col p-12 text-base" "w-full h-full text-slate-50 bg-gray-900 flex flex-col p-12 text-base"
); );
const divider = ( const divider = (
<View style={tw("w-full mt-4")}> <View style={tw("w-full mt-4")}>
@ -391,7 +265,7 @@ const CV = () => (
<Page size="A4" style={pageStyles}> <Page size="A4" style={pageStyles}>
<Intro /> <Intro />
{divider} {divider}
<Text style={tw("text-2xl mt-2")}>Experience</Text> <Text style={tw("text-2xl mt-2 text-violet-500")}>Experience</Text>
<View style={tw("my-auto")}> <View style={tw("my-auto")}>
{experience({ {experience({
company: "idimitrov.dev", company: "idimitrov.dev",
@ -400,13 +274,7 @@ const CV = () => (
from: new Date("2023"), from: new Date("2023"),
to: new Date("9999"), to: new Date("9999"),
description: description:
"This is my software consulting and development business. Please head over to my resume website or Upwork to learn more.", "This is my software consulting and development business. It offers web development services to businesses around the world. Please head over to my resume website or my Upwork profile to learn more.",
technologies: [
"Business development",
"Software Development",
"Communication",
...skills(["architectures"])
],
links: [ links: [
{ {
text: "Upwork", text: "Upwork",
@ -417,6 +285,7 @@ const CV = () => (
href: "https://www.idimitrov.dev/cases", href: "https://www.idimitrov.dev/cases",
}, },
], ],
feedback: "100% Job Success"
})} })}
{experience({ {experience({
company: "Stepsy", company: "Stepsy",
@ -425,15 +294,7 @@ 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: description:
"Created a multi-tenant knowledge base website based on Google APIs", "As a software developer working with stepsy.co, I was responsible for implementing their brand new wiki web app stepsy.wiki. Working on this greenfield project allowed me to make fundamental technical decisions that had a positive impact on further development.",
technologies: skills([
"nextjs",
"styles",
"linux",
"git",
"general",
"architectures"
]).concat(["googleapis", "Fuse.js", "Interact.js"]),
links: [ links: [
{ {
text: "Case Study", text: "Case Study",
@ -450,8 +311,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: description:
"Worked on seven international eCommerce web apps serving customers in the US and Europe.", "As a software developer at RA Creative, I was responsible for delivering software solutions to an eCommerce business operating in 2 continents - Europe and North America. Watches of Switzerland Group is an international retailer of world leading luxury watch and jewellery brands. It has a market cap of £1.5B.",
technologies: skillsInverted(["dataIntegration", "python", "nextjs"]),
links: [ links: [
{ text: "RA Creative", href: "https://racreative.co.uk/" }, { text: "RA Creative", href: "https://racreative.co.uk/" },
{ {
@ -476,17 +336,9 @@ const CV = () => (
to: new Date("May 2020"), to: new Date("May 2020"),
description: description:
"Developed a full-stack web + android app helping students book exams, browse resources, see events, news and more.", "Developed a full-stack web + android app helping students book exams, browse resources, see events, news and more.",
technologies: skillsInverted([
"hybris",
"payment",
"dataIntegration",
"python",
"nextjs",
"styles",
]),
})} })}
{divider} {divider}
<Text style={tw("text-2xl mt-2")}>Education</Text> <Text style={tw("text-2xl mt-2 text-violet-500")}>Education</Text>
{education({ {education({
institution: "SWU 'Neofit Rilski'", institution: "SWU 'Neofit Rilski'",
location: "Blagoevgrad, Bulgaria", location: "Blagoevgrad, Bulgaria",
@ -498,7 +350,7 @@ const CV = () => (
"This is an engineering degree focused on the science of electronics and electrical engineering. It studies the physical properties of individual electrons and the forces that take place when current is flowing through a circuit.", "This is an engineering degree focused on the science of electronics and electrical engineering. It studies the physical properties of individual electrons and the forces that take place when current is flowing through a circuit.",
})} })}
{divider} {divider}
<Text style={tw("text-2xl mt-2")}>Certificates</Text> <Text style={tw("text-2xl mt-2 text-violet-500")}>Certificates</Text>
{certificate({ {certificate({
name: "Oracle Certified Professional, Java SE 8 Programmer", name: "Oracle Certified Professional, Java SE 8 Programmer",
issuer: "Oracle", issuer: "Oracle",

View File

@ -150,11 +150,11 @@
"systems": "systems_3" "systems": "systems_3"
}, },
"locked": { "locked": {
"lastModified": 1700381994, "lastModified": 1701244257,
"narHash": "sha256-ANUCVLf7v276VepwjyfGNmMfY0+d9fZ9cVlt5DwZ7TM=", "narHash": "sha256-rJHTSJlDa0gkJubwdsNKZHQe0Is54Uk1f2chTYTxnO4=",
"owner": "ivandimitrov8080", "owner": "ivandimitrov8080",
"repo": "flake-ide", "repo": "flake-ide",
"rev": "0cb6f5a5ba5aa36194061bdd5fbaca589023f9f7", "rev": "1f702a622d51814e8a11f72f389eff73239c1082",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -165,11 +165,11 @@
}, },
"nixpkgs": { "nixpkgs": {
"locked": { "locked": {
"lastModified": 1700538105, "lastModified": 1701174899,
"narHash": "sha256-uZhOCmwv8VupEmPZm3erbr9XXmyg7K67Ul3+Rx2XMe0=", "narHash": "sha256-1W+FMe8mWsJKXoBc+QgKmEeRj33kTFnPq7XCjU+bfnA=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "51a01a7e5515b469886c120e38db325c96694c2f", "rev": "010c7296f3b19a58b206fdf7d68d75a5b0a09e9e",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -204,11 +204,11 @@
"pre-commit-hooks": "pre-commit-hooks" "pre-commit-hooks": "pre-commit-hooks"
}, },
"locked": { "locked": {
"lastModified": 1700557248, "lastModified": 1701250280,
"narHash": "sha256-8g+ZzsZcLpO55d1LvhfjheJuDlDyIm1POUNULJqSvgs=", "narHash": "sha256-Nx2nqkUfOAvW+GlVIs5HK8WfuZsbN8FqW2bXNx0fMJc=",
"owner": "nix-community", "owner": "nix-community",
"repo": "nixvim", "repo": "nixvim",
"rev": "a05b2a9cbfb28f2590b441192fa20b70b0ed319a", "rev": "f56d412f84e2cee53365ade1093f9cc449d58fa3",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -259,11 +259,11 @@
"nixpkgs-stable": "nixpkgs-stable" "nixpkgs-stable": "nixpkgs-stable"
}, },
"locked": { "locked": {
"lastModified": 1700064067, "lastModified": 1700922917,
"narHash": "sha256-1ZWNDzhu8UlVCK7+DUN9dVQfiHX1bv6OQP9VxstY/gs=", "narHash": "sha256-ej2fch/T584b5K9sk1UhmZF7W6wEfDHuoUYpFN8dtvM=",
"owner": "cachix", "owner": "cachix",
"repo": "pre-commit-hooks.nix", "repo": "pre-commit-hooks.nix",
"rev": "e558068cba67b23b4fbc5537173dbb43748a17e8", "rev": "e5ee5c5f3844550c01d2131096c7271cec5e9b78",
"type": "github" "type": "github"
}, },
"original": { "original": {

117
tech.ts Normal file
View File

@ -0,0 +1,117 @@
const tech = {
android: ["Android", "Android Studio"],
architectures: [
"Microservices",
"MVC",
"Layered architecture",
"DDD",
"EDA",
"Publish-subscribe",
"Client-server",
"REST",
"Pipes and filters",
],
java: [
"Java",
"JPA",
"Hibernate",
"Spring Framework",
"Spring Boot",
"Lombok",
"Spring MVC",
"Thymeleaf",
"JSP",
"JSTL",
"XML",
"Spring Security",
"OAuth2",
"H2",
"Spring Boot Actuator",
"Maven",
"Gradle",
"Ant",
],
web: ["JavaScript", "HTML", "CSS"],
api: ["REST", "SOAP"],
db: ["MySQL", "PostgreSQL"],
linux: [
"Linux",
"Bash",
"coreutils",
"Ubuntu",
"CentOS",
"RHEL",
"SSH",
"iptables",
"systemd",
"vim",
"Monit",
"CLI",
"pandoc",
"LUKS",
"hexdump",
"dd",
],
git: ["git", "GitHub", "GitLab", "BitBucket"],
hybris: ["SAP hybris", "ZK Framework"],
payment: ["PayPal", "Adyen", "V12", "Wells Fargo Open Banking APIs"],
dataIntegration: [
"Spring Batch",
"Data Pipeline",
"Scriptella",
"Easy Batch",
"GETL",
"Apache Camel",
"Apache Samza",
"Apache Flink",
"Apache Storm",
"Apache Spark",
"Apache NiFi",
],
python: [
"python",
"BeautifulSoup4",
"requests",
"pypandoc",
"markdownify",
"html2text",
"Poetry",
],
javascript: ["TypeScript", "React"],
nextjs: [
"NextJS 12",
"NextJS 13",
"NextJS 14",
"NextAuth",
"Prisma",
"Vercel",
"Vercel Postgres",
"Formik",
"Framer Motion",
],
styles: [
"CSS",
"SASS",
"TailwindCSS",
"DaisyUI",
"tailwind-scrollbar",
"FontAwesome",
"nProgress",
],
general: ["Markdown", "Google", "DuckDuckGo", "PDF", "Email"],
} as const;
const techKeys = Object.keys(tech) as Array<keyof typeof tech>;
type TechKeys = keyof typeof tech;
export const skills = (skills: TechKeys[]): string[] => {
return skills.map((s) => tech[s]).flat();
};
export const skillsInverted = (skills: TechKeys[]): string[] => {
return techKeys
.filter((k) => !skills.includes(k))
.map((s) => tech[s])
.flat();
};