2022-04-16 10:43:45 +00:00
< script lang = "ts" context = "module" >
import type { Load , LoadInput , LoadOutput } from '@sveltejs/kit';
import { differenceInCalendarDays , intlFormat } from 'date-fns';
2022-04-26 06:23:15 +00:00
export const prerender = true;
2022-04-16 10:43:45 +00:00
type BlogPost = {
filename: string;
2022-04-26 06:23:15 +00:00
preview: string[];
2022-04-16 10:43:45 +00:00
title: string;
slug: string;
date: Date;
book_review?: boolean;
};
export async function load({ fetch } : LoadInput): Promise< LoadOutput > {
const posts = await fetch('/api/blog.json')
.then((res) => res.json())
.then((res) => res.posts);
const mostRecentPost = posts[0];
const daysSinceLastPublish = differenceInCalendarDays(
new Date(),
new Date(mostRecentPost.date)
);
2022-06-05 12:02:17 +00:00
const numberOfPosts = posts.length;
const firstPost = posts[numberOfPosts - 1]
const daysSinceFirstPost = differenceInCalendarDays(new Date(), new Date(firstPost.date))
const averageDaysBetweenPosts = Number(daysSinceFirstPost / numberOfPosts).toFixed(2)
2022-04-16 10:43:45 +00:00
const res: LoadOutput = {
status: 200,
props: {
posts,
2022-06-05 12:02:17 +00:00
firstPost,
averageDaysBetweenPosts,
daysSinceFirstPost,
daysSinceLastPublish,
numberOfPosts,
2022-04-16 10:43:45 +00:00
}
};
return res;
}
< / script >
< script lang = "ts" >
import Navbar from '../components/Navbar.svelte';
export let posts: BlogPost[];
2022-06-05 12:02:17 +00:00
export let firstPost: BlogPost;
export let numberOfPosts: number;
2022-04-16 10:43:45 +00:00
export let daysSinceLastPublish: number;
2022-06-05 12:02:17 +00:00
export let daysSinceFirstPost: number;
export let averageDaysBetweenPosts: number;
2022-04-16 10:43:45 +00:00
< / script >
2022-04-17 10:07:40 +00:00
< svelte:head >
2022-05-27 19:35:55 +00:00
<!-- Primary Meta Tags -->
2022-04-17 10:07:40 +00:00
< title > Blog | thomaswilson.xyz< / title >
2022-05-27 19:35:55 +00:00
< meta name = "title" content = "Blog | thomaswilson.xyz" >
< meta name = "description" content = "I write about software and how I should have built it, and sometimes other things." >
<!-- Open Graph / Facebook -->
< meta property = "og:type" content = "website" >
< meta property = "og:url" content = "https://www.thomaswilson.xyz/blog" >
< meta property = "og:title" content = "Blog | thomaswilson.xyz" >
< meta property = "og:description" content = "I write about software and how I should have built it, and sometimes other things." >
<!-- Twitter -->
< meta property = "twitter:title" content = "Blog | thomaswilson.xyz" >
< meta property = "twitter:description" content = "I write about software and how I should have built it, and sometimes other things." >
2022-04-17 10:07:40 +00:00
< / svelte:head >
2022-04-16 10:43:45 +00:00
< Navbar / >
< main class = "thomaswilson-container" >
< section class = "thomaswilson-strapline section" >
< h1 > Blog< / h1 >
< p >
I write about software and I how I should have built it, books I've read, and sometimes other
things.
< / p >
< p >
2022-06-05 12:02:17 +00:00
It's been < span
2022-04-26 06:23:15 +00:00
class="days-since"
class:days-since-success={ daysSinceLastPublish === 0 }
>
2022-04-16 10:43:45 +00:00
{ daysSinceLastPublish }
< / span >
2022-06-05 12:02:17 +00:00
{ daysSinceLastPublish === 1 ? 'day' : 'days' } since I last published something. On average I publish something every { averageDaysBetweenPosts } days ({ numberOfPosts } posts in { daysSinceFirstPost } days).
2022-04-16 10:43:45 +00:00
< / p >
< / section >
< section class = "section" >
< h2 > All Writing< / h2 >
< ul class = "posts" >
{ #each posts as post }
< li class = "post" >
< a href = { `/blog/ ${ post . slug } ` } >
{ #if post . book_review } 📚 { /if }
< div class = "post-title" > { post . title } </ div >
2022-04-26 06:23:15 +00:00
< div class = "post-preview" > { post . preview } ...</ div >
2022-04-16 10:43:45 +00:00
< div class = "post-date" > { intlFormat ( new Date ( post . date ))} </ div >
< / a >
</ li > { /each }
< / ul >
< / section >
< / main >
< style >
.posts {
list-style: none;
margin: 0;
padding: 0;
display: grid;
grid-template-columns: 1fr;
gap: var(--spacing-base);
2022-05-06 21:21:44 +00:00
max-width: 100%;
2022-04-16 10:43:45 +00:00
}
.post {
border: 1px solid var(--gray-200);
padding: var(--spacing-md);
transition: 0.2s;
border-radius: 8px;
2022-05-06 21:21:44 +00:00
max-width: 100%;
2022-04-16 10:43:45 +00:00
}
.post:hover {
color: var(--brand-orange);
}
.post a {
color: inherit;
text-decoration: none;
}
.post-title {
text-decoration: underline;
font-family: var(--font-family-title);
font-weight: 600;
padding-bottom: 8px;
}
.post-date {
font-size: 0.9rem;
}
.post-preview {
font-size: 0.9rem;
line-height: 120%;
color: var(--gray-600);
}
.days-since {
color: var(--brand-orange);
font-weight: 300;
border: 1px solid var(--brand-orange);
border-radius: 4px;
padding: 8px;
font-family: monospace;
}
2022-04-17 10:07:40 +00:00
.days-since-success {
color: var(--brand-green);
border: 1px solid var(--brand-green);
animation-name: pulse_green;
animation-duration: 5.2s;
animation-iteration-count: infinite;
background: rgba(54, 130, 127, 0.05);
}
@keyframes pulse_green {
0% {
box-shadow: 0 0 0 0px rgba(54, 130, 127, 1);
}
2022-04-26 06:23:15 +00:00
20%,
100% {
2022-04-17 10:07:40 +00:00
box-shadow: 0 0 0 5px rgba(54, 130, 127, 0);
}
}
2022-04-16 10:43:45 +00:00
< / style >