diff --git a/package-lock.json b/package-lock.json index 8e2b02f..4dd2875 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,6 +18,7 @@ "@astrojs/react": "1.2.2", "@astrojs/tailwind": "2.1.3", "@percy/cli": "1.17.0", + "@types/marked": "4.0.8", "astro": "1.9.2", "astro-compress": "1.1.28", "concurrently": "7.6.0", @@ -25,6 +26,7 @@ "iconify-icon-names": "1.1.0", "immer": "9.0.18", "locales-ts": "1.0.0", + "marked": "4.2.12", "postcss": "8.4.21", "prettier": "2.8.3", "prettier-plugin-astro": "0.7.2", @@ -1217,6 +1219,12 @@ "integrity": "sha512-hw3bhStrg5e3FQT8qZKCJTrzt/UbEaunU1xRWJ+aNOTmeBMvE3S4Ml2HiiNnZgL8izu0LFVkHUoPFXL1s5QNpQ==", "dev": true }, + "node_modules/@types/marked": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.8.tgz", + "integrity": "sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw==", + "dev": true + }, "node_modules/@types/mdast": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", @@ -4866,6 +4874,18 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/marked": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz", + "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==", + "dev": true, + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 12" + } + }, "node_modules/matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", @@ -10406,6 +10426,12 @@ "integrity": "sha512-hw3bhStrg5e3FQT8qZKCJTrzt/UbEaunU1xRWJ+aNOTmeBMvE3S4Ml2HiiNnZgL8izu0LFVkHUoPFXL1s5QNpQ==", "dev": true }, + "@types/marked": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.8.tgz", + "integrity": "sha512-HVNzMT5QlWCOdeuBsgXP8EZzKUf0+AXzN+sLmjvaB3ZlLqO+e4u0uXrdw9ub69wBKFs+c6/pA4r9sy6cCDvImw==", + "dev": true + }, "@types/mdast": { "version": "3.0.10", "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-3.0.10.tgz", @@ -13008,6 +13034,12 @@ "integrity": "sha512-y8j3a5/DkJCmS5x4dMCQL+OR0+2EAq3DOtio1COSHsmW2BGXnNCK3v12hJt1LrUz5iZH5g0LmuYOjDdI+czghA==", "dev": true }, + "marked": { + "version": "4.2.12", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.12.tgz", + "integrity": "sha512-yr8hSKa3Fv4D3jdZmtMMPghgVt6TWbk86WQaWhDloQjRSQhMMYCAro7jP7VDJrjjdV8pxVxMssXS8B8Y5DZ5aw==", + "dev": true + }, "matcher": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/matcher/-/matcher-3.0.0.tgz", diff --git a/package.json b/package.json index c94f56c..f39746e 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "@astrojs/react": "1.2.2", "@astrojs/tailwind": "2.1.3", "@percy/cli": "1.17.0", + "@types/marked": "4.0.8", "astro": "1.9.2", "astro-compress": "1.1.28", "concurrently": "7.6.0", @@ -38,6 +39,7 @@ "iconify-icon-names": "1.1.0", "immer": "9.0.18", "locales-ts": "1.0.0", + "marked": "4.2.12", "postcss": "8.4.21", "prettier": "2.8.3", "prettier-plugin-astro": "0.7.2", diff --git a/public/cv.pdf b/public/cv.pdf index f50b9f2..f102d8a 100644 Binary files a/public/cv.pdf and b/public/cv.pdf differ diff --git a/src/components/description.astro b/src/components/description.astro new file mode 100644 index 0000000..0fe4a5c --- /dev/null +++ b/src/components/description.astro @@ -0,0 +1,40 @@ +--- +import { marked } from 'marked'; + +export interface Props { + content: string; + classList: (string | undefined)[]; +} + +const minIndent = (str: string) => { + const match = str.match(/^[\t ]*(?=\S)/gm); + + if (!match) return 0; + + return match.reduce((r, a) => Math.min(r, a.length), Number.POSITIVE_INFINITY); +}; + +const stripIndent = (str: string) => { + const indent = minIndent(str); + + if (indent === 0) return str; + + const regex = new RegExp(`^[ \\t]{${indent}}`, 'gm'); + + return str.replace(regex, ''); +}; + +const { content, classList } = Astro.props; +--- + +
+ + diff --git a/src/web/components/photo.astro b/src/components/photo.astro similarity index 100% rename from src/web/components/photo.astro rename to src/components/photo.astro diff --git a/src/data/sections/experience-section.data.ts b/src/data/sections/experience-section.data.ts index 46d2f39..df1bfc0 100644 --- a/src/data/sections/experience-section.data.ts +++ b/src/data/sections/experience-section.data.ts @@ -27,14 +27,14 @@ const experienceSectionData = { role: 'Senior front-end developer', company: 'Google', dates: [new Date('2020-02'), null], - description: [ - 'In tristique vulputate augue vel egestas.', - 'Quisque ac imperdiet tortor, at lacinia ex.', - 'Duis vel ex hendrerit, commodo odio sed, aliquam enim.', - 'Ut arcu nulla, tincidunt eget arcu eget, molestie vulputate nisi.', - 'Nunc malesuada leo et est iaculis facilisis.', - 'Fusce eu urna ut magna malesuada fringilla.', - ], + description: ` + - In tristique vulputate augue vel egestas. + - Quisque ac imperdiet tortor, at lacinia ex. + - Duis vel ex hendrerit, commodo odio sed, aliquam enim. + - Ut arcu nulla, tincidunt eget arcu eget, molestie vulputate nisi. + - Nunc malesuada leo et est iaculis facilisis. + - Fusce eu urna ut magna malesuada fringilla. + `, tagsList: { title: 'Technologies', tags: [react(), nextJs(), typescript(), nx(), firebase()], @@ -45,12 +45,12 @@ const experienceSectionData = { role: 'React.js developer', company: 'Facebook', dates: [new Date('2019-04'), new Date('2020-02')], - description: [ - 'Aenean eget ultricies felis. Pellentesque dictum massa ut tellus eleifend, sed posuere massa mattis.', - 'Ut posuere massa lacus, eleifend molestie tortor auctor vel.', - 'Sed sed sollicitudin eros, id ultricies mi. Aliquam sodales elit vel ante tempor, non vehicula nibh facilisis.', - 'Cras feugiat ultricies maximus. Aliquam tristique ex odio, ac semper urna accumsan a.', - ], + description: ` + - Aenean eget ultricies felis. Pellentesque dictum massa ut tellus eleifend, sed posuere massa mattis. + - Ut posuere massa lacus, eleifend molestie tortor auctor vel. + - Sed sed sollicitudin eros, id ultricies mi. Aliquam sodales elit vel ante tempor, non vehicula nibh facilisis. + - Cras feugiat ultricies maximus. Aliquam tristique ex odio, ac semper urna accumsan a. + `, tagsList: { title: 'Technologies', tags: [react(), reactQuery(), chakraUi(), eslint()], @@ -61,12 +61,14 @@ const experienceSectionData = { role: 'Junior front-end developer', company: 'GitLab', dates: [new Date('2016-09'), new Date('2019-04')], - description: [ - 'Nulla volutpat justo ante, rhoncus posuere massa egestas in.', - 'Quisque pellentesque, dolor nec sollicitudin iaculis, sem velit consequat ligula, eget tempus ligula leo et est.', - 'Maecenas ut elit sit amet nibh maximus condimentum in nec lorem. Pellentesque tincidunt odio vel leo suscipit, in interdum mi gravida.', - 'Donec non vulputate augue.', - ], + description: ` + Nulla volutpat justo ante, rhoncus posuere massa egestas in: + + - Quisque pellentesque, dolor nec sollicitudin iaculis, sem velit consequat ligula, eget tempus ligula leo et est. + - Maecenas ut elit sit amet nibh maximus condimentum in nec lorem. Pellentesque tincidunt odio vel leo suscipit, in interdum mi gravida. + + Donec non vulputate augue 🤓 + `, tagsList: { title: 'Technologies', tags: [vue(), tailwindCss(), pnpm()], diff --git a/src/data/sections/main-section.data.ts b/src/data/sections/main-section.data.ts index f5097ea..2cd3e54 100644 --- a/src/data/sections/main-section.data.ts +++ b/src/data/sections/main-section.data.ts @@ -23,10 +23,10 @@ const mainSectionData = { { label: 'Email', value: 'mark.freeman.dev@gmail.com' }, { label: 'LinkedIn', value: '/in/mark-freeman', url: 'https://linkedin.com' }, { label: 'GitHub', value: '/mark-freeman', url: 'https://github.com' }, - { label: 'Website', value: 'mark-freeman-personal-website.com', url: '#', fullRow: true }, + { label: 'Website', value: 'mark-freeman-personal-website.com', url: '/', fullRow: true }, ], 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. Nulla lacinia, erat sit amet elementum vulputate, lectus mauris volutpat mi, vitae accumsan metus elit ut nunc. Vestibulum lacinia enim eget eros fermentum scelerisque. Proin augue leo, posuere ut imperdiet vitae, fermentum eu ipsum. Sed sed neque sagittis, posuere urna nec, commodo leo. Pellentesque posuere justo vitae massa volutpat maximus.', + 'Lorem ipsum dolor sit amet, consectetur **adipiscing elit**. In sodales ac dui at *vestibulum*. In condimentum metus id dui tincidunt, in blandit mi [vehicula](/). Nulla lacinia, erat sit amet elementum vulputate, lectus mauris volutpat mi, vitae accumsan metus elit ut nunc. Vestibulum lacinia enim eget eros fermentum scelerisque. Proin augue leo, posuere ut imperdiet vitae, fermentum eu ipsum. Sed sed neque sagittis, posuere urna nec, commodo leo. Pellentesque posuere justo vitae massa volutpat maximus.', tags: [{ name: 'Open for freelance' }, { name: 'Available for mentoring' }, { name: 'Working on side project' }], action: { label: 'Download CV', diff --git a/src/pdf/components/description.astro b/src/pdf/components/description.astro index a8bef5c..d22913d 100644 --- a/src/pdf/components/description.astro +++ b/src/pdf/components/description.astro @@ -1,23 +1,12 @@ --- -import type { Description } from '@/types/shared'; +import Description from '@/components/description.astro'; export interface Props { - content: Description; + content: string; } const { content } = Astro.props; +const baseClass = /* tw */ 'text-base font-normal text-gray-500'; --- -
- { - Array.isArray(content) ? ( - - ) : ( -
{content}
- ) - } -
+ diff --git a/src/pdf/sections/main-section.pdf.astro b/src/pdf/sections/main-section.pdf.astro index 14c647f..72e0009 100644 --- a/src/pdf/sections/main-section.pdf.astro +++ b/src/pdf/sections/main-section.pdf.astro @@ -1,6 +1,6 @@ --- import type { MainSection } from '@/types/sections/main-section.types'; -import Photo from '@/pdf/components/photo.astro'; +import Photo from '@/components/photo.astro'; import Description from '@/pdf/components/description.astro'; import LabelledValue from '@/pdf/components/labelled-value.astro'; diff --git a/src/pdf/sections/portfolio-section.pdf.astro b/src/pdf/sections/portfolio-section.pdf.astro index 7c2750e..e1db881 100644 --- a/src/pdf/sections/portfolio-section.pdf.astro +++ b/src/pdf/sections/portfolio-section.pdf.astro @@ -21,7 +21,7 @@ const { config, projects } = Astro.props;
-
+
{(pdfDetails ?? details).map((detail) => ( ))} diff --git a/src/types/sections/education-section.types.ts b/src/types/sections/education-section.types.ts index 3c41207..a1f1e6c 100644 --- a/src/types/sections/education-section.types.ts +++ b/src/types/sections/education-section.types.ts @@ -1,4 +1,4 @@ -import type { DateRange, Description, LinkButton, Section } from '../shared'; +import type { DateRange, LinkButton, Section } from '../shared'; export interface Diploma { /** @@ -17,9 +17,9 @@ export interface Diploma { dates: DateRange; /** - * A short overview of your studies. You can write it as a paragraph (string) or as a list of bullet points (string[]). + * A short overview of your studies. You can use markdown syntax. */ - description: Description; + description: string; /** * [WEB] Links related to your studies (e.g. course/university website, link to realized project). diff --git a/src/types/sections/experience-section.types.ts b/src/types/sections/experience-section.types.ts index 37c7726..fa1af39 100644 --- a/src/types/sections/experience-section.types.ts +++ b/src/types/sections/experience-section.types.ts @@ -1,4 +1,4 @@ -import type { DateRange, Description, LinkButton, Section, TagsList } from '../shared'; +import type { DateRange, LinkButton, Section, TagsList } from '../shared'; export interface Job { /** @@ -17,9 +17,9 @@ export interface Job { dates: DateRange; /** - * A short overview of your job. You can write it as a paragraph (string) or as a list of bullet points (string[]). + * A short overview of your job. You can use markdown syntax. */ - description: Description; + description: string; /** * Any information that you want to highlight. diff --git a/src/types/sections/portfolio-section.types.ts b/src/types/sections/portfolio-section.types.ts index ec6f523..ef9a0db 100644 --- a/src/types/sections/portfolio-section.types.ts +++ b/src/types/sections/portfolio-section.types.ts @@ -1,4 +1,4 @@ -import type { DateRange, Photo, LabelledValue, LinkButton, Section, TagsList, Description } from '../shared'; +import type { DateRange, Photo, LabelledValue, LinkButton, Section, TagsList } from '../shared'; export interface Project { /** @@ -35,9 +35,9 @@ export interface Project { pdfDetails?: LabelledValue[]; /** - * A short overview of the project. You can write it as a paragraph (string) or as a list of bullet points (string[]). + * A short overview of the project. You can use markdown syntax. */ - description: Description; + description: string; /** * Any information that you want to highlight. diff --git a/src/types/sections/testimonials-section.types.ts b/src/types/sections/testimonials-section.types.ts index 9f1b2e3..9007ee3 100644 --- a/src/types/sections/testimonials-section.types.ts +++ b/src/types/sections/testimonials-section.types.ts @@ -21,7 +21,7 @@ export interface Testimonial { relation: string; /** - * [WEB] Content of the testimonial. + * [WEB] Content of the testimonial. You can use markdown syntax. */ content: string; diff --git a/src/types/shared.ts b/src/types/shared.ts index 16eb30f..f270111 100644 --- a/src/types/shared.ts +++ b/src/types/shared.ts @@ -22,12 +22,6 @@ export type Photo = Promise<{ default: ImageMetadata }> | string; */ 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 interface SectionConfig { /** * Name displayed as a section header (except for the main section). diff --git a/src/web/components/description.astro b/src/web/components/description.astro index 5880c01..8dd56e4 100644 --- a/src/web/components/description.astro +++ b/src/web/components/description.astro @@ -1,29 +1,15 @@ --- -import type { Description } from '@/types/shared'; -import Typography from './typography.astro'; +import Description from '@/components/description.astro'; export interface Props { - content: Description; + content: string; class?: string; } -const { content, ...props } = Astro.props; +const { content, class: className } = Astro.props; + +const baseClass = + /* tw */ 'text-sm leading-relaxed font-normal text-gray-500 sm:text-base sm:leading-relaxed dark:text-gray-300'; --- -
- { - Array.isArray(content) ? ( -
    - {content.map((line) => ( - - {line} - - ))} -
- ) : ( - - {content} - - ) - } -
+ diff --git a/src/web/sections/favorites/book-tile.astro b/src/web/sections/favorites/book-tile.astro index 44b6ca3..b8c79e2 100644 --- a/src/web/sections/favorites/book-tile.astro +++ b/src/web/sections/favorites/book-tile.astro @@ -1,6 +1,6 @@ --- import type { Book } from '@/types/sections/favorites-section.types'; -import Photo from '@/web/components/photo.astro'; +import Photo from '@/components/photo.astro'; import Typography from '@/web/components/typography.astro'; export interface Props extends Book {} diff --git a/src/web/sections/favorites/media-tile.astro b/src/web/sections/favorites/media-tile.astro index cd318d2..038fcb3 100644 --- a/src/web/sections/favorites/media-tile.astro +++ b/src/web/sections/favorites/media-tile.astro @@ -1,6 +1,6 @@ --- import type { Media } from '@/types/sections/favorites-section.types'; -import Photo from '@/web/components/photo.astro'; +import Photo from '@/components/photo.astro'; import Typography from '@/web/components/typography.astro'; export interface Props extends Media {} diff --git a/src/web/sections/favorites/person-tile.astro b/src/web/sections/favorites/person-tile.astro index 99ab839..14cddd8 100644 --- a/src/web/sections/favorites/person-tile.astro +++ b/src/web/sections/favorites/person-tile.astro @@ -1,6 +1,6 @@ --- import type { Person } from '@/types/sections/favorites-section.types'; -import Photo from '@/web/components/photo.astro'; +import Photo from '@/components/photo.astro'; import Typography from '@/web/components/typography.astro'; export interface Props extends Person {} diff --git a/src/web/sections/favorites/video-tile.astro b/src/web/sections/favorites/video-tile.astro index d8911bc..8d88ffb 100644 --- a/src/web/sections/favorites/video-tile.astro +++ b/src/web/sections/favorites/video-tile.astro @@ -1,6 +1,6 @@ --- import type { Video } from '@/types/sections/favorites-section.types'; -import Photo from '@/web/components/photo.astro'; +import Photo from '@/components/photo.astro'; import Typography from '@/web/components/typography.astro'; export interface Props extends Video {} diff --git a/src/web/sections/main/main-section.web.astro b/src/web/sections/main/main-section.web.astro index 3d918aa..66123fb 100644 --- a/src/web/sections/main/main-section.web.astro +++ b/src/web/sections/main/main-section.web.astro @@ -1,8 +1,9 @@ --- import type { MainSection } from '@/types/sections/main-section.types'; +import Description from '@/web/components/description.astro'; import DownloadButton from '@/web/components/download-button.astro'; import LinkButton from '@/web/components/link-button.astro'; -import Photo from '@/web/components/photo.astro'; +import Photo from '@/components/photo.astro'; import SectionCard from '@/web/components/section-card.astro'; import TagsList from '@/web/components/tags-list.astro'; import Typography from '@/web/components/typography.astro'; @@ -54,7 +55,7 @@ const { action, config, description, details, fullName, image, links, role, tags }
- {description} +
diff --git a/src/web/sections/portfolio/project.astro b/src/web/sections/portfolio/project.astro index e63289f..9f86223 100644 --- a/src/web/sections/portfolio/project.astro +++ b/src/web/sections/portfolio/project.astro @@ -3,7 +3,7 @@ import type { Project } from '@/types/sections/portfolio-section.types'; import Description from '@/web/components/description.astro'; import LabelledValue from '@/web/components/labelled-value.astro'; import LinkButton from '@/web/components/link-button.astro'; -import Photo from '@/web/components/photo.astro'; +import Photo from '@/components/photo.astro'; import TagsList from '@/web/components/tags-list.astro'; import Timestamp from '@/web/components/timestamp.astro'; import Typography from '@/web/components/typography.astro'; diff --git a/src/web/sections/testimonials/testimonial.astro b/src/web/sections/testimonials/testimonial.astro index c0b1b3b..eb4599e 100644 --- a/src/web/sections/testimonials/testimonial.astro +++ b/src/web/sections/testimonials/testimonial.astro @@ -1,8 +1,9 @@ --- import type { Testimonial } from '@/types/sections/testimonials-section.types'; import LinkButton from '@/web/components/link-button.astro'; -import Photo from '@/web/components/photo.astro'; +import Photo from '@/components/photo.astro'; import Typography from '@/web/components/typography.astro'; +import Description from '@/web/components/description.astro'; export interface Props extends Testimonial {} @@ -28,5 +29,5 @@ const { author, content, image, links, relation } = Astro.props; ) }
- {content} +