chore: myriad fixes + book year pages

This commit is contained in:
Cory Dransfeldt 2024-11-17 11:55:53 -08:00
parent 3ab6f77a69
commit aec8471b06
No known key found for this signature in database
45 changed files with 508 additions and 293 deletions

View file

@ -2,6 +2,7 @@
import Layout from '@layouts/Layout.astro';
import BlockRenderer from '@components/blocks/BlockRenderer.astro';
import { fetchPages } from '@utils/data/pages';
import { fetchGlobalData } from '@utils/data/global/index.js';
export const prerender = true;
@ -14,12 +15,11 @@ export async function getStaticPaths() {
}
const { page } = Astro.props;
const { globals } = Astro.locals;
const { globals } = await fetchGlobalData(Astro);
const currentUrl = Astro.url.pathname;
---
<Layout
globals={globals}
pageTitle={page.title}
description={page.description}
ogImage={page.open_graph_image}

View file

@ -4,7 +4,8 @@ import Warning from "@components/blocks/banners/Warning.astro";
import AssociatedMedia from "@components/blocks/AssociatedMedia.astro";
import ProgressBar from "@components/media/ProgressBar.astro";
import { IconArrowLeft, IconHeart, IconNeedle } from "@tabler/icons-react";
import { fetchBookByUrl } from "@utils/data/bookByUrl.js";
import { fetchBookByUrl } from "@utils/data/dynamic/bookByUrl.js";
import { fetchGlobalData } from '@utils/data/global/index.js';
const { isbn } = Astro.params;
@ -14,7 +15,7 @@ if (!book) return Astro.redirect("/404", 404);
const alt = `${book.title}${book.author ? ` by ${book.author}` : ""}`;
const pageTitle = `Books / ${book.title}`;
const description = book.description || `Details about the book ${book.title}`;
const { globals } = Astro.locals;
const { globals } = await fetchGlobalData(Astro);
---
<Layout pageTitle={pageTitle} description={description} schema="book">

View file

@ -3,10 +3,11 @@ import Layout from "@layouts/Layout.astro";
import Rss from "@components/blocks/banners/Rss.astro";
import ProgressBar from "@components/media/ProgressBar.astro";
import { fetchBooks } from "@utils/data/books.js";
import { md, htmlTruncate } from "@utils/helpers.js";
import { fetchGlobalData } from '@utils/data/global/index.js';
import { md, htmlTruncate } from "@utils/helpers/general.js";
const books = await fetchBooks();
const { globals } = Astro.locals;
const { globals } = await fetchGlobalData(Astro);
const title = "Currently reading";
const description = "Here's what I'm reading at the moment.";
const updated = new Date().toISOString();

View file

@ -0,0 +1,46 @@
---
import Layout from "@layouts/Layout.astro";
import Grid from "@components/media/Grid.astro";
import { IconArrowLeft } from "@tabler/icons-react";
import { filterBooksByStatus, findFavoriteBooks, mediaLinks } from "@utils/helpers/media.js";
import { fetchGlobalData } from '@utils/data/global/index.js';
import { fetchBooks } from "@utils/data/books.js";
import { DateTime } from "luxon";
const { globals } = await fetchGlobalData(Astro);
const books = await fetchBooks();
const { year } = Astro.params;
const yearData = books.years.find((y) => y.value === parseInt(year, 10));
if (!yearData) return Astro.redirect("/404", 404);
const bookData = filterBooksByStatus(yearData.data, "finished");
const bookDataFavorites = findFavoriteBooks(bookData);
const favoriteBooks = mediaLinks(bookDataFavorites, "book", 5);
const currentYear = DateTime.now().year;
const isCurrentYear = parseInt(year, 10) === currentYear;
const pageTitle = `${year} / Books`;
const description = isCurrentYear
? `I've finished ${bookData.length} books this year.`
: `I finished ${bookData.length} books in ${year}.`;
const intro = isCurrentYear
? `
I've finished <strong class="highlight-text">${bookData.length} books</strong> this year.
${favoriteBooks ? ` Among my favorites are ${favoriteBooks}.` : ''}
`
: `
I finished <strong class="highlight-text">${bookData.length} books</strong> in
<strong class="highlight-text">${year}</strong>.
${favoriteBooks ? ` Among my favorites were ${favoriteBooks}.` : ''}
`;
---
<Layout globals={globals} pageTitle={pageTitle} description={description} schema="books-year">
<a href="/books" class="back-link">
<IconArrowLeft size={18} /> Back to books
</a>
<h2 class="page-title">{year} / Books</h2>
<div set:html={intro}></div>
<hr />
<Grid globals={globals} data={bookData} shape="vertical" count={200} loading="eager" />
</Layout>

View file

@ -1,8 +1,10 @@
import { generateJsonFeed } from '@utils/generateJsonFeed';
import { fetchGlobals } from '@utils/data/globals';
import { fetchActivity } from '@utils/data/activity';
import fs from 'fs/promises';
import path from 'path';
export async function GET() {
export async function getStaticPaths() {
const globals = await fetchGlobals();
const activity = await fetchActivity();
@ -13,10 +15,9 @@ export async function GET() {
data: activity,
});
return new Response(feed, {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
const filePath = path.resolve('public/feeds/all.json');
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, feed);
return [];
}

View file

@ -1,22 +1,23 @@
import { generateRssFeed } from "@utils/generateRssFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchActivity } from "@utils/data/activity";
import fs from "fs/promises";
import path from "path";
export async function GET() {
export async function getStaticPaths() {
const globals = await fetchGlobals();
const activity = await fetchActivity();
const rss = generateRssFeed({
permalink: "/feeds/all.xml",
title: "All activity / Cory Dransfeldt",
title: "All activity feed",
globals,
data: activity,
});
return new Response(rss, {
status: 200,
headers: {
"Content-Type": "application/rss+xml",
},
});
const filePath = path.resolve("public/feeds/all.xml");
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, rss);
return [];
}

View file

@ -0,0 +1,23 @@
import { generateJsonFeed } from "@utils/generateJsonFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchBooks } from "@utils/data/books";
import fs from "fs/promises";
import path from "path";
export async function getStaticPaths() {
const globals = await fetchGlobals();
const books = await fetchBooks();
const feed = generateJsonFeed({
permalink: "/feeds/books.json",
title: "Books / Cory Dransfeldt",
globals,
data: books.feed,
});
const filePath = path.resolve("public/feeds/books.json");
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, feed);
return [];
}

View file

@ -0,0 +1,23 @@
import { generateRssFeed } from "@utils/generateRssFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchBooks } from "@utils/data/books";
import fs from "fs/promises";
import path from "path";
export async function getStaticPaths() {
const globals = await fetchGlobals();
const books = await fetchBooks();
const rss = generateRssFeed({
permalink: "/feeds/books.xml",
title: "Books feed",
globals,
data: books.feed,
});
const filePath = path.resolve("public/feeds/books.xml");
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, rss);
return [];
}

View file

@ -1,22 +0,0 @@
import { generateJsonFeed } from '@utils/generateJsonFeed';
import { fetchGlobals } from '@utils/data/globals';
import { fetchBooks } from '@utils/data/books';
export async function GET() {
const globals = await fetchGlobals();
const books = await fetchBooks();
const feed = generateJsonFeed({
permalink: "/feeds/books.json",
title: "Books / Cory Dransfeldt",
globals,
data: books.feed,
});
return new Response(feed, {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
}

View file

@ -1,22 +0,0 @@
import { generateJsonFeed } from '@utils/generateJsonFeed';
import { fetchGlobals } from '@utils/data/globals';
import { fetchLinks } from '@utils/data/links';
export async function GET() {
const globals = await fetchGlobals();
const links = await fetchLinks();
const feed = generateJsonFeed({
permalink: "/feeds/links.json",
title: "Links / Cory Dransfeldt",
globals,
data: links,
});
return new Response(feed, {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
}

View file

@ -1,22 +0,0 @@
import { generateJsonFeed } from '@utils/generateJsonFeed';
import { fetchGlobals } from '@utils/data/globals';
import { fetchAllPosts } from '@utils/data/posts';
export async function GET() {
const globals = await fetchGlobals();
const posts = await fetchAllPosts();
const feed = generateJsonFeed({
permalink: "/feeds/posts.json",
title: "Posts / Cory Dransfeldt",
globals,
data: posts,
});
return new Response(feed, {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
}

View file

@ -0,0 +1,23 @@
import { generateJsonFeed } from "@utils/generateJsonFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchLinks } from "@utils/data/links";
import fs from "fs/promises";
import path from "path";
export async function getStaticPaths() {
const globals = await fetchGlobals();
const links = await fetchLinks();
const feed = generateJsonFeed({
permalink: "/feeds/links.json",
title: "Links / Cory Dransfeldt",
globals,
data: links,
});
const filePath = path.resolve("public/feeds/links.json");
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, feed);
return [];
}

View file

@ -0,0 +1,23 @@
import { generateRssFeed } from "@utils/generateRssFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchLinks } from "@utils/data/links";
import fs from "fs/promises";
import path from "path";
export async function getStaticPaths() {
const globals = await fetchGlobals();
const links = await fetchLinks();
const rss = generateRssFeed({
permalink: "/feeds/links.xml",
title: "Links feed",
globals,
data: links,
});
const filePath = path.resolve("public/feeds/links.xml");
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, rss);
return [];
}

View file

@ -1,8 +1,10 @@
import { generateJsonFeed } from '@utils/generateJsonFeed';
import { fetchGlobals } from '@utils/data/globals';
import { fetchMovies } from '@utils/data/movies';
import fs from 'fs/promises';
import path from 'path';
export async function GET() {
export async function getStaticPaths() {
const globals = await fetchGlobals();
const movies = await fetchMovies();
@ -13,10 +15,9 @@ export async function GET() {
data: movies.feed,
});
return new Response(feed, {
status: 200,
headers: {
"Content-Type": "application/json",
},
});
const filePath = path.resolve("public/feeds/movies.json");
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, feed);
return [];
}

View file

@ -0,0 +1,23 @@
import { generateRssFeed } from "@utils/generateRssFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchMovies } from "@utils/data/movies";
import fs from "fs/promises";
import path from "path";
export async function getStaticPaths() {
const globals = await fetchGlobals();
const movies = await fetchMovies();
const rss = generateRssFeed({
permalink: "/feeds/movies.xml",
title: "Movies feed",
globals,
data: movies.feed,
});
const filePath = path.resolve("public/feeds/movies.xml");
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, rss);
return [];
}

View file

@ -0,0 +1,23 @@
import { generateJsonFeed } from "@utils/generateJsonFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchAllPosts } from "@utils/data/posts";
import fs from "fs/promises";
import path from "path";
export async function getStaticPaths() {
const globals = await fetchGlobals();
const posts = await fetchAllPosts();
const feed = generateJsonFeed({
permalink: "/feeds/posts.json",
title: "Posts / Cory Dransfeldt",
globals,
data: posts,
});
const filePath = path.resolve("public/feeds/posts.json");
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, feed);
return [];
}

View file

@ -0,0 +1,23 @@
import { generateRssFeed } from "@utils/generateRssFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchAllPosts } from "@utils/data/posts";
import fs from "fs/promises";
import path from "path";
export async function getStaticPaths() {
const globals = await fetchGlobals();
const posts = await fetchAllPosts();
const rss = generateRssFeed({
permalink: "/feeds/posts.xml",
title: "Posts feed",
globals,
data: posts,
});
const filePath = path.resolve("public/feeds/posts.xml");
await fs.mkdir(path.dirname(filePath), { recursive: true });
await fs.writeFile(filePath, rss);
return [];
}

View file

@ -1,22 +0,0 @@
import { generateRssFeed } from "@utils/generateRssFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchBooks } from '@utils/data/books';
export async function GET() {
const globals = await fetchGlobals();
const books = await fetchBooks();
const rss = generateRssFeed({
permalink: "/feeds/books.xml",
title: "Books / Cory Dransfeldt",
globals,
data: books.feed,
});
return new Response(rss, {
status: 200,
headers: {
"Content-Type": "application/rss+xml",
},
});
}

View file

@ -1,22 +0,0 @@
import { generateRssFeed } from "@utils/generateRssFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchLinks } from '@utils/data/links';
export async function GET() {
const globals = await fetchGlobals();
const links = await fetchLinks();
const rss = generateRssFeed({
permalink: "/feeds/links.xml",
title: "Links / Cory Dransfeldt",
globals,
data: links,
});
return new Response(rss, {
status: 200,
headers: {
"Content-Type": "application/rss+xml",
},
});
}

View file

@ -1,22 +0,0 @@
import { generateRssFeed } from "@utils/generateRssFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchMovies } from '@utils/data/movies';
export async function GET() {
const globals = await fetchGlobals();
const movies = await fetchMovies();
const rss = generateRssFeed({
permalink: "/feeds/movies.xml",
title: "Movies / Cory Dransfeldt",
globals,
data: movies.feed,
});
return new Response(rss, {
status: 200,
headers: {
"Content-Type": "application/rss+xml",
},
});
}

View file

@ -1,22 +0,0 @@
import { generateRssFeed } from "@utils/generateRssFeed";
import { fetchGlobals } from "@utils/data/globals";
import { fetchAllPosts } from '@utils/data/posts';
export async function GET() {
const globals = await fetchGlobals();
const posts = await fetchAllPosts();
const rss = generateRssFeed({
permalink: "/feeds/posts.xml",
title: "Posts / Cory Dransfeldt",
globals,
data: posts,
});
return new Response(rss, {
status: 200,
headers: {
"Content-Type": "application/rss+xml",
},
});
}

View file

@ -1,64 +0,0 @@
import fetchSyndication from '@utils/data/syndication.js';
import { fetchGlobals } from '@utils/data/globals.js';
export async function GET() {
const globals = await fetchGlobals();
const entries = await fetchSyndication();
if (!entries.length) return new Response('No feed entries found.', { status: 404 });
const title = globals.site_name || 'Syndicated content / Cory Dransfeldt';
const permalink = '/feeds/syndication.xml';
const xml = `<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<atom:link href="${globals.url}${permalink}" rel="self" type="application/rss+xml" />
<title><![CDATA[${title}]]></title>
<description><![CDATA[${globals.site_description || ''}]]></description>
<link>${globals.url}${permalink}</link>
<lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
<image>
<title><![CDATA[${title}]]></title>
<link>${globals.url}${permalink}</link>
<url>${globals.cdn_url}${globals.avatar}?class=w200</url>
<width>144</width>
<height>144</height>
</image>
${entries
.slice(0, 20)
.map(
(entry) => `
<item>
<title><![CDATA[${entry.syndication.title}]]></title>
<link>${encodeAmp(entry.syndication.url)}</link>
<pubDate>${new Date(entry.syndication.date).toUTCString()}</pubDate>
<guid isPermaLink="false">${encodeAmp(entry.syndication.url)}</guid>
<description><![CDATA[${escapeHTML(entry.syndication.description)}]]></description>
</item>`
)
.join('')}
</channel>
</rss>`;
return new Response(xml, {
status: 200,
headers: {
'Content-Type': 'application/rss+xml',
},
});
}
function encodeAmp(url) {
return url.replace(/&/g, '&amp;');
}
function escapeHTML(str) {
if (!str) return '';
return str
.replace(/&/g, '&amp;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#039;');
}

View file

@ -0,0 +1,62 @@
import { DateTime } from "luxon";
import fetchSyndication from '@utils/data/syndication.js';
import { fetchGlobals } from '@utils/data/globals.js';
import { dateToRFC822, encodeAmp, md } from '@utils/helpers/general.js';
const generateSyndicationRSS = async () => {
const globals = await fetchGlobals();
const entries = await fetchSyndication();
if (!entries.length) throw new Error('No feed entries found.');
const title = globals.site_name || 'Syndicated Content Feed';
const permalink = '/feeds/syndication.xml';
const xml = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<atom:link href="${globals.url}${permalink}" rel="self" type="application/rss+xml" />
<title><![CDATA[${title}]]></title>
<description><![CDATA[${globals.site_description || ''}]]></description>
<link>${globals.url}</link>
<lastBuildDate>${dateToRFC822(DateTime.now())}</lastBuildDate>
<image>
<title><![CDATA[${title}]]></title>
<link>${globals.url}</link>
<url>${globals.cdn_url}${globals.avatar}?class=w200</url>
<width>144</width>
<height>144</height>
</image>
${entries
.slice(0, 20)
.map(
(entry) => `
<item>
<title><![CDATA[${entry.syndication.title || 'Untitled'}]]></title>
<link>${encodeAmp(entry.syndication.url)}</link>
<pubDate>${dateToRFC822(entry.syndication.date)}</pubDate>
<guid isPermaLink="false">${encodeAmp(entry.syndication.url)}</guid>
<description><![CDATA[${md(entry.syndication.description || '')}]]></description>
</item>`
)
.join('')}
</channel>
</rss>`;
return xml;
};
export async function GET() {
try {
const rss = await generateSyndicationRSS();
return new Response(rss, {
status: 200,
headers: { 'Content-Type': 'application/rss+xml' },
});
} catch (error) {
console.error(error.message);
return new Response('Error generating syndication feed.', { status: 500 });
}
}
export const prerender = true;

View file

@ -3,8 +3,9 @@ import Layout from '@layouts/Layout.astro';
import Intro from '@components/home/Intro.astro';
import RecentActivity from '@components/home/RecentActivity.astro';
import RecentPosts from '@components/home/RecentPosts.astro';
import { fetchGlobalData } from '@utils/data/global/index.js';
const { globals } = Astro.locals;
const { globals } = await fetchGlobalData(Astro);
const schema = 'blog';
const pageTitle = globals.site_name;
const description = 'This is a blog post description';
@ -13,14 +14,12 @@ const fullUrl = globals.url + '/blog/my-post';
const themeColor = globals.theme_color;
---
<Layout
globals={globals}
pageTitle={pageTitle}
description={description}
ogImage={ogImage}
fullUrl={fullUrl}
themeColor={themeColor}
schema={schema}
globals={globals}
>
<Intro intro={globals.intro} />
<RecentActivity />

View file

@ -3,14 +3,12 @@ import Layout from "@layouts/Layout.astro";
import Paginator from "@components/nav/Paginator.astro";
import RssBanner from "@components/blocks/banners/Rss.astro";
import { fetchLinks } from "@utils/data/links.js";
import { fetchGlobalData } from '@utils/data/global/index.js';
const { globals } = Astro.locals;
const { globals } = await fetchGlobalData(Astro);
const links = await fetchLinks();
const title = "Links";
const description = "These are links I've liked or otherwise found interesting. They're all added manually, after having been read and, I suppose, properly considered.";
// Pagination Settings
const pageSize = 30;
const currentPage = parseInt(Astro.url.searchParams.get("page") || "1", 10);
const totalPages = Math.ceil(links.length / pageSize);

View file

@ -2,14 +2,15 @@
import { getCollection } from 'astro:content';
import { IconStar } from '@tabler/icons-react';
import { fetchAllPosts } from "@data/posts.js";
import { fetchGlobalData } from '@utils/data/global/index.js';
import Layout from "@layouts/Layout.astro";
import Paginator from '@components/nav/Paginator.astro';
import { md } from '@utils/helpers.js';
import { md } from '@utils/helpers/general.js';
import { DateTime } from 'luxon';
const posts = await fetchAllPosts();
const { page } = Astro.props;
const { globals } = Astro.locals;
const { globals } = await fetchGlobalData(Astro);
const currentUrl = Astro.url.pathname;
const currentPage = Astro.params.page ? parseInt(Astro.params.page, 10) : 1;

View file

@ -3,7 +3,8 @@ import { IconStar } from "@tabler/icons-react";
import { fetchAllPosts } from "@data/posts.js";
import { fetchAnalyticsData } from "@data/analytics.js";
import { fetchLinks } from "@data/links.js";
import { md } from '@utils/helpers.js';
import { fetchGlobalData } from '@utils/data/global/index.js';
import { md } from '@utils/helpers/general.js';
import { getPopularPosts } from '@utils/getPopularPosts.js';
const analytics = await fetchAnalyticsData();
@ -38,7 +39,7 @@ export async function getStaticPaths() {
}
const { post } = Astro.props;
const { globals } = Astro.locals;
const { globals } = await fetchGlobalData(Astro);
const { year, title } = Astro.params;
const currentUrl = Astro.url.pathname;
const htmlContent = md(post.content);