From c9be513a40721c518b332d001a63e2505bf0020a Mon Sep 17 00:00:00 2001 From: April Eaton Date: Mon, 12 Jan 2026 16:29:41 +0100 Subject: [PATCH 1/4] Better themeing with proper light/dark mode support The themeing is broken up into 4 colors, `text`, `background`, `accent`, and `highlight` `text` is used for most foreground elements, including obviously text `background` is used for most background colors `accent` is used for decorations `highlight` is used for highlighting certain elements, such as headers --- client/src/App.css | 40 ++++++++++++++++++++++++- client/src/components/header/header.css | 22 ++++++++++++-- client/src/components/header/index.tsx | 1 + 3 files changed, 60 insertions(+), 3 deletions(-) diff --git a/client/src/App.css b/client/src/App.css index 1d2bc97..5cebb30 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -1,6 +1,44 @@ -html { +:root { + /* Catppuccin colors */ + /* Light mode */ + --light-text: #1e2030; + --light-background: #eff1f5; + --light-accent: #8839ef; + --light-highlight: #209fb5; + /* Dark mode */ + --dark-text: #cad3f5; + --dark-background: #24273a; + --dark-accent: #c6a0f6; + --dark-highlight: #7dc4e4; + + /* Global configs */ color-scheme: light dark; font-family: system-ui; +} + +@media (prefers-color-scheme: light) { + html { + color: var(--light-text); + background-color: var(--light-background); + } + + h1 { + color: var(--light-highlight); + } +} + +@media (prefers-color-scheme: dark) { + html { + color: var(--dark-text); + background-color: var(--dark-background); + } + + h1 { + color: var(--dark-highlight); + } +} + +html { display: flex; align-items: center; justify-content: center; diff --git a/client/src/components/header/header.css b/client/src/components/header/header.css index dd546ca..ef0aaaf 100644 --- a/client/src/components/header/header.css +++ b/client/src/components/header/header.css @@ -1,5 +1,4 @@ header { - border-color: #c6a0f6; border-width: 2px; border-style: solid; @@ -20,8 +19,27 @@ nav { } a { - color: #cad3f5; text-decoration: none; font-weight: bold; } } + +@media (prefers-color-scheme: light) { + header { + border-color: var(--light-accent); + } + + a { + color: var(--light-text); + } +} + +@media (prefers-color-scheme: dark) { + header { + border-color: var(--dark-accent); + } + + a { + color: var(--dark-text); + } +} diff --git a/client/src/components/header/index.tsx b/client/src/components/header/index.tsx index 18eda90..cbbd234 100644 --- a/client/src/components/header/index.tsx +++ b/client/src/components/header/index.tsx @@ -1,3 +1,4 @@ +import "/src/App.css"; import "./header.css"; import { Nav } from "./nav"; From 7294793125c5533cfe31d925e4e88608635fd77c Mon Sep 17 00:00:00 2001 From: April Eaton Date: Mon, 12 Jan 2026 16:39:31 +0100 Subject: [PATCH 2/4] Extract navigation links to private component --- client/src/components/header/nav.tsx | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/client/src/components/header/nav.tsx b/client/src/components/header/nav.tsx index 68d2f24..26938fb 100644 --- a/client/src/components/header/nav.tsx +++ b/client/src/components/header/nav.tsx @@ -5,13 +5,17 @@ export function Nav() { return ( ); } + +function NavLink(props: { path: string; name: string }) { + return ( +
  • + {props.name} +
  • + ); +} From e85d93270b9a42a924c2c0d6fdeeb75e70ae5797 Mon Sep 17 00:00:00 2001 From: April Eaton Date: Mon, 12 Jan 2026 17:41:57 +0100 Subject: [PATCH 3/4] Restructuring for better layout and code reuse --- client/src/App.css | 27 +++++++++++--- client/src/components/header/header.css | 8 +++- client/src/pages/about.tsx | 7 ++-- client/src/pages/page.tsx | 11 ++++++ client/src/pages/root.tsx | 7 ++-- client/tsconfig.json | 49 ++++++++++++++----------- 6 files changed, 73 insertions(+), 36 deletions(-) create mode 100644 client/src/pages/page.tsx diff --git a/client/src/App.css b/client/src/App.css index 5cebb30..f202981 100644 --- a/client/src/App.css +++ b/client/src/App.css @@ -39,12 +39,29 @@ } html { - display: flex; - align-items: center; - justify-content: center; } body { - height: 100%; - width: 100%; + min-height: 100svh; + height: fit-content; + display: flex; + flex-direction: column; + align-items: center; + margin: 0; +} + +#app { + height: 100%; + min-width: 100%; + display: flex; + flex-direction: column; + align-items: center; + align-content: center; + justify-content: center; +} + +#body { + max-width: 40rem; + width: 100%; + height: 100%; } diff --git a/client/src/components/header/header.css b/client/src/components/header/header.css index ef0aaaf..a5862d7 100644 --- a/client/src/components/header/header.css +++ b/client/src/components/header/header.css @@ -1,8 +1,14 @@ header { + --margin: 0.25rem; + --padding: 0.25rem; border-width: 2px; border-style: solid; - position: sticky top; + position: sticky; + + margin: var(--margin); + padding: var(--padding); + width: calc(100% - (2 * var(--margin)) - (2 * var(--padding)) - 4px); } nav { diff --git a/client/src/pages/about.tsx b/client/src/pages/about.tsx index 7af40d5..a8dd87e 100644 --- a/client/src/pages/about.tsx +++ b/client/src/pages/about.tsx @@ -1,16 +1,15 @@ -import { Header } from "/src/components/header"; +import { Page } from "/src/pages/page"; import "/src/App.css"; export function About() { return ( - <> -
    +

    About Starve Me Now!

    Firstly, this is intended for those who have a starvation/diet control fetish. This is not intended to help with weight loss or similar reasons to fast.

    - +
    ); } diff --git a/client/src/pages/page.tsx b/client/src/pages/page.tsx new file mode 100644 index 0000000..c48ab01 --- /dev/null +++ b/client/src/pages/page.tsx @@ -0,0 +1,11 @@ +import { Header } from "@/components/header"; +import "@/App.css"; + +export function Page(props: { children: React.ReactNode }) { + return ( + <> +
    +
    {props.children}
    + + ); +} diff --git a/client/src/pages/root.tsx b/client/src/pages/root.tsx index 7057d23..c8cf456 100644 --- a/client/src/pages/root.tsx +++ b/client/src/pages/root.tsx @@ -1,14 +1,13 @@ -import { Header } from "/src/components/header"; +import { Page } from "/src/pages/page"; import "/src/App.css"; export function Root() { return ( - <> -
    +

    Starve Me Now!

    Edit src/App.tsx to get started!

    - +
    ); } diff --git a/client/tsconfig.json b/client/tsconfig.json index ddc2511..d6ccc11 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -1,29 +1,34 @@ { - "compilerOptions": { - /* Visit https://aka.ms/tsconfig to read more about this file */ - "target": "ES2020", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "jsx": "react-jsx", - "useDefineForClassFields": true, + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + "target": "ES2020", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "jsx": "react-jsx", + "useDefineForClassFields": true, - /* Modules */ - "module": "ESNext", - "moduleResolution": "bundler", + /* Modules */ + "module": "ESNext", + "moduleResolution": "bundler", - /* Emit */ - "noEmit": true, + /* Emit */ + "noEmit": true, - /* Interop Constraints */ - "isolatedModules": true, - "allowSyntheticDefaultImports": true, - "allowImportingTsExtensions": true, - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, + /* Interop Constraints */ + "isolatedModules": true, + "allowSyntheticDefaultImports": true, + "allowImportingTsExtensions": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, - /* Type Checking */ - "strict": true, + /* Type Checking */ + "strict": true, - /* Completeness */ - "skipLibCheck": true - } + /* Completeness */ + "skipLibCheck": true, + + "baseUrl": "./src", + "paths": { + "@/*": ["*"] + } + } } From 33073798216b25a916f2d79463c9219e2f145b68 Mon Sep 17 00:00:00 2001 From: April Eaton Date: Mon, 12 Jan 2026 17:45:05 +0100 Subject: [PATCH 4/4] Moving to better absoulte paths with `@` syntax --- client/src/App.tsx | 6 +++--- client/src/components/header/index.tsx | 2 +- client/src/index.tsx | 10 +++++----- client/src/pages/about.tsx | 4 ++-- client/src/pages/root.tsx | 4 ++-- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/client/src/App.tsx b/client/src/App.tsx index b01dfa7..82db791 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -1,6 +1,6 @@ -import "/src/App.css"; -import { About } from "./pages/about"; -import { Root } from "./pages/root"; +import "@/App.css"; +import { About } from "@/pages/about"; +import { Root } from "@/pages/root"; import { BrowserRouter, Route, Routes } from "react-router"; export function App() { diff --git a/client/src/components/header/index.tsx b/client/src/components/header/index.tsx index cbbd234..90dcd5c 100644 --- a/client/src/components/header/index.tsx +++ b/client/src/components/header/index.tsx @@ -1,4 +1,4 @@ -import "/src/App.css"; +import "@/App.css"; import "./header.css"; import { Nav } from "./nav"; diff --git a/client/src/index.tsx b/client/src/index.tsx index e2d3e7b..6dc29df 100644 --- a/client/src/index.tsx +++ b/client/src/index.tsx @@ -1,11 +1,11 @@ -import { createRoot } from 'react-dom/client'; -import { StrictMode } from 'react'; -import { App } from './App'; +import { createRoot } from "react-dom/client"; +import { StrictMode } from "react"; +import { App } from "@/App"; let container = document.getElementById("app")!; -let root = createRoot(container) +let root = createRoot(container); root.render( - + , ); diff --git a/client/src/pages/about.tsx b/client/src/pages/about.tsx index a8dd87e..2f9ee32 100644 --- a/client/src/pages/about.tsx +++ b/client/src/pages/about.tsx @@ -1,5 +1,5 @@ -import { Page } from "/src/pages/page"; -import "/src/App.css"; +import { Page } from "@/pages/page"; +import "@/App.css"; export function About() { return ( diff --git a/client/src/pages/root.tsx b/client/src/pages/root.tsx index c8cf456..1060df5 100644 --- a/client/src/pages/root.tsx +++ b/client/src/pages/root.tsx @@ -1,5 +1,5 @@ -import { Page } from "/src/pages/page"; -import "/src/App.css"; +import { Page } from "./page"; +import "@/App.css"; export function Root() { return (