mirror of
https://github.com/mikkelsvartveit/astro-personal-website.git
synced 2025-12-22 11:12:38 +00:00
Build article page
This commit is contained in:
parent
296d8c8874
commit
819f2e4aca
11 changed files with 230 additions and 10 deletions
BIN
src/assets/images/lorempicsum.jpeg
Normal file
BIN
src/assets/images/lorempicsum.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 46 KiB |
|
|
@ -9,9 +9,9 @@
|
|||
$: isScrolled = scrollPosition > 0;
|
||||
|
||||
const navbarContent = [
|
||||
{ name: "📝 Articles", href: "/articles" },
|
||||
{ name: "👨💻 Projects", href: "/programming" },
|
||||
{ name: "📷 Photography", href: "/photography" },
|
||||
// { name: "📝 Articles", href: "/articles" },
|
||||
];
|
||||
|
||||
let collapsed = true;
|
||||
|
|
|
|||
21
src/content/blog/lorem-2.md
Normal file
21
src/content/blog/lorem-2.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
intro: "Nunc at ex consequat, tincidunt est eu, pellentesque tellus. Sed sodales massa et condimentum pharetra. Curabitur euismod ac arcu id dapibus."
|
||||
image: "@assets/images/lorempicsum.jpeg"
|
||||
date: 2023-10-19
|
||||
---
|
||||
|
||||
# Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc at ex consequat, tincidunt est eu, pellentesque tellus. Sed sodales massa et condimentum pharetra. Curabitur euismod ac arcu id dapibus. Aliquam viverra tellus quis sem interdum commodo. Vivamus vel porttitor massa. Fusce vitae risus quis lacus blandit tincidunt. Phasellus pretium condimentum eleifend. Ut sit amet ligula eget sapien luctus bibendum eu in neque. Praesent at commodo augue. Sed a aliquet nibh. Praesent venenatis massa sit amet tempor volutpat. Praesent porttitor ultricies dui, non rutrum tortor eleifend et. Ut et massa a massa bibendum ornare vitae non massa. Donec lacus lacus, tempor id mollis ac, commodo et tortor.
|
||||
|
||||
Donec malesuada, mauris id viverra viverra, velit velit finibus nulla, quis elementum orci elit non mauris. Phasellus odio neque, lobortis in dignissim at, aliquet in quam. Nullam et sodales nibh. Integer vulputate lacinia ultrices. Cras pharetra tincidunt vehicula. Maecenas sit amet eleifend dolor, sed accumsan magna. Mauris sed mi quis magna molestie molestie.
|
||||
|
||||
Integer dui sem, imperdiet sit amet pretium nec, interdum sit amet justo. Praesent imperdiet ante urna, ac commodo nisl luctus quis. Aenean sit amet pretium dolor. Maecenas efficitur augue eget ipsum vulputate, quis dapibus nulla egestas. Nunc et ullamcorper risus. Morbi mauris neque, malesuada sit amet dictum et, fringilla vel velit. Suspendisse tincidunt neque vitae orci pharetra, vel rhoncus justo maximus. Quisque lacinia feugiat vulputate. Donec quis nunc felis. Donec rhoncus tempor ex sit amet tristique. Integer a ex velit. Nunc nec sapien sit amet massa pretium elementum eget vitae tellus. Curabitur et ligula sit amet turpis viverra convallis. Interdum et malesuada fames ac ante ipsum primis in faucibus.
|
||||
|
||||
Curabitur at ex facilisis, tincidunt risus lacinia, maximus arcu. Suspendisse lobortis id orci at laoreet. Donec luctus urna ac condimentum aliquet. Nulla ac libero lacus. Vestibulum fermentum, augue at faucibus laoreet, leo libero blandit mi, et porta libero justo non risus. Etiam sollicitudin facilisis condimentum. Proin a gravida velit, quis pulvinar odio. Nam vehicula risus in nisi euismod, in hendrerit est fermentum. Morbi fermentum elementum urna, non rhoncus libero sodales eget. Curabitur sed felis sit amet dolor facilisis elementum et vitae dolor.
|
||||
|
||||
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam quis tempor lorem. Sed bibendum pulvinar nibh eget feugiat. Sed at vehicula odio. Vivamus porttitor magna tortor, sit amet venenatis sapien lobortis at. Nam placerat condimentum purus in pellentesque. Quisque gravida tincidunt tincidunt. Duis varius, est ac molestie posuere, nisl mauris lacinia ex, tincidunt hendrerit enim eros eget turpis. Nulla facilisi.
|
||||
21
src/content/blog/lorem-3.md
Normal file
21
src/content/blog/lorem-3.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
intro: "Nunc at ex consequat, tincidunt est eu, pellentesque tellus. Sed sodales massa et condimentum pharetra. Curabitur euismod ac arcu id dapibus."
|
||||
image: "@assets/images/lorempicsum.jpeg"
|
||||
date: 2023-10-19
|
||||
---
|
||||
|
||||
# Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc at ex consequat, tincidunt est eu, pellentesque tellus. Sed sodales massa et condimentum pharetra. Curabitur euismod ac arcu id dapibus. Aliquam viverra tellus quis sem interdum commodo. Vivamus vel porttitor massa. Fusce vitae risus quis lacus blandit tincidunt. Phasellus pretium condimentum eleifend. Ut sit amet ligula eget sapien luctus bibendum eu in neque. Praesent at commodo augue. Sed a aliquet nibh. Praesent venenatis massa sit amet tempor volutpat. Praesent porttitor ultricies dui, non rutrum tortor eleifend et. Ut et massa a massa bibendum ornare vitae non massa. Donec lacus lacus, tempor id mollis ac, commodo et tortor.
|
||||
|
||||
Donec malesuada, mauris id viverra viverra, velit velit finibus nulla, quis elementum orci elit non mauris. Phasellus odio neque, lobortis in dignissim at, aliquet in quam. Nullam et sodales nibh. Integer vulputate lacinia ultrices. Cras pharetra tincidunt vehicula. Maecenas sit amet eleifend dolor, sed accumsan magna. Mauris sed mi quis magna molestie molestie.
|
||||
|
||||
Integer dui sem, imperdiet sit amet pretium nec, interdum sit amet justo. Praesent imperdiet ante urna, ac commodo nisl luctus quis. Aenean sit amet pretium dolor. Maecenas efficitur augue eget ipsum vulputate, quis dapibus nulla egestas. Nunc et ullamcorper risus. Morbi mauris neque, malesuada sit amet dictum et, fringilla vel velit. Suspendisse tincidunt neque vitae orci pharetra, vel rhoncus justo maximus. Quisque lacinia feugiat vulputate. Donec quis nunc felis. Donec rhoncus tempor ex sit amet tristique. Integer a ex velit. Nunc nec sapien sit amet massa pretium elementum eget vitae tellus. Curabitur et ligula sit amet turpis viverra convallis. Interdum et malesuada fames ac ante ipsum primis in faucibus.
|
||||
|
||||
Curabitur at ex facilisis, tincidunt risus lacinia, maximus arcu. Suspendisse lobortis id orci at laoreet. Donec luctus urna ac condimentum aliquet. Nulla ac libero lacus. Vestibulum fermentum, augue at faucibus laoreet, leo libero blandit mi, et porta libero justo non risus. Etiam sollicitudin facilisis condimentum. Proin a gravida velit, quis pulvinar odio. Nam vehicula risus in nisi euismod, in hendrerit est fermentum. Morbi fermentum elementum urna, non rhoncus libero sodales eget. Curabitur sed felis sit amet dolor facilisis elementum et vitae dolor.
|
||||
|
||||
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam quis tempor lorem. Sed bibendum pulvinar nibh eget feugiat. Sed at vehicula odio. Vivamus porttitor magna tortor, sit amet venenatis sapien lobortis at. Nam placerat condimentum purus in pellentesque. Quisque gravida tincidunt tincidunt. Duis varius, est ac molestie posuere, nisl mauris lacinia ex, tincidunt hendrerit enim eros eget turpis. Nulla facilisi.
|
||||
21
src/content/blog/lorem.md
Normal file
21
src/content/blog/lorem.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
intro: "Nunc at ex consequat, tincidunt est eu, pellentesque tellus. Sed sodales massa et condimentum pharetra. Curabitur euismod ac arcu id dapibus."
|
||||
image: "@assets/images/lorempicsum.jpeg"
|
||||
date: 2023-10-19
|
||||
---
|
||||
|
||||
# Lorem ipsum dolor sit amet, consectetur adipiscing elit
|
||||
|
||||
## Heading 2
|
||||
|
||||
### Heading 3
|
||||
|
||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc at ex consequat, tincidunt est eu, pellentesque tellus. Sed sodales massa et condimentum pharetra. Curabitur euismod ac arcu id dapibus. Aliquam viverra tellus quis sem interdum commodo. Vivamus vel porttitor massa. Fusce vitae risus quis lacus blandit tincidunt. Phasellus pretium condimentum eleifend. Ut sit amet ligula eget sapien luctus bibendum eu in neque. Praesent at commodo augue. Sed a aliquet nibh. Praesent venenatis massa sit amet tempor volutpat. Praesent porttitor ultricies dui, non rutrum tortor eleifend et. Ut et massa a massa bibendum ornare vitae non massa. Donec lacus lacus, tempor id mollis ac, commodo et tortor.
|
||||
|
||||
Donec malesuada, mauris id viverra viverra, velit velit finibus nulla, quis elementum orci elit non mauris. Phasellus odio neque, lobortis in dignissim at, aliquet in quam. Nullam et sodales nibh. Integer vulputate lacinia ultrices. Cras pharetra tincidunt vehicula. Maecenas sit amet eleifend dolor, sed accumsan magna. Mauris sed mi quis magna molestie molestie.
|
||||
|
||||
Integer dui sem, imperdiet sit amet pretium nec, interdum sit amet justo. Praesent imperdiet ante urna, ac commodo nisl luctus quis. Aenean sit amet pretium dolor. Maecenas efficitur augue eget ipsum vulputate, quis dapibus nulla egestas. Nunc et ullamcorper risus. Morbi mauris neque, malesuada sit amet dictum et, fringilla vel velit. Suspendisse tincidunt neque vitae orci pharetra, vel rhoncus justo maximus. Quisque lacinia feugiat vulputate. Donec quis nunc felis. Donec rhoncus tempor ex sit amet tristique. Integer a ex velit. Nunc nec sapien sit amet massa pretium elementum eget vitae tellus. Curabitur et ligula sit amet turpis viverra convallis. Interdum et malesuada fames ac ante ipsum primis in faucibus.
|
||||
|
||||
Curabitur at ex facilisis, tincidunt risus lacinia, maximus arcu. Suspendisse lobortis id orci at laoreet. Donec luctus urna ac condimentum aliquet. Nulla ac libero lacus. Vestibulum fermentum, augue at faucibus laoreet, leo libero blandit mi, et porta libero justo non risus. Etiam sollicitudin facilisis condimentum. Proin a gravida velit, quis pulvinar odio. Nam vehicula risus in nisi euismod, in hendrerit est fermentum. Morbi fermentum elementum urna, non rhoncus libero sodales eget. Curabitur sed felis sit amet dolor facilisis elementum et vitae dolor.
|
||||
|
||||
Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Etiam quis tempor lorem. Sed bibendum pulvinar nibh eget feugiat. Sed at vehicula odio. Vivamus porttitor magna tortor, sit amet venenatis sapien lobortis at. Nam placerat condimentum purus in pellentesque. Quisque gravida tincidunt tincidunt. Duis varius, est ac molestie posuere, nisl mauris lacinia ex, tincidunt hendrerit enim eros eget turpis. Nulla facilisi.
|
||||
|
|
@ -14,6 +14,17 @@ const programmingCollection = defineCollection({
|
|||
}),
|
||||
});
|
||||
|
||||
const blogCollection = defineCollection({
|
||||
type: "content",
|
||||
schema: ({ image }) =>
|
||||
z.object({
|
||||
image: image(),
|
||||
intro: z.string(),
|
||||
date: z.date(),
|
||||
}),
|
||||
});
|
||||
|
||||
export const collections = {
|
||||
programming: programmingCollection,
|
||||
blog: blogCollection,
|
||||
};
|
||||
|
|
|
|||
43
src/pages/articles/[article].astro
Normal file
43
src/pages/articles/[article].astro
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
---
|
||||
import ContainerLayout from "@layouts/ContainerLayout.astro";
|
||||
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||
import TextContentLayout from "@layouts/TextContentLayout.astro";
|
||||
import type { GetStaticPaths } from "astro";
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
export const getStaticPaths = (async () => {
|
||||
const blogCollection = await getCollection("blog");
|
||||
return blogCollection.map((entry) => ({
|
||||
params: {
|
||||
article: entry.slug,
|
||||
},
|
||||
props: { entry },
|
||||
}));
|
||||
}) satisfies GetStaticPaths;
|
||||
|
||||
const project = Astro.props.entry;
|
||||
const { Content } = await project.render();
|
||||
const { title, date } = project.data;
|
||||
---
|
||||
|
||||
<BaseLayout {title}>
|
||||
<ContainerLayout>
|
||||
<TextContentLayout>
|
||||
<p class="mx-auto mb-4 text-gray-500">
|
||||
{
|
||||
new Date(date).toLocaleDateString("en-US", {
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
year: "numeric",
|
||||
})
|
||||
}
|
||||
</p>
|
||||
|
||||
<div
|
||||
class="prose prose-lg max-w-none font-serif prose-headings:text-gray-600 prose-h1:font-light prose-h1:leading-snug prose-h1:underline prose-h1:decoration-yellow-400 prose-h1:decoration-2 prose-h1:underline-offset-8 prose-h2:font-light prose-p:text-gray-700 prose-a:text-teal-600 prose-a:no-underline prose-a:duration-100 hover:prose-a:text-teal-500 hover:prose-a:underline prose-strong:text-gray-700 before:prose-code:content-[''] after:prose-code:content-['']"
|
||||
>
|
||||
<Content />
|
||||
</div>
|
||||
</TextContentLayout>
|
||||
</ContainerLayout>
|
||||
</BaseLayout>
|
||||
60
src/pages/articles/index.astro
Normal file
60
src/pages/articles/index.astro
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
---
|
||||
import { Image } from "astro:assets";
|
||||
import Paragraph from "@components/Paragraph.astro";
|
||||
import ContainerLayout from "@layouts/ContainerLayout.astro";
|
||||
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||
import TextContentLayout from "@layouts/TextContentLayout.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
const articles = await getCollection("blog");
|
||||
---
|
||||
|
||||
<BaseLayout title="Programming">
|
||||
<ContainerLayout>
|
||||
<TextContentLayout>
|
||||
<h1
|
||||
class="mb-8 text-center font-serif text-3xl font-light tracking-wide text-gray-600 sm:text-4xl"
|
||||
>
|
||||
Articles
|
||||
</h1>
|
||||
|
||||
<Paragraph>
|
||||
Sometimes I write about technology, programming, software, productivity
|
||||
or other things that interests me.
|
||||
</Paragraph>
|
||||
|
||||
<section class="sm:max-w-2xl">
|
||||
{
|
||||
articles
|
||||
.sort((p2, p1) => p1.data.date.getTime() - p2.data.date.getTime())
|
||||
.map(async (article) => {
|
||||
const { slug, data } = article;
|
||||
const { image, intro } = data;
|
||||
const { headings } = await article.render();
|
||||
const title = headings[0].text;
|
||||
return (
|
||||
<a
|
||||
href={`/articles/${slug}`}
|
||||
class="my-8 grid grid-cols-1 mx-auto max-w-xs sm:max-w-none sm:grid-cols-3 overflow-hidden rounded-lg bg-white shadow duration-100 hover:translate-x-1 hover:shadow-md"
|
||||
>
|
||||
<Image
|
||||
src={image}
|
||||
alt={title}
|
||||
class="col-span-1 object-cover h-48 sm:h-full"
|
||||
/>
|
||||
|
||||
<div class="col-span-1 sm:col-span-2 p-4">
|
||||
<h2 class="mb-2 text-xl font-serif text-gray-700 line-clamp-2">
|
||||
{title}
|
||||
</h2>
|
||||
|
||||
<p class="line-clamp-2 text-gray-500 font-serif">{intro}</p>
|
||||
</div>
|
||||
</a>
|
||||
);
|
||||
})
|
||||
}
|
||||
</section>
|
||||
</TextContentLayout>
|
||||
</ContainerLayout>
|
||||
</BaseLayout>
|
||||
|
|
@ -1,18 +1,26 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import { Image } from "astro:assets";
|
||||
import BaseLayout from "../layouts/BaseLayout.astro";
|
||||
import Link from "@components/Link.astro";
|
||||
import Paragraph from "@components/Paragraph.astro";
|
||||
import SocialIcons from "@components/SocialIcons.astro";
|
||||
|
||||
import portraitImage from "@assets/images/portrait.jpg";
|
||||
|
||||
const articles = await getCollection("blog");
|
||||
const latestArticle = articles.sort(
|
||||
(p2, p1) => p1.data.date.getTime() - p2.data.date.getTime(),
|
||||
)[0];
|
||||
const latestArticleSlug = latestArticle.slug;
|
||||
const latestArticleTitle = (await latestArticle.render()).headings[0].text;
|
||||
const latestArticleImage = latestArticle.data.image;
|
||||
---
|
||||
|
||||
<BaseLayout>
|
||||
<div
|
||||
class="mx-auto flex max-w-5xl flex-col-reverse px-3 pb-8 pt-12 sm:px-6 md:flex-row"
|
||||
class="mx-auto flex max-w-5xl flex-col-reverse px-3 pb-6 pt-8 sm:px-6 md:flex-row items-stretch"
|
||||
>
|
||||
<section class="w-full md:w-1/2">
|
||||
<section class="w-full md:w-3/5 mb-10 mt-4">
|
||||
<h1
|
||||
class="mb-8 font-serif text-3xl font-light tracking-wide text-gray-600 sm:text-4xl"
|
||||
>
|
||||
|
|
@ -26,9 +34,10 @@ import portraitImage from "@assets/images/portrait.jpg";
|
|||
|
||||
<Paragraph>
|
||||
Here you will find some
|
||||
<Link href="/programming">programming projects</Link>, and a small
|
||||
<Link href="/programming">programming projects</Link>, a small
|
||||
<Link href="/photography">collection of photos</Link>
|
||||
I'm proud of.
|
||||
I'm proud of, and even a few
|
||||
<Link href="/articles">articles I've written</Link>.
|
||||
</Paragraph>
|
||||
|
||||
<Paragraph>
|
||||
|
|
@ -41,7 +50,7 @@ import portraitImage from "@assets/images/portrait.jpg";
|
|||
</div>
|
||||
</section>
|
||||
|
||||
<figure class="px-4 md:w-1/2">
|
||||
<figure class="px-4 md:w-1/2 my-auto">
|
||||
<Image
|
||||
class="mx-auto mb-12 block w-full max-w-sm rounded-full border-4 border-white bg-gray-100 text-transparent shadow-lg shadow-gray-400 md:mx-0 md:ml-auto md:w-5/6"
|
||||
src={portraitImage}
|
||||
|
|
@ -54,7 +63,21 @@ import portraitImage from "@assets/images/portrait.jpg";
|
|||
</figure>
|
||||
</div>
|
||||
|
||||
<footer class="mb-12 mt-4 flex justify-center">
|
||||
<a
|
||||
href={`/articles/${latestArticleSlug}`}
|
||||
class="mx-auto block max-w-lg px-3 sm:px-6 text-gray-600"
|
||||
>
|
||||
<h2 class="text-center text-lg mb-3 text-gray-500">Latest article</h2>
|
||||
|
||||
<div
|
||||
class="flex bg-white shadow transition hover:-translate-y-0.5 hover:shadow-md rounded-lg overflow-hidden items-center"
|
||||
>
|
||||
<Image src={latestArticleImage} alt="" class="w-32 h-20" />
|
||||
<h3 class="text-lg font-serif mx-3 line-clamp-2">{latestArticleTitle}</h3>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<footer class="mb-8 mt-20 flex justify-center w-full">
|
||||
<p class="text-xs text-gray-400">
|
||||
Built with
|
||||
<Link href="https://astro.build/" target="_blank">Astro</Link>
|
||||
|
|
@ -63,3 +86,24 @@ import portraitImage from "@assets/images/portrait.jpg";
|
|||
</p>
|
||||
</footer>
|
||||
</BaseLayout>
|
||||
|
||||
<!-- <style> -->
|
||||
<!-- .footer-fixed { -->
|
||||
<!-- position: fixed; -->
|
||||
<!-- bottom: 0; -->
|
||||
<!-- } -->
|
||||
<!-- </style> -->
|
||||
<!---->
|
||||
<!-- <script> -->
|
||||
<!-- window.addEventListener("DOMContentLoaded", checkFooterPosition); -->
|
||||
<!-- window.addEventListener("resize", checkFooterPosition); -->
|
||||
<!---->
|
||||
<!-- function checkFooterPosition() { -->
|
||||
<!-- const footer = document.querySelector("footer"); -->
|
||||
<!-- if (document.body.clientHeight <= window.innerHeight) { -->
|
||||
<!-- footer?.classList.add("footer-fixed"); -->
|
||||
<!-- } else { -->
|
||||
<!-- footer?.classList.remove("footer-fixed"); -->
|
||||
<!-- } -->
|
||||
<!-- } -->
|
||||
<!-- </script> -->
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import Paragraph from "@components/Paragraph.astro";
|
|||
import ContainerLayout from "@layouts/ContainerLayout.astro";
|
||||
import BaseLayout from "@layouts/BaseLayout.astro";
|
||||
import TextContentLayout from "@layouts/TextContentLayout.astro";
|
||||
import { Image } from "astro:assets";
|
||||
import Photo from "@components/Photo.astro";
|
||||
|
||||
const photos = await Astro.glob("../../assets/photos/*");
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ const projects = await getCollection("programming");
|
|||
.map(({ data, slug }) => (
|
||||
<a
|
||||
href={`/programming/${slug}`}
|
||||
class="mx-auto overflow-hidden rounded-lg bg-white pb-8 shadow-lg duration-100 hover:-translate-y-1 hover:shadow-xl"
|
||||
class="mx-auto overflow-hidden rounded-lg bg-white pb-8 shadow-md duration-100 hover:-translate-y-1 hover:shadow-lg"
|
||||
>
|
||||
<Image
|
||||
src={data.image}
|
||||
|
|
|
|||
Loading…
Reference in a new issue