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,