Compare commits
2 Commits
main
...
c38123b595
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c38123b595 | ||
|
|
e88a3dfd52 |
@@ -11,11 +11,6 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "22"
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
|
||||
36
CLAUDE.md
@@ -1,13 +1,8 @@
|
||||
# CLAUDE.md
|
||||
|
||||
## Important Rules
|
||||
|
||||
- **Always update `CLAUDE.md` and `README.md`** when making changes that affect project structure, commands, deployment, tooling, or conventions. Keep them in sync.
|
||||
- Do not include co-author lines or "Generated by" attributions in commit messages.
|
||||
|
||||
## Project Overview
|
||||
|
||||
The Lofty Project is a 501(c)(4) connecting creative talent with leftist organizing. This repo is the **pre-launch landing page** — a single-page static site with interest signup links.
|
||||
Lofty is a 501(c)(4) social welfare organization connecting creative professionals with the progressive movement. This repo is the **pre-launch landing page** — a single-page static site to collect email signups.
|
||||
|
||||
**Stack:** Astro 5 (static output), TypeScript, Bun 1.3+
|
||||
|
||||
@@ -16,13 +11,10 @@ The Lofty Project is a 501(c)(4) connecting creative talent with leftist organiz
|
||||
```
|
||||
src/
|
||||
layouts/Layout.astro # HTML shell, meta tags, Typekit fonts, design tokens, CSS reset
|
||||
pages/index.astro # All page sections (hero, pillars, signup, footer), scoped CSS, client JS
|
||||
pages/index.astro # All page sections (hero, pillars, signup form, footer), scoped CSS, client JS
|
||||
public/
|
||||
favicon.svg # Stylized "L" mark
|
||||
hero-bg.webp/.jpg # Hero background image (WebP + JPEG fallback)
|
||||
astro.config.mjs # Static output, site URL, dev toolbar disabled
|
||||
wrangler.toml # Cloudflare Pages deployment config
|
||||
.gitea/workflows/ # CI/CD via Gitea Actions
|
||||
```
|
||||
|
||||
Two-file architecture: `Layout.astro` (global concerns) + `index.astro` (all content). No component files — single page with no reuse opportunity.
|
||||
@@ -35,16 +27,6 @@ bun run build # Static build to dist/
|
||||
bun run preview # Preview production build
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
Deploys to **Cloudflare Pages** via Gitea Actions on push to `main`.
|
||||
|
||||
```bash
|
||||
bun run deploy # Build + deploy to Cloudflare Pages (manual)
|
||||
```
|
||||
|
||||
Config lives in `wrangler.toml`. CI requires `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` as Gitea secrets.
|
||||
|
||||
## Linting & Formatting
|
||||
|
||||
Uses **Biome** for both linting and formatting.
|
||||
@@ -71,6 +53,8 @@ Format: `type(scope): subject`
|
||||
bun run commit # Guided commit via commitizen (cz-git)
|
||||
```
|
||||
|
||||
Do not include co-author lines or "Generated by" attributions in commit messages.
|
||||
|
||||
## Git Hooks (Lefthook)
|
||||
|
||||
- **pre-commit:** Biome check on staged files
|
||||
@@ -79,17 +63,19 @@ bun run commit # Guided commit via commitizen (cz-git)
|
||||
|
||||
## Design Tokens
|
||||
|
||||
Colors, typography, spacing, and easing are defined as CSS custom properties in `Layout.astro`:
|
||||
Colors, typography, and spacing are defined as CSS custom properties in `Layout.astro`:
|
||||
|
||||
- **Colors:** cream (#F5F0EB), dusty-rose (#C48B8B), slate-blue (#8A9BB5), navy (#1A1F2E)
|
||||
- **Fonts:** `neue-haas-grotesk-display` (body, weight 500), `meno-text` (display/headings) via Typekit
|
||||
- **Spacing/type:** Fluid scales using `clamp()`
|
||||
- **Easing:** `--ease-out-quart` (hover), `--ease-in-out` (layout/entrance animations)
|
||||
|
||||
## Environment Variables
|
||||
|
||||
- `PUBLIC_SIGNUP_ENDPOINT` — Form submission endpoint (defaults to `/api/signup`). See `.env.example`.
|
||||
|
||||
## Key Patterns
|
||||
|
||||
- All scroll animations use `.reveal` class + IntersectionObserver (threshold 0.1, -40px root margin)
|
||||
- Hero animations: line-by-line blur-in reveal with staggered delays, quartic ease-out
|
||||
- Hover interactions use `--ease-out-quart`, layout/entrance animations use `--ease-in-out`
|
||||
- Hero animations are CSS-only with staggered delays via `--i` custom property
|
||||
- `prefers-reduced-motion` is detected via inline script and disables all animations via `.reduce-motion` class
|
||||
- Hero background image uses blur + desaturation + cream overlay for glassmorphic effect
|
||||
- Form handler uses progressive enhancement — works as standard POST without JS
|
||||
|
||||
10
README.md
@@ -15,16 +15,6 @@ bun run build # Static build to dist/
|
||||
bun run preview # Preview production build
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
Deploys to Cloudflare Pages via Gitea Actions on push to `main`. To deploy manually:
|
||||
|
||||
```sh
|
||||
bun run deploy # Build + deploy to Cloudflare Pages
|
||||
```
|
||||
|
||||
Requires `CLOUDFLARE_API_TOKEN` and `CLOUDFLARE_ACCOUNT_ID` (set as Gitea secrets for CI, or via `wrangler login` locally).
|
||||
|
||||
## Linting & Formatting
|
||||
|
||||
```sh
|
||||
|
||||
3
bun.lock
@@ -11,7 +11,6 @@
|
||||
"@biomejs/biome": "^2.3.10",
|
||||
"@commitlint/cli": "^20.2.0",
|
||||
"@commitlint/config-conventional": "^20.2.0",
|
||||
"chrome-devtools-mcp": "^0.17.0",
|
||||
"commitizen": "^4.3.1",
|
||||
"cz-git": "^1.12.0",
|
||||
"lefthook": "^2.0.12",
|
||||
@@ -353,8 +352,6 @@
|
||||
|
||||
"chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="],
|
||||
|
||||
"chrome-devtools-mcp": ["chrome-devtools-mcp@0.17.0", "", { "bin": { "chrome-devtools-mcp": "build/src/index.js" } }, "sha512-vMi2zXq2ph2EG6amyyApcvuKJcEFj4cGK1XQVb6x8vQYHk8D9ZnSxdtFqD0cRnG7SbUOrg3GhjOZEJAD1dZWSQ=="],
|
||||
|
||||
"ci-info": ["ci-info@4.4.0", "", {}, "sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg=="],
|
||||
|
||||
"cli-boxes": ["cli-boxes@3.0.0", "", {}, "sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g=="],
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
"format": "biome format --write .",
|
||||
"format:check": "biome format .",
|
||||
"commit": "cz",
|
||||
"deploy": "astro build && wrangler pages deploy",
|
||||
"prepare": "lefthook install"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -22,7 +21,6 @@
|
||||
"@biomejs/biome": "^2.3.10",
|
||||
"@commitlint/cli": "^20.2.0",
|
||||
"@commitlint/config-conventional": "^20.2.0",
|
||||
"chrome-devtools-mcp": "^0.17.0",
|
||||
"commitizen": "^4.3.1",
|
||||
"cz-git": "^1.12.0",
|
||||
"lefthook": "^2.0.12"
|
||||
|
||||
|
Before Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 420 B |
|
Before Width: | Height: | Size: 3.1 KiB |
|
Before Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 9.8 KiB |
@@ -1,21 +0,0 @@
|
||||
{
|
||||
"name": "Lofty",
|
||||
"short_name": "Lofty",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icons/web-app-manifest-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
},
|
||||
{
|
||||
"src": "/icons/web-app-manifest-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable"
|
||||
}
|
||||
],
|
||||
"theme_color": "#ffffff",
|
||||
"background_color": "#ffffff",
|
||||
"display": "standalone"
|
||||
}
|
||||
|
Before Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 5.8 KiB |
|
Before Width: | Height: | Size: 5.3 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="377" height="192" viewBox="0 0 377 192" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.05 148V142.45C19.2 141.7 21.75 136.3 21.75 120.85V70.6C21.75 54.4 19.05 49.75 4.05 49.15V43.6C19.2 44.05 22.5 44.2 32.4 44.2C42.3 44.2 51.15 43.75 58.95 43.6V49.15C45 50.2 41.4 53.8 41.4 71.35V120.7C41.4 136.9 44.85 139 60.15 139C76.65 139 86.85 131.95 91.2 113.8H96.9L95.7 131.8C94.95 141.1 93.15 144.7 89.7 148C73.95 147.55 63 147.4 48.9 147.4C31.95 147.4 14.85 147.7 4.05 148ZM143.946 72.25C166.896 72.25 181.746 88.45 181.746 110.95C181.746 133.75 166.746 149.65 143.946 149.65C121.296 149.65 106.446 133.75 106.446 110.95C106.446 88.15 121.296 72.25 143.946 72.25ZM143.946 143.2C156.396 143.2 162.696 130.45 162.696 110.95C162.696 91.75 156.396 78.7 143.946 78.7C131.646 78.7 125.346 91.75 125.346 110.95C125.346 130.45 131.646 143.2 143.946 143.2ZM272.777 149.5C250.277 150.1 245.327 143.35 245.477 120.85C245.627 111.1 245.627 86.95 245.627 83.95H216.977V126.85C216.977 139.45 220.427 142.3 228.077 142.9V148C218.627 147.7 216.527 147.55 209.027 147.55C201.527 147.55 195.827 147.7 188.177 148V142.9C195.677 142.45 200.627 139.75 200.627 127V83.95H190.877L189.827 78.1C199.277 74.95 199.577 72.55 202.277 64.15C204.977 55.9 208.727 48.85 214.877 43.3C220.577 38.2 228.227 34.75 236.777 34.75C249.077 34.75 257.477 40.15 257.477 48.1C257.477 51.25 256.127 54.25 253.877 56.05L248.927 57.85C244.877 50.5 238.277 43 230.327 43C222.227 43 216.977 50.2 216.977 63.25V74.35H241.727C248.177 69.85 253.577 63.1 258.077 56.05L263.777 57.25C262.577 62.8 262.127 69.4 262.127 74.35L285.977 73.9L284.327 83.95H261.977C261.977 86.95 261.977 109.75 261.827 118.9C261.827 133.45 268.877 137.35 278.477 137.35C281.777 137.35 285.227 136.9 288.677 136.15L289.877 140.5C285.077 143.5 278.327 147.1 272.777 149.5ZM374.849 73.9V79C368.699 79.45 365.549 82.3 357.599 100.3C349.649 118.45 339.149 143.05 329.099 167.5C326.999 172.75 318.599 191.35 303.449 191.35C294.899 191.35 288.749 185.65 287.849 176.95L290.849 174.1C294.149 176.5 297.449 177.4 301.949 177.4C311.699 177.4 319.649 168.7 326.549 151.45C319.499 133.75 310.499 113.8 304.049 98.95C295.949 80.35 292.349 79.75 287.249 79V73.9C292.349 74.2 299.549 74.35 306.599 74.35C313.949 74.35 319.649 74.2 326.549 73.9V79C319.649 79.45 316.349 82.3 321.149 95.65C324.299 104.8 330.899 120.55 335.549 131.05C339.749 120.25 346.499 102.25 348.149 96.55C351.749 84.25 348.599 79.3 339.749 79V73.9C346.499 74.35 349.949 74.35 356.399 74.35C361.799 74.35 368.399 74.35 374.849 73.9Z" fill="white"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 6.3 KiB |
@@ -1,3 +0,0 @@
|
||||
<svg width="377" height="192" viewBox="0 0 377 192" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M4.05 148V142.45C19.2 141.7 21.75 136.3 21.75 120.85V70.6C21.75 54.4 19.05 49.75 4.05 49.15V43.6C19.2 44.05 22.5 44.2 32.4 44.2C42.3 44.2 51.15 43.75 58.95 43.6V49.15C45 50.2 41.4 53.8 41.4 71.35V120.7C41.4 136.9 44.85 139 60.15 139C76.65 139 86.85 131.95 91.2 113.8H96.9L95.7 131.8C94.95 141.1 93.15 144.7 89.7 148C73.95 147.55 63 147.4 48.9 147.4C31.95 147.4 14.85 147.7 4.05 148ZM143.946 72.25C166.896 72.25 181.746 88.45 181.746 110.95C181.746 133.75 166.746 149.65 143.946 149.65C121.296 149.65 106.446 133.75 106.446 110.95C106.446 88.15 121.296 72.25 143.946 72.25ZM143.946 143.2C156.396 143.2 162.696 130.45 162.696 110.95C162.696 91.75 156.396 78.7 143.946 78.7C131.646 78.7 125.346 91.75 125.346 110.95C125.346 130.45 131.646 143.2 143.946 143.2ZM272.777 149.5C250.277 150.1 245.327 143.35 245.477 120.85C245.627 111.1 245.627 86.95 245.627 83.95H216.977V126.85C216.977 139.45 220.427 142.3 228.077 142.9V148C218.627 147.7 216.527 147.55 209.027 147.55C201.527 147.55 195.827 147.7 188.177 148V142.9C195.677 142.45 200.627 139.75 200.627 127V83.95H190.877L189.827 78.1C199.277 74.95 199.577 72.55 202.277 64.15C204.977 55.9 208.727 48.85 214.877 43.3C220.577 38.2 228.227 34.75 236.777 34.75C249.077 34.75 257.477 40.15 257.477 48.1C257.477 51.25 256.127 54.25 253.877 56.05L248.927 57.85C244.877 50.5 238.277 43 230.327 43C222.227 43 216.977 50.2 216.977 63.25V74.35H241.727C248.177 69.85 253.577 63.1 258.077 56.05L263.777 57.25C262.577 62.8 262.127 69.4 262.127 74.35L285.977 73.9L284.327 83.95H261.977C261.977 86.95 261.977 109.75 261.827 118.9C261.827 133.45 268.877 137.35 278.477 137.35C281.777 137.35 285.227 136.9 288.677 136.15L289.877 140.5C285.077 143.5 278.327 147.1 272.777 149.5ZM374.849 73.9V79C368.699 79.45 365.549 82.3 357.599 100.3C349.649 118.45 339.149 143.05 329.099 167.5C326.999 172.75 318.599 191.35 303.449 191.35C294.899 191.35 288.749 185.65 287.849 176.95L290.849 174.1C294.149 176.5 297.449 177.4 301.949 177.4C311.699 177.4 319.649 168.7 326.549 151.45C319.499 133.75 310.499 113.8 304.049 98.95C295.949 80.35 292.349 79.75 287.249 79V73.9C292.349 74.2 299.549 74.35 306.599 74.35C313.949 74.35 319.649 74.2 326.549 73.9V79C319.649 79.45 316.349 82.3 321.149 95.65C324.299 104.8 330.899 120.55 335.549 131.05C339.749 120.25 346.499 102.25 348.149 96.55C351.749 84.25 348.599 79.3 339.749 79V73.9C346.499 74.35 349.949 74.35 356.399 74.35C361.799 74.35 368.399 74.35 374.849 73.9Z" fill="#003049"/>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 2.5 KiB |
@@ -5,11 +5,11 @@ interface Props {
|
||||
}
|
||||
|
||||
const {
|
||||
title = "Lofty — Talent, media, and tech for collective power",
|
||||
description = "The Lofty Project bridges talented creatives with leftist movements and progressive campaigns — connecting designers, filmmakers, and strategists to build a better country for all.",
|
||||
title = "Lofty — Creative power for the progressive movement",
|
||||
description = "Lofty connects creative professionals with progressive campaigns, produces original political media, and builds digital infrastructure for progressive organizing.",
|
||||
} = Astro.props;
|
||||
|
||||
const ogImage = "/banner.jpg";
|
||||
const ogImage = "/og.png";
|
||||
---
|
||||
|
||||
<!doctype html>
|
||||
@@ -17,12 +17,7 @@ const ogImage = "/banner.jpg";
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<link rel="icon" type="image/png" href="/icons/favicon-96x96.png" sizes="96x96" />
|
||||
<link rel="icon" type="image/svg+xml" href="/icons/favicon.svg" />
|
||||
<link rel="shortcut icon" href="/icons/favicon.ico" />
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="/icons/apple-touch-icon.png" />
|
||||
<meta name="apple-mobile-web-app-title" content="Lofty" />
|
||||
<link rel="manifest" href="/icons/site.webmanifest" />
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
|
||||
<title>{title}</title>
|
||||
|
||||
@@ -3,10 +3,7 @@ import Layout from "../layouts/Layout.astro";
|
||||
|
||||
// const signupEndpoint = import.meta.env.PUBLIC_SIGNUP_ENDPOINT || "/api/signup";
|
||||
|
||||
const heroWords = [
|
||||
["Talent,", "media,", "and", "tech"],
|
||||
["for", "collective", "power"],
|
||||
];
|
||||
const heroLines = ["Talent, media, and tech", "for collective power"];
|
||||
|
||||
const pillars = [
|
||||
{
|
||||
@@ -46,15 +43,8 @@ const pillars = [
|
||||
</header>
|
||||
<div class="container hero-inner">
|
||||
<h1 class="hero-headline">
|
||||
{heroWords.map((group, groupIndex) => (
|
||||
<span class="word-line">
|
||||
{group.map((word, wordIndex) => {
|
||||
const wordNum = heroWords.slice(0, groupIndex).flat().length + wordIndex;
|
||||
return (
|
||||
<span class="word-reveal" style={`--i: ${wordNum}`}>{word}</span>
|
||||
);
|
||||
})}
|
||||
</span>
|
||||
{heroLines.map((line, i) => (
|
||||
<span class="line-reveal" style={`--i: ${i}`}>{line}</span>
|
||||
))}
|
||||
</h1>
|
||||
<p class="hero-sub">
|
||||
@@ -201,8 +191,6 @@ const pillars = [
|
||||
.hero-bg img {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 100vh;
|
||||
min-height: 100dvh;
|
||||
object-fit: cover;
|
||||
object-position: center center;
|
||||
filter: blur(2px) saturate(0.15) brightness(1.2);
|
||||
@@ -267,28 +255,13 @@ const pillars = [
|
||||
line-height: 1.05;
|
||||
}
|
||||
|
||||
.word-line {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.word-reveal {
|
||||
display: inline-block;
|
||||
.line-reveal {
|
||||
display: block;
|
||||
opacity: 0;
|
||||
filter: blur(10px);
|
||||
transform: translateY(0.4em);
|
||||
animation: line-clip 1.4s var(--ease-out-quart) forwards;
|
||||
animation-delay: calc(0.3s + var(--i) * 0.12s);
|
||||
margin-right: 0.25em;
|
||||
}
|
||||
|
||||
.word-reveal:last-child {
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.word-line {
|
||||
display: block;
|
||||
}
|
||||
animation-delay: calc(0.3s + var(--i) * 0.35s);
|
||||
}
|
||||
|
||||
@keyframes line-clip {
|
||||
|
||||
6
wrangler.json
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/cloudflare/workers-sdk/main/packages/wrangler/config-schema/schema.json",
|
||||
"name": "lofty-landing",
|
||||
"pages_build_output_dir": "dist",
|
||||
"compatibility_date": "2026-02-01"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
name = "lofty-landing"
|
||||
pages_build_output_dir = "dist"
|
||||
compatibility_date = "2026-02-01"
|
||||