diff --git a/astro.config.mjs b/astro.config.mjs index e90a62c3..f7f6fa3e 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -19,6 +19,7 @@ export default defineConfig({ }, }), ], + prefetch: true, output: 'server', adapter: netlify(), vite: { diff --git a/src/consts.ts b/src/consts.ts index 5fc306ba..7e8853df 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -1,2 +1,9 @@ export const SITE_TITLE = 'Bianca Fiore'; export const SITE_DESCRIPTION = 'Welcome to my website!'; + +export const DEFAULT_DATE_OPTIONS: Intl.DateTimeFormatOptions = { + weekday: 'long', + year: 'numeric', + month: 'long', + day: 'numeric', +}; diff --git a/src/content/articles/first-post.md b/src/content/articles/first-post.md index 169d2794..0e7c7ee9 100644 --- a/src/content/articles/first-post.md +++ b/src/content/articles/first-post.md @@ -3,6 +3,8 @@ title: 'First post' description: 'Lorem ipsum dolor sit amet' publishDate: 'Jul 08 2022' featuredImage: '' +tags: ['first', 'post'] +author: 'Bianca Fiore' slug: 'first-post' --- diff --git a/src/content/articles/markdown-style-guide.md b/src/content/articles/markdown-style-guide.md index b2b14eb4..a293089a 100644 --- a/src/content/articles/markdown-style-guide.md +++ b/src/content/articles/markdown-style-guide.md @@ -3,6 +3,8 @@ title: 'Markdown Style Guide' description: 'Here is a sample of some basic Markdown syntax that can be used when writing Markdown content in Astro.' publishDate: 'Jul 01 2022' featuredImage: '' +tags: ['second', 'post'] +author: 'Bianca Fiore' slug: 'markdown-style-guide' --- @@ -98,7 +100,7 @@ November 18, 2015. #### Output | Italics | Bold | Code | -| --------- | -------- | ------ | +|-----------|----------|--------| | _italics_ | **bold** | `code` | ## Code Blocks @@ -129,13 +131,13 @@ Output ```html - - - Example HTML5 Document - - -

Test

- + + + Example HTML5 Document + + +

Test

+ ``` @@ -162,40 +164,40 @@ Output #### Syntax ```markdown -- List item -- Another item -- And another item +- List item +- Another item +- And another item ``` #### Output -- List item -- Another item -- And another item +- List item +- Another item +- And another item ### Nested list #### Syntax ```markdown -- Fruit - - Apple - - Orange - - Banana -- Dairy - - Milk - - Cheese +- Fruit + - Apple + - Orange + - Banana +- Dairy + - Milk + - Cheese ``` #### Output -- Fruit - - Apple - - Orange - - Banana -- Dairy - - Milk - - Cheese +- Fruit + - Apple + - Orange + - Banana +- Dairy + - Milk + - Cheese ## Other Elements — abbr, sub, sup, kbd, mark diff --git a/src/content/articles/second-post.md b/src/content/articles/second-post.md index 6ea60b07..115aa3a2 100644 --- a/src/content/articles/second-post.md +++ b/src/content/articles/second-post.md @@ -3,6 +3,8 @@ title: 'Second post' description: 'Lorem ipsum dolor sit amet' publishDate: 'Jul 22 2022' featuredImage: '' +tags: ['post'] +author: 'Bianca Fiore' slug: 'second-post' --- diff --git a/src/content/articles/third-post.md b/src/content/articles/third-post.md index d664cb6f..daa0b28b 100644 --- a/src/content/articles/third-post.md +++ b/src/content/articles/third-post.md @@ -3,6 +3,8 @@ title: 'Third post' description: 'Lorem ipsum dolor sit amet' publishDate: 'Jul 15 2022' featuredImage: '' +tags: [] +author: 'Bianca Fiore' slug: 'third-post' --- diff --git a/src/content/articles/using-mdx.mdx b/src/content/articles/using-mdx.mdx index 70206593..ef3dbc8a 100644 --- a/src/content/articles/using-mdx.mdx +++ b/src/content/articles/using-mdx.mdx @@ -3,6 +3,8 @@ title: 'Using MDX' description: 'Lorem ipsum dolor sit amet' publishDate: 'Jul 02 2022' featuredImage: '' +tags: ['first', 'post'] +author: 'Bianca Fiore' slug: 'using-mdx' --- @@ -23,6 +25,8 @@ If you have existing content authored in MDX, this integration will hopefully ma Here is how you import and use a UI component inside of MDX. When you open this page in the browser, you should see the clickable button below. + + import HeaderLink from '../../ui/components/atoms/headerLink/HeaderLink.astro'; @@ -34,5 +38,5 @@ import HeaderLink from '../../ui/components/atoms/headerLink/HeaderLink.astro'; - [MDX Syntax Documentation](https://mdxjs.com/docs/what-is-mdx) - [Astro Usage Documentation](https://docs.astro.build/en/guides/markdown-content/#markdown-and-mdx-pages) - **Note:** [Client Directives](https://docs.astro.build/en/reference/directives-reference/#client-directives) are - still required to create interactive components. Otherwise, all components in your MDX will render as static HTML - (no JavaScript) by default. +still required to create interactive components. Otherwise, all components in your MDX will render as static HTML +(no JavaScript) by default. diff --git a/src/content/config.ts b/src/content/config.ts index 026f76c2..ab42913e 100644 --- a/src/content/config.ts +++ b/src/content/config.ts @@ -7,6 +7,8 @@ const articles = defineCollection({ publishDate: z.coerce.date(), updatedDate: z.coerce.date().optional(), featuredImage: z.string().optional(), + tags: z.string().array().optional(), + author: z.string(), }), }); diff --git a/src/pages/index.astro b/src/pages/index.astro index f0b778f1..19e4ec14 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -5,11 +5,12 @@ import Testimonials from '@components/organisms/testimonials/Testimonials.astro' import MyWork from '@components/organisms/myWork/MyWork.astro'; import LatestArticles from '@components/organisms/latestArticles/LatestArticles.astro'; -// current todo: fresh from the blog +// current todo: fresh from the blog (variants) // todo: latest articles following(https://scroll-driven-animations.style/demos/stacking-cards/css/) // todo: reveal on enter viewport (check current implementation). add .reveal to test // todo: SEO + HTML structure // todo: view transitions +// todo: theme toggle // todo: add vitest // todo: add CIs --- @@ -18,13 +19,4 @@ import LatestArticles from '@components/organisms/latestArticles/LatestArticles. -
-
-
-
-
-
-
-
- diff --git a/src/pages/tags/[...tag].astro b/src/pages/tags/[...tag].astro new file mode 100644 index 00000000..e76fbe13 --- /dev/null +++ b/src/pages/tags/[...tag].astro @@ -0,0 +1,32 @@ +--- +import { getCollection } from 'astro:content'; +import BaseLayout from 'src/ui/components/templates/baseLayout/BaseLayout.astro'; +import ArticleLayout from 'src/ui/components/templates/articleLayout/ArticleLayout.astro'; + +export async function getStaticPaths() { + const allPosts = await getCollection('articles'); + const uniqueTags = [...new Set(allPosts.map((post) => post.data.tags)?.flat())]; + + return uniqueTags?.map((tag) => { + const filteredPosts = allPosts.filter((post) => + post.data.tags.includes(tag), + ); + return { + params: { tag }, + props: { posts: filteredPosts }, + }; + }); +} + +const { tag = '' } = Astro.params; +const { posts } = Astro.props; +--- + + +

Posts tagged with {tag}

+
    + {posts?.map((post) => + , + )} +
+
diff --git a/src/pages/tags/index.astro b/src/pages/tags/index.astro new file mode 100644 index 00000000..ef867d92 --- /dev/null +++ b/src/pages/tags/index.astro @@ -0,0 +1,7 @@ +--- +import BaseLayout from '@components/templates/baseLayout/BaseLayout.astro'; +--- + + +

Hello, blog!

+
diff --git a/src/ui/components/atoms/logo/logo.css b/src/ui/components/atoms/logo/logo.css index c5ea42e8..91f97dcc 100644 --- a/src/ui/components/atoms/logo/logo.css +++ b/src/ui/components/atoms/logo/logo.css @@ -12,7 +12,7 @@ svg { transition: scale 0.2s, - fill 0.2s; + fill 0.3s; } &.--is-scrolling:not(.--is-menu-open) svg { diff --git a/src/ui/components/organisms/header/components/menuButton/menuButton.css b/src/ui/components/organisms/header/components/menuButton/menuButton.css index e7c6156d..f379ecce 100644 --- a/src/ui/components/organisms/header/components/menuButton/menuButton.css +++ b/src/ui/components/organisms/header/components/menuButton/menuButton.css @@ -18,7 +18,7 @@ border: 1px solid var(--neutral-main); height: calc(var(--header-height) * 0.85); position: absolute; - transition: border 0.3s; + transition: border 0.2s; translate: 0 -25%; width: calc(var(--header-height) * 0.85); z-index: 20; diff --git a/src/ui/components/organisms/header/utils/intersectionObserver/intersectionObserver.ts b/src/ui/components/organisms/header/utils/intersectionObserver/intersectionObserver.ts index a1b9e80e..ede8ae17 100644 --- a/src/ui/components/organisms/header/utils/intersectionObserver/intersectionObserver.ts +++ b/src/ui/components/organisms/header/utils/intersectionObserver/intersectionObserver.ts @@ -1,39 +1,53 @@ +const SELECTORS = { + HEADER: '.header', + LATEST_ARTICLES: '.latest-articles__wrapper', + SITE_LOGO_SVG: '.site__logo svg', + HEADER_MENU_TEXT: '.header', + HEADER_MENU_OUTLINES: '.header__menu-button__outline', +}; + +const getComputedStyleValue = (property: string): string => + getComputedStyle(document.documentElement).getPropertyValue(property); + +function isIntersecting(element: HTMLElement): boolean { + const { HEADER: HEADER_SELECTOR } = SELECTORS; + const headerOffsetHeight = (document.querySelector(HEADER_SELECTOR) as HTMLElement).offsetHeight / 2; + const threshold = element.offsetTop - headerOffsetHeight; + const sectionBottom = element.offsetTop + element.offsetHeight - headerOffsetHeight; + + return window.scrollY >= threshold && window.scrollY < sectionBottom; +} + export function intersectionObserver(): void { - function handleScroll() { - let hasIntersected = false; - const WHITE = getComputedStyle(document.documentElement).getPropertyValue('--white'); - const BLACK = getComputedStyle(document.documentElement).getPropertyValue("--neutral-main'"); - const HEADER = document.querySelector('.header') as HTMLElement; - const LATEST_ARTICLES = document.querySelector('.latest-articles__wrapper') as HTMLElement; - const SITE_LOGO_SVG = document.querySelector('.site__logo svg') as HTMLElement; - const HEADER_MENU_TEXT = document.querySelector('.header__menu-text') as HTMLElement; - const HEADER_MENU_OUTLINES = document.querySelectorAll( - '.header__menu-button__outline' - ) as unknown as HTMLElement[]; - const ELEMENTS_TO_INTERSECT: HTMLElement[] = [LATEST_ARTICLES]; - - if (!HEADER || !LATEST_ARTICLES) return; - - ELEMENTS_TO_INTERSECT.forEach(({ offsetTop, offsetHeight }) => { - const headerOffsetHeight = HEADER.offsetHeight / 2; - const threshold = offsetTop - headerOffsetHeight; - const sectionBottom = offsetTop + offsetHeight - headerOffsetHeight; - - if (window.scrollY >= threshold && window.scrollY < sectionBottom) hasIntersected = true; - }); - - if (hasIntersected) { - HEADER.classList.add('--hue-change'); - SITE_LOGO_SVG.style.fill = WHITE; - HEADER_MENU_TEXT.style.color = WHITE; - HEADER_MENU_OUTLINES.forEach((element) => (element.style.borderColor = WHITE)); - } else { - HEADER.classList.remove('--hue-change'); - SITE_LOGO_SVG.style.fill = BLACK; - HEADER_MENU_TEXT.style.color = BLACK; - HEADER_MENU_OUTLINES.forEach((element) => (element.style.borderColor = BLACK)); - } - } + const WHITE = getComputedStyleValue('--white'); + const BLACK = getComputedStyleValue('--neutral-main'); + const { + HEADER: HEADER_SELECTOR, + LATEST_ARTICLES: LATEST_ARTICLES_SELECTOR, + SITE_LOGO_SVG: SITE_LOGO_SVG_SELECTOR, + HEADER_MENU_TEXT: HEADER_MENU_TEXT_SELECTOR, + HEADER_MENU_OUTLINES: HEADER_MENU_OUTLINES_SELECTOR, + } = SELECTORS; - window.addEventListener('scroll', handleScroll); + const HEADER = document.querySelector(HEADER_SELECTOR) as HTMLElement; + const LATEST_ARTICLES = document.querySelector(LATEST_ARTICLES_SELECTOR) as HTMLElement; + const SITE_LOGO_SVG = document.querySelector(SITE_LOGO_SVG_SELECTOR) as HTMLElement; + const HEADER_MENU_TEXT = document.querySelector(HEADER_MENU_TEXT_SELECTOR) as HTMLElement; + const HEADER_MENU_OUTLINES = document.querySelectorAll(HEADER_MENU_OUTLINES_SELECTOR) as unknown as HTMLElement[]; + + if (!HEADER || !LATEST_ARTICLES) return; + + const hasIntersected = isIntersecting(LATEST_ARTICLES); + + if (hasIntersected) { + SITE_LOGO_SVG.style.fill = WHITE; + HEADER_MENU_TEXT.style.color = WHITE; + HEADER_MENU_OUTLINES.forEach((element) => (element.style.borderColor = WHITE)); + } else { + SITE_LOGO_SVG.style.fill = BLACK; + HEADER_MENU_TEXT.style.color = BLACK; + HEADER_MENU_OUTLINES.forEach((element) => (element.style.borderColor = BLACK)); + } } + +window.addEventListener('scroll', intersectionObserver); diff --git a/src/ui/components/organisms/latestArticles/LatestArticles.astro b/src/ui/components/organisms/latestArticles/LatestArticles.astro index 352f84e4..834051f7 100644 --- a/src/ui/components/organisms/latestArticles/LatestArticles.astro +++ b/src/ui/components/organisms/latestArticles/LatestArticles.astro @@ -1,6 +1,12 @@ --- import './latestArticles.css'; import { getCollection } from 'astro:content'; +import { DEFAULT_DATE_OPTIONS } from 'src/consts'; + +const enum ArticleType { + FEATURED = 'featured', + DEFAULT = 'default', +} const MAX_ARTICLES = 4; @@ -10,9 +16,12 @@ posts.sort((a, b) => new Date(b.data.publishDate) - new Date(a.data.publishDate)

Fresh from the blog

-
    +
      {posts.map(({ slug, data }) => { - const href = `/articles/${slug}`; + const variant: ArticleType = data.featuredImage ? ArticleType.FEATURED : ArticleType.DEFAULT; + const publishedDate = data.publishDate.toLocaleDateString('en', DEFAULT_DATE_OPTIONS); + const href = `/articles/${slug}`; + console.log(variant) return (
    • @@ -21,9 +30,18 @@ posts.sort((a, b) => new Date(b.data.publishDate) - new Date(a.data.publishDate) {data.title} - {data.title} + {data.featuredImage && ( + {data.title} + )}

      {data.description}

      - + +

      {data.author}

      + {data.tags?.map((tag) => ( + {tag} + ))}
    • ); diff --git a/src/ui/components/organisms/latestArticles/latestArticles.css b/src/ui/components/organisms/latestArticles/latestArticles.css index 67486f14..3c041878 100644 --- a/src/ui/components/organisms/latestArticles/latestArticles.css +++ b/src/ui/components/organisms/latestArticles/latestArticles.css @@ -12,4 +12,10 @@ display: inline-block; } } + + .latest__article__item { + & > * { + color: var(--white); + } + } }