complete restyle
All checks were successful
Deploy Blog / deploy (push) Successful in 2m16s

This commit is contained in:
Thomas Bishop 2026-03-08 19:08:26 +00:00
parent 4858c1a68a
commit f62963f5c9
10 changed files with 119 additions and 299 deletions

53
@s
View file

@ -1,53 +0,0 @@
---
title: "Replacing garage guttering"
slug: /replacing-garage-guttering/
date: 2025-12-06
tags: ["projects", "DIY"]
---
I faced the following problems with the guttering on my garage:
- It had been bent out of shape by the wind
- The seals on the joins had worn away causing leaks
- There was sitting water that wasn't making it to the downpipe
- It was old and gross
Whenever it rained heavily, these problems would compound and lead to water
pouring over onto the garage brickwork.
The sitting water was caused by the lack of a sufficient drop from the union
join with my neighbour's gutter to the downpipe. A further impediment was that
the water had to turn a 90 degree angle, around the side of the garabe, before
reaching the downpipe. As a result, water was only making it to the downpipe
when there was very heavy rain and/or high winds. During normal drip-drainage of
the daily dew condensation on the roof, the water was just pooling in the
gutter.
I decided to redesign the passage to the downpipe. Instead of trying to make the
water turn a bend I thought it would be better to work _with_ gravity and have
the drop start at the end of the guttering, not around the corner. This way, the
water would have increased velocity at the beginning of its descent into the
downpipe.
By fashioning a "swans neck" sequence of joins, the downpipe now turns the
corner _during_ descent and is fed downwards along the wall to the water butt.
This has been working very well and the water no longer pools. I've noticed
however that condensation forms on the underside of the downpipe. This doesn't
look great and I worry about it wearing away the sealant I have applied at the
joins.
Overall, however I think it looks much neater as well as being more satisfying
from an engineering perspective. The white half-round gutters blend in nicely
with the neighbours' and look a lot cleaner.
I didn't keep track of costs for this project. I think in total it cost around
£80. This included the cost of the Floplast guttering and fixtures, the downpipe
and the protective mesh I applied to the top of the gutters to prevent blockages
from leaves and roof moss.
In order to drill the fixtures into the garage masonry I needed a more powerful
drill than my 18V battery-powered Erbauer. I bought this a few years ago before
I knew much about brands and power-tool quality. So I bought a wired Makita
hammer-drill for around £90. I think when I buy new power-tools in future I will
stick to Makita. The build quality and performance is excellent.

10
package-lock.json generated
View file

@ -80,7 +80,6 @@
"integrity": "sha512-IaaGWsQqfsQWVLqMn9OB92MNN7zukfVA4s7KKAI0KfrrDsZ0yhi5uV4baBuLuN7n3vsZpwP8asPPcVwApxvjBQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.27.1",
@ -2263,7 +2262,6 @@
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.7.tgz",
"integrity": "sha512-wAHc/cgKzW7LZNFloThyHnV/AX9gTg3w5yAv0gvQHPZoCnepwqCMtzbuPbb2UvfvO32XZ46e8bPOYbfZhzVnnQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@tanstack/query-core": "5.90.7"
},
@ -2419,7 +2417,6 @@
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@ -2532,7 +2529,6 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001716",
"electron-to-chromium": "^1.5.149",
@ -2951,7 +2947,6 @@
"integrity": "sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.8.0",
"@eslint-community/regexpp": "^4.12.1",
@ -4386,7 +4381,6 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@ -4396,7 +4390,6 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.26.0"
},
@ -4814,7 +4807,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@ -5004,7 +4996,6 @@
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.25.0",
"fdir": "^6.4.4",
@ -5093,7 +5084,6 @@
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz",
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},

View file

@ -13,7 +13,7 @@ const renderer = {
}
const highlighter = await createHighlighter({
themes: ["gruvbox-dark-hard"],
themes: ["light-plus"],
langs: [
"javascript",
@ -49,7 +49,7 @@ const posts = files.map((file) => {
(match, lang, code) => {
return highlighter.codeToHtml(code.trim(), {
lang: lang || "text",
theme: "gruvbox-dark-hard",
theme: "light-plus",
transformers: [transformerColorizedBrackets()],
})

View file

@ -5,23 +5,23 @@ import { convertDate } from "@/utils/convertDate"
const PostListing = ({ posts, title, showAllButton }) => {
return (
<div className="container mx-auto py-4 px-1 md:p-4 grow">
<div className="space-my-8">
<section className="container">
<h2 className="text-2xl font-semibold mb-4 block h2-home scanlined px-2">
<div className="">
<div className="">
<section className="">
<h2 className="">
{`${title}`}
</h2>
{posts.map((post) => (
<ul>
<li className="mb-4">
<div className="flex justify-between flex-col relative hover:bg-[#504945]">
<span className="overflow-hidden whitespace-nowrap text-muted-foreground shrink-0 condensed">
<ul className="no-bullets">
<li className="">
<div className="">
<span style={{ marginRight: '1rem' }}>
{convertDate(post.date)}
</span>
<Link
to={`/posts/${post.slug}`}
key={post.slug}
className="overflow-hidden text-ellipsis whitespace-nowrap min-w-0"
className=""
>
{post.title}
</Link>

View file

@ -1,94 +1,42 @@
@import url("https://fonts.googleapis.com/css2?family=Inter:ital,opsz,wght@0,14..32,100..900;1,14..32,100..900&family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap");
@import "./styles/_variables.css";
@import "tailwindcss";
@import "tw-animate-css";
* {
outline-color: color-mix(in srgb, var(--ring) 50%, transparent);
.header-links {
display: flex;
list-style: none;
gap: .5rem;
margin: 0;
padding: 0;
}
html {
font-family: var(--font-sansserif);
.plain-link {
color: inherit;
text-decoration: none;
}
body {
background-color: var(--background);
color: var(--foreground);
.no-bullets {
list-style: none;
padding-left: 0;
}
.condensed {
font-family: "Inter";
blockquote {
font-style: italic;
}
figcaption {
font-weight: 500;
font-family: "Inter";
text-align: center;
font-style: italic;
}
h1 {
color: var(--color-orange-light);
font-family: "Inter";
figure {
text-align: center;
}
h2 {
font-family: "Inter";
color: var(--color-green-light);
}
.h2-home {
font-family: "Inter";
font-weight: 600;
}
h3 {
font-family: "Inter";
font-weight: 600 !important;
}
.monospaced-font {
font-family: "iA Writer Mono";
}
.scanlined {
position: relative;
/* Add this */
}
.scanlined::after {
content: "";
position: absolute;
top: 0;
left: 0;
figure img {
width: 100%;
height: 100%;
background-image: linear-gradient(rgba(0, 0, 0, 0.4) 1px, transparent 1px);
background-size: 2px 2px;
background-repeat: repeat;
pointer-events: none;
z-index: 9999;
/* Might want to lower this too */
}
code {
font-family: var(--font-monospaced);
}
p code {
color: var(--foreground);
background: #504945;
font-size: 14px;
padding: 0.2rem 0.3rem;
border-radius: var(--radius);
font-weight: 500;
max-width: 500px;
min-width: 300px;
height: auto;
}
.shiki {
padding: 1rem 1.2rem;
border-radius: 0;
overflow-x: auto;
margin: 1.5rem 0;
line-height: 1.3;
/* counter-reset: line; */
font-family: var(--font-monospaced) !important;
font-size: 14px !important;
padding: 1rem;
border: 1pt solid black;
}

View file

@ -4,16 +4,16 @@ import portrait from "../images/portrait-compressed.jpg"
const AboutPage = () => {
return (
<MainTemplate>
<div className="container mx-auto py-4 px-1 md:p-4">
<figure className="w-full flex flex-col items-center mb-6">
<div className="scanlined inline-block">
<div className="">
<figure className="">
<div className="">
<img
alt="A portrait of the blog author"
src={portrait}
className="w-80 flex"
style={{ width: '25%' }}
/>
</div>
<figcaption className="text-sm text-muted-foreground mt-3 text-center">
<figcaption className="">
Pictured with the WITCH computer at the{" "}
<a
href="https://www.tnmoc.org/"
@ -63,22 +63,22 @@ const AboutPage = () => {
<p className="leading-[1.6] [&:not(:first-child)]:mt-6">
Some things I like:
<ul className="pt-2">
<li className="mb-1">🐶 Staffies and other bull-breeds</li>
<li className="mb-1">🎼 Classical music (Haydn, Mozart, JSB)</li>
<li className="mb-1">🛸 Science fiction </li>
<ul className="no-bullets">
<li className="">🐶 Staffies and other bull-breeds</li>
<li className="">🎼 Classical music (Haydn, Mozart, JSB)</li>
<li className="">🛸 Science fiction </li>
</ul>
</p>
<p className="leading-[1.6] [&:not(:first-child)]:mt-6">
<p className="">
Some things I'm interested in:
<ul className="pt-2">
<li className="mb-1">🧑💻 Self-hosting and digital resiliance</li>
<li className="mb-1">🖳 The history of computing and networks</li>
<li className="mb-1"> Buddhism</li>
<ul className="no-bullets">
<li className="">🧑💻 Self-hosting and digital resiliance</li>
<li className="">🖳 The history of computing and networks</li>
<li className=""> Buddhism</li>
{/*
<li className="mb-1">📡 Civil communications infrastructure</li>
<li className="">📡 Civil communications infrastructure</li>
*/}
</ul>
</p>

View file

@ -10,64 +10,21 @@ const HomePage = () => {
const { posts } = usePosts()
return (
<MainTemplate>
<div className="container mx-auto md:p-4 py-4 px-1 grow">
<div className="space-my-8">
<section className="space-y-4">
<div className="gap-6 flex flex-col items-center sm:flex-row">
<div className="scanlined">
<img src={gruvboxComputer} className="md:w-80 w-50" />
</div>
<div>
<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="text-center sm:text-left md:text-left text-muted font-medium">
A wizard who goes to bed early. This is my technical scrapbook
<p>A wizard who goes to bed early. This is my technical scrapbook
and digital garden.
</p>
</div>
</div>
</section>
</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 md:p-4 py-4 px-1 grow">
<div className="space-my-8">
<section className="container">
<h2 className="text-2xl font-semibold mb-4 text-[#d3869b]! h2-home scanlined px-2">
{`projects`}
</h2>
<ul>
<li className="pb-2">
<a
className="underline underline-offset-4 text-[18px] text-primary hover:text-primary/80 font-medium"
href="https://eolas.systemsobscure.net"
target="_blank"
>
eolas
</a>
</li>
<li>
<p className="">
A public frontend for my local Zettelkasten created with
NodeJS, Python and React.
</p>
</li>
</ul>
</section>
</div>
</div>
<CodeStats />
<EolasListing />
{/* <CodeStats />
<EolasListing /> */}
</MainTemplate>
)
}

View file

@ -9,7 +9,7 @@ const PostsPage = () => {
return (
<MainTemplate>
<PostListing title="all posts" posts={posts} />
<PostListing title="All posts" posts={posts} />
</MainTemplate>
)
}

View file

@ -3,6 +3,7 @@ import MainTemplate from "./MainTemplate"
import { Link, useParams } from "react-router"
import { convertDate } from "@/utils/convertDate"
import { usePosts } from "@/hooks/usePosts"
import { convertDateFriendly } from "../utils/convertDate"
const BlogTemplate = () => {
const { slug } = useParams()
@ -15,19 +16,19 @@ const BlogTemplate = () => {
{!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 inline-block scanlined px-2">
<article className="">
<header className="">
<h1 className="">
{post?.title}
</h1>
<div className="flex flex-wrap align-center gap-4 text-[#928374] condensed font-medium">
<div className="">
<time datetime={convertDate(post?.date)} className="text-sm">
{convertDate(post?.date)}
{convertDateFriendly(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]"
style={{ marginRight: '0.5rem' }}
key={i}
to={`/tags/${tag}`}
>
@ -40,30 +41,7 @@ const BlogTemplate = () => {
<div
className="
[&>h2]:text-2xl [&>h2]:font-bold [&>h2]:my-4 [&>h2]:text-[#ebdbb2]!
[&>h3]:text-xl [&>h3]:font-bold [&>h3]:my-4 [&>h3]:text-[#ebdbb2]!
[&>h4]:text-lg [&>h4]:font-bold [&>h4]:my-4 [&>h4]:text-[#ebdbb2]!
[&>p]:leading-7 [&>p:not(:first-child)]:mt-4
[&>p+:is(h1,h2,h3,h4,h5,h6)]:mt-6
[&>blockquote]:mt-4 [&>blockquote]:border-l-2 [&>blockquote]:pl-6 [&>blockquote]:text-muted-foreground
[&>ul]:my-4 [&>ul]:ml-6 [&>ul]:list-disc [&>ul>li]:mt-2
[&>pre]:mt-6 [&>pre]:mb-6
[&>p+pre]:mt-6
[&>pre+p]:mt-6
[&>ul+pre]:mt-6
[&>li]:leading-[1.6]
[&_li_code]:relative [&_li_code]:rounded [&_li_code]:bg-[#504945] [&_li_code]:px-[0.3rem] [&_li_code]:py-[0.2rem] [&_li_code]:font-mono [&_li_code]:text-sm [&_li_code]:font-normal
[&>code]:relative [&>code]:rounded [&>code]:bg-[#504945] [&>code]:px-[0.3rem] [&>code]:py-[0.2rem] [&>code]:font-mono [&>code]:text-sm [&>code]:font-normal
[&>figure]:w-full [&>figure]:max-w-2xl [&>figure]:flex [&>figure]:flex-col [&>figure]:items-center [&>figure]:justify-center [&>figure]:mb-6 [&>figure]:mx-auto [&>figure>img]:max-w-full [&>figure>img]:max-h-[700px] [&>figure>img]:w-auto [&>figure>img]:h-auto [&>figure>img]:object-contain
[&>figure>img]:max-w-2xl [&>figure>img]:max-h-[700px] [&>figure>img]:w-auto [&>figure>img]:h-auto [&>figure>img]:object-contain
[&>figure>figcaption]:text-sm [&>figure>figcaption]:text-[#bdae93] [&>figure>figcaption]:mt-3 [&>figure>figcaption]:text-center
[&>figure>figcaption>a]:text-primary [&>figure>figcaption>a:hover]:text-primary/80
[&_a]:underline [&_a]:underline-offset-3 [&_a]:hover:text-[#689d6a] [&_a]:text-primary
[&>table]:w-full [&>table]:my-4
[&>table>thead>tr]:m-0 [&>table>thead>tr]:border-t [&>table>thead>tr]:p-0 [&>table>thead>tr:even]:bg-muted
[&>table>thead>tr>th]:border [&>table>thead>tr>th]:px-4 [&>table>thead>tr>th]:py-2 [&>table>thead>tr>th]:text-left [&>table>thead>tr>th]:font-bold [&>table>thead>tr>th[align=center]]:text-center [&>table>thead>tr>th[align=right]]:text-right
[&>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 }}
/>

View file

@ -1,33 +1,32 @@
// @ts-nocheck
import gruvboxComputer from "../images/gruvbox-computer.svg"
import { Link } from "react-router"
const Header = () => {
return (
<header className="md:py-6 pb-4">
<nav className="bg-sidebar container mx-auto justify-between flex gap-1">
<Link to="/">
<div className="scanlined">
<img src={gruvboxComputer} className="w-11" />
</div>
</Link>
<ul class="flex space-x-4 px-4 py-2 text-sm">
<li class="flex flex-col items-center justify-center">
<header>
<nav className="">
<h1>
<Link
class="text-primary underline underline-offset-3 hover:text-[#689d6a] condensed font-semibold text-lg"
to="/posts"
>
posts
</Link>
className="plain-link"
to="/">Systems Obscure</Link>
</h1>
<ul className="header-links">
<li>
<Link 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>
<Link to="/about">About</Link>
</li>
<li className="flex flex-col items-center justify-center">
<a
className=""
href="https://forgejo.systemsobscure.net/thomasabishop"
target="blank"
>
Forgejo
</a>
</li>
</ul>
</nav>
</header>
@ -36,16 +35,16 @@ const Header = () => {
const Footer = () => {
return (
<footer className="bg-sidebar container mx-auto px-4 mt-10 mb-8">
<footer className="mx-auto">
<nav>
<ul className="flex flex-row justify-start gap-4">
<ul className="">
<li className="flex flex-col items-center justify-center">
<a
className="text-primary underline underline-offset-3 hover:text-[#689d6a] font-semibold"
className=""
href="https://forgejo.systemsobscure.net/thomasabishop"
target="blank"
>
forgejo
Forgejo
</a>
</li>
</ul>
@ -56,13 +55,14 @@ const Footer = () => {
const MainTemplate = ({ children }) => {
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">
<div className="">
<main className="">
<Header />
<div>{children}</div>
<Footer />
</main>
</div>
)
}
export default MainTemplate
//antialiased max-w-3xl mt-3 mx-auto bg-[#282828] no-scanlines wrapper
//main: flex-auto min-w-0 mt-0 flex flex-col px-2 md:px-0