AI Policy
+ return ( +AI Policy
-Last updated: 7th July 2025
+Last updated: 7th July 2025
-- The text content of the blog posts is entirely written by myself. -
+The text content of the blog posts is entirely written by myself.
-- I use AI (Github Copilot code review) to detect and correct typos and spelling errors. -
++ I use AI (Github Copilot code review) to detect and correct typos and + spelling errors. +
-- I do sometimes use AI as a research tool (e.g. 'tell me what technologies solve X problem') and suggestions from AI may make it into a blog post. However the content and subject of blog posts always respresents my genuine thoughts, opinions or experiences on a topic; I do not use AI to suggest topic ideas. -
++ I do sometimes use AI as a research tool (e.g. 'tell me what + technologies solve X problem') and suggestions from AI may make it + into a blog post. However the content and subject of blog posts always + respresents my genuine thoughts, opinions or experiences on a topic; I + do not use AI to suggest topic ideas. +
-- Images may be AI generated - when they are, the alt text reflects it. -
- -- Code snippets may or may not be generated with AI assistance; code snippets are a genuine representation the code I write in both professional and personal contexts. -
++ Images may be AI generated - when they are, the alt text reflects it. +
++ Code snippets may or may not be generated with AI assistance; code + snippets are a genuine representation the code I write in both + professional and personal contexts. +
Conway's Game of Life
-Conway's game of life is a classic zero player game that makes for a fun programming exercise.
-See the wikipedia article here.
-Maybe we can play around with alternative rule sets, or investigate performance optimisation.
-Conway's Game of Life
++ Conway's game of life is a classic zero player game that makes for + a fun programming exercise. +
++ See the{" "} + + wikipedia article here. + +
++ Maybe we can play around with alternative rule sets, or investigate + performance optimisation. +
+Open Source Projects
--
-
-
-
- react-github-permalink
-
-
Provide a Github permalink and this React component will display the - codeblock. I use this component regularly in my blog. -
-
- -
-
- react-text-highlight
-
-
- Highlight some text and show a
-corresponding comment in the page margin. -
- -
-
- use-cookie-state
-
-
- A useState like React hook that is responsive to cookie changes that - occur outside of the React context. Includes polyfill for browsers - that do not support the CookieStore API. -
-
+ return (
+ -
+
+ react-github-permalink
+
+
+ {" "} + Provide a Github permalink and this React component will display the + codeblock. I use this component regularly in my blog. +
+
+ -
+
+ react-text-highlight
+
+
+ Highlight some text and show a{" "} +
++ corresponding comment + {" "} + in the page margin. +
+ -
+
+ use-cookie-state
+
+
+ A useState like React hook that is responsive to cookie changes that + occur outside of the React context. Includes polyfill for browsers + that do not support the CookieStore API. +
+
- -
-
- TypeScript Tutorial Series
-
-
- A TypeScript tutorial series, complete with interactive exercises, - starting from the very basics and going up to generics and mapped - and index types. -
-
+ -
+
+ TypeScript Tutorial Series
+
+
+ A TypeScript tutorial series, complete with interactive exercises, + starting from the very basics and going up to generics and mapped + and index types. +
+
- -
-
- Javascript 101
-
-
- A JavaScript tutorial series for people who know nothing about - coding. Complete with interactive exercises. -
-
- -
+
+ Javascript 101
+
+
+ A JavaScript tutorial series for people who know nothing about + coding. Complete with interactive exercises. +
+
+
Open Source Projects
+-
+
Black Sheep Code
-A blog about modern web development.
-Black Sheep Code
+A blog about modern web development.
+Blog
-Blog
+- I support open source:{" "} - - Open Collective - -
- > - ); ++ I support open source:{" "} + + Open Collective + +
+ > + ); } diff --git a/src/app/posts/[slug]/page.tsx b/src/app/posts/[slug]/page.tsx index 32707ba4..886f898b 100644 --- a/src/app/posts/[slug]/page.tsx +++ b/src/app/posts/[slug]/page.tsx @@ -1,35 +1,37 @@ import { BlogPostFrame } from "@/components/BlogPostFrame/BlogPostFrame"; -import { getMetadata, getAllPostFrontmatter, getBlogContent } from "@/utils/blogPosts"; -import { PropsWithChildren } from "react"; +import { + getAllPostFrontmatter, + getBlogContent, + getMetadata, +} from "@/utils/blogPosts"; +import type { PropsWithChildren } from "react"; export async function generateStaticParams() { - - const allFrontMatter = await getAllPostFrontmatter(); - return allFrontMatter.map((v) => { - - return { slug: v.slug.replace("posts/", "") } - }) + const allFrontMatter = await getAllPostFrontmatter(); + return allFrontMatter.map((v) => { + return { slug: v.slug.replace("posts/", "") }; + }); } export async function generateMetadata(props: { - params: Promise<{ - slug: string - }> + params: Promise<{ + slug: string; + }>; }) { - const params = await props.params; - return getMetadata(`/posts/${params.slug}`); + const params = await props.params; + return getMetadata(`/posts/${params.slug}`); } -export default async function PageLayout(props: PropsWithChildren<{ +export default async function PageLayout( + props: PropsWithChildren<{ params: Promise<{ - slug: string - }> -}>) { - - const params = await props.params; - const content = await getBlogContent( params.slug,"posts"); - return- This is a sandbox page. -
+ return ( +This is a sandbox page.
-☝️ Interactive demo
-☝️ Interactive demo
+-
- Spotted an error? Edit this page with Github -
-+
+ Spotted an error?{" "} + + Edit this page with Github + +
+- This article is a part of the series "{firstSeriesItem.frontmatter.series?.description ?? firstSeriesItem.frontmatter.series?.name}"
--
- {props.frontmatter?.seriesFrontmatter?.map((v) => {
- return
- - - {v.frontmatter.meta?.title ?? v.slug} - - - })} -
+ This article is a part of the series " + + {firstSeriesItem.frontmatter.series?.description ?? + firstSeriesItem.frontmatter.series?.name} + + "{" "} +
+-
+ {props.frontmatter?.seriesFrontmatter?.map((v) => {
+ return (
+
- + + {v.frontmatter.meta?.title ?? v.slug} + + + ); + })} +
{frontmatter.frontmatter.meta.title}
--
- Questions? Comments? Criticisms? Get in the comments! 👇 - > +export async function FrontmatterBox( + props: PropsWithChildren<{ + slug: string; + }> +) { + const frontmatter = await getFrontmatterFromSlug(props.slug); + + if (!frontmatter) { + return <>{props.children}>; + } + + return ( + <> +
{frontmatter.frontmatter.meta.title}
++
+ Questions? Comments? Criticisms?{" "} + Get in the comments! 👇 + > > -} \ No newline at end of file + ); +} diff --git a/src/components/ImagePanel/ImagePanel.tsx b/src/components/ImagePanel/ImagePanel.tsx index 583b1c85..a1b5f6a7 100644 --- a/src/components/ImagePanel/ImagePanel.tsx +++ b/src/components/ImagePanel/ImagePanel.tsx @@ -1,25 +1,25 @@ -import { ReactNode } from "react" +import type { ReactNode } from "react"; type ImageWithCaption = { - image: ReactNode, - caption?: string; -} + image: ReactNode; + caption?: string; +}; export function ImagePanel(props: { - images: ImageWithCaption | Array
{v.caption}
-{v.caption}
+Articles tagged "{props.filterInformation.tagFilter}":
} - {props.filterInformation.tagFilter && !props.filterInformation.didFindArticles && <>No articles found for tag "{props.filterInformation.tagFilter}"
You might find these articles useful:
>} -+ Articles tagged{" "} + "{props.filterInformation.tagFilter}": +
+ )} + {props.filterInformation.tagFilter && + !props.filterInformation.didFindArticles && ( + <> ++ No articles found for tag{" "} + "{props.filterInformation.tagFilter}" +
+You might find these articles useful:
+ > + )} +{v.frontmatter.meta?.title ?? v.slug}
- {v.frontmatter.meta?.dateCreated &&{v.frontmatter.meta?.description ?? ''}
-+ {v.frontmatter.meta?.title ?? v.slug} +
+ {v.frontmatter.meta?.dateCreated && ( ++ {v.frontmatter.meta?.description ?? ""} +
+