Document interfaces that describes cv data (#168)
Co-authored-by: Szymon Kin <68154191+hoolek77@users.noreply.github.com>
This commit is contained in:
parent
5ed3ad4fa3
commit
8d0cd278eb
19 changed files with 518 additions and 21 deletions
Binary file not shown.
|
Before Width: | Height: | Size: 62 KiB |
BIN
src/assets/favorites/books/book-2.jpg
Normal file
BIN
src/assets/favorites/books/book-2.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 70 KiB |
|
|
@ -10,7 +10,7 @@ const config = {
|
||||||
now: 'now',
|
now: 'now',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
seo: {
|
meta: {
|
||||||
title: 'Mark Freeman - Senior React Developer',
|
title: 'Mark Freeman - Senior React Developer',
|
||||||
description:
|
description:
|
||||||
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sodales ac dui at vestibulum. In condimentum metus id dui tincidunt, in blandit mi vehicula.',
|
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. In sodales ac dui at vestibulum. In condimentum metus id dui tincidunt, in blandit mi vehicula.',
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ const favoritesSectionData = {
|
||||||
url: 'https://www.goodreads.com/book/show/4099.The_Pragmatic_Programmer',
|
url: 'https://www.goodreads.com/book/show/4099.The_Pragmatic_Programmer',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: 'https://m.media-amazon.com/images/I/61aFldsgAmL._SY344_BO1,204,203,200_QL70_ML2_.jpg',
|
image: import('@/assets/favorites/books/book-2.jpg'),
|
||||||
title: 'Domain-Driven Design: Tackling Complexity in the Heart of Software',
|
title: 'Domain-Driven Design: Tackling Complexity in the Heart of Software',
|
||||||
author: 'Eric Evans',
|
author: 'Eric Evans',
|
||||||
url: 'https://www.goodreads.com/book/show/179133.Domain_Driven_Design',
|
url: 'https://www.goodreads.com/book/show/179133.Domain_Driven_Design',
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,23 @@
|
||||||
import type { Locale } from 'date-fns';
|
import type { Locale } from 'date-fns';
|
||||||
|
|
||||||
export interface I18nConfig {
|
export interface I18nConfig {
|
||||||
|
/**
|
||||||
|
* Language code used for date formatting, translations, and value of the page `lang` attribute.
|
||||||
|
*/
|
||||||
locale: Locale;
|
locale: Locale;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date format used when displaying date ranges in some sections.
|
||||||
|
*/
|
||||||
dateFormat: string;
|
dateFormat: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of translations used in the application.
|
||||||
|
*/
|
||||||
translations: {
|
translations: {
|
||||||
|
/**
|
||||||
|
* Used in date ranges to represent the current date.
|
||||||
|
*/
|
||||||
now: string;
|
now: string;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
55
src/types/config/meta-config.types.ts
Normal file
55
src/types/config/meta-config.types.ts
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
export interface MetaConfig {
|
||||||
|
/**
|
||||||
|
* [WEB] Page title.
|
||||||
|
*
|
||||||
|
* Displayed as browser tab title and in search results.
|
||||||
|
* It's recommended to keep it between 30 and 60 characters.
|
||||||
|
*
|
||||||
|
* @see https://www.screamingfrog.co.uk/learn-seo/page-title
|
||||||
|
*/
|
||||||
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Page description.
|
||||||
|
*
|
||||||
|
* Displayed under the title in search results.
|
||||||
|
* It's recommended to keep it between 70 and 155 characters.
|
||||||
|
*
|
||||||
|
* @see https://www.screamingfrog.co.uk/learn-seo/meta-description
|
||||||
|
*/
|
||||||
|
description: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] URL or path to the page's favicon.
|
||||||
|
*
|
||||||
|
* Specified icon will be displayed next to the page title in browser tab.
|
||||||
|
*/
|
||||||
|
favicon: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Title used in open graph links.
|
||||||
|
*
|
||||||
|
* If not specified, the title property will be used.
|
||||||
|
*
|
||||||
|
* @see https://ahrefs.com/blog/open-graph-meta-tags
|
||||||
|
*/
|
||||||
|
ogTitle?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Description used in open graph links.
|
||||||
|
*
|
||||||
|
* If not specified, the description property will be used.
|
||||||
|
*
|
||||||
|
* @see https://ahrefs.com/blog/open-graph-meta-tags
|
||||||
|
*/
|
||||||
|
ogDescription?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Image used in open graph links.
|
||||||
|
*
|
||||||
|
* It's recommended to keep it between 30 and 60 characters.
|
||||||
|
*
|
||||||
|
* @see https://ahrefs.com/blog/open-graph-meta-tags
|
||||||
|
*/
|
||||||
|
ogImage?: string;
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
export interface PdfConfig {
|
export interface PdfConfig {
|
||||||
|
/**
|
||||||
|
* [PDF] Displays footer with specified content on each PDF page.
|
||||||
|
*
|
||||||
|
* You can use it to add the data processing clause.
|
||||||
|
*/
|
||||||
footer?: string;
|
footer?: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
export interface SeoConfig {
|
|
||||||
title: string;
|
|
||||||
description: string;
|
|
||||||
favicon: string;
|
|
||||||
ogTitle?: string;
|
|
||||||
ogDescription?: string;
|
|
||||||
ogImage?: string;
|
|
||||||
}
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import type { I18nConfig } from './config/i18n-config.types';
|
import type { I18nConfig } from './config/i18n-config.types';
|
||||||
import type { PdfConfig } from './config/pdf-config.types';
|
import type { PdfConfig } from './config/pdf-config.types';
|
||||||
import type { SeoConfig } from './config/seo-config.types';
|
import type { MetaConfig } from './config/meta-config.types';
|
||||||
import type { EducationSection } from './sections/education-section.types';
|
import type { EducationSection } from './sections/education-section.types';
|
||||||
import type { ExperienceSection } from './sections/experience-section.types';
|
import type { ExperienceSection } from './sections/experience-section.types';
|
||||||
import type { FavoritesSection } from './sections/favorites-section.types';
|
import type { FavoritesSection } from './sections/favorites-section.types';
|
||||||
|
|
@ -10,22 +10,70 @@ import type { SkillsSection } from './sections/skills-section.types';
|
||||||
import type { TestimonialsSection } from './sections/testimonials-section.types';
|
import type { TestimonialsSection } from './sections/testimonials-section.types';
|
||||||
|
|
||||||
export interface Config {
|
export interface Config {
|
||||||
seo: SeoConfig;
|
/**
|
||||||
|
* [WEB] Page metadata used for SEO and social media sharing.
|
||||||
|
*/
|
||||||
|
meta: MetaConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Language and date display configuration.
|
||||||
|
*/
|
||||||
i18n: I18nConfig;
|
i18n: I18nConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [PDF] Configuration of the pdf generation.
|
||||||
|
*/
|
||||||
pdf?: PdfConfig;
|
pdf?: PdfConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Sections {
|
export interface Sections {
|
||||||
|
/**
|
||||||
|
* Basic information about you.
|
||||||
|
*/
|
||||||
main: MainSection;
|
main: MainSection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grouped lists of your skills.
|
||||||
|
*/
|
||||||
skills: SkillsSection;
|
skills: SkillsSection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Your employment history.
|
||||||
|
*/
|
||||||
experience: ExperienceSection;
|
experience: ExperienceSection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Your projects and initiatives.
|
||||||
|
*/
|
||||||
portfolio: PortfolioSection;
|
portfolio: PortfolioSection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Your education degrees and certifications.
|
||||||
|
*/
|
||||||
education: EducationSection;
|
education: EducationSection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Recommendations from your previous employers and people you worked with.
|
||||||
|
*/
|
||||||
testimonials: TestimonialsSection;
|
testimonials: TestimonialsSection;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] List of sources you use to gain knowledge and inspiration.
|
||||||
|
*/
|
||||||
favorites: FavoritesSection;
|
favorites: FavoritesSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* All data used to generate the cv.
|
||||||
|
*/
|
||||||
export interface Data {
|
export interface Data {
|
||||||
|
/**
|
||||||
|
* Global configuration of the web and pdf versions of the cv.
|
||||||
|
*/
|
||||||
config: Config;
|
config: Config;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configurations for the particular sections of the cv.
|
||||||
|
*/
|
||||||
sections: Sections;
|
sections: Sections;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,35 @@
|
||||||
import type { DateRange, Description, LinkButton, Section } from '../shared';
|
import type { DateRange, Description, LinkButton, Section } from '../shared';
|
||||||
|
|
||||||
export interface Diploma {
|
export interface Diploma {
|
||||||
|
/**
|
||||||
|
* Name of the certificate or the degree you got.
|
||||||
|
*/
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the institution that issued the certificate or degree.
|
||||||
|
*/
|
||||||
institution: string;
|
institution: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date range when you were studying in the institution.
|
||||||
|
*/
|
||||||
dates: DateRange;
|
dates: DateRange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A short overview of your studies. You can write it as a paragraph (string) or as a list of bullet points (string[]).
|
||||||
|
*/
|
||||||
description: Description;
|
description: Description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Links related to your studies (e.g. course/university website, link to realized project).
|
||||||
|
*/
|
||||||
links: LinkButton[];
|
links: LinkButton[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EducationSection extends Section {
|
export interface EducationSection extends Section {
|
||||||
|
/**
|
||||||
|
* List of your diplomas, certificates, .etc. Start with the most recent one.
|
||||||
|
*/
|
||||||
diplomas: Diploma[];
|
diplomas: Diploma[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,41 @@
|
||||||
import type { DateRange, Description, LinkButton, Section, TagsList } from '../shared';
|
import type { DateRange, Description, LinkButton, Section, TagsList } from '../shared';
|
||||||
|
|
||||||
export interface Job {
|
export interface Job {
|
||||||
|
/**
|
||||||
|
* Your position in the company.
|
||||||
|
*/
|
||||||
role: string;
|
role: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the company.
|
||||||
|
*/
|
||||||
company: string;
|
company: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date range when you were working in the company.
|
||||||
|
*/
|
||||||
dates: DateRange;
|
dates: DateRange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A short overview of your job. You can write it as a paragraph (string) or as a list of bullet points (string[]).
|
||||||
|
*/
|
||||||
description: Description;
|
description: Description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any information that you want to highlight.
|
||||||
|
* We recommend to describe the technologies used in the project.
|
||||||
|
*/
|
||||||
tagsList: TagsList;
|
tagsList: TagsList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Links related to your job (e.g. production app, company's website, project website).
|
||||||
|
*/
|
||||||
links: LinkButton[];
|
links: LinkButton[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExperienceSection extends Section {
|
export interface ExperienceSection extends Section {
|
||||||
|
/**
|
||||||
|
* List of your jobs in a chronological order. Start with the most recent one.
|
||||||
|
*/
|
||||||
jobs: Job[];
|
jobs: Job[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,39 +1,129 @@
|
||||||
import type { Photo, Section } from '../shared';
|
import type { Photo, Section } from '../shared';
|
||||||
|
|
||||||
export interface Book {
|
export interface Book {
|
||||||
|
/**
|
||||||
|
* [WEB] Book title.
|
||||||
|
*/
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Book cover.
|
||||||
|
*
|
||||||
|
* **Ratio**: 3:4
|
||||||
|
*
|
||||||
|
* **Display size**: 300x400px
|
||||||
|
*/
|
||||||
image: Photo;
|
image: Photo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Full name of the book author.
|
||||||
|
*/
|
||||||
author: string;
|
author: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Website to buy the book or read more about it.
|
||||||
|
*/
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Person {
|
export interface Person {
|
||||||
|
/**
|
||||||
|
* [WEB] Full name of the person.
|
||||||
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Photo of the person.
|
||||||
|
*
|
||||||
|
* **Ratio**: 1:1
|
||||||
|
*
|
||||||
|
* **Display size**: 200x200px
|
||||||
|
*/
|
||||||
image: Photo;
|
image: Photo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Main website related to the person.
|
||||||
|
*/
|
||||||
url?: string;
|
url?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Video {
|
export interface Video {
|
||||||
|
/**
|
||||||
|
* [WEB] Title of the video.
|
||||||
|
*/
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Thumbnail of the video.
|
||||||
|
*
|
||||||
|
* **Ratio**: 16:9
|
||||||
|
*
|
||||||
|
* **Display size**: 448x252px
|
||||||
|
*/
|
||||||
image: Photo;
|
image: Photo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Link to the video.
|
||||||
|
*/
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Media {
|
export interface Media {
|
||||||
|
/**
|
||||||
|
* [WEB] Title of the media.
|
||||||
|
*/
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Type of the media (e.g. podcast, blog, newsletter, YouTube channel, .etc).
|
||||||
|
*/
|
||||||
type: string;
|
type: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Logo of the media.
|
||||||
|
*
|
||||||
|
* **Ratio**: 1:1
|
||||||
|
*
|
||||||
|
* **Display size**: 200x200px
|
||||||
|
*/
|
||||||
image: Photo;
|
image: Photo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] URL to the main website related to the media.
|
||||||
|
*/
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SubSection<Data = unknown> {
|
export interface SubSection<Data = unknown> {
|
||||||
|
/**
|
||||||
|
* [WEB] Title that will be displayed above the list of items.
|
||||||
|
*/
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] List of items to display within the subsection.
|
||||||
|
*/
|
||||||
data: Data[];
|
data: Data[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface FavoritesSection extends Section {
|
export interface FavoritesSection extends Section {
|
||||||
|
/**
|
||||||
|
* [WEB] List of your favorite books.
|
||||||
|
*/
|
||||||
books?: SubSection<Book>;
|
books?: SubSection<Book>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] List of the people that inspire you.
|
||||||
|
*/
|
||||||
people?: SubSection<Person>;
|
people?: SubSection<Person>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] List of the videos you learned the most from.
|
||||||
|
*/
|
||||||
videos?: SubSection<Video>;
|
videos?: SubSection<Video>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] List of other media types that helps you to growth in your field.
|
||||||
|
*/
|
||||||
medias?: SubSection<Media>;
|
medias?: SubSection<Media>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,58 @@
|
||||||
import type { DownloadButton, Photo, LabelledValue, LinkButton, Section, Tag } from '../shared';
|
import type { DownloadButton, Photo, LabelledValue, LinkButton, Section, Tag } from '../shared';
|
||||||
|
|
||||||
export interface MainSection extends Section {
|
export interface MainSection extends Section {
|
||||||
|
/**
|
||||||
|
* Your image.
|
||||||
|
*
|
||||||
|
* **Ratio**: 1:1
|
||||||
|
*
|
||||||
|
* **Display size**: 208x208px
|
||||||
|
*/
|
||||||
image: Photo;
|
image: Photo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Your name.
|
||||||
|
*/
|
||||||
fullName: string;
|
fullName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Your current role.
|
||||||
|
*/
|
||||||
role: string;
|
role: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label-value pairs with some key details about you.
|
||||||
|
*
|
||||||
|
* E.g. phone, email, location, expected salary.
|
||||||
|
*/
|
||||||
details: LabelledValue[];
|
details: LabelledValue[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [PDF] Labeled-value pairs that will be used in the PDF version of your resume.
|
||||||
|
*
|
||||||
|
* You can use it to add your social media profiles as those listed under the `links` property aren't used in the PDF.
|
||||||
|
*
|
||||||
|
* If not provided, the `details` will be used instead.
|
||||||
|
*/
|
||||||
pdfDetails?: LabelledValue[];
|
pdfDetails?: LabelledValue[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A short overview of you and your experience.
|
||||||
|
*/
|
||||||
description: string;
|
description: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Any information that you want to highlight.
|
||||||
|
*/
|
||||||
tags: Tag[];
|
tags: Tag[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] A button that will be used to download your resume.
|
||||||
|
*/
|
||||||
action: DownloadButton;
|
action: DownloadButton;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Your social media profiles.
|
||||||
|
*/
|
||||||
links: LinkButton[];
|
links: LinkButton[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,59 @@
|
||||||
import type { DateRange, Photo, LabelledValue, LinkButton, Section, TagsList, Description } from '../shared';
|
import type { DateRange, Photo, LabelledValue, LinkButton, Section, TagsList, Description } from '../shared';
|
||||||
|
|
||||||
export interface Project {
|
export interface Project {
|
||||||
|
/**
|
||||||
|
* Name of the project.
|
||||||
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Logo of the project.
|
||||||
|
*
|
||||||
|
* **Ratio**: 1:1
|
||||||
|
*
|
||||||
|
* **Display size**: 120x120px
|
||||||
|
*/
|
||||||
image: Photo;
|
image: Photo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date range when you were working on the project.
|
||||||
|
*/
|
||||||
dates: DateRange;
|
dates: DateRange;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Label-value pairs with some key details about the project.
|
||||||
|
*/
|
||||||
details: LabelledValue[];
|
details: LabelledValue[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [PDF] Labeled-value pairs that will be used in the PDF version of your resume.
|
||||||
|
*
|
||||||
|
* You can use it to add some links related to your project as those listed under the `links` property aren't used in the PDF.
|
||||||
|
*
|
||||||
|
* If not provided, the `details` will be used instead.
|
||||||
|
*/
|
||||||
pdfDetails?: LabelledValue[];
|
pdfDetails?: LabelledValue[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A short overview of the project. You can write it as a paragraph (string) or as a list of bullet points (string[]).
|
||||||
|
*/
|
||||||
description: Description;
|
description: Description;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Any information that you want to highlight.
|
||||||
|
* We recommend to describe the technologies used in the project.
|
||||||
|
*/
|
||||||
tagsList: TagsList;
|
tagsList: TagsList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Links related to your project (e.g. GitHub repository, live demo, mockups).
|
||||||
|
*/
|
||||||
links: LinkButton[];
|
links: LinkButton[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PortfolioSection extends Section {
|
export interface PortfolioSection extends Section {
|
||||||
|
/**
|
||||||
|
* List of your projects in a chronological order. Start with the most recent one.
|
||||||
|
*/
|
||||||
projects: Project[];
|
projects: Project[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,30 @@ export interface Skill extends Tag {}
|
||||||
export type SkillLevel = 1 | 2 | 3 | 4 | 5;
|
export type SkillLevel = 1 | 2 | 3 | 4 | 5;
|
||||||
|
|
||||||
export interface LevelledSkill extends Skill {
|
export interface LevelledSkill extends Skill {
|
||||||
|
/**
|
||||||
|
* Your level of skill proficiency in a 1-5 scale.
|
||||||
|
*/
|
||||||
level: SkillLevel;
|
level: SkillLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SkillSet {
|
export interface SkillSet {
|
||||||
|
/**
|
||||||
|
* Title that will be displayed above the list of skills.
|
||||||
|
*/
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of skills with or without levels.
|
||||||
|
*
|
||||||
|
* If you want to displays skills with levels, we recommend to also provide the `description` property.
|
||||||
|
* This way anyone viewing your resume will know what is the meaning of each level.
|
||||||
|
*/
|
||||||
skills: Skill[] | LevelledSkill[];
|
skills: Skill[] | LevelledSkill[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SkillsSection extends Section {
|
export interface SkillsSection extends Section {
|
||||||
|
/**
|
||||||
|
* Grouped lists of your skills.
|
||||||
|
*/
|
||||||
skillSets: SkillSet[];
|
skillSets: SkillSet[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,39 @@
|
||||||
import type { Photo, LinkButton, Section } from '../shared';
|
import type { Photo, LinkButton, Section } from '../shared';
|
||||||
|
|
||||||
export interface Testimonial {
|
export interface Testimonial {
|
||||||
|
/**
|
||||||
|
* [WEB] Photo of the testimonial author.
|
||||||
|
*
|
||||||
|
* **Ratio**: 1:1
|
||||||
|
*
|
||||||
|
* **Display size**: 56x56px
|
||||||
|
*/
|
||||||
image: Photo;
|
image: Photo;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Full name of the testimonial author.
|
||||||
|
*/
|
||||||
author: string;
|
author: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Your relation to the testimonial author (e.g. supervisor, colleague, subordinate).
|
||||||
|
*/
|
||||||
relation: string;
|
relation: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Content of the testimonial.
|
||||||
|
*/
|
||||||
content: string;
|
content: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Social media (e.g. LinkedIn profile, website) of the testimonial author.
|
||||||
|
*/
|
||||||
links: LinkButton[];
|
links: LinkButton[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TestimonialsSection extends Section {
|
export interface TestimonialsSection extends Section {
|
||||||
|
/**
|
||||||
|
* [WEB] List of your testimonials in a chronological order. Start with the most recent one.
|
||||||
|
*/
|
||||||
testimonials: Testimonial[];
|
testimonials: Testimonial[];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,52 +1,162 @@
|
||||||
import type { CircleFlags, Fa6Brands, Fa6Solid, Ri, SimpleIcons } from 'iconify-icon-names';
|
import type { CircleFlags, Fa6Brands, Fa6Solid, Ri, SimpleIcons } from 'iconify-icon-names';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the icon from the iconify library.
|
||||||
|
*
|
||||||
|
* @see https://icon-sets.iconify.design
|
||||||
|
*/
|
||||||
export type IconName = Fa6Brands | Fa6Solid | SimpleIcons | CircleFlags | Ri;
|
export type IconName = Fa6Brands | Fa6Solid | SimpleIcons | CircleFlags | Ri;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* - Dynamic import of the image from `src/assets` folder. Recommended as it enables image optimization.
|
||||||
|
* - Path to the image placed in the `public` folder.
|
||||||
|
* - URL of the image stored online.
|
||||||
|
*/
|
||||||
export type Photo = Promise<{ default: ImageMetadata }> | string;
|
export type Photo = Promise<{ default: ImageMetadata }> | string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Two date objects representing some time period.
|
||||||
|
*
|
||||||
|
* If the second date is `null`, it means that the period is still ongoing.
|
||||||
|
* In such case, the translation from `config.i18n.translations.now` will be used.
|
||||||
|
*/
|
||||||
export type DateRange = [from: Date, to: Date | null];
|
export type DateRange = [from: Date, to: Date | null];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a string is provided, it will be displayed as a single justified paragraph.
|
||||||
|
* If an array of strings is provided it will be displayed as a list.
|
||||||
|
*/
|
||||||
export type Description = string | string[];
|
export type Description = string | string[];
|
||||||
|
|
||||||
export interface SectionConfig {
|
export interface SectionConfig {
|
||||||
|
/**
|
||||||
|
* Name displayed as a section header (except for the main section).
|
||||||
|
*
|
||||||
|
* [WEB] Content of the tooltip displayed when someone hovers over the section in the sidebar.
|
||||||
|
*/
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] URL hash used to navigate to the section.
|
||||||
|
*/
|
||||||
slug: string;
|
slug: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Icon used in sidebar navigation to represent the section.
|
||||||
|
*/
|
||||||
icon: IconName;
|
icon: IconName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should section be displayed on the page.
|
||||||
|
*/
|
||||||
visible: boolean;
|
visible: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Section {
|
export interface Section {
|
||||||
|
/**
|
||||||
|
* Base information about the section.
|
||||||
|
*/
|
||||||
config: SectionConfig;
|
config: SectionConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LabelledValue {
|
export interface LabelledValue {
|
||||||
|
/**
|
||||||
|
* Bolder text displayed on the left side of the value.
|
||||||
|
*/
|
||||||
label: string;
|
label: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text displayed on the right side.
|
||||||
|
* If a list of strings provided, they will be separated by a comma.
|
||||||
|
*/
|
||||||
value: string | string[];
|
value: string | string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URL that will be opened in a new tab, when the value is clicked.
|
||||||
|
*/
|
||||||
url?: string;
|
url?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [PDF] When labelled value is displayed in a grid, it will span the whole row.
|
||||||
|
*/
|
||||||
fullRow?: boolean;
|
fullRow?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Tag {
|
export interface Tag {
|
||||||
|
/**
|
||||||
|
* Text displayed within the tag.
|
||||||
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Icon displayed next to the tag text.
|
||||||
|
*/
|
||||||
icon?: IconName;
|
icon?: IconName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Color of the icon. By default, the color is inherited from the text.
|
||||||
|
*/
|
||||||
iconColor?: string;
|
iconColor?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] URL that will be opened in a new tab, when the tag is clicked.
|
||||||
|
*/
|
||||||
url?: string;
|
url?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Text displayed in the tooltip when someone hovers over the tag.
|
||||||
|
*/
|
||||||
description?: string;
|
description?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TagsList {
|
export interface TagsList {
|
||||||
|
/**
|
||||||
|
* [PDF] Text displayed before the list of tags.
|
||||||
|
*/
|
||||||
title: string;
|
title: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tags to be displayed within the list.
|
||||||
|
* [WEB] Tags are displayed as gray blocks. All tag properties are used.
|
||||||
|
* [PDF] Tags are displayed comma separated list. Only the `name` property are used.
|
||||||
|
*/
|
||||||
tags: Tag[];
|
tags: Tag[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface DownloadButton {
|
export interface DownloadButton {
|
||||||
|
/**
|
||||||
|
* [WEB] Text displayed within the download button.
|
||||||
|
*/
|
||||||
label: string;
|
label: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] URL or path to the CV file.
|
||||||
|
*/
|
||||||
url: string;
|
url: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Name of the file that will be downloaded.
|
||||||
|
*
|
||||||
|
* If not specified, the original file name will be used and file will open in a PDF viewer in some browsers.
|
||||||
|
*
|
||||||
|
* If specified, the file will be downloaded immediately (without preview) in all browsers.
|
||||||
|
*/
|
||||||
downloadedFileName?: string;
|
downloadedFileName?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LinkButton {
|
export interface LinkButton {
|
||||||
|
/**
|
||||||
|
* [WEB] Name displayed in the tooltip when someone hovers over the button.
|
||||||
|
*/
|
||||||
name: string;
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] Icon displayed within the button.
|
||||||
|
*/
|
||||||
icon: IconName;
|
icon: IconName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [WEB] URL that will be opened in a new tab, when the button is clicked.
|
||||||
|
*/
|
||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@
|
||||||
import type { Data } from '@/types/data';
|
import type { Data } from '@/types/data';
|
||||||
import Analytics from '@/web/analytics/analytics.astro';
|
import Analytics from '@/web/analytics/analytics.astro';
|
||||||
|
|
||||||
export interface Props extends Pick<Data['config'], 'seo' | 'i18n'> {}
|
export interface Props extends Pick<Data['config'], 'meta' | 'i18n'> {}
|
||||||
|
|
||||||
const { seo, i18n } = Astro.props;
|
const { meta, i18n } = Astro.props;
|
||||||
---
|
---
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
|
|
@ -13,12 +13,12 @@ const { seo, i18n } = Astro.props;
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
<meta name="generator" content={Astro.generator} />
|
<meta name="generator" content={Astro.generator} />
|
||||||
<title>{seo.title}</title>
|
<title>{meta.title}</title>
|
||||||
<meta name="description" content={seo.description} />
|
<meta name="description" content={meta.description} />
|
||||||
<link rel="icon" type="image/svg+xml" href={seo.favicon} />
|
<link rel="icon" type="image/svg+xml" href={meta.favicon} />
|
||||||
<meta property="og:title" content={seo.ogTitle ?? seo.title} />
|
<meta property="og:title" content={meta.ogTitle ?? meta.title} />
|
||||||
<meta property="og:description" content={seo.ogDescription ?? seo.description} />
|
<meta property="og:description" content={meta.ogDescription ?? meta.description} />
|
||||||
{seo.ogImage && <meta property="og:image" content={seo.ogImage} />}
|
{meta.ogImage && <meta property="og:image" content={meta.ogImage} />}
|
||||||
<script is:inline>
|
<script is:inline>
|
||||||
const theme = (() => {
|
const theme = (() => {
|
||||||
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
|
if (typeof localStorage !== 'undefined' && localStorage.getItem('theme')) {
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,11 @@ import { isServer } from './env';
|
||||||
const getInitialHash = () => {
|
const getInitialHash = () => {
|
||||||
if (isServer) return '';
|
if (isServer) return '';
|
||||||
|
|
||||||
return window.location.hash || `#${sections.main.config.slug}`;
|
const firstVisibleSection = Object.values(sections).find((section) => section.config.visible);
|
||||||
|
|
||||||
|
if (!firstVisibleSection) return '';
|
||||||
|
|
||||||
|
return window.location.hash || `#${firstVisibleSection.config.slug}`;
|
||||||
};
|
};
|
||||||
|
|
||||||
const createHashState = () => {
|
const createHashState = () => {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue