124 lines
5.3 KiB
Markdown
124 lines
5.3 KiB
Markdown
# Vibn — Marketing Site
|
||
|
||
Production Vite + React 18 + Tailwind CSS implementation of the Vibn marketing
|
||
homepage and beta-invite signup page.
|
||
|
||
## Stack
|
||
|
||
- **Vite 6** — dev server, HMR, multi-page build
|
||
- **React 18** — function components + hooks, no router (two static entries)
|
||
- **Tailwind CSS 3** — utility classes + a small `@layer components` block for
|
||
things that don't compress cleanly to utilities (gradients, pseudo-elements,
|
||
custom shadows)
|
||
- **No CSS-in-JS, no UI library** — design tokens live as CSS custom properties
|
||
so a tweak panel or theme switcher can runtime-swap the accent palette
|
||
- **Geist + Geist Mono** — loaded from Google Fonts in each entry HTML
|
||
|
||
## Getting started
|
||
|
||
```bash
|
||
npm install
|
||
npm run dev # http://localhost:5173 (homepage)
|
||
# http://localhost:5173/beta.html (signup)
|
||
npm run build # production build → dist/
|
||
npm run preview # serve the built bundle
|
||
```
|
||
|
||
## Project layout
|
||
|
||
```
|
||
vibn-app/
|
||
├── index.html ← homepage entry
|
||
├── beta.html ← beta-signup entry
|
||
├── vite.config.js ← multi-page input config
|
||
├── tailwind.config.js ← design tokens + named animations
|
||
├── postcss.config.js
|
||
├── public/
|
||
│ └── logo-black.png ← favicon (V_ mark on black)
|
||
└── src/
|
||
├── main.jsx ← mounts <App />
|
||
├── beta-main.jsx ← mounts <BetaApp />
|
||
├── styles.css ← Tailwind + tokens + keyframes + .btn / .card / .logo-mark
|
||
├── App.jsx ← homepage composition
|
||
├── BetaApp.jsx ← signup-page composition
|
||
├── lib/
|
||
│ └── primitives.jsx ← Logo, LogoMark, Arrow, Eyebrow, Glow, TrustStrip
|
||
└── components/
|
||
├── Nav.jsx
|
||
├── Hero.jsx ← Reddit-quote / promise variants + prompt input
|
||
├── Wall.jsx ← faux chat-window "homework wall" scene
|
||
├── CrossedOut.jsx ← animated strike-through term wall
|
||
├── Journey.jsx ← 4-step path + "where others stop" marker
|
||
├── Audience.jsx ← 3 audience cards w/ Reddit-style quotes
|
||
├── Closing.jsx
|
||
├── Footer.jsx
|
||
├── LaunchModal.jsx ← hero prompt-submit modal
|
||
└── beta/
|
||
├── BetaForm.jsx ← 5-step form
|
||
├── Confirmed.jsx ← submitted state w/ queue card + referral
|
||
└── Benefits.jsx ← "what you get inside" trio
|
||
```
|
||
|
||
## Design tokens
|
||
|
||
All colors are exposed as CSS custom properties (see `src/styles.css`,
|
||
`:root` block) and aliased in `tailwind.config.js → theme.extend.colors`:
|
||
|
||
| Tailwind class | CSS var | Default |
|
||
|---|---|---|
|
||
| `bg-bg` | `--c-bg` | `oklch(0.155 0.008 60)` |
|
||
| `bg-bg-1` | `--c-bg-1` | `oklch(0.185 0.009 60)` |
|
||
| `text-fg` | `--c-fg` | `oklch(0.97 0.005 80)` |
|
||
| `text-fg-dim` | `--c-fg-dim` | `oklch(0.78 0.006 80)` |
|
||
| `text-fg-mute` | `--c-fg-mute` | `oklch(0.58 0.006 80)` |
|
||
| `text-fg-faint` | `--c-fg-faint` | `oklch(0.42 0.006 80)` |
|
||
| `text-accent` | `--c-accent` | `oklch(0.74 0.175 35)` (coral) |
|
||
| `bg-accent` | `--c-accent` | (same) |
|
||
| `border-hairline` | `--c-hairline` | `oklch(0.32 0.010 60 / 0.55)` |
|
||
| `text-ok` | `--c-ok` | `oklch(0.78 0.16 155)` |
|
||
|
||
To re-theme at runtime, set the variables on `:root` from JS:
|
||
|
||
```js
|
||
document.documentElement.style.setProperty("--c-accent", "#9ee649");
|
||
document.documentElement.style.setProperty("--c-accent-glow", "#9ee64959");
|
||
document.documentElement.style.setProperty("--c-accent-fg", "#0f1408");
|
||
```
|
||
|
||
## Type scale
|
||
|
||
Fluid `clamp()` sizes are used inline:
|
||
|
||
- Hero headline: `clamp(44px, 7.4vw, 104px)`
|
||
- Section H2: `clamp(36px, 4.8vw, 64px)`
|
||
- Body / sub: `clamp(16–17px, 1.6–2.2vw, 19–28px)`
|
||
|
||
Geist is the body face; Geist Mono is reserved for tags, eyebrows, code, and
|
||
"trust strip" details.
|
||
|
||
## Animations
|
||
|
||
Keyframes are defined once in `styles.css`; some are also registered as named
|
||
Tailwind utilities (`animate-caret-blink`, `animate-pulse-ok`, etc.) for
|
||
ergonomics. Anything not in the config uses an inline `style={{ animation: ... }}`
|
||
with the keyframe name.
|
||
|
||
## Notes & next steps
|
||
|
||
- **No router.** Homepage links to `/beta.html` directly. Drop in
|
||
`react-router-dom` if you need client-side navigation between more pages.
|
||
- **Form submission is a stub.** `BetaForm` just waits 700 ms and toggles to
|
||
the confirmed state. Wire to your real endpoint (e.g. `fetch("/api/invite", …)`).
|
||
- **Queue position is deterministic on email.** Replace with the real one from
|
||
your backend.
|
||
- **The hero "Live from minute one" pill is currently not rendered** in this
|
||
port (the marketing prototype defaults it off). Re-add by uncommenting the
|
||
pill in `Hero.jsx` if you want it back.
|
||
- **The Tweaks panel from the prototype is not ported.** Tweaks are a design-time
|
||
tool; runtime theming is enough via the CSS-var token system.
|
||
|
||
## Browser support
|
||
|
||
Uses `oklch()`, `text-wrap: balance`, and `backdrop-filter`. Safari 15.4+,
|
||
Chrome 111+, Firefox 113+.
|