// landing.jsx — responsive (mobile + desktop) + i18n
const CDN = '/frontend/assets/';
const REFERENCE_SLIDES = [
{ images: [CDN+'reference1-1-9e52dff8.webp', CDN+'reference1-2-4e4525f1.webp', CDN+'reference1-3-f8ca8a9a.webp'], video: CDN+'reference1.mp4' },
{ images: [CDN+'referenceChina2-1-fa6ce117.webp', CDN+'referenceChina2-2-6305572a.webp', CDN+'referenceChina2-3-1da23e96.webp'], video: CDN+'referenceChina2.mp4' },
{ images: [CDN+'reference3-1-aacd1e93.webp', CDN+'reference3-2-4dcf1a34.webp', CDN+'reference3-3-e48eac56.webp'], video: CDN+'reference3.mp4' },
];
const I2V_SLIDES = [
{ from: CDN+'man-first-b1805e6c.webp', video: CDN+'i2v-man.mp4' },
{ from: CDN+'imageChina1-1-59866e85.webp', video: CDN+'i2v-china1.mp4' },
{ from: CDN+'image3-1-3ef70758.webp', video: CDN+'i2v-image3.mp4' },
];
const FEATURE_IMGS = [CDN+'ability1-f6937f83.webp', CDN+'ability2-ce0109cb.webp', CDN+'ability3-fae52eca.webp'];
const TEMPLATE_IMGS = [CDN+'template1-a3871cf5.webp', CDN+'template2-d00aa5ec.webp', CDN+'template3-2929203a.webp', CDN+'chineseWomen-578147cd.webp', CDN+'tamplate3-08aa58fc.webp', CDN+'banner5-f5f8e907.webp'];
const CASE_IMGS = [CDN+'case-new1.webp', CDN+'creat4-3d0d2761.webp', CDN+'case-new2.webp', CDN+'creat6-fa1a4a32.webp', CDN+'case-new3.webp', CDN+'creat2-9767a973.webp', CDN+'creat3-f3991d9c.webp'];
const COMMUNITY_IMGS = [CDN+'image13-0bff0a93.webp', CDN+'image1-65c70b29.webp', CDN+'image2-2bd38261.webp', CDN+'image3-2365f902.webp', CDN+'image5-026301b6.webp', CDN+'image9-7780b44b.webp', CDN+'image7-ad3b6592.webp', CDN+'image15-e2b3524a.webp', CDN+'image11-983b87c9.webp'];
const USER_AVATARS = [CDN+'userImageChina1-70ed1a18.webp', CDN+'userImageChina2-a4d679d9.webp', CDN+'userImageChina3-97972b0d.webp', CDN+'userImageChina4-5a2c61f5.webp', CDN+'userImageChina5-d968467b.webp', CDN+'userImageChina6-9a3d5358.webp'];
// useCarousel + Carousel are now global from shared.jsx
// useBreakpoint() is now global from shared.jsx
// ─── Section Badge ────────────────────────────────────────────────────────────
const SectionBadge = ({ text, color = 'var(--accent)' }) => (
{text}
);
const SectionTitle = ({ children, size, mb = 16 }) => (
{children}
);
// ─── Dot indicators ───────────────────────────────────────────────────────────
const Dots = ({ count, active, onSelect, color = 'var(--accent)' }) => (
{Array.from({ length: count }).map((_, i) => (
);
// ─── Reference Section ────────────────────────────────────────────────────────
const ReferenceSection = () => {
const { t } = useI18n();
const { isMobile } = useBreakpoint();
const [slide, setSlide] = useCarousel(REFERENCE_SLIDES.length);
const videoRefs = React.useRef([]);
// Pause/play videos on slide change
React.useEffect(() => {
videoRefs.current.forEach((v, i) => {
if (!v) return;
if (i === slide) { v.currentTime = 0; v.play().catch(() => {}); }
else { v.pause(); }
});
}, [slide]);
const visual = (
{/* Left: preload all ref image sets, show active */}
{[0, 1, 2].map(imgIdx => (
{REFERENCE_SLIDES.map((s, si) => (

))}
{t('landing.ref.refLabel')} {imgIdx + 1}
))}
{/* All videos preloaded, only active one visible */}
{REFERENCE_SLIDES.map((s, i) => (
);
return (
{t('landing.ref.title')}
{t('landing.ref.desc1')}
{t('landing.ref.desc2')}
);
};
// ─── I2V Section ──────────────────────────────────────────────────────────────
const I2VSection = () => {
const { t } = useI18n();
const { isMobile } = useBreakpoint();
const [slide, setSlide] = useCarousel(I2V_SLIDES.length, 4200);
const i2vVideoRefs = React.useRef([]);
React.useEffect(() => {
i2vVideoRefs.current.forEach((v, i) => {
if (!v) return;
if (i === slide) { v.currentTime = 0; v.play().catch(() => {}); }
else { v.pause(); }
});
}, [slide]);
const cur = I2V_SLIDES[slide];
const imgPair = (
{/* Preload all first-frame images, show active */}
{I2V_SLIDES.map((s, i) => (

))}
{t('landing.i2v.firstLabel')}
{I2V_SLIDES.map((s, i) => (
);
return (
{isMobile ? (
) : null}
{t('landing.i2v.title')}
{t('landing.i2v.desc1')}
{t('landing.i2v.desc2')}
{['feat1','feat2','feat3'].map(k => (
→
{t('landing.i2v.'+k)}
))}
{!isMobile ? (
) : null}
);
};
// ─── Why Choose Us ────────────────────────────────────────────────────────────
const WhyUsSection = () => {
const { t } = useI18n();
const { isMobile, isTablet } = useBreakpoint();
const [active, setActive] = React.useState(0);
React.useEffect(() => {
const timer = setInterval(() => setActive(i => (i + 1) % 3), 3500);
return () => clearInterval(timer);
}, []);
return (
{t('landing.why.title')}
{t('landing.why.subtitle')}
{/* Stats */}
{['1','2','3','4'].map(k => (
{t('landing.why.stat'+k+'val')}
{t('landing.why.stat'+k+'label')}
))}
{/* Feature cards */}
{[{k:'1',img:FEATURE_IMGS[0]},{k:'2',img:FEATURE_IMGS[1]},{k:'3',img:FEATURE_IMGS[2]}].map((f,i) => (
setActive(i)} style={{ borderRadius: 18, overflow: 'hidden', border: '1px solid '+(active===i ? 'rgba(34,211,238,0.3)' : 'var(--line-2)'), background: active===i ? 'rgba(34,211,238,0.03)' : 'rgba(255,255,255,0.02)', cursor: 'pointer', transition: 'all .3s' }}>

{ e.target.style.display='none'; e.target.parentNode.style.background='rgba(255,255,255,0.04)'; }} />
{t('landing.why.feat'+f.k+'icon')}
{t('landing.why.feat'+f.k+'title')}
{t('landing.why.feat'+f.k+'desc')}
))}
);
};
// ─── Templates ────────────────────────────────────────────────────────────────
const TemplateSection = () => {
const { t } = useI18n();
const { isMobile, isTablet } = useBreakpoint();
const cols = isMobile ? 3 : (isTablet ? 4 : 6);
return (
{[1,2,3,4,5,6].map((n,i) => (
{ e.currentTarget.style.transform='translateY(-3px) scale(1.02)'; e.currentTarget.style.borderColor='rgba(244,114,182,0.4)'; }}
onMouseLeave={e => { e.currentTarget.style.transform=''; e.currentTarget.style.borderColor=''; }}>
{ e.target.style.display='none'; e.target.parentNode.style.background=`hsl(${i*60},40%,10%)`; }} />
{t('landing.tpl.'+n)}
{!isMobile &&
{t('landing.tpl.'+n+'en')}
}
))}
);
};
// ─── Cases — uses shared Carousel component ─────────────────────────────────
const CasesSection = () => {
const { t } = useI18n();
const { isMobile } = useBreakpoint();
const radius = isMobile ? 12 : 18;
return (
{t('landing.cases.title')}
{t('landing.cases.subtitle')}
(
)} />
);
};
// ─── Community ────────────────────────────────────────────────────────────────
const CommunitySection = () => {
const { t } = useI18n();
const { isMobile } = useBreakpoint();
return (
);
};
// ─── Testimonials ─────────────────────────────────────────────────────────────
const TestimonialsSection = () => {
const { t } = useI18n();
const { isMobile } = useBreakpoint();
const pages = isMobile ? 6 : 2;
const perPage = isMobile ? 1 : 3;
const [slide, setSlide] = useCarousel(pages, 5000);
const reviews = [1,2,3,4,5,6].map(n => ({ q: t('landing.rev.q'+n), name: t('landing.rev.n'+n), title: t('landing.rev.t'+n), avatar: USER_AVATARS[n-1] }));
return (
{t('landing.rev.title')}
{reviews.map((r, i) => {
const inPage = i >= slide * perPage && i < (slide + 1) * perPage;
return (
"
{r.q}

{ e.target.style.display='none'; e.target.parentNode.style.background='rgba(167,139,250,0.15)'; }} />
{[1,2,3,4,5].map(s => ★)}
);
})}
);
};
// ─── Pricing (dynamic from API) ──────────────────────────────────────────────
const LandingPricing = () => {
const { t } = useI18n();
const { isMobile } = useBreakpoint();
const [plans, setPlans] = React.useState(null);
const [coins, setCoins] = React.useState(null);
const [tab, setTab] = React.useState('plans');
React.useEffect(() => {
fetch('/api/v1/subscriptions/plans').then(r => r.json()).then(d => setPlans((d.items || []).sort((a, b) => (a.sort_order || 0) - (b.sort_order || 0)))).catch(() => setPlans([]));
fetch('/api/v1/subscriptions/coin-packages').then(r => r.json()).then(d => setCoins((d.items || []).sort((a, b) => (a.sort_order || 0) - (b.sort_order || 0)))).catch(() => setCoins([]));
}, []);
// Hide entire section if no data
if (plans !== null && coins !== null && plans.length === 0 && coins.length === 0) return null;
return (
{t('landing.pricingTitle')}
{t('landing.pricingSubtitle')}
{/* Tab toggle */}
{[{ id: 'plans', label: '订阅套餐' }, { id: 'coins', label: '额度充值' }].map(tb => (
))}
{tab === 'plans' ? (
/* Subscription plans */
{plans && plans.length > 0 ? (
{plans.map((p, i) => {
const isFeatured = i === 1 || p.type === 'month';
const price = p.current_price || p.base_price;
const isFree = price === 0;
return (
{isFeatured &&
Most popular
}
{p.name}
{isFree ? '$0' : '$' + price}
{!isFree && /{p.type === 'year' ? 'year' : p.type === 'week' ? 'week' : 'month'}}
{isFree ? 'Get started free' : isFeatured ? 'Start creating' : 'Subscribe'}
{p.bonus_coins > 0 && (
{p.bonus_coins.toLocaleString()} credits
)}
{p.duration_days > 0 && (
{p.duration_days} days access
)}
{p.first_purchase_price > 0 && (
First purchase ${p.first_purchase_price}
)}
);
})}
) : null}
) : (
/* Coin packages */
{coins && coins.length > 0 ? (
{coins.map(pkg => {
const total = pkg.coins + (pkg.bonus_coins || 0);
const isPopular = pkg.tag === 'popular';
return (
{pkg.tag &&
{pkg.tag === 'popular' ? 'HOT' : pkg.tag === 'recommended' ? '推荐' : pkg.tag}
}
{total.toLocaleString()}
额度
{pkg.bonus_coins > 0 &&
含赠送 {pkg.bonus_coins.toLocaleString()}
}
${pkg.amount}
购买
);
})}
) : null}
)}
);
};
// ─── CTA Banner ───────────────────────────────────────────────────────────────
const CTABanner = () => {
const { t } = useI18n();
const { isMobile } = useBreakpoint();
return (

e.target.style.display='none'} />
{t('landing.cta.title')}
{t('landing.cta.subtitle')}
);
};
// ─── FAQ ──────────────────────────────────────────────────────────────────────
const FAQSection = () => {
const { t } = useI18n();
const { isMobile } = useBreakpoint();
const [open, setOpen] = React.useState(null);
return (
{t('landing.faq.title')}
{[1,2,3,4,5,6].map(n => (
{open===n &&
{t('landing.faq.a'+n)}
}
))}
);
};
// ─── Hero Prompt Bar ──────────────────────────────────────────────────────────
const HeroPromptBar = () => {
const { t } = useI18n();
const { isMobile } = useBreakpoint();
const [mode, setMode] = React.useState('image');
const [prompt, setPrompt] = React.useState('cinematic shot of a calico cat astronaut floating above a neon Tokyo, soft volumetric light, 35mm');
return (
{[{id:'image',labelKey:'landing.imgMode',icon:'image'},{id:'video',labelKey:'landing.vidMode',icon:'video',hot:true}].map(m => (
))}
{!isMobile &&
{mode==='image' ? 'Pollo 2.5' : 'Veo 3.1'}
}
);
};
// ─── Landing Screen ───────────────────────────────────────────────────────────
const LandingScreen = ({ tweaks }) => {
const { t } = useI18n();
const { isMobile } = useBreakpoint();
const isLoggedIn = window.YiteAPI && window.YiteAPI.isLoggedIn();
const cachedUser = isLoggedIn ? window.YiteAPI.getUser() : null;
return (
{/* ── HERO ── */}
NEW
{t('landing.newBadge')}
{t('landing.heroTitle1')}
{t('landing.heroTitle2')}
{t('landing.heroSubtitle')}
{!isMobile && (
{t('landing.trustLine')}
{['MASHABLE','TECHCRUNCH','FORBES','BBC','THE VERGE'].map(b => (
{b}
))}
)}
{/* ── FOOTER ── */}
);
};
Object.assign(window, { LandingScreen });