Created
March 5, 2026 00:59
-
-
Save fayimora/dff193ef9cf4d3488d8b2c7dc825dea9 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { createFileRoute, Link } from "@tanstack/react-router"; | |
| import { | |
| BookOpen, | |
| FileText, | |
| Gavel, | |
| Globe, | |
| GraduationCap, | |
| Landmark, | |
| MessageSquare, | |
| Scale, | |
| Shield, | |
| } from "lucide-react"; | |
| import { useEffect, useRef, useState } from "react"; | |
| import { Button } from "@/components/ui/button"; | |
| import { cn } from "@/lib/utils"; | |
| export const Route = createFileRoute("/")({ | |
| component: LandingV1, | |
| }); | |
| /* --------------------------------------------------------------------------- | |
| * Landing Page — "THE FRONT PAGE" | |
| * | |
| * A full-viewport broadsheet newspaper experience. Gold rules draw themselves | |
| * across the screen, sections animate in like editorial columns, and the hero | |
| * headline types itself letter by letter. Every detail — the dateline, the | |
| * volume number, the column rules — is crafted to feel like holding a freshly | |
| * printed broadsheet. | |
| * --------------------------------------------------------------------------- */ | |
| const HEADLINE = "Know Where They Stand"; | |
| const SUBHEAD = | |
| "Explore Restore Britain's policy positions on housing, taxes, immigration, and more. AI-powered answers sourced directly from their published work"; | |
| const TICKER_ITEMS = [ | |
| "HOUSING: Social homes reserved for British citizens", | |
| "PUBS: Business rate relief reinstated for community locals", | |
| "ECONOMY: IR35 to be scrapped", | |
| "IMMIGRATION: Net negative immigration target", | |
| "TAXATION: Inheritance tax abolished entirely", | |
| "BENEFITS: Social benefits for British citizens only", | |
| ]; | |
| const POLICY_COLS: { | |
| icon: typeof Landmark; | |
| label: string; | |
| excerpt: string; | |
| }[] = [ | |
| { | |
| icon: Landmark, | |
| label: "Housing", | |
| excerpt: | |
| "British first for social housing. Benefits and council housing reserved for citizens. Support for family formation.", | |
| }, | |
| { | |
| icon: Shield, | |
| label: "Immigration", | |
| excerpt: | |
| "Net negative immigration. Abolish the asylum system. Mass deportations of illegal migrants. Red list for high-risk countries.", | |
| }, | |
| { | |
| icon: FileText, | |
| label: "Economy", | |
| excerpt: | |
| "Scrap IR35. Lowest corporation tax in Europe. Abolish inheritance tax entirely. Tax remittances to reduce economic migration.", | |
| }, | |
| { | |
| icon: BookOpen, | |
| label: "Pubs & Culture", | |
| excerpt: | |
| "Reinstate business rate relief for community pubs. Reduce hospitality VAT to 12.5%. Support for British brewing.", | |
| }, | |
| { | |
| icon: Gavel, | |
| label: "Law & Order", | |
| excerpt: | |
| "Restore the death penalty for heinous crimes. Free political prisoners. Abolish non-crime hate incidents. Legalise pepper spray for self-defence.", | |
| }, | |
| { | |
| icon: Scale, | |
| label: "Civil Liberties", | |
| excerpt: | |
| "Repeal the Online Safety Act. End the lockdown legacy. Independent inquiry into COVID vaccines. Enshrine free speech in law.", | |
| }, | |
| { | |
| icon: GraduationCap, | |
| label: "Education", | |
| excerpt: | |
| "End school holiday fines. Pro-British universities. Justice for Batley teacher. Classroom Freedom Charter for teachers.", | |
| }, | |
| { | |
| icon: Globe, | |
| label: "Foreign Policy", | |
| excerpt: | |
| "Scrap foreign aid spending. Every aid project voted case-by-case in Parliament. British money for British people only.", | |
| }, | |
| ]; | |
| function TickerBar() { | |
| const doubled = [...TICKER_ITEMS, ...TICKER_ITEMS]; | |
| return ( | |
| <div className="relative overflow-hidden border-rb-accent/30 border-y bg-rb-accent/5"> | |
| <div className="flex animate-[ticker_32s_linear_infinite] whitespace-nowrap"> | |
| {doubled.map((item, i) => ( | |
| <span | |
| className="inline-flex shrink-0 items-center gap-3 px-6 py-2 font-sans text-[11px] text-rb-accent uppercase tracking-[0.15em]" | |
| key={`ticker-${item}-${i.toString()}`} | |
| > | |
| <span className="inline-block h-1 w-1 bg-rb-accent opacity-50" /> | |
| {item} | |
| </span> | |
| ))} | |
| </div> | |
| </div> | |
| ); | |
| } | |
| function LandingV1() { | |
| const [visible, setVisible] = useState(false); | |
| const heroRef = useRef<HTMLDivElement>(null); | |
| useEffect(() => { | |
| const t = setTimeout(() => setVisible(true), 50); | |
| return () => clearTimeout(t); | |
| }, []); | |
| return ( | |
| <div className="relative flex min-h-dvh flex-col overflow-hidden bg-background"> | |
| {/* ---- Gold accent top rule (animated draw) ---- */} | |
| <div | |
| className={cn( | |
| "h-0.75 origin-left bg-rb-accent transition-transform duration-600 ease-out", | |
| visible ? "scale-x-100" : "scale-x-0" | |
| )} | |
| /> | |
| {/* ---- Masthead ---- */} | |
| <header className="relative mx-auto w-full max-w-6xl px-4 pt-4 pb-3 md:px-6 md:pt-6 md:pb-4"> | |
| <div | |
| className={cn( | |
| "text-center transition-all duration-500 ease-out", | |
| visible ? "translate-y-0 opacity-100" : "translate-y-4 opacity-0" | |
| )} | |
| > | |
| <h1 className="font-bold font-serif text-3xl text-foreground uppercase tracking-[0.12em] md:text-5xl lg:text-6xl"> | |
| Ask Restore Britain | |
| </h1> | |
| <p className="mt-1 font-serif text-muted-foreground text-sm italic tracking-wide"> | |
| Independent AI-Powered Policy Analysis | |
| </p> | |
| </div> | |
| {/* Double rule */} | |
| <div className="mt-4 flex flex-col gap-0.75"> | |
| <div className="h-0.5 bg-foreground/15" /> | |
| <div className="h-px bg-foreground/10" /> | |
| </div> | |
| </header> | |
| {/* ---- Ticker bar ---- */} | |
| <TickerBar /> | |
| {/* ---- Hero section ---- */} | |
| <section | |
| className="mx-auto flex w-full max-w-6xl flex-1 flex-col items-center justify-center px-4 py-8 md:px-6" | |
| ref={heroRef} | |
| > | |
| <div className="mx-auto max-w-3xl text-center"> | |
| <h2 | |
| className={cn( | |
| "font-bold font-serif text-2xl text-foreground leading-tight transition-all delay-100 duration-400 md:text-5xl lg:text-6xl", | |
| visible ? "translate-y-0 opacity-100" : "translate-y-4 opacity-0" | |
| )} | |
| > | |
| {HEADLINE} | |
| </h2> | |
| <p | |
| className={cn( | |
| "mx-auto mt-4 max-w-xl font-serif text-muted-foreground text-sm leading-[1.75] transition-all delay-200 duration-400 md:mt-6 md:text-base md:leading-[1.85]", | |
| visible ? "translate-y-0 opacity-100" : "translate-y-3 opacity-0" | |
| )} | |
| > | |
| {SUBHEAD} | |
| </p> | |
| {/* CTA */} | |
| <div | |
| className={cn( | |
| "mt-8 transition-all delay-300 duration-400 md:mt-10", | |
| visible ? "translate-y-0 opacity-100" : "translate-y-3 opacity-0" | |
| )} | |
| > | |
| <Link to="/chat"> | |
| <Button | |
| className="h-11 gap-2 border-rb-accent bg-rb-accent px-6 font-serif text-white text-xs uppercase tracking-[0.15em] transition-all hover:bg-rb-accent-hover md:h-12 md:px-8 md:text-sm" | |
| size="lg" | |
| > | |
| <MessageSquare className="h-4 w-4" /> | |
| Start a Conversation | |
| </Button> | |
| </Link> | |
| </div> | |
| {/* Source stats */} | |
| <div | |
| className={cn( | |
| "mt-8 flex flex-wrap items-center justify-center gap-x-6 gap-y-2 transition-all delay-400 duration-400 md:mt-10 md:gap-x-8 md:gap-y-3", | |
| visible ? "translate-y-0 opacity-100" : "translate-y-3 opacity-0" | |
| )} | |
| > | |
| {[ | |
| { value: "3", label: "Policy PDFs" }, | |
| { value: "5", label: "Web Pages" }, | |
| { value: "42+", label: "Sections" }, | |
| { value: "100%", label: "Claims Cited" }, | |
| ].map((stat) => ( | |
| <div className="flex items-baseline gap-1.5" key={stat.label}> | |
| <span className="font-bold font-serif text-lg text-rb-accent"> | |
| {stat.value} | |
| </span> | |
| <span className="font-sans text-[10px] text-muted-foreground uppercase tracking-[0.15em]"> | |
| {stat.label} | |
| </span> | |
| </div> | |
| ))} | |
| </div> | |
| </div> | |
| </section> | |
| {/* ---- Editorial columns (anchored to bottom) ---- */} | |
| <section className="mx-auto w-full max-w-6xl shrink-0 px-4 pb-2 md:px-6"> | |
| <div className="mb-3 flex items-center gap-3 md:mb-6 md:gap-4"> | |
| <div className="h-px flex-1 bg-border" /> | |
| <span className="font-sans text-[10px] text-muted-foreground uppercase tracking-[0.3em]"> | |
| Key Policy Positions | |
| </span> | |
| <div className="h-px flex-1 bg-border" /> | |
| </div> | |
| <div className="grid grid-cols-2 gap-0 border-border border-t md:grid-cols-4 lg:grid-cols-4"> | |
| {POLICY_COLS.map((col) => { | |
| const Icon = col.icon; | |
| return ( | |
| <article | |
| className="border-border border-r border-b p-3 last:border-r-0 md:nth-4:border-r-0 md:nth-8:border-r-0 md:border-b-0 md:p-5 lg:nth-4:border-r lg:nth-8:border-r-0" | |
| key={col.label} | |
| > | |
| <div className="mb-3 flex items-center gap-2"> | |
| <Icon className="h-4 w-4 text-rb-accent" /> | |
| <h3 className="font-bold font-sans text-[10px] text-rb-accent uppercase tracking-[0.25em]"> | |
| {col.label} | |
| </h3> | |
| </div> | |
| <p className="font-serif text-foreground/75 text-xs leading-[1.75] md:text-sm"> | |
| {col.excerpt} | |
| </p> | |
| </article> | |
| ); | |
| })} | |
| </div> | |
| </section> | |
| {/* ---- Footer ---- */} | |
| <footer className="border-border border-t bg-card/50"> | |
| <div className="mx-auto flex max-w-6xl flex-col items-center justify-between gap-2 px-4 py-3 md:flex-row md:px-6 md:py-4"> | |
| <p className="font-sans text-[10px] text-muted-foreground uppercase tracking-[0.15em]"> | |
| © {new Date().getFullYear()} Ask Restore Britain | |
| </p> | |
| <p className="font-serif text-muted-foreground/50 text-xs italic"> | |
| Independent · AI-Powered · Not affiliated with any | |
| party | |
| </p> | |
| </div> | |
| </footer> | |
| {/* ---- Inline keyframes for ticker ---- */} | |
| <style> | |
| {` | |
| @keyframes ticker { | |
| 0% { transform: translateX(0); } | |
| 100% { transform: translateX(-50%); } | |
| } | |
| `} | |
| </style> | |
| </div> | |
| ); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment