Files
soul/app/page.tsx
卡若 b60edb3d47 feat: 完整重构小程序匹配功能 + 修复UI对齐 + 文章数据API
主要更新:
1. 按H5网页端完全重构匹配功能(match页面)
   - 4种匹配类型: 创业合伙/资源对接/导师顾问/团队招募
   - 资源对接等类型弹出手机号/微信号输入框
   - 去掉重新匹配按钮,改为返回按钮

2. 修复所有卡片对齐和宽度问题
   - 目录页附录卡片居中
   - 首页阅读进度卡片满宽度
   - 我的页面菜单卡片对齐
   - 推广中心分享卡片统一宽度

3. 修复目录页图标和文字对齐
   - section-icon固定40rpx宽高
   - section-title与图标垂直居中

4. 更新真实完整文章标题(62篇)
   - 从book目录读取真实markdown文件名
   - 替换之前的简化标题

5. 新增文章数据API
   - /api/db/chapters - 获取完整书籍结构
   - 支持按ID获取单篇文章内容
2026-01-21 15:49:12 +08:00

241 lines
10 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
* 一场SOUL的创业实验 - 首页
* 开发: 卡若
* 技术支持: 存客宝
*/
"use client"
import { useState, useEffect } from "react"
import { useRouter } from "next/navigation"
import { Search, ChevronRight, BookOpen, Home, List, User, Users } from "lucide-react"
import { useStore } from "@/lib/store"
import { bookData, getTotalSectionCount } from "@/lib/book-data"
export default function HomePage() {
const router = useRouter()
const { user } = useStore()
const [mounted, setMounted] = useState(false)
const [searchQuery, setSearchQuery] = useState("")
const totalSections = getTotalSectionCount()
const hasFullBook = user?.hasFullBook || false
const purchasedCount = hasFullBook ? totalSections : user?.purchasedSections?.length || 0
useEffect(() => {
setMounted(true)
}, [])
// 推荐章节
const featuredSections = [
{ id: "1.1", title: "荷包:电动车出租的被动收入模式", tag: "免费", part: "真实的人" },
{ id: "3.1", title: "3000万流水如何跑出来", tag: "热门", part: "真实的行业" },
{ id: "8.1", title: "流量杠杆:抖音、Soul、飞书", tag: "推荐", part: "真实的赚钱" },
]
// 最新更新
const latestSection = {
id: "9.14",
title: "大健康私域一个月150万的70后",
part: "真实的赚钱",
}
if (!mounted) {
return null
}
return (
<div className="min-h-screen bg-black text-white pb-24">
{/* 顶部区域 */}
<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 shadow-lg shadow-[#00CED1]/30">
<span className="text-white font-bold text-lg">S</span>
</div>
<div>
<h1 className="text-lg font-bold text-white">Soul<span className="text-[#00CED1]"></span></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>
{/* 搜索栏 */}
<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"
>
<Search className="w-4 h-4 text-gray-500" />
<span className="text-gray-500 text-sm">...</span>
</div>
</header>
<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>
</div>
{/* 阅读进度卡 */}
<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
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>
</div>
<div>
<h3 className="text-base font-semibold text-white mb-3"></h3>
<div className="space-y-3">
{bookData.map((part) => (
<div
key={part.id}
onClick={() => router.push("/chapters")}
className="p-4 rounded-xl bg-[#1c1c1e] border border-white/5 cursor-pointer active:scale-[0.98] transition-transform"
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-lg bg-gradient-to-br from-[#00CED1]/20 to-[#20B2AA]/10 flex items-center justify-center shrink-0">
<span className="text-[#00CED1] font-bold text-sm">{part.number}</span>
</div>
<div className="flex-1 min-w-0">
<h4 className="text-white font-medium text-sm mb-0.5">{part.title}</h4>
<p className="text-gray-500 text-xs truncate">{part.subtitle}</p>
</div>
<ChevronRight className="w-4 h-4 text-gray-600 shrink-0" />
</div>
</div>
))}
</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>
<h4 className="text-white font-medium text-sm mb-1"></h4>
<p className="text-gray-400 text-xs">6Soul开播?</p>
</div>
<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-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("/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">
<Users className="w-7 h-7 text-white" />
</div>
<span className="text-gray-500 text-xs 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>
)
}