尚未检测到更新。GitHub 发布版本后会显示在这里。
个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证正在加载完整 README。 以下为已保存的摘录。
A small, premium-feeling product website for paid digital nomad city guides.
Bangkok is the first guide. The architecture is built so you can add Ubud,
Chiang Mai, Koh Samui, Kuala Lumpur (and more) by dropping in new MDX files and
metadata — no template-rewriting needed.
• Next.js 14 (App Router) + TypeScript
• Tailwind CSS with a premium black / off-white / warm sand / electric blue palette
• MDX content files (rendered via next-mdx-remote)
• Supabase (optional) for email-gated access — with a JSON/env-var fallback for MVP
• No CMS, no auth library, no DB required to run locally
Open.查看完整 README ↗A small, premium-feeling product website for paid digital nomad city guides.
Bangkok is the first guide. The architecture is built so you can add Ubud, Chiang Mai, Koh Samui, Kuala Lumpur (and more) by dropping in new MDX files and metadata — no template-rewriting needed.
next-mdx-remote)npm install
cp .env.example .env.local # optional — works fine without
npm run dev # starts TinaCMS + Next.js together
Open http://localhost:3000.
Edit content visually: open http://localhost:3000/admin/index.html — that's the TinaCMS editor (see Content management below).
Routes you can hit immediately:
/ — root marketing page (lists all guides)/guides/bangkok — public landing page (hero, what's inside, FAQ, CTA)/guides/bangkok/access — email gate/guides/bangkok/app — protected guide dashboard/guides/bangkok/app/areas-to-stay (or any of the 13 section slugs)Test the gate with one of the demo emails in config/approvedEmails.json:
When someone enters their email on the access page, the client POSTs to
/api/access, which runs verifyAccess() from lib/access.ts.
Resolution order:
APPROVED_EMAILS env var (comma-separated, applies to all guides) — easiest for one-off launchesconfig/approvedEmails.json (per-guide list) — easiest for MVPpurchases table (if NEXT_PUBLIC_SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY are set) — recommended once you have real buyersOn success, the client stores a small token in localStorage under
fh:access:<guideSlug> and redirects to /guides/<slug>/app. The protected app
shell (components/GuideAppShell.tsx) reads
that token on mount and bounces unauthenticated users back to /access.
This is intentionally simple. It's a validation MVP — not a fortress. Anyone with the URL and the right email can unlock. Swap to a real session/JWT once you bolt on payments.
The fastest way:
// config/approvedEmails.json
{
"bangkok": [
"[email protected]",
"[email protected]",
"[email protected]"
]
}
Or via env (.env.local):
[email protected],[email protected]
purchases table:create table purchases (
id uuid primary key default gen_random_uuid(),
email text not null,
guide_slug text not null,
access_granted boolean default true,
created_at timestamptz default now()
);
create index on purchases (email, guide_slug);
.env.local:NEXT_PUBLIC_SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=eyJ...
The service role key bypasses RLS, so keep it server-side only — it's only
read in lib/access.ts which runs in the API route runtime.
insert into purchases (email, guide_slug) values ('[email protected]', 'bangkok');
Once you're ready for real payments:
NEXT_PUBLIC_CHECKOUT_URL in .env.local so all "Get the guide" buttons point to it.app/api/webhooks/lemon-squeezy/route.ts (or stripe) that:
order_created / checkout.session.completed, inserts the customer email + guide slug into the Supabase purchases table.lib/access.ts already checks Supabase, so no other changes are needed — once
the buyer's email lands in the table, they can unlock the guide.
You have two ways to edit content:
npm run dev
# then open http://localhost:3000/admin/index.html
You'll get a side-by-side editor:
Guide Sections → bangkok → <section>)Click Save and Tina writes the change straight back to the .mdx file on disk. Next.js hot-reloads, so you see the result on the live site within a second.
If you're comfortable with markdown, open any content/guides/bangkok/*.mdx in VS Code. Same outcome, faster for bulk edits, but you'll need to write the JSX for custom blocks yourself. See the components reference below.
The local editor writes to your laptop. For a deployed setup where someone else can edit from a browser without git:
.env.local and Vercel:
NEXT_PUBLIC_TINA_CLIENT_ID=...
TINA_TOKEN=...
/admin/index.html on the live site lets logged-in editors save — Tina commits the change to GitHub, Vercel rebuilds, content is live in ~60s.No code changes needed — tina/config.ts already reads those env vars and falls back to local-only mode if they're missing.
| Path | Editable in Tina? |
|---|---|
content/guides/bangkok/*.mdx | ✅ Yes — section title, description, body, all custom blocks |
lib/guides.ts (guide metadata, sections list, quick stats) | ❌ No — code, edit manually |
config/approvedEmails.json (MVP buyer list) | ❌ No — edit manually or move to Supabase |
FAQ on landing page (in app/guides/[slug]/page.tsx) | ❌ No — could be moved to MDX later if it changes often |
If you want guide metadata (price, hero quick stats, FAQ) editable in Tina too, that's a follow-up: move those from TypeScript into a content/guides/<slug>/_meta.json collection and add it to the schema.
All guide content lives in content/guides/<slug>/*.mdx. The Bangkok guide
has 13 sections:
content/guides/bangkok/
overview.mdx
areas-to-stay.mdx
first-24-hours.mdx
monthly-budget.mdx
cafes.mdx
coworking.mdx
gyms.mdx
getting-around.mdx
scooter-reality-check.mdx
weekend-trips.mdx
mistakes-to-avoid.mdx
resource-vault.mdx
Each file is plain MDX — write markdown, drop in components, ship.
Wired up automatically in components/MdxRenderer.tsx:
| Component | Use it for |
|---|---|
<AreaCard /> | Neighborhood comparison (vibe, rent, pros/cons, score) |
<BudgetCard /> | Budget tier (Budget / Comfortable / Premium) |
<BudgetCalculator /> | Interactive monthly budget sliders |
<CafeCard /> | Cafes with WiFi/plug/noise/call ratings |
<CoworkingCard /> | Coworking spaces with day-pass + pros/cons |
<GymCard /> | Gyms / Muay Thai / yoga / wellness |
<Checklist /> | Interactive checklist (saves progress in localStorage) |
<WarningCard severity="warn|danger|info" /> | Highlighted callout |
<ResourceCard /> | External link with category |
<TripCard /> | Weekend trip with verdict (Yes / Maybe / Skip) |
<VideoBlock /> | Placeholder for your own video content |
<ProTip /> | A blue-highlighted tip block |
<MapPlaceholder /> | Faux map (swap for a real embed later) |
<PlaceCard url="..." /> | Google Maps URL → name, photo, rating, address from the place snapshot (data/places.json, built by scripts/places-snapshot.ts); unknown links render a basic link card |
Editing a section is just:
# Save the file. Next will hot-reload.
nano content/guides/bangkok/cafes.mdx
Content now lives in Notion (read via the "Freedom Hustle Site"
integration), not MDX. The full step-by-step — Notion authoring, pulling
section page IDs, wiring lib/guides.ts, Stripe, access, verify, deploy —
is in docs/GUIDE_ROLLOUT.md.
Key gotcha: a status flip in lib/guides.ts only goes live in production
after deploy — editing locally does nothing for the live site.
app/
layout.tsx # Global layout + fonts
page.tsx # Home (lists guides)
globals.css # Tailwind + prose styles
api/access/route.ts # POST /api/access — gating endpoint
guides/[slug]/
page.tsx # Public landing page
access/page.tsx # Email gate (client form)
app/
layout.tsx # Protected shell (sidebar + access check)
page.tsx # Dashboard (section cards)
[section]/page.tsx # MDX-rendered section page
components/
AreaCard.tsx # ...one file per MDX component
BudgetCalculator.tsx # Interactive sliders
Checklist.tsx # Saves progress to localStorage
GuideAppShell.tsx # Client-side gate + layout
GuideDashboard.tsx # Section grid
Hero.tsx # Landing hero
LockedAccess.tsx # Access page form
MdxRenderer.tsx # MDX → React with all components wired
MobileSectionNav.tsx # Bottom drawer nav on mobile
SectionNav.tsx # Sticky desktop sidebar
... (and more — CafeCard, CoworkingCard, etc.)
config/
approvedEmails.json # MVP fallback access list
content/
guides/bangkok/*.mdx # All 13 Bangkok sections
lib/
access.ts # verifyAccess() — env → JSON → Supabase
clientAccess.ts # localStorage helpers
guides.ts # Guide metadata + section registry
mdx.ts # MDX file loader (gray-matter)
ink-900), off-white background (sand-50),
warm sand accents (sand-100–500), electric blue accent (electric-500).2xl/3xl, soft shadows, off-white surfaces.
No corporate grids, no SaaS gradients.Things you might expect that we left out, on purpose:
git + a text editor. Add Sanity/Contentlayer later if you want.