feat: move all functionality for blog pages to the server
This commit is contained in:
parent
5ca7fc1ced
commit
1fd055c38f
6 changed files with 99 additions and 72 deletions
|
|
@ -1 +1,42 @@
|
||||||
|
import { BlogController } from '$lib/blog/BlogController.js';
|
||||||
|
import type { Load } from '@sveltejs/kit';
|
||||||
|
import { differenceInCalendarDays, getYear } from 'date-fns';
|
||||||
|
|
||||||
export const prerender = true;
|
export const prerender = true;
|
||||||
|
|
||||||
|
export const load: Load = async ({ params, url }) => {
|
||||||
|
const controller = await BlogController.singleton();
|
||||||
|
const tags = url.searchParams.getAll('tag');
|
||||||
|
let posts = [];
|
||||||
|
|
||||||
|
if (tags.length > 0) {
|
||||||
|
posts = await controller.getBlogPostsByTags(tags);
|
||||||
|
} else {
|
||||||
|
posts = await controller.getAllBlogPosts();
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentYear = getYear(new Date());
|
||||||
|
console.log({ posts });
|
||||||
|
const mostRecentPost = posts[0];
|
||||||
|
|
||||||
|
const daysSinceLastPublish = differenceInCalendarDays(new Date(), new Date(mostRecentPost.date));
|
||||||
|
|
||||||
|
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);
|
||||||
|
const numberOfBlogPostsThisYear: number = posts.filter(
|
||||||
|
(post) => getYear(new Date(post.date)) === currentYear
|
||||||
|
).length;
|
||||||
|
|
||||||
|
return {
|
||||||
|
tags,
|
||||||
|
posts,
|
||||||
|
firstPost,
|
||||||
|
averageDaysBetweenPosts,
|
||||||
|
daysSinceFirstPost,
|
||||||
|
daysSinceLastPublish,
|
||||||
|
numberOfPosts,
|
||||||
|
numberOfBlogPostsThisYear,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
|
||||||
|
|
@ -71,7 +71,11 @@
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section class="section">
|
<section class="section">
|
||||||
|
{#if data.tags.length > 0}
|
||||||
|
<h2>Tags: {data.tags.join(", ")}</h2>
|
||||||
|
{:else}
|
||||||
<h2>All Writing</h2>
|
<h2>All Writing</h2>
|
||||||
|
{/if}
|
||||||
<ul class="posts">
|
<ul class="posts">
|
||||||
{#each posts as post, index}
|
{#each posts as post, index}
|
||||||
<BlogPostListItem
|
<BlogPostListItem
|
||||||
|
|
|
||||||
|
|
@ -1,45 +0,0 @@
|
||||||
import type { LoadEvent } from '@sveltejs/kit';
|
|
||||||
import { differenceInCalendarDays, getYear } from 'date-fns';
|
|
||||||
export const prerender = false;
|
|
||||||
|
|
||||||
interface BlogPostListItem {
|
|
||||||
title: string;
|
|
||||||
author: string;
|
|
||||||
book_review: boolean;
|
|
||||||
content: string;
|
|
||||||
date: string;
|
|
||||||
preview: string;
|
|
||||||
slug: string;
|
|
||||||
content_type: 'blog' | 'book_review' | 'snout_street_studios';
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function load({ fetch }: LoadEvent) {
|
|
||||||
const posts: BlogPostListItem[] = await fetch('/api/blog.json')
|
|
||||||
.then((res) => res.json())
|
|
||||||
.then((res) => res.posts);
|
|
||||||
|
|
||||||
const currentYear = getYear(new Date());
|
|
||||||
console.log({ posts });
|
|
||||||
const mostRecentPost = posts[0];
|
|
||||||
console.log({ ...mostRecentPost });
|
|
||||||
|
|
||||||
const daysSinceLastPublish = differenceInCalendarDays(new Date(), new Date(mostRecentPost.date));
|
|
||||||
|
|
||||||
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);
|
|
||||||
const numberOfBlogPostsThisYear: number = posts.filter(
|
|
||||||
(post) => getYear(new Date(post.date)) === currentYear
|
|
||||||
).length;
|
|
||||||
|
|
||||||
return {
|
|
||||||
posts,
|
|
||||||
firstPost,
|
|
||||||
averageDaysBetweenPosts,
|
|
||||||
daysSinceFirstPost,
|
|
||||||
daysSinceLastPublish,
|
|
||||||
numberOfPosts,
|
|
||||||
numberOfBlogPostsThisYear,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
14
src/routes/blog/[slug]/+page.server.ts
Normal file
14
src/routes/blog/[slug]/+page.server.ts
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { error, type Load, type LoadEvent } from '@sveltejs/kit';
|
||||||
|
import { BlogController } from '../../../lib/blog/BlogController.js';
|
||||||
|
|
||||||
|
export const load: Load = async ({ params, fetch }) => {
|
||||||
|
const controller = await BlogController.singleton();
|
||||||
|
const slug = params['slug'] as string;
|
||||||
|
const post = await controller.getBlogPostBySlug(slug);
|
||||||
|
|
||||||
|
if (!post) {
|
||||||
|
return error(404, 'Post not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
return { post, date: new Date(post.date) };
|
||||||
|
};
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PageData } from "./$types.js";
|
import type { PageData, PageServerData } from "./$types.js";
|
||||||
import { intlFormat } from "date-fns";
|
import { intlFormat } from "date-fns";
|
||||||
import Navbar from "$lib/components/Navbar.svelte";
|
import Navbar from "$lib/components/Navbar.svelte";
|
||||||
import { onMount } from "svelte";
|
import { onMount } from "svelte";
|
||||||
|
|
@ -9,11 +9,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
let { data }: Props = $props();
|
let { data }: Props = $props();
|
||||||
let { date, post } = $derived(data);
|
const post = data.post;
|
||||||
|
|
||||||
onMount(() => {
|
|
||||||
console.log({ date, post });
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<svelte:head>
|
<svelte:head>
|
||||||
|
|
@ -41,14 +37,14 @@
|
||||||
<header class="blog__header">
|
<header class="blog__header">
|
||||||
<h1 class="title post-title">{post.title}</h1>
|
<h1 class="title post-title">{post.title}</h1>
|
||||||
<p class="post-author">
|
<p class="post-author">
|
||||||
{#if post.autor}
|
{#if post.author}
|
||||||
{post.author}
|
{post.author}
|
||||||
{:else}
|
{:else}
|
||||||
Thomas Wilson
|
Thomas Wilson
|
||||||
{/if}
|
{/if}
|
||||||
</p>
|
</p>
|
||||||
<p class="post-date">
|
<p class="post-date">
|
||||||
{intlFormat(date, {
|
{intlFormat(post.date, {
|
||||||
weekday: "long",
|
weekday: "long",
|
||||||
day: "2-digit",
|
day: "2-digit",
|
||||||
month: "long",
|
month: "long",
|
||||||
|
|
@ -56,6 +52,16 @@
|
||||||
localeMatcher: "best fit",
|
localeMatcher: "best fit",
|
||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
|
{#if post}
|
||||||
|
<div class="post-tags">
|
||||||
|
{#each post.tags as tag}
|
||||||
|
<a
|
||||||
|
href={`/blog?tag=${encodeURIComponent(tag)}`}
|
||||||
|
class="post-tags__tag">#{tag}</a
|
||||||
|
>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<article id="article">
|
<article id="article">
|
||||||
|
|
@ -64,7 +70,7 @@
|
||||||
</article>
|
</article>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
<style lang="scss">
|
<style>
|
||||||
.blog {
|
.blog {
|
||||||
background-color: var(--colour-scheme-background);
|
background-color: var(--colour-scheme-background);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -80,6 +86,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
container-type: inline-size;
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-title {
|
.post-title {
|
||||||
|
|
@ -87,6 +94,14 @@
|
||||||
line-height: 125%;
|
line-height: 125%;
|
||||||
max-width: 30ch;
|
max-width: 30ch;
|
||||||
font-family: var(--font-family-serif);
|
font-family: var(--font-family-serif);
|
||||||
|
font-size: clamp(2rem, 10vw, 4rem);
|
||||||
|
max-width: 95%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@container (min-width: 550px) {
|
||||||
|
.post-title {
|
||||||
|
font-size: 4rem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.post-author {
|
.post-author {
|
||||||
|
|
@ -104,6 +119,21 @@
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.post-tags {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
margin-top: 8px;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.post-tags__tag {
|
||||||
|
border: 2px solid var(--brand-orange);
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 4px 8px;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
:global(#article p) {
|
:global(#article p) {
|
||||||
padding-bottom: 12px;
|
padding-bottom: 12px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,17 +0,0 @@
|
||||||
import type { LoadEvent } from '@sveltejs/kit';
|
|
||||||
import type { Post } from '$lib/Post.js';
|
|
||||||
|
|
||||||
export async function load({ params, fetch }: LoadEvent): Promise<{ post: Post; date: Date }> {
|
|
||||||
const { slug } = params;
|
|
||||||
const { post } = await fetch(`/api/blog/${slug}.json`)
|
|
||||||
.then((res) => res.json())
|
|
||||||
.catch((error) => {
|
|
||||||
console.error(error);
|
|
||||||
return { post: null };
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
post,
|
|
||||||
date: new Date(post.date),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue