style: change theme and header
All checks were successful
Deploy Blog / deploy (push) Successful in 1m38s

This commit is contained in:
Thomas Bishop 2025-10-20 17:23:59 +01:00
parent 899e3d8cb7
commit 50751e0c20
20 changed files with 574 additions and 232 deletions

2
.gitignore vendored
View file

@ -1,3 +1,5 @@
.env
# Logs
logs
*.log

199
package-lock.json generated
View file

@ -13,7 +13,10 @@
"@radix-ui/react-toggle": "^1.1.8",
"@shikijs/colorized-brackets": "^3.6.0",
"@tailwindcss/vite": "^4.1.6",
"@tanstack/react-query": "^5.90.5",
"@tanstack/react-query-devtools": "^5.90.2",
"@vitejs/plugin-react-swc": "^3.10.2",
"axios": "^1.12.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"gray-matter": "^4.0.3",
@ -2706,6 +2709,59 @@
"vite": "^5.2.0 || ^6"
}
},
"node_modules/@tanstack/query-core": {
"version": "5.90.5",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.90.5.tgz",
"integrity": "sha512-wLamYp7FaDq6ZnNehypKI5fNvxHPfTYylE0m/ZpuuzJfJqhR5Pxg9gvGBHZx4n7J+V5Rg5mZxHHTlv25Zt5u+w==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@tanstack/query-devtools": {
"version": "5.90.1",
"resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.90.1.tgz",
"integrity": "sha512-GtINOPjPUH0OegJExZ70UahT9ykmAhmtNVcmtdnOZbxLwT7R5OmRztR5Ahe3/Cu7LArEmR6/588tAycuaWb1xQ==",
"license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@tanstack/react-query": {
"version": "5.90.5",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.90.5.tgz",
"integrity": "sha512-pN+8UWpxZkEJ/Rnnj2v2Sxpx1WFlaa9L6a4UO89p6tTQbeo+m0MS8oYDjbggrR8QcTyjKoYWKS3xJQGr3ExT8Q==",
"license": "MIT",
"dependencies": {
"@tanstack/query-core": "5.90.5"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"react": "^18 || ^19"
}
},
"node_modules/@tanstack/react-query-devtools": {
"version": "5.90.2",
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.90.2.tgz",
"integrity": "sha512-vAXJzZuBXtCQtrY3F/yUNJCV4obT/A/n81kb3+YqLbro5Z2+phdAbceO+deU3ywPw8B42oyJlp4FhO0SoivDFQ==",
"license": "MIT",
"dependencies": {
"@tanstack/query-devtools": "5.90.1"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
},
"peerDependencies": {
"@tanstack/react-query": "^5.90.2",
"react": "^18 || ^19"
}
},
"node_modules/@types/babel__core": {
"version": "7.20.5",
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
@ -3153,6 +3209,23 @@
"dev": true,
"license": "Python-2.0"
},
"node_modules/asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
"license": "MIT"
},
"node_modules/axios": {
"version": "1.12.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.12.2.tgz",
"integrity": "sha512-vMJzPewAlRyOgxV2dU0Cuz2O8zzzx9VYtbJOaBgXFeLc4IV/Eg50n4LowmehOOR61S8ZMpc2K5Sa7g6A4jfkUw==",
"license": "MIT",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"proxy-from-env": "^1.1.0"
}
},
"node_modules/balanced-match": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
@ -3252,7 +3325,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz",
"integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
@ -3428,6 +3500,18 @@
"simple-swizzle": "^0.2.2"
}
},
"node_modules/combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"license": "MIT",
"dependencies": {
"delayed-stream": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/comma-separated-tokens": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz",
@ -3556,6 +3640,15 @@
"dev": true,
"license": "MIT"
},
"node_modules/delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
"license": "MIT",
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/depd": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
@ -3601,7 +3694,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz",
"integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.1",
@ -3653,7 +3745,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
"integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@ -3663,7 +3754,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@ -3673,7 +3763,6 @@
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz",
"integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==",
"dev": true,
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
@ -3682,6 +3771,21 @@
"node": ">= 0.4"
}
},
"node_modules/es-set-tostringtag": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz",
"integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==",
"license": "MIT",
"dependencies": {
"es-errors": "^1.3.0",
"get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/esbuild": {
"version": "0.25.4",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz",
@ -4192,6 +4296,63 @@
"dev": true,
"license": "ISC"
},
"node_modules/follow-redirects": {
"version": "1.15.11",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz",
"integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==",
"funding": [
{
"type": "individual",
"url": "https://github.com/sponsors/RubenVerborgh"
}
],
"license": "MIT",
"engines": {
"node": ">=4.0"
},
"peerDependenciesMeta": {
"debug": {
"optional": true
}
}
},
"node_modules/form-data": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
"integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
"license": "MIT",
"dependencies": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.8",
"es-set-tostringtag": "^2.1.0",
"hasown": "^2.0.2",
"mime-types": "^2.1.12"
},
"engines": {
"node": ">= 6"
}
},
"node_modules/form-data/node_modules/mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
"license": "MIT",
"engines": {
"node": ">= 0.6"
}
},
"node_modules/form-data/node_modules/mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"license": "MIT",
"dependencies": {
"mime-db": "1.52.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/forwarded": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
@ -4230,7 +4391,6 @@
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
@ -4250,7 +4410,6 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
"integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"call-bind-apply-helpers": "^1.0.2",
@ -4275,7 +4434,6 @@
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz",
"integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
"dev": true,
"license": "MIT",
"dependencies": {
"dunder-proto": "^1.0.1",
@ -4315,7 +4473,6 @@
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@ -4388,7 +4545,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
"integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@ -4397,11 +4553,25 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/has-tostringtag": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
"integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
"license": "MIT",
"dependencies": {
"has-symbols": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"function-bind": "^1.1.2"
@ -5014,7 +5184,6 @@
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
"integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
@ -5555,6 +5724,12 @@
"node": ">= 0.10"
}
},
"node_modules/proxy-from-env": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
"license": "MIT"
},
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",

View file

@ -16,7 +16,10 @@
"@radix-ui/react-toggle": "^1.1.8",
"@shikijs/colorized-brackets": "^3.6.0",
"@tailwindcss/vite": "^4.1.6",
"@tanstack/react-query": "^5.90.5",
"@tanstack/react-query-devtools": "^5.90.2",
"@vitejs/plugin-react-swc": "^3.10.2",
"axios": "^1.12.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"gray-matter": "^4.0.3",

11
src/api/fosstodon-api.ts Normal file
View file

@ -0,0 +1,11 @@
import axios from "axios"
const fosstodonApi = axios.create({
baseURL: import.meta.env.VITE_FOSSTODON_API_URL,
timeout: 10000,
headers: {
Authorization: import.meta.env.VITE_FOSSTODON_BEARER_TOKEN,
},
})
export default fosstodonApi

View file

@ -3,6 +3,8 @@ import { Button } from "@/components/ui/button"
import { useTheme } from "@/context/ThemeProvider"
import { MoonStar, MenuIcon } from "lucide-react"
import { Link } from "react-router"
import headerImage from "../images/radigue_gruvbox.png"
import controlPanel from "../images/control-panel.png"
import {
NavigationMenu,
NavigationMenuContent,
@ -20,19 +22,19 @@ const Menu = () => {
<NavigationMenu>
<NavigationMenuList>
{/* Desktop menu - hidden on mobile, visible on md+ */}
<div className="hidden md:flex md:space-x-1">
<NavigationMenuItem className="border">
<div className="hidden md:flex md:space-x-3">
<NavigationMenuItem className="">
<NavigationMenuLink
asChild
className={navigationMenuTriggerStyle()}
className={`${navigationMenuTriggerStyle()} border-0 rounded bg-accent/20 backdrop-blur-md hover:bg-accent/40 active:bg-accent/40 focus-visible:outline-none font-semibold transition-colors`}
>
<Link to="/posts/page/1">Posts</Link>
</NavigationMenuLink>
</NavigationMenuItem>
<NavigationMenuItem className="border">
<NavigationMenuItem className="">
<NavigationMenuLink
asChild
className={navigationMenuTriggerStyle()}
className={`${navigationMenuTriggerStyle()} border-0 rounded bg-accent/20 backdrop-blur-md hover:bg-accent/40 active:bg-accent/40 focus-visible:outline-none font-semibold transition-colors`}
>
<Link to="/about">About</Link>
</NavigationMenuLink>
@ -41,11 +43,11 @@ const Menu = () => {
{/* Mobile dropdown - visible only on small screens */}
<NavigationMenuItem className="md:hidden px-4">
<NavigationMenuTrigger className="border rounded-none">
<NavigationMenuTrigger className="border-0 rounded bg-accent/20 backdrop-blur-md hover:bg-accent/40 active:bg-accent/40 focus-visible:outline-none font-semibold border-none">
<MenuIcon />
</NavigationMenuTrigger>
<NavigationMenuContent>
<NavigationMenuContent className="bg-accent/20 border-none active:border-none">
<NavigationMenuLink asChild>
<Link to="/posts/page/1" className="block">
Posts
@ -67,20 +69,40 @@ const Menu = () => {
const Header = () => {
const { theme, setTheme } = useTheme()
return (
<header className="w-full h-12 flex items-center justify-center border-b fixed top-0 z-20 bg-sidebar">
<header className="w-full h-15 flex items-center justify-center border-b border-border border-b-1 fixed top-0 z-20 bg-sidebar">
<div
className="absolute inset-0 opacity-70 dark:opacity-40"
style={{
backgroundImage: `url(${headerImage})`,
backgroundSize: "cover",
backgroundPosition: "center 30%",
backgroundRepeat: "no-repeat",
filter: "blur(0px) grayscale(10%)",
}}
/>
<div className="absolute inset-0 bg-gradient-to-b from-background/40 via-background/30 to-background/40 dark:from-background/60 dark:via-background/50 dark:to-background/60" />
<div className="w-full px-0 md:px-4 flex items-center justify-between">
<div className="flex items-center md:px-0 px-4">
<Button
variant="ghost"
asChild
className="border md:border-none rounded-none"
className="border-0 rounded bg-accent/40 backdrop-blur-sm hover:bg-background/40 active:bg-background/40 focus-visible:outline-none transition-colors"
// className="border-0 rounded-none bg-background/20 backdrop-blur-sm hover:bg-background/40 transition-colors"
// className="border-0 rounded-none bg-background/40 backdrop-blur-md hover:bg-background transition-colors"
//
//className="border md:border-none rounded-none z-500"
>
<Link to="/">
<span className="text-lg font-semibold">Systems Obscure</span>
<span className="text-xl tracking-normal font-bold">
Systems Obscure
</span>
</Link>
</Button>
</div>
<div className="flex itemr justify-between md:gap-4">
<div className="flex itemr justify-between md:gap-4 z-500">
{/*
<Toggle
className="border bg-background rounded-none"
pressed={theme === "dark"}
@ -90,6 +112,9 @@ const Header = () => {
>
<MoonStar size={10} />
</Toggle>
*/}
<Menu />
{/*

View file

@ -0,0 +1,27 @@
import { Card, CardFooter } from "./ui/card"
const TodayILearnedCard = ({ tootBody, avatar }) => {
return (
<>
<Card className="flex flex-col h-full hover:bg-primary/5 py-6 px-0 rounded-none">
<div
className="px-5 font-mono text-[14px]"
dangerouslySetInnerHTML={{
__html: tootBody.replace("#TIL", " ").substring(0, 220),
}}
/>
<div className="px-6 text-sm font-semibold flex items-center gap-2">
{/*
<img src={avatar} className="object-contain rounded-full" />
*/}
systemsobscure@fosstodon.org
</div>
</Card>
</>
)
}
export default TodayILearnedCard

View file

@ -14,9 +14,7 @@ const PostListing = ({ posts, title, showAllButton }) => {
return (
<>
<div className="mb-5">
<h2 className="scroll-m-20 text-[1.3rem] font-semibold border-b pb-2">
{title}
</h2>
<h2 className="scroll-m-20 text-[1.5rem] font-bold ">{title}</h2>
</div>
<div className="grid grid-cols-1 md:grid-cols-1 gap-3">
{posts.map((post) => (
@ -27,10 +25,10 @@ const PostListing = ({ posts, title, showAllButton }) => {
>
<Card
key={post.slug}
className="flex flex-col h-full hover:bg-primary/5 py-4 rounded-none"
className="flex flex-col h-full hover:bg-primary/5 py-4 rounded border-none "
>
<CardHeader className="">
<CardTitle className="leading-snug font-semibold ">
<CardTitle className="leading-snug font-bold ">
{post.title}
</CardTitle>
<CardDescription className="text-sm text-muted-foreground">
@ -47,7 +45,7 @@ const PostListing = ({ posts, title, showAllButton }) => {
<Button
asChild
variant="secondary"
className="w-full mt-4 rounded-none border-1"
className="w-full mt-4 rounded bg-accent/20 hover:bg-accent/40"
>
<Link to="/posts/page/1">View all</Link>
</Button>

View file

@ -0,0 +1,38 @@
// @ts-nocheck
import { useQuery } from "@tanstack/react-query"
import fosstodonApi from "@/api/fosstodon-api"
import TodayILearnedCard from "@/components/TodayILearnedCard"
const TodayILearned = ({}) => {
const { data, isLoading } = useQuery({
queryKey: [`today_I_learned_toots`],
queryFn: () =>
fosstodonApi.get(`statuses?tagged=TIL`).then((res) => res.data),
})
console.log(data)
return (
<>
<div className="mt-8">
<h2 className="scroll-m-20 text-[1.3rem] font-semibold border-b pb-2 mb-5">
Today I learned...
</h2>
<div className="grid grid-cols-1 md:grid-cols-1 gap-3">
{data &&
data.map((toot, i) => (
<TodayILearnedCard
key={i}
tootBody={toot?.content}
avatar={toot?.account.header}
/>
))}
</div>
</div>
</>
)
}
export default TodayILearned

View file

@ -23,7 +23,7 @@ const ThemeProviderContext = createContext<ThemeProviderState>(initialState)
export function ThemeProvider({
children,
defaultTheme = "system",
defaultTheme = "dark",
storageKey = "vite-ui-theme",
...props
}: ThemeProviderProps) {

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 139 KiB

View file

@ -7,6 +7,18 @@ import BlogTemplate from "./templates/BlogTemplate"
import "./index.css"
import { PostsPage } from "./pages/posts"
import TagTemplate from "./templates/TagTemplate"
import { QueryClient, QueryClientProvider } from "@tanstack/react-query"
import { ReactQueryDevtools } from "@tanstack/react-query-devtools"
const queryClient = new QueryClient({
defaultOptions: {
queries: {
staleTime: 15 * 60 * 1000, // 15 minutes
retry: 3,
refetchOnWindowFocus: false,
},
},
})
export default function ScrollToTop() {
const { pathname } = useLocation()
@ -22,6 +34,7 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
<StrictMode>
<BrowserRouter>
<ScrollToTop />
<QueryClientProvider client={queryClient}>
<Routes>
<Route index element={<HomePage />} />
<Route path="/about" element={<AboutPage />} />
@ -29,6 +42,9 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
<Route path="/posts/:slug" element={<BlogTemplate />} />
<Route path="/tags/:tag" element={<TagTemplate />} />
</Routes>
<ReactQueryDevtools initialIsOpen={false} />
</QueryClientProvider>
</BrowserRouter>
</StrictMode>
)

View file

@ -5,7 +5,7 @@ const AboutPage = () => {
return (
<MainTemplate>
<div className="mb-5 ">
<h2 className="scroll-m-20 text-2xl font-semibold lg:text-2xl border-b pb-3">
<h2 className="scroll-m-20 text-3xl font-semibold lg:text-3xl pb-3">
About
</h2>
</div>
@ -21,7 +21,7 @@ const AboutPage = () => {
<a
href="https://www.tnmoc.org/"
target="_blank"
className="text-primary hover:text-primary/80"
className="text-[#83a598] hover:text-accent/90"
>
National Museum of Computing
</a>
@ -43,7 +43,7 @@ const AboutPage = () => {
<a
href="https://en.wikipedia.org/wiki/ITV_(TV_network)"
target="_blank"
className="underline decoration-1 hover:text-primary/80 underline-offset-4"
className="underline decoration-1 text-[#83a598] hover:text-accent/90 underline-offset-4"
>
ITV
</a>{" "}
@ -53,7 +53,7 @@ const AboutPage = () => {
<a
href="https://en.wikipedia.org/wiki/BBC"
target="_blank"
className="underline decoration-1 hover:text-primary/80 underline-offset-4"
className="underline decoration-1 text-[#83a598] hover:text-accent/90underline-offset-4"
>
BBC
</a>{" "}
@ -61,7 +61,7 @@ const AboutPage = () => {
<a
href="https://www.arria.com/"
target="_blank"
className="underline decoration-1 hover:text-primary/80 underline-offset-4"
className="underline decoration-1 text-[#83a598] hover:text-accent/90 underline-offset-4"
>
Arria NLG
</a>{" "}
@ -96,7 +96,7 @@ const AboutPage = () => {
I self-host my own Git forge at{" "}
<a
href="https://forgejo.systemsobscure.net/thomasabishop"
className="underline decoration-1 hover:text-primary/80 underline-offset-2"
className="underline decoration-1 text-[#83a598] hover:text-accent/90 underline-offset-2"
>
forgejo.systemsobscure.net
</a>{" "}

View file

@ -2,13 +2,15 @@ import MainTemplate from "@/templates/MainTemplate"
import PostListing from "@/containers/PostListing"
import { usePosts } from "@/hooks/usePosts"
import roundedPortrait from "../images/round-portrait.png"
import TodayILearned from "@/containers/TodayILearned"
const HomePage = () => {
const { posts } = usePosts()
return (
<MainTemplate>
<div className="mb-7 border border-foreground py-6 px-6 md:px-8 md:pt-9 dark:bg-sidebar">
<div className="mb-7 border-none border-accent/40 py-6 px-6 md:px-8 md:pt-6 bg-accent/15 opacity-90 rounded">
<div className="flex flex-col items-center md:flex-row md:items-start gap-4 md:gap-8 md:flex-row-reverse">
{/*
<div className="flex-shrink-0">
<img
src={roundedPortrait}
@ -16,9 +18,10 @@ const HomePage = () => {
className="rounded-image w-36 h-36 md:w-38 md:h-38 object-contain border-2 rounded-full"
/>
</div>
*/}
<div className="text-center md:text-left flex-1">
<h1 className="scroll-m-20 text-2xl font-semibold">
<h1 className="scroll-m-20 text-3xl font-bold">
Another software engineer with a blog
</h1>
<p className="leading-[1.7] mt-5">

View file

@ -62,7 +62,7 @@ const PostsPage = () => {
return (
<MainTemplate>
<div className="mb-5 ">
<h2 className="scroll-m-20 text-2xl font-semibold lg:text-2xl border-b pb-3">
<h2 className="scroll-m-20 text-3xl font-bold lg:text-3xl">
All posts
</h2>
</div>
@ -76,10 +76,10 @@ const PostsPage = () => {
>
<Card
key={post.slug}
className="flex flex-col h-full hover:bg-primary/5 py-4 px-0 rounded-none"
className="flex flex-col h-full hover:bg-primary/5 py-4 rounded border-none"
>
<CardHeader>
<CardTitle className="leading-snug font-semibold">
<CardTitle className="leading-snug font-bold">
{post.title}
</CardTitle>
<CardDescription className="text-sm text-muted-foreground">

View file

@ -35,37 +35,80 @@
--font-sansserif: "Inter", sans-serif;
}
/* .dark { */
/* --background: oklch(0.145 0 0); */
/* --foreground: oklch(0.985 0 0); */
/* --card: oklch(0.205 0 0); */
/* --card-foreground: oklch(0.985 0 0); */
/* --popover: oklch(0.205 0 0); */
/* --popover-foreground: oklch(0.985 0 0); */
/* --primary: oklch(0.922 0 0); */
/* --primary-foreground: oklch(0.205 0 0); */
/* --secondary: oklch(0.269 0 0); */
/* --secondary-foreground: oklch(0.985 0 0); */
/* --muted: oklch(0.269 0 0); */
/* --muted-foreground: oklch(0.708 0 0); */
/* --accent: oklch(0.269 0 0); */
/* --accent-foreground: oklch(0.985 0 0); */
/* --destructive: oklch(0.704 0.191 22.216); */
/* --border: oklch(1 0 0 / 10%); */
/* --input: oklch(1 0 0 / 15%); */
/* --ring: oklch(0.556 0 0); */
/* --chart-1: oklch(0.488 0.243 264.376); */
/* --chart-2: oklch(0.696 0.17 162.48); */
/* --chart-3: oklch(0.769 0.188 70.08); */
/* --chart-4: oklch(0.627 0.265 303.9); */
/* --chart-5: oklch(0.645 0.246 16.439); */
/* --sidebar: oklch(0.205 0 0); */
/* --sidebar-foreground: oklch(0.985 0 0); */
/* --sidebar-primary: oklch(0.488 0.243 264.376); */
/* --sidebar-primary-foreground: oklch(0.985 0 0); */
/* --sidebar-accent: oklch(0.269 0 0); */
/* --sidebar-accent-foreground: oklch(0.985 0 0); */
/* --sidebar-border: oklch(1 0 0 / 10%); */
/* --sidebar-ring: oklch(0.556 0 0); */
/* } */
.dark {
--background: oklch(0.145 0 0);
--foreground: oklch(0.985 0 0);
--card: oklch(0.205 0 0);
--card-foreground: oklch(0.985 0 0);
--popover: oklch(0.205 0 0);
--popover-foreground: oklch(0.985 0 0);
--primary: oklch(0.922 0 0);
--primary-foreground: oklch(0.205 0 0);
--secondary: oklch(0.269 0 0);
--secondary-foreground: oklch(0.985 0 0);
--muted: oklch(0.269 0 0);
--muted-foreground: oklch(0.708 0 0);
--accent: oklch(0.269 0 0);
--accent-foreground: oklch(0.985 0 0);
--background: oklch(0.2 0 0);
/* Softer dark gray instead of 0.145 */
--foreground: oklch(0.9 0 0);
/* Softer off-white instead of 0.985 */
--card: oklch(0.22 0 0);
/* Slightly lighter card */
--card-foreground: oklch(0.9 0 0);
/* Match foreground */
--popover: oklch(0.22 0 0);
--popover-foreground: oklch(0.9 0 0);
--primary: oklch(0.85 0 0);
/* Less harsh white */
--primary-foreground: oklch(0.22 0 0);
--secondary: oklch(0.3 0 0);
/* Lighter secondary */
--secondary-foreground: oklch(0.9 0 0);
--muted: oklch(0.3 0 0);
--muted-foreground: oklch(0.65 0 0);
/* Slightly softer */
--accent: #458588;
--accent-foreground: oklch(0.9 0 0);
--destructive: oklch(0.704 0.191 22.216);
--border: oklch(1 0 0 / 10%);
--input: oklch(1 0 0 / 15%);
--border: oklch(1 0 0 / 15%);
/* Slightly more visible borders */
--input: oklch(1 0 0 / 18%);
--ring: oklch(0.556 0 0);
--chart-1: oklch(0.488 0.243 264.376);
--chart-2: oklch(0.696 0.17 162.48);
--chart-3: oklch(0.769 0.188 70.08);
--chart-4: oklch(0.627 0.265 303.9);
--chart-5: oklch(0.645 0.246 16.439);
--sidebar: oklch(0.205 0 0);
--sidebar-foreground: oklch(0.985 0 0);
--sidebar: oklch(0.22 0 0);
/* Match card */
--sidebar-foreground: oklch(0.9 0 0);
--sidebar-primary: oklch(0.488 0.243 264.376);
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.269 0 0);
--sidebar-accent-foreground: oklch(0.985 0 0);
--sidebar-border: oklch(1 0 0 / 10%);
--sidebar-primary-foreground: oklch(0.9 0 0);
--sidebar-accent: oklch(0.3 0 0);
--sidebar-accent-foreground: oklch(0.9 0 0);
--sidebar-border: oklch(1 0 0 / 15%);
--sidebar-ring: oklch(0.556 0 0);
}

View file

@ -1,5 +1,5 @@
* {
border-color: var(--border);
/* border-color: var(--border);*/
outline-color: color-mix(in srgb, var(--ring) 50%, transparent);
}
@ -39,7 +39,7 @@ a[href]:not([aria-disabled="true"]),
box-shadow: none !important;
}
img {
figure > img {
max-width: 600px;
min-width: 300px;
}
@ -48,3 +48,4 @@ img.rounded-image {
max-width: auto;
min-width: auto;
}

View file

@ -4,7 +4,7 @@ code {
p code {
color: var(--foreground);
background: var(--color-accent);
background: var(--muted);
font-size: 14px;
padding: 0.2rem 0.3rem;
border-radius: var(--radius);

View file

@ -17,7 +17,7 @@ const BlogTemplate = () => {
) : (
<>
<div className="mb-5">
<h2 className="text-2xl font-semibold lg:text-2xl border-b pb-3">
<h2 className="text-3xl font-semibold lg:text-3xl">
{post?.title}
</h2>
</div>
@ -27,7 +27,7 @@ const BlogTemplate = () => {
</span>
<div className="flex gap-1 mt-3 md:mt-0">
{post?.tags?.map((tag, i) => (
<Badge asChild variant="secondary">
<Badge asChild variant="secondary" className="">
<Link key={i} to={`/tags/${tag}`}>
{tag}
</Link>
@ -60,7 +60,7 @@ const BlogTemplate = () => {
[&>li]:leading-[1.6]
[&_li_code]:relative [&_li_code]:rounded [&_li_code]:bg-muted [&_li_code]:px-[0.3rem] [&_li_code]:py-[0.2rem] [&_li_code]:font-mono [&_li_code]:text-sm [&_li_code]:font-normal
[&>p]:mt-6 [&>p]:leading-[1.6]
[&_a]:underline [&_a]:underline-offset-4 [&_a]:hover:text-muted-foreground
[&_a]:underline [&_a]:underline-offset-4 [&_a]:hover:text-accent/80 [&_a]:text-[#83a598]
[&>figure]:w-full [&>figure]:flex [&>figure]:flex-col [&>figure]:items-center [&>figure]:justify-center [&>figure]:mb-6 [&>figure]:mx-auto
[&>figure>img]:w-full
[&>figure>figcaption]:text-sm [&>figure>figcaption]:text-muted-foreground [&>figure>figcaption]:mt-3 [&>figure>figcaption]:text-center

View file

@ -21,7 +21,7 @@ const MainContent = ({ children }) => {
return (
<div className={classes}>
<Header />
<main className="flex-1 w-full px-2 md:px-4 flex justify-center pt-16">
<main className="flex-1 w-full px-2 md:px-4 flex justify-center pt-22">
<div className="w-full max-w-3xl lg:max-w-3xl xl:max-w-3xl px-2 md:px-4 md:py-3 py-0">
{children}
</div>