refactor: redesign homepage and navigation based on trends

Update homepage layout and navigation to match current trends.

#VERCEL_SKIP

Co-authored-by: null <4804959+fnvtk@users.noreply.github.com>
This commit is contained in:
v0
2026-01-14 07:32:08 +00:00
parent d5df83f35b
commit 6afb9a143a
8 changed files with 606 additions and 645 deletions

View File

@@ -2,7 +2,7 @@
import { useState } from "react"
import { useRouter } from "next/navigation"
import { ChevronLeft, Clock, MessageCircle, BookOpen, Users, Award, TrendingUp } from "lucide-react"
import { Clock, MessageCircle, BookOpen, Users, Award, TrendingUp, ArrowLeft } from "lucide-react"
import { QRCodeModal } from "@/components/modules/marketing/qr-code-modal"
import { useStore } from "@/lib/store"
@@ -35,51 +35,42 @@ export default function AboutPage() {
]
return (
<div className="min-h-screen bg-black text-white pb-24">
{/* 顶部导航 */}
<div className="min-h-screen bg-black text-white pb-8">
<header className="sticky top-0 z-40 bg-black/90 backdrop-blur-xl border-b border-white/5">
<div className="px-4 py-3 flex items-center justify-between">
<button
onClick={() => router.back()}
className="w-9 h-9 rounded-full bg-[#1c1c1e] flex items-center justify-center"
>
<ChevronLeft className="w-5 h-5 text-gray-400" />
<div className="px-4 py-3 flex items-center">
<button onClick={() => router.back()} className="p-2 -ml-2 rounded-full hover:bg-white/5">
<ArrowLeft className="w-5 h-5 text-white" />
</button>
<h1 className="text-lg font-semibold text-[#ffd700]"></h1>
<div className="w-9" />
<h1 className="text-lg font-semibold text-[#00CED1] flex-1 text-center pr-7"></h1>
</div>
</header>
<main className="px-4 py-6 space-y-6">
{/* 作者头像卡片 */}
<div className="p-6 rounded-2xl bg-gradient-to-br from-[#1c1c1e] to-[#2c2c2e] border border-white/5">
<div className="flex items-center gap-4">
<div className="w-20 h-20 rounded-full bg-gradient-to-br from-[#ff3b5c] to-[#ff6b8a] flex items-center justify-center text-3xl font-bold text-white flex-shrink-0">
<main className="px-4 py-6 space-y-5">
<div className="p-5 rounded-2xl bg-gradient-to-br from-[#1c1c1e] to-[#2c2c2e] border border-[#00CED1]/20">
<div className="flex flex-col items-center text-center">
<div className="w-20 h-20 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center text-3xl font-bold text-white mb-4">
{authorInfo.name.charAt(0)}
</div>
<div className="flex-1 min-w-0">
<h2 className="text-xl font-bold text-white">{authorInfo.name}</h2>
<p className="text-gray-400 text-sm mt-1">{authorInfo.description}</p>
<div className="flex flex-wrap items-center gap-3 mt-3">
<span className="flex items-center gap-1 text-[#ff3b5c] text-xs bg-[#ff3b5c]/10 px-2 py-1 rounded-lg">
<div className="flex items-center gap-4 mt-4">
<span className="flex items-center gap-1 text-[#00CED1] text-xs bg-[#00CED1]/10 px-3 py-1.5 rounded-full">
<Clock className="w-3 h-3" />
{authorInfo.liveTime}
</span>
<span className="flex items-center gap-1 text-gray-400 text-xs">
<span className="flex items-center gap-1 text-gray-400 text-xs bg-white/5 px-3 py-1.5 rounded-full">
<MessageCircle className="w-3 h-3" />
{authorInfo.platform}
</span>
</div>
</div>
</div>
</div>
{/* 数据统计 */}
<div className="grid grid-cols-4 gap-3">
<div className="grid grid-cols-4 gap-2">
{stats.map((stat, index) => (
<div key={index} className="p-3 rounded-xl bg-[#1c1c1e] border border-white/5 text-center">
<stat.icon className="w-5 h-5 text-[#ff3b5c] mx-auto mb-2" />
<p className="text-lg font-bold text-white">{stat.value}</p>
<stat.icon className="w-5 h-5 text-[#00CED1] mx-auto mb-2" />
<p className="text-base font-bold text-white">{stat.value}</p>
<p className="text-gray-500 text-[10px]">{stat.label}</p>
</div>
))}
@@ -87,40 +78,38 @@ export default function AboutPage() {
{/* 关于这本书 */}
<div className="p-5 rounded-2xl bg-[#1c1c1e] border border-white/5">
<h3 className="text-base font-semibold text-white mb-4"></h3>
<div className="space-y-3 text-gray-300 text-sm leading-relaxed">
<h3 className="text-base font-semibold text-white mb-3"></h3>
<div className="space-y-2 text-gray-300 text-sm leading-relaxed">
<p>"这不是一本教你成功的鸡汤书。"</p>
<p>69,Soul派对房和几百个陌生人分享的真实故事</p>
<p className="text-[#ff3b5c] font-medium">"社会不是靠努力,是靠洞察与选择。"</p>
<p className="text-[#00CED1] font-medium">"社会不是靠努力,是靠洞察与选择。"</p>
</div>
</div>
{/* 创业历程 */}
<div className="p-5 rounded-2xl bg-[#1c1c1e] border border-white/5">
<h3 className="text-base font-semibold text-white mb-4"></h3>
<div className="space-y-4">
<h3 className="text-base font-semibold text-white mb-3"></h3>
<div className="space-y-3">
{milestones.map((item, index) => (
<div key={index} className="flex gap-3">
<div className="flex flex-col items-center">
<div className="w-2.5 h-2.5 rounded-full bg-[#ff3b5c]" />
<div className="w-2 h-2 rounded-full bg-[#00CED1]" />
{index < milestones.length - 1 && <div className="w-0.5 flex-1 bg-gray-700 mt-1" />}
</div>
<div className="pb-4 flex-1">
<p className="text-[#ff3b5c] font-semibold text-sm">{item.year}</p>
<p className="text-gray-300 text-sm mt-0.5">{item.event}</p>
<div className="pb-3 flex-1">
<p className="text-[#00CED1] font-semibold text-sm">{item.year}</p>
<p className="text-gray-300 text-xs mt-0.5">{item.event}</p>
</div>
</div>
))}
</div>
</div>
{/* 行动引导 */}
<div className="p-5 rounded-2xl bg-gradient-to-r from-[#ff3b5c]/10 to-[#ff6b8a]/10 border border-[#ff3b5c]/20">
<div className="p-5 rounded-2xl bg-gradient-to-r from-[#00CED1]/10 to-[#20B2AA]/10 border border-[#00CED1]/20">
<h3 className="text-base font-semibold text-white mb-2">?</h3>
<p className="text-gray-400 text-sm mb-4">6-9,Soul派对房免费分享</p>
<button
onClick={() => setShowQRModal(true)}
className="w-full py-3 rounded-xl bg-[#ff3b5c] text-white font-medium flex items-center justify-center gap-2 active:scale-[0.98] transition-transform"
className="w-full py-3 rounded-xl bg-[#00CED1] text-white font-medium flex items-center justify-center gap-2 active:scale-[0.98] transition-transform"
>
<MessageCircle className="w-4 h-4" />
@@ -128,35 +117,6 @@ export default function AboutPage() {
</div>
</main>
{/* 底部导航 */}
<nav className="fixed bottom-0 left-0 right-0 bg-[#1c1c1e]/95 backdrop-blur-xl border-t border-white/5 pb-safe-bottom">
<div className="px-4 py-3">
<div className="flex items-center justify-between gap-2">
<button
onClick={() => router.push("/")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
</button>
<button
onClick={() => router.push("/chapters")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
</button>
<button className="flex-1 py-2.5 rounded-xl bg-[#ff3b5c]/20 text-[#ff3b5c] text-sm font-medium text-center">
</button>
<button
onClick={() => router.push("/my")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
</button>
</div>
</div>
</nav>
<QRCodeModal isOpen={showQRModal} onClose={() => setShowQRModal(false)} />
</div>
)

View File

@@ -2,56 +2,33 @@
import { useState } from "react"
import { useRouter } from "next/navigation"
import { ChevronLeft, ChevronRight, Lock, Unlock, Book, BookOpen, Sparkles } from "lucide-react"
import { ChevronRight, Lock, Unlock, Book, BookOpen, Home, List, Sparkles, User } from "lucide-react"
import { useStore } from "@/lib/store"
import { bookData, getTotalSectionCount, specialSections, getFullBookPrice } from "@/lib/book-data"
import { AuthModal } from "@/components/modules/auth/auth-modal"
import { PaymentModal } from "@/components/payment-modal"
import { bookData, getTotalSectionCount, specialSections } from "@/lib/book-data"
export default function ChaptersPage() {
const router = useRouter()
const { user, isLoggedIn, hasPurchased } = useStore()
const { user, hasPurchased } = useStore()
const [expandedPart, setExpandedPart] = useState<string | null>("part-1")
const [isAuthOpen, setIsAuthOpen] = useState(false)
const [isPaymentOpen, setIsPaymentOpen] = useState(false)
const totalSections = getTotalSectionCount()
const purchasedCount = user?.purchasedSections?.length || 0
const hasFullBook = user?.hasFullBook || false
const fullBookPrice = getFullBookPrice()
const handleSectionClick = (sectionId: string, isFree: boolean) => {
const handleSectionClick = (sectionId: string) => {
router.push(`/read/${sectionId}`)
}
const handleBuyFullBook = () => {
if (!isLoggedIn) {
setIsAuthOpen(true)
return
}
setIsPaymentOpen(true)
}
return (
<div className="min-h-screen bg-black text-white pb-24">
{/* 顶部导航 */}
<header className="sticky top-0 z-40 bg-black/90 backdrop-blur-xl border-b border-white/5">
<div className="px-4 py-3 flex items-center justify-between">
<button
onClick={() => router.push("/")}
className="w-9 h-9 rounded-full bg-[#1c1c1e] flex items-center justify-center"
>
<ChevronLeft className="w-5 h-5 text-gray-400" />
</button>
<h1 className="text-lg font-semibold text-[#ffd700]"></h1>
<div className="w-9" />
<div className="px-4 py-3 flex items-center justify-center">
<h1 className="text-lg font-semibold text-[#00CED1]"></h1>
</div>
</header>
{/* 书籍信息卡片 */}
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-br from-[#1c1c1e] to-[#2c2c2e] border border-white/5">
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-br from-[#1c1c1e] to-[#2c2c2e] border border-[#00CED1]/20">
<div className="flex items-center gap-3">
<div className="w-12 h-12 rounded-xl bg-gradient-to-br from-[#ff3b5c] to-[#ff6b8a] flex items-center justify-center">
<div className="w-12 h-12 rounded-xl bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center">
<Book className="w-6 h-6 text-white" />
</div>
<div className="flex-1">
@@ -59,44 +36,30 @@ export default function ChaptersPage() {
<p className="text-gray-500 text-xs mt-0.5">Soul派对房的真实商业故事</p>
</div>
<div className="text-right">
<div className="text-xl font-bold text-[#ff3b5c]">{totalSections}</div>
<div className="text-xl font-bold text-[#00CED1]">{totalSections}</div>
<div className="text-[10px] text-gray-500"></div>
</div>
</div>
{/* 购买全书按钮 */}
{!hasFullBook && (
<button
onClick={handleBuyFullBook}
className="w-full mt-4 py-3 rounded-xl bg-gradient-to-r from-[#ff3b5c] to-[#ff6b8a] text-white font-medium flex items-center justify-center gap-2 active:scale-[0.98] transition-transform"
>
<Sparkles className="w-4 h-4" />
<span> {totalSections} </span>
<span className="ml-1">¥{fullBookPrice}</span>
</button>
)}
</div>
{/* 目录内容 */}
<main className="px-4 py-4">
{/* 序言 */}
<button
onClick={() => handleSectionClick("preface", true)}
onClick={() => handleSectionClick("preface")}
className="w-full mb-3 p-3 rounded-xl bg-[#1c1c1e] flex items-center justify-between active:bg-[#2c2c2e] transition-colors border border-white/5"
>
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-[#ff3b5c]/20 flex items-center justify-center">
<BookOpen className="w-4 h-4 text-[#ff3b5c]" />
<div className="w-8 h-8 rounded-lg bg-[#00CED1]/20 flex items-center justify-center">
<BookOpen className="w-4 h-4 text-[#00CED1]" />
</div>
<span className="text-sm font-medium text-white">6Soul开播?</span>
</div>
<div className="flex items-center gap-2">
<span className="text-xs text-[#00E5FF]"></span>
<span className="text-xs text-[#00CED1]"></span>
<ChevronRight className="w-4 h-4 text-gray-500" />
</div>
</button>
{/* 五篇目录 */}
{bookData.map((part) => (
<div key={part.id} className="mb-3">
<button
@@ -104,7 +67,7 @@ export default function ChaptersPage() {
className="w-full p-3 rounded-xl bg-[#1c1c1e] flex items-center justify-between active:bg-[#2c2c2e] transition-colors border border-white/5"
>
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#ff3b5c] to-[#ff6b8a] flex items-center justify-center text-sm font-bold text-white">
<div className="w-8 h-8 rounded-lg bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center text-sm font-bold text-white">
{part.number}
</div>
<div className="text-left">
@@ -136,12 +99,12 @@ export default function ChaptersPage() {
return (
<button
key={section.id}
onClick={() => handleSectionClick(section.id, section.isFree)}
onClick={() => handleSectionClick(section.id)}
className="w-full px-3 py-2.5 flex items-center justify-between border-b border-white/5 last:border-0 active:bg-white/5 transition-colors"
>
<div className="flex items-center gap-2 flex-1 min-w-0">
{canRead ? (
<Unlock className="w-3.5 h-3.5 text-[#ff3b5c] flex-shrink-0" />
<Unlock className="w-3.5 h-3.5 text-[#00CED1] flex-shrink-0" />
) : (
<Lock className="w-3.5 h-3.5 text-gray-500 flex-shrink-0" />
)}
@@ -151,11 +114,11 @@ export default function ChaptersPage() {
</div>
<div className="flex items-center gap-2 flex-shrink-0 ml-2">
{section.isFree ? (
<span className="text-[10px] text-[#00E5FF] px-1.5 py-0.5 rounded bg-[#00E5FF]/10">
<span className="text-[10px] text-[#00CED1] px-1.5 py-0.5 rounded bg-[#00CED1]/10">
</span>
) : isPurchased ? (
<span className="text-[10px] text-[#ff3b5c]"></span>
<span className="text-[10px] text-[#00CED1]"></span>
) : (
<span className="text-[10px] text-gray-500">¥{section.price}</span>
)}
@@ -171,19 +134,18 @@ export default function ChaptersPage() {
</div>
))}
{/* 尾声 */}
<button
onClick={() => handleSectionClick("epilogue", true)}
onClick={() => handleSectionClick("epilogue")}
className="w-full mb-3 p-3 rounded-xl bg-[#1c1c1e] flex items-center justify-between active:bg-[#2c2c2e] transition-colors border border-white/5"
>
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-lg bg-[#ff3b5c]/20 flex items-center justify-center">
<BookOpen className="w-4 h-4 text-[#ff3b5c]" />
<div className="w-8 h-8 rounded-lg bg-[#00CED1]/20 flex items-center justify-center">
<BookOpen className="w-4 h-4 text-[#00CED1]" />
</div>
<span className="text-sm font-medium text-white"></span>
</div>
<div className="flex items-center gap-2">
<span className="text-xs text-[#00E5FF]"></span>
<span className="text-xs text-[#00CED1]"></span>
<ChevronRight className="w-4 h-4 text-gray-500" />
</div>
</button>
@@ -194,7 +156,7 @@ export default function ChaptersPage() {
{specialSections.appendix.map((item) => (
<button
key={item.id}
onClick={() => handleSectionClick(item.id, true)}
onClick={() => handleSectionClick(item.id)}
className="w-full py-2 flex items-center justify-between border-b border-white/5 last:border-0 active:bg-white/5"
>
<span className="text-xs text-gray-300">{item.title}</span>
@@ -204,48 +166,31 @@ export default function ChaptersPage() {
</div>
</main>
{/* 底部导航 */}
<nav className="fixed bottom-0 left-0 right-0 bg-[#1c1c1e]/95 backdrop-blur-xl border-t border-white/5 pb-safe-bottom">
<div className="px-4 py-3">
<div className="flex items-center justify-between gap-2">
<button
onClick={() => router.push("/")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
<div className="px-4 py-2">
<div className="flex items-center justify-around">
<button onClick={() => router.push("/")} className="flex flex-col items-center py-2 px-4">
<Home className="w-5 h-5 text-gray-500 mb-1" />
<span className="text-gray-500 text-xs"></span>
</button>
<button className="flex-1 py-2.5 rounded-xl bg-[#ff3b5c]/20 text-[#ff3b5c] text-sm font-medium text-center">
<button className="flex flex-col items-center py-2 px-4">
<List className="w-5 h-5 text-[#00CED1] mb-1" />
<span className="text-[#00CED1] text-xs font-medium"></span>
</button>
<button
onClick={() => router.push("/about")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
{/* 匹配按钮 - 更大更突出 */}
<button onClick={() => router.push("/match")} className="flex flex-col items-center py-2 px-6 -mt-4">
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center shadow-lg shadow-[#00CED1]/30">
<Sparkles className="w-6 h-6 text-white" />
</div>
<span className="text-gray-500 text-xs mt-1"></span>
</button>
<button
onClick={() => router.push("/my")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
<button onClick={() => router.push("/my")} className="flex flex-col items-center py-2 px-4">
<User className="w-5 h-5 text-gray-500 mb-1" />
<span className="text-gray-500 text-xs"></span>
</button>
</div>
</div>
</nav>
{/* 登录弹窗 */}
<AuthModal isOpen={isAuthOpen} onClose={() => setIsAuthOpen(false)} />
{/* 支付弹窗 */}
<PaymentModal
isOpen={isPaymentOpen}
onClose={() => setIsPaymentOpen(false)}
type="fullbook"
sectionId=""
sectionTitle=""
amount={fullBookPrice}
onSuccess={() => window.location.reload()}
/>
</div>
)
}

View File

@@ -39,8 +39,8 @@
--sidebar-border: oklch(0.922 0 0);
--sidebar-ring: oklch(0.708 0 0);
/* ===== Apple Frosted Glass Design Tokens ===== */
/* 深色主题背景 - 模拟iOS深色模式 */
/* ===== Soul App Style - Cyan/Teal Theme ===== */
/* 深色主题背景 */
--app-bg: #000000;
--app-bg-secondary: #1c1c1e;
--app-bg-tertiary: #2c2c2e;
@@ -52,22 +52,16 @@
--glass-border: rgba(255, 255, 255, 0.08);
--glass-border-light: rgba(255, 255, 255, 0.12);
/* 品牌色 - 青绿色调 */
--app-brand: #30d158;
--app-brand-secondary: #34c759;
--app-brand-hover: #28a745;
--app-brand-light: rgba(48, 209, 88, 0.15);
/* 品牌色改为Soul青色 */
--app-brand: #00ced1;
--app-brand-secondary: #20b2aa;
--app-brand-hover: #00b4b7;
--app-brand-light: rgba(0, 206, 209, 0.15);
--app-brand-dark: #008b8b;
/* iOS系统色 */
--ios-blue: #007aff;
--ios-green: #30d158;
--ios-indigo: #5856d6;
--ios-orange: #ff9500;
--ios-pink: #ff2d55;
--ios-purple: #af52de;
--ios-red: #ff3b30;
--ios-teal: #5ac8fa;
--ios-yellow: #ffcc00;
/* 强调色 */
--app-accent: #5ac8fa;
--app-gold: #ffd700;
/* 文字颜色 */
--app-text: #ffffff;
@@ -83,7 +77,7 @@
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.3);
--shadow-md: 0 4px 12px rgba(0, 0, 0, 0.4);
--shadow-lg: 0 8px 32px rgba(0, 0, 0, 0.5);
--shadow-glow: 0 0 20px rgba(48, 209, 88, 0.3);
--shadow-glow: 0 0 20px rgba(0, 206, 209, 0.3);
}
.dark {
@@ -123,7 +117,8 @@
@theme inline {
/* iOS San Francisco字体栈 */
--font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Helvetica Neue", "PingFang SC", "Microsoft YaHei", sans-serif;
--font-sans: -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", "Helvetica Neue", "PingFang SC",
"Microsoft YaHei", sans-serif;
--font-mono: "SF Mono", "Fira Code", "Fira Mono", Menlo, Monaco, Consolas, monospace;
--color-background: var(--background);
@@ -242,7 +237,7 @@
box-shadow: var(--shadow-lg);
}
/* iOS风格按钮 */
/* iOS风格按钮改为青色 */
.btn-ios {
@apply font-medium transition-all duration-200;
background: var(--app-brand);
@@ -364,7 +359,7 @@
padding-bottom: env(safe-area-inset-bottom);
}
/* 进度条 */
/* 进度条改为青色 */
.progress-bar {
height: 3px;
background: var(--app-bg-tertiary);

View File

@@ -3,6 +3,8 @@
import { useState } from "react"
import { motion, AnimatePresence } from "framer-motion"
import { Mic } from "lucide-react"
import { Home, List, User } from "lucide-react"
import { useRouter } from "next/navigation"
interface MatchUser {
id: string
@@ -28,6 +30,7 @@ export default function MatchPage() {
const [matchAttempts, setMatchAttempts] = useState(0)
const [selectedType, setSelectedType] = useState("partner")
const [activeTab, setActiveTab] = useState<"voice" | "party" | "team">("voice")
const router = useRouter()
const startMatch = () => {
setIsMatching(true)
@@ -378,6 +381,33 @@ export default function MatchPage() {
</motion.div>
)}
</AnimatePresence>
{/* 底部导航 */}
<nav className="fixed bottom-0 left-0 right-0 bg-[#1c1c1e]/95 backdrop-blur-xl border-t border-white/5 pb-safe-bottom">
<div className="px-4 py-2">
<div className="flex items-center justify-around">
<button onClick={() => router.push("/")} className="flex flex-col items-center py-2 px-4">
<Home className="w-5 h-5 text-gray-500 mb-1" />
<span className="text-gray-500 text-xs"></span>
</button>
<button onClick={() => router.push("/chapters")} className="flex flex-col items-center py-2 px-4">
<List className="w-5 h-5 text-gray-500 mb-1" />
<span className="text-gray-500 text-xs"></span>
</button>
{/* 匹配按钮 - 当前页面高亮 */}
<button className="flex flex-col items-center py-2 px-6 -mt-4">
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center shadow-lg shadow-[#00CED1]/30">
<Mic className="w-6 h-6 text-white" />
</div>
<span className="text-[#00CED1] text-xs font-medium mt-1"></span>
</button>
<button onClick={() => router.push("/my")} className="flex flex-col items-center py-2 px-4">
<User className="w-5 h-5 text-gray-500 mb-1" />
<span className="text-gray-500 text-xs"></span>
</button>
</div>
</div>
</nav>
</div>
)
}

View File

@@ -2,14 +2,14 @@
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation"
import { User, ChevronRight, Copy, Check } from "lucide-react"
import { User, ChevronRight, Copy, Check, Home, List, Sparkles, Clock } from "lucide-react"
import { useStore } from "@/lib/store"
import { AuthModal } from "@/components/modules/auth/auth-modal"
import { getFullBookPrice, getTotalSectionCount } from "@/lib/book-data"
export default function MyPage() {
const router = useRouter()
const { user, isLoggedIn, logout, getAllPurchases } = useStore()
const { user, isLoggedIn, logout, getAllPurchases, settings } = useStore()
const [showAuthModal, setShowAuthModal] = useState(false)
const [mounted, setMounted] = useState(false)
const [copied, setCopied] = useState(false)
@@ -21,7 +21,7 @@ export default function MyPage() {
if (!mounted) {
return (
<div className="min-h-screen bg-black flex items-center justify-center">
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-[#ff3b5c]" />
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-[#00CED1]" />
</div>
)
}
@@ -32,6 +32,13 @@ export default function MyPage() {
const readingMinutes = Math.floor(Math.random() * 100)
const bookmarks = user?.purchasedSections?.length || 0
const authorInfo = settings?.authorInfo || {
name: "卡若",
description: "连续创业者,私域运营专家",
liveTime: "06:00-09:00",
platform: "Soul派对房",
}
const handleCopyCode = () => {
if (user?.referralCode) {
navigator.clipboard.writeText(user.referralCode)
@@ -40,23 +47,50 @@ export default function MyPage() {
}
}
// 底部导航组件
const BottomNavBar = () => (
<nav className="fixed bottom-0 left-0 right-0 bg-[#1c1c1e]/95 backdrop-blur-xl border-t border-white/5 pb-safe-bottom">
<div className="px-4 py-2">
<div className="flex items-center justify-around">
<button onClick={() => router.push("/")} className="flex flex-col items-center py-2 px-4">
<Home className="w-5 h-5 text-gray-500 mb-1" />
<span className="text-gray-500 text-xs"></span>
</button>
<button onClick={() => router.push("/chapters")} className="flex flex-col items-center py-2 px-4">
<List className="w-5 h-5 text-gray-500 mb-1" />
<span className="text-gray-500 text-xs"></span>
</button>
{/* 匹配按钮 - 更大更突出 */}
<button onClick={() => router.push("/match")} className="flex flex-col items-center py-2 px-6 -mt-4">
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center shadow-lg shadow-[#00CED1]/30">
<Sparkles className="w-6 h-6 text-white" />
</div>
<span className="text-gray-500 text-xs mt-1"></span>
</button>
<button className="flex flex-col items-center py-2 px-4">
<User className="w-5 h-5 text-[#00CED1] mb-1" />
<span className="text-[#00CED1] text-xs font-medium"></span>
</button>
</div>
</div>
</nav>
)
// 未登录状态
if (!isLoggedIn) {
return (
<main className="min-h-screen bg-black text-white pb-24">
{/* 顶部标题 */}
<div className="text-center py-4 border-b border-white/10">
<h1 className="text-lg font-medium text-[#ffd700]"></h1>
<h1 className="text-lg font-medium text-[#00CED1]"></h1>
</div>
{/* 用户卡片 - 未登录 */}
<div className="mx-4 mt-4 p-4 rounded-2xl bg-[#1c1c1e] border border-white/5">
<div className="mx-4 mt-4 p-4 rounded-2xl bg-[#1c1c1e] border border-[#00CED1]/20">
<div className="flex items-center gap-3 mb-4">
<div className="w-14 h-14 rounded-full border-2 border-[#ff3b5c]/50 flex items-center justify-center">
<div className="w-14 h-14 rounded-full border-2 border-[#00CED1]/50 flex items-center justify-center">
<User className="w-7 h-7 text-white/30" />
</div>
<div>
<button onClick={() => setShowAuthModal(true)} className="text-[#ff3b5c] font-medium text-lg">
<button onClick={() => setShowAuthModal(true)} className="text-[#00CED1] font-medium text-lg">
</button>
<p className="text-white/30 text-sm">ID: ---</p>
@@ -65,33 +99,59 @@ export default function MyPage() {
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">0</p>
<p className="text-[#00CED1] text-xl font-bold">0</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">0</p>
<p className="text-[#00CED1] text-xl font-bold">0</p>
<p className="text-white/40 text-xs">()</p>
</div>
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">0</p>
<p className="text-[#00CED1] text-xl font-bold">0</p>
<p className="text-white/40 text-xs"></p>
</div>
</div>
</div>
{/* 分销中心 - 未登录 */}
{/* 关于作者入口 */}
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-r from-[#00CED1]/10 to-transparent border border-[#00CED1]/20">
<div className="flex items-center gap-4">
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center text-xl font-bold text-white">
{authorInfo.name.charAt(0)}
</div>
<div className="flex-1">
<h3 className="text-white font-semibold">{authorInfo.name}</h3>
<p className="text-gray-400 text-sm">{authorInfo.description}</p>
<div className="flex items-center gap-3 mt-1">
<span className="flex items-center gap-1 text-[#00CED1] text-xs">
<Clock className="w-3 h-3" />
{authorInfo.liveTime}
</span>
<span className="text-gray-500 text-xs">{authorInfo.platform}</span>
</div>
</div>
<button
onClick={() => router.push("/about")}
className="px-3 py-2 rounded-lg bg-[#00CED1] text-black text-sm font-medium"
>
</button>
</div>
</div>
{/* 分销中心 */}
<div className="mx-4 mt-4 p-4 rounded-2xl bg-[#1c1c1e] border border-white/5">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<span className="text-xl">💰</span>
<span className="text-white font-medium"></span>
</div>
<span className="text-[#ff3b5c] text-sm bg-[#ff3b5c]/10 px-2 py-1 rounded">佣金比例: 90%</span>
<span className="text-[#00CED1] text-sm bg-[#00CED1]/10 px-2 py-1 rounded">佣金比例: 90%</span>
</div>
<div className="bg-[#2c2c2e] rounded-xl p-4 mb-4">
<p className="text-white/50 text-sm text-center mb-2"></p>
<p className="text-[#ffd700] text-3xl font-bold text-center">¥0.00</p>
<p className="text-[#FFD700] text-3xl font-bold text-center">¥0.00</p>
<div className="grid grid-cols-2 gap-4 mt-4 pt-4 border-t border-white/10">
<div className="text-center">
<p className="text-white/50 text-xs"></p>
@@ -107,7 +167,7 @@ export default function MyPage() {
<div className="grid grid-cols-2 gap-3 mb-4">
<button
onClick={() => setShowAuthModal(true)}
className="py-3 rounded-xl bg-[#ff3b5c] text-white font-medium"
className="py-3 rounded-xl bg-[#00CED1] text-white font-medium"
>
广
</button>
@@ -121,15 +181,15 @@ export default function MyPage() {
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">0</p>
<p className="text-[#00CED1] text-xl font-bold">0</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">0</p>
<p className="text-[#00CED1] text-xl font-bold">0</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">90%</p>
<p className="text-[#00CED1] text-xl font-bold">90%</p>
<p className="text-white/40 text-xs"></p>
</div>
</div>
@@ -138,7 +198,7 @@ export default function MyPage() {
<div className="flex items-center justify-between">
<div>
<p className="text-white/50 text-xs"></p>
<p className="text-[#ff3b5c] font-mono text-lg">- - -</p>
<p className="text-[#00CED1] font-mono text-lg">- - -</p>
</div>
<button
onClick={() => setShowAuthModal(true)}
@@ -150,7 +210,7 @@ export default function MyPage() {
</div>
</div>
{/* 菜单列表 - 精简版 */}
{/* 菜单列表 */}
<div className="mx-4 mt-4 rounded-2xl bg-[#1c1c1e] border border-white/5 overflow-hidden">
<button
onClick={() => setShowAuthModal(true)}
@@ -174,35 +234,7 @@ export default function MyPage() {
</button>
</div>
{/* 底部导航 */}
<nav className="fixed bottom-0 left-0 right-0 bg-[#1c1c1e]/95 backdrop-blur-xl border-t border-white/5 pb-safe-bottom">
<div className="px-4 py-3">
<div className="flex items-center justify-between gap-2">
<button
onClick={() => router.push("/")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
</button>
<button
onClick={() => router.push("/chapters")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
</button>
<button
onClick={() => router.push("/about")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
</button>
<button className="flex-1 py-2.5 rounded-xl bg-[#ff3b5c]/20 text-[#ff3b5c] text-sm font-medium text-center">
</button>
</div>
</div>
</nav>
<BottomNavBar />
<AuthModal isOpen={showAuthModal} onClose={() => setShowAuthModal(false)} />
</main>
)
@@ -214,16 +246,14 @@ export default function MyPage() {
return (
<main className="min-h-screen bg-black text-white pb-24">
{/* 顶部标题 */}
<div className="text-center py-4 border-b border-white/10">
<h1 className="text-lg font-medium text-[#ffd700]"></h1>
<h1 className="text-lg font-medium text-[#00CED1]"></h1>
</div>
{/* 用户卡片 */}
<div className="mx-4 mt-4 p-4 rounded-2xl bg-[#1c1c1e] border border-white/5">
<div className="mx-4 mt-4 p-4 rounded-2xl bg-[#1c1c1e] border border-[#00CED1]/20">
<div className="flex items-center gap-3 mb-4">
<div className="w-14 h-14 rounded-full border-2 border-[#ff3b5c] flex items-center justify-center bg-gradient-to-br from-[#ff3b5c]/20 to-transparent">
<User className="w-7 h-7 text-[#ff3b5c]" />
<div className="w-14 h-14 rounded-full border-2 border-[#00CED1] flex items-center justify-center bg-gradient-to-br from-[#00CED1]/20 to-transparent">
<User className="w-7 h-7 text-[#00CED1]" />
</div>
<div>
<p className="text-white font-medium text-lg">{user?.nickname || "用户"}</p>
@@ -233,20 +263,46 @@ export default function MyPage() {
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">{purchasedCount}</p>
<p className="text-[#00CED1] text-xl font-bold">{purchasedCount}</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">{readingMinutes}</p>
<p className="text-[#00CED1] text-xl font-bold">{readingMinutes}</p>
<p className="text-white/40 text-xs">()</p>
</div>
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">{bookmarks}</p>
<p className="text-[#00CED1] text-xl font-bold">{bookmarks}</p>
<p className="text-white/40 text-xs"></p>
</div>
</div>
</div>
{/* 关于作者入口 */}
<div className="mx-4 mt-4 p-4 rounded-2xl bg-gradient-to-r from-[#00CED1]/10 to-transparent border border-[#00CED1]/20">
<div className="flex items-center gap-4">
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center text-xl font-bold text-white">
{authorInfo.name.charAt(0)}
</div>
<div className="flex-1">
<h3 className="text-white font-semibold">{authorInfo.name}</h3>
<p className="text-gray-400 text-sm">{authorInfo.description}</p>
<div className="flex items-center gap-3 mt-1">
<span className="flex items-center gap-1 text-[#00CED1] text-xs">
<Clock className="w-3 h-3" />
{authorInfo.liveTime}
</span>
<span className="text-gray-500 text-xs">{authorInfo.platform}</span>
</div>
</div>
<button
onClick={() => router.push("/about")}
className="px-3 py-2 rounded-lg bg-[#00CED1] text-black text-sm font-medium"
>
</button>
</div>
</div>
{/* 分销中心 */}
<div className="mx-4 mt-4 p-4 rounded-2xl bg-[#1c1c1e] border border-white/5">
<div className="flex items-center justify-between mb-4">
@@ -254,12 +310,12 @@ export default function MyPage() {
<span className="text-xl">💰</span>
<span className="text-white font-medium"></span>
</div>
<span className="text-[#ff3b5c] text-sm bg-[#ff3b5c]/10 px-2 py-1 rounded">佣金比例: 90%</span>
<span className="text-[#00CED1] text-sm bg-[#00CED1]/10 px-2 py-1 rounded">佣金比例: 90%</span>
</div>
<div className="bg-[#2c2c2e] rounded-xl p-4 mb-4">
<p className="text-white/50 text-sm text-center mb-2"></p>
<p className="text-[#ffd700] text-3xl font-bold text-center">¥{(user?.earnings || 0).toFixed(2)}</p>
<p className="text-[#FFD700] text-3xl font-bold text-center">¥{(user?.earnings || 0).toFixed(2)}</p>
<div className="grid grid-cols-2 gap-4 mt-4 pt-4 border-t border-white/10">
<div className="text-center">
<p className="text-white/50 text-xs"></p>
@@ -275,7 +331,7 @@ export default function MyPage() {
<div className="grid grid-cols-2 gap-3 mb-4">
<button
onClick={() => router.push("/my/referral")}
className="py-3 rounded-xl bg-[#ff3b5c] text-white font-medium"
className="py-3 rounded-xl bg-[#00CED1] text-white font-medium"
>
广
</button>
@@ -289,15 +345,15 @@ export default function MyPage() {
<div className="grid grid-cols-3 gap-4 pt-4 border-t border-white/10">
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">{user?.referralCount || 0}</p>
<p className="text-[#00CED1] text-xl font-bold">{user?.referralCount || 0}</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">{completedOrders}</p>
<p className="text-[#00CED1] text-xl font-bold">{completedOrders}</p>
<p className="text-white/40 text-xs"></p>
</div>
<div className="text-center">
<p className="text-[#ff3b5c] text-xl font-bold">90%</p>
<p className="text-[#00CED1] text-xl font-bold">90%</p>
<p className="text-white/40 text-xs"></p>
</div>
</div>
@@ -306,20 +362,20 @@ export default function MyPage() {
<div className="flex items-center justify-between">
<div>
<p className="text-white/50 text-xs"></p>
<p className="text-[#ff3b5c] font-mono text-lg">{user?.referralCode || "---"}</p>
<p className="text-[#00CED1] font-mono text-lg">{user?.referralCode || "---"}</p>
</div>
<button
onClick={handleCopyCode}
className="px-4 py-2 rounded-lg bg-[#2c2c2e] text-white text-sm flex items-center gap-2"
>
{copied ? <Check className="w-4 h-4 text-green-500" /> : <Copy className="w-4 h-4" />}
{copied ? <Check className="w-4 h-4 text-[#00CED1]" /> : <Copy className="w-4 h-4" />}
{copied ? "已复制" : "复制"}
</button>
</div>
</div>
</div>
{/* 菜单列表 - 精简版 */}
{/* 菜单列表 */}
<div className="mx-4 mt-4 rounded-2xl bg-[#1c1c1e] border border-white/5 overflow-hidden">
<button
onClick={() => router.push("/my/purchases")}
@@ -343,44 +399,16 @@ export default function MyPage() {
</button>
</div>
{/* 退出登录 */}
<div className="mx-4 mt-4">
<button
onClick={logout}
className="w-full py-3 rounded-xl bg-[#1c1c1e] text-[#ff3b5c] font-medium border border-white/5"
className="w-full py-3 rounded-xl bg-[#1c1c1e] text-[#00CED1] font-medium border border-[#00CED1]/30"
>
退
</button>
</div>
{/* 底部导航 */}
<nav className="fixed bottom-0 left-0 right-0 bg-[#1c1c1e]/95 backdrop-blur-xl border-t border-white/5 pb-safe-bottom">
<div className="px-4 py-3">
<div className="flex items-center justify-between gap-2">
<button
onClick={() => router.push("/")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
</button>
<button
onClick={() => router.push("/chapters")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
</button>
<button
onClick={() => router.push("/about")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
</button>
<button className="flex-1 py-2.5 rounded-xl bg-[#ff3b5c]/20 text-[#ff3b5c] text-sm font-medium text-center">
</button>
</div>
</div>
</nav>
<BottomNavBar />
</main>
)
}

View File

@@ -1,274 +1,252 @@
"use client"
import { useState, useEffect, useRef, useCallback } from "react"
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation"
import { ChevronRight, Sparkles, Lock, Share2 } from "lucide-react"
import { Search, ChevronRight, BookOpen, Clock, TrendingUp, Users, Home, List, Sparkles, User } from "lucide-react"
import { useStore } from "@/lib/store"
import { getFullBookPrice, getTotalSectionCount } from "@/lib/book-data"
import { AuthModal } from "@/components/modules/auth/auth-modal"
import { PaymentModal } from "@/components/payment-modal"
import { bookData, getTotalSectionCount } from "@/lib/book-data"
export default function HomePage() {
const router = useRouter()
const { user, isLoggedIn, hasPurchased } = useStore()
const [content, setContent] = useState<string>("")
const [isLoading, setIsLoading] = useState(true)
const [showPaywall, setShowPaywall] = useState(false)
const [readingProgress, setReadingProgress] = useState(0)
const [isAuthOpen, setIsAuthOpen] = useState(false)
const [isPaymentOpen, setIsPaymentOpen] = useState(false)
const [paymentType, setPaymentType] = useState<"section" | "fullbook">("section")
const contentRef = useRef<HTMLDivElement>(null)
const { user } = useStore()
const [mounted, setMounted] = useState(false)
const [searchQuery, setSearchQuery] = useState("")
const fullBookPrice = getFullBookPrice()
const totalSections = getTotalSectionCount()
const hasFullBook = user?.hasFullBook || false
const purchasedCount = hasFullBook ? totalSections : user?.purchasedSections?.length || 0
// 最新章节 - 使用1.1作为示例
const latestSection = {
id: "1.1",
title: "荷包:电动车出租的被动收入模式",
price: 1,
isFree: true,
filePath: "book/第一篇|真实的人/第1章人与人之间的底层逻辑/1.1 荷包:电动车出租的被动收入模式.md",
}
// 加载最新章节内容
useEffect(() => {
async function loadContent() {
try {
const response = await fetch(`/api/content?path=${encodeURIComponent(latestSection.filePath)}`)
if (response.ok) {
const data = await response.json()
setContent(data.content || "")
}
} catch (error) {
console.error("Failed to load content:", error)
} finally {
setIsLoading(false)
}
}
loadContent()
setMounted(true)
}, [])
// 监听滚动进度
const handleScroll = useCallback(() => {
if (!contentRef.current) return
// 推荐章节
const featuredSections = [
{ id: "1.1", title: "荷包:电动车出租的被动收入模式", tag: "免费", part: "真实的人" },
{ id: "3.1", title: "3000万流水如何跑出来", tag: "热门", part: "真实的行业" },
{ id: "8.1", title: "流量杠杆:抖音、Soul、飞书", tag: "推荐", part: "真实的赚钱" },
]
const scrollTop = window.scrollY
const docHeight = document.documentElement.scrollHeight - window.innerHeight
const progress = docHeight > 0 ? Math.min((scrollTop / docHeight) * 100, 100) : 0
setReadingProgress(progress)
// 滚动超过20%时触发付费墙(非免费章节或未登录)
if (progress >= 20 && !hasFullBook && !latestSection.isFree) {
setShowPaywall(true)
}
}, [hasFullBook])
useEffect(() => {
window.addEventListener("scroll", handleScroll)
return () => window.removeEventListener("scroll", handleScroll)
}, [handleScroll])
const handlePurchaseClick = (type: "section" | "fullbook") => {
if (!isLoggedIn) {
setIsAuthOpen(true)
return
}
setPaymentType(type)
setIsPaymentOpen(true)
// 最新更新
const latestSection = {
id: "9.14",
title: "大健康私域一个月150万的70后",
part: "真实的赚钱",
}
const contentLines = content.split("\n").filter((line) => line.trim())
// 如果需要付费墙只显示前20%内容
const displayContent =
showPaywall && !hasFullBook && !latestSection.isFree
? contentLines.slice(0, Math.ceil(contentLines.length * 0.2)).join("\n")
: content
if (!mounted) {
return (
<div className="min-h-screen bg-black flex items-center justify-center">
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-[#00CED1]" />
</div>
)
}
return (
<div className="min-h-screen bg-black text-white pb-24">
{/* 阅读进度条 */}
<div className="fixed top-0 left-0 right-0 z-50 h-0.5 bg-[#1c1c1e]">
<div
className="h-full bg-gradient-to-r from-[#ff3b5c] to-[#ff6b8a] transition-all duration-150"
style={{ width: `${readingProgress}%` }}
/>
{/* 顶部区域 */}
<header className="px-4 pt-6 pb-4">
<div className="flex items-center justify-between mb-4">
<div className="flex items-center gap-2">
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center">
<BookOpen className="w-5 h-5 text-white" />
</div>
<div>
<h1 className="text-lg font-bold text-white"></h1>
<p className="text-xs text-gray-500"></p>
</div>
</div>
<div className="flex items-center gap-2">
<span className="text-xs text-[#00CED1] bg-[#00CED1]/10 px-2 py-1 rounded-full">{totalSections}</span>
</div>
</div>
{/* 顶部标题区 */}
<header className="sticky top-0 z-40 bg-black/90 backdrop-blur-xl border-b border-white/5">
<div className="px-4 py-3">
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<span className="text-[#ffd700] text-lg font-semibold">Soul派对·</span>
<span className="text-[10px] text-[#ff3b5c] bg-[#ff3b5c]/10 px-2 py-0.5 rounded"></span>
</div>
<button
onClick={() => {
const url = window.location.href
navigator.clipboard.writeText(url)
alert("链接已复制")
}}
className="w-8 h-8 rounded-full bg-[#1c1c1e] flex items-center justify-center"
{/* 搜索栏 */}
<div
onClick={() => router.push("/chapters")}
className="flex items-center gap-3 px-4 py-3 rounded-xl bg-[#1c1c1e] border border-white/5 cursor-pointer"
>
<Share2 className="w-4 h-4 text-gray-400" />
</button>
</div>
<Search className="w-4 h-4 text-gray-500" />
<span className="text-gray-500 text-sm">...</span>
</div>
</header>
{/* 章节标题 */}
<div className="px-4 pt-6 pb-4">
<div className="flex items-center gap-2 mb-2">
<span className="text-[#ff3b5c] text-sm font-medium bg-[#ff3b5c]/10 px-3 py-1 rounded-full">
{latestSection.id}
</span>
{latestSection.isFree && (
<span className="text-xs text-[#00E5FF] bg-[#00E5FF]/10 px-2 py-0.5 rounded"></span>
)}
<main className="px-4 space-y-5">
{/* Banner卡片 - 最新章节 */}
<div
onClick={() => router.push(`/read/${latestSection.id}`)}
className="relative p-5 rounded-2xl overflow-hidden cursor-pointer"
style={{
background: "linear-gradient(135deg, #0d3331 0%, #1a1a2e 50%, #16213e 100%)",
}}
>
<div className="absolute top-0 right-0 w-32 h-32 opacity-20">
<div className="w-full h-full bg-[#00CED1] rounded-full blur-3xl" />
</div>
<span className="inline-block px-2 py-1 rounded text-xs bg-[#00CED1] text-black font-medium mb-3">
</span>
<h2 className="text-lg font-bold text-white mb-2 pr-8">{latestSection.title}</h2>
<p className="text-sm text-gray-400 mb-3">{latestSection.part}</p>
<div className="flex items-center gap-2 text-[#00CED1] text-sm font-medium">
<ChevronRight className="w-4 h-4" />
</div>
<h1 className="text-xl font-bold text-white leading-tight">{latestSection.title}</h1>
<p className="text-gray-500 text-sm mt-2"></p>
</div>
{/* 内容区域 */}
<main ref={contentRef} className="px-4 pb-8">
{isLoading ? (
<div className="space-y-4">
{[...Array(8)].map((_, i) => (
{/* 阅读进度卡 */}
<div className="p-4 rounded-2xl bg-[#1c1c1e] border border-white/5">
<div className="flex items-center justify-between mb-3">
<h3 className="text-sm font-medium text-white"></h3>
<span className="text-xs text-gray-500">
{purchasedCount}/{totalSections}
</span>
</div>
<div className="w-full h-2 bg-[#2c2c2e] rounded-full overflow-hidden mb-3">
<div
key={i}
className="h-4 bg-[#1c1c1e] rounded animate-pulse"
style={{ width: `${Math.random() * 40 + 60}%` }}
className="h-full bg-gradient-to-r from-[#00CED1] to-[#20B2AA] rounded-full transition-all"
style={{ width: `${(purchasedCount / totalSections) * 100}%` }}
/>
</div>
<div className="grid grid-cols-4 gap-3">
<div className="text-center">
<p className="text-[#00CED1] text-lg font-bold">{purchasedCount}</p>
<p className="text-gray-500 text-xs"></p>
</div>
<div className="text-center">
<p className="text-white text-lg font-bold">{totalSections - purchasedCount}</p>
<p className="text-gray-500 text-xs"></p>
</div>
<div className="text-center">
<p className="text-white text-lg font-bold">5</p>
<p className="text-gray-500 text-xs"></p>
</div>
<div className="text-center">
<p className="text-white text-lg font-bold">11</p>
<p className="text-gray-500 text-xs"></p>
</div>
</div>
</div>
{/* 精选推荐 */}
<div>
<div className="flex items-center justify-between mb-3">
<h3 className="text-base font-semibold text-white"></h3>
<button onClick={() => router.push("/chapters")} className="text-xs text-[#00CED1] flex items-center gap-1">
<ChevronRight className="w-3 h-3" />
</button>
</div>
<div className="space-y-3">
{featuredSections.map((section) => (
<div
key={section.id}
onClick={() => router.push(`/read/${section.id}`)}
className="p-4 rounded-xl bg-[#1c1c1e] border border-white/5 cursor-pointer active:scale-[0.98] transition-transform"
>
<div className="flex items-start justify-between">
<div className="flex-1">
<div className="flex items-center gap-2 mb-2">
<span className="text-[#00CED1] text-xs font-medium">{section.id}</span>
<span
className={`text-xs px-2 py-0.5 rounded ${
section.tag === "免费"
? "bg-[#00CED1]/10 text-[#00CED1]"
: section.tag === "热门"
? "bg-pink-500/10 text-pink-400"
: "bg-purple-500/10 text-purple-400"
}`}
>
{section.tag}
</span>
</div>
<h4 className="text-white font-medium text-sm mb-1">{section.title}</h4>
<p className="text-gray-500 text-xs">{section.part}</p>
</div>
<ChevronRight className="w-4 h-4 text-gray-600 mt-1" />
</div>
</div>
))}
</div>
) : (
<article className="text-gray-300 leading-[1.9] text-[16px]">
{displayContent.split("\n").map(
(paragraph, index) =>
paragraph.trim() && (
<p key={index} className="mb-5">
{paragraph}
</p>
),
)}
</article>
)}
{/* 付费墙 - 只在非免费章节且滚动超过20%时显示 */}
{showPaywall && !hasFullBook && !latestSection.isFree && (
<div className="relative mt-4">
{/* 渐变遮罩 */}
<div className="absolute -top-32 left-0 right-0 h-32 bg-gradient-to-t from-black to-transparent pointer-events-none" />
{/* 付费卡片 */}
<div className="p-6 rounded-2xl bg-gradient-to-b from-[#1c1c1e] to-[#2c2c2e] border border-white/10">
<div className="text-center">
<div className="w-14 h-14 mx-auto mb-3 rounded-2xl bg-[#ff3b5c]/10 flex items-center justify-center">
<Lock className="w-7 h-7 text-[#ff3b5c]" />
</div>
<h3 className="text-lg font-semibold text-white mb-2"></h3>
<p className="text-gray-400 text-sm mb-5">{isLoggedIn ? "支付1元继续阅读" : "登录并支付1元继续阅读"}</p>
<div className="space-y-3 mb-4">
<button
onClick={() => handlePurchaseClick("section")}
className="w-full py-3 px-5 rounded-xl bg-[#ff3b5c] text-white font-medium active:scale-[0.98] transition-transform"
{/* 五篇概览 */}
<div>
<h3 className="text-base font-semibold text-white mb-3"></h3>
<div className="grid grid-cols-2 gap-3">
{bookData.slice(0, 4).map((part) => (
<div
key={part.id}
onClick={() => router.push("/chapters")}
className="p-4 rounded-xl bg-[#1c1c1e] border border-white/5 cursor-pointer"
>
<div className="flex items-center justify-center gap-2">
<span></span>
<span className="text-lg font-bold">¥1</span>
<span className="text-[#00CED1] text-xs font-medium mb-1 block">{part.number}</span>
<h4 className="text-white font-medium text-sm mb-1">{part.title}</h4>
<p className="text-gray-500 text-xs">{part.subtitle}</p>
</div>
))}
</div>
</div>
</button>
<button
onClick={() => handlePurchaseClick("fullbook")}
className="w-full py-3 px-5 rounded-xl bg-[#2c2c2e] border border-white/10 text-white font-medium active:scale-[0.98] transition-transform"
{/* 数据统计 */}
<div className="grid grid-cols-3 gap-3">
<div className="p-4 rounded-xl bg-[#1c1c1e] border border-white/5 text-center">
<TrendingUp className="w-5 h-5 text-[#00CED1] mx-auto mb-2" />
<p className="text-white font-bold">3000</p>
<p className="text-gray-500 text-xs"></p>
</div>
<div className="p-4 rounded-xl bg-[#1c1c1e] border border-white/5 text-center">
<Users className="w-5 h-5 text-[#00CED1] mx-auto mb-2" />
<p className="text-white font-bold">55+</p>
<p className="text-gray-500 text-xs"></p>
</div>
<div className="p-4 rounded-xl bg-[#1c1c1e] border border-white/5 text-center">
<Clock className="w-5 h-5 text-[#00CED1] mx-auto mb-2" />
<p className="text-white font-bold">15</p>
<p className="text-gray-500 text-xs"></p>
</div>
</div>
{/* 序言入口 */}
<div
onClick={() => router.push("/read/preface")}
className="p-4 rounded-xl bg-gradient-to-r from-[#00CED1]/10 to-transparent border border-[#00CED1]/20 cursor-pointer"
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
<Sparkles className="w-4 h-4 text-[#ffd700]" />
<span> {totalSections} </span>
</div>
<span className="text-[#ffd700]">¥{fullBookPrice}</span>
</div>
</button>
</div>
<p className="text-xs text-gray-500">90%</p>
</div>
</div>
</div>
)}
{/* 底部引导 - 免费章节或已购买时显示 */}
{!showPaywall && (
<div className="mt-8 p-4 rounded-xl bg-[#1c1c1e] border border-white/5">
<div className="flex items-center justify-between">
<div>
<p className="text-white font-medium"></p>
<p className="text-gray-500 text-sm mt-1"> {totalSections} </p>
<h4 className="text-white font-medium text-sm mb-1"></h4>
<p className="text-gray-400 text-xs">6Soul开播?</p>
</div>
<button
onClick={() => router.push("/chapters")}
className="px-4 py-2 rounded-lg bg-[#ff3b5c] text-white text-sm font-medium flex items-center gap-1"
>
<ChevronRight className="w-4 h-4" />
</button>
<span className="text-xs text-[#00CED1] bg-[#00CED1]/10 px-2 py-1 rounded"></span>
</div>
</div>
)}
</main>
{/* 底部导航 */}
<nav className="fixed bottom-0 left-0 right-0 bg-[#1c1c1e]/95 backdrop-blur-xl border-t border-white/5 pb-safe-bottom">
<div className="px-4 py-3">
<div className="flex items-center justify-between gap-2">
<button
onClick={() => router.push("/chapters")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
<div className="px-4 py-2">
<div className="flex items-center justify-around">
<button className="flex flex-col items-center py-2 px-4">
<Home className="w-5 h-5 text-[#00CED1] mb-1" />
<span className="text-[#00CED1] text-xs font-medium"></span>
</button>
<button
onClick={() => router.push("/about")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
<button onClick={() => router.push("/chapters")} className="flex flex-col items-center py-2 px-4">
<List className="w-5 h-5 text-gray-500 mb-1" />
<span className="text-gray-500 text-xs"></span>
</button>
<button
onClick={() => router.push("/my")}
className="flex-1 py-2.5 rounded-xl bg-[#2c2c2e] text-white text-sm font-medium text-center active:bg-[#3c3c3e]"
>
{/* 匹配按钮 - 更大更突出 */}
<button onClick={() => router.push("/match")} className="flex flex-col items-center py-2 px-6 -mt-4">
<div className="w-14 h-14 rounded-full bg-gradient-to-br from-[#00CED1] to-[#20B2AA] flex items-center justify-center shadow-lg shadow-[#00CED1]/30">
<Sparkles className="w-6 h-6 text-white" />
</div>
<span className="text-[#00CED1] text-xs mt-1"></span>
</button>
<button
onClick={() => handlePurchaseClick("fullbook")}
className="flex-1 py-2.5 rounded-xl bg-[#ff3b5c] text-white text-sm font-medium text-center active:scale-[0.98]"
>
<button onClick={() => router.push("/my")} className="flex flex-col items-center py-2 px-4">
<User className="w-5 h-5 text-gray-500 mb-1" />
<span className="text-gray-500 text-xs"></span>
</button>
</div>
</div>
</nav>
{/* 登录弹窗 */}
<AuthModal isOpen={isAuthOpen} onClose={() => setIsAuthOpen(false)} />
{/* 支付弹窗 */}
<PaymentModal
isOpen={isPaymentOpen}
onClose={() => setIsPaymentOpen(false)}
type={paymentType}
sectionId={latestSection.id}
sectionTitle={latestSection.title}
amount={paymentType === "section" ? latestSection.price : fullBookPrice}
onSuccess={() => window.location.reload()}
/>
</div>
)
}

View File

@@ -2,55 +2,74 @@
import Link from "next/link"
import { usePathname } from "next/navigation"
import { Home, User } from "lucide-react"
import { Home, List, Sparkles, User } from "lucide-react"
export function BottomNav() {
const pathname = usePathname()
// 在文档页面管理后台不显示底部导航
if (pathname.startsWith("/documentation") || pathname.startsWith("/admin")) {
// 在文档页面管理后台、阅读页面和关于页面不显示底部导航
if (
pathname.startsWith("/documentation") ||
pathname.startsWith("/admin") ||
pathname.startsWith("/read") ||
pathname.startsWith("/about")
) {
return null
}
const navItems = [
{ href: "/", icon: Home, label: "首页" },
{ href: "/match", emoji: "🤝", label: "匹配合作" },
{ href: "/chapters", icon: List, label: "目录" },
{ href: "/match", icon: Sparkles, label: "匹配", isCenter: true },
{ href: "/my", icon: User, label: "我的" },
]
return (
<>
{/* iOS风格底部导航 - 只有3个按钮 */}
<nav className="fixed bottom-0 left-0 right-0 z-40 glass-nav safe-bottom">
<nav className="fixed bottom-0 left-0 right-0 z-40 bg-[#1c1c1e]/95 backdrop-blur-xl border-t border-white/5 safe-bottom">
<div className="flex items-center justify-around py-2 max-w-lg mx-auto">
{navItems.map((item, index) => {
const isActive = pathname === item.href || (item.href === '/match' && pathname.startsWith('/match'))
const isActive = pathname === item.href
const Icon = item.icon
// 中间的匹配按钮特殊处理
if (item.isCenter) {
return (
<Link key={index} href={item.href} className="flex flex-col items-center py-2 px-6 -mt-4">
<div
className={`w-14 h-14 rounded-full flex items-center justify-center shadow-lg transition-all ${
isActive
? "bg-gradient-to-br from-[#00CED1] to-[#20B2AA] shadow-[#00CED1]/30"
: "bg-gradient-to-br from-[#00CED1] to-[#20B2AA] shadow-[#00CED1]/30"
}`}
>
<Icon className="w-6 h-6 text-white" />
</div>
<span className={`text-xs mt-1 ${isActive ? "text-[#00CED1] font-medium" : "text-gray-500"}`}>
{item.label}
</span>
</Link>
)
}
return (
<Link
key={index}
href={item.href!}
className="flex flex-col items-center py-2 px-4 sm:px-6 touch-feedback transition-all duration-200"
href={item.href}
className="flex flex-col items-center py-2 px-4 touch-feedback transition-all duration-200"
>
<div className={`w-7 h-7 flex items-center justify-center mb-1 transition-colors ${
isActive ? "text-[var(--app-brand)]" : "text-[var(--app-text-tertiary)]"
}`}>
{item.emoji ? (
<span className="text-2xl">{item.emoji}</span>
) : (
<Icon className="w-6 h-6" strokeWidth={isActive ? 2.5 : 1.5} />
)}
<div
className={`w-6 h-6 flex items-center justify-center mb-1 transition-colors ${
isActive ? "text-[#00CED1]" : "text-gray-500"
}`}
>
<Icon className="w-5 h-5" strokeWidth={isActive ? 2 : 1.5} />
</div>
<span className={`text-[10px] font-medium transition-colors ${
isActive ? "text-[var(--app-brand)]" : "text-[var(--app-text-tertiary)]"
}`}>
<span
className={`text-xs transition-colors ${isActive ? "text-[#00CED1] font-medium" : "text-gray-500"}`}
>
{item.label}
</span>
{/* 激活指示器 */}
{isActive && (
<div className="absolute -bottom-0.5 w-1 h-1 rounded-full bg-[var(--app-brand)]" />
)}
</Link>
)
})}

View File

@@ -22,6 +22,7 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
const [isAuthOpen, setIsAuthOpen] = useState(false)
const [paymentType, setPaymentType] = useState<"section" | "fullbook">("section")
const [readingProgress, setReadingProgress] = useState(0)
const [showPaywall, setShowPaywall] = useState(false)
const { user, isLoggedIn, hasPurchased } = useStore()
const fullBookPrice = getFullBookPrice()
@@ -37,11 +38,15 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
const docHeight = document.documentElement.scrollHeight - window.innerHeight
const progress = docHeight > 0 ? Math.min((scrollTop / docHeight) * 100, 100) : 0
setReadingProgress(progress)
if (progress >= 20 && !canAccess) {
setShowPaywall(true)
}
}
window.addEventListener("scroll", handleScroll)
return () => window.removeEventListener("scroll", handleScroll)
}, [])
}, [canAccess])
// 加载内容
useEffect(() => {
@@ -78,15 +83,14 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
}
const contentLines = content.split("\n").filter((line) => line.trim())
const previewLineCount = Math.ceil(contentLines.length * 0.1) // 改为10%
const previewLineCount = Math.ceil(contentLines.length * 0.2) // 改为20%
const previewContent = contentLines.slice(0, previewLineCount).join("\n")
return (
<div className="min-h-screen bg-black text-white">
{/* 阅读进度条 */}
<div className="fixed top-0 left-0 right-0 z-50 h-0.5 bg-[#1c1c1e]">
<div
className="h-full bg-gradient-to-r from-[#ff3b5c] to-[#ff6b8a] transition-all duration-150"
className="h-full bg-gradient-to-r from-[#00CED1] to-[#20B2AA] transition-all duration-150"
style={{ width: `${readingProgress}%` }}
/>
</div>
@@ -95,7 +99,7 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
<header className="sticky top-0 z-40 bg-black/80 backdrop-blur-xl border-b border-white/5">
<div className="max-w-2xl mx-auto px-4 py-3 flex items-center justify-between">
<button
onClick={() => router.push("/")}
onClick={() => router.push("/chapters")}
className="w-9 h-9 rounded-full bg-[#1c1c1e] flex items-center justify-center active:bg-[#2c2c2e]"
>
<ChevronLeft className="w-5 h-5 text-gray-400" />
@@ -119,13 +123,12 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
{/* 阅读内容 */}
<main className="max-w-2xl mx-auto px-5 py-8 pb-32">
{/* 标题 */}
<div className="mb-8">
<div className="flex items-center gap-2 mb-3">
<span className="text-[#ff3b5c] text-sm font-medium bg-[#ff3b5c]/10 px-3 py-1 rounded-full">
<span className="text-[#00CED1] text-sm font-medium bg-[#00CED1]/10 px-3 py-1 rounded-full">
{section.id}
</span>
{section.isFree && <span className="text-xs text-[#00E5FF] bg-[#00E5FF]/10 px-2 py-0.5 rounded"></span>}
{section.isFree && <span className="text-xs text-[#00CED1] bg-[#00CED1]/10 px-2 py-0.5 rounded"></span>}
</div>
<h1 className="text-2xl font-bold text-white leading-tight">{section.title}</h1>
</div>
@@ -166,20 +169,21 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
)}
</article>
{showPaywall && (
<>
{/* 渐变遮罩 */}
<div className="relative">
<div className="absolute -top-32 left-0 right-0 h-32 bg-gradient-to-t from-black to-transparent pointer-events-none" />
</div>
{/* 付费提示卡片 */}
<div className="mt-8 p-6 rounded-2xl bg-gradient-to-b from-[#1c1c1e] to-[#2c2c2e] border border-white/10">
<div className="mt-8 p-6 rounded-2xl bg-gradient-to-b from-[#1c1c1e] to-[#2c2c2e] border border-[#00CED1]/20">
<div className="text-center">
<div className="w-16 h-16 mx-auto mb-4 rounded-2xl bg-[#ff3b5c]/10 flex items-center justify-center">
<Lock className="w-8 h-8 text-[#ff3b5c]" />
<div className="w-16 h-16 mx-auto mb-4 rounded-2xl bg-[#00CED1]/10 flex items-center justify-center">
<Lock className="w-8 h-8 text-[#00CED1]" />
</div>
<h3 className="text-xl font-semibold text-white mb-2"></h3>
<p className="text-gray-400 text-sm mb-6">
10%{isLoggedIn ? "购买后继续阅读" : "登录并购买后继续阅读"}
20%{isLoggedIn ? "购买后继续阅读" : "登录并购买后继续阅读"}
</p>
{/* 购买选项 */}
@@ -190,13 +194,13 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
>
<div className="flex items-center justify-between">
<span></span>
<span className="text-[#ff3b5c]">¥{section.price}</span>
<span className="text-[#00CED1]">¥{section.price}</span>
</div>
</button>
<button
onClick={() => handlePurchaseClick("fullbook")}
className="w-full py-3.5 px-6 rounded-xl bg-gradient-to-r from-[#ff3b5c] to-[#ff6b8a] text-white font-medium active:scale-[0.98] transition-transform shadow-lg shadow-[#ff3b5c]/20"
className="w-full py-3.5 px-6 rounded-xl bg-gradient-to-r from-[#00CED1] to-[#20B2AA] text-white font-medium active:scale-[0.98] transition-transform shadow-lg shadow-[#00CED1]/20"
>
<div className="flex items-center justify-between">
<div className="flex items-center gap-2">
@@ -214,6 +218,8 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
<p className="text-xs text-gray-500">90%</p>
</div>
</div>
</>
)}
</div>
)}
</main>