163 lines
4.8 KiB
Markdown
163 lines
4.8 KiB
Markdown
# ExposedGays
|
|
|
|
100% free gay cruising map + chat + spots directory + sex shop. No subscriptions ever.
|
|
|
|
**Domain:** exposedgays.com
|
|
|
|
## Quick Start
|
|
|
|
```bash
|
|
npm install
|
|
cp .env.example .env.local
|
|
# Edit .env.local with your Supabase keys (optional for local demo — mock data works offline)
|
|
npm run dev
|
|
```
|
|
|
|
Open [http://localhost:3000](http://localhost:3000)
|
|
|
|
## Features
|
|
|
|
| Feature | Status |
|
|
|---------|--------|
|
|
| Real-time cruising map (Leaflet + OSM) | ✅ Mock data + Supabase-ready |
|
|
| User clustering + position badges | ✅ |
|
|
| Map filters (age, position, kinks, PrEP) | ✅ |
|
|
| Cruiser Cards + Profile popup | ✅ |
|
|
| Instant chat + city chat + DMs + groups | ✅ Mock + Supabase schema |
|
|
| Cruising spot directory | ✅ |
|
|
| **Shop** (affiliate links, local cart) | ✅ |
|
|
| Age verification gate (Florida-compliant) | ✅ |
|
|
| Vanilla mode blur toggle | ✅ |
|
|
| Dark mode, mobile-first, PWA manifest | ✅ |
|
|
| Anonymous browsing + optional profile | ✅ |
|
|
|
|
## Tech Stack
|
|
|
|
- **Next.js 15** App Router + TypeScript
|
|
- **Tailwind CSS** + shadcn/ui components
|
|
- **React-Leaflet** + OpenStreetMap tiles
|
|
- **Supabase** — Auth, Postgres + PostGIS, Realtime, Storage
|
|
- **Zustand** — localStorage cart
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
exposedgays/
|
|
├── public/
|
|
│ └── manifest.json # PWA manifest
|
|
├── src/
|
|
│ ├── app/
|
|
│ │ ├── layout.tsx # Root layout + nav
|
|
│ │ ├── page.tsx # Map (home)
|
|
│ │ ├── shop/page.tsx # Sex shop
|
|
│ │ ├── chat/page.tsx # City chat + DMs
|
|
│ │ ├── spots/page.tsx # Spot directory
|
|
│ │ └── profile/page.tsx # User profile editor
|
|
│ ├── components/
|
|
│ │ ├── AgeGate.tsx # 18+ DOB verification
|
|
│ │ ├── Map.tsx # Interactive cruising map
|
|
│ │ ├── Shop.tsx # Product grid + cart
|
|
│ │ ├── Nav.tsx # Top/bottom nav with Shop link
|
|
│ │ ├── ChatPanel.tsx # Real-time chat UI
|
|
│ │ ├── CruiserCard.tsx # Squirt-style cruiser cards
|
|
│ │ ├── ProfilePopup.tsx # Tap icon → profile modal
|
|
│ │ ├── SpotDirectory.tsx # Spot listings + search
|
|
│ │ └── ui/ # shadcn components
|
|
│ ├── lib/
|
|
│ │ ├── products.ts # Dummy shop inventory
|
|
│ │ ├── cart.ts # Zustand localStorage cart
|
|
│ │ ├── mock-data.ts # Demo cruisers + spots
|
|
│ │ └── supabase/ # Supabase client helpers
|
|
│ └── types/index.ts
|
|
├── supabase/
|
|
│ └── schema.sql # Full Postgres + PostGIS + RLS
|
|
├── .env.example
|
|
└── package.json
|
|
```
|
|
|
|
## Supabase Setup
|
|
|
|
### 1. Create project
|
|
|
|
Go to [supabase.com](https://supabase.com) → New Project (free tier).
|
|
|
|
### 2. Run schema
|
|
|
|
SQL Editor → paste contents of `supabase/schema.sql` → Run.
|
|
|
|
### 3. Enable Realtime
|
|
|
|
Dashboard → Database → Replication → enable `chat_messages` and `profiles`.
|
|
|
|
### 4. Create Storage bucket
|
|
|
|
```sql
|
|
INSERT INTO storage.buckets (id, name, public) VALUES ('gallery', 'gallery', true);
|
|
INSERT INTO storage.buckets (id, name, public) VALUES ('shop', 'shop', true);
|
|
```
|
|
|
|
### 5. Copy keys to `.env.local`
|
|
|
|
```
|
|
NEXT_PUBLIC_SUPABASE_URL=https://xxxxx.supabase.co
|
|
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJ...
|
|
SUPABASE_SERVICE_ROLE_KEY=eyJ...
|
|
```
|
|
|
|
### CLI alternative
|
|
|
|
```bash
|
|
npx supabase init
|
|
npx supabase link --project-ref YOUR_PROJECT_REF
|
|
npx supabase db push
|
|
```
|
|
|
|
## 5-Minute Deployment (Vercel + Supabase + DNS)
|
|
|
|
### Step 1 — Push to GitHub (1 min)
|
|
|
|
```bash
|
|
git init
|
|
git add .
|
|
git commit -m "ExposedGays starter"
|
|
gh repo create exposedgays --private --push
|
|
```
|
|
|
|
### Step 2 — Vercel deploy (2 min)
|
|
|
|
1. [vercel.com](https://vercel.com) → Import Git repo
|
|
2. Framework: **Next.js** (auto-detected)
|
|
3. Add environment variables from `.env.example`
|
|
4. Deploy → get `exposedgays.vercel.app`
|
|
|
|
### Step 3 — Custom domain (1 min)
|
|
|
|
1. Vercel → Project → Settings → Domains → Add `exposedgays.com` + `www.exposedgays.com`
|
|
2. Vercel shows required DNS records
|
|
|
|
### Step 4 — DNS at registrar (1 min)
|
|
|
|
| Type | Name | Value |
|
|
|------|------|-------|
|
|
| A | @ | `76.76.21.21` |
|
|
| CNAME | www | `cname.vercel-dns.com` |
|
|
|
|
(Or use Cloudflare CNAME flattening if proxied.)
|
|
|
|
### Step 5 — Verify
|
|
|
|
- Visit `https://exposedgays.com` — age gate appears
|
|
- Map loads with cruiser icons
|
|
- Shop nav works with affiliate buttons
|
|
- PWA installable on mobile
|
|
|
|
## Shop Affiliate Notes
|
|
|
|
- Cart is **localStorage only** — no checkout on-site
|
|
- "Buy Now" opens affiliate URLs in new tab (`rel="sponsored"`)
|
|
- Replace placeholder URLs with real Amazon Associates / AdamMale affiliate links
|
|
- Products defined in `src/lib/products.ts` (static) or `shop_products` table (DB)
|
|
|
|
## License
|
|
|
|
Private — exposedgays.com © 2026 |