font restyle and new diy post
All checks were successful
Deploy Blog / deploy (push) Successful in 1m31s
|
|
@ -2,7 +2,7 @@
|
|||
title: "Creating a router cabinet"
|
||||
slug: /creating-a-router-cabinet/
|
||||
date: 2025-10-05
|
||||
tags: ["personal", "projects", "diy"]
|
||||
tags: ["personal", "projects", "DIY"]
|
||||
---
|
||||
|
||||
As you can see below, my consumer networking was quite messy. I wanted to hide
|
||||
|
|
@ -51,5 +51,9 @@ my Philips Hue bridge and a Raspberry Pi 3 which I am running on the mesh
|
|||
network as a [Pihole](https://pi-hole.net/). The main router wouldn't sit nicely
|
||||
on the shelf so I just used a couple of wood screws to hold it in place.
|
||||
|
||||
The total cost was £38.78 covering the price of the cabinet and a new
|
||||
surge-protected Masterplug extension lead.
|
||||
The total cost was £35.47.
|
||||
|
||||
| Product | Cost |
|
||||
| ------------------------------------- | ----- |
|
||||
| Wall Mounted Kitchen Storage Cabinet | 26.67 |
|
||||
| Masterplug Four Socket Extension Lead | 8.80 |
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
title: "Homeowner at last"
|
||||
slug: /homeowner-at-last/
|
||||
date: 2025-08-28
|
||||
tags: ["personal", "projects", "diy"]
|
||||
tags: ["personal", "projects"]
|
||||
---
|
||||
|
||||
After many years of saving and renting I am finally a homeowner! I bought a
|
||||
|
|
|
|||
BIN
posts/img/product-image.png
Normal file
|
After Width: | Height: | Size: 411 KiB |
BIN
posts/img/security-light-battery-unit.jpg
Normal file
|
After Width: | Height: | Size: 1.9 MiB |
BIN
posts/img/security-light-closeup.jpg
Normal file
|
After Width: | Height: | Size: 1.4 MiB |
BIN
posts/img/security-light-device-taping.jpg
Normal file
|
After Width: | Height: | Size: 1.7 MiB |
BIN
posts/img/security-light-feeding-cable-rotated.jpg
Normal file
|
After Width: | Height: | Size: 3.6 MiB |
BIN
posts/img/security-light-feeding-cable.jpg
Normal file
|
After Width: | Height: | Size: 2.9 MiB |
BIN
posts/img/security-light-finished.jpg
Normal file
|
After Width: | Height: | Size: 3.6 MiB |
BIN
posts/img/security-light-flexible-trunking.jpg
Normal file
|
After Width: | Height: | Size: 1.1 MiB |
BIN
posts/img/security-light-panel-taping.jpg
Normal file
|
After Width: | Height: | Size: 2.6 MiB |
88
posts/installing-a-solar-powered-security-light.md
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
---
|
||||
title: "Installing a solar-powered security light"
|
||||
slug: /installing-a-security-light/
|
||||
date: 2025-11-16
|
||||
tags: ["projects", "DIY"]
|
||||
---
|
||||
|
||||

|
||||
|
||||
I recently installed a security light in the back garden. I wanted it to be
|
||||
"dumb" (not IoT-linked) and solar-powered with battery power as a fallback.
|
||||
|
||||
The
|
||||
[Auraglow Hybrid](https://web.archive.org/web/20250826070058/https://www.diy.com/departments/auraglow-hybrid-solar-battery-twin-led-security-light-cyrus/5060539629306_BQ.prd)
|
||||
met these criteria and was very cheap.
|
||||
|
||||
Normally, I would pay more for a higher quality device but the reviews were
|
||||
uniformly good and I wanted to see how plausible a solar-powered light would be
|
||||
in English winters, before shelling out any more.
|
||||
|
||||

|
||||
|
||||
I placed it above the garage side-door to illuminate the garden and the pathway
|
||||
to the garage from the Command Center.
|
||||
|
||||
In order to maximise access to sunlight, I had to use the full-length of the
|
||||
solar panel cable (5m) to stretch it round from the back of the garage (which is
|
||||
south-facing) to the side door.
|
||||
|
||||
The cable connecting the solar panel to the light is a 3.5mm TRS cable - the
|
||||
same as those used for earphones. It's very flimsy, like a pair of liquorice
|
||||
laces and once I had tacked it along the roof of the garage I started to worry
|
||||
about how well it would endure, longer-term. I think this is the only aspect of
|
||||
the light where you get what you pay for. The loose wire also looked a bit
|
||||
rubbish and the aesthetics of this grated on me.
|
||||
|
||||

|
||||
|
||||
So, to improve its water-proofing and protect it from UV I bought some
|
||||
cylindrical black conduit from Screwfix. I don't think this is truly
|
||||
outdoors-grade but it's a lot better than than exposing the thin cable to the
|
||||
elements. As the diameter of the conduit is several times wider than the cable,
|
||||
it can be used for additional cabling down the line, should I need it.
|
||||
|
||||

|
||||
|
||||
This left the cable loose at the terminals so I bought some flexible trunking to
|
||||
protect the cable at the joins. (This is also intended for indoor use so I'll
|
||||
have to see how well it lasts.) I joined the trunking to the conduit with
|
||||
self-amalgamating tape for a water-tight seal.
|
||||
|
||||

|
||||
|
||||
I'm happy with the appearance and think it looks quite professional.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
As for the device itself, the performance is as good as the reviews suggested.
|
||||
The LED luminosity is very bright and the sensor is effective. (Perhaps a bit
|
||||
too effective since I've noticed it being triggered by spiders weaving webs
|
||||
around the light.) After a couple of days I removed the back-up batteries to see
|
||||
how well the solar panel was working. I waited two days before putting them
|
||||
back, and the light functioned exactly the same as it did on battery power
|
||||
throughout this period. (For the last few weeks, we have mostly had cloudy,
|
||||
rainy days with only occasional bursts of sunlight.)
|
||||
|
||||
Other than the spiders, the only other main drawback is that it requires C-type
|
||||
batteries. As rechargable batteries of this type are hard to come by it meant I
|
||||
couldn't use a high-quality brand like Eneloop. I had to go for the least-worst
|
||||
Chinese-branded batteries I could find on Amazon if I wanted to use
|
||||
rechargables.
|
||||
|
||||
Ideally I would want some visual indicator of the current capacity of the solar
|
||||
battery and the back-up batteries but for a device under £20 this is probably
|
||||
asking a bit too much.
|
||||
|
||||
Mostly due to me over-engineering the cabling, the total cost of this project
|
||||
was £60.17.
|
||||
|
||||
| Product | Cost |
|
||||
| ------------------------------------------------------------- | ----- |
|
||||
| Auraglow Hybrid Solar & Battery Twin LED Security Light (B&Q) | 15.99 |
|
||||
| Round conduit and connectors (Screwfix) | 17.52 |
|
||||
| Flexible trunking (Amazon) | 6.15 |
|
||||
| Self-amalgamating tape 10m (Amazon) | 6.52 |
|
||||
| EBL 5000mAh C-type recharageable batteries (Amazon) | 13.99 |
|
||||
|
|
@ -10,13 +10,13 @@ const EolasEntries = ({ entries }) => {
|
|||
<ul>
|
||||
<li className="mb-4">
|
||||
<div className="flex justify-between items-center relative gap-3 hover:bg-[#504945]">
|
||||
<span className="overflow-hidden whitespace-nowrap text-muted-foreground shrink-0">
|
||||
<span className="overflow-hidden whitespace-nowrap text-muted-foreground shrink-0 condensed">
|
||||
{convertDate(entry.last_modified)}
|
||||
</span>
|
||||
<a
|
||||
href={`https://eolas.systemsobscure.net/entries/${entry.title}`}
|
||||
key={i}
|
||||
className="text-right overflow-hidden text-ellipsis whitespace-nowrap min-w-0 flex-1"
|
||||
className="text-right overflow-hidden text-ellipsis whitespace-nowrap min-w-0 flex-1 font-medium"
|
||||
>
|
||||
{entry.title.replace(/_/g, " ")}
|
||||
</a>
|
||||
|
|
@ -39,7 +39,7 @@ const EolasListing = () => {
|
|||
<div className="space-my-8">
|
||||
<section className="container">
|
||||
<h2 className="text-2xl font-medium mb-4 text-[#fabd2f]!">
|
||||
Recent zettels
|
||||
recent notes (external)
|
||||
</h2>
|
||||
|
||||
{isLoading && <span>Loading...</span>}
|
||||
|
|
|
|||
|
|
@ -8,18 +8,18 @@ const PostListing = ({ posts, title, showAllButton }) => {
|
|||
<div className="container mx-auto p-4 grow">
|
||||
<div className="space-my-8">
|
||||
<section className="container">
|
||||
<h2 className="text-2xl font-medium mb-4">{title}</h2>
|
||||
<h2 className="text-2xl font-semibold mb-4">{title}</h2>
|
||||
{posts.map((post) => (
|
||||
<ul>
|
||||
<li className="mb-4">
|
||||
<div className="flex justify-between items-center relative gap-3 hover:bg-[#504945]">
|
||||
<span className="overflow-hidden whitespace-nowrap text-muted-foreground shrink-0">
|
||||
<span className="overflow-hidden whitespace-nowrap text-muted-foreground shrink-0 condensed">
|
||||
{convertDate(post.date)}
|
||||
</span>
|
||||
<Link
|
||||
to={`/posts/${post.slug}`}
|
||||
key={post.slug}
|
||||
className="text-right overflow-hidden text-ellipsis whitespace-nowrap min-w-0 flex-1"
|
||||
className="text-right overflow-hidden text-ellipsis whitespace-nowrap min-w-0 flex-1 font-medium"
|
||||
>
|
||||
{post.title}
|
||||
</Link>
|
||||
|
|
|
|||
|
|
@ -1,31 +1,8 @@
|
|||
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&family=IBM+Plex+Sans+Condensed:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&family=IBM+Plex+Sans:ital,wght@0,100..700;1,100..700&display=swap");
|
||||
@import "./styles/_variables.css";
|
||||
@import "tailwindcss";
|
||||
@import "tw-animate-css";
|
||||
|
||||
@font-face {
|
||||
font-family: "iA Writer Quattro";
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-weight: 400;
|
||||
src:
|
||||
url(https://cdn.jsdelivr.net/fontsource/fonts/ia-writer-quattro@latest/latin-400-normal.woff2)
|
||||
format("woff2"),
|
||||
url(https://cdn.jsdelivr.net/fontsource/fonts/ia-writer-quattro@latest/latin-400-normal.woff)
|
||||
format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "iA Writer Mono";
|
||||
font-style: normal;
|
||||
font-display: swap;
|
||||
font-weight: 400;
|
||||
src:
|
||||
url(https://cdn.jsdelivr.net/fontsource/fonts/ia-writer-mono@latest/latin-400-normal.woff2)
|
||||
format("woff2"),
|
||||
url(https://cdn.jsdelivr.net/fontsource/fonts/ia-writer-mono@latest/latin-400-normal.woff)
|
||||
format("woff");
|
||||
}
|
||||
|
||||
* {
|
||||
outline-color: color-mix(in srgb, var(--ring) 50%, transparent);
|
||||
}
|
||||
|
|
@ -39,14 +16,29 @@ body {
|
|||
color: var(--foreground);
|
||||
}
|
||||
|
||||
.condensed {
|
||||
font-family: "IBM Plex Sans Condensed";
|
||||
}
|
||||
|
||||
figcaption {
|
||||
font-weight: 500;
|
||||
font-family: "IBM Plex Sans Condensed";
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: var(--color-orange-light);
|
||||
|
||||
font-family: "IBM Plex Sans Condensed";
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-family: "IBM Plex Sans Condensed";
|
||||
color: var(--color-green-light);
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-family: "IBM Plex Sans Condensed";
|
||||
}
|
||||
.monospaced-font {
|
||||
font-family: "iA Writer Mono";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,12 +17,12 @@ const HomePage = () => {
|
|||
<img src={gruvboxComputer} className="md:w-80 w-50" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold py-3 monospaced-font text-center sm:text-left md:text-left">
|
||||
<div className="scanlined inline-block italic py-1 px-2">
|
||||
<h1 className="text-4xl font-bold py-3 text-center sm:text-left md:text-left">
|
||||
<div className="scanlined inline-block py-1 px-2">
|
||||
systems obscure
|
||||
</div>
|
||||
</h1>
|
||||
<p className="leading-relaxed text-center sm:text-left md:text-left">
|
||||
<p className="text-center sm:text-left md:text-left text-muted condensed font-medium text-lg">
|
||||
Software engineer at ITV, formerly BBC. This is my technical
|
||||
scrapbook and digital garden.
|
||||
</p>
|
||||
|
|
@ -32,23 +32,23 @@ const HomePage = () => {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<PostListing title="Recent posts" posts={posts.slice(0, 5)} />
|
||||
<PostListing title="recent posts" posts={posts.slice(0, 5)} />
|
||||
|
||||
<PostListing
|
||||
title="Highlights"
|
||||
title="highlights"
|
||||
posts={posts.filter((post) => post.tags.includes("highlight"))}
|
||||
/>
|
||||
|
||||
<div className="container mx-auto p-4 grow">
|
||||
<div className="space-my-8">
|
||||
<section className="container">
|
||||
<h2 className="text-2xl font-medium mb-4 text-[#fb4934]!">
|
||||
Projects
|
||||
<h2 className="text-2xl font-semibold mb-4 text-[#d3869b]!">
|
||||
projects
|
||||
</h2>
|
||||
<ul>
|
||||
<li className="pb-2">
|
||||
<a
|
||||
className="underline underline-offset-3 text-[18px] text-primary hover:text-primary/80"
|
||||
className="underline underline-offset-3 text-[18px] text-primary hover:text-primary/80 font-medium"
|
||||
href="https://eolas.systemsobscure.net"
|
||||
target="_blank"
|
||||
>
|
||||
|
|
@ -56,7 +56,7 @@ const HomePage = () => {
|
|||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<p className="text-muted">
|
||||
<p className="">
|
||||
A public frontend for my local Zettelkasten created with
|
||||
NodeJS, Python and React.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,79 +1,79 @@
|
|||
:root {
|
||||
--radius: 0.3rem;
|
||||
--background: #282828;
|
||||
--foreground: #ebdbb2;
|
||||
--sidebar: #3c3836;
|
||||
--color-red-light: #fb4934;
|
||||
--color-orange-light: #fe8019;
|
||||
--color-green-light: #b8bb26;
|
||||
--color-aqua-muted: #689d6a;
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: #8ec07c;
|
||||
--primary-muted: #689d6a;
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.97 0 0);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: #bdae93;
|
||||
--muted-foreground: #928374;
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
--font-monospaced: "iA Writer Mono";
|
||||
--font-sansserif: "iA Writer Quattro", sans-serif;
|
||||
--radius: 0.3rem;
|
||||
--background: #282828;
|
||||
--foreground: #ebdbb2;
|
||||
--sidebar: #3c3836;
|
||||
--color-red-light: #fb4934;
|
||||
--color-orange-light: #fe8019;
|
||||
--color-green-light: #b8bb26;
|
||||
--color-aqua-muted: #689d6a;
|
||||
--card: oklch(1 0 0);
|
||||
--card-foreground: oklch(0.145 0 0);
|
||||
--popover: oklch(1 0 0);
|
||||
--popover-foreground: oklch(0.145 0 0);
|
||||
--primary: #8ec07c;
|
||||
--primary-muted: #689d6a;
|
||||
--primary-foreground: oklch(0.985 0 0);
|
||||
--secondary: oklch(0.97 0 0);
|
||||
--secondary-foreground: oklch(0.205 0 0);
|
||||
--muted: #bdae93;
|
||||
--muted-foreground: #928374;
|
||||
--accent: oklch(0.97 0 0);
|
||||
--accent-foreground: oklch(0.205 0 0);
|
||||
--destructive: oklch(0.577 0.245 27.325);
|
||||
--border: oklch(0.922 0 0);
|
||||
--input: oklch(0.922 0 0);
|
||||
--ring: oklch(0.708 0 0);
|
||||
--chart-1: oklch(0.646 0.222 41.116);
|
||||
--chart-2: oklch(0.6 0.118 184.704);
|
||||
--chart-3: oklch(0.398 0.07 227.392);
|
||||
--chart-4: oklch(0.828 0.189 84.429);
|
||||
--chart-5: oklch(0.769 0.188 70.08);
|
||||
--sidebar-foreground: oklch(0.145 0 0);
|
||||
--sidebar-primary: oklch(0.205 0 0);
|
||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
||||
--sidebar-accent: oklch(0.97 0 0);
|
||||
--sidebar-accent-foreground: oklch(0.205 0 0);
|
||||
--sidebar-border: oklch(0.922 0 0);
|
||||
--sidebar-ring: oklch(0.708 0 0);
|
||||
--font-monospaced: "IBM Plex Mono";
|
||||
--font-sansserif: "IBM Plex Sans", sans-serif;
|
||||
}
|
||||
|
||||
@theme inline {
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius));
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
--radius-sm: calc(var(--radius) - 4px);
|
||||
--radius-md: calc(var(--radius) - 2px);
|
||||
--radius-lg: var(--radius);
|
||||
--radius-xl: calc(var(--radius));
|
||||
--color-background: var(--background);
|
||||
--color-foreground: var(--foreground);
|
||||
--color-card: var(--card);
|
||||
--color-card-foreground: var(--card-foreground);
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-muted: var(--muted);
|
||||
--color-muted-foreground: var(--muted-foreground);
|
||||
--color-accent: var(--accent);
|
||||
--color-accent-foreground: var(--accent-foreground);
|
||||
--color-destructive: var(--destructive);
|
||||
--color-border: var(--border);
|
||||
--color-input: var(--input);
|
||||
--color-ring: var(--ring);
|
||||
--color-chart-1: var(--chart-1);
|
||||
--color-chart-2: var(--chart-2);
|
||||
--color-chart-3: var(--chart-3);
|
||||
--color-chart-4: var(--chart-4);
|
||||
--color-chart-5: var(--chart-5);
|
||||
--color-sidebar: var(--sidebar);
|
||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||
--color-sidebar-primary: var(--sidebar-primary);
|
||||
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
||||
--color-sidebar-accent: var(--sidebar-accent);
|
||||
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
||||
--color-sidebar-border: var(--sidebar-border);
|
||||
--color-sidebar-ring: var(--sidebar-ring);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,41 +5,41 @@ import { convertDate } from "@/utils/convertDate"
|
|||
import { usePosts } from "@/hooks/usePosts"
|
||||
|
||||
const BlogTemplate = () => {
|
||||
const { slug } = useParams()
|
||||
const { posts } = usePosts()
|
||||
const post = posts?.find((x) => x.slug === slug)
|
||||
const { slug } = useParams()
|
||||
const { posts } = usePosts()
|
||||
const post = posts?.find((x) => x.slug === slug)
|
||||
|
||||
return (
|
||||
<MainTemplate>
|
||||
<div className="container mx-auto p-4 grow">
|
||||
{!post ? (
|
||||
<div>Loading...</div>
|
||||
) : (
|
||||
<article className="prose prose-lg max-w-none">
|
||||
<header className="mb-6 pb-4">
|
||||
<h1 className="text-4xl font-semibold mb-4 leading-tight">
|
||||
{post?.title}
|
||||
</h1>
|
||||
<div className="flex flex-wrap align-center gap-4 text-[#928374]">
|
||||
<time datetime={convertDate(post?.date)} className="text-sm ">
|
||||
{convertDate(post?.date)}
|
||||
</time>
|
||||
<div className="flex flex-wrap gap-3 align-center">
|
||||
{post?.tags?.map((tag, i) => (
|
||||
<Link
|
||||
className="text-primary text-sm underline underline-offset-3 hover:text-[#689d6a]"
|
||||
key={i}
|
||||
to={`/tags/${tag}`}
|
||||
>
|
||||
{tag}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
return (
|
||||
<MainTemplate>
|
||||
<div className="container mx-auto p-4 grow">
|
||||
{!post ? (
|
||||
<div>Loading...</div>
|
||||
) : (
|
||||
<article className="prose prose-lg max-w-none">
|
||||
<header className="mb-6 pb-4">
|
||||
<h1 className="text-4xl font-bold mb-4 leading-tight">
|
||||
{post?.title}
|
||||
</h1>
|
||||
<div className="flex flex-wrap align-center gap-4 text-[#928374] condensed font-medium">
|
||||
<time datetime={convertDate(post?.date)} className="text-sm">
|
||||
{convertDate(post?.date)}
|
||||
</time>
|
||||
<div className="flex flex-wrap gap-3 align-center">
|
||||
{post?.tags?.map((tag, i) => (
|
||||
<Link
|
||||
className="text-primary text-sm underline underline-offset-3 hover:text-[#689d6a]"
|
||||
key={i}
|
||||
to={`/tags/${tag}`}
|
||||
>
|
||||
{tag}
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div
|
||||
className="
|
||||
<div
|
||||
className="
|
||||
[&>h2]:text-2xl [&>h2]:font-medium [&>h2]:my-4 [&>h2]:text-[#fabd2f]!
|
||||
[&>h3]:text-xl [&>h3]:font-medium [&>h3]:my-4 [&>h3]:text-[#fabd2f]
|
||||
[&>h4]:text-lg [&>h4]:font-medium [&>h4]:my-4 [&>h4]:text-[#fabd2f]
|
||||
|
|
@ -65,13 +65,13 @@ const BlogTemplate = () => {
|
|||
[&>table>tbody>tr]:m-0 [&>table>tbody>tr]:border-t [&>table>tbody>tr]:p-0 [&>table>tbody>tr:even]:bg-muted
|
||||
[&>table>tbody>tr>td]:border [&>table>tbody>tr>td]:px-4 [&>table>tbody>tr>td]:py-2 [&>table>tbody>tr>td]:text-left [&>table>tbody>tr>td[align=center]]:text-center [&>table>tbody>tr>td[align=right]]:text-right
|
||||
"
|
||||
dangerouslySetInnerHTML={{ __html: post?.html }}
|
||||
/>
|
||||
</article>
|
||||
)}
|
||||
</div>
|
||||
</MainTemplate>
|
||||
)
|
||||
dangerouslySetInnerHTML={{ __html: post?.html }}
|
||||
/>
|
||||
</article>
|
||||
)}
|
||||
</div>
|
||||
</MainTemplate>
|
||||
)
|
||||
}
|
||||
|
||||
export default BlogTemplate
|
||||
|
|
|
|||
|
|
@ -3,82 +3,82 @@
|
|||
import gruvboxComputer from "../images/gruvbox-computer.svg"
|
||||
import { Link } from "react-router"
|
||||
const Header = () => {
|
||||
return (
|
||||
<header className="py-6">
|
||||
<nav className="bg-sidebar container mx-auto justify-between flex gap-1">
|
||||
<div className="scanlined">
|
||||
<img src={gruvboxComputer} className="w-10" />
|
||||
</div>
|
||||
<ul class="flex space-x-4 px-4 py-2">
|
||||
<li class="flex flex-col items-center justify-center">
|
||||
<Link
|
||||
class="text-primary underline underline-offset-3 hover:text-[#689d6a]"
|
||||
to="/"
|
||||
>
|
||||
home
|
||||
</Link>
|
||||
</li>
|
||||
return (
|
||||
<header className="py-6">
|
||||
<nav className="bg-sidebar container mx-auto justify-between flex gap-1">
|
||||
<div className="scanlined">
|
||||
<img src={gruvboxComputer} className="w-10" />
|
||||
</div>
|
||||
<ul class="flex space-x-4 px-4 py-2">
|
||||
<li class="flex flex-col items-center justify-center">
|
||||
<Link
|
||||
class="text-primary underline underline-offset-3 hover:text-[#689d6a] condensed font-semibold text-lg"
|
||||
to="/"
|
||||
>
|
||||
home
|
||||
</Link>
|
||||
</li>
|
||||
|
||||
<li class="flex flex-col items-center justify-center">
|
||||
<Link
|
||||
class="text-primary underline underline-offset-3 hover:text-[#689d6a]"
|
||||
to="/posts"
|
||||
>
|
||||
posts
|
||||
</Link>
|
||||
</li>
|
||||
<li class="flex flex-col items-center justify-center">
|
||||
<Link
|
||||
class="text-primary underline underline-offset-3 hover:text-[#689d6a]"
|
||||
to="/about"
|
||||
>
|
||||
about
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
<li class="flex flex-col items-center justify-center">
|
||||
<Link
|
||||
class="text-primary underline underline-offset-3 hover:text-[#689d6a] condensed font-semibold text-lg"
|
||||
to="/posts"
|
||||
>
|
||||
posts
|
||||
</Link>
|
||||
</li>
|
||||
<li class="flex flex-col items-center justify-center">
|
||||
<Link
|
||||
class="text-primary underline underline-offset-3 hover:text-[#689d6a] condensed font-semibold text-lg"
|
||||
to="/about"
|
||||
>
|
||||
about
|
||||
</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
|
||||
const Footer = () => {
|
||||
return (
|
||||
<footer className="bg-sidebar container mx-auto px-4 mt-10 mb-8">
|
||||
<nav>
|
||||
<ul className="flex flex-row justify-start gap-4">
|
||||
<li className="flex flex-col items-center justify-center">
|
||||
<a
|
||||
className="text-primary underline underline-offset-3 hover:text-[#689d6a]"
|
||||
href="https://forgejo.systemsobscure.net/thomasabishop"
|
||||
target="blank"
|
||||
>
|
||||
forgejo
|
||||
</a>
|
||||
</li>
|
||||
<li className="">
|
||||
<a
|
||||
className="text-primary underline underline-offset-3 hover:text-[#689d6a]"
|
||||
href="https://fosstodon.org/@systemsobscure"
|
||||
target="blank"
|
||||
>
|
||||
fosstodon
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</footer>
|
||||
)
|
||||
return (
|
||||
<footer className="bg-sidebar container mx-auto px-4 mt-10 mb-8">
|
||||
<nav>
|
||||
<ul className="flex flex-row justify-start gap-4">
|
||||
<li className="flex flex-col items-center justify-center">
|
||||
<a
|
||||
className="text-primary underline underline-offset-3 hover:text-[#689d6a] font-semibold"
|
||||
href="https://forgejo.systemsobscure.net/thomasabishop"
|
||||
target="blank"
|
||||
>
|
||||
forgejo
|
||||
</a>
|
||||
</li>
|
||||
<li className="">
|
||||
<a
|
||||
className="text-primary underline underline-offset-3 hover:text-[#689d6a] font-semibold"
|
||||
href="https://fosstodon.org/@systemsobscure"
|
||||
target="blank"
|
||||
>
|
||||
fosstodon
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
|
||||
const MainTemplate = ({ children }) => {
|
||||
return (
|
||||
<div className="antialiased max-w-3xl mt-3 mx-auto text-[#fbf1c7] bg-[#282828] no-scanlines wrapper">
|
||||
<main className="flex-auto min-w-0 mt-0 flex flex-col px-2 md:px-0">
|
||||
<Header />
|
||||
<div>{children}</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
return (
|
||||
<div className="antialiased max-w-3xl mt-3 mx-auto bg-[#282828] no-scanlines wrapper">
|
||||
<main className="flex-auto min-w-0 mt-0 flex flex-col px-2 md:px-0">
|
||||
<Header />
|
||||
<div>{children}</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
export default MainTemplate
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ const TagTemplate = () => {
|
|||
return (
|
||||
<MainTemplate>
|
||||
<div className="container mx-auto p-4">
|
||||
<h1 className="h1 text-3xl text-[#b8bb26]!">{`Posts tagged: #${tag}`}</h1>
|
||||
<h1 className="h1 text-3xl text-[#b8bb26]! font-bold">{`Posts tagged: #${tag}`}</h1>
|
||||
</div>
|
||||
<PostListing title={null} posts={filteredPosts} />
|
||||
</MainTemplate>
|
||||
|
|
|
|||