Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Notes

[![Version](https://img.shields.io/badge/version-5.31.0-blue.svg)](https://github.com/antoniwan/notes/releases)
[![Version](https://img.shields.io/badge/version-6.0.0-blue.svg)](https://github.com/antoniwan/notes/releases)

Personal writing site: essays and notes on fatherhood, masculinity, culture, and day-to-day life. Some posts are in English, some in Spanish, with links between translations where it applies.

Expand All @@ -24,7 +24,6 @@ Live site: [notes.antoniwan.online](https://notes.antoniwan.online)
- **Table of contents on long posts** — floating contents control with section links and a jump to the top
- **RSS** (`/rss.xml`) and **JSON Feed** (`/feed.json`)
- **Random quotes API** — `GET /api/quotes` (Stoic excerpts, other philosophy, lines from posts; optional `?kind=`)
- **Public API** page at `/api/` — lists endpoints in plain language
- **Schema.org JSON-LD** where it fits the page type
- **Comments** — optional [Remark42](https://remark42.com/) embed when you set env vars (see `docs/comments-setup.md`)
- **Service worker** — registered for caching; the registration URL includes the **package version** from `package.json` so a version bump can nudge browsers to pick up updates
Expand Down
31 changes: 30 additions & 1 deletion astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,35 @@ import { remarkReadingTime } from './remark-reading-time.mjs';
import { buildSeoRedirects, shouldIncludeInSitemap } from './src/utils/seoRouting';
import { getSitemapTranslationLinksByUrl } from './src/utils/sitemapTranslations';

/** Vite connect middleware: `/path/` → `/path` before Astro trailingSlash 404. */
function trailingSlashDevRedirectPlugin() {
return {
name: 'trailing-slash-dev-redirect',
configureServer(server) {
const handler = (req, res, next) => {
const raw = req.url ?? '/';
const qIndex = raw.indexOf('?');
const pathname = qIndex === -1 ? raw : raw.slice(0, qIndex);
const search = qIndex === -1 ? '' : raw.slice(qIndex);

if (pathname.length > 1 && pathname.endsWith('/')) {
res.statusCode = 301;
res.setHeader('Location', `${pathname.replace(/\/+$/, '') || '/'}${search}`);
res.end();
return;
}

next();
};

// Post hook: run after Vite/Astro install their middlewares, then jump to front.
return () => {
server.middlewares.stack.unshift({ route: '', handle: handler });
};
},
};
}

// https://astro.build/config
export default defineConfig({
site: SITE_URL,
Expand Down Expand Up @@ -102,7 +131,7 @@ export default defineConfig({
},
// Vite optimizations for better performance
vite: {
plugins: [tailwindcss()],
plugins: [trailingSlashDevRedirectPlugin(), tailwindcss()],
server: {
watch: {
// Polling can break HMR on macOS; use native events for hot-reload
Expand Down
6 changes: 3 additions & 3 deletions docs/TECHNICAL-AUDIT.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Notes — Technical Audit

**Audit date:** 2026-07-28
**App version:** 5.30.1 (service-worker API cache fix + audit hygiene)
**App version:** 6.0.0 (visual UI overhaul — monochrome + marigold/violet accents)
**Production:** [notes.antoniwan.online](https://notes.antoniwan.online) · Vercel project `notes` (`prj_MrjdKV4wL7ubFNGKhVBASHub9rmb`)
**Companion product map:** [roadmap.md](./roadmap.md) (§7 product audit, §8 technical roadmap)

Expand Down Expand Up @@ -48,7 +48,7 @@ A **hybrid Astro site**: almost everything is statically prerendered at build ti
── ReadingProgress / ReadState / Footer / SW
┌─────┴──────┬────────────┬─────────────┬──────────────┐
PageLayout BlogLayout BrainScience* Feeds/API docs
PageLayout BlogLayout BrainScience* Feeds
│ │
Content Posts (MD/MDX) ← content.config.ts schema
collections publishFilters · translationUtils · tagVocabulary
Expand Down Expand Up @@ -76,7 +76,7 @@ A **hybrid Astro site**: almost everything is statically prerendered at build ti
| Author tools | `/brain-science/*`, `/tag-management` | `noindex` + sitemap-excluded |
| Library | `/library`, `/library/books` | Static data in `src/data/library.ts` |
| Syndication | `/rss.xml`, `/feed.json`, `@astrojs/sitemap` | Feed eligibility ≠ listing eligibility |
| API | `/api/`, `/api/quotes` | Quotes is SSR; index is static docs |
| API | `/api/quotes` | SSR JSON quotes endpoint |
| System | `/404`, `/sitemap.xml` → 301 to sitemap-index | |

Redirects live in two places: Astro `buildSeoRedirects()` (`src/utils/seoRouting.ts`) and `vercel.json` (legacy hosts + Remark42 rewrite). Prefer adding post/tag redirects in `seoRouting.ts` going forward. Remark42 upstream: set `REMARK42_UPSTREAM_ORIGIN` and run `pnpm run sync-remark42-rewrite` (see `docs/comments-setup.md`).
Expand Down
4 changes: 3 additions & 1 deletion docs/multilingual-setup.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ The current language is automatically hidden from the toggle.
- Discoverable via language toggle when `translationGroup` is set
- Excluded from RSS/JSON feeds, `/everything`, category/tag indexes, Guided Path, and search (via `isListingEligiblePost` / `isFeedEligiblePost`)

Spanish-only orphans without an English pair stay indexable with correct `lang="es"` metadata; add a `translationGroup` only when a real pair exists. If a Spanish post should appear in listings/feeds, set `featured: true`.
**Guided Path** always excludes Spanish posts (`language: ["es"]`), even if `featured: true`. Read Spanish via the language toggle on the English note.

Spanish-only orphans without an English pair stay indexable with correct `lang="es"` metadata; add a `translationGroup` only when a real pair exists. If a Spanish post should appear in category/tag/feed listings, set `featured: true` (Guided Path still omits it).

## Technical Implementation

Expand Down
4 changes: 1 addition & 3 deletions docs/quotes-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,4 @@ if (quote.sourceUrl) {
console.log(metadata.countsByKind);
```

## Human-readable docs

The `/api/` page on the live site summarizes the same behavior and includes a small tester UI.
See also `src/pages/api/quotes.ts` and `src/data/quotes.ts`.
2 changes: 1 addition & 1 deletion docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ This section is a **checkpoint** so the roadmap does not read like the site is o
- **Home**: **highlight** masonry for posts marked `featured` or `highlight` in frontmatter.
- **Brain Science**: multi-page **stats and charts** (cadence, topics, sentiment, etc.).
- **Library**: dedicated **books** pages (see §4).
- **Feeds & APIs**: **RSS**, **JSON Feed**, **GET `/api/quotes`**, human-readable **`/api/`** overview.
- **Feeds & APIs**: **RSS**, **JSON Feed**, **GET `/api/quotes`**.
- **Quality & distribution**: **Schema.org** where it fits, optional **Remark42** comments, **service worker** for caching (version bumped on build), **Vercel Web Analytics** and **Speed Insights** in the base layout when those products are enabled on Vercel.
- **About**: curated topic grid; optional **Letterboxd “latest watched”** when `LETTERBOXD_*` env vars are set.

Expand Down
33 changes: 33 additions & 0 deletions measure-bs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({ headless: true });
const page = await browser.newPage({ viewport: { width: 1280, height: 900 } });
await page.goto('http://localhost:4321/brain-science/insights', { waitUntil: 'networkidle', timeout: 90000 });
await page.waitForTimeout(1500);
const info = await page.evaluate(() => {
const p = document.querySelector('#vuln-bar > p');
if (!p) return { err: 'no p' };
const cs = getComputedStyle(p);
const rect = p.getBoundingClientRect();
const parent = p.parentElement;
const pcs = parent ? getComputedStyle(parent) : null;
return {
text: p.textContent.slice(0, 80),
width: rect.width,
height: rect.height,
display: cs.display,
maxWidth: cs.maxWidth,
widthCss: cs.width,
float: cs.float,
writingMode: cs.writingMode,
whiteSpace: cs.whiteSpace,
wordBreak: cs.wordBreak,
parentDisplay: pcs?.display,
parentWidth: parent?.getBoundingClientRect().width,
parentClass: parent?.className,
canvasWidths: [...document.querySelectorAll('canvas')].slice(0,3).map(c => ({id:c.id, w:c.width, cw:c.clientWidth, style:c.getAttribute('style')})),
};
});
console.log(JSON.stringify(info, null, 2));
await browser.close();
})();
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "notes blog",
"type": "module",
"version": "5.31.0",
"version": "6.0.0",
"repository": {
"type": "git",
"url": "https://github.com/antoniwan/notes.git"
Expand Down Expand Up @@ -58,6 +58,7 @@
"@typescript-eslint/parser": "^8.59.2",
"eslint": "^10.3.0",
"eslint-plugin-astro": "^1.7.0",
"playwright": "1.55.0",
"prettier": "^3.8.3",
"prettier-plugin-astro": "^0.14.1",
"prettier-plugin-tailwindcss": "^0.8.0",
Expand Down
29 changes: 29 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion specs/004-ui-ux-refinement/data-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,5 @@ This feature does not add runtime-persisted entities. The model below defines de
- `library books` -> `/library/books` (`src/pages/library/books.astro`)
- `tag management` -> `/tag-management` (`src/pages/tag-management.astro`)
- `brain science landing` -> `/brain-science` (`src/pages/brain-science/index.astro`)
- `api docs` -> `/api` (`src/pages/api/index.astro`)
- `api quotes` -> `/api/quotes` (`src/pages/api/quotes.ts`)
- `not found` -> `/404` (`src/pages/404.astro`)
2 changes: 1 addition & 1 deletion specs/004-ui-ux-refinement/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

- `/`, `/about`, `/p/[...slug]`, `/everything`, `/category`, `/category/[category]`
- `/tag`, `/tag/[tag]`, `/guided-path`, `/library`, `/library/books`
- `/tag-management`, `/brain-science`, `/api`, `/404`
- `/tag-management`, `/brain-science`, `/404`

### Baseline capture notes

Expand Down
2 changes: 1 addition & 1 deletion src/components/BackToTop.astro
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const { class: className = '' } = Astro.props;
<button
type="button"
class:list={[
'group invisible fixed right-8 bottom-8 z-50 inline-flex translate-y-4 items-center justify-center rounded-full bg-[rgb(var(--color-primary))] p-3 text-white opacity-0 shadow-lg transition-all duration-300 hover:bg-[rgb(var(--color-primary-hover))]',
'group invisible fixed right-8 bottom-8 z-50 inline-flex translate-y-4 items-center justify-center rounded-full bg-[rgb(var(--color-primary))] p-3 text-[rgb(var(--color-on-primary))] opacity-0 shadow-lg transition-all duration-300 hover:bg-[rgb(var(--color-primary-hover))]',
'border border-white/20',
className,
]}
Expand Down
6 changes: 3 additions & 3 deletions src/components/BaseHead.astro
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,8 @@ const updatedDateISO = updatedDate?.toISOString();
{!heroImage && <link rel="preload" href="/images/default.avif" as="image" />}

<!-- Theme & Color -->
<meta name="theme-color" content="#3b82f6" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#0f172a" media="(prefers-color-scheme: dark)" />
<meta name="theme-color" content="#ffffff" media="(prefers-color-scheme: light)" />
<meta name="theme-color" content="#0a0a0a" media="(prefers-color-scheme: dark)" />
<meta name="color-scheme" content="light dark" />

<!-- Astro 6 Fonts API -->
Expand Down Expand Up @@ -112,7 +112,7 @@ const updatedDateISO = updatedDate?.toISOString();
// Update meta theme-color
const metaThemeColor = document.querySelector('meta[name="theme-color"]');
if (metaThemeColor) {
metaThemeColor.setAttribute('content', theme === 'dark' ? '#0f172a' : '#ffffff');
metaThemeColor.setAttribute('content', theme === 'dark' ? '#0a0a0a' : '#ffffff');
}
} catch (error) {
// Fallback to system preference if localStorage fails
Expand Down
Loading
Loading