fix: product subdomain cleanup

This commit is contained in:
2026-07-23 20:52:49 -04:00
parent a6ef4d2955
commit 8e33af43a5
39 changed files with 1597 additions and 630 deletions

View File

@@ -1,5 +1,5 @@
import { ContactForm } from "~/components/ContactForm";
import { LineageContactQuestions } from "~/routes/contact";
import SubdomainHeader from "~/components/SubdomainHeader";
/**
* Life and Lineage contact page (`lineage.freno.me/contact`).
@@ -9,9 +9,9 @@ import { LineageContactQuestions } from "~/routes/contact";
* — is derived from `useSite()` inside the component via
* `CONTACT_CONTEXT.lineage`.
*
* Renders the Life-and-Lineage FAQ accordion (re-imported from the main-site
* contact route so the canonical definition lives in one place) above the
* form — the lineage subdomain is the natural home for product support Q&A.
* Subdomain contact pages intentionally render only the shared contact form —
* no Life-and-Lineage FAQ accordion and no main-site disclaimer subline
* (those remain exclusive to the main `freno.me/contact` page).
*
* vercel.json rewrites `lineage.freno.me/*` → the internal `/lineage/*` route
* prefix; the browser URL stays `lineage.freno.me/contact`.
@@ -22,8 +22,9 @@ import { LineageContactQuestions } from "~/routes/contact";
*/
export default function LineageContactPage() {
return (
<ContactForm>
<LineageContactQuestions />
</ContactForm>
<>
<SubdomainHeader />
<ContactForm />
</>
);
}

View File

@@ -33,6 +33,7 @@
* the form posts to the correct tRPC mutation (Lineage-branded email).
*/
import { PageHead } from "~/components/PageHead";
import SubdomainHeader from "~/components/SubdomainHeader";
import DeletionForm from "~/components/DeletionForm";
import {
DELETION_PRODUCT_KEY,
@@ -45,6 +46,7 @@ export default function LineageDeletionPage() {
return (
<>
<PageHead title={PAGE_META.title} description={PAGE_META.description} />
<SubdomainHeader />
<div class="pt-20">
<div class="mx-auto p-4 md:p-6 lg:p-12">
<div class="text-text w-full justify-center">

View File

@@ -31,6 +31,7 @@
import { A } from "@solidjs/router";
import { createSignal, onMount, onCleanup } from "solid-js";
import { PageHead } from "~/components/PageHead";
import SubdomainHeader from "~/components/SubdomainHeader";
import DownloadOnAppStore from "~/components/icons/DownloadOnAppStore";
import Button from "~/components/ui/Button";
import { glitchText } from "~/lib/client-utils";
@@ -71,10 +72,9 @@ export default function LineageDownloadsPage() {
return (
<>
<PageHead
title={PAGE_META.title}
description={PAGE_META.description}
/>
<PageHead title={PAGE_META.title} description={PAGE_META.description} />
<SubdomainHeader />
<div class="bg-base relative min-h-screen overflow-hidden px-4 pt-[15vh] pb-12 md:px-8">
{/* Subtle scanline effect — consistent with the unified downloads page. */}
@@ -131,7 +131,7 @@ export default function LineageDownloadsPage() {
</div>
{/* Secondary CTA → landing page */}
<p class="mt-12 text-center text-sm text-subtext0">
<p class="text-subtext0 mt-12 text-center text-sm">
<A
href={LINEAGE_HOME_HREF}
class="underline transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105"

View File

@@ -1,60 +1,49 @@
/**
* Life and Lineage — lineage subdomain landing page (task 08).
* Life and Lineage — lineage subdomain landing page.
*
* Migrates the legacy `src/routes/marketing/life-and-lineage.tsx` page to the
* `lineage.freno.me` root (vercel.json rewrites `lineage.freno.me/*` →
* `/lineage/*`), and enriches it with feature highlights + a game-art strip.
*
* Site-awareness:
* - `<PageHead>` reads `useSite()` → the lineage `titleSuffix`
* (` | Life and Lineage`) + canonical `https://lineage.freno.me/` are
* derived automatically (task 02); we pass only the base title here.
* - The Google Play badge links to the **public browser path** `/downloads`
* (subdomain-relative), which vercel rewrites to `/lineage/downloads`
* (task 11). The App Store link is an absolute external URL, unchanged.
* - `SimpleParallax` reuses the existing Cave parallax background — a
* fitting "dark fantasy" ambience — and continues to work under the
* subdomain because assets are served from the shared `/public` root.
*
* Auth: this page performs NO auth — Lineage's mobile JWT (`LINEAGE_JWT_SECRET`)
* is for the mobile app's API calls, not the web landing page.
* This intentionally preserves the original marketing-page structure: a single
* full-viewport `SimpleParallax` Cave background with the app icon, title,
* tagline, and store badges centered on screen. No sidebars, no scrollable
* feature sections, and no extra content — the parallax effect depends on the
* page being exactly one viewport tall. The persistent `SubdomainHeader`
* sits sticky above the parallax backdrop so navigation is reachable on every
* subdomain page.
*/
import { A } from "@solidjs/router";
import { PageHead } from "~/components/PageHead";
import SubdomainHeader from "~/components/SubdomainHeader";
import SimpleParallax from "~/components/SimpleParallax";
import DownloadOnAppStoreDark from "~/components/icons/DownloadOnAppStoreDark";
import { For } from "solid-js";
import {
APP_STORE_URL,
DOWNLOADS_HREF,
APP_ICON_SRC,
GOOGLE_PLAY_BADGE_SRC,
SCREENSHOT_ASSETS,
PAGE_META,
FEATURES
PAGE_META
} from "~/routes/lineage/landing-content";
export default function LineageLandingPage() {
return (
<>
<PageHead title={PAGE_META.title} description={PAGE_META.description} />
<SubdomainHeader />
<SimpleParallax>
<div class="flex h-full flex-col items-center justify-center px-4 text-white">
{/* Hero */}
<img
src={APP_ICON_SRC}
alt="Life and Lineage App Icon"
height={128}
width={128}
class="object-cover object-center"
/>
<h1 class="mb-4 mt-4 text-center text-5xl font-bold">
<div>
<img
src={APP_ICON_SRC}
alt="Life and Lineage App Icon"
height={128}
width={128}
class="object-cover object-center"
/>
</div>
<h1 class="mt-4 mb-4 text-center text-5xl font-bold">
Life and Lineage
</h1>
<p class="mb-8 text-xl">A dark fantasy adventure</p>
<p class="text-xl">A dark fantasy adventure</p>
{/* Store badges — App Store (external) + Google Play → /downloads */}
<div class="flex flex-wrap items-center justify-center gap-4">
<div class="mt-8 flex flex-wrap items-center justify-center gap-4">
<a
class="my-auto transition-all duration-200 ease-out active:scale-95"
href={APP_STORE_URL}
@@ -75,68 +64,6 @@ export default function LineageLandingPage() {
/>
</A>
</div>
{/* Feature highlights */}
<section class="mt-16 w-full max-w-4xl">
<h2 class="mb-6 text-center text-2xl font-semibold">
Why players return
</h2>
<div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
<For each={FEATURES}>
{(feature) => (
<div class="bg-base/70 rounded-lg p-4 backdrop-blur-sm">
<h3 class="mb-1 text-lg font-bold">{feature.title}</h3>
<p class="text-sm text-subtext0">
{feature.description}
</p>
</div>
)}
</For>
</div>
</section>
{/* Game art / screenshots strip */}
<section class="mt-16 w-full max-w-4xl">
<h2 class="mb-6 text-center text-2xl font-semibold">
glimpses of the world
</h2>
<div class="flex flex-col items-center gap-6">
<div class="flex flex-wrap items-center justify-center gap-6">
<img
src={SCREENSHOT_ASSETS.home}
alt="Life and Lineage home"
class="h-auto w-full max-w-sm rounded-lg shadow-lg"
loading="lazy"
/>
<img
src={SCREENSHOT_ASSETS.shops}
alt="Life and Lineage shops"
class="h-auto w-full max-w-sm rounded-lg shadow-lg"
loading="lazy"
/>
</div>
<video
src={SCREENSHOT_ASSETS.preview}
class="w-full max-w-2xl rounded-lg shadow-lg"
controls
muted
playsinline
preload="metadata"
/>
</div>
</section>
{/* Secondary CTA → per-subdomain downloads page */}
<p class="mt-16 text-sm text-subtext0">
Prefer a direct download?{" "}
<A
href={DOWNLOADS_HREF}
class="underline transition-transform duration-200 ease-in-out hover:-translate-y-0.5 hover:scale-105"
>
Visit the downloads page
</A>
.
</p>
</div>
</SimpleParallax>
</>

View File

@@ -17,6 +17,7 @@
*/
import { A } from "@solidjs/router";
import { PageHead } from "~/components/PageHead";
import SubdomainHeader from "~/components/SubdomainHeader";
export default function LineagePrivacyPolicy() {
return (
@@ -25,6 +26,7 @@ export default function LineagePrivacyPolicy() {
title="Privacy Policy"
description="Privacy policy for Life and Lineage mobile game, outlining data collection, usage, and user rights."
/>
<SubdomainHeader />
<div class="min-h-screen px-[8vw] py-[10vh]">
<div class="py-4 text-xl">Life and Lineage&apos;s Privacy Policy</div>
<div class="py-2">Last Updated: October 22, 2024</div>
@@ -52,10 +54,7 @@ export default function LineagePrivacyPolicy() {
<div class="pb-2">
<div class="-ml-6">(b) Data Removal:</div> Users can request the
removal of all information related to them by visiting{" "}
<A
href="/deletion"
class="text-blue hover-underline-animation"
>
<A href="/deletion" class="text-blue hover-underline-animation">
this page
</A>{" "}
and filling out the provided form.