diff --git a/app/globals.css b/app/globals.css index fd48df8..5e9537d 100644 --- a/app/globals.css +++ b/app/globals.css @@ -4,6 +4,7 @@ @custom-variant dark (&:is(.dark *)); :root { + /* ===== iOS/Apple Design System Colors ===== */ --background: oklch(1 0 0); --foreground: oklch(0.145 0 0); --card: oklch(1 0 0); @@ -28,7 +29,7 @@ --chart-3: oklch(0.398 0.07 227.392); --chart-4: oklch(0.828 0.189 84.429); --chart-5: oklch(0.769 0.188 70.08); - --radius: 0.625rem; + --radius: 1rem; --sidebar: oklch(0.985 0 0); --sidebar-foreground: oklch(0.145 0 0); --sidebar-primary: oklch(0.205 0 0); @@ -38,14 +39,51 @@ --sidebar-border: oklch(0.922 0 0); --sidebar-ring: oklch(0.708 0 0); - /* Custom app tokens */ - --app-bg: #0a1628; - --app-card: #0f2137; - --app-brand: #38bdac; - --app-brand-hover: #2da396; + /* ===== Apple Frosted Glass Design Tokens ===== */ + /* 深色主题背景 - 模拟iOS深色模式 */ + --app-bg: #000000; + --app-bg-secondary: #1c1c1e; + --app-bg-tertiary: #2c2c2e; + + /* 毛玻璃效果 */ + --glass-bg: rgba(28, 28, 30, 0.72); + --glass-bg-light: rgba(44, 44, 46, 0.65); + --glass-bg-heavy: rgba(18, 18, 20, 0.85); + --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); + + /* 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-text: #ffffff; - --app-text-muted: #9ca3af; - --app-border: rgba(75, 85, 99, 0.5); + --app-text-secondary: rgba(235, 235, 245, 0.6); + --app-text-tertiary: rgba(235, 235, 245, 0.3); + --app-text-muted: #8e8e93; + + /* 分隔线和边框 */ + --app-separator: rgba(84, 84, 88, 0.65); + --app-border: rgba(255, 255, 255, 0.1); + + /* 阴影 */ + --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); } .dark { @@ -84,8 +122,10 @@ } @theme inline { - --font-sans: "Geist", "Geist Fallback"; - --font-mono: "Geist Mono", "Geist Mono Fallback"; + /* iOS San Francisco字体栈 */ + --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); --color-foreground: var(--foreground); --color-card: var(--card); @@ -110,10 +150,11 @@ --color-chart-3: var(--chart-3); --color-chart-4: var(--chart-4); --color-chart-5: var(--chart-5); - --radius-sm: calc(var(--radius) - 4px); - --radius-md: calc(var(--radius) - 2px); + --radius-sm: calc(var(--radius) - 8px); + --radius-md: calc(var(--radius) - 4px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); + --radius-2xl: calc(var(--radius) + 8px); --color-sidebar: var(--sidebar); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar-primary: var(--sidebar-primary); @@ -125,7 +166,7 @@ /* Custom semantic tokens for app */ --color-app-bg: var(--app-bg); - --color-app-card: var(--app-card); + --color-app-card: var(--glass-bg); --color-app-brand: var(--app-brand); --color-app-brand-hover: var(--app-brand-hover); --color-app-text: var(--app-text); @@ -137,7 +178,335 @@ * { @apply border-border outline-ring/50; } + + html { + /* 启用iOS平滑滚动 */ + scroll-behavior: smooth; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + text-rendering: optimizeLegibility; + } + body { @apply bg-background text-foreground; + /* iOS安全区域适配 */ + padding-top: env(safe-area-inset-top); + padding-bottom: env(safe-area-inset-bottom); + padding-left: env(safe-area-inset-left); + padding-right: env(safe-area-inset-right); + } +} + +/* ===== Apple Frosted Glass Components ===== */ +@layer components { + /* 毛玻璃卡片 */ + .glass-card { + background: var(--glass-bg); + backdrop-filter: saturate(180%) blur(20px); + -webkit-backdrop-filter: saturate(180%) blur(20px); + border: 1px solid var(--glass-border); + border-radius: 1rem; + } + + .glass-card-light { + background: var(--glass-bg-light); + backdrop-filter: saturate(180%) blur(20px); + -webkit-backdrop-filter: saturate(180%) blur(20px); + border: 1px solid var(--glass-border-light); + border-radius: 1rem; + } + + .glass-card-heavy { + background: var(--glass-bg-heavy); + backdrop-filter: saturate(200%) blur(30px); + -webkit-backdrop-filter: saturate(200%) blur(30px); + border: 1px solid var(--glass-border); + border-radius: 1.25rem; + } + + /* 毛玻璃导航栏 */ + .glass-nav { + background: var(--glass-bg-heavy); + backdrop-filter: saturate(180%) blur(20px); + -webkit-backdrop-filter: saturate(180%) blur(20px); + border-bottom: 0.5px solid var(--app-separator); + } + + /* 毛玻璃弹窗 */ + .glass-modal { + background: var(--glass-bg-heavy); + backdrop-filter: saturate(200%) blur(40px); + -webkit-backdrop-filter: saturate(200%) blur(40px); + border: 1px solid var(--glass-border); + border-radius: 1.5rem; + box-shadow: var(--shadow-lg); + } + + /* iOS风格按钮 */ + .btn-ios { + @apply font-medium transition-all duration-200; + background: var(--app-brand); + color: white; + border-radius: 0.75rem; + padding: 0.875rem 1.5rem; + font-size: 1rem; + letter-spacing: -0.01em; + } + + .btn-ios:hover { + background: var(--app-brand-hover); + transform: scale(0.98); + } + + .btn-ios:active { + transform: scale(0.95); + } + + .btn-ios-secondary { + @apply font-medium transition-all duration-200; + background: var(--glass-bg); + backdrop-filter: blur(10px); + color: var(--app-brand); + border: 1px solid var(--glass-border); + border-radius: 0.75rem; + padding: 0.875rem 1.5rem; + } + + /* iOS风格输入框 */ + .input-ios { + background: var(--app-bg-secondary); + border: none; + border-radius: 0.625rem; + padding: 0.875rem 1rem; + font-size: 1rem; + color: var(--app-text); + transition: all 0.2s ease; + } + + .input-ios:focus { + outline: none; + box-shadow: 0 0 0 4px var(--app-brand-light); + } + + .input-ios::placeholder { + color: var(--app-text-tertiary); + } + + /* iOS风格分割线 */ + .separator-ios { + height: 0.5px; + background: var(--app-separator); + margin: 0 1rem; + } + + /* iOS风格列表项 */ + .list-item-ios { + @apply flex items-center justify-between px-4 py-3; + background: var(--glass-bg-light); + border-bottom: 0.5px solid var(--app-separator); + transition: background 0.15s ease; + } + + .list-item-ios:first-child { + border-top-left-radius: 0.75rem; + border-top-right-radius: 0.75rem; + } + + .list-item-ios:last-child { + border-bottom-left-radius: 0.75rem; + border-bottom-right-radius: 0.75rem; + border-bottom: none; + } + + .list-item-ios:active { + background: var(--glass-bg-heavy); + } + + /* 书籍阅读器样式 */ + .book-reader { + @apply min-h-screen; + background: linear-gradient(180deg, #000000 0%, #1a1a1a 100%); + } + + .book-page { + @apply max-w-2xl mx-auto px-6 py-8; + background: var(--glass-bg); + backdrop-filter: blur(20px); + border-radius: 1rem; + margin: 1rem; + } + + .book-content { + @apply prose prose-invert max-w-none; + font-size: 1.0625rem; + line-height: 1.8; + letter-spacing: 0.01em; + } + + .book-content h1, + .book-content h2, + .book-content h3 { + @apply font-semibold; + letter-spacing: -0.02em; + } + + .book-content p { + margin-bottom: 1.5em; + text-align: justify; + } + + /* 章节导航 */ + .chapter-nav { + @apply fixed bottom-0 left-0 right-0; + background: var(--glass-bg-heavy); + backdrop-filter: saturate(180%) blur(20px); + border-top: 0.5px solid var(--app-separator); + padding-bottom: env(safe-area-inset-bottom); + } + + /* 进度条 */ + .progress-bar { + height: 3px; + background: var(--app-bg-tertiary); + border-radius: 1.5px; + overflow: hidden; + } + + .progress-bar-fill { + height: 100%; + background: linear-gradient(90deg, var(--app-brand) 0%, var(--app-brand-secondary) 100%); + border-radius: 1.5px; + transition: width 0.3s ease; + } + + /* 骨架屏动画 */ + .skeleton { + background: linear-gradient( + 90deg, + var(--app-bg-secondary) 25%, + var(--app-bg-tertiary) 50%, + var(--app-bg-secondary) 75% + ); + background-size: 200% 100%; + animation: skeleton-loading 1.5s infinite; + border-radius: 0.5rem; + } + + @keyframes skeleton-loading { + 0% { + background-position: 200% 0; + } + 100% { + background-position: -200% 0; + } + } + + /* 页面过渡动画 */ + .page-transition { + animation: page-fade-in 0.3s ease-out; + } + + @keyframes page-fade-in { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } + } + + /* 弹窗动画 */ + .modal-overlay { + animation: modal-overlay-in 0.25s ease-out; + } + + .modal-content { + animation: modal-content-in 0.3s cubic-bezier(0.32, 0.72, 0, 1); + } + + @keyframes modal-overlay-in { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + + @keyframes modal-content-in { + from { + opacity: 0; + transform: scale(0.95) translateY(10px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } + } + + /* 发光效果 */ + .glow { + box-shadow: var(--shadow-glow); + } + + .glow-text { + text-shadow: 0 0 20px var(--app-brand); + } +} + +/* ===== 响应式适配 ===== */ +@layer utilities { + /* 移动端安全区域 */ + .safe-top { + padding-top: env(safe-area-inset-top); + } + + .safe-bottom { + padding-bottom: env(safe-area-inset-bottom); + } + + .safe-left { + padding-left: env(safe-area-inset-left); + } + + .safe-right { + padding-right: env(safe-area-inset-right); + } + + /* 触摸反馈 */ + .touch-feedback { + -webkit-tap-highlight-color: transparent; + } + + .touch-feedback:active { + opacity: 0.7; + transform: scale(0.98); + } + + /* 隐藏滚动条但保持可滚动 */ + .scrollbar-hide { + -ms-overflow-style: none; + scrollbar-width: none; + } + + .scrollbar-hide::-webkit-scrollbar { + display: none; + } + + /* iOS风格文字省略 */ + .text-ellipsis-2 { + display: -webkit-box; + -webkit-line-clamp: 2; + -webkit-box-orient: vertical; + overflow: hidden; + } + + .text-ellipsis-3 { + display: -webkit-box; + -webkit-line-clamp: 3; + -webkit-box-orient: vertical; + overflow: hidden; } } diff --git a/app/my/referral/page.tsx b/app/my/referral/page.tsx index 14d1232..99e1c59 100644 --- a/app/my/referral/page.tsx +++ b/app/my/referral/page.tsx @@ -2,8 +2,7 @@ import { useState, useEffect } from "react" import Link from "next/link" -import { ChevronLeft, Copy, Share2, Users, Wallet, MessageCircle, ImageIcon } from "lucide-react" -import { Button } from "@/components/ui/button" +import { ChevronLeft, Copy, Share2, Users, Wallet, MessageCircle, ImageIcon, TrendingUp, Gift, Check, ArrowRight } from "lucide-react" import { useStore, type Purchase } from "@/lib/store" import { PosterModal } from "@/components/modules/referral/poster-modal" import { WithdrawalModal } from "@/components/modules/referral/withdrawal-modal" @@ -30,10 +29,10 @@ export default function ReferralPage() { if (!isLoggedIn || !user) { return ( -
-
-

请先登录

- +
+
+

请先登录

+ 返回首页
@@ -83,143 +82,172 @@ export default function ReferralPage() { alert("朋友圈文案已复制!\n\n打开微信 → 发朋友圈 → 粘贴即可") } - const handleShareToSoul = async () => { - const shareText = `在Soul派对房听卡若讲了好多真实的创业故事,他把这些故事整理成了一本书《一场SOUL的创业实验场》,推荐给你们~ - -每天早上6-9点直播,这本书就是直播内容的精华版。 - -链接: ${referralLink}` - await navigator.clipboard.writeText(shareText) - alert("Soul分享文案已复制!\n\n打开Soul → 发动态 → 粘贴即可") - } - return ( -
- {/* Header */} -
-
- - +
+ {/* 背景光效 */} +
+
+
+ + {/* Header - iOS风格 */} +
+
+ + -

分销中心

-
+

分销中心

+
-
- {/* Earnings Card */} -
-
-
- - 累计收益 +
+ {/* 收益卡片 - 毛玻璃渐变 */} +
+ {/* 背景装饰 */} +
+ +
+
+
+
+ +
+
+

累计收益

+

{distributorShare}% 返利

+
+
+
+

¥{totalEarnings.toFixed(2)}

+

待结算: ¥{pendingEarnings.toFixed(2)}

+
- {distributorShare}%返利 -
-

¥{totalEarnings.toFixed(2)}

-

待结算: ¥{pendingEarnings.toFixed(2)}

- - -
- - {/* Stats */} -
-
- -

{referralUsers}

-

邀请人数

-
-
- -

{referralPurchases.length}

-

成交订单

+
- {/* Referral link */} -
-

我的专属链接

-
-
+ {/* 数据统计 */} +
+
+
+ +
+

{referralUsers}

+

邀请人数

+
+
+
+ +
+

{referralPurchases.length}

+

成交订单

+
+
+ + {/* 专属链接 */} +
+
+

我的专属链接

+ + {user.referralCode} + +
+ +
+
{referralLink}
- + {copied ? : } +
-

- 邀请码: {user.referralCode} + +

+ 好友通过此链接购买,你将获得 {distributorShare}% 返利

- {/* Share buttons - improved for WeChat/Soul */} -
- -
+
+

生成推广海报

+

一键生成精美海报分享

+
+ + + + -
+
+

分享到朋友圈

+

复制文案发朋友圈

+
+ + + + +
+ +
+
+

更多分享方式

+

使用系统分享功能

+
+ +
- setShowPoster(false)} - referralLink={referralLink} - referralCode={user.referralCode} - nickname={user.nickname} - /> - - setShowWithdrawal(false)} - availableAmount={totalEarnings} - /> - - {/* Recent earnings */} + {/* 收益明细 */} {referralPurchases.length > 0 && ( -
-
-

收益明细

+
+
+

收益明细

-
- {referralPurchases.slice(0, 5).map((purchase) => ( -
-
-

{purchase.type === "fullbook" ? "整本书" : "单节"}

-

- {new Date(purchase.createdAt).toLocaleDateString("zh-CN")} -

+
+ {referralPurchases.slice(0, 10).map((purchase, idx) => ( +
+
+
+ +
+
+

+ {purchase.type === "fullbook" ? "整本书购买" : "单节购买"} +

+

+ {new Date(purchase.createdAt).toLocaleDateString("zh-CN")} +

+
-

+

+¥{(purchase.referrerEarnings || 0).toFixed(2)}

@@ -227,7 +255,34 @@ export default function ReferralPage() {
)} + + {/* 空状态 */} + {referralPurchases.length === 0 && ( +
+
+ +
+

暂无收益记录

+

+ 分享专属链接,好友购买即可获得 {distributorShare}% 返利 +

+
+ )}
+ + setShowPoster(false)} + referralLink={referralLink} + referralCode={user.referralCode} + nickname={user.nickname} + /> + + setShowWithdrawal(false)} + availableAmount={totalEarnings} + />
) } diff --git a/app/page.tsx b/app/page.tsx index 494226e..2c8aae2 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -5,17 +5,20 @@ import { PurchaseSection } from "@/components/purchase-section" import { Footer } from "@/components/footer" import { getBookStructure } from "@/lib/book-file-system" -// Force dynamic rendering if we want it to update on every request without rebuild -// or use revalidation. For now, we can leave it default (static if no dynamic functions used, but fs usage makes it dynamic in dev usually). -// Actually, in App Router, using fs directly in a Server Component usually makes it static at build time unless using dynamic functions. -// To ensure it updates when files change in dev, it should be fine. +// 强制动态渲染,确保内容实时更新 export const dynamic = 'force-dynamic'; export default async function HomePage() { const parts = getBookStructure() return ( -
+
+ {/* 背景渐变效果 */} +
+ + {/* 装饰性光晕 */} +
+ diff --git a/components/book-cover.tsx b/components/book-cover.tsx index 4477e3f..5d3122c 100644 --- a/components/book-cover.tsx +++ b/components/book-cover.tsx @@ -1,7 +1,7 @@ "use client" import { useState, useEffect } from "react" import { Button } from "@/components/ui/button" -import { BookOpen } from "lucide-react" +import { BookOpen, Sparkles } from "lucide-react" import Link from "next/link" import { getFullBookPrice, getAllSections } from "@/lib/book-data" import { useStore } from "@/lib/store" @@ -22,82 +22,95 @@ export function BookCover() { }, []) return ( -
- {/* Background decorative lines - simplified */} -
- - - +
+ {/* 动态光效背景 */} +
+ {/* 主光晕 */} +
+ {/* 次光晕 */} +
+
- {/* Content - more compact for mobile */} -
- {/* Soul badge */} -
- Soul · 派对房 + {/* 装饰性网格线 */} +
+ + {/* 内容区域 */} +
+ {/* Soul 徽章 - 毛玻璃效果 */} +
+ + Soul · 派对房
- {/* Main title - smaller on mobile */} -

+ {/* 主标题 - iOS风格大字体 */} +

一场SOUL的
- 创业实验场 + + 创业实验场 +

- {/* Subtitle */} -

来自Soul派对房的真实商业故事

+ {/* 副标题 */} +

+ 来自Soul派对房的真实商业故事 +

- {/* Quote - smaller */} -

"社会不是靠努力,是靠洞察与选择"

+ {/* 引用语 */} +

+ "社会不是靠努力,是靠洞察与选择" +

- {/* Price info - compact card */} -
-
+ {/* 价格信息卡片 - 毛玻璃效果 */} +
+
-

¥{fullBookPrice.toFixed(1)}

-

整本价格

+

+ ¥{fullBookPrice.toFixed(1)} +

+

整本价格

-
+
-

{sectionsCount}

-

商业案例

+

{sectionsCount}

+

商业案例

- {/* Author info - compact */} -
+ {/* 作者信息 */} +
-

作者

-

卡若

+

作者

+

卡若

-

每日直播

-

06:00-09:00

+

每日直播

+

06:00-09:00

- {/* CTA Button */} - - + 立即阅读 + -

首章免费 · 部分章节3天后解锁

+

+ 首章免费 · 部分章节3天后解锁 +

- {/* Modals */} + {/* 底部渐变遮罩 */} +
+ + {/* 弹窗 */} setIsAuthOpen(false)} /> +
- {/* Glass card */} -
- {/* Quote */} -
- "这不是一本教你成功的鸡汤书。这是我每天早上6点到9点,在Soul派对房和几百个陌生人分享的真实故事。" + {/* 毛玻璃卡片 */} +
+ {/* 引用图标 */} +
+ + + +
+ + {/* 引用内容 */} +
+ 这不是一本教你成功的鸡汤书。 + + 这是我每天早上6点到9点,在Soul派对房和几百个陌生人分享的真实故事。 +
- {/* Author */} -

— 卡若

+ {/* 作者签名 */} +
+
+ 卡 +
+
+

卡若

+

Soul派对房主理人

+
+
- {/* Stats */} -
-
-

55+

-

真实案例

+ {/* 分隔线 */} +
+ + {/* 统计数据 */} +
+
+

55+

+

真实案例

-
-

11

-

核心章节

+
+

11

+

核心章节

-
-

100+

-

商业洞察

+
+

100+

+

商业洞察

diff --git a/components/bottom-nav.tsx b/components/bottom-nav.tsx index e12d8fd..b4ba3ed 100644 --- a/components/bottom-nav.tsx +++ b/components/bottom-nav.tsx @@ -2,7 +2,7 @@ import Link from "next/link" import { usePathname } from "next/navigation" -import { Home, MessageCircle, User } from "lucide-react" +import { Home, MessageCircle, User, BookOpen } from "lucide-react" import { useState } from "react" import { QRCodeModal } from "./modules/marketing/qr-code-modal" @@ -10,20 +10,23 @@ export function BottomNav() { const pathname = usePathname() const [showQRModal, setShowQRModal] = useState(false) - if (pathname.startsWith("/documentation")) { + // 在文档页面和管理后台不显示底部导航 + if (pathname.startsWith("/documentation") || pathname.startsWith("/admin")) { return null } const navItems = [ { href: "/", icon: Home, label: "首页" }, + { href: "/chapters", icon: BookOpen, label: "目录" }, { action: () => setShowQRModal(true), icon: MessageCircle, label: "派对群" }, { href: "/my", icon: User, label: "我的" }, ] return ( <> -