diff --git a/README.md b/README.md index 76e33f8a..3c898977 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,17 @@

- willtheorangeguy.github.io + willtheorangeguy.github.io

-

My personal Astro + Astro Paper + Tailwind + Github Pages site.

+

My personal site: an Astro + AstroPaper + Tailwind blog and portfolio, deployed to GitHub Pages.

- - Docker State - + Astro Build State + + Docker State CodeQL State @@ -22,75 +22,83 @@ GitHub Issues GitHub Pull Requests - - Discord Server ID - - GitHub Languages + + License

Key Features • - How To Use • + Installation • + Usage • + Documentation • + SupportContributing • - Changelog • - Credits & Contributors + Credits • + License

- + -![screenshot](./docs/images/welcome.jpg) +![screenshot](https://raw.githubusercontent.com/willtheorangeguy/.github/main/icons/willtheorangeguy.github.io/welcome.jpg) + +**The live site is at [williamvdg.me](https://williamvdg.me).** ## Key Features -- Uses the Astro build system to create a static blog. -- Stylized with Tailwind CSS and the Astro Paper theme. -- Projects, Labs, and Uses pages. -- Displays links to all of my personal projects. -- Cross platform, web browser based. +- A static Astro 7 blog on the AstroPaper theme, styled with Tailwind 4. +- Posts are Markdown with a Zod-validated schema, so a typo in frontmatter fails the build rather than publishing quietly. +- Per-post social preview images generated at build time with Satori. +- Client-side search over the whole site via Pagefind — no search backend. +- Projects, Labs, and Uses pages, plus a published Storybook style guide at `/styleguide`. +- Short-link redirects under `/r/`, and Google Maps contribution stats refreshed on a schedule. +- Deployed to GitHub Pages and mirrored as a Docker image on every push to `main`. + +## Installation -## How To Use +```bash +git clone https://github.com/willtheorangeguy/willtheorangeguy.github.io.git +cd willtheorangeguy.github.io +npm install +npm run dev +``` -**To access the latest version of the website visit it at [williamvdg.me](https://willtheorangeguy.github.io/).** +Then open `http://localhost:4321` — http, not https. Either npm or pnpm works locally; CI uses pnpm. Docker and production builds are covered in [`docs/installation.md`](docs/installation.md). -**To clone and run your own copy of this website**, you'll need [Git](https://git-scm.com/downloads) installed on your computer. If you would rather not use Git, you can just download the code from GitHub [above](https://github.com/willtheorangeguy/willtheorangeguy.github.io/archive/refs/heads/main.zip). From your command line: +## Usage -```bash -# Clone this repository -$ git clone https://github.com/willtheorangeguy/willtheorangeguy.github.io.git +Posts are Markdown files in `src/data/blog/`: -# Go into the repository -$ cd willtheorangeguy.github.io +```markdown +--- +title: A title +pubDatetime: 2026-08-19T10:00:00Z +description: One sentence, used for previews and the generated OG image. +--- -# Run Astro -$ npm run dev +Body copy. ``` -You can also pull the [Docker](https://www.docker.com/) image from GitHub Packages. From your command line: - -```bash -# Pull image -$ docker pull ghcr.io/willtheorangeguy/willtheorangeguy.github.io:main +`title`, `pubDatetime`, and `description` are required; `tags`, `draft`, `featured`, and the rest are optional and documented in [`docs/usage.md`](docs/usage.md). -# Run container -$ docker run -d -p 8000:80 ghcr.io/willtheorangeguy/willtheorangeguy.github.io:main +Search is powered by Pagefind, which indexes built output — it works after `npm run build && npm run preview`, not under `npm run dev`. -# Now, navigate to localhost in your browser to see the webpage -``` +## Documentation -If support is required, please open a **[GitHub Discussion](https://github.com/willtheorangeguy/willtheorangeguy.github.io/discussions/new)** or join our **[Discord](https://discord.gg/axMJXSRvTJ)**. +Full documentation lives in [`docs/`](docs/README.md): +[Installation](docs/installation.md) · [Quickstart](docs/quickstart.md) · [Usage](docs/usage.md) · [Configuration](docs/configuration.md) · [Architecture](docs/architecture.md) · [Development](docs/development.md) · [Deployment](docs/deployment.md) · [Google Maps automation](docs/google-maps-automation.md) · [FAQ](docs/faq.md) · [Troubleshooting](docs/troubleshooting.md) · [Roadmap](docs/roadmap.md) -## Contributing +Legal text served by the site lives in [`docs/legal/`](docs/legal/): [Privacy Policy](docs/legal/privacy.md) and [Terms and Conditions](docs/legal/terms.md). -Please contribute using [GitHub Flow](https://guides.github.com/introduction/flow). Create a branch, add commits, and [open a pull request](https://github.com/willtheorangeguy/willtheorangeguy.github.io/compare). +![Visualization of the codebase](./diagram.svg) -Please read [`CONTRIBUTING`](https://github.com/willtheorangeguy/.github/blob/main/CONTRIBUTING.md) for details on our [`CODE OF CONDUCT`](https://github.com/willtheorangeguy/.github/blob/main/CODE_OF_CONDUCT.md), and the process for submitting pull requests to us. +## Support -## Changelog +Open a [GitHub Discussion](https://github.com/willtheorangeguy/willtheorangeguy.github.io/discussions/new) or file an [issue](https://github.com/willtheorangeguy/willtheorangeguy.github.io/issues/new/choose). -See the [`CHANGELOG`](CHANGELOG.md) file for details. +## Contributing -![Visualization of the codebase](./diagram.svg) +Contributions welcome. See the org-wide [Contributing Guide](https://github.com/willtheorangeguy/.github/blob/main/CONTRIBUTING.md) and [Code of Conduct](https://github.com/willtheorangeguy/.github/blob/main/CODE_OF_CONDUCT.md). ## Credits @@ -126,12 +134,6 @@ This software uses the following open source packages, projects, services or web - [@willtheorangeguy](https://github.com/willtheorangeguy) - Sponsor on [PayPal](https://paypal.me/wvdg44?country.x=CA&locale.x=en_US) - [@JASKIRAT11011](https://github.com/JASKIRAT11011) -## You may also like... - -- [Running Calculator](https://github.com/willtheorangeguy/Running-Calculator) - A running speed calculator for any unit of distance. -- [Python Logo Widgets](https://github.com/willtheorangeguy/Python-Logo-Widgets) - Python Powered Logo widgets that can be added to any GUI project. -- [Random Lotto Number Chooser](https://github.com/willtheorangeguy/Random-Lotto-Number-Chooser) - Randomly pick lucky lotto numbers. - ## License -This project is licensed under the [MIT License](https://mit-license.org/) - see the [`LICENSE`](LICENSE.md) file for details. See the [Privacy Policy](https://github.com/willtheorangeguy/willtheorangeguy.github.io/blob/main/docs/legal/PRIVACY.md) and [Terms and Conditions](https://github.com/willtheorangeguy/willtheorangeguy.github.io/blob/main/docs/legal/TERMS.md) for legal information. +This project is licensed under the [MIT License](https://mit-license.org/) - see the [`LICENSE`](LICENSE.md) file for details. See the [Privacy Policy](docs/legal/privacy.md) and [Terms and Conditions](docs/legal/terms.md) for legal information. diff --git a/docs/README.md b/docs/README.md index 70503005..dfe77c6c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,13 +1,40 @@ -# willtheorangeguy.github.io Documentation - -This folder includes all of the docs for willtheorangeguy.github.io. - -```text -├── docs -| ├── images -| ├── legal -| | ├── PRIVACY.md -| | ├── TERMS.md -| ├── USAGE.md -└── README.md +# willtheorangeguy.github.io — Documentation + +The source of my personal site at [williamvdg.me](https://williamvdg.me): an Astro static site +built on the AstroPaper theme, deployed to GitHub Pages and mirrored as a Docker image. + ``` +docs/ +├── README.md this index +├── quickstart.md clone to a running dev server +├── installation.md prerequisites, npm and pnpm, Docker +├── usage.md writing posts, drafts, and the short-link redirects +├── configuration.md site metadata, socials, feature flags, timezone +├── architecture.md Astro layout, React islands, OG images, search, theming +├── development.md lint, format, Storybook, conventions, CI +├── deployment.md Pages, the custom domain, the Docker image +├── google-maps-automation.md the scheduled contribution-stats scraper +├── faq.md questions this setup raises +├── troubleshooting.md concrete errors and their causes +├── roadmap.md gaps and deliberate non-goals +├── legal/ +│ ├── privacy.md privacy policy served by the site +│ └── terms.md terms and conditions served by the site +└── internal/ + └── known-issues.md defects found while documenting (not fixed) +``` + +## Start here + +- Running it locally — [Quickstart](./quickstart.md) +- Writing a post — [Usage](./usage.md) +- Changing the site's identity, socials, or feature flags — [Configuration](./configuration.md) +- Understanding the build — [Architecture](./architecture.md), then [Deployment](./deployment.md) + +## Note on the Projects page + +`src/pages/projects.astro` hardcodes image URLs pointing into other repositories' +`docs/images/` directories. Those directories are being removed across the account in favour of +a central `willtheorangeguy/.github/icons/`, so most of those images will 404 as that work +merges. This is recorded in [`internal/known-issues.md`](./internal/known-issues.md) with the +replacement URLs. diff --git a/docs/USAGE.md b/docs/USAGE.md deleted file mode 100644 index b3ea3033..00000000 --- a/docs/USAGE.md +++ /dev/null @@ -1,18 +0,0 @@ -# willtheorangeguy.github.io Usage - -To run the willtheorangeguy.github.io website, you can run the scripts from GitHub, or run a [Docker](https://www.docker.com/) container from [GitHub Packages](https://github.com/willtheorangeguy/willtheorangeguy.github.io/pkgs/container/willtheorangeguy.github.io). - -## GitHub Scripts - -1. To run the willtheorangeguy.github.io website, download the latest `.zip` file from [GitHub Releases](https://github.com/willtheorangeguy/willtheorangeguy.github.io/releases/latest) page. -2. Extract the `.zip` file using a program like [7-Zip](https://www.7-zip.org/). -3. Start the Astro server: `npm run dev`. -4. Point your browser to `https://localhost:4321/` to view a preview. - -## Docker Container - -1. Download and install [Docker](https://www.docker.com/products/docker-desktop/). -2. Open a terminal and pull the container: `docker pull ghcr.io/willtheorangeguy/willtheorangeguy.github.io:main`. -3. Start the container: `docker run -d -p 8000:80 ghcr.io/willtheorangeguy/willtheorangeguy.github.io:main`. -4. Head to [http://localhost:8000/](http://localhost:8000/). -5. Enjoy the website! diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 00000000..61f45544 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,94 @@ +# willtheorangeguy.github.io — Architecture + +An Astro static site on the [AstroPaper](https://github.com/satnaing/astro-paper) theme. Astro 7, +Tailwind 4, React 19 for a few interactive islands, TypeScript throughout. Output is static HTML +— there is no server. + +## Layout + +``` +src/ +├── config.ts site metadata, pagination, feature flags, timezone +├── constants.ts SOCIALS, SHARE_LINKS, GISCUS +├── content.config.ts Zod schema for the blog collection +├── data/blog/ posts, as Markdown +├── pages/ routes, including projects.astro and og.png.ts +├── layouts/ page shells +├── components/ .astro components, plus three .tsx islands +├── stories/ Storybook stories +├── styles/global.css theme variables via @theme inline +├── utils/ OG generation, caches, helpers +└── assets/icons/ SVGs imported by constants.ts + +public/ +├── r/ short-link redirects, with an index +├── toggle-theme.js the theme switcher, vanilla JS +├── pagefind/ search index, copied in by the build +└── styleguide/ Storybook output, built by the build +``` + +`@/` resolves to `src/`, configured in `tsconfig.json`. Relative imports that climb out of a +directory are avoided. + +## Content + +Posts are a Zod-validated Astro content collection. The schema is the contract: it names every +legal frontmatter field, and anything else fails the build. Files prefixed `_` are skipped by +the loader. + +## React islands, kept small + +Only three components are React, and only because they are interactive: `GoogleMapsStats.tsx`, +`UnsplashStats.tsx`, and `Comments.tsx` (Giscus). Everything else is `.astro` and ships no +JavaScript. That boundary is worth keeping — the reason the site is fast is that almost none of +it hydrates. + +## OG images + +Generated at build time with Satori and `@resvg/resvg-js`. `src/pages/og.png.ts` is the entry +point, templates are in `src/utils/og-templates/`, and orchestration is in +`src/utils/generateOgImages.ts`. `@resvg/resvg-js` is excluded from Vite's `optimizeDeps` +because it is a native module, which is the sort of thing that looks like a stray config line +until you remove it. + +## Search + +[Pagefind](https://pagefind.app/), which indexes built output rather than source. The build runs +`pagefind --site dist` and copies the result into `public/pagefind/` so `astro preview` can serve +it. Search therefore does not work under `npm run dev`, and a partial build leaves `/search` +broken — which is why the build script is longer than `astro build`. + +## Theming + +Light and dark are CSS variables in `src/styles/global.css`, declared with `@theme inline`: +`--color-accent`, `--color-background`, `--color-foreground`, `--color-border`, `--color-muted`. +The toggle is `public/toggle-theme.js`, plain JavaScript with no framework, so the theme applies +before hydration and the page does not flash. + +## The build pipeline + +``` +npm run build + = fetch-maps-stats # scrape/refresh Google Maps contribution stats + && storybook:build # Storybook -> public/styleguide + && astro check # type-check + && astro build # -> dist/ + && pagefind --site dist # search index + && cp -r dist/pagefind public/ +``` + +Each step leaves something visibly missing if skipped. The Storybook step means a normal build +also publishes the style guide at `/styleguide`. + +## Deployment + +Two targets from the same source: GitHub Pages on push to `main`, and a Docker image (Node build +stage, Nginx serving stage) published to GHCR. [Deployment](./deployment.md) covers both. + +## The Projects page + +`src/pages/projects.astro` is a hand-maintained list of projects with a hardcoded image URL each. +Those URLs point into other repositories' `docs/images/` directories, which are being retired +across the account in favour of `willtheorangeguy/.github/icons/`. Most of them will 404 as that +work lands — see [`internal/known-issues.md`](./internal/known-issues.md), which lists the +replacement URLs. diff --git a/docs/configuration.md b/docs/configuration.md new file mode 100644 index 00000000..8698ba60 --- /dev/null +++ b/docs/configuration.md @@ -0,0 +1,58 @@ +# willtheorangeguy.github.io — Configuration + +Four files decide almost everything. None of them needs environment variables — the site is +static and builds the same way everywhere. + +## `src/config.ts` — site identity and behaviour + +The single source of truth for site metadata. + +| Key | Current | Effect | +|---|---|---| +| `website` | `https://williamvdg.me/` | Canonical URL. Feeds sitemap, RSS, and canonical tags. | +| `author`, `profile` | `willtheorangeguy` | Author name and profile link | +| `title`, `desc` | "To Be Continued" | Site title and description | +| `ogImage` | `hero.jpg` | Fallback social preview image | +| `lightAndDarkMode` | `true` | Whether the theme toggle appears | +| `postPerIndex` | `5` | Posts on the home page | +| `postPerPage` | `10` | Posts per page in listings | +| `scheduledPostMargin` | 15 minutes | Grace window for posts dated slightly in the future | +| `showArchives` | `true` | The archive page | +| `showBackButton` | `true` | Back button on post pages | +| `editPost` | enabled | The "Suggest Changes" link and the branch it edits | +| `dynamicOgImage` | `true` | Generate per-post OG images at build time | +| `lang` | `en` | `html lang` attribute | +| `timezone` | `America/Vancouver` | Default for post dates; a post may override it in frontmatter | + +## `src/constants.ts` — links + +`SOCIALS` is the icon row: GitHub, Instagram, LinkedIn, X, Mastodon, Bluesky, Stack Overflow, +YouTube, Steam, and email. Each entry is a name, an href, a link title for screen readers, and an +imported SVG. Adding one means adding the icon to `src/assets/icons/` and importing it here. + +`SHARE_LINKS` is the per-post share row. `GISCUS` configures the comment system, which is backed +by GitHub Discussions on this repository — the ids there come from the Giscus setup page and are +public by design. + +## `src/content.config.ts` — what a post may contain + +A Zod schema for the `blog` collection. It defines every valid frontmatter field and rejects +anything else at build time, so a typo in a key fails the build rather than being silently +ignored. [Usage](./usage.md) lists the fields. + +## `astro.config.ts` — the build + +Integrations (sitemap, React), Shiki syntax-highlighting themes, and remark plugins. `site` is +read from `SITE.website` rather than duplicated. + +## The custom domain + +`CNAME` contains `williamvdg.me`. It is what makes GitHub Pages serve the site from that domain +rather than `willtheorangeguy.github.io`, and it must stay in the published output — see +[Deployment](./deployment.md). + +## Google Maps stats + +The one piece of data fetched from outside. It is cached into `src/data/google-maps-stats.json` +and `src/utils/googleMapsCache.ts`, refreshed on a schedule, and documented in +[Google Maps automation](./google-maps-automation.md). diff --git a/docs/deployment.md b/docs/deployment.md new file mode 100644 index 00000000..857a0a39 --- /dev/null +++ b/docs/deployment.md @@ -0,0 +1,57 @@ +# willtheorangeguy.github.io — Deployment + +Two targets, same source. + +## GitHub Pages + +`.github/workflows/astro.yml` runs on push to `main`: it detects the package manager from the +lockfile, installs, builds, and uploads `dist/` as the Pages artifact. + +The site is served at **[williamvdg.me](https://williamvdg.me)** rather than at +`willtheorangeguy.github.io`, because `CNAME` at the repository root contains `williamvdg.me` +and is copied into the published output. Deleting it, or dropping it from the artifact, moves +the site back to the github.io domain and breaks every existing link. + +`SITE.website` in `src/config.ts` must agree with that domain — it drives canonical URLs, the +sitemap, and RSS. Changing one without the other produces a site that quietly advertises the +wrong address to search engines. + +## Docker image + +`.github/workflows/docker-image.yml` publishes to +`ghcr.io/willtheorangeguy/willtheorangeguy.github.io:main`. + +The Dockerfile is two stages: `node:lts` installs and runs `npm run build`, then `nginx:alpine` +receives `dist/` plus `nginx/nginx.conf`. + +**The container listens on 8080, not 80.** `nginx/nginx.conf` has `listen 8080` and the +Dockerfile declares `EXPOSE 8080`, so: + +```bash +docker run -d -p 8000:8080 ghcr.io/willtheorangeguy/willtheorangeguy.github.io:main +``` + +The `-p 8000:80` that appeared in the README and older docs maps to a port nothing listens on, +and the container looks broken. Recorded in +[`internal/known-issues.md`](./internal/known-issues.md). + +## Other scheduled workflows + +| Workflow | Trigger | Purpose | +|---|---|---| +| `astro.yml` | push to `main` | Build and deploy to Pages | +| `docker-image.yml` | push to `main` | Build and publish the container | +| `update-google-maps-stats.yml` | daily, plus manual | Refresh contribution stats and commit them | +| `codeql.yml` | push, PR, schedule | Security analysis | +| `gitleaks.yml` | push, PR | Secret scanning | +| `diagram.yml` | scheduled | Regenerates `diagram.svg`, the codebase visualisation | + +The Google Maps workflow commits back to the repository and then triggers a rebuild, so the +site's stats stay current without a manual step. [Google Maps +automation](./google-maps-automation.md) covers its fallbacks. + +## Rolling back + +Pages deploys the artifact from the latest `main`, so a rollback is a revert and a push. The +container is tagged `:main` only, with no version tags, so there is nothing older to pull — +rebuilding from an earlier commit is the only route. diff --git a/docs/development.md b/docs/development.md new file mode 100644 index 00000000..b06d1b78 --- /dev/null +++ b/docs/development.md @@ -0,0 +1,76 @@ +# willtheorangeguy.github.io — Development + +## Commands + +```bash +npm run dev # dev server at http://localhost:4321 +npm run build # full production build (see below) +npm run preview # serve the built output +npm run sync # regenerate Astro content collection types + +npm run lint # ESLint +npm run format:check # Prettier, check only +npm run format # Prettier, write + +npm run fetch-maps-stats # refresh the Google Maps cache +npm run storybook # Storybook at :6006 +npm run storybook:build # Storybook -> public/styleguide +``` + +## The build is not just `astro build` + +``` +fetch-maps-stats && storybook:build && astro check && astro build + && pagefind --site dist && cp -r dist/pagefind public/ +``` + +Skipping the Pagefind steps leaves `/search` broken; skipping the Storybook step leaves +`/styleguide` missing. Run the script rather than its parts. + +## Package managers + +CI installs with pnpm (`pnpm install --frozen-lockfile`); either works locally. Both +`package-lock.json` and `pnpm-lock.yaml` are committed, which means the two can disagree without +anything noticing — pnpm's is the one that decides what ships. See +[`internal/known-issues.md`](./internal/known-issues.md). + +## Conventions + +- **ESLint disallows `console.log`** everywhere except `scripts/`. +- **Prettier**: 2-space indent, 80-column print width, double quotes, LF endings, `es5` trailing + commas. +- **Tailwind class order** is enforced by `prettier-plugin-tailwindcss`, using + `src/styles/global.css` as the stylesheet reference — so `npm run format` reorders classes and + that reordering is not noise. +- **Imports use the `@/` alias** for `src/`. Avoid relative paths that climb out of a directory. +- **Keep React to interactive components.** Three `.tsx` islands exist; everything else is + `.astro` and ships no JavaScript. + +## Storybook + +Stories live in `src/stories/`. `npm run storybook` serves them at `:6006`; the production build +emits them to `public/styleguide`, so the deployed site carries its own style guide. + +## Tests + +There are none. Playwright is a dependency because `scripts/update-maps-cache.mjs` drives a +headless browser, not because anything is tested with it. `astro check` in the build is the only +automated correctness gate, and it is a type check. + +## CI + +`astro.yml` builds and deploys, `codeql.yml` and `gitleaks.yml` scan, `diagram.yml` regenerates +`diagram.svg`, and `update-google-maps-stats.yml` refreshes the stats cache on a schedule. +[Deployment](./deployment.md) has the full table. + +## Working on the Projects page + +`src/pages/projects.astro` is hand-maintained: one block per project, each with a hardcoded +image URL. Those URLs currently point into other repositories' `docs/images/` folders, which are +being retired in favour of `willtheorangeguy/.github/icons/`. If you touch that file, move the +URLs over — [`internal/known-issues.md`](./internal/known-issues.md) lists each replacement. + +## Contributing + +See the org-wide +[Contributing Guide](https://github.com/willtheorangeguy/.github/blob/main/CONTRIBUTING.md). diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 00000000..25f55f47 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,78 @@ +# willtheorangeguy.github.io — FAQ + +## What is this? + +The source of my personal site — a blog and portfolio at +[williamvdg.me](https://williamvdg.me). It is a static Astro site on the AstroPaper theme, +deployed to GitHub Pages. + +## Can I use it as a template? + +The code is MIT-licensed, so yes, but it is my site rather than a theme: the content, the +socials, the projects list, and the Google Maps stats are all mine. +[AstroPaper](https://github.com/satnaing/astro-paper) is the thing to start from if you want +this shape of site. + +## Why does search not work locally? + +Search is Pagefind, which indexes the *built* output. `npm run dev` never produces that index. +Run `npm run build` then `npm run preview`. + +## Why is the build so long? + +It is six steps, not one: fetch Google Maps stats, build Storybook, type-check, build, index for +search, copy the index. Each contributes something visible to the deployed site. +[Development](./development.md) breaks it down. + +## npm or pnpm? + +CI uses pnpm; both work locally. Both lockfiles are committed, which is not ideal — pnpm's is the +one that decides what actually ships. + +## Does the site track me? + +The privacy policy at [`legal/privacy.md`](./legal/privacy.md) is authoritative. Simple Analytics +is credited in the README, and Giscus loads GitHub Discussions on post pages when comments are +shown. + +## Why are there so few React components? + +Three, and only because they need interactivity. Everything else is `.astro`, which ships no +JavaScript at all. Keeping that boundary is why the site is fast. + +## Where do the Google Maps numbers come from? + +A scheduled scrape of my Google Maps contributor profile, cached in the repository and refreshed +daily by a workflow. It falls back to the committed cache when the scrape fails, so the site +never shows an error in place of a number — see +[Google Maps automation](./google-maps-automation.md). + +## What is `/r/`? + +Short links: `/r/gh`, `/r/yt`, and so on, each a small redirect page under `public/r/`. Add one +with `add-redirect.ps1` rather than by hand, so the index stays in step. + +## Why is the site at williamvdg.me and not willtheorangeguy.github.io? + +The `CNAME` file. It has to stay in the published output, and `SITE.website` in `src/config.ts` +has to agree with it. + +## The Docker container does not respond + +Publish port 8080, not 80: `docker run -d -p 8000:8080 ...`. nginx inside the image listens on +8080. The older `-p 8000:80` instruction was wrong. + +## Why do some project images not load? + +They point into other repositories' `docs/images/` folders, which are being retired in favour of +a central icon directory. See [`internal/known-issues.md`](./internal/known-issues.md). + +## Is there a test suite? + +No. `astro check` type-checks during the build, and that is the only automated gate. Playwright +is present for the stats scraper, not for tests. + +## What licence? + +MIT for the code — [`LICENSE.md`](../LICENSE.md). The posts and images are mine. The theme is +AstroPaper, MIT, credited in the README. diff --git a/docs/google-maps-stats.md b/docs/google-maps-stats.md deleted file mode 100644 index e69de29b..00000000 diff --git a/docs/images/logo.png b/docs/images/logo.png deleted file mode 100644 index ae431dd3..00000000 Binary files a/docs/images/logo.png and /dev/null differ diff --git a/docs/images/welcome.jpg b/docs/images/welcome.jpg deleted file mode 100644 index a6a4cf46..00000000 Binary files a/docs/images/welcome.jpg and /dev/null differ diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 00000000..ec020757 --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,67 @@ +# willtheorangeguy.github.io — Installation + +## Prerequisites + +| Requirement | Notes | +|---|---| +| Node 20+ | Astro 7 and the native OG-image module both want a current Node | +| npm or pnpm | CI uses pnpm; either works locally | +| Git | | +| Docker | Only for the container route | + +## From source + +```bash +git clone https://github.com/willtheorangeguy/willtheorangeguy.github.io.git +cd willtheorangeguy.github.io +npm install +npm run dev +``` + +`http://localhost:4321` — http, not https. + +### A note on the two lockfiles + +Both `package-lock.json` and `pnpm-lock.yaml` are committed. CI installs with +`pnpm install --frozen-lockfile`, so pnpm's is the one that governs what is actually built. +Running `npm install` updates the other, and the two can drift apart without anything +complaining. Recorded in [`internal/known-issues.md`](./internal/known-issues.md). + +## Docker + +```bash +docker pull ghcr.io/willtheorangeguy/willtheorangeguy.github.io:main +docker run -d -p 8000:80 ghcr.io/willtheorangeguy/willtheorangeguy.github.io:main +``` + +Then `http://localhost:8000` — port 8000, not plain `localhost`, because the container's port 80 +is published there. + +The image is a multi-stage build: Node builds the site, Nginx serves the result. It contains the +built output only, so nothing in it can be edited usefully — it is for running the site, not for +working on it. + +## Building for production + +```bash +npm run build +npm run preview +``` + +The full pipeline runs the Google Maps fetch, Storybook, a type check, the Astro build, Pagefind +indexing, and a copy of the search index into `public/`. See +[Architecture](./architecture.md) for what each step contributes. + +`npm run build` reaches the network for the Google Maps stats. It falls back to the committed +cache if that fails, so an offline build still works — see +[Google Maps automation](./google-maps-automation.md). + +## Verifying + +```bash +npm run lint +npm run format:check +``` + +There is no test suite. Playwright is installed — the stats scraper uses it — but nothing is +wired up as tests. diff --git a/docs/internal/known-issues.md b/docs/internal/known-issues.md new file mode 100644 index 00000000..1447a864 --- /dev/null +++ b/docs/internal/known-issues.md @@ -0,0 +1,122 @@ +# Known Issues — willtheorangeguy.github.io + +Concrete defects and gaps found while writing this repository's documentation in +August 2026. **Nothing here was changed** — each one needs a code, configuration, or +licensing decision rather than a documentation one. + +Ordered by severity. See [`docs/roadmap.md`](../roadmap.md) for the narrative version, +which also covers deliberate non-goals. + + +**8 open:** 1 high, 3 medium, 4 low. + +## 1. The Projects page points at other repositories' docs/images/, which the docs sweep is deleting + +**Severity:** High +**Where:** `src/pages/projects.astro` + +**What:** The page hardcodes 16 image URLs into other repositories under this account, all of the form `.../{Repo}/{branch}/docs/images/{file}`. The account-wide documentation standardisation moves images to `willtheorangeguy/.github/icons/{Repo}/` and deletes each repository's `docs/images/`. Checked each URL against both the current default branch and the pending `docs/content` branch: + + BROKEN NOW PyWorkout docs/images/logo.png + BREAKS WHEN PR MERGES Apache-File-Directory, Auto-Anouncements, Chrome-File-Directory, + Craft-Clash, incremental-clicker, Maximum-PC-Builds-Archive, + Nginx-File-Directory, ProgramVer, PyAvatar, PyTricks-Archive, + Running-Calculator, wikipicture-web + ok LEGO-Block-Creator, Snoopy-Landing-Page, this repo + +That is one image already 404ing and twelve more that will as the open pull requests merge. Every replacement file already exists under `.github/icons/` -- verified filename by filename. + +**Why it matters:** This is the public portfolio page of a personal site, and it is about to lose three quarters of its images -- not gradually, but as a batch, the moment a set of documentation pull requests is merged. Nothing in either repository connects the two: the sweep deletes a directory, and a hardcoded URL in an unrelated project silently stops resolving. Nobody finds out until they look at the page. + +It is also the clearest argument for the central icon directory existing at all. The URLs reach into other repositories' internal layout, so any reorganisation anywhere breaks this page, and there are three different URL spellings in the file -- `raw.githubusercontent.com/...`, `github.com/.../raw/...`, and `github.com/.../blob/...?raw=true` -- which suggests they were each added by hand at different times. + +**Suggested fix:** Replace every one with `https://raw.githubusercontent.com/willtheorangeguy/.github/main/icons/{Repo}/{file}`. All the files are already there. Do this before merging the remaining sweep pull requests. Longer term, generating the Projects page from the GitHub API would remove the hand-maintained URL list entirely -- see `docs/roadmap.md`. + +## 2. The documented docker run command maps a port nothing listens on + +**Severity:** Medium +**Where:** `README.md` and `docs/USAGE.md` (both corrected in this pass); `nginx/nginx.conf`; `Dockerfile` + +**What:** Both documents gave `docker run -d -p 8000:80 ghcr.io/willtheorangeguy/willtheorangeguy.github.io:main`. `nginx/nginx.conf` line 9 is `listen 8080`, and the Dockerfile declares `EXPOSE 8080`. Port 80 inside the container is closed, so the published mapping reaches nothing. The correct command is `-p 8000:8080`. The README additionally said 'navigate to localhost', which is port 80 on the host and wrong even for a correct mapping. + +**Why it matters:** The container runs, reports healthy, and serves nothing -- the worst shape for a first-run failure, because every signal says the image is fine and the user has no reason to suspect the instruction. Someone trying the published image is most likely evaluating whether the project works at all, and this is what they see. The listen port was presumably changed to 8080 at some point to allow running as a non-root user, and the documentation was not updated with it. + +**Suggested fix:** Corrected in this pass in the README and `docs/usage.md`, and `docs/deployment.md` now states the listen port explicitly. Adding a `HEALTHCHECK` to the Dockerfile against the real port would make the mismatch fail loudly rather than silently. + +## 3. The README logo used a github.com/blob URL, which serves HTML + +**Severity:** Medium +**Where:** `README.md` (corrected in this pass) + +**What:** The logo was `https://github.com/willtheorangeguy/willtheorangeguy.github.io/blob/main/docs/images/logo.png`. A `/blob/` URL returns the GitHub file-viewer page, not the image bytes, so the `` renders as a broken-image glyph. The screenshot below it used a relative path, `./docs/images/welcome.jpg`, which works on GitHub but not when the README is rendered anywhere else. + +**Why it matters:** The logo is the first element of the README, so the repository's front page opened with a broken image. This is the same defect the central `.github/icons/` directory was created to eliminate -- it was found in twelve READMEs during the sweep -- and it had survived here, in the repository belonging to the person doing the sweep. + +**Suggested fix:** Corrected in this pass: both images now use `https://raw.githubusercontent.com/willtheorangeguy/.github/main/icons/willtheorangeguy.github.io/{file}`, and `docs/images/` is removed since the files already exist centrally. + +## 4. Two lockfiles are committed and only one governs CI + +**Severity:** Medium +**Where:** `package-lock.json`, `pnpm-lock.yaml`, `.github/workflows/update-google-maps-stats.yml` + +**What:** Both lockfiles are tracked. The workflows install with `pnpm install --frozen-lockfile`, so `pnpm-lock.yaml` decides what is actually built and deployed. `package.json` scripts, the `Dockerfile` (`RUN npm install`), and `CLAUDE.md` all use npm. `astro.yml` detects the package manager from whichever lockfile it finds. + +**Why it matters:** The two files can resolve the same ranges to different versions and nothing reports it. A developer working locally with npm can test against one dependency tree while Pages deploys another, which is the kind of difference that surfaces as a bug reproducible only in production. The Dockerfile compounds it by running `npm install` rather than a locked install, so the container image is built from a third resolution that matches neither lockfile. + +**Suggested fix:** Pick one. Given CI already uses pnpm, deleting `package-lock.json` and switching the Dockerfile to `pnpm install --frozen-lockfile` is the smaller change. Whichever is chosen, the Dockerfile should do a locked install rather than `npm install`. + +## 5. docs/google-maps-stats.md was a tracked empty file + +**Severity:** Low +**Where:** `docs/google-maps-stats.md` (deleted in this pass) + +**What:** Zero bytes, committed in `8af25c4` ('fix: fix Docker build step'), and never written to since. Nothing generates it: the stats workflow commits `src/utils/googleMapsCache.ts` and `src/data/google-maps-stats.json`, neither of which is this file. Nothing links to it. + +**Why it matters:** An empty file next to `google-maps-automation.md` reads as documentation that failed to generate, so anyone auditing the docs folder has to open it to find out it is nothing. Its name also suggests it holds the stats, which invites someone to wire something up to it. Given it arrived in a commit about the Docker build, it was almost certainly created by accident. + +**Suggested fix:** Deleted in this pass. If a rendered stats page is wanted, it belongs under `src/pages/` where it would be served, not under `docs/`. + +## 6. CLAUDE.md describes a build pipeline and an Astro version that have both moved on + +**Severity:** Low +**Where:** `CLAUDE.md`; `package.json` + +**What:** `CLAUDE.md` gives the build as `fetch-maps-stats && astro check && astro build && pagefind --site dist && cp -r dist/pagefind public/`. The actual script inserts `npm run storybook:build` after `fetch-maps-stats`. It also calls the site 'Astro 6'; `package.json` pins `astro: ^7.1.4`. + +**Why it matters:** `CLAUDE.md` is written to orient an agent that has not read the code, so a wrong build pipeline propagates into work rather than merely misinforming a reader -- an agent told the pipeline has five steps has no reason to preserve a sixth it does not know about, and dropping the Storybook step silently removes `/styleguide` from the deployed site. The version being a major release out has the same character: advice correct for Astro 6 is not necessarily correct for 7. + +**Suggested fix:** Update both lines. Describing the pipeline as 'whatever `npm run build` runs -- do not decompose it' would be more durable than transcribing the steps, since the transcription is what went stale. + +## 7. The privacy policy and terms linked their contact address without a scheme + +**Severity:** Low +**Where:** `docs/legal/privacy.md` and `docs/legal/terms.md` (both corrected and renamed in this pass) + +**What:** Both documents ended with 'By visiting this page on our website: [github.com/willtheorangeguy/willtheorangeguy.github.io](github.com/willtheorangeguy/willtheorangeguy.github.io).' The target has no scheme, so Markdown treats it as a relative path and it resolves to `docs/legal/github.com/...`, which does not exist. Both files were also uppercase, `PRIVACY.md` and `TERMS.md`, against the lowercase convention this sweep applies. + +**Why it matters:** It is the Contact Us section of a privacy policy -- the single link a reader follows to ask what data is held about them or to have it removed -- and it 404s. A legal document that cannot be acted on is worse than a short one, and this is the part regulators and readers both care about. The same schemeless form appears in the terms, so it was copied rather than mistyped once. + +**Suggested fix:** Corrected in this pass: both links now carry `https://`, and the files are renamed to `privacy.md` and `terms.md` with the README updated. Worth grepping the other repositories for `](github.com/` -- a schemeless Markdown link looks right in source and fails only when rendered. + +## 8. PLANNING.md is a three-line stub + +**Severity:** Low +**Where:** `PLANNING.md` + +**What:** A heading and one sentence pointing at the Issues page and at `.../projects?type=classic`. Classic Projects were retired by GitHub, so that link no longer reaches a working board. The identical file exists in `Snoopy-Landing-Page`. + +**Why it matters:** A root-level file implies content and has none, and half of what it does contain is a dead link. Its practical effect is one more row in the repository listing that a reader opens once and learns nothing from. That the same stub appears in more than one repository suggests it was templated rather than written. + +**Suggested fix:** Delete it, here and in `Snoopy-Landing-Page`. GitHub Issues already serves the purpose and is where the file points anyway. + + +--- + +## Also, across every repository + +**`.bandit` is present on disk but untracked in git.** Verified in PyWorkout, treklogger, +skyscanner-cli, booking-cli, piggy, and aibot — the config file exists locally in each but +`git ls-files` does not know about it, so none of it reached GitHub. + +The August 2026 security sweep therefore looks complete locally and landed nowhere. Worth +checking across all 44 repositories it covered. diff --git a/docs/legal/PRIVACY.md b/docs/legal/privacy.md similarity index 98% rename from docs/legal/PRIVACY.md rename to docs/legal/privacy.md index 09898447..cfd4ad7a 100644 --- a/docs/legal/PRIVACY.md +++ b/docs/legal/privacy.md @@ -113,4 +113,4 @@ You are advised to review this Privacy Policy periodically for any changes. Chan If you have any questions about this Privacy Policy, You can contact us: -- By visiting this page on our website: [github.com/willtheorangeguy/willtheorangeguy.github.io](github.com/willtheorangeguy/willtheorangeguy.github.io). +- By visiting this page on our website: [github.com/willtheorangeguy/willtheorangeguy.github.io](https://github.com/willtheorangeguy/willtheorangeguy.github.io). diff --git a/docs/legal/TERMS.md b/docs/legal/terms.md similarity index 98% rename from docs/legal/TERMS.md rename to docs/legal/terms.md index f98c2990..b5d8affc 100644 --- a/docs/legal/TERMS.md +++ b/docs/legal/terms.md @@ -96,4 +96,4 @@ By continuing to access or use Our Service after those revisions become effectiv If you have any questions about these Terms and Conditions, You can contact us: -- By visiting this page on our website: [github.com/willtheorangeguy/willtheorangeguy.github.io](github.com/willtheorangeguy/willtheorangeguy.github.io). +- By visiting this page on our website: [github.com/willtheorangeguy/willtheorangeguy.github.io](https://github.com/willtheorangeguy/willtheorangeguy.github.io). diff --git a/docs/quickstart.md b/docs/quickstart.md new file mode 100644 index 00000000..c83a31a5 --- /dev/null +++ b/docs/quickstart.md @@ -0,0 +1,49 @@ +# willtheorangeguy.github.io — Quickstart + +## Run it + +```bash +git clone https://github.com/willtheorangeguy/willtheorangeguy.github.io.git +cd willtheorangeguy.github.io +npm install +npm run dev +``` + +Open `http://localhost:4321`. Note **http**, not https — the Astro dev server does not use TLS. + +Either npm or pnpm works locally; CI uses pnpm, and both lockfiles are committed. Pick one and +stay with it for a session, or you will churn the other lockfile. + +## Write something + +Posts are Markdown in `src/data/blog/`. The minimum: + +```markdown +--- +title: A title +pubDatetime: 2026-08-19T10:00:00Z +description: One sentence, used for previews and the OG image. +--- + +Body copy. +``` + +Save it and the dev server picks it up. Prefix a filename with `_` to have the loader ignore it, +or set `draft: true`. [Usage](./usage.md) covers the rest of the frontmatter. + +## Build it + +```bash +npm run build +npm run preview +``` + +The build is longer than `astro build` alone: it fetches Google Maps stats, builds Storybook into +`public/styleguide`, type-checks, builds, then runs Pagefind and copies the search index into +`public/`. Skipping any of it leaves something visibly missing — most obviously `/search`, which +needs the Pagefind index. [Development](./development.md) breaks the pipeline down. + +## What success looks like + +The dev server prints a local URL, the home page lists your posts newest first, and `/search` +works after a full `npm run build` (it will not work from `npm run dev` alone, which is expected). diff --git a/docs/roadmap.md b/docs/roadmap.md new file mode 100644 index 00000000..a777eb54 --- /dev/null +++ b/docs/roadmap.md @@ -0,0 +1,52 @@ +# willtheorangeguy.github.io — Roadmap + +Known gaps and direction. Actual defects are in +[`internal/known-issues.md`](./internal/known-issues.md). + +## Where it is + +A working personal site: blog with tags and archives, projects, labs, and uses pages, generated +OG images, client-side search, light and dark themes, a published style guide, short links, and a +scheduled stats scraper. Deployed to Pages on every push and mirrored as a container. + +## Considered + +**Moving the project images to the central icon directory.** The Projects page hardcodes URLs +into other repositories' `docs/images/` folders. That directory is being retired account-wide in +favour of `willtheorangeguy/.github/icons/`, so those images break as the work merges. The +replacements all exist already; this is a find-and-replace, and it is the most urgent item here. + +**Generating the Projects page instead of hand-writing it.** Every entry is a hand-maintained +block with a hardcoded URL, which is why the images could drift out of date without anything +noticing. The GitHub API already knows the repository list, the descriptions, and the topics. + +**One package manager.** Two committed lockfiles can disagree, and only pnpm's governs CI. + +**Pinning the container base images.** `node:lts` and `nginx:alpine` both move. + +**Versioned container tags.** Only `:main` is published, so there is nothing to roll back to. + +**Tests.** `astro check` is the only automated gate and it checks types, not behaviour. +Playwright is already installed for the stats scraper, so a couple of smoke tests — the home page +renders, a post renders, `/search` finds something — would cost little. + +**Retiring `PLANNING.md`.** Three lines pointing at GitHub Issues. + +## Non-goals + +**Becoming a theme.** [AstroPaper](https://github.com/satnaing/astro-paper) is the theme; this is +one person's site built on it. Generalising it would mean maintaining a product. + +**A CMS or a server.** Posts are Markdown in the repository, and the deployed artefact is static +files. That is what makes it cheap to host, fast, and trivially archivable. + +**More React.** Three interactive islands is the budget. The site is fast because almost nothing +hydrates. + +**Self-hosted analytics or comments.** Simple Analytics and Giscus are deliberate: neither needs +a database, and both keep the deployment static. + +## Contributing + +It is a personal site, so feature suggestions are less useful than bug reports. See the org-wide +[Contributing Guide](https://github.com/willtheorangeguy/.github/blob/main/CONTRIBUTING.md). diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md new file mode 100644 index 00000000..a480dd7a --- /dev/null +++ b/docs/troubleshooting.md @@ -0,0 +1,78 @@ +# willtheorangeguy.github.io — Troubleshooting + +## `/search` returns nothing, or 404s + +Pagefind indexes built output. Under `npm run dev` there is no index. Run: + +```bash +npm run build && npm run preview +``` + +If it is still empty after a full build, check that the `cp -r dist/pagefind public/` step ran — +running `astro build` on its own skips it. + +## The Docker container does not respond on localhost:8000 + +Map to 8080, not 80: + +```bash +docker run -d -p 8000:8080 ghcr.io/willtheorangeguy/willtheorangeguy.github.io:main +``` + +`nginx/nginx.conf` has `listen 8080` and the Dockerfile declares `EXPOSE 8080`. The `-p 8000:80` +in the older instructions maps to a port nothing is listening on, so the container looks dead +when it is fine. Recorded in [`internal/known-issues.md`](./internal/known-issues.md). + +## `https://localhost:4321` refuses to connect + +The Astro dev server is plain HTTP. Use `http://localhost:4321`. + +## The build fails in `astro check` + +A type error, most often in frontmatter: `src/content.config.ts` validates every post's +frontmatter with Zod and rejects unknown keys. The message names the file and the field. This is +deliberate — a typo'd `draft` key would otherwise publish a post you meant to hold back. + +## A post does not appear + +Three usual causes: `draft: true`, a filename starting with `_` (which the loader skips), or a +`pubDatetime` more than 15 minutes in the future. + +## The Google Maps numbers are stale or wrong + +The scrape runs daily and falls back to the committed cache when it fails, so stale numbers mean +the scrape has been failing quietly. Run it by hand: + +```bash +npm run fetch-maps-stats +``` + +[Google Maps automation](./google-maps-automation.md) covers the fallback layers. + +## `npm install` keeps changing a lockfile + +Both `package-lock.json` and `pnpm-lock.yaml` are committed, so whichever manager you did not use +looks modified. CI uses pnpm. Pick one for a session and discard the other file's churn rather +than committing both. + +## Project images are broken on `/projects` + +They point into other repositories' `docs/images/` directories, which are being removed in +favour of `willtheorangeguy/.github/icons/`. The replacement URLs are listed in +[`internal/known-issues.md`](./internal/known-issues.md). + +## OG images fail to generate + +`@resvg/resvg-js` is a native module and is deliberately excluded from Vite's `optimizeDeps`. +If it fails to load, reinstall dependencies for your platform — a `node_modules` copied between +operating systems will not work. + +## Prettier reorders my Tailwind classes + +Intended: `prettier-plugin-tailwindcss` enforces class order against `src/styles/global.css`. +Run `npm run format` before committing and the diff stays clean. + +## Still stuck + +[Open an issue](https://github.com/willtheorangeguy/willtheorangeguy.github.io/issues/new/choose) +with the command you ran and the full output. diff --git a/docs/usage.md b/docs/usage.md new file mode 100644 index 00000000..c4f5aea9 --- /dev/null +++ b/docs/usage.md @@ -0,0 +1,79 @@ +# willtheorangeguy.github.io — Usage + +## Writing a post + +Create a Markdown file in `src/data/blog/`. + +```markdown +--- +title: A title +pubDatetime: 2026-08-19T10:00:00Z +description: One sentence, used for previews and the generated OG image. +tags: + - astro +featured: false +draft: false +--- + +Body copy. +``` + +`title`, `pubDatetime`, and `description` are required. The rest are optional: + +| Field | Effect | +|---|---| +| `modDatetime` | Shows an "updated" date | +| `tags` | Tag pages are generated from these | +| `featured` | Pins the post to the featured section | +| `draft` | Excluded from the build | +| `ogImage` | Overrides the generated social preview | +| `canonicalURL` | For posts published elsewhere first | +| `hideEditPost` | Hides the "Suggest Changes" link on that post | +| `timezone` | Overrides the site default for this post's dates | + +The schema in `src/content.config.ts` is strict: an unrecognised frontmatter key fails the build +rather than being ignored. That is deliberate — a silently dropped `draft: true` would publish +something you meant to keep back. + +Two ways to keep a post out of the build: `draft: true`, or a filename starting with `_`, which +the glob loader skips entirely. + +Dates slightly in the future are still published, within the 15-minute +`scheduledPostMargin` in [Configuration](./configuration.md), so a post dated a few minutes ahead +does not vanish because of clock skew. + +## Previewing + +```bash +npm run dev # http://localhost:4321 +``` + +Search does not work in dev. It is powered by Pagefind, which indexes the built output, so +`/search` only works after a full `npm run build` followed by `npm run preview`. + +## Short-link redirects + +`public/r/` holds small redirect pages — `/r/gh`, `/r/yt`, `/r/git`, `/r/fs`, and a few numbered +ones — with an index at `/r/`. Add one with the helper script rather than by hand: + +```powershell +.\add-redirect.ps1 -Slug gh -Description "GitHub Profile" -Destination "https://github.com/willtheorangeguy" +``` + +It creates the subfolder, writes the redirect page, and updates the index, which is three things +to forget if you do it manually. + +## Running a built copy + +```bash +npm run build +npm run preview +``` + +Or the published container: + +```bash +docker run -d -p 8000:80 ghcr.io/willtheorangeguy/willtheorangeguy.github.io:main +``` + +Then `http://localhost:8000`. [Installation](./installation.md) covers both routes in full.