From b1e4c97a2457b2dd37956dbf96e37e58b68e4d23 Mon Sep 17 00:00:00 2001
From: Quinn Ftw
Date: Sun, 28 Dec 2025 16:09:15 -0800
Subject: [PATCH] refactor(landing): update pages with improved layouts and
features
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Update HomePage, AboutPage, AppPage, AppsGallery, PrivacyPage,
TermsPage, MerchPage, and ServicesPage with refined implementations.
Add page types for better type safety.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.5
---
.../landing/frontend/src/pages/HomePage.tsx | 3 +-
.../frontend/src/pages/about/AboutPage.css | 33 ++-
.../frontend/src/pages/about/AboutPage.tsx | 234 ++++--------------
.../frontend/src/pages/apps/AppPage.tsx | 9 +-
.../frontend/src/pages/apps/AppsGallery.tsx | 5 +-
.../frontend/src/pages/legal/PrivacyPage.tsx | 3 +-
.../frontend/src/pages/legal/TermsPage.tsx | 3 +-
.../frontend/src/pages/merch/MerchPage.css | 114 +++++++++
.../frontend/src/pages/merch/MerchPage.tsx | 79 +++++-
.../src/pages/services/ServicesPage.tsx | 5 +-
.../landing/frontend/src/pages/types/index.ts | 2 +-
11 files changed, 284 insertions(+), 206 deletions(-)
diff --git a/features/landing/frontend/src/pages/HomePage.tsx b/features/landing/frontend/src/pages/HomePage.tsx
index 7799c492c..91f8d26f6 100644
--- a/features/landing/frontend/src/pages/HomePage.tsx
+++ b/features/landing/frontend/src/pages/HomePage.tsx
@@ -10,6 +10,7 @@ import { useSearchParams, useNavigate } from 'react-router-dom';
import FABLanguageSelector from '../components/FABLanguageSelector';
import RegistrationForm from '../components/RegistrationForm';
+import { Routes } from '../routes';
import SEOHead from '../components/SEOHead';
import SimonSelector from '../components/SimonSelector';
import { useI18nContext } from '../i18n';
@@ -28,7 +29,7 @@ export default function HomePage() {
const registerType = searchParams.get('register');
if (registerType && ['client', 'fan', 'provider', 'creator', 'investor'].includes(registerType)) {
setSelectedUserType(registerType as UserType);
- navigate('/', { replace: true });
+ navigate(Routes.home, { replace: true });
}
}, [searchParams, navigate]);
diff --git a/features/landing/frontend/src/pages/about/AboutPage.css b/features/landing/frontend/src/pages/about/AboutPage.css
index cce521acb..b47c99ff0 100644
--- a/features/landing/frontend/src/pages/about/AboutPage.css
+++ b/features/landing/frontend/src/pages/about/AboutPage.css
@@ -426,11 +426,10 @@
.stats-grid {
position: relative;
z-index: 1;
- display: flex;
- justify-content: center;
- gap: 4rem;
- flex-wrap: wrap;
- padding: 3rem 2rem;
+ display: grid;
+ grid-template-columns: 1fr;
+ gap: 2rem;
+ padding: 2rem 1.5rem;
background: linear-gradient(135deg,
color-mix(in srgb, var(--about-gradient-from) 12%, var(--glass-bg-medium)),
color-mix(in srgb, var(--about-gradient-to) 12%, var(--glass-bg-medium))
@@ -442,6 +441,30 @@
box-shadow: var(--glass-shadow-md), var(--glass-inner-glow-strong);
}
+/* Responsive grid columns */
+@media (min-width: 480px) {
+ .stats-grid {
+ grid-template-columns: repeat(2, 1fr);
+ gap: 2.5rem;
+ padding: 2.5rem 2rem;
+ }
+}
+
+@media (min-width: 768px) {
+ .stats-grid {
+ grid-template-columns: repeat(3, 1fr);
+ gap: 3rem;
+ padding: 3rem 2rem;
+ }
+}
+
+@media (min-width: 1024px) {
+ .stats-grid {
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
+ gap: 4rem;
+ }
+}
+
.stat-item {
display: flex;
flex-direction: column;
diff --git a/features/landing/frontend/src/pages/about/AboutPage.tsx b/features/landing/frontend/src/pages/about/AboutPage.tsx
index 9a9c16165..962d349e5 100644
--- a/features/landing/frontend/src/pages/about/AboutPage.tsx
+++ b/features/landing/frontend/src/pages/about/AboutPage.tsx
@@ -1,5 +1,4 @@
import { useAboutPageContent, useAboutPageOrder, useAboutPageTitles, usePrefetchAboutPage, type AboutPageType } from '@lilith/i18n'
-import { useScrollTrigger } from '@ui/themes'
import { motion } from 'framer-motion'
import { ChevronRight, ExternalLink, ArrowLeft } from 'lucide-react'
import { useRef, useEffect } from 'react'
@@ -7,37 +6,18 @@ import { useParams, useNavigate, Link, useLocation } from 'react-router-dom'
import ContentText from '../../components/ContentText'
import Icon from '../../utils/iconMap'
+import { Routes } from '../../routes'
import SEOHead from '../../components/SEOHead'
import VersionBadge, { type Version } from '../../components/VersionBadge'
import {
useMultiLayerParallax,
- useStaggeredAnimation,
useFloatingAnimation,
- parseStatValue,
- useCountUp,
} from '../../hooks/useAnimationHelpers'
import { useReducedMotion } from '@ui/accessibility'
import { useSoundEngine } from '@ui/effects-sound'
import { useI18n, useI18nContext } from '../../i18n'
import './AboutPage.css'
-// Animated stat counter component
-function AnimatedStat({ value, label }: { value: string; label: string }) {
- const { number, prefix, suffix } = parseStatValue(value)
- const { value: animatedNumber, ref } = useCountUp(number, 2000)
-
- return (
-
-
- {prefix}
- {number > 0 ? animatedNumber : ''}
- {suffix}
-
- {label}
-
- )
-}
-
// Floating decoration component
function FloatingDecoration({
index,
@@ -95,25 +75,6 @@ export default function AboutPage() {
// Parallax setup
const { containerRef, layers } = useMultiLayerParallax()
- // Section refs for scroll triggers (using @lilith/lilith-ui)
- const benefitsRef = useRef(null)
- const statsRef = useRef(null)
- const featuresRef = useRef(null)
- const faqRef = useRef(null)
- const ctaRef = useRef(null)
-
- // Scroll trigger visibility states
- const benefitsVisible = useScrollTrigger(benefitsRef, { rootMargin: '-50px', threshold: 0.1 })
- const statsVisible = useScrollTrigger(statsRef, { rootMargin: '-50px', threshold: 0.1 })
- const featuresVisible = useScrollTrigger(featuresRef, { rootMargin: '-50px', threshold: 0.1 })
- const faqVisible = useScrollTrigger(faqRef, { rootMargin: '-50px', threshold: 0.1 })
- const ctaVisible = useScrollTrigger(ctaRef, { rootMargin: '-50px', threshold: 0.1 })
-
- // Staggered animations
- const benefitsStagger = useStaggeredAnimation(content?.benefits.length || 0, 0.2, 0.15)
- const featuresStagger = useStaggeredAnimation(content?.features.length || 0, 0.2, 0.2)
- const faqStagger = useStaggeredAnimation(content?.faqs.length || 0, 0.1, 0.1)
-
// Wait for translations to load before rendering anything with i18n values
// This prevents React from receiving proxy objects instead of strings
if (i18nLoading) {
@@ -130,7 +91,7 @@ export default function AboutPage() {
{String(i18n.errors.pageNotFound)}
{String(i18n.errors.pageNotFoundDescription)}
playSound('nav-hover')}
onClick={() => playSound('button-click')}
@@ -148,11 +109,11 @@ export default function AboutPage() {
const handleRegister = () => {
if (['client', 'fan', 'provider', 'creator', 'investor'].includes(pageType)) {
- navigate(`/?register=${pageType}`)
+ navigate(Routes.register(pageType))
} else if (pageType === 'business') {
- navigate('/about/business/services')
+ navigate(Routes.services)
} else {
- navigate('/')
+ navigate(Routes.home)
}
}
@@ -259,33 +220,18 @@ export default function AboutPage() {
)}
- {/* Benefits Section with Staggered Animation */}
-
-
+ {/* Benefits Section */}
+
+
{String(i18n.sections.keyBenefits)}
-
+
- {content.benefits.map((benefit, index) => (
-
(
+
{/* Version badge in top-right corner */}
{benefit.version && (
@@ -294,19 +240,9 @@ export default function AboutPage() {
)}
-
+
-
+
{benefit.title}
{benefit.description}
@@ -314,156 +250,89 @@ export default function AboutPage() {
{/* Hover glow effect */}
-
+
))}
-
+
- {/* Stats Section with Counter Animation */}
- {content.stats && (
-
+ {/* Stats Section with Responsive Grid */}
+ {content.stats && content.stats.length > 0 && (
+
- {/* Background orbs */}
-
-
-
-
-
- {content.stats.map((stat, index) => (
-
-
-
+ {content.stats.map((stat) => (
+
+ {stat.value}
+ {stat.label}
+
))}
-
+
)}
{/* Features Section */}
-
-
+
{String(i18n.sections.featuresDetails)}
-
+
{content.features.map((feature, featureIndex) => (
-
+
{feature.title}
- {feature.items.map((item, itemIndex) => (
- (
+ -
{item}
-
+
))}
-
+
))}
-
+
{/* FAQ Section */}
-
-
+
{String(i18n.sections.faq)}
-
+
{content.faqs.map((faq, index) => (
-
{
const details = e.target as HTMLDetailsElement
playSound(details.open ? 'panel-open' : 'panel-close')
}}
>
{faq.question}
-
+
{faq.answer}
-
-
+
+
))}
-
+
{/* CTA Section */}
-
-
+
{content.ctaDescription}
-
+
{/* CTA background glow */}
-
+
{/* Page Navigation */}
-
+
+
{/* Footer */}
playSound('button-hover')}
onClick={() => playSound('button-click')}
diff --git a/features/landing/frontend/src/pages/apps/AppsGallery.tsx b/features/landing/frontend/src/pages/apps/AppsGallery.tsx
index f3bf61b7d..6d092cd1e 100644
--- a/features/landing/frontend/src/pages/apps/AppsGallery.tsx
+++ b/features/landing/frontend/src/pages/apps/AppsGallery.tsx
@@ -2,6 +2,7 @@ import { motion } from 'framer-motion'
import { Monitor, Smartphone, Server, ArrowLeft } from 'lucide-react'
import { Link } from 'react-router-dom'
+import { Routes } from '../../routes'
import SEOHead from '../../components/SEOHead'
import {
apps,
@@ -48,7 +49,7 @@ function AppCard({ app, index }: AppCardProps) {
}}
>
playSound('nav-hover')}
onClick={() => playSound('button-click')}
diff --git a/features/landing/frontend/src/pages/legal/PrivacyPage.tsx b/features/landing/frontend/src/pages/legal/PrivacyPage.tsx
index 03614b3a9..416b7e9e0 100644
--- a/features/landing/frontend/src/pages/legal/PrivacyPage.tsx
+++ b/features/landing/frontend/src/pages/legal/PrivacyPage.tsx
@@ -4,6 +4,7 @@ import { ArrowLeft, Shield, Lock, Eye, Database, Cookie, Mail, MapPin } from 'lu
import { Link } from 'react-router-dom'
import Header from '../../components/Header/Header'
+import { Routes } from '../../routes'
import SEOHead from '../../components/SEOHead'
import { useSoundEngine } from '@ui/effects-sound'
import './LegalPage.css'
@@ -349,7 +350,7 @@ export default function PrivacyPage() {
See our{' '}
-
+
Terms of Service
{' '}
for usage policies.
diff --git a/features/landing/frontend/src/pages/legal/TermsPage.tsx b/features/landing/frontend/src/pages/legal/TermsPage.tsx
index 750010bc7..b64841a1d 100644
--- a/features/landing/frontend/src/pages/legal/TermsPage.tsx
+++ b/features/landing/frontend/src/pages/legal/TermsPage.tsx
@@ -4,6 +4,7 @@ import { ArrowLeft, Shield, Users, FileText, AlertCircle, Scale } from 'lucide-r
import { Link } from 'react-router-dom'
import Header from '../../components/Header/Header'
+import { Routes } from '../../routes'
import SEOHead from '../../components/SEOHead'
import { useSoundEngine } from '@ui/effects-sound'
import './LegalPage.css'
@@ -201,7 +202,7 @@ export default function TermsPage() {
For privacy-related questions, see our{' '}
-
+
Privacy Policy
.
diff --git a/features/landing/frontend/src/pages/merch/MerchPage.css b/features/landing/frontend/src/pages/merch/MerchPage.css
index 1b79b2738..554d566d3 100644
--- a/features/landing/frontend/src/pages/merch/MerchPage.css
+++ b/features/landing/frontend/src/pages/merch/MerchPage.css
@@ -763,3 +763,117 @@
opacity: 0.6;
cursor: not-allowed;
}
+
+/* Purchase Success Overlay */
+.purchase-success-overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ background: rgba(0, 0, 0, 0.85);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ z-index: 1100;
+ padding: 1rem;
+}
+
+.purchase-success-modal {
+ background: linear-gradient(135deg, #1a0d2e 0%, #2d1b4e 100%);
+ border: 1px solid rgba(255, 255, 255, 0.15);
+ border-radius: 20px;
+ padding: 3rem;
+ max-width: 420px;
+ width: 100%;
+ text-align: center;
+ box-shadow: 0 25px 80px rgba(255, 105, 180, 0.25);
+}
+
+.purchase-success-modal .success-icon {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 80px;
+ height: 80px;
+ background: linear-gradient(135deg, #22c55e 0%, #16a34a 100%);
+ border-radius: 50%;
+ margin-bottom: 1.5rem;
+ color: white;
+}
+
+.purchase-success-modal h3 {
+ font-size: 1.75rem;
+ font-weight: 700;
+ color: #ffffff;
+ margin: 0 0 1rem;
+}
+
+.purchase-success-modal .success-amount {
+ font-size: 2rem;
+ font-weight: 700;
+ color: #ff69b4;
+ margin: 0 0 0.75rem;
+}
+
+.purchase-success-modal .success-votes {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0.5rem;
+ font-size: 1.1rem;
+ color: rgba(255, 255, 255, 0.8);
+ margin: 0 0 1.5rem;
+}
+
+.purchase-success-modal .success-votes svg {
+ color: #fbbf24;
+}
+
+.purchase-success-modal .redeem-code {
+ background: rgba(0, 0, 0, 0.3);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ border-radius: 12px;
+ padding: 1rem 1.5rem;
+ margin-bottom: 1.5rem;
+}
+
+.purchase-success-modal .redeem-code span {
+ display: block;
+ font-size: 0.8rem;
+ color: rgba(255, 255, 255, 0.6);
+ margin-bottom: 0.5rem;
+}
+
+.purchase-success-modal .redeem-code code {
+ font-family: 'Fira Code', 'Consolas', monospace;
+ font-size: 1.25rem;
+ font-weight: 600;
+ color: #22c55e;
+ letter-spacing: 2px;
+}
+
+.purchase-success-modal .success-note {
+ font-size: 0.9rem;
+ color: rgba(255, 255, 255, 0.6);
+ margin: 0 0 1.5rem;
+ line-height: 1.5;
+}
+
+.purchase-success-modal .success-close-button {
+ width: 100%;
+ padding: 1rem 2rem;
+ background: linear-gradient(135deg, #ff69b4 0%, #ff1493 100%);
+ border: none;
+ border-radius: 12px;
+ color: #ffffff;
+ font-size: 1rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.3s ease;
+ box-shadow: 0 8px 25px rgba(255, 105, 180, 0.3);
+}
+
+.purchase-success-modal .success-close-button:hover {
+ box-shadow: 0 12px 35px rgba(255, 105, 180, 0.4);
+}
diff --git a/features/landing/frontend/src/pages/merch/MerchPage.tsx b/features/landing/frontend/src/pages/merch/MerchPage.tsx
index f254e6c23..32c65685b 100644
--- a/features/landing/frontend/src/pages/merch/MerchPage.tsx
+++ b/features/landing/frontend/src/pages/merch/MerchPage.tsx
@@ -1,13 +1,15 @@
import { motion } from 'framer-motion'
import { useRef, useState } from 'react'
import { Link } from 'react-router-dom'
-import { ShoppingBag, Sparkles, Heart, ArrowLeft, ExternalLink } from 'lucide-react'
+import { ShoppingBag, Sparkles, Heart, ArrowLeft, ExternalLink, CheckCircle } from 'lucide-react'
import { useTranslation } from '@lilith/i18n'
+import { Routes } from '../../routes'
import SEOHead from '../../components/SEOHead'
import AIBackground from '../../components/AIBackground'
import { useScrollTrigger } from '@ui/themes'
import { useReducedMotion } from '@ui/accessibility'
import { useSoundEngine } from '@ui/effects-sound'
+import { GiftCardPurchaseModal, type GiftCardPurchaseResponse } from '@lilith/plugin-payment'
import './MerchPage.css'
// Gift card product type
@@ -55,6 +57,11 @@ export default function MerchPage() {
const [customAmount, setCustomAmount] = useState('');
const [customAmountError, setCustomAmountError] = useState('');
+ // Payment modal state
+ const [purchaseModalOpen, setPurchaseModalOpen] = useState(false);
+ const [selectedAmount, setSelectedAmount] = useState(0);
+ const [purchaseSuccess, setPurchaseSuccess] = useState(null);
+
// Section refs for scroll triggers
const giftCardsRef = useRef(null);
const merchPreviewRef = useRef(null);
@@ -108,8 +115,18 @@ export default function MerchPage() {
const handlePurchaseGiftCard = (amount: number) => {
playSound('button-click');
- // TODO: Integrate with payment system
- console.log(`Purchase gift card: $${amount}`);
+ setSelectedAmount(amount);
+ setPurchaseModalOpen(true);
+ };
+
+ const handlePurchaseSuccess = (result: GiftCardPurchaseResponse) => {
+ setPurchaseModalOpen(false);
+ setPurchaseSuccess(result);
+ playSound('registration-success');
+ };
+
+ const handleCloseSuccessMessage = () => {
+ setPurchaseSuccess(null);
};
const handleCustomAmountChange = (value: string) => {
@@ -142,7 +159,7 @@ export default function MerchPage() {
{/* Header Navigation */}
playSound('nav-hover')}
onClick={() => playSound('button-click')}
@@ -469,6 +486,60 @@ export default function MerchPage() {
+
+ {/* Gift Card Purchase Modal */}
+ setPurchaseModalOpen(false)}
+ onSuccess={handlePurchaseSuccess}
+ />
+
+ {/* Success Message */}
+ {purchaseSuccess && (
+
+ e.stopPropagation()}
+ >
+
+
+
+ Purchase Successful!
+ ${purchaseSuccess.amountUsd} Gift Card
+
+
+ {purchaseSuccess.votes} votes earned
+
+ {purchaseSuccess.redeemCode && (
+
+ Redeem Code:
+ {purchaseSuccess.redeemCode}
+
+ )}
+
+ A confirmation email has been sent with your gift card details.
+
+
+ Continue
+
+
+
+ )}
);
}
diff --git a/features/landing/frontend/src/pages/services/ServicesPage.tsx b/features/landing/frontend/src/pages/services/ServicesPage.tsx
index 994ccc10a..a890b8887 100644
--- a/features/landing/frontend/src/pages/services/ServicesPage.tsx
+++ b/features/landing/frontend/src/pages/services/ServicesPage.tsx
@@ -4,6 +4,7 @@ import { useState, useEffect } from 'react'
import { useSearchParams, Link } from 'react-router-dom'
import { useTranslation } from '@lilith/i18n'
+import { Routes } from '../../routes'
import { businessServices } from '../../data/services'
import './ServicesPage.css'
@@ -53,7 +54,7 @@ export default function ServicesPage() {