refactor(landing): update app entry points and utilities
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 <noreply@anthropic.com>
This commit is contained in:
parent
e48131424f
commit
4acf3ef8a9
7 changed files with 104 additions and 39 deletions
|
|
@ -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 (
|
||||
<Routes>
|
||||
<Route element={<Layout />}>
|
||||
<Route path="/" element={<HomePage />} />
|
||||
<Route path="/values" element={<ValuesPage />} />
|
||||
<Route path="/apps" element={<AppsGallery />} />
|
||||
<Route path="/apps/:appId" element={<AppPage />} />
|
||||
<Route path="/about/business/services" element={<ServicesPage />} />
|
||||
<Route path="/about/:type" element={<AboutPage />} />
|
||||
<Route path="/merch" element={<MerchPage />} />
|
||||
<Route path="/terms" element={<TermsPage />} />
|
||||
<Route path="/privacy" element={<PrivacyPage />} />
|
||||
<Route path={RoutePatterns.home} element={<HomePage />} />
|
||||
<Route path={RoutePatterns.values} element={<ValuesPage />} />
|
||||
<Route path={RoutePatterns.apps} element={<AppsGallery />} />
|
||||
<Route path={RoutePatterns.app} element={<AppPage />} />
|
||||
<Route path={RoutePatterns.services} element={<ServicesPage />} />
|
||||
<Route path={RoutePatterns.about} element={<AboutPage />} />
|
||||
{/* Shop routes */}
|
||||
<Route path={RoutePatterns.shop} element={<Navigate to={RoutePatterns.shopGiftCards} replace />} />
|
||||
<Route path={RoutePatterns.shopGiftCards} element={<ShopGiftCardsPage />} />
|
||||
<Route path={RoutePatterns.shopGiftCardDetail} element={<ShopGiftCardsPage />} />
|
||||
<Route path={RoutePatterns.shopApparel} element={<ShopApparelPage />} />
|
||||
<Route path={RoutePatterns.shopApparelDetail} element={<ShopApparelPage />} />
|
||||
<Route path={RoutePatterns.shopIdeas} element={<ShopIdeasPage />} />
|
||||
<Route path={RoutePatterns.shopCheckout} element={<ShopCheckoutPage />} />
|
||||
<Route path={RoutePatterns.roadmap} element={<RoadmapPage />} />
|
||||
<Route path={RoutePatterns.terms} element={<TermsPage />} />
|
||||
<Route path={RoutePatterns.privacy} element={<PrivacyPage />} />
|
||||
</Route>
|
||||
</Routes>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
|
|
|||
|
|
@ -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 @@
|
|||
*
|
||||
* <I18nProvider config={{ resources: bundledResources }}>
|
||||
* ```
|
||||
*
|
||||
* 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];
|
||||
|
|
|
|||
|
|
@ -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) */}
|
||||
<I18nProvider config={i18nConfig}>
|
||||
<ThemeProvider defaultTheme="cyberpunk">
|
||||
{/* App contains additional domain-specific I18nProvider from makeI18n factory */}
|
||||
<App />
|
||||
<Toaster position="top-center" />
|
||||
<DevUserProvider>
|
||||
<CartProvider>
|
||||
{/* App contains additional domain-specific I18nProvider from makeI18n factory */}
|
||||
<App />
|
||||
{/* Dev-only user type switcher for testing different user states */}
|
||||
<DevUserSwitcher />
|
||||
<Toaster position="top-center" />
|
||||
</CartProvider>
|
||||
</DevUserProvider>
|
||||
</ThemeProvider>
|
||||
</I18nProvider>
|
||||
</AnalyticsProvider>
|
||||
|
|
|
|||
|
|
@ -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?',
|
||||
|
|
|
|||
|
|
@ -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<string, LucideIcon> = {
|
|||
'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<string, LucideIcon> = {
|
|||
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
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue