Marketing & media site for the Lethal Threat Racing BMX team — photos & video, race results, schedule, achievements, an Instagram feed, sponsor showcase, and a phone/computer video uploader.
Built with React 19 + TypeScript + Vite and React Router. Clean, sponsor-friendly design.
npm install
npm run dev # http://localhost:5173
npm run build # production build to dist/
npm run preview # preview the production buildAll content lives in plain TypeScript data files under src/data/. Edit these and
the site updates — no database, no login.
| File | What it controls |
|---|---|
src/data/site.ts |
Team name, tagline, email, social links, location |
src/data/team.ts |
Rider roster (photo, number, class, bio, sponsors) |
src/data/results.ts |
Race results table |
src/data/schedule.ts |
Upcoming & past events |
src/data/achievements.ts |
Milestones timeline |
src/data/sponsors.ts |
Sponsor logos by tier |
src/data/gallery.ts |
Photos & videos shown in the gallery |
Drop files into public/ (e.g. public/riders/alex.jpg, public/media/clip.mp4)
and reference them with a leading slash: "/riders/alex.jpg". The sample data
currently uses placeholder image services so the layout renders before you add art.
The feed uses the official Instagram Graph API. See src/services/instagram.ts.
- Create a Meta app + Instagram Business/Creator account linked to a Facebook Page.
- Generate a long-lived access token (≈60 days; refresh on a schedule).
- Copy
.env.exampleto.envand setVITE_INSTAGRAM_TOKEN=....
With no token set, the section shows sample tiles so it never looks broken.
Security: any
VITE_variable is bundled into the public JS. For production, proxy the call through a small serverless function so the token stays server-side. The UI already reads from the service layer, so swapping in a proxy won't change components.
src/components/VideoUpload.tsx + src/services/upload.ts provide a working
drag-and-drop / file-picker uploader with validation, progress, and preview. It
supports phone capture (capture="environment") and desktop files.
Current phase: videos preview locally in the browser — nothing is published yet.
Next phase: replace uploadVideo() in src/services/upload.ts with a real
implementation (pre-signed URL to Azure Blob / S3, or an API POST). The components
depend only on the service's types, so the UI won't need to change.
It's a static SPA — host the dist/ folder anywhere (Netlify, Vercel, Azure Static
Web Apps, GitHub Pages). public/_redirects is included for Netlify-style SPA
fallback; other hosts need an equivalent "rewrite all routes to index.html" rule.
src/
components/ Navbar, Footer, InstagramFeed, VideoUpload, MediaGrid, ...
pages/ Home, Team, Gallery, Results, Schedule, Achievements, Sponsors, Upload, Contact
data/ Editable content (see table above)
services/ instagram.ts, upload.ts (integration boundaries)
types.ts Shared domain types
index.css Design tokens + base styles
App.css Component & page styles