个人 GitHub 账号下公开仓库的所有者可以登录并验证所有权,自行管理介绍,无需管理员批准。
登录并生成验证文件,在 30 分钟内将其提交到此仓库的默认分支。其他分支或分叉仓库中的文件无效。然后在下方检查文件,即可无需管理员批准直接管理项目。请保留文件以维持管理权限。
如需登录,将前往登录页面。登录后请回到此处,再次点击所选的验证按钮。
在项目文件夹中运行 /nomorevibe verify,即可验证所有权并自行管理介绍。
一分钟完成验证whitelabel app for walking tours
翻译准备中
取自仓库 README
正在加载完整 README。 以下为已保存的摘录。
Deploy your own location-aware heritage walking guide.
Nearmark is an open-source platform for building a mobile, map-based history guide to a
place – a queer-history trail, an arts walk, a pub crawl, an architecture tour, anything
tied to locations in a city. Visitors open it in their phone browser (or install it as an
app), explore a live map, and unlock illustrated, narrated stories as they walk – either
following a guided tour or wandering in discovery mode, where stories pop up when
they get near a site.查看完整 README ↗Deploy your own location-aware heritage walking guide.
Nearmark is an open-source platform for building a mobile, map-based history guide to a place – a queer-history trail, an arts walk, a pub crawl, an architecture tour, anything tied to locations in a city. Visitors open it in their phone browser (or install it as an app), explore a live map, and unlock illustrated, narrated stories as they walk – either following a guided tour or wandering in discovery mode, where stories pop up when they get near a site.
It comes with a simple admin backoffice so a non-technical team can manage all the content themselves – no code, no spreadsheets.
/admin) – add and edit locations and tours, upload photos
and audio, drag-to-reorder stops, publish/draft, manage editors. Fully keyboard- and
screen-reader-accessible (WCAG 2.1 AA)./place/<slug>) and
tour (/tour/<slug>) with Open Graph + JSON-LD, plus a live /sitemap.xml and /robots.txt.
Verify the domain in Google Search Console (set VITE_GSC_VERIFICATION) and submit the sitemap.Built with Vue 3 + Vite. Hosted free on Vercel. One codebase serves two pages:
the public app (index.html) and the admin (admin.html, served at /admin).
This repository is the platform. The branding, copy, content and integrations all come from configuration – so you can stand up your own instance without editing component code.
Deeper reference:
docs/FSD.mdis the functional specification – features, data model, and architecture in one place.
You'll need (all have free tiers):
You do not need to be a senior engineer. If you can copy files, paste values into a form, and run a couple of commands, you can deploy this. The steps below assume you're a developer setting it up on behalf of an organisation.
Fork this repository to your own GitHub account, then clone your fork:
git clone https://github.com/YOUR-USERNAME/nearmark-app.git
cd nearmark-app
npm install
In the Supabase dashboard, open the SQL Editor, then paste-and-run, in order:
schema.sql – tables, security policies, the media storage bucketseed.sql – (optional) example rows; skip it if you'll add your own contentmigration-*.sql file in numerical order – migration-002-… through the
highest-numbered one. Each is small, additive and idempotent (add column if not exists), so run them all to bring the schema up to date; re-running is harmless. The
last one, migration-041-data-api-grants.sql, grants the Data API roles access to the
tables (required: since 2026-10-30 Supabase no longer does this automatically).Running a client on the shared core? Any time you
git pullnew features, check for newmigration-*.sqlfiles and run them in each Supabase project – a missing column shows up as a "Save failed" in the admin.
Adding a new table in a migration? Grant it, or the Data API can't reach it (since 2026-10-30).
schema.sqlsetsalter default privilegesso tables created after it inherit the grants automatically; if a project predates that, add explicit grants in the migration (grant select on public.your_table to anon;+ full CRUD toauthenticated, service_role) — seemigration-041-data-api-grants.sqlfor the pattern.
Then create your first admin user: Authentication → Users → Add user → Create new user, set an email + password, and tick Auto Confirm User. Keep "Allow new users to sign up" turned off so only people you invite can reach the admin.
Branded invite emails (optional). By default invites come from "Supabase Auth". To send them from your app instead, paste the branded templates and configure custom SMTP — see
supabase/email-templates/.
.envCopy the example and fill it in:
cp .env.example .env
At minimum set VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY (from step 2). Everything
else is optional – set VITE_APP_NAME, colours and copy to brand the app for your
organisation. See the Configuration reference below. Run it
locally to check:
npm run dev # public app → http://localhost:5173/ admin → /admin.html
npm run size # build, then check the JS bundle against its size budget (gzipped)
npm run size fails if the bundle grows past the budget in scripts/check-bundle-size.mjs
— a guard against a heavy dependency or a lost code-split creeping in. Wire it into CI to
enforce it automatically.
Sign in to /admin.html with the user you created and add a location or two. (With no
Supabase configured, the app falls back to bundled example content so you can preview the
look first.)
npm run build, output directory dist
(Vercel detects these)..env.main thereafter auto-deploys.Your app is now live at your-project.vercel.app, with the admin at /admin. To use your
own domain, add it under Vercel → Domains.
Day-to-day content – locations, tours, photos, audio – is all managed in the admin
backoffice at /admin, no code required. Sign in with a Supabase user, then add
locations (drop a pin on the map, write the story, upload images), group them into tours,
and publish. Drafts stay hidden from the public app until published.
The editor also supports: a media-library picker (reuse an uploaded photo across
locations without re-uploading), in-place image replace, before/after photo
sliders, per-photo and per-cover credit toggles, a per-location link-button label,
a "guided tour only" flag (hide a stop from Discovery mode), Preview (open a
location or tour in the live app in a new tab; also shareable via ?story=<slug> /
?tour=<slug>), road-following walking routes (below), and an unsaved-changes
guard. Admin login supports optional two-factor (TOTP). Every screen is keyboard-
and screen-reader-navigable (WCAG 2.1 AA).
Two admin features are powered by Supabase Edge Functions
in supabase/functions/. They're optional – the app degrades gracefully without them –
but deploy them (with the Supabase CLI) to enable:
User management – admin-users powers the screen for inviting/listing/removing admins:
supabase functions deploy admin-users --project-ref YOUR_PROJECT_REF
Road-following walking routes – compute-route snaps a tour's route to real
footpaths and roads (via OpenRouteService) instead of
straight "crow-flies" lines:
supabase secrets set ORS_KEY='YOUR_FULL_ORS_KEY' --project-ref YOUR_PROJECT_REF
supabase functions deploy compute-route --project-ref YOUR_PROJECT_REF
route_geometry), so the app draws it offline
with no per-visit API calls. A tour with no calculated route just falls back to straight
lines, and the stored route auto-clears when you change the tour's stops.Every value is optional and overridable via a VITE_* variable in .env (or in Vercel's
environment variables). Blank values fall back to generic Nearmark defaults. Visual theme
tokens (palette, fonts) live in src/theme.js and
src/lib/tokens.js; identity and copy come from these variables:
| Variable | What it controls |
|---|---|
VITE_APP_NAME | Product name – browser tab title and installed-app name |
VITE_APP_SHORT_NAME | Short name shown under the home-screen icon |
VITE_ORG_NAME | Wordmark shown top-left in the app |
VITE_BRAND_BARS | Logo-mark bar colours, comma-separated hex (blank = neutral default) |
VITE_LOGO_URL | Optional in-app logo image URL; blank shows the wordmark + bar mark (never another org's logo) |
VITE_ICON_URL | Optional install icon (square ~512px PNG URL) → PWA manifest + favicon + apple-touch; blank = bundled neutral placeholder |
VITE_APP_DESCRIPTION | Meta description – baked into the static <meta> + Open Graph/Twitter card, so link-preview scrapers (WhatsApp, iMessage…) show it |
VITE_THEME_COLOR | Browser UI / PWA splash colour (hex); also the static first-paint page background, so a light theme doesn't flash dark while the app boots |
VITE_THEME | Named palette in src/themes (e.g. tollesbury); blank = default dark |
VITE_PUBLIC_URL | Canonical URL for the "Share this app" feature (blank = current site origin) |
VITE_DEFAULT_UNITS | Default distance units for a new visitor: km (metres/km, the default) or mi (yards/miles). Visitors can still switch in Settings |
VITE_GSC_VERIFICATION | Google Search Console verification token (or the whole pasted <meta> tag) → an inert <meta name="google-site-verification"> on the public page; no cookies. Blank = not emitted |
VITE_COVER_HEADLINE | Big cover headline; {city} is replaced with the city name |
VITE_COVER_INTRO | Cover intro line; supports {city} |
VITE_SPLASH_TITLE | Title on the first (location-permission) screen |
App icons & logo (white-label). The icons shipped in public/
(icon-192.png, icon-512.png, apple-touch-icon.png, favicon-48.png) are
neutral Nearmark placeholders – a fresh deployment never displays another
organisation's logo. A deployment supplies its own branding entirely through env,
without touching the shared codebase:
VITE_ICON_URL – the install/home-screen icon (a square ~512px PNG URL,
e.g. on the client's Supabase Storage/CDN). At build time it's wired into the
PWA manifest, favicon and apple-touch link. Blank → the neutral placeholders.VITE_LOGO_URL – the in-app logo image. Blank → the VITE_ORG_NAME
wordmark beside the neutral bar mark (VITE_BRAND_BARS).(Forked/standalone deployments can instead just replace the four files in
public/.)
To rebrand further, adjust the colour/font tokens via VITE_THEME /
src/themes. Starter content for testing lives in src/data/seed.js.
MIT – free to use, modify and deploy, including commercially. Copyright (c) 2026 Jonathan Harbourne / Nearmark.
VITE_SPLASH_BODY | Body text on the first screen |
VITE_DISCOVERY_PROMPT | Text shown when prompting to enable location for Discovery |
VITE_DISCOVERY_SCAN_LABEL | Discovery "scan" button label (default Scan for nearby stories; e.g. …history, …places of interest) |
VITE_COMPLETION_MESSAGE | Message on the "tour complete" screen |
VITE_STORY_LINK_LABEL | Label for a location's external link, e.g. Visit the artist’s website (the link hides when a location has no URL) |
VITE_FEEDBACK_EMAIL | Recipient for the story card's "Suggest a correction" mailto: link, e.g. [email protected] (blank hides the link) |
VITE_PRIVACY_URL | Privacy/consent policy link shown on the /approve/<token> approval page (blank hides the link). See docs/approval-flow.md |
VITE_CONTENT_SOURCE_LABEL | Attribution credit, e.g. example.org (blank hides it) |
VITE_CONTENT_SOURCE_URL | Optional link on the content-source label (blank = plain text) |
VITE_PLATFORM_NAME | "Powered by …" footer attribution (default Nearmark) |
VITE_PLATFORM_URL | Link for the platform name (blank = plain text) |
VITE_CONTENT_SOURCE_NOTE | Sourcing paragraph in Settings (blank hides it) |
VITE_WIKI_BASE_URL | Base URL for article links + admin URL validation |
VITE_REPO_URL | "Source code" link in the admin (blank hides it) |
VITE_GUIDE_URL | "Guide & help" link in the admin sidebar (default nearmark.co.uk/guide; blank hides it) |
VITE_FEEDBACK_URL | Admin "Suggest an improvement" link (default nearmark.co.uk/feedback; blank hides it) |
VITE_HELP_EMAIL | Admin "Ask a question" mailto: link — a light way for editors to reach a human (default [email protected]; blank hides it) |
VITE_RELEASES_URL | Admin version / "what's new" link (blank = <VITE_REPO_URL>/releases) |
VITE_SUPABASE_URL | Supabase project URL (backend) |
VITE_SUPABASE_ANON_KEY | Supabase publishable/anon key (safe in the client) |
VITE_POSTHOG_KEY | PostHog project token for analytics (blank disables) |
VITE_POSTHOG_HOST | PostHog host (default EU cloud) |
VITE_ANALYTICS_URL | PostHog project URL for the admin "Open in PostHog" link (blank = derived from the host) |
VITE_ANALYTICS_EMBED_URL | PostHog shared-dashboard Embed URL to show analytics inside the admin (blank = link out only) |
VITE_CITY_NAME | Active city label, e.g. Tollesbury (blank = bundled seed city) |
VITE_CITY_AREA | City sub-label, e.g. Essex |
VITE_CITIES | Admin city options, comma-separated (e.g. London,Brighton); blank = just VITE_CITY_NAME (single-city sites skip the public city picker) |
VITE_MAP_CENTER_LAT / VITE_MAP_CENTER_LNG | Initial map centre |
VITE_MAP_ZOOM | Initial map zoom level |
VITE_MAP_PMTILES_URL | Offline vector basemap: a per-deployment Protomaps .pmtiles file URL (served with HTTP range support, e.g. Supabase Storage). Blank → online-only raster OSM. See docs/maplibre-migration.md |
VITE_CONSENT_NOTICE_VERSION | Privacy-notice version stamped when an admin logs a resident's written consent to publish an address (default 1.0) |