's'
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
"use client";
|
||||
|
||||
import { useState } from "react";
|
||||
import { useRef, useState } from "react";
|
||||
import { LandingHero } from "./landing/LandingHero";
|
||||
import { AssetStats } from "./landing/AssetStats";
|
||||
import { TopicEbookShowcase } from "./landing/TopicEbookShowcase";
|
||||
@@ -31,6 +31,22 @@ export function LandingPage({
|
||||
}: LandingPageProps) {
|
||||
const [loginModalOpen, setLoginModalOpen] = useState(false);
|
||||
const [promoModalOpen, setPromoModalOpen] = useState(false);
|
||||
const [payTestMode, setPayTestMode] = useState(() => {
|
||||
if (typeof window === "undefined") return false;
|
||||
return localStorage.getItem("vipPayTestMode") === "1";
|
||||
});
|
||||
const titleTapCountRef = useRef(0);
|
||||
|
||||
const handleHeroTitleTap = () => {
|
||||
titleTapCountRef.current += 1;
|
||||
if (titleTapCountRef.current < 10) return;
|
||||
titleTapCountRef.current = 0;
|
||||
const nextMode = !payTestMode;
|
||||
setPayTestMode(nextMode);
|
||||
if (typeof window !== "undefined") {
|
||||
localStorage.setItem("vipPayTestMode", nextMode ? "1" : "0");
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -43,7 +59,7 @@ export function LandingPage({
|
||||
<div className={styles.landingNoise} />
|
||||
</div>
|
||||
<div className={styles.landingSceneInner}>
|
||||
<LandingHero />
|
||||
<LandingHero onTitleTap={handleHeroTitleTap} />
|
||||
<AssetStats />
|
||||
<TopicEbookShowcase onLockedClick={() => setLoginModalOpen(true)} />
|
||||
<CompareSection />
|
||||
@@ -54,6 +70,7 @@ export function LandingPage({
|
||||
<LandingCTA
|
||||
onJoin={onJoin}
|
||||
onLogin={() => setLoginModalOpen(true)}
|
||||
payTestMode={payTestMode}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,10 +17,19 @@ type VipHeaderProps = {
|
||||
isLoggedIn: boolean;
|
||||
userName?: string | null;
|
||||
userEmail?: string | null;
|
||||
wechatNick?: string | null;
|
||||
wechatAvatar?: string | null;
|
||||
onLogout?: () => void;
|
||||
};
|
||||
|
||||
export function VipHeader({ isLoggedIn, userName, userEmail, onLogout }: VipHeaderProps) {
|
||||
export function VipHeader({
|
||||
isLoggedIn,
|
||||
userName,
|
||||
userEmail,
|
||||
wechatNick,
|
||||
wechatAvatar,
|
||||
onLogout,
|
||||
}: VipHeaderProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -38,8 +47,9 @@ export function VipHeader({ isLoggedIn, userName, userEmail, onLogout }: VipHead
|
||||
onLogout?.();
|
||||
};
|
||||
|
||||
const showUser = isLoggedIn || userEmail;
|
||||
const displayName = userName || userEmail || "会员";
|
||||
const hasWechatProfile = !!(wechatNick || wechatAvatar);
|
||||
const showUser = isLoggedIn || !!userEmail || hasWechatProfile;
|
||||
const displayName = wechatNick || userName || userEmail || "会员";
|
||||
|
||||
return (
|
||||
<header className={styles.header}>
|
||||
@@ -54,10 +64,15 @@ export function VipHeader({ isLoggedIn, userName, userEmail, onLogout }: VipHead
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpen((o) => !o)}
|
||||
className="flex h-9 w-9 shrink-0 items-center justify-center rounded-full bg-amber-500 text-sm font-semibold text-white shadow-sm hover:bg-amber-600"
|
||||
className="flex h-9 w-9 shrink-0 items-center justify-center overflow-hidden rounded-full bg-amber-500 text-sm font-semibold text-white shadow-sm hover:bg-amber-600"
|
||||
aria-label="用户菜单"
|
||||
>
|
||||
{getAvatarLetter(displayName)}
|
||||
{wechatAvatar ? (
|
||||
// eslint-disable-next-line @next/next/no-img-element
|
||||
<img src={wechatAvatar} alt={displayName} className="h-full w-full object-cover" />
|
||||
) : (
|
||||
getAvatarLetter(displayName)
|
||||
)}
|
||||
</button>
|
||||
{isLoggedIn && (
|
||||
<span
|
||||
|
||||
@@ -9,13 +9,30 @@ type VipLayoutProps = {
|
||||
isLoggedIn: boolean;
|
||||
userName?: string | null;
|
||||
userEmail?: string | null;
|
||||
wechatNick?: string | null;
|
||||
wechatAvatar?: string | null;
|
||||
onLogout?: () => void;
|
||||
};
|
||||
|
||||
export function VipLayout({ children, isLoggedIn, userName, userEmail, onLogout }: VipLayoutProps) {
|
||||
export function VipLayout({
|
||||
children,
|
||||
isLoggedIn,
|
||||
userName,
|
||||
userEmail,
|
||||
wechatNick,
|
||||
wechatAvatar,
|
||||
onLogout,
|
||||
}: VipLayoutProps) {
|
||||
return (
|
||||
<div className={styles.root}>
|
||||
<VipHeader isLoggedIn={isLoggedIn} userName={userName} userEmail={userEmail} onLogout={onLogout} />
|
||||
<VipHeader
|
||||
isLoggedIn={isLoggedIn}
|
||||
userName={userName}
|
||||
userEmail={userEmail}
|
||||
wechatNick={wechatNick}
|
||||
wechatAvatar={wechatAvatar}
|
||||
onLogout={onLogout}
|
||||
/>
|
||||
<main className={styles.main}>{children}</main>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,22 +1,20 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState } from "react";
|
||||
import { formatRestoreDateShort } from "@/config/promo.config";
|
||||
import styles from "../vip.module.css";
|
||||
|
||||
type LandingCTAProps = {
|
||||
onJoin: () => void;
|
||||
onLogin: () => void;
|
||||
payTestMode?: boolean;
|
||||
};
|
||||
|
||||
/** 设为 true 可重新展示「适合你 / 请止步」区块(下方 JSX 与 vip.module.css 内样式均保留) */
|
||||
const SHOW_CTA_AUDIENCE_BOUNDARY = false;
|
||||
|
||||
export function LandingCTA({ onJoin, onLogin }: LandingCTAProps) {
|
||||
const [restoreDate, setRestoreDate] = useState<string>("");
|
||||
useEffect(() => {
|
||||
setRestoreDate(formatRestoreDateShort());
|
||||
}, []);
|
||||
export function LandingCTA({ onJoin, onLogin, payTestMode }: LandingCTAProps) {
|
||||
const [restoreDate] = useState<string>(() => formatRestoreDateShort());
|
||||
|
||||
return (
|
||||
<section className={`${styles.section} ${styles.ctaSection}`} aria-labelledby="cta-heading">
|
||||
@@ -74,6 +72,7 @@ export function LandingCTA({ onJoin, onLogin }: LandingCTAProps) {
|
||||
type="button"
|
||||
onClick={onJoin}
|
||||
className={`${styles.btnPrimary} ${styles.btnLarge} ${styles.ctaBtnPrimary}`}
|
||||
style={payTestMode ? { background: "linear-gradient(135deg,#16a34a,#22c55e)" } : undefined}
|
||||
>
|
||||
🔒 立即加入
|
||||
</button>
|
||||
|
||||
@@ -2,12 +2,18 @@
|
||||
|
||||
import styles from "../vip.module.css";
|
||||
|
||||
export function LandingHero() {
|
||||
type LandingHeroProps = {
|
||||
onTitleTap?: () => void;
|
||||
};
|
||||
|
||||
export function LandingHero({ onTitleTap }: LandingHeroProps) {
|
||||
return (
|
||||
<section className={`${styles.section} ${styles.heroSection} ${styles.heroSection3d}`} style={{ textAlign: "center" }}>
|
||||
<p
|
||||
className={`${styles.heroEyebrow} animate__animated animate__fadeInDown`}
|
||||
style={{ animationDelay: "0.1s", animationFillMode: "both" }}
|
||||
style={{ animationDelay: "0.1s", animationFillMode: "both", cursor: "pointer" }}
|
||||
onClick={onTitleTap}
|
||||
title="连续点击 10 次切换测试价格"
|
||||
>
|
||||
异度星球会员中心
|
||||
</p>
|
||||
|
||||
Reference in New Issue
Block a user