From ba8cad78675911ea8eb20211aaacb6306d9e1c44 Mon Sep 17 00:00:00 2001 From: schmug <38227427+schmug@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:27:56 -0400 Subject: [PATCH] feat: expand About bio with longer-form narrative MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move bio copy, current-focus items, tagline, and social links into a single shared module (src/data/about.ts) and render it identically on both About surfaces — the static /about page and the in-OS AboutApp. Bio expands to four paragraphs covering the studio-of-one framing, Cloudflare-native stack rationale, and CortechOS-as-metaphor note. Closes #11. Co-Authored-By: Claude Opus 4.6 (1M context) --- e2e/smoke.spec.ts | 19 ++++++++++++- src/components/os/apps/AboutApp.tsx | 31 ++++++++------------- src/data/about.test.ts | 33 ++++++++++++++++++++++ src/data/about.ts | 33 ++++++++++++++++++++++ src/pages/about.astro | 43 +++++++++++++++++------------ 5 files changed, 121 insertions(+), 38 deletions(-) create mode 100644 src/data/about.test.ts create mode 100644 src/data/about.ts diff --git a/e2e/smoke.spec.ts b/e2e/smoke.spec.ts index 3986b58..55c82a3 100644 --- a/e2e/smoke.spec.ts +++ b/e2e/smoke.spec.ts @@ -1,4 +1,9 @@ import { test, expect, devices, type ConsoleMessage, type Page } from '@playwright/test'; +import { bio } from '../src/data/about'; + +// Stable, distinctive prefix of the first bio paragraph. Sourcing from the +// shared module keeps this assertion in sync with copy changes. +const BIO_OPENER = bio[0].slice(0, 40); const IFRAME_APPS = [ { id: 'dmarc-mx', name: 'dmarc.mx', url: 'https://dmarc.mx' }, @@ -67,7 +72,9 @@ test.describe('desktop golden path', () => { // About auto-opens on first boot; clicking the icon focuses the singleton. await page.locator('button[aria-label="Open About Cory"]').click(); - await expect(page.locator('section[aria-label="About Cory window"]')).toBeVisible(); + const aboutWindow = page.locator('section[aria-label="About Cory window"]'); + await expect(aboutWindow).toBeVisible(); + await expect(aboutWindow.getByText(BIO_OPENER)).toBeVisible(); await page.screenshot({ path: testInfo.outputPath('2-about-open.png') }); // Brand-mark regression: AboutApp header renders the full mark as an , not an emoji. @@ -100,6 +107,16 @@ test.describe('desktop golden path', () => { }); }); +test.describe('about static page', () => { + test.use({ viewport: { width: 1440, height: 900 } }); + + test('renders shared bio on /about', async ({ page }) => { + await page.goto('/about', { waitUntil: 'domcontentloaded' }); + await expect(page.getByRole('heading', { level: 1, name: 'Cory' })).toBeVisible(); + await expect(page.getByText(BIO_OPENER)).toBeVisible(); + }); +}); + // Strip defaultBrowserType — can't change browser at describe scope, only viewport/UA matter. const { defaultBrowserType: _ignoredBrowser, ...iPhone14 } = devices['iPhone 14']; diff --git a/src/components/os/apps/AboutApp.tsx b/src/components/os/apps/AboutApp.tsx index 566a077..01cf5e8 100644 --- a/src/components/os/apps/AboutApp.tsx +++ b/src/components/os/apps/AboutApp.tsx @@ -1,3 +1,5 @@ +import { bio, currentFocus, socialLinks, tagline } from '../../../data/about'; + export default function AboutApp() { return (
@@ -11,38 +13,29 @@ export default function AboutApp() {
About

Cory

-

- Indie builder · Cloudflare-native · studio-of-one -

+

{tagline}

-

- I make small, well-scoped software that does one job well and ships. Most of it lives on Cloudflare Workers and Pages, written in TypeScript, deployed continuously. -

-

- The constant threads: DNS and email security, RSS and feed discovery, contact utilities, AI / Claude Code tooling, and occasional generative-art experiments that exist mostly to make me smile. -

-

- CortechOS is my attempt at a single memorable home for all of it — every icon on this desktop opens one of the things I've built, running live. -

+ {bio.map((paragraph, index) => ( +

{paragraph}

+ ))}
Current focus
    - - - - + {currentFocus.map(({ badge, title, note }) => ( + + ))}
- - - + {socialLinks.map(({ label, href, value }) => ( + + ))}
); diff --git a/src/data/about.test.ts b/src/data/about.test.ts new file mode 100644 index 0000000..c34e6a9 --- /dev/null +++ b/src/data/about.test.ts @@ -0,0 +1,33 @@ +import { describe, expect, it } from 'vitest'; +import { bio, currentFocus, socialLinks, tagline } from './about'; + +describe('about data', () => { + it('has a non-empty tagline', () => { + expect(tagline.trim().length).toBeGreaterThan(0); + }); + + it('has at least four non-empty bio paragraphs', () => { + expect(bio.length).toBeGreaterThanOrEqual(4); + for (const paragraph of bio) { + expect(paragraph.trim().length).toBeGreaterThan(0); + } + }); + + it('has at least one current-focus item with a badge, title, and note', () => { + expect(currentFocus.length).toBeGreaterThan(0); + for (const item of currentFocus) { + expect(item.badge.trim().length).toBeGreaterThan(0); + expect(item.title.trim().length).toBeGreaterThan(0); + expect(item.note.trim().length).toBeGreaterThan(0); + } + }); + + it('social links all use https and expose a visible value', () => { + expect(socialLinks.length).toBeGreaterThan(0); + for (const link of socialLinks) { + expect(link.href).toMatch(/^https:\/\//); + expect(link.label.trim().length).toBeGreaterThan(0); + expect(link.value.trim().length).toBeGreaterThan(0); + } + }); +}); diff --git a/src/data/about.ts b/src/data/about.ts new file mode 100644 index 0000000..bea5ac5 --- /dev/null +++ b/src/data/about.ts @@ -0,0 +1,33 @@ +export const tagline = 'Indie builder · Cloudflare-native · studio-of-one'; + +export const bio: readonly string[] = [ + "I'm Cory. I build small, well-scoped software and ship it under cortech.online. Most of what I make is one person's worth of work: a DNS tool, an email-auth utility, a QR-code service, a stager for apartment photos. Some of it pays; most of it doesn't. That's fine — the point is that it exists.", + '"Studio of one" is the honest label. No co-founder, no roadmap meetings, no quarterly planning. I pick a problem I actually have, build the smallest thing that solves it, and put it online. If it\'s useful to someone else, even better.', + 'The stack is Cloudflare — Pages, Workers, D1, KV, R2. Not because it\'s trendy, but because one person can run a real product on it without paging themselves at 3 AM. Edge-by-default removes a whole class of infra decisions I\'d rather not be making.', + 'CortechOS, the desktop metaphor you\'re looking at, is a joke that kept going. A portfolio site should reflect the shape of the work. Mine is a pile of small windows that each do one thing. So: here\'s a pile of small windows.', +]; + +export type FocusItem = { + badge: string; + title: string; + note: string; +}; + +export const currentFocus: readonly FocusItem[] = [ + { badge: '🛡️', title: 'dmarc.mx', note: 'DMARC, SPF, DKIM, BIMI, MTA-STS in one scan.' }, + { badge: '📣', title: 'donthype.me', note: 'RSS feed discovery and reading without the hype cycle.' }, + { badge: '📇', title: 'q-r.contact', note: 'Contact QR codes generated locally; no tracking.' }, + { badge: '🧠', title: 'Claude Code tooling', note: 'cclog, claude-view, claudzibit, karkinos — sharper agents.' }, +]; + +export type SocialLink = { + label: string; + href: string; + value: string; +}; + +export const socialLinks: readonly SocialLink[] = [ + { label: 'GitHub', href: 'https://github.com/schmug', value: 'github.com/schmug' }, + { label: 'LinkedIn', href: 'https://www.linkedin.com/in/cory-rankin/', value: 'linkedin.com/in/cory-rankin' }, + { label: 'Sponsor', href: 'https://github.com/sponsors/schmug', value: 'github.com/sponsors/schmug' }, +]; diff --git a/src/pages/about.astro b/src/pages/about.astro index 994e494..1315a98 100644 --- a/src/pages/about.astro +++ b/src/pages/about.astro @@ -1,5 +1,6 @@ --- import Base from '../layouts/Base.astro'; +import { bio, currentFocus, socialLinks, tagline } from '../data/about'; --- @@ -13,30 +14,36 @@ import Base from '../layouts/Base.astro';

About

Cory

+

{tagline}

-

- I'm a builder. I like making small, well-scoped things that do one job well and ship. My work lives mostly on Cloudflare (Workers, Pages) and tends to be TypeScript-first. -

-

- Current focus: DNS and email security (dmarc.mx), contact-card utilities (q-r.contact), AI and Claude Code tooling (cclog, claude-view, claudzibit), and the occasional piece of generative art (AntArt, RepoGotchi). -

-

- This page is about to turn into CortechOS — a tiny branded desktop where every icon is one of those projects, running live in a window. Until then, here's the static version. -

+ {bio.map((paragraph) =>

{paragraph}

)}
-
- -
GitHub
-
github.com/schmug
-
- -
Sponsor
-
github.com/sponsors/schmug
-
+
+
Current focus
+
    + {currentFocus.map(({ badge, title, note }) => ( +
  • + +
    +
    {title}
    +
    {note}
    +
    +
  • + ))} +
+
+ +
+ {socialLinks.map(({ label, href, value }) => ( + +
{label}
+
{value}
+
+ ))}