mirror of
https://github.com/AmruthPillai/Reactive-Resume.git
synced 2025-11-13 00:03:27 +10:00
feat(templates): redesign and add back in the original templates from v3
This commit is contained in:
@ -23,7 +23,6 @@ export const Page = ({ mode = "preview", pageNumber, children }: Props) => {
|
||||
className={cn("relative bg-white", mode === "builder" && "shadow-2xl")}
|
||||
style={{
|
||||
fontFamily,
|
||||
padding: page.margin,
|
||||
width: `${pageSizeMap[page.format].width * MM_TO_PX}px`,
|
||||
minHeight: `${pageSizeMap[page.format].height * MM_TO_PX}px`,
|
||||
}}
|
||||
|
||||
@ -32,6 +32,7 @@ export const ArtboardPage = () => {
|
||||
document.documentElement.style.setProperty("font-size", `${metadata.typography.font.size}px`);
|
||||
document.documentElement.style.setProperty("line-height", `${metadata.typography.lineHeight}`);
|
||||
|
||||
document.documentElement.style.setProperty("--margin", `${metadata.page.margin}px`);
|
||||
document.documentElement.style.setProperty("--font-size", `${metadata.typography.font.size}px`);
|
||||
document.documentElement.style.setProperty(
|
||||
"--line-height",
|
||||
|
||||
@ -486,7 +486,7 @@ export const Azurill = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<div className="p-custom space-y-3">
|
||||
{isFirstPage && <Header />}
|
||||
|
||||
<div className="grid grid-cols-3 gap-x-4">
|
||||
|
||||
@ -497,7 +497,7 @@ export const Bronzor = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="p-custom space-y-4">
|
||||
{isFirstPage && <Header />}
|
||||
|
||||
<div className="space-y-4">
|
||||
|
||||
@ -29,47 +29,45 @@ const Header = () => {
|
||||
const basics = useArtboardStore((state) => state.resume.basics);
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-3">
|
||||
<div className="col-span-2 flex items-center gap-x-4">
|
||||
<Picture />
|
||||
<div className="flex items-center space-x-4">
|
||||
<Picture />
|
||||
|
||||
<div className="space-y-2">
|
||||
<div>
|
||||
<div className="text-2xl font-bold">{basics.name}</div>
|
||||
<div className="text-base">{basics.headline}</div>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<div>
|
||||
<div className="text-2xl font-bold">{basics.name}</div>
|
||||
<div className="text-base">{basics.headline}</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-sm">
|
||||
{basics.location && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-map-pin text-primary" />
|
||||
<div>{basics.location}</div>
|
||||
</div>
|
||||
)}
|
||||
{basics.phone && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-phone text-primary" />
|
||||
<a href={`tel:${basics.phone}`} target="_blank" rel="noreferrer">
|
||||
{basics.phone}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
{basics.email && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-at text-primary" />
|
||||
<a href={`mailto:${basics.email}`} target="_blank" rel="noreferrer">
|
||||
{basics.email}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<Link url={basics.url} />
|
||||
{basics.customFields.map((item) => (
|
||||
<div key={item.id} className="flex items-center gap-x-1.5">
|
||||
<i className={cn(`ph ph-bold ph-${item.icon}`, "text-primary")} />
|
||||
<span>{[item.name, item.value].filter(Boolean).join(": ")}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-sm">
|
||||
{basics.location && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-map-pin text-primary" />
|
||||
<div>{basics.location}</div>
|
||||
</div>
|
||||
)}
|
||||
{basics.phone && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-phone text-primary" />
|
||||
<a href={`tel:${basics.phone}`} target="_blank" rel="noreferrer">
|
||||
{basics.phone}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
{basics.email && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-at text-primary" />
|
||||
<a href={`mailto:${basics.email}`} target="_blank" rel="noreferrer">
|
||||
{basics.email}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<Link url={basics.url} />
|
||||
{basics.customFields.map((item) => (
|
||||
<div key={item.id} className="flex items-center gap-x-1.5">
|
||||
<i className={cn(`ph ph-bold ph-${item.icon}`, "text-primary")} />
|
||||
<span>{[item.name, item.value].filter(Boolean).join(": ")}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -497,35 +495,23 @@ const mapSectionToComponent = (section: SectionKey) => {
|
||||
};
|
||||
|
||||
export const Chikorita = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const margin = useArtboardStore((state) => state.resume.metadata.page.margin);
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="space-y-4">
|
||||
<div className="grid h-full grid-cols-3">
|
||||
<div className="main p-custom group col-span-2 space-y-4">
|
||||
{isFirstPage && <Header />}
|
||||
|
||||
<div className="relative z-10 grid grid-cols-3 space-x-8">
|
||||
<div className="main group col-span-2 space-y-4">
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="sidebar group space-y-4 text-background">
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div
|
||||
style={{ columnGap: margin }}
|
||||
className="pointer-events-none absolute inset-0 grid grid-cols-3"
|
||||
>
|
||||
<div className="col-start-3 bg-primary" />
|
||||
<div className="sidebar p-custom group h-full space-y-4 bg-primary text-background">
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -29,16 +29,16 @@ const Header = () => {
|
||||
const basics = useArtboardStore((state) => state.resume.basics);
|
||||
|
||||
return (
|
||||
<div className="relative z-20 grid grid-cols-3 space-x-4">
|
||||
<div className="mx-auto">
|
||||
<Picture />
|
||||
</div>
|
||||
<div className="p-custom relative grid grid-cols-3 space-x-4 pb-0">
|
||||
<Picture className="mx-auto" />
|
||||
|
||||
<div className="col-span-2 space-y-0.5 text-background">
|
||||
<h2 className="min-h-[30px] text-4xl font-bold">{basics.name}</h2>
|
||||
<p className="min-h-[24px]">{basics.headline}</p>
|
||||
<div className="relative z-10 col-span-2 text-background">
|
||||
<div className="space-y-0.5">
|
||||
<h2 className="text-3xl font-bold">{basics.name}</h2>
|
||||
<p>{basics.headline}</p>
|
||||
</div>
|
||||
|
||||
<div className="text-text !mt-10">
|
||||
<div className="text-text col-span-2 col-start-2 mt-10">
|
||||
<div className="flex flex-wrap items-center gap-x-2 gap-y-0.5 text-sm">
|
||||
{basics.location && (
|
||||
<>
|
||||
@ -524,19 +524,22 @@ export const Ditto = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
{isFirstPage && <div className="absolute inset-x-0 top-0 z-10 h-32 bg-primary" />}
|
||||
<div>
|
||||
{isFirstPage && (
|
||||
<div className="relative">
|
||||
<Header />
|
||||
<div className="absolute inset-x-0 top-0 h-[85px] w-full bg-primary" />
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isFirstPage && <Header />}
|
||||
|
||||
<div className="grid grid-cols-3 space-x-4">
|
||||
<div className="sidebar group space-y-4">
|
||||
<div className="grid grid-cols-3">
|
||||
<div className="sidebar p-custom group space-y-4">
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="main group col-span-2 space-y-4">
|
||||
<div className="main p-custom group col-span-2 space-y-4">
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
|
||||
533
apps/artboard/src/templates/gengar.tsx
Normal file
533
apps/artboard/src/templates/gengar.tsx
Normal file
@ -0,0 +1,533 @@
|
||||
import {
|
||||
Award,
|
||||
Certification,
|
||||
CustomSection,
|
||||
CustomSectionGroup,
|
||||
Education,
|
||||
Experience,
|
||||
Interest,
|
||||
Language,
|
||||
Profile,
|
||||
Project,
|
||||
Publication,
|
||||
Reference,
|
||||
SectionKey,
|
||||
SectionWithItem,
|
||||
Skill,
|
||||
URL,
|
||||
Volunteer,
|
||||
} from "@reactive-resume/schema";
|
||||
import { cn, hexToRgb, isEmptyString, isUrl } from "@reactive-resume/utils";
|
||||
import get from "lodash.get";
|
||||
import { Fragment } from "react";
|
||||
|
||||
import { Picture } from "../components/picture";
|
||||
import { useArtboardStore } from "../store/artboard";
|
||||
import { TemplateProps } from "../types/template";
|
||||
|
||||
const Header = () => {
|
||||
const basics = useArtboardStore((state) => state.resume.basics);
|
||||
|
||||
return (
|
||||
<div className="p-custom space-y-4 bg-primary text-background">
|
||||
<Picture className="border-background" />
|
||||
|
||||
<div>
|
||||
<h2 className="text-2xl font-bold">{basics.name}</h2>
|
||||
<p>{basics.headline}</p>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-start gap-y-2 text-sm">
|
||||
{basics.location && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-map-pin" />
|
||||
<div>{basics.location}</div>
|
||||
</div>
|
||||
)}
|
||||
{basics.phone && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-phone" />
|
||||
<a href={`tel:${basics.phone}`} target="_blank" rel="noreferrer">
|
||||
{basics.phone}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
{basics.email && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-at" />
|
||||
<a href={`mailto:${basics.email}`} target="_blank" rel="noreferrer">
|
||||
{basics.email}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
{isUrl(basics.url.href) && <Link url={basics.url} />}
|
||||
{basics.customFields.map((item) => (
|
||||
<Fragment key={item.id}>
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className={cn(`ph ph-bold ph-${item.icon}`)} />
|
||||
<span>{[item.name, item.value].filter(Boolean).join(": ")}</span>
|
||||
</div>
|
||||
</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Summary = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.summary);
|
||||
|
||||
if (!section.visible || isEmptyString(section.content)) return null;
|
||||
|
||||
return (
|
||||
<section id={section.id}>
|
||||
<div
|
||||
className="wysiwyg"
|
||||
style={{ columns: section.columns }}
|
||||
dangerouslySetInnerHTML={{ __html: section.content }}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
type RatingProps = { level: number };
|
||||
|
||||
const Rating = ({ level }: RatingProps) => (
|
||||
<div className="flex items-center gap-x-1">
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={cn("h-2.5 w-5 border border-primary", level > index && "bg-primary")}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
type LinkProps = {
|
||||
url: URL;
|
||||
icon?: React.ReactNode;
|
||||
label?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const Link = ({ url, icon, label, className }: LinkProps) => {
|
||||
if (!isUrl(url.href)) return null;
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
{icon ?? <i className="ph ph-bold ph-link text-primary group-[.sidebar]:text-background" />}
|
||||
<a
|
||||
href={url.href}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
className={cn("inline-block", className)}
|
||||
>
|
||||
{label || url.label || url.href}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type SectionProps<T> = {
|
||||
section: SectionWithItem<T> | CustomSectionGroup;
|
||||
children?: (item: T) => React.ReactNode;
|
||||
className?: string;
|
||||
urlKey?: keyof T;
|
||||
levelKey?: keyof T;
|
||||
summaryKey?: keyof T;
|
||||
keywordsKey?: keyof T;
|
||||
};
|
||||
|
||||
const Section = <T,>({
|
||||
section,
|
||||
children,
|
||||
className,
|
||||
urlKey,
|
||||
levelKey,
|
||||
summaryKey,
|
||||
keywordsKey,
|
||||
}: SectionProps<T>) => {
|
||||
if (!section.visible || !section.items.length) return null;
|
||||
|
||||
return (
|
||||
<section id={section.id} className="grid">
|
||||
<h4 className="mb-2 border-b border-primary text-base font-bold">{section.name}</h4>
|
||||
|
||||
<div
|
||||
className="grid gap-x-6 gap-y-3"
|
||||
style={{ gridTemplateColumns: `repeat(${section.columns}, 1fr)` }}
|
||||
>
|
||||
{section.items
|
||||
.filter((item) => item.visible)
|
||||
.map((item) => {
|
||||
const url = (urlKey && get(item, urlKey)) as URL | undefined;
|
||||
const level = (levelKey && get(item, levelKey, 0)) as number | undefined;
|
||||
const summary = (summaryKey && get(item, summaryKey, "")) as string | undefined;
|
||||
const keywords = (keywordsKey && get(item, keywordsKey, [])) as string[] | undefined;
|
||||
|
||||
return (
|
||||
<div key={item.id} className={cn("space-y-2", className)}>
|
||||
<div>
|
||||
{children?.(item as T)}
|
||||
{url !== undefined && <Link url={url} />}
|
||||
</div>
|
||||
|
||||
{summary !== undefined && !isEmptyString(summary) && (
|
||||
<div className="wysiwyg" dangerouslySetInnerHTML={{ __html: summary }} />
|
||||
)}
|
||||
|
||||
{level !== undefined && level > 0 && <Rating level={level} />}
|
||||
|
||||
{keywords !== undefined && keywords.length > 0 && (
|
||||
<p className="text-sm">{keywords.join(", ")}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
const Profiles = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.profiles);
|
||||
const fontSize = useArtboardStore((state) => state.resume.metadata.typography.font.size);
|
||||
|
||||
return (
|
||||
<Section<Profile> section={section}>
|
||||
{(item) => (
|
||||
<div>
|
||||
{isUrl(item.url.href) ? (
|
||||
<Link
|
||||
url={item.url}
|
||||
label={item.username}
|
||||
icon={
|
||||
<img
|
||||
className="ph"
|
||||
width={fontSize}
|
||||
height={fontSize}
|
||||
alt={item.network}
|
||||
src={`https://cdn.simpleicons.org/${item.icon}`}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<p>{item.username}</p>
|
||||
)}
|
||||
<p className="text-sm">{item.network}</p>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Experience = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.experience);
|
||||
|
||||
return (
|
||||
<Section<Experience> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.company}</div>
|
||||
<div>{item.position}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right group-[.sidebar]:text-left">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
<div>{item.location}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Education = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.education);
|
||||
|
||||
return (
|
||||
<Section<Education> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.institution}</div>
|
||||
<div>{item.area}</div>
|
||||
<div>{item.score}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right group-[.sidebar]:text-left">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
<div>{item.studyType}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Awards = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.awards);
|
||||
|
||||
return (
|
||||
<Section<Award> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.title}</div>
|
||||
<div>{item.awarder}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right group-[.sidebar]:text-left">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Certifications = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.certifications);
|
||||
|
||||
return (
|
||||
<Section<Certification> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.issuer}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right group-[.sidebar]:text-left">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Skills = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.skills);
|
||||
|
||||
return (
|
||||
<Section<Skill> section={section} levelKey="level" keywordsKey="keywords">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Interests = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.interests);
|
||||
|
||||
return (
|
||||
<Section<Interest> section={section} className="space-y-1" keywordsKey="keywords">
|
||||
{(item) => <div className="font-bold">{item.name}</div>}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Publications = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.publications);
|
||||
|
||||
return (
|
||||
<Section<Publication> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.publisher}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right group-[.sidebar]:text-left">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Volunteer = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.volunteer);
|
||||
|
||||
return (
|
||||
<Section<Volunteer> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.organization}</div>
|
||||
<div>{item.position}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right group-[.sidebar]:text-left">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
<div>{item.location}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Languages = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.languages);
|
||||
|
||||
return (
|
||||
<Section<Language> section={section} levelKey="level">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Projects = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.projects);
|
||||
|
||||
return (
|
||||
<Section<Project> section={section} urlKey="url" summaryKey="summary" keywordsKey="keywords">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right group-[.sidebar]:text-left">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const References = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.references);
|
||||
|
||||
return (
|
||||
<Section<Reference> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Custom = ({ id }: { id: string }) => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.custom[id]);
|
||||
|
||||
return (
|
||||
<Section<CustomSection>
|
||||
section={section}
|
||||
urlKey="url"
|
||||
summaryKey="summary"
|
||||
keywordsKey="keywords"
|
||||
>
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right group-[.sidebar]:text-left">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
<div>{item.location}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const mapSectionToComponent = (section: SectionKey) => {
|
||||
switch (section) {
|
||||
case "profiles":
|
||||
return <Profiles />;
|
||||
case "experience":
|
||||
return <Experience />;
|
||||
case "education":
|
||||
return <Education />;
|
||||
case "awards":
|
||||
return <Awards />;
|
||||
case "certifications":
|
||||
return <Certifications />;
|
||||
case "skills":
|
||||
return <Skills />;
|
||||
case "interests":
|
||||
return <Interests />;
|
||||
case "publications":
|
||||
return <Publications />;
|
||||
case "volunteer":
|
||||
return <Volunteer />;
|
||||
case "languages":
|
||||
return <Languages />;
|
||||
case "projects":
|
||||
return <Projects />;
|
||||
case "references":
|
||||
return <References />;
|
||||
default:
|
||||
if (section.startsWith("custom.")) return <Custom id={section.split(".")[1]} />;
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const Gengar = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
const primaryColor = useArtboardStore((state) => state.resume.metadata.theme.primary);
|
||||
|
||||
return (
|
||||
<div className="grid min-h-[inherit] grid-cols-3">
|
||||
<div
|
||||
className={cn(
|
||||
"sidebar group flex flex-col",
|
||||
!(isFirstPage || sidebar.length > 0) && "hidden",
|
||||
)}
|
||||
>
|
||||
{isFirstPage && <Header />}
|
||||
|
||||
<div
|
||||
className="p-custom flex-1 space-y-4"
|
||||
style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }}
|
||||
>
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="main group col-span-2">
|
||||
{isFirstPage && (
|
||||
<div
|
||||
className="p-custom space-y-4"
|
||||
style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }}
|
||||
>
|
||||
<Summary />
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="p-custom space-y-4">
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
527
apps/artboard/src/templates/glalie.tsx
Normal file
527
apps/artboard/src/templates/glalie.tsx
Normal file
@ -0,0 +1,527 @@
|
||||
import {
|
||||
Award,
|
||||
Certification,
|
||||
CustomSection,
|
||||
CustomSectionGroup,
|
||||
Education,
|
||||
Experience,
|
||||
Interest,
|
||||
Language,
|
||||
Profile,
|
||||
Project,
|
||||
Publication,
|
||||
Reference,
|
||||
SectionKey,
|
||||
SectionWithItem,
|
||||
Skill,
|
||||
URL,
|
||||
Volunteer,
|
||||
} from "@reactive-resume/schema";
|
||||
import { cn, hexToRgb, isEmptyString, isUrl, linearTransform } from "@reactive-resume/utils";
|
||||
import get from "lodash.get";
|
||||
import { Fragment } from "react";
|
||||
|
||||
import { Picture } from "../components/picture";
|
||||
import { useArtboardStore } from "../store/artboard";
|
||||
import { TemplateProps } from "../types/template";
|
||||
|
||||
const Header = () => {
|
||||
const basics = useArtboardStore((state) => state.resume.basics);
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center space-y-4 text-center">
|
||||
<Picture />
|
||||
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<div className="text-2xl font-bold">{basics.name}</div>
|
||||
<div className="text-base">{basics.headline}</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col items-start gap-y-1.5 rounded border border-primary px-3 py-4 text-left text-sm">
|
||||
{basics.location && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-map-pin text-primary" />
|
||||
<div>{basics.location}</div>
|
||||
</div>
|
||||
)}
|
||||
{basics.phone && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-phone text-primary" />
|
||||
<a href={`tel:${basics.phone}`} target="_blank" rel="noreferrer">
|
||||
{basics.phone}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
{basics.email && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-at text-primary" />
|
||||
<a href={`mailto:${basics.email}`} target="_blank" rel="noreferrer">
|
||||
{basics.email}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<Link url={basics.url} />
|
||||
{basics.customFields.map((item) => (
|
||||
<div key={item.id} className="flex items-center gap-x-1.5">
|
||||
<i className={cn(`ph ph-bold ph-${item.icon} text-primary`)} />
|
||||
<span>{[item.name, item.value].filter(Boolean).join(": ")}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const Summary = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.summary);
|
||||
|
||||
if (!section.visible || isEmptyString(section.content)) return null;
|
||||
|
||||
return (
|
||||
<section id={section.id}>
|
||||
<h4 className="mb-2 border-b pb-0.5 text-sm font-bold">{section.name}</h4>
|
||||
|
||||
<div
|
||||
className="wysiwyg"
|
||||
style={{ columns: section.columns }}
|
||||
dangerouslySetInnerHTML={{ __html: section.content }}
|
||||
/>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
type RatingProps = { level: number };
|
||||
|
||||
const Rating = ({ level }: RatingProps) => {
|
||||
const primaryColor = useArtboardStore((state) => state.resume.metadata.theme.primary);
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<div
|
||||
className="h-2.5 w-full rounded-sm"
|
||||
style={{ backgroundColor: hexToRgb(primaryColor, 0.4) }}
|
||||
/>
|
||||
<div
|
||||
className="absolute inset-y-0 left-0 h-2.5 w-full rounded-sm bg-primary"
|
||||
style={{ width: `${linearTransform(level, 0, 5, 0, 100)}%` }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type LinkProps = {
|
||||
url: URL;
|
||||
icon?: React.ReactNode;
|
||||
label?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const Link = ({ url, icon, label, className }: LinkProps) => {
|
||||
if (!isUrl(url.href)) return null;
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
{icon ?? <i className="ph ph-bold ph-link text-primary group-[.sidebar]:text-primary" />}
|
||||
<a
|
||||
href={url.href}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
className={cn("inline-block", className)}
|
||||
>
|
||||
{label || url.label || url.href}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type SectionProps<T> = {
|
||||
section: SectionWithItem<T> | CustomSectionGroup;
|
||||
children?: (item: T) => React.ReactNode;
|
||||
className?: string;
|
||||
urlKey?: keyof T;
|
||||
levelKey?: keyof T;
|
||||
summaryKey?: keyof T;
|
||||
keywordsKey?: keyof T;
|
||||
};
|
||||
|
||||
const Section = <T,>({
|
||||
section,
|
||||
children,
|
||||
className,
|
||||
urlKey,
|
||||
levelKey,
|
||||
summaryKey,
|
||||
keywordsKey,
|
||||
}: SectionProps<T>) => {
|
||||
if (!section.visible || !section.items.length) return null;
|
||||
|
||||
return (
|
||||
<section id={section.id} className="grid">
|
||||
<h4 className="mb-2 border-b pb-0.5 text-sm font-bold group-[.sidebar]:text-primary">
|
||||
{section.name}
|
||||
</h4>
|
||||
|
||||
<div
|
||||
className="grid gap-x-6 gap-y-3"
|
||||
style={{ gridTemplateColumns: `repeat(${section.columns}, 1fr)` }}
|
||||
>
|
||||
{section.items
|
||||
.filter((item) => item.visible)
|
||||
.map((item) => {
|
||||
const url = (urlKey && get(item, urlKey)) as URL | undefined;
|
||||
const level = (levelKey && get(item, levelKey, 0)) as number | undefined;
|
||||
const summary = (summaryKey && get(item, summaryKey, "")) as string | undefined;
|
||||
const keywords = (keywordsKey && get(item, keywordsKey, [])) as string[] | undefined;
|
||||
|
||||
return (
|
||||
<div key={item.id} className={cn("space-y-2", className)}>
|
||||
<div>
|
||||
{children?.(item as T)}
|
||||
{url !== undefined && <Link url={url} />}
|
||||
</div>
|
||||
|
||||
{summary !== undefined && !isEmptyString(summary) && (
|
||||
<div className="wysiwyg" dangerouslySetInnerHTML={{ __html: summary }} />
|
||||
)}
|
||||
|
||||
{level !== undefined && level > 0 && <Rating level={level} />}
|
||||
|
||||
{keywords !== undefined && keywords.length > 0 && (
|
||||
<p className="text-sm">{keywords.join(", ")}</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
const Experience = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.experience);
|
||||
|
||||
return (
|
||||
<Section<Experience> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.company}</div>
|
||||
<div>{item.position}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
<div>{item.location}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Education = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.education);
|
||||
|
||||
return (
|
||||
<Section<Education> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.institution}</div>
|
||||
<div>{item.area}</div>
|
||||
<div>{item.score}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
<div>{item.studyType}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Profiles = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.profiles);
|
||||
const fontSize = useArtboardStore((state) => state.resume.metadata.typography.font.size);
|
||||
|
||||
return (
|
||||
<Section<Profile> section={section}>
|
||||
{(item) => (
|
||||
<div>
|
||||
{isUrl(item.url.href) ? (
|
||||
<Link
|
||||
url={item.url}
|
||||
label={item.username}
|
||||
icon={
|
||||
<img
|
||||
className="ph"
|
||||
width={fontSize}
|
||||
height={fontSize}
|
||||
alt={item.network}
|
||||
src={`https://cdn.simpleicons.org/${item.icon}`}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<p>{item.username}</p>
|
||||
)}
|
||||
<p className="text-sm">{item.network}</p>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Awards = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.awards);
|
||||
|
||||
return (
|
||||
<Section<Award> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.title}</div>
|
||||
<div>{item.awarder}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Certifications = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.certifications);
|
||||
|
||||
return (
|
||||
<Section<Certification> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.issuer}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Skills = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.skills);
|
||||
|
||||
return (
|
||||
<Section<Skill> section={section} levelKey="level" keywordsKey="keywords">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Interests = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.interests);
|
||||
|
||||
return (
|
||||
<Section<Interest> section={section} keywordsKey="keywords" className="space-y-0.5">
|
||||
{(item) => <div className="font-bold">{item.name}</div>}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Publications = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.publications);
|
||||
|
||||
return (
|
||||
<Section<Publication> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.publisher}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Volunteer = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.volunteer);
|
||||
|
||||
return (
|
||||
<Section<Volunteer> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.organization}</div>
|
||||
<div>{item.position}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
<div>{item.location}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Languages = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.languages);
|
||||
|
||||
return (
|
||||
<Section<Language> section={section} levelKey="level">
|
||||
{(item) => (
|
||||
<div className="space-y-0.5">
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Projects = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.projects);
|
||||
|
||||
return (
|
||||
<Section<Project> section={section} urlKey="url" summaryKey="summary" keywordsKey="keywords">
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const References = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.references);
|
||||
|
||||
return (
|
||||
<Section<Reference> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Custom = ({ id }: { id: string }) => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.custom[id]);
|
||||
|
||||
return (
|
||||
<Section<CustomSection>
|
||||
section={section}
|
||||
urlKey="url"
|
||||
summaryKey="summary"
|
||||
keywordsKey="keywords"
|
||||
>
|
||||
{(item) => (
|
||||
<div className="flex items-center justify-between group-[.sidebar]:flex-col group-[.sidebar]:items-start">
|
||||
<div className="text-left">
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
|
||||
<div className="shrink-0 text-right">
|
||||
<div className="font-bold">{item.date}</div>
|
||||
<div>{item.location}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const mapSectionToComponent = (section: SectionKey) => {
|
||||
switch (section) {
|
||||
case "profiles":
|
||||
return <Profiles />;
|
||||
case "summary":
|
||||
return <Summary />;
|
||||
case "experience":
|
||||
return <Experience />;
|
||||
case "education":
|
||||
return <Education />;
|
||||
case "awards":
|
||||
return <Awards />;
|
||||
case "certifications":
|
||||
return <Certifications />;
|
||||
case "skills":
|
||||
return <Skills />;
|
||||
case "interests":
|
||||
return <Interests />;
|
||||
case "publications":
|
||||
return <Publications />;
|
||||
case "volunteer":
|
||||
return <Volunteer />;
|
||||
case "languages":
|
||||
return <Languages />;
|
||||
case "projects":
|
||||
return <Projects />;
|
||||
case "references":
|
||||
return <References />;
|
||||
default:
|
||||
if (section.startsWith("custom.")) return <Custom id={section.split(".")[1]} />;
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const Glalie = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
const primaryColor = useArtboardStore((state) => state.resume.metadata.theme.primary);
|
||||
|
||||
return (
|
||||
<div className="grid min-h-[inherit] grid-cols-3">
|
||||
<div
|
||||
className="sidebar p-custom group space-y-4"
|
||||
style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }}
|
||||
>
|
||||
{isFirstPage && <Header />}
|
||||
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="main p-custom group col-span-2 space-y-4">
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -4,7 +4,10 @@ import { Azurill } from "./azurill";
|
||||
import { Bronzor } from "./bronzor";
|
||||
import { Chikorita } from "./chikorita";
|
||||
import { Ditto } from "./ditto";
|
||||
import { Gengar } from "./gengar";
|
||||
import { Glalie } from "./glalie";
|
||||
import { Kakuna } from "./kakuna";
|
||||
import { Leafish } from "./leafish";
|
||||
import { Nosepass } from "./nosepass";
|
||||
import { Onyx } from "./onyx";
|
||||
import { Pikachu } from "./pikachu";
|
||||
@ -12,24 +15,30 @@ import { Rhyhorn } from "./rhyhorn";
|
||||
|
||||
export const getTemplate = (template: Template) => {
|
||||
switch (template) {
|
||||
case "onyx":
|
||||
return Onyx;
|
||||
case "kakuna":
|
||||
return Kakuna;
|
||||
case "rhyhorn":
|
||||
return Rhyhorn;
|
||||
case "azurill":
|
||||
return Azurill;
|
||||
case "ditto":
|
||||
return Ditto;
|
||||
case "chikorita":
|
||||
return Chikorita;
|
||||
case "bronzor":
|
||||
return Bronzor;
|
||||
case "pikachu":
|
||||
return Pikachu;
|
||||
case "chikorita":
|
||||
return Chikorita;
|
||||
case "ditto":
|
||||
return Ditto;
|
||||
case "gengar":
|
||||
return Gengar;
|
||||
case "glalie":
|
||||
return Glalie;
|
||||
case "kakuna":
|
||||
return Kakuna;
|
||||
case "leafish":
|
||||
return Leafish;
|
||||
case "nosepass":
|
||||
return Nosepass;
|
||||
case "onyx":
|
||||
return Onyx;
|
||||
case "pikachu":
|
||||
return Pikachu;
|
||||
case "rhyhorn":
|
||||
return Rhyhorn;
|
||||
default:
|
||||
return Onyx;
|
||||
}
|
||||
|
||||
@ -452,7 +452,7 @@ export const Kakuna = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="p-custom space-y-4">
|
||||
{isFirstPage && <Header />}
|
||||
|
||||
<div className="space-y-4">
|
||||
|
||||
468
apps/artboard/src/templates/leafish.tsx
Normal file
468
apps/artboard/src/templates/leafish.tsx
Normal file
@ -0,0 +1,468 @@
|
||||
import {
|
||||
Award,
|
||||
Certification,
|
||||
CustomSection,
|
||||
CustomSectionGroup,
|
||||
Education,
|
||||
Experience,
|
||||
Interest,
|
||||
Language,
|
||||
Project,
|
||||
Publication,
|
||||
Reference,
|
||||
SectionKey,
|
||||
SectionWithItem,
|
||||
Skill,
|
||||
URL,
|
||||
Volunteer,
|
||||
} from "@reactive-resume/schema";
|
||||
import { cn, hexToRgb, isEmptyString, isUrl } from "@reactive-resume/utils";
|
||||
import get from "lodash.get";
|
||||
import React, { Fragment } from "react";
|
||||
|
||||
import { Picture } from "../components/picture";
|
||||
import { useArtboardStore } from "../store/artboard";
|
||||
import { TemplateProps } from "../types/template";
|
||||
|
||||
const Header = () => {
|
||||
const basics = useArtboardStore((state) => state.resume.basics);
|
||||
const section = useArtboardStore((state) => state.resume.sections.summary);
|
||||
const profiles = useArtboardStore((state) => state.resume.sections.profiles);
|
||||
const primaryColor = useArtboardStore((state) => state.resume.metadata.theme.primary);
|
||||
const fontSize = useArtboardStore((state) => state.resume.metadata.typography.font.size);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div
|
||||
className="p-custom flex items-center space-x-8"
|
||||
style={{ backgroundColor: hexToRgb(primaryColor, 0.2) }}
|
||||
>
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
<div className="text-3xl font-bold">{basics.name}</div>
|
||||
<div className="text-base font-medium text-primary">{basics.headline}</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="wysiwyg"
|
||||
style={{ columns: section.columns }}
|
||||
dangerouslySetInnerHTML={{ __html: section.content }}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Picture />
|
||||
</div>
|
||||
|
||||
<div className="p-custom space-y-3" style={{ backgroundColor: hexToRgb(primaryColor, 0.4) }}>
|
||||
<div className="flex flex-wrap items-center gap-x-3 gap-y-0.5 text-sm">
|
||||
{basics.location && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-map-pin text-primary" />
|
||||
<div>{basics.location}</div>
|
||||
</div>
|
||||
)}
|
||||
{basics.phone && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-phone text-primary" />
|
||||
<a href={`tel:${basics.phone}`} target="_blank" rel="noreferrer">
|
||||
{basics.phone}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
{basics.email && (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
<i className="ph ph-bold ph-at text-primary" />
|
||||
<a href={`mailto:${basics.email}`} target="_blank" rel="noreferrer">
|
||||
{basics.email}
|
||||
</a>
|
||||
</div>
|
||||
)}
|
||||
<Link url={basics.url} />
|
||||
{basics.customFields.map((item) => (
|
||||
<div key={item.id} className="flex items-center gap-x-1.5">
|
||||
<i className={cn(`ph ph-bold ph-${item.icon}`, "text-primary")} />
|
||||
<span>{[item.name, item.value].filter(Boolean).join(": ")}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{profiles.visible && profiles.items.length > 0 && (
|
||||
<div className="flex items-center gap-x-3 gap-y-0.5">
|
||||
{profiles.items
|
||||
.filter((item) => item.visible)
|
||||
.map((item) => (
|
||||
<div key={item.id} className="flex items-center gap-x-2">
|
||||
<Link
|
||||
url={item.url}
|
||||
label={item.username}
|
||||
className="text-sm"
|
||||
icon={
|
||||
<img
|
||||
className="ph"
|
||||
width={fontSize}
|
||||
height={fontSize}
|
||||
alt={item.network}
|
||||
src={`https://cdn.simpleicons.org/${item.icon}`}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type RatingProps = { level: number };
|
||||
|
||||
const Rating = ({ level }: RatingProps) => (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
{Array.from({ length: 5 }).map((_, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={cn("h-3 w-6 border-2 border-primary", level > index && "bg-primary")}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
type LinkProps = {
|
||||
url: URL;
|
||||
icon?: React.ReactNode;
|
||||
label?: string;
|
||||
className?: string;
|
||||
};
|
||||
|
||||
const Link = ({ url, icon, label, className }: LinkProps) => {
|
||||
if (!isUrl(url.href)) return null;
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-x-1.5">
|
||||
{icon ?? <i className="ph ph-bold ph-link text-primary" />}
|
||||
<a
|
||||
href={url.href}
|
||||
target="_blank"
|
||||
rel="noreferrer noopener nofollow"
|
||||
className={cn("inline-block", className)}
|
||||
>
|
||||
{label || url.label || url.href}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
type SectionProps<T> = {
|
||||
section: SectionWithItem<T> | CustomSectionGroup;
|
||||
children?: (item: T) => React.ReactNode;
|
||||
className?: string;
|
||||
urlKey?: keyof T;
|
||||
levelKey?: keyof T;
|
||||
summaryKey?: keyof T;
|
||||
keywordsKey?: keyof T;
|
||||
};
|
||||
|
||||
const Section = <T,>({
|
||||
section,
|
||||
children,
|
||||
className,
|
||||
urlKey,
|
||||
levelKey,
|
||||
summaryKey,
|
||||
keywordsKey,
|
||||
}: SectionProps<T>) => {
|
||||
if (!section.visible || !section.items.length) return null;
|
||||
|
||||
return (
|
||||
<section id={section.id} className="grid">
|
||||
<h4 className="mb-2 border-b border-primary text-left font-bold text-primary">
|
||||
{section.name}
|
||||
</h4>
|
||||
|
||||
<div
|
||||
className="grid gap-x-6 gap-y-3"
|
||||
style={{ gridTemplateColumns: `repeat(${section.columns}, 1fr)` }}
|
||||
>
|
||||
{section.items
|
||||
.filter((item) => item.visible)
|
||||
.map((item) => {
|
||||
const url = (urlKey && get(item, urlKey)) as URL | undefined;
|
||||
const level = (levelKey && get(item, levelKey, 0)) as number | undefined;
|
||||
const summary = (summaryKey && get(item, summaryKey, "")) as string | undefined;
|
||||
const keywords = (keywordsKey && get(item, keywordsKey, [])) as string[] | undefined;
|
||||
|
||||
return (
|
||||
<div key={item.id} className={cn("space-y-2", className)}>
|
||||
<div>{children?.(item as T)}</div>
|
||||
|
||||
{summary !== undefined && !isEmptyString(summary) && (
|
||||
<div className="wysiwyg" dangerouslySetInnerHTML={{ __html: summary }} />
|
||||
)}
|
||||
|
||||
{level !== undefined && level > 0 && <Rating level={level} />}
|
||||
|
||||
{keywords !== undefined && keywords.length > 0 && (
|
||||
<p className="text-sm">{keywords.join(", ")}</p>
|
||||
)}
|
||||
|
||||
{url !== undefined && <Link url={url} />}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
const Experience = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.experience);
|
||||
|
||||
return (
|
||||
<Section<Experience> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.company}</div>
|
||||
<div>{item.position}</div>
|
||||
<div>{item.location}</div>
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Education = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.education);
|
||||
|
||||
return (
|
||||
<Section<Education> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.institution}</div>
|
||||
<div>{item.area}</div>
|
||||
<div>{item.score}</div>
|
||||
<div>{item.studyType}</div>
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Awards = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.awards);
|
||||
|
||||
return (
|
||||
<Section<Award> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.title}</div>
|
||||
<div>{item.awarder}</div>
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Certifications = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.certifications);
|
||||
|
||||
return (
|
||||
<Section<Certification> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.issuer}</div>
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Skills = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.skills);
|
||||
|
||||
return (
|
||||
<Section<Skill> section={section} levelKey="level" keywordsKey="keywords">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Interests = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.interests);
|
||||
|
||||
return (
|
||||
<Section<Interest> section={section} keywordsKey="keywords" className="space-y-0.5">
|
||||
{(item) => <div className="font-bold">{item.name}</div>}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Publications = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.publications);
|
||||
|
||||
return (
|
||||
<Section<Publication> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.publisher}</div>
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Volunteer = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.volunteer);
|
||||
|
||||
return (
|
||||
<Section<Volunteer> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.organization}</div>
|
||||
<div>{item.position}</div>
|
||||
<div>{item.location}</div>
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Languages = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.languages);
|
||||
|
||||
return (
|
||||
<Section<Language> section={section} levelKey="level">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Projects = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.projects);
|
||||
|
||||
return (
|
||||
<Section<Project> section={section} urlKey="url" summaryKey="summary" keywordsKey="keywords">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const References = () => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.references);
|
||||
|
||||
return (
|
||||
<Section<Reference> section={section} urlKey="url" summaryKey="summary">
|
||||
{(item) => (
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const Custom = ({ id }: { id: string }) => {
|
||||
const section = useArtboardStore((state) => state.resume.sections.custom[id]);
|
||||
|
||||
return (
|
||||
<Section<CustomSection>
|
||||
section={section}
|
||||
urlKey="url"
|
||||
summaryKey="summary"
|
||||
keywordsKey="keywords"
|
||||
>
|
||||
{(item) => (
|
||||
<div>
|
||||
<div>
|
||||
<div className="font-bold">{item.name}</div>
|
||||
<div>{item.description}</div>
|
||||
<div>{item.location}</div>
|
||||
<div className="font-bold">{item.date}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const mapSectionToComponent = (section: SectionKey) => {
|
||||
switch (section) {
|
||||
case "experience":
|
||||
return <Experience />;
|
||||
case "education":
|
||||
return <Education />;
|
||||
case "awards":
|
||||
return <Awards />;
|
||||
case "certifications":
|
||||
return <Certifications />;
|
||||
case "skills":
|
||||
return <Skills />;
|
||||
case "interests":
|
||||
return <Interests />;
|
||||
case "publications":
|
||||
return <Publications />;
|
||||
case "volunteer":
|
||||
return <Volunteer />;
|
||||
case "languages":
|
||||
return <Languages />;
|
||||
case "projects":
|
||||
return <Projects />;
|
||||
case "references":
|
||||
return <References />;
|
||||
default:
|
||||
if (section.startsWith("custom.")) return <Custom id={section.split(".")[1]} />;
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const Leafish = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isFirstPage && <Header />}
|
||||
|
||||
<div className="p-custom grid grid-cols-2 items-start space-x-6">
|
||||
<div className="grid gap-y-4">
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="grid gap-y-4">
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@ -31,7 +31,6 @@ const Header = () => {
|
||||
return (
|
||||
<div className="grid grid-cols-4 gap-x-6">
|
||||
<div className="mt-1 space-y-2 text-right">
|
||||
<p className="font-medium text-primary">Personal Information</p>
|
||||
<Picture className="ml-auto" />
|
||||
</div>
|
||||
|
||||
@ -504,9 +503,9 @@ export const Nosepass = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="p-custom space-y-6">
|
||||
<div className="flex items-center justify-between">
|
||||
<img alt="Europass Logo" className="h-[48px]" src="https://i.imgur.com/eRK005p.png" />
|
||||
<img alt="Europass Logo" className="h-[42px]" src="https://i.imgur.com/eRK005p.png" />
|
||||
|
||||
<p className="font-medium text-primary">Curriculum Vitae</p>
|
||||
|
||||
|
||||
@ -490,18 +490,16 @@ export const Onyx = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="p-custom space-y-4">
|
||||
{isFirstPage && <Header />}
|
||||
|
||||
<div className="space-y-4">
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -524,23 +524,21 @@ export const Pikachu = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="grid grid-cols-3 space-x-6">
|
||||
<div className="sidebar group space-y-4">
|
||||
{isFirstPage && <Picture className="w-full !max-w-none" />}
|
||||
<div className="p-custom grid grid-cols-3 space-x-6">
|
||||
<div className="sidebar group space-y-4">
|
||||
{isFirstPage && <Picture className="w-full !max-w-none" />}
|
||||
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="main group col-span-2 space-y-4">
|
||||
{isFirstPage && <Header />}
|
||||
<div className="main group col-span-2 space-y-4">
|
||||
{isFirstPage && <Header />}
|
||||
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@ -496,18 +496,16 @@ export const Rhyhorn = ({ columns, isFirstPage = false }: TemplateProps) => {
|
||||
const [main, sidebar] = columns;
|
||||
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="p-custom space-y-4">
|
||||
{isFirstPage && <Header />}
|
||||
|
||||
<div className="space-y-4">
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
{main.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
{sidebar.map((section) => (
|
||||
<Fragment key={section}>{mapSectionToComponent(section)}</Fragment>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@ -22,6 +22,7 @@ module.exports = {
|
||||
relaxed: "calc(var(--line-height) + 0.3)",
|
||||
loose: "calc(var(--line-height) + 0.5)",
|
||||
},
|
||||
spacing: { custom: "var(--margin)" },
|
||||
},
|
||||
},
|
||||
plugins: [require("@tailwindcss/typography")],
|
||||
|
||||
BIN
apps/client/public/templates/jpg/gengar.jpg
Normal file
BIN
apps/client/public/templates/jpg/gengar.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 670 KiB |
BIN
apps/client/public/templates/jpg/glalie.jpg
Normal file
BIN
apps/client/public/templates/jpg/glalie.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 577 KiB |
BIN
apps/client/public/templates/jpg/leafish.jpg
Normal file
BIN
apps/client/public/templates/jpg/leafish.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 589 KiB |
349
apps/client/public/templates/json/gengar.json
Normal file
349
apps/client/public/templates/json/gengar.json
Normal file
@ -0,0 +1,349 @@
|
||||
{
|
||||
"basics": {
|
||||
"name": "John Doe",
|
||||
"headline": "Creative and Innovative Web Developer",
|
||||
"email": "john.doe@gmail.com",
|
||||
"phone": "(555) 123-4567",
|
||||
"location": "Pleasantville, CA 94588",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://johndoe.me/"
|
||||
},
|
||||
"customFields": [],
|
||||
"picture": {
|
||||
"url": "https://i.imgur.com/HgwyOuJ.jpg",
|
||||
"size": 120,
|
||||
"aspectRatio": 1,
|
||||
"borderRadius": 0,
|
||||
"effects": {
|
||||
"hidden": false,
|
||||
"border": false,
|
||||
"grayscale": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"summary": {
|
||||
"name": "Summary",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "summary",
|
||||
"content": "<p>Innovative Web Developer with 5 years of experience in building impactful and user-friendly websites and applications. Specializes in <strong>front-end technologies</strong> and passionate about modern web standards and cutting-edge development techniques. Proven track record of leading successful projects from concept to deployment.</p>"
|
||||
},
|
||||
"awards": {
|
||||
"name": "Awards",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "awards",
|
||||
"items": []
|
||||
},
|
||||
"certifications": {
|
||||
"name": "Certifications",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "certifications",
|
||||
"items": [
|
||||
{
|
||||
"id": "spdhh9rrqi1gvj0yqnbqunlo",
|
||||
"visible": true,
|
||||
"name": "Full-Stack Web Development",
|
||||
"issuer": "CodeAcademy",
|
||||
"date": "2020",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "n838rddyqv47zexn6cxauwqp",
|
||||
"visible": true,
|
||||
"name": "AWS Certified Developer",
|
||||
"issuer": "Amazon Web Services",
|
||||
"date": "2019",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"education": {
|
||||
"name": "Education",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "education",
|
||||
"items": [
|
||||
{
|
||||
"id": "yo3p200zo45c6cdqc6a2vtt3",
|
||||
"visible": true,
|
||||
"institution": "University of California",
|
||||
"studyType": "Bachelor's in Computer Science",
|
||||
"area": "Berkeley, CA",
|
||||
"score": "",
|
||||
"date": "August 2012 to May 2016",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"experience": {
|
||||
"name": "Experience",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "experience",
|
||||
"items": [
|
||||
{
|
||||
"id": "lhw25d7gf32wgdfpsktf6e0x",
|
||||
"visible": true,
|
||||
"company": "Creative Solutions Inc.",
|
||||
"position": "Senior Web Developer",
|
||||
"location": "San Francisco, CA",
|
||||
"date": "January 2019 to Present",
|
||||
"summary": "<ul><li><p>Spearheaded the redesign of the main product website, resulting in a 40% increase in user engagement.</p></li><li><p>Developed and implemented a new responsive framework, improving cross-device compatibility.</p></li><li><p>Mentored a team of four junior developers, fostering a culture of technical excellence.</p></li></ul>",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://creativesolutions.inc/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "r6543lil53ntrxmvel53gbtm",
|
||||
"visible": true,
|
||||
"company": "TechAdvancers",
|
||||
"position": "Web Developer",
|
||||
"location": "San Jose, CA",
|
||||
"date": "June 2016 to December 2018",
|
||||
"summary": "<ul><li><p>Collaborated in a team of 10 to develop high-quality web applications using React.js and Node.js.</p></li><li><p>Managed the integration of third-party services such as Stripe for payments and Twilio for SMS services.</p></li><li><p>Optimized application performance, achieving a 30% reduction in load times.</p></li></ul>",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://techadvancers.com/"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"volunteer": {
|
||||
"name": "Volunteering",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "volunteer",
|
||||
"items": []
|
||||
},
|
||||
"interests": {
|
||||
"name": "Interests",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "interests",
|
||||
"items": []
|
||||
},
|
||||
"languages": {
|
||||
"name": "Languages",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "languages",
|
||||
"items": []
|
||||
},
|
||||
"profiles": {
|
||||
"name": "Profiles",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "profiles",
|
||||
"items": [
|
||||
{
|
||||
"id": "cnbk5f0aeqvhx69ebk7hktwd",
|
||||
"visible": true,
|
||||
"network": "LinkedIn",
|
||||
"username": "johndoe",
|
||||
"icon": "linkedin",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://linkedin.com/in/johndoe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ukl0uecvzkgm27mlye0wazlb",
|
||||
"visible": true,
|
||||
"network": "GitHub",
|
||||
"username": "johndoe",
|
||||
"icon": "github",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://github.com/johndoe"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"projects": {
|
||||
"name": "Projects",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "projects",
|
||||
"items": [
|
||||
{
|
||||
"id": "yw843emozcth8s1ubi1ubvlf",
|
||||
"visible": true,
|
||||
"name": "E-Commerce Platform",
|
||||
"description": "Project Lead",
|
||||
"date": "",
|
||||
"summary": "<p>Led the development of a full-stack e-commerce platform, improving sales conversion by 25%.</p>",
|
||||
"keywords": [],
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ncxgdjjky54gh59iz2t1xi1v",
|
||||
"visible": true,
|
||||
"name": "Interactive Dashboard",
|
||||
"description": "Frontend Developer",
|
||||
"date": "",
|
||||
"summary": "<p>Created an interactive analytics dashboard for a SaaS application, enhancing data visualization for clients.</p>",
|
||||
"keywords": [],
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"publications": {
|
||||
"name": "Publications",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "publications",
|
||||
"items": []
|
||||
},
|
||||
"references": {
|
||||
"name": "References",
|
||||
"columns": 1,
|
||||
"visible": false,
|
||||
"id": "references",
|
||||
"items": [
|
||||
{
|
||||
"id": "f2sv5z0cce6ztjl87yuk8fak",
|
||||
"visible": true,
|
||||
"name": "Available upon request",
|
||||
"description": "",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"skills": {
|
||||
"name": "Skills",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "skills",
|
||||
"items": [
|
||||
{
|
||||
"id": "hn0keriukh6c0ojktl9gsgjm",
|
||||
"visible": true,
|
||||
"name": "Web Technologies",
|
||||
"description": "Advanced",
|
||||
"level": 0,
|
||||
"keywords": [
|
||||
"HTML5",
|
||||
"JavaScript",
|
||||
"PHP",
|
||||
"Python"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "r8c3y47vykausqrgmzwg5pur",
|
||||
"visible": true,
|
||||
"name": "Web Frameworks",
|
||||
"description": "Intermediate",
|
||||
"level": 0,
|
||||
"keywords": [
|
||||
"React.js",
|
||||
"Angular",
|
||||
"Vue.js",
|
||||
"Laravel",
|
||||
"Django"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "b5l75aseexqv17quvqgh73fe",
|
||||
"visible": true,
|
||||
"name": "Tools",
|
||||
"description": "Intermediate",
|
||||
"level": 0,
|
||||
"keywords": [
|
||||
"Webpack",
|
||||
"Git",
|
||||
"Jenkins",
|
||||
"Docker",
|
||||
"JIRA"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"custom": {}
|
||||
},
|
||||
"metadata": {
|
||||
"template": "gengar",
|
||||
"layout": [
|
||||
[
|
||||
[
|
||||
"summary",
|
||||
"experience",
|
||||
"education",
|
||||
"projects",
|
||||
"references"
|
||||
],
|
||||
[
|
||||
"profiles",
|
||||
"skills",
|
||||
"certifications",
|
||||
"interests",
|
||||
"languages",
|
||||
"awards",
|
||||
"volunteer",
|
||||
"publications"
|
||||
]
|
||||
],
|
||||
[
|
||||
[],
|
||||
[]
|
||||
]
|
||||
],
|
||||
"css": {
|
||||
"value": ".section {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}",
|
||||
"visible": false
|
||||
},
|
||||
"page": {
|
||||
"margin": 14,
|
||||
"format": "a4",
|
||||
"options": {
|
||||
"breakLine": true,
|
||||
"pageNumbers": true
|
||||
}
|
||||
},
|
||||
"theme": {
|
||||
"background": "#ffffff",
|
||||
"text": "#000000",
|
||||
"primary": "#0891b2"
|
||||
},
|
||||
"typography": {
|
||||
"font": {
|
||||
"family": "IBM Plex Serif",
|
||||
"subset": "latin",
|
||||
"variants": [
|
||||
"regular"
|
||||
],
|
||||
"size": 13
|
||||
},
|
||||
"lineHeight": 1.6,
|
||||
"hideIcons": false,
|
||||
"underlineLinks": true
|
||||
},
|
||||
"notes": ""
|
||||
}
|
||||
}
|
||||
345
apps/client/public/templates/json/glalie.json
Normal file
345
apps/client/public/templates/json/glalie.json
Normal file
@ -0,0 +1,345 @@
|
||||
{
|
||||
"basics": {
|
||||
"name": "John Doe",
|
||||
"headline": "Creative and Innovative Web Developer",
|
||||
"email": "john.doe@gmail.com",
|
||||
"phone": "(555) 123-4567",
|
||||
"location": "Pleasantville, CA 94588",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://johndoe.me/"
|
||||
},
|
||||
"customFields": [],
|
||||
"picture": {
|
||||
"url": "https://i.imgur.com/HgwyOuJ.jpg",
|
||||
"size": 120,
|
||||
"aspectRatio": 1,
|
||||
"borderRadius": 0,
|
||||
"effects": {
|
||||
"hidden": false,
|
||||
"border": false,
|
||||
"grayscale": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"summary": {
|
||||
"name": "Summary",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "summary",
|
||||
"content": "<p>Innovative Web Developer with 5 years of experience in building impactful and user-friendly websites and applications. Specializes in <strong>front-end technologies</strong> and passionate about modern web standards and cutting-edge development techniques. Proven track record of leading successful projects from concept to deployment.</p>"
|
||||
},
|
||||
"awards": {
|
||||
"name": "Awards",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "awards",
|
||||
"items": []
|
||||
},
|
||||
"certifications": {
|
||||
"name": "Certifications",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "certifications",
|
||||
"items": [
|
||||
{
|
||||
"id": "spdhh9rrqi1gvj0yqnbqunlo",
|
||||
"visible": true,
|
||||
"name": "Full-Stack Web Development",
|
||||
"issuer": "CodeAcademy",
|
||||
"date": "2020",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "n838rddyqv47zexn6cxauwqp",
|
||||
"visible": true,
|
||||
"name": "AWS Certified Developer",
|
||||
"issuer": "Amazon Web Services",
|
||||
"date": "2019",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"education": {
|
||||
"name": "Education",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "education",
|
||||
"items": [
|
||||
{
|
||||
"id": "yo3p200zo45c6cdqc6a2vtt3",
|
||||
"visible": true,
|
||||
"institution": "University of California",
|
||||
"studyType": "Bachelor's in Computer Science",
|
||||
"area": "Berkeley, CA",
|
||||
"score": "",
|
||||
"date": "August 2012 to May 2016",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"experience": {
|
||||
"name": "Experience",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "experience",
|
||||
"items": [
|
||||
{
|
||||
"id": "lhw25d7gf32wgdfpsktf6e0x",
|
||||
"visible": true,
|
||||
"company": "Creative Solutions Inc.",
|
||||
"position": "Senior Web Developer",
|
||||
"location": "San Francisco, CA",
|
||||
"date": "January 2019 to Present",
|
||||
"summary": "<ul><li><p>Spearheaded the redesign of the main product website, resulting in a 40% increase in user engagement.</p></li><li><p>Developed and implemented a new responsive framework, improving cross-device compatibility.</p></li><li><p>Mentored a team of four junior developers, fostering a culture of technical excellence.</p></li></ul>",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://creativesolutions.inc/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "r6543lil53ntrxmvel53gbtm",
|
||||
"visible": true,
|
||||
"company": "TechAdvancers",
|
||||
"position": "Web Developer",
|
||||
"location": "San Jose, CA",
|
||||
"date": "June 2016 to December 2018",
|
||||
"summary": "<ul><li><p>Collaborated in a team of 10 to develop high-quality web applications using React.js and Node.js.</p></li><li><p>Managed the integration of third-party services such as Stripe for payments and Twilio for SMS services.</p></li><li><p>Optimized application performance, achieving a 30% reduction in load times.</p></li></ul>",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://techadvancers.com/"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"volunteer": {
|
||||
"name": "Volunteering",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "volunteer",
|
||||
"items": []
|
||||
},
|
||||
"interests": {
|
||||
"name": "Interests",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "interests",
|
||||
"items": []
|
||||
},
|
||||
"languages": {
|
||||
"name": "Languages",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "languages",
|
||||
"items": []
|
||||
},
|
||||
"profiles": {
|
||||
"name": "Profiles",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "profiles",
|
||||
"items": [
|
||||
{
|
||||
"id": "cnbk5f0aeqvhx69ebk7hktwd",
|
||||
"visible": true,
|
||||
"network": "LinkedIn",
|
||||
"username": "johndoe",
|
||||
"icon": "linkedin",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://linkedin.com/in/johndoe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ukl0uecvzkgm27mlye0wazlb",
|
||||
"visible": true,
|
||||
"network": "GitHub",
|
||||
"username": "johndoe",
|
||||
"icon": "github",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://github.com/johndoe"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"projects": {
|
||||
"name": "Projects",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "projects",
|
||||
"items": [
|
||||
{
|
||||
"id": "yw843emozcth8s1ubi1ubvlf",
|
||||
"visible": true,
|
||||
"name": "E-Commerce Platform",
|
||||
"description": "Project Lead",
|
||||
"date": "",
|
||||
"summary": "<p>Led the development of a full-stack e-commerce platform, improving sales conversion by 25%.</p>",
|
||||
"keywords": [],
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ncxgdjjky54gh59iz2t1xi1v",
|
||||
"visible": true,
|
||||
"name": "Interactive Dashboard",
|
||||
"description": "Frontend Developer",
|
||||
"date": "",
|
||||
"summary": "<p>Created an interactive analytics dashboard for a SaaS application, enhancing data visualization for clients.</p>",
|
||||
"keywords": [],
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"publications": {
|
||||
"name": "Publications",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "publications",
|
||||
"items": []
|
||||
},
|
||||
"references": {
|
||||
"name": "References",
|
||||
"columns": 1,
|
||||
"visible": false,
|
||||
"id": "references",
|
||||
"items": [
|
||||
{
|
||||
"id": "f2sv5z0cce6ztjl87yuk8fak",
|
||||
"visible": true,
|
||||
"name": "Available upon request",
|
||||
"description": "",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"skills": {
|
||||
"name": "Skills",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "skills",
|
||||
"items": [
|
||||
{
|
||||
"id": "hn0keriukh6c0ojktl9gsgjm",
|
||||
"visible": true,
|
||||
"name": "Web Technologies",
|
||||
"description": "Advanced",
|
||||
"level": 0,
|
||||
"keywords": [
|
||||
"HTML5",
|
||||
"JavaScript",
|
||||
"PHP",
|
||||
"Python"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "r8c3y47vykausqrgmzwg5pur",
|
||||
"visible": true,
|
||||
"name": "Web Frameworks",
|
||||
"description": "Intermediate",
|
||||
"level": 0,
|
||||
"keywords": [
|
||||
"React.js",
|
||||
"Angular",
|
||||
"Vue.js",
|
||||
"Laravel",
|
||||
"Django"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "b5l75aseexqv17quvqgh73fe",
|
||||
"visible": true,
|
||||
"name": "Tools",
|
||||
"description": "Intermediate",
|
||||
"level": 0,
|
||||
"keywords": [
|
||||
"Webpack",
|
||||
"Git",
|
||||
"Jenkins",
|
||||
"Docker",
|
||||
"JIRA"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"custom": {}
|
||||
},
|
||||
"metadata": {
|
||||
"template": "glalie",
|
||||
"layout": [
|
||||
[
|
||||
[
|
||||
"summary",
|
||||
"experience",
|
||||
"education",
|
||||
"projects",
|
||||
"references"
|
||||
],
|
||||
[
|
||||
"profiles",
|
||||
"skills",
|
||||
"certifications",
|
||||
"interests",
|
||||
"languages",
|
||||
"awards",
|
||||
"volunteer",
|
||||
"publications"
|
||||
]
|
||||
]
|
||||
],
|
||||
"css": {
|
||||
"value": ".section {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}",
|
||||
"visible": false
|
||||
},
|
||||
"page": {
|
||||
"margin": 14,
|
||||
"format": "a4",
|
||||
"options": {
|
||||
"breakLine": true,
|
||||
"pageNumbers": true
|
||||
}
|
||||
},
|
||||
"theme": {
|
||||
"background": "#ffffff",
|
||||
"text": "#000000",
|
||||
"primary": "#0d9488"
|
||||
},
|
||||
"typography": {
|
||||
"font": {
|
||||
"family": "IBM Plex Serif",
|
||||
"subset": "latin",
|
||||
"variants": [
|
||||
"regular"
|
||||
],
|
||||
"size": 13
|
||||
},
|
||||
"lineHeight": 1.6,
|
||||
"hideIcons": false,
|
||||
"underlineLinks": true
|
||||
},
|
||||
"notes": ""
|
||||
}
|
||||
}
|
||||
345
apps/client/public/templates/json/leafish.json
Normal file
345
apps/client/public/templates/json/leafish.json
Normal file
@ -0,0 +1,345 @@
|
||||
{
|
||||
"basics": {
|
||||
"name": "John Doe",
|
||||
"headline": "Creative and Innovative Web Developer",
|
||||
"email": "john.doe@gmail.com",
|
||||
"phone": "(555) 123-4567",
|
||||
"location": "Pleasantville, CA 94588",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://johndoe.me/"
|
||||
},
|
||||
"customFields": [],
|
||||
"picture": {
|
||||
"url": "https://i.imgur.com/HgwyOuJ.jpg",
|
||||
"size": 120,
|
||||
"aspectRatio": 1,
|
||||
"borderRadius": 0,
|
||||
"effects": {
|
||||
"hidden": false,
|
||||
"border": false,
|
||||
"grayscale": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"sections": {
|
||||
"summary": {
|
||||
"name": "Summary",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "summary",
|
||||
"content": "<p>Innovative Web Developer with 5 years of experience in building impactful and user-friendly websites and applications. Specializes in <strong>front-end technologies</strong> and passionate about modern web standards and cutting-edge development techniques. Proven track record of leading successful projects from concept to deployment.</p>"
|
||||
},
|
||||
"awards": {
|
||||
"name": "Awards",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "awards",
|
||||
"items": []
|
||||
},
|
||||
"certifications": {
|
||||
"name": "Certifications",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "certifications",
|
||||
"items": [
|
||||
{
|
||||
"id": "spdhh9rrqi1gvj0yqnbqunlo",
|
||||
"visible": true,
|
||||
"name": "Full-Stack Web Development",
|
||||
"issuer": "CodeAcademy",
|
||||
"date": "2020",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "n838rddyqv47zexn6cxauwqp",
|
||||
"visible": true,
|
||||
"name": "AWS Certified Developer",
|
||||
"issuer": "Amazon Web Services",
|
||||
"date": "2019",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"education": {
|
||||
"name": "Education",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "education",
|
||||
"items": [
|
||||
{
|
||||
"id": "yo3p200zo45c6cdqc6a2vtt3",
|
||||
"visible": true,
|
||||
"institution": "University of California",
|
||||
"studyType": "Bachelor's in Computer Science",
|
||||
"area": "Berkeley, CA",
|
||||
"score": "",
|
||||
"date": "August 2012 to May 2016",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"experience": {
|
||||
"name": "Experience",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "experience",
|
||||
"items": [
|
||||
{
|
||||
"id": "lhw25d7gf32wgdfpsktf6e0x",
|
||||
"visible": true,
|
||||
"company": "Creative Solutions Inc.",
|
||||
"position": "Senior Web Developer",
|
||||
"location": "San Francisco, CA",
|
||||
"date": "January 2019 to Present",
|
||||
"summary": "<ul><li><p>Spearheaded the redesign of the main product website, resulting in a 40% increase in user engagement.</p></li><li><p>Developed and implemented a new responsive framework, improving cross-device compatibility.</p></li><li><p>Mentored a team of four junior developers, fostering a culture of technical excellence.</p></li></ul>",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://creativesolutions.inc/"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "r6543lil53ntrxmvel53gbtm",
|
||||
"visible": true,
|
||||
"company": "TechAdvancers",
|
||||
"position": "Web Developer",
|
||||
"location": "San Jose, CA",
|
||||
"date": "June 2016 to December 2018",
|
||||
"summary": "<ul><li><p>Collaborated in a team of 10 to develop high-quality web applications using React.js and Node.js.</p></li><li><p>Managed the integration of third-party services such as Stripe for payments and Twilio for SMS services.</p></li><li><p>Optimized application performance, achieving a 30% reduction in load times.</p></li></ul>",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://techadvancers.com/"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"volunteer": {
|
||||
"name": "Volunteering",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "volunteer",
|
||||
"items": []
|
||||
},
|
||||
"interests": {
|
||||
"name": "Interests",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "interests",
|
||||
"items": []
|
||||
},
|
||||
"languages": {
|
||||
"name": "Languages",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "languages",
|
||||
"items": []
|
||||
},
|
||||
"profiles": {
|
||||
"name": "Profiles",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "profiles",
|
||||
"items": [
|
||||
{
|
||||
"id": "cnbk5f0aeqvhx69ebk7hktwd",
|
||||
"visible": true,
|
||||
"network": "LinkedIn",
|
||||
"username": "johndoe",
|
||||
"icon": "linkedin",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://linkedin.com/in/johndoe"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ukl0uecvzkgm27mlye0wazlb",
|
||||
"visible": true,
|
||||
"network": "GitHub",
|
||||
"username": "johndoe",
|
||||
"icon": "github",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": "https://github.com/johndoe"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"projects": {
|
||||
"name": "Projects",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "projects",
|
||||
"items": [
|
||||
{
|
||||
"id": "yw843emozcth8s1ubi1ubvlf",
|
||||
"visible": true,
|
||||
"name": "E-Commerce Platform",
|
||||
"description": "Project Lead",
|
||||
"date": "",
|
||||
"summary": "<p>Led the development of a full-stack e-commerce platform, improving sales conversion by 25%.</p>",
|
||||
"keywords": [],
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ncxgdjjky54gh59iz2t1xi1v",
|
||||
"visible": true,
|
||||
"name": "Interactive Dashboard",
|
||||
"description": "Frontend Developer",
|
||||
"date": "",
|
||||
"summary": "<p>Created an interactive analytics dashboard for a SaaS application, enhancing data visualization for clients.</p>",
|
||||
"keywords": [],
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"publications": {
|
||||
"name": "Publications",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "publications",
|
||||
"items": []
|
||||
},
|
||||
"references": {
|
||||
"name": "References",
|
||||
"columns": 1,
|
||||
"visible": false,
|
||||
"id": "references",
|
||||
"items": [
|
||||
{
|
||||
"id": "f2sv5z0cce6ztjl87yuk8fak",
|
||||
"visible": true,
|
||||
"name": "Available upon request",
|
||||
"description": "",
|
||||
"summary": "",
|
||||
"url": {
|
||||
"label": "",
|
||||
"href": ""
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"skills": {
|
||||
"name": "Skills",
|
||||
"columns": 1,
|
||||
"visible": true,
|
||||
"id": "skills",
|
||||
"items": [
|
||||
{
|
||||
"id": "hn0keriukh6c0ojktl9gsgjm",
|
||||
"visible": true,
|
||||
"name": "Web Technologies",
|
||||
"description": "Advanced",
|
||||
"level": 0,
|
||||
"keywords": [
|
||||
"HTML5",
|
||||
"JavaScript",
|
||||
"PHP",
|
||||
"Python"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "r8c3y47vykausqrgmzwg5pur",
|
||||
"visible": true,
|
||||
"name": "Web Frameworks",
|
||||
"description": "Intermediate",
|
||||
"level": 0,
|
||||
"keywords": [
|
||||
"React.js",
|
||||
"Angular",
|
||||
"Vue.js",
|
||||
"Laravel",
|
||||
"Django"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "b5l75aseexqv17quvqgh73fe",
|
||||
"visible": true,
|
||||
"name": "Tools",
|
||||
"description": "Intermediate",
|
||||
"level": 0,
|
||||
"keywords": [
|
||||
"Webpack",
|
||||
"Git",
|
||||
"Jenkins",
|
||||
"Docker",
|
||||
"JIRA"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"custom": {}
|
||||
},
|
||||
"metadata": {
|
||||
"template": "leafish",
|
||||
"layout": [
|
||||
[
|
||||
[
|
||||
"summary",
|
||||
"experience",
|
||||
"education",
|
||||
"references"
|
||||
],
|
||||
[
|
||||
"profiles",
|
||||
"skills",
|
||||
"certifications",
|
||||
"interests",
|
||||
"languages",
|
||||
"projects",
|
||||
"awards",
|
||||
"volunteer",
|
||||
"publications"
|
||||
]
|
||||
]
|
||||
],
|
||||
"css": {
|
||||
"value": ".section {\n\toutline: 1px solid #000;\n\toutline-offset: 4px;\n}",
|
||||
"visible": false
|
||||
},
|
||||
"page": {
|
||||
"margin": 14,
|
||||
"format": "a4",
|
||||
"options": {
|
||||
"breakLine": true,
|
||||
"pageNumbers": true
|
||||
}
|
||||
},
|
||||
"theme": {
|
||||
"background": "#ffffff",
|
||||
"text": "#000000",
|
||||
"primary": "#7b4f1a"
|
||||
},
|
||||
"typography": {
|
||||
"font": {
|
||||
"family": "IBM Plex Serif",
|
||||
"subset": "latin",
|
||||
"variants": [
|
||||
"regular"
|
||||
],
|
||||
"size": 13
|
||||
},
|
||||
"lineHeight": 1.6,
|
||||
"hideIcons": false,
|
||||
"underlineLinks": true
|
||||
},
|
||||
"notes": ""
|
||||
}
|
||||
}
|
||||
BIN
apps/client/public/templates/pdf/gengar.pdf
Normal file
BIN
apps/client/public/templates/pdf/gengar.pdf
Normal file
Binary file not shown.
BIN
apps/client/public/templates/pdf/glalie.pdf
Normal file
BIN
apps/client/public/templates/pdf/glalie.pdf
Normal file
Binary file not shown.
BIN
apps/client/public/templates/pdf/leafish.pdf
Normal file
BIN
apps/client/public/templates/pdf/leafish.pdf
Normal file
Binary file not shown.
Reference in New Issue
Block a user