Skip to content
View odiwr's full-sized avatar
โœ๏ธ
Cooking up.
โœ๏ธ
Cooking up.

Block or report odiwr

Block user

Prevent this user from interacting with your repositories and sending you notifications. Learn more about blocking users.

You must be logged in to block users.

Content in all repositories owned by your account will be closed.
Maximum 250 characters. Please donโ€™t include any personal information such as legal names or email addresses. Markdown is supported. This note will only be visible to you.
Report abuse

Contact GitHub support about this userโ€™s behavior. Learn more about reporting abuse.

Report abuse
odiwr/README.md

odiwr.com

Personal site, plus a dashboard that edits it.

Hosts

Host Serves
odiwr.com the landing page, work write-ups at /[slug], /dashboard
projects.odiwr.com the projects listing
creative.odiwr.com the creative mosaic

Both subdomains are this same app: src/proxy.ts rewrites their root onto /projects and /creative, and gives each host its own robots.txt and sitemap.xml. DNS has to point them here.

Content

Everything editable lives in one JSON document in R2 (site/content.json), read through src/lib/content.ts. There is no database. The dashboard writes it; the site reads it through a short cache that a save clears.

Until a section has real entries it shows filler from src/lib/filler.ts, which disappears on its own once the first entry is published.

Dashboard

/dashboard, behind Google sign-in restricted to ADMIN_EMAILS. Analytics reads GA4 through a service account; Work, Blog and Media edit the document and the bucket.

Environment

Copy into .env.local โ€” it is gitignored, and none of it belongs in the repo.

NEXT_PUBLIC_SITE_URL           # optional; defaults to https://odiwr.com
SESSION_SECRET                 # signs the dashboard cookie (PAYLOAD_SECRET also accepted)
ADMIN_EMAILS                   # comma separated allow-list
GOOGLE_CLIENT_ID               # OAuth client for the dashboard sign-in
GOOGLE_CLIENT_SECRET
GOOGLE_SITE_VERIFICATION       # optional; Search Console meta tag
GA_PROPERTY_ID                 # GA4 numeric property id
GOOGLE_SERVICE_ACCOUNT_EMAIL   # read-only access to that property
GOOGLE_SERVICE_ACCOUNT_KEY
R2_ENDPOINT                    # the content document and all uploads
R2_BUCKET
R2_ACCESS_KEY_ID
R2_SECRET_ACCESS_KEY
R2_PUBLIC_URL                  # public origin, e.g. https://media.odiwr.com

The OAuth client needs <origin>/dashboard/auth/callback registered as a redirect URI, for production and for localhost.

Generated files

Each writes a module that is committed; re-run after changing its inputs.

Command Writes
npm run icons every favicon size from public/brand/catguy.svg
npm run icons:data inline SVG for the icons found in src/
npm run stacks the searchable tech-stack index
npm run fonts:subset the CJK and @ font subsets, and their unicode-ranges

Bucket layout

npm run r2:plan prints a reorganisation plan; npm run r2:apply performs it. Moves are copy-then-delete and cannot be undone, and assets are shared with the old site โ€” read the header of scripts/reorganize-r2.mjs first.

Pinned Loading

  1. sokko sokko Public

    Official Sokkoโ„ข Website

    HTML

  2. ume-bot ume-bot Public

    JavaScript

  3. BestTime BestTime Public

    An embeddable timeline web component that reads a Google Sheet. Zero dependencies, works in any framework.

    TypeScript 1