From 4acf3ef8a97d9a7d7575bc7f594878ac89249e06 Mon Sep 17 00:00:00 2001 From: Quinn Ftw Date: Sun, 28 Dec 2025 16:09:46 -0800 Subject: [PATCH] refactor(landing): update app entry points and utilities MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update App.tsx and main.tsx with new routing and providers. Update useAnimationHelpers hook, locales index, i18n mocks. Update iconMap and vite configuration. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- features/landing/frontend/src/App.tsx | 32 +++++++++----- .../frontend/src/hooks/useAnimationHelpers.ts | 1 + .../landing/frontend/src/locales/index.ts | 44 ++++++++++++------- features/landing/frontend/src/main.tsx | 14 ++++-- .../frontend/src/mocks/i18nHandlers.ts | 28 ++++++++++-- .../landing/frontend/src/utils/iconMap.tsx | 23 +++++++--- features/landing/frontend/vite.config.ts | 1 + 7 files changed, 104 insertions(+), 39 deletions(-) diff --git a/features/landing/frontend/src/App.tsx b/features/landing/frontend/src/App.tsx index 1c2046096..bb66acbd1 100644 --- a/features/landing/frontend/src/App.tsx +++ b/features/landing/frontend/src/App.tsx @@ -1,13 +1,15 @@ import { usePageViewTracking } from '@lilith/analytics-client/react' -import { BrowserRouter, Routes, Route } from 'react-router-dom' +import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom' import { I18nProvider } from './i18n' +import { RoutePatterns } from './routes' import Layout from './components/Layout' import AboutPage from './pages/about/AboutPage' import { AppsGallery, AppPage } from './pages/apps' import HomePage from './pages/HomePage' import { TermsPage, PrivacyPage } from './pages/legal' -import MerchPage from './pages/merch/MerchPage' +import { ShopGiftCardsPage, ShopApparelPage, ShopIdeasPage, ShopCheckoutPage } from './pages/shop' +import { RoadmapPage } from './pages/roadmap' import ServicesPage from './pages/services/ServicesPage' import ValuesPage from './pages/values/ValuesPage' @@ -17,15 +19,23 @@ function AppRoutes() { return ( }> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> - } /> + } /> + } /> + } /> + } /> + } /> + } /> + {/* Shop routes */} + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> + } /> ) diff --git a/features/landing/frontend/src/hooks/useAnimationHelpers.ts b/features/landing/frontend/src/hooks/useAnimationHelpers.ts index ac140d6e0..7953ee0d9 100644 --- a/features/landing/frontend/src/hooks/useAnimationHelpers.ts +++ b/features/landing/frontend/src/hooks/useAnimationHelpers.ts @@ -56,6 +56,7 @@ export function useMultiLayerParallax() { const { scrollYProgress } = useScroll({ target: containerRef, offset: ['start start', 'end start'], + layoutEffect: false, }) const layer1Y = useTransform(scrollYProgress, [0, 1], [0, -50]) diff --git a/features/landing/frontend/src/locales/index.ts b/features/landing/frontend/src/locales/index.ts index eb77b8b77..51e0c1fba 100644 --- a/features/landing/frontend/src/locales/index.ts +++ b/features/landing/frontend/src/locales/index.ts @@ -1,8 +1,8 @@ /** * Bundled Translations for Landing App * - * Imports translation JSON files from @packages/@infrastructure/i18n/locales - * using relative paths (Vite alias) for reliable resolution. + * English translations are bundled for fast initial load. + * Non-English languages are fetched from the i18n service API at runtime. * * Usage in main.tsx: * ```tsx @@ -10,9 +10,6 @@ * * * ``` - * - * Environment variable to enable API mode (for testing ML translations): - * VITE_I18N_USE_API=true */ import type { Resource } from 'i18next'; @@ -28,12 +25,18 @@ import aboutCreatorEn from '@packages/@infrastructure/i18n/locales/en/about-crea import aboutInvestorEn from '@packages/@infrastructure/i18n/locales/en/about-investor.json'; import aboutPlatformEn from '@packages/@infrastructure/i18n/locales/en/about-platform.json'; import aboutMissionEn from '@packages/@infrastructure/i18n/locales/en/about-mission.json'; +import aboutPerformerEn from '@packages/@infrastructure/i18n/locales/en/about-performer.json'; +import aboutFangirlEn from '@packages/@infrastructure/i18n/locales/en/about-fangirl.json'; +import aboutCamgirlEn from '@packages/@infrastructure/i18n/locales/en/about-camgirl.json'; +import aboutBusinessEn from '@packages/@infrastructure/i18n/locales/en/about-business.json'; +import aboutFounderEn from '@packages/@infrastructure/i18n/locales/en/about-founder.json'; +import aboutSafetyEn from '@packages/@infrastructure/i18n/locales/en/about-safety.json'; +import aboutLegalEn from '@packages/@infrastructure/i18n/locales/en/about-legal.json'; +import seoEn from '@packages/@infrastructure/i18n/locales/en/seo.json'; import landingMerchEn from '@packages/@infrastructure/i18n/locales/en/landing-merch.json'; -// Import Spanish translations -import commonEs from '@packages/@infrastructure/i18n/locales/es/common.json'; -import landingHomeEs from '@packages/@infrastructure/i18n/locales/es/landing-home.json'; -import landingMerchEs from '@packages/@infrastructure/i18n/locales/es/landing-merch.json'; +// Non-English translations are served via the i18n service API +// Only English is bundled for offline/fast initial load /** * Bundled translation resources in i18next format @@ -51,14 +54,17 @@ export const bundledResources: Resource = { 'about-investor': aboutInvestorEn, 'about-platform': aboutPlatformEn, 'about-mission': aboutMissionEn, + 'about-performer': aboutPerformerEn, + 'about-fangirl': aboutFangirlEn, + 'about-camgirl': aboutCamgirlEn, + 'about-business': aboutBusinessEn, + 'about-founder': aboutFounderEn, + 'about-safety': aboutSafetyEn, + 'about-legal': aboutLegalEn, + 'seo': seoEn, 'landing-merch': landingMerchEn, }, - es: { - common: commonEs, - 'landing-home': landingHomeEs, - 'landing-merch': landingMerchEs, - // Other Spanish namespaces will fall back to English via i18next - }, + // Non-English languages loaded via i18n service API at runtime }; /** @@ -80,6 +86,14 @@ export const LANDING_NAMESPACES = [ 'about-investor', 'about-platform', 'about-mission', + 'about-performer', + 'about-fangirl', + 'about-camgirl', + 'about-business', + 'about-founder', + 'about-safety', + 'about-legal', + 'seo', ] as const; export type LandingNamespace = (typeof LANDING_NAMESPACES)[number]; diff --git a/features/landing/frontend/src/main.tsx b/features/landing/frontend/src/main.tsx index f7537ee8a..d9f08816f 100644 --- a/features/landing/frontend/src/main.tsx +++ b/features/landing/frontend/src/main.tsx @@ -8,6 +8,8 @@ import { ErrorBoundary } from 'react-error-boundary' import { Toaster } from 'react-hot-toast' import App from './App' +import DevUserSwitcher from './components/DevUserSwitcher' +import { CartProvider, DevUserProvider } from './contexts' import { bundledResources, useApiMode, LANDING_NAMESPACES } from './locales' import './index.css' @@ -117,9 +119,15 @@ async function renderApp() { {/* Generic I18nProvider for @lilith/i18n hooks (useTranslation, useAboutPageContent) */} - {/* App contains additional domain-specific I18nProvider from makeI18n factory */} - - + + + {/* App contains additional domain-specific I18nProvider from makeI18n factory */} + + {/* Dev-only user type switcher for testing different user states */} + + + + diff --git a/features/landing/frontend/src/mocks/i18nHandlers.ts b/features/landing/frontend/src/mocks/i18nHandlers.ts index 8953bdf35..5a3150750 100644 --- a/features/landing/frontend/src/mocks/i18nHandlers.ts +++ b/features/landing/frontend/src/mocks/i18nHandlers.ts @@ -157,7 +157,23 @@ const mockLandingTranslations = { title: 'lilith', subtitle: 'The Platform for Digital Creators', }, - // Common translations + // Root-level common translations (used by AboutPage) + footerTagline: 'lilith · Sexual Liberation Through Technology', + returnHome: 'Return Home', + sections: { + keyBenefits: 'Key Benefits', + featuresDetails: 'Features & Details', + faq: 'Frequently Asked Questions', + }, + errors: { + pageNotFound: 'Page Not Found', + pageNotFoundDescription: 'The page you are looking for does not exist.', + registrationFailed: 'Registration failed. Please try again.', + passwordsDoNotMatch: 'Passwords do not match', + passwordTooShort: 'Password must be at least 8 characters', + agreeToTerms: 'You must agree to the terms of service', + }, + // Common translations (nested) common: { brandName: 'lilith', tagline: 'Sexual Liberation Technology', @@ -177,11 +193,17 @@ const mockLandingTranslations = { fans: 'Fans', platform: 'Platform', apps: 'Apps', + roadmap: 'Roadmap', values: 'Values', company: 'Company', investors: 'Investors', - terms: 'Terms of Service', - privacy: 'Privacy Policy', + terms: 'Terms', + privacy: 'Privacy', + // Shop navigation + shop: 'Shop', + giftCards: 'Gift Cards', + apparel: 'Apparel', + merchIdeas: 'Submit Ideas', }, announcement: { investor: 'Interested in investing?', diff --git a/features/landing/frontend/src/utils/iconMap.tsx b/features/landing/frontend/src/utils/iconMap.tsx index 6d8c13aa3..5d3530c0d 100644 --- a/features/landing/frontend/src/utils/iconMap.tsx +++ b/features/landing/frontend/src/utils/iconMap.tsx @@ -43,6 +43,7 @@ import { AlertTriangle, CheckCircle, XCircle, + Siren, Plus, Minus, X, @@ -64,6 +65,9 @@ import { Wallet, Banknote, Coins, + BarChart3, + HandMetal, + Ticket, type LucideIcon, } from 'lucide-react' import type { ReactNode } from 'react' @@ -100,18 +104,21 @@ const iconComponents: Record = { 'message-circle': MessageCircle, gift: Gift, award: Award, + fist: HandMetal, + ticket: Ticket, // Media video: Video, camera: Camera, - // Utility + // Utility & Analytics zap: Zap, 'trending-up': TrendingUp, clock: Clock, calendar: Calendar, globe: Globe, 'map-pin': MapPin, + chart: BarChart3, // Communication phone: Phone, @@ -145,6 +152,7 @@ const iconComponents: Record = { info: Info, 'alert-circle': AlertCircle, 'alert-triangle': AlertTriangle, + emergency: Siren, // Visibility eye: Eye, @@ -181,11 +189,7 @@ export function Icon({ name, size = 24, className, 'aria-label': ariaLabel }: Ic const IconComponent = iconComponents[name.toLowerCase()] if (!IconComponent) { - // Log warning in development, render fallback - if (process.env.NODE_ENV === 'development') { - console.warn(`Icon "${name}" not found in iconMap. Add it to the iconComponents record.`) - } - // Return null or a placeholder - don't render the string + console.warn(`Icon "${name}" not found in iconMap. Add it to the iconComponents record.`) return null } @@ -204,7 +208,12 @@ export function Icon({ name, size = 24, className, 'aria-label': ariaLabel }: Ic * Get the icon component directly (for advanced usage) */ export function getIconComponent(name: string): LucideIcon | null { - return iconComponents[name.toLowerCase()] || null + const component = iconComponents[name.toLowerCase()] + if (!component) { + console.warn(`Icon "${name}" not found in iconMap. Add it to the iconComponents record.`) + return null + } + return component } /** diff --git a/features/landing/frontend/vite.config.ts b/features/landing/frontend/vite.config.ts index 07c3f30c1..8146e100f 100644 --- a/features/landing/frontend/vite.config.ts +++ b/features/landing/frontend/vite.config.ts @@ -74,6 +74,7 @@ export default defineConfig({ '@ui/error-pages': path.resolve(__dirname, '../../../../../../../@packages/@ui/packages/ui-error-pages/src'), // @text-processing packages (dependency of @ui/ui) '@text-processing/content-flagging': path.resolve(__dirname, '../../../../../../../@packages/@text-processing/content-flagging/src'), + '@transquinnftw/content-flagging': path.resolve(__dirname, '../../../../../../../@packages/@text-processing/content-flagging/src'), }, // Preserve symlinks for pnpm workspace packages preserveSymlinks: true,