We don't always have the answers, but we'll always have the Poets. Select a subject and receive a poem or excerpt paired with a cocktail or non-alcoholic beverage.
Functional architecture, app styling, content compilation, and editor's notes by Jojo Nickolin. App structure and JavaScript logic built with Claude (Anthropic).
git s
gin-and-phonics/
├── public/ # Static assets
│ ├── favicon.svg
│ ├── transparent-logo.png
│ └── fonts/ # Self-hosted fonts
│ ├── biroscript-regularus-webfont.woff
│ └── biroscript-regularus-webfont.woff2
├── src/
│ ├── assets/
│ │ └── images/ # Bundled images (Vite fingerprints these)
│ │ ├── brown-arrow-icon.png
│ │ ├── lp-bookstore.JPG
│ │ ├── lp-bookstore-m.JPG
│ │ └── lp-ex-libris.png
│ ├── components/ # Presentation layer
│ │ ├── Citation.jsx # Source attribution for passages
│ │ ├── ContentSection.jsx # Two-column passage + recipe layout
│ │ ├── EditorNote.jsx # Editor's annotation for a passage
│ │ ├── EmptyState.jsx # Initial state before selection
│ │ ├── Footer.jsx # Site footer
│ │ ├── Header.jsx # Masthead / site title
│ │ ├── LandingPage.jsx # Full-screen welcome screen with CTA
│ │ ├── PassageDisplay.jsx # Renders a single passage with citation
│ │ ├── RecipeCard.jsx # Renders a recipe with source
│ │ └── TagSelector.jsx # Dropdown to pick a subject
│ ├── data/ # Data layer (pure JS, no framework deps)
│ │ ├── constants.js # Tag display labels
│ │ ├── passages.js # All passages keyed by theme
│ │ └── recipes.js # Cocktail/beverage recipes keyed by tag
│ ├── hooks/ # Functionality layer (React logic)
│ │ └── usePassageSelection.js # State + actions for tag/passage/recipe
│ ├── styles/ # Per-component CSS (BEM naming, CSS custom properties)
│ │ ├── Citation.css
│ │ ├── ContentSection.css
│ │ ├── EditorNote.css
│ │ ├── global.css # Resets, custom properties, font declarations
│ │ ├── Header.css
│ │ ├── LandingPage.css
│ │ ├── Layout.css
│ │ ├── PassageDisplay.css
│ │ ├── RecipeCard.css
│ │ └── TagSelector.css
│ ├── utils/ # Pure functions (no React)
│ │ └── passages.js # Tag extraction, random passage, recipe lookup
│ ├── App.jsx # Root component
│ └── main.jsx # ReactDOM entry point
├── CHANGELOG.md
├── index.html # Vite HTML entry
├── netlify.toml # Netlify SPA redirect config
├── package.json
└── vite.config.js
| Layer | Directory | Responsibility |
|---|---|---|
| Data | src/data/ |
Raw content — passages, recipes, constants. No framework imports. |
| Utils | src/utils/ |
Pure functions that query/transform data. No React. |
| Hooks | src/hooks/ |
React state management and side effects. |
| Components | src/components/ |
Presentational React components. Each imports only its own CSS. |
| Styles | src/styles/ |
One CSS file per component, plus global.css for variables & resets. |
npm install
npm run dev # Local dev server at http://localhost:5173
npm run build # Production build → dist/
npm run preview # Preview the production build locally- Push this repo to GitHub/GitLab/Bitbucket
- In Netlify → "Add new site" → "Import an existing project"
- Settings:
- Build command:
npm run build - Publish directory:
dist
- Build command:
- Deploy
Or drag-and-drop the dist/ folder at app.netlify.com/drop.
Fonts are declared via @font-face in src/styles/global.css:
- EB Garamond — passages, titles, decorative headings (Fontsource CDN)
- JetBrains Mono — UI elements, tags, labels (Fontsource CDN)
- biroscript-regularus — decorative handwritten accents (local
/fonts/)
- Background: cream (
#FEFAE6) - Text: ink (
#000000) - Primary UI color: card-blue (
#5080B4) — labels, borders, buttons - Handwritten accents: pen-brown (
#6f1a07) - Responsive: single-column below 680px