docs: rewrite README for the Earth Walker site

Replaces the boilerplate's generic stack-and-versioning notes with
project-specific deployment guidance: routes, env vars, the
inquiry-delivery flow (so future maintainers understand the Nostr
plumbing isn't optional), image discipline (the anonymity rule plus
the imagemagick incantation that normalizes new assets), and the
add-a-project recipe.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Padreug 2026-05-27 11:26:18 +02:00
commit d9f52c6e7b

148
README.md
View file

@ -1,74 +1,122 @@
# boilerplate-website # Earth Walker Design
Opinionated Vue 3 starter — the base every new aiolabs website forks from. Studio site for an interior designer. Vue 3 + Vite + shadcn-vue +
Tailwind 4. Anonymous-by-default contact: inquiry submissions are
encrypted in the visitor's browser and delivered to the designer's
Nostr inbox.
## Stack ## Routes
- **Vue 3.5** + **Vite 8** + **TypeScript 6** | Path | Purpose |
- **shadcn-vue** (via `reka-ui` + `class-variance-authority` + `tailwind-merge`) — components.json pre-wired, run `pnpm dlx shadcn-vue@latest add <name>` to copy components in |---|---|
- **Tailwind CSS 4** (via `@tailwindcss/vite` — no `tailwind.config.js`) | `/` | Hero, studio voice, two project teasers, inquiry CTA |
- **Pinia 3** — sample `useCounterStore` in `src/stores/` | `/portfolio` | Two-up project grid (Boulder, Asheville) |
- **Vue Router 5** — file in `src/router/index.ts`, lazy-loaded views in `src/views/` | `/portfolio/boulder` | Boulder project detail — editorial image scroll + lightbox |
- **Vue I18n 11**`src/i18n/locales/{en,es}.json` | `/portfolio/asheville` | Asheville project detail |
- **vee-validate 4** + **zod 3** — form validation primitives (zod pinned to ^3 until `@vee-validate/zod` ships a v4-compatible resolver) | `/contact` | Inquiry form (Nostr-delivered) |
- **@lucide/vue** — icon set (`lucide-vue-next` is deprecated upstream)
- **ESLint 10** (flat config) + **Prettier 3**
## Quick start ## Local dev
```sh ```sh
pnpm install pnpm install
pnpm dev # vite dev server cp .env.example .env # fill in VITE_OWNER_NPUB
pnpm build # type-check + production build pnpm dev # http://localhost:5173
pnpm preview # serve dist/ pnpm build # type-check + production build to dist/
pnpm preview # serve dist/
pnpm lint pnpm lint
pnpm format pnpm format
``` ```
## Layout The contact form requires `VITE_OWNER_NPUB` to be set — without it,
`submitInquiry` throws so visitors see an explicit error rather
than silently dropping submissions. Generate one with
[`nak key generate`](https://github.com/fiatjaf/nak) or any Nostr client.
``` ## Env vars
src/
├─ App.vue # router-view shell
├─ main.ts # plugin wiring
├─ style.css # tailwind + shadcn-vue CSS variables
├─ lib/utils.ts # cn() — shadcn-vue's class merger
├─ router/index.ts
├─ stores/counter.ts # example pinia store
├─ i18n/
│ ├─ index.ts
│ └─ locales/{en,es}.json
├─ views/HomeView.vue # proof-of-wiring page (i18n + pinia + tailwind)
└─ features/
├─ nostr/README.md # opt-in: nostr-tools wiring (see file)
└─ lnbits/README.md # opt-in: LNbits payments wiring (see file)
```
## Optional features | Var | Required | Default | Notes |
|---|---|---|---|
| `VITE_OWNER_NPUB` | yes | — | The designer's Nostr public key (`npub1…`). Inquiries are NIP-17 gift-wrapped to this key. |
| `VITE_NOSTR_RELAYS` | no | `wss://relay.damus.io,wss://nos.lol,wss://relay.nostr.band` | Comma-separated wss:// list. Submission succeeds if any one relay accepts. |
Both nostr and LNbits live as **documentation-only** folders. The deps Both are inlined at build time by Vite. Rotating either requires a
aren't installed by default — bundle stays small for sites that don't rebuild + redeploy.
need them. Each folder's README walks you through enabling.
- **`src/features/nostr/`** — connect to relays, sign/publish events, contact forms that DM the site owner's npub ## How the contact form delivers inquiries
- **`src/features/lnbits/`** — create invoices, accept Lightning payments via an LNbits instance
## Versioning strategy 1. Visitor fills the form (name optional, contact method + value,
message). Validation runs client-side via `vee-validate` + `zod`.
2. `submitInquiry()` (`src/features/nostr/submitInquiry.ts`):
- generates a fresh ephemeral secp256k1 keypair
- decodes `VITE_OWNER_NPUB` to hex
- calls `nip17.wrapEvent()` to produce a kind:1059 gift-wrap with
NIP-44 v2 encryption inside (the visitor's identity is the
throwaway key, not anything they entered)
- publishes via `SimplePool` to the configured relays in parallel
3. The designer receives the inquiry as a DM in any NIP-17 capable
Nostr client (Damus, Amethyst, 0xchat, etc.) signed in with the
matching nsec.
The boilerplate's `main` branch is **the "tools wired, no content" baseline**. New site = clone (or fork on Forgejo) → start adding content immediately. No server in between stores the message. There is no inbox to leak.
To pull dep refreshes from the boilerplate into an existing site: ## Theming
Light + dark stone-warm palettes live in `src/style.css` as OKLCH
CSS variables. Toggle persists to `localStorage` under
`ewd:theme` (see `src/composables/useTheme.ts`). Typography pairs
Fraunces (display, h1h3, brand wordmark) with Inter (UI/body) via
Bunny Fonts, declared in `index.html` and bound through Tailwind 4
`@theme` directives.
To recolor: edit the OKLCH triples in `src/style.css` under `:root`
and `.dark`. Keep all shadcn-vue token names intact.
## Image discipline
All images live under `public/images/<project>/`. The build pipeline
expects:
- Filenames are sequence-numbered (`01.jpg`, `02.jpg`, …) — never
leak addresses, neighborhood names, or owner identities in the
filename.
- EXIF / GPS / timestamp / maker metadata is stripped before commit.
Re-run on new assets:
```sh
nix-shell -p imagemagick --run \
'for f in *.jpg; do magick "$f" -auto-orient -strip -resize "2400x2400>" \
-interlace Plane -sampling-factor 4:2:0 -quality 82 "${f}.tmp" \
&& mv "${f}.tmp" "$f"; done'
```
- Alt text in `src/data/projects.ts` describes the room/feature, not
the location.
## Adding a project
1. Drop sequence-numbered images into `public/images/<slug>/`.
2. Add a new `Project` entry in `src/data/projects.ts` (typed) with
`slug`, `name`, `eyebrow`, `intro`, `cover`, `coverAlt`, and an
`images[]` array. Each image takes a `feature` tag
(`hero` | `wide` | `narrow` | `paired`) that drives the layout
slot in `ProjectDetail.vue`'s editorial scroll.
3. Add a 4-line view at `src/views/projects/<Slug>View.vue`:
```vue
<script setup lang="ts">
import ProjectDetail from '@/components/projects/ProjectDetail.vue'
import { mySlug } from '@/data/projects'
</script>
<template><ProjectDetail :project="mySlug" /></template>
```
4. Register the route in `src/router/index.ts`.
5. The `PortfolioView` already iterates `projects[]`, so the new
project's card appears automatically.
## Stack
Tracking the upstream boilerplate (`aiolabs/boilerplate-website`).
To pull dependency refreshes:
```sh ```sh
git remote add boilerplate forgejo@git.atitlan.io:aiolabs/boilerplate-website.git git remote add boilerplate forgejo@git.atitlan.io:aiolabs/boilerplate-website.git
git fetch boilerplate git fetch boilerplate
git merge boilerplate/main git merge boilerplate/main
``` ```
When a site diverges enough to no longer benefit from these merges, drop the remote — it becomes its own thing.
## Keeping deps current
- The boilerplate gets dep bumps via PRs (Renovate / Dependabot configurable; otherwise periodic `pnpm update --latest` + manual review).
- The Vue ecosystem (vue, pinia, router, i18n, vee-validate) versions in lockstep — when one majors, the others usually follow within weeks.
- Tailwind 4 + shadcn-vue + reka-ui is the current modern combo. shadcn-vue uses tw-animate-css (not the deprecated tailwindcss-animate plugin).