diff --git a/apps/planner/app/routes/home.tsx b/apps/planner/app/routes/home.tsx index de5d4e9..e9177de 100644 --- a/apps/planner/app/routes/home.tsx +++ b/apps/planner/app/routes/home.tsx @@ -3,20 +3,87 @@ import type { Route } from "./+types/home"; export function meta(_args: Route.MetaArgs) { return [ - { title: "trails.cool Planner" }, - { name: "description", content: "Collaborative route planning" }, + { title: "trails.cool Planner — Collaborative Route Planning" }, + { name: "description", content: "Plan hiking and cycling routes together in real-time. No account needed." }, ]; } +const features = [ + { key: "featureCollaborative", icon: "👥" }, + { key: "featureRouting", icon: "🗺️" }, + { key: "featureElevation", icon: "⛰️" }, + { key: "featureExport", icon: "📥" }, + { key: "featureNoAccount", icon: "🔓" }, +] as const; + export default function Home() { const { t } = useTranslation("planner"); return ( -
-
-

{t("title")}

-

{t("subtitle")}

-
+
+ {/* Hero */} +
+

+ {t("title")} +

+

+ {t("landing.heroDescription")} +

+ + {t("landing.startPlanning")} + +
+ + {/* Features */} +
+
+ {features.map(({ key, icon }) => ( +
+
{icon}
+

+ {t(`landing.${key}`)} +

+

+ {t(`landing.${key}Desc`)} +

+
+ ))} +
+
+ + {/* Secondary CTA */} +
+

+ {t("landing.saveRoutes")} +

+

+ {t("landing.saveRoutesDesc")} +

+ + {t("landing.goToJournal")} + +
+ + {/* Footer */} +
); } diff --git a/e2e/planner.test.ts b/e2e/planner.test.ts index 0d7d67c..67d6c97 100644 --- a/e2e/planner.test.ts +++ b/e2e/planner.test.ts @@ -3,8 +3,8 @@ import { test, expect } from "@playwright/test"; test.describe("Planner", () => { test("loads the home page", async ({ page }) => { await page.goto("/"); - await expect(page).toHaveTitle("trails.cool Planner"); - await expect(page.getByText("Collaborative route planning")).toBeVisible(); + await expect(page).toHaveTitle(/trails\.cool Planner/); + await expect(page.getByRole("link", { name: "Start Planning" })).toBeVisible(); }); test("can create a session via API", async ({ request }) => { diff --git a/openspec/changes/planner-landing-page/.openspec.yaml b/openspec/changes/archive/2026-03-25-planner-landing-page/.openspec.yaml similarity index 100% rename from openspec/changes/planner-landing-page/.openspec.yaml rename to openspec/changes/archive/2026-03-25-planner-landing-page/.openspec.yaml diff --git a/openspec/changes/planner-landing-page/design.md b/openspec/changes/archive/2026-03-25-planner-landing-page/design.md similarity index 100% rename from openspec/changes/planner-landing-page/design.md rename to openspec/changes/archive/2026-03-25-planner-landing-page/design.md diff --git a/openspec/changes/planner-landing-page/proposal.md b/openspec/changes/archive/2026-03-25-planner-landing-page/proposal.md similarity index 100% rename from openspec/changes/planner-landing-page/proposal.md rename to openspec/changes/archive/2026-03-25-planner-landing-page/proposal.md diff --git a/openspec/changes/planner-landing-page/specs/planner-session/spec.md b/openspec/changes/archive/2026-03-25-planner-landing-page/specs/planner-session/spec.md similarity index 100% rename from openspec/changes/planner-landing-page/specs/planner-session/spec.md rename to openspec/changes/archive/2026-03-25-planner-landing-page/specs/planner-session/spec.md diff --git a/openspec/changes/archive/2026-03-25-planner-landing-page/tasks.md b/openspec/changes/archive/2026-03-25-planner-landing-page/tasks.md new file mode 100644 index 0000000..53095da --- /dev/null +++ b/openspec/changes/archive/2026-03-25-planner-landing-page/tasks.md @@ -0,0 +1,16 @@ +## 1. Landing Page Content + +- [x] 1.1 Rewrite Planner home.tsx with hero section: heading, subtitle, "Start Planning" CTA linking to /new +- [x] 1.2 Add feature highlights section (4-5 cards): collaborative editing, routing profiles, elevation profile, GPX export, no account needed +- [x] 1.3 Add secondary CTA: "Save your routes on trails.cool" linking to Journal +- [x] 1.4 Add footer: privacy link, GitHub repo, BRouter/OSM attribution + +## 2. i18n + +- [x] 2.1 Add all landing page strings to en.ts and de.ts (hero, features, CTAs, footer) + +## 3. Verify + +- [x] 3.1 Verify landing page renders correctly at planner.trails.cool +- [x] 3.2 Verify "Start Planning" creates a session and redirects +- [x] 3.3 Update E2E planner test if home page assertions changed diff --git a/openspec/changes/planner-landing-page/tasks.md b/openspec/changes/planner-landing-page/tasks.md deleted file mode 100644 index 0506515..0000000 --- a/openspec/changes/planner-landing-page/tasks.md +++ /dev/null @@ -1,16 +0,0 @@ -## 1. Landing Page Content - -- [ ] 1.1 Rewrite Planner home.tsx with hero section: heading, subtitle, "Start Planning" CTA linking to /new -- [ ] 1.2 Add feature highlights section (4-5 cards): collaborative editing, routing profiles, elevation profile, GPX export, no account needed -- [ ] 1.3 Add secondary CTA: "Save your routes on trails.cool" linking to Journal -- [ ] 1.4 Add footer: privacy link, GitHub repo, BRouter/OSM attribution - -## 2. i18n - -- [ ] 2.1 Add all landing page strings to en.ts and de.ts (hero, features, CTAs, footer) - -## 3. Verify - -- [ ] 3.1 Verify landing page renders correctly at planner.trails.cool -- [ ] 3.2 Verify "Start Planning" creates a session and redirects -- [ ] 3.3 Update E2E planner test if home page assertions changed diff --git a/openspec/specs/planner-session/spec.md b/openspec/specs/planner-session/spec.md index 9e20ba9..9f86e40 100644 --- a/openspec/specs/planner-session/spec.md +++ b/openspec/specs/planner-session/spec.md @@ -73,6 +73,21 @@ The Planner SHALL display presence indicators showing which users are currently - **WHEN** a user disconnects from the session - **THEN** their cursor disappears from all other participants' maps within 5 seconds +### Requirement: Planner home page +The Planner home page SHALL explain the tool's purpose and provide a one-click way to start planning. + +#### Scenario: First-time visitor +- **WHEN** a user visits planner.trails.cool for the first time +- **THEN** they see a landing page explaining collaborative route planning, key features, and a prominent "Start Planning" button + +#### Scenario: Start a session +- **WHEN** a user clicks "Start Planning" +- **THEN** a new anonymous session is created and the user is redirected to the session view + +#### Scenario: Journal link +- **WHEN** a user wants to save routes permanently +- **THEN** a secondary CTA links to trails.cool for account creation + ### Requirement: No user data collection The Planner SHALL NOT collect, store, or track any personal user data. Sessions are anonymous by default. diff --git a/packages/i18n/src/locales/de.ts b/packages/i18n/src/locales/de.ts index 9e86754..dea861c 100644 --- a/packages/i18n/src/locales/de.ts +++ b/packages/i18n/src/locales/de.ts @@ -39,6 +39,28 @@ export default { loss: "Höhenmeter abwärts", profile: "Höhenprofil", }, + landing: { + startPlanning: "Planung starten", + heroDescription: "Plane Wander- und Radrouten gemeinsam in Echtzeit. Kein Konto nötig.", + featureCollaborative: "Echtzeit-Zusammenarbeit", + featureCollaborativeDesc: "Wegpunkte gemeinsam bearbeiten — Änderungen werden sofort synchronisiert.", + featureRouting: "Intelligentes Routing", + featureRoutingDesc: "BRouter berechnet optimale Routen für Wandern, Radfahren oder Autofahren mit Höhenprofil.", + featureElevation: "Höhenprofil", + featureElevationDesc: "Das vollständige Höhenprofil deiner Route mit Auf- und Abstiegsstatistiken.", + featureExport: "GPX-Export", + featureExportDesc: "Exportiere deine Route als GPX für jedes GPS-Gerät oder jede App.", + featureNoAccount: "Kein Konto nötig", + featureNoAccountDesc: "Sofort loslegen. Teile einen Link und jeder kann deiner Sitzung beitreten.", + saveRoutes: "Routen speichern?", + saveRoutesDesc: "Erstelle ein kostenloses Konto auf trails.cool, um Routen zu speichern, Aktivitäten zu verfolgen und mehr.", + goToJournal: "Zu trails.cool", + footer: { + privacy: "Datenschutz", + source: "Quellcode", + builtWith: "Erstellt mit BRouter und OpenStreetMap", + }, + }, }, journal: { title: "trails.cool", diff --git a/packages/i18n/src/locales/en.ts b/packages/i18n/src/locales/en.ts index c5b3837..3842de0 100644 --- a/packages/i18n/src/locales/en.ts +++ b/packages/i18n/src/locales/en.ts @@ -39,6 +39,28 @@ export default { loss: "Elevation Loss", profile: "Elevation Profile", }, + landing: { + startPlanning: "Start Planning", + heroDescription: "Plan hiking and cycling routes together in real-time. No account needed.", + featureCollaborative: "Real-Time Collaboration", + featureCollaborativeDesc: "Edit waypoints together — changes sync instantly across all participants.", + featureRouting: "Smart Routing", + featureRoutingDesc: "BRouter computes optimal routes for hiking, cycling, or driving with elevation awareness.", + featureElevation: "Elevation Profile", + featureElevationDesc: "See the full elevation profile of your route with gain and loss statistics.", + featureExport: "GPX Export", + featureExportDesc: "Export your route as GPX for use in any GPS device or app.", + featureNoAccount: "No Account Needed", + featureNoAccountDesc: "Start planning immediately. Share a link and anyone can join your session.", + saveRoutes: "Want to save your routes?", + saveRoutesDesc: "Create a free account on trails.cool to keep your routes, track activities, and more.", + goToJournal: "Go to trails.cool", + footer: { + privacy: "Privacy", + source: "Source Code", + builtWith: "Built with BRouter and OpenStreetMap", + }, + }, }, journal: { title: "trails.cool",