diff options
| author | Joe Carstairs <me@joeac.net> | 2026-06-18 19:21:59 +0100 |
|---|---|---|
| committer | Joe Carstairs <me@joeac.net> | 2026-06-18 19:21:59 +0100 |
| commit | ca8e6824eaa711105f4092365792720c9dde026b (patch) | |
| tree | 2b6493941352d11b799ee63d3f1311c13de649b8 /website/src/pages | |
| parent | a0f25057283a397f006127b6f582d190d2c4294e (diff) | |
remove Astro website
Diffstat (limited to 'website/src/pages')
| -rw-r--r-- | website/src/pages/blog/[...slug].astro | 28 | ||||
| -rw-r--r-- | website/src/pages/blog/index.astro | 23 | ||||
| -rw-r--r-- | website/src/pages/blog/rss.xml.ts | 37 | ||||
| -rw-r--r-- | website/src/pages/blog/subscribe.astro | 90 | ||||
| -rw-r--r-- | website/src/pages/contact.astro | 97 | ||||
| -rw-r--r-- | website/src/pages/error.astro | 14 | ||||
| -rw-r--r-- | website/src/pages/index.astro | 11 | ||||
| -rw-r--r-- | website/src/pages/links/rss.xml.ts | 33 | ||||
| -rw-r--r-- | website/src/pages/microlog/[...slug].astro | 26 | ||||
| -rw-r--r-- | website/src/pages/microlog/index.astro | 13 | ||||
| -rw-r--r-- | website/src/pages/microlog/rss.xml.ts | 29 |
11 files changed, 0 insertions, 401 deletions
diff --git a/website/src/pages/blog/[...slug].astro b/website/src/pages/blog/[...slug].astro deleted file mode 100644 index 54cf9ac..0000000 --- a/website/src/pages/blog/[...slug].astro +++ /dev/null @@ -1,28 +0,0 @@ ---- -import { type CollectionEntry, getCollection, render } from 'astro:content'; -import BlogPost from '../../layouts/BlogPost.astro'; -import { renderGemtextToHtml } from '../../renderGemtextToHtml'; - -export async function getStaticPaths() { - const posts = await getCollection('blog'); - return posts.map((post) => ({ - params: { slug: post.id }, - props: post, - })); -} -type Props = CollectionEntry<'blog'>; - -const post = Astro.props; -const Content = post.filePath?.endsWith('.gmi') - ? renderGemtextToHtml(post.body ?? '', post.data.title) - : (await render(post)).Content; ---- - -<BlogPost - title={post.data.title} - description={post.data.description} - pubDate={post.data.pubDate ?? new Date(post.id)} - updatedDate={post.data.updatedDate} -> - { post.filePath?.endsWith('.gmi') ? <Fragment set:html={Content}></Fragment> : <Content />} -</BlogPost> diff --git a/website/src/pages/blog/index.astro b/website/src/pages/blog/index.astro deleted file mode 100644 index df758ed..0000000 --- a/website/src/pages/blog/index.astro +++ /dev/null @@ -1,23 +0,0 @@ ---- -import BaseHead from '../../components/BaseHead.astro'; -import { SITE_TITLE, SITE_DESCRIPTION } from '../../consts'; -import BlogFeed from '../../components/BlogFeed.astro'; -import Navbar from '../../components/Navbar.astro'; ---- - -<!doctype html> -<html lang="en"> - <head> - <BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} /> - </head> - <body> - <Navbar /> - <main> - <BlogFeed headingLevel={1}> - <section> - <p><a href="/blog/subscribe">How to subscribe to this blog</a></p> - </section> - </BlogFeed> - </main> - </body> -</html> diff --git a/website/src/pages/blog/rss.xml.ts b/website/src/pages/blog/rss.xml.ts deleted file mode 100644 index 5b90fd0..0000000 --- a/website/src/pages/blog/rss.xml.ts +++ /dev/null @@ -1,37 +0,0 @@ -import path from 'node:path'; -import rss from '@astrojs/rss'; -import type { APIContext } from 'astro'; -import { getCollection } from 'astro:content'; -import MarkdownIt from 'markdown-it'; - -const mdParser = new MarkdownIt({ - html: true -}); - -export async function GET(context: APIContext) { - // `site` is guaranteed to exist because we define it in our Astro config - const site = context.site!; - const posts = await getCollection('blog'); - - return rss({ - title: 'Joe Carstairs’ blog', - description: 'Short posts on random topics I find interesting', - customData: ` - <image>/images/headshot.webp</image> - <language>en-GB</language> - `, - site: path.join(site.toString(), 'blog'), - trailingSlash: false, - items: posts.map((post) => ({ - link: `/blog/${post.id}`, - title: post.data.title, - content: mdParser.render(post.body ?? ''), - pubDate: post.data.pubDate, - description: post.data.description, - author: 'Joe Carstairs', - - // A page for displaying comments related to the item - /* commentsUrl: `${post.slug}/comments`, */ - })), - }) -} diff --git a/website/src/pages/blog/subscribe.astro b/website/src/pages/blog/subscribe.astro deleted file mode 100644 index cbb6237..0000000 --- a/website/src/pages/blog/subscribe.astro +++ /dev/null @@ -1,90 +0,0 @@ ---- -import Page from "../../layouts/Page.astro"; - ---- - -<Page - title="How to subscribe to joeac's blog" - description="How to subscribe to joeac's blog" -> - <section> - <h1>How to subscribe to my blog</h1> - - <p> - The short version: use my <a href="/blog/rss.xml">RSS file</a> or my - <a href="gemini://joeac.net/logs/longlog.gmi">gemlog</a>. - </p> - - <p> - If neither of those things means anything to you, no worries. You could - just look at my website every once in a while, but that gets old. A better - way is to use my RSS file. Here's how. - </p> - - <p> - An RSS file, if you don't know, is a file containing a list of posts in a - format that's so stupid even computers can understand it. Mine is at - <a href="https://joeac.net/blog/rss.xml">https://joeac.net/blog/rss.xml</a>. - Since computers can understand it, you can get software to read it - automatically and tell you when I've made a new blog post. That's much less - hassle than having to check manually yourself! - </p> - - <p> - I'm not the only person serving RSS files, of course. You might not have - heard of them, but they're actually all over the Web. In the early days of - the Web, everyone was using them, so they've ended up built in to a whole - load of foundational Web technology, and hence ubiquitous, even if most - Web users have forgotten they exist. Once you've subscribed to my blog, - you can subscribe to basically any blog, podcast, or YouTube channel, and - a lot of other Websites for news, organisations, whatever. Point a - well-designed RSS aggregator or RSS reader at most Websites, and it'll - automatically find an associated RSS feed. - </p> - - <p> - If you're not persuaded, try reading - <a href="https://doctorow.medium.com/you-should-be-using-an-rss-reader-76aed31151f9"> - Cory Doctorow explaining why RSS is ridiculously good - </a>. He's terrifyingly persuasive. Also, read his novels! - </p> - - <p> - If you just want to give it a go quickly, probably the quickest way is to - use someone else's RSS aggregator that they'll let you use as a service. - <a href="https://feedly.com/news-reader">Feedly</a> and - <a href="https://www.inoreader.com">Inoreader</a> have free tiers. - </p> - - <p> - If you want to have a little more control, you can self-host an RSS - reader, like <a href="https://tt-rss.org">Tiny Tiny RSS</a>, - <a href="https://miniflux.app">Miniflux</a>, or - <a href="https://freshrss.org">FreshRSS</a>. But why would you do that? - Self-hosting is complicated! Why not just use a normal, local app? Here are - some options for that you might want to investigate. All these are active - free and open-source software projects at the time of writing. - </p> - - <ul> - <li><a href="https://hyliu.me/fluent-reader">Fluent Reader</a> (Linux, Windows, Mac, also mobile I think?)</li> - <li><a href="https://www.rssowl.org">RSSOwl</a> (Linux, Windows, Mac)</li> - <li><a href="https://capyreader.com">Capy Reader</a> (Android)</li> - <li><a href="https://apps.kde.org/en-gb/akregator">Akregator</a> (Linux, Windows (unstable))</li> - <li><a href="https://gfeeds.gabmus.org">GFeeds</a> (Linux)</li> - <li><a href="https://lzone.de/liferea">Liferea</a> (Linux)</li> - </ul> - - <p> - For the terminally geeky, there is also - <a href="https://newsboat.org">Newsboat</a>. I used it for ages, it works - fabulously, but it's all in the terminal, so you have to be OK with that. - </p> - - <p> - You can also just enter 'RSS feed reader' into your favourite search - engine, software distribution, or app store and see what comes up. Try - adding 'FOSS' into the query to prioritise free, open-source software. - </p> - </section> -</Page> diff --git a/website/src/pages/contact.astro b/website/src/pages/contact.astro deleted file mode 100644 index 85a5155..0000000 --- a/website/src/pages/contact.astro +++ /dev/null @@ -1,97 +0,0 @@ ---- -import OtpDialog from "../components/OtpDialog.astro"; -import Page from "../layouts/Page.astro"; -export const prerender = false; ---- - -<Page title="Contact" description="Contact Joe Carstairs"> - <OtpDialog /> - - <form class="contact-form"> - <h1>Contact me</h1> - <p hidden class="error"/> - <label for="name">Name</label> - <input id="name" name="name" type="text" required> - <label for="email">Email</label> - <input id="email" name="email" type="email" required> - <label for="message">Message</label> - <textarea id="message" name="message" required></textarea> - <input type="submit" value="Send"> - </form> - - <section class="success" hidden="true"> - <h1>You sent me a message!</h1> - <p>Thanks for that. I may be in touch.</p> - <p>In case you forgot, your message was this:</p> - <hr> - <dl> - <dt>Name</dt> <dd class="sentname">???</dd> - <dt>Email</dt> <dd class="sentemail">???</dd> - <dt>Message</dt> <dd class="sentmessage">???</dd> - </dl> - </section> - - <script> - import { resendOtp } from '../scripts/contact/resend-otp'; - import { submitContactForm } from '../scripts/contact/submit-contact-form'; - import { submitOtpForm } from '../scripts/contact/submit-otp-form'; - import type { Selectors } from '../scripts/contact/selectors'; - - function locateOrPanic<T extends Element>(selector: string, desc: string, root?: Element): T { - const elem = (root ?? document).querySelector<T>(selector); - if (!elem) { - alert(`Technical error: could not locate ${desc}. Please let Joe know if you have another means of contacting him.`); - throw new Error(`Could not locate ${desc}`); - } - return elem; - } - - const contactForm = locateOrPanic<HTMLFormElement>('form.contact-form', 'contact form'); - const otpDialog = locateOrPanic<HTMLDialogElement>('dialog.otp-dialog', 'OTP dialog'); - const otpForm = locateOrPanic<HTMLFormElement>('form.otp-form', 'OTP form'); - const successSection = document.querySelector('section.success'); - let resendButtonInterval: undefined | NodeJS.Timeout = undefined; - - const selectors: Selectors = { - contactForm: { - emailElem: () => locateOrPanic<HTMLInputElement>('input[name="email"]', 'email input', contactForm), - errorElem: () => contactForm.querySelector('.error'), - nameElem: () => locateOrPanic<HTMLInputElement>('input[name="name"]', 'name input', contactForm), - messageElem: () => locateOrPanic<HTMLTextAreaElement>('textarea[name="message"]', 'message textarea', contactForm), - self: () => contactForm, - submitButton: () => contactForm.querySelector('input[type="submit"]'), - }, - otpDialog: { - allOtpInputs: () => otpForm.querySelectorAll('input:not([type="submit"])'), - errorElem: () => otpDialog.querySelector('.error'), - firstOtpInput: () => otpForm.querySelector('input:not([type="submit"]):first-child'), - otpForm: () => otpForm, - otpRecipient: () => otpDialog.querySelector('.otp-recipient'), - otpValidUntil: () => otpDialog.querySelector('.otp-valid-until'), - resendButton: () => otpDialog.querySelector<HTMLButtonElement>('button.resend-button'), - self: () => otpDialog, - submitButton: () => otpForm.querySelector('input[type="submit"]'), - }, - successSection: { - email: () => successSection?.querySelector('.sentemail') ?? null, - name: () => successSection?.querySelector('.sentname') ?? null, - message: () => successSection?.querySelector('.sentmessage') ?? null, - self: () => successSection, - } - }; - - contactForm.addEventListener('submit', async (event) => { - event.preventDefault(); - ({ resendButtonInterval } = await submitContactForm(selectors, resendButtonInterval)); - }); - - selectors.otpDialog.resendButton()?.addEventListener('click', async () => { - ({ resendButtonInterval } = await resendOtp(selectors, resendButtonInterval)); - }); - - otpForm.addEventListener('submit', async (event) => { - event.preventDefault(); - await submitOtpForm(selectors); - }); - </script> -</Page> diff --git a/website/src/pages/error.astro b/website/src/pages/error.astro deleted file mode 100644 index dd7188a..0000000 --- a/website/src/pages/error.astro +++ /dev/null @@ -1,14 +0,0 @@ ---- -import Page from '../layouts/Page.astro'; ---- - -<Page title="Got lost?" description="Error page for Joe's personal website"> - <section> - <h1>Got lost?</h1> - - <p> - If you’re on this page, something’s probably gone wrong. Try going to - my <a href="/">homepage</a> instead. - </p> - </section> -</Page> diff --git a/website/src/pages/index.astro b/website/src/pages/index.astro deleted file mode 100644 index 8f26424..0000000 --- a/website/src/pages/index.astro +++ /dev/null @@ -1,11 +0,0 @@ ---- -import BlogFeed from '../components/BlogFeed.astro'; -import LinksFeed from '../components/LinksFeed.astro'; -import Me from '../components/Me.astro'; -import { SITE_TITLE, SITE_DESCRIPTION } from '../consts'; -import Page from '../layouts/Page.astro'; ---- - -<Page title={SITE_TITLE} description={SITE_DESCRIPTION}> - <Me /> -</Page> diff --git a/website/src/pages/links/rss.xml.ts b/website/src/pages/links/rss.xml.ts deleted file mode 100644 index 3f9e9a0..0000000 --- a/website/src/pages/links/rss.xml.ts +++ /dev/null @@ -1,33 +0,0 @@ -import path from 'node:path'; -import rss from '@astrojs/rss'; -import type { APIContext } from 'astro'; -import LINKS from '../../data/links.ts'; -import MarkdownIt from 'markdown-it'; - -const mdParser = new MarkdownIt({ - html: true -}); - -export async function GET(context: APIContext) { - // `site` is guaranteed to exist because we define it in our Astro config - const site = context.site!; - - return rss({ - title: 'Joe Carstairs’ links', - description: 'An assortment of links I’m accumulating.', - customData: ` - <image>/images/headshot.webp</image> - <language>en-GB</language> - `, - site: path.join(site.toString(), 'links'), - trailingSlash: false, - items: LINKS.map((link) => ({ - link: link.href, - title: link.title, - content: mdParser.render(link.description), - pubDate: new Date(link.isoDateAdded), - description: mdParser.render(link.description), - author: 'Joe Carstairs', - })), - }) -} diff --git a/website/src/pages/microlog/[...slug].astro b/website/src/pages/microlog/[...slug].astro deleted file mode 100644 index 69c94b0..0000000 --- a/website/src/pages/microlog/[...slug].astro +++ /dev/null @@ -1,26 +0,0 @@ ---- -import { type CollectionEntry, getCollection, render } from 'astro:content'; -import MicrologPost from '../../layouts/MicrologPost.astro'; -import { renderGemtextToHtml } from '../../renderGemtextToHtml'; - -export async function getStaticPaths() { - const posts = await getCollection('microlog'); - return posts.map((post) => ({ - params: { slug: post.id }, - props: post, - })); -} -type Props = CollectionEntry<'microlog'>; - -const { id: slug, body } = Astro.props; -const pubDateStr = slug.replaceAll(/\.[0-9]+/g, ''); -const pubDate = new Date(pubDateStr); -if (isNaN(pubDate.valueOf())) { - throw new Error(`Could not construct a valid publication date for microlog post: ${slug}`); -} -const Content = renderGemtextToHtml(body ?? '', pubDateStr); ---- - -<MicrologPost pubDate={pubDate} title={pubDateStr}> - <Fragment set:html={Content}></Fragment> -</MicrologPost> diff --git a/website/src/pages/microlog/index.astro b/website/src/pages/microlog/index.astro deleted file mode 100644 index dd1ee16..0000000 --- a/website/src/pages/microlog/index.astro +++ /dev/null @@ -1,13 +0,0 @@ ---- -import { SITE_TITLE, SITE_DESCRIPTION } from '../../consts'; -import MicrologFeed from '../../components/MicrologFeed.astro'; -import Page from '../../layouts/Page.astro'; ---- - -<Page title={SITE_TITLE} description={SITE_DESCRIPTION}> - <MicrologFeed headingLevel={1}> - <!-- <section> - <p><a href="/blog/subscribe">How to subscribe to this blog</a></p> - </section> --> - </MicrologFeed> -</Page> diff --git a/website/src/pages/microlog/rss.xml.ts b/website/src/pages/microlog/rss.xml.ts deleted file mode 100644 index fa04b32..0000000 --- a/website/src/pages/microlog/rss.xml.ts +++ /dev/null @@ -1,29 +0,0 @@ -import path from "node:path"; -import rss from "@astrojs/rss"; -import type { APIContext } from "astro"; -import { getCollection } from "astro:content"; -import { renderGemtextToHtml } from "../../renderGemtextToHtml"; - -export async function GET(context: APIContext) { - // `site` is guaranteed to exist because we define it in our Astro config - const site = context.site!; - const posts = await getCollection("microlog"); - - return rss({ - title: "Joe Carstairs’ microlog", - description: "My private X feed I guess?", - customData: ` - <image>/images/headshot.webp</image> - <language>en-GB</language> - `, - site: path.join(site.toString(), "microlog"), - trailingSlash: false, - items: posts.map((post) => ({ - link: `/microlog/${post.id}`, - title: post.id, - content: renderGemtextToHtml(post.body ?? ""), - pubDate: new Date(post.id.replace(/\.[0-9]+$/g, "")), - author: "Joe Carstairs", - })), - }); -} |
