feat: Implement iOS-style UI, payment, referral, and reading experience improvements
This commit is contained in:
395
app/globals.css
395
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 (
|
||||
<div className="min-h-screen bg-app-bg text-app-text flex items-center justify-center pb-20">
|
||||
<div className="text-center">
|
||||
<p className="text-app-text-muted mb-4">请先登录</p>
|
||||
<Link href="/" className="text-app-brand hover:underline">
|
||||
<div className="min-h-screen bg-black text-white flex items-center justify-center pb-20">
|
||||
<div className="text-center glass-card p-8">
|
||||
<p className="text-[var(--app-text-secondary)] mb-4">请先登录</p>
|
||||
<Link href="/" className="btn-ios inline-block">
|
||||
返回首页
|
||||
</Link>
|
||||
</div>
|
||||
@@ -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 (
|
||||
<div className="min-h-screen bg-app-bg text-app-text pb-24">
|
||||
{/* Header */}
|
||||
<header className="sticky top-0 z-50 bg-app-bg/90 backdrop-blur-md border-b border-app-border">
|
||||
<div className="max-w-xs mx-auto px-4 py-3 flex items-center">
|
||||
<Link href="/my" className="flex items-center gap-1 text-app-text-muted hover:text-app-text">
|
||||
<ChevronLeft className="w-5 h-5" />
|
||||
<div className="min-h-screen bg-black text-white pb-24 page-transition">
|
||||
{/* 背景光效 */}
|
||||
<div className="fixed inset-0 -z-10">
|
||||
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-[500px] h-[500px] bg-[var(--app-brand)] opacity-[0.05] blur-[150px] rounded-full" />
|
||||
</div>
|
||||
|
||||
{/* Header - iOS风格 */}
|
||||
<header className="sticky top-0 z-50 glass-nav safe-top">
|
||||
<div className="max-w-md mx-auto px-4 py-3 flex items-center">
|
||||
<Link href="/my" className="w-8 h-8 rounded-full bg-[var(--app-bg-secondary)] flex items-center justify-center touch-feedback">
|
||||
<ChevronLeft className="w-5 h-5 text-[var(--app-text-secondary)]" />
|
||||
</Link>
|
||||
<h1 className="flex-1 text-center text-sm font-semibold">分销中心</h1>
|
||||
<div className="w-5" />
|
||||
<h1 className="flex-1 text-center font-semibold">分销中心</h1>
|
||||
<div className="w-8" />
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main className="max-w-xs mx-auto px-4 py-4">
|
||||
{/* Earnings Card */}
|
||||
<div className="bg-gradient-to-br from-app-brand/20 to-app-card rounded-xl p-4 border border-app-brand/30 mb-3">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<Wallet className="w-4 h-4 text-app-brand" />
|
||||
<span className="text-app-text-muted text-xs">累计收益</span>
|
||||
<main className="max-w-md mx-auto px-4 py-6">
|
||||
{/* 收益卡片 - 毛玻璃渐变 */}
|
||||
<div className="relative glass-card-heavy p-6 mb-6 overflow-hidden">
|
||||
{/* 背景装饰 */}
|
||||
<div className="absolute top-0 right-0 w-32 h-32 bg-[var(--app-brand)] opacity-[0.15] blur-[50px] rounded-full" />
|
||||
|
||||
<div className="relative">
|
||||
<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-[var(--app-brand-light)] flex items-center justify-center">
|
||||
<Wallet className="w-5 h-5 text-[var(--app-brand)]" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-[var(--app-text-tertiary)] text-xs">累计收益</p>
|
||||
<p className="text-[var(--app-brand)] text-xs font-medium">{distributorShare}% 返利</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="text-right">
|
||||
<p className="text-3xl font-bold text-white glow-text">¥{totalEarnings.toFixed(2)}</p>
|
||||
<p className="text-[var(--app-text-tertiary)] text-xs">待结算: ¥{pendingEarnings.toFixed(2)}</p>
|
||||
</div>
|
||||
</div>
|
||||
<span className="text-app-brand text-xs">{distributorShare}%返利</span>
|
||||
</div>
|
||||
|
||||
<p className="text-2xl font-bold text-app-text mb-0.5">¥{totalEarnings.toFixed(2)}</p>
|
||||
<p className="text-app-text-muted text-xs mb-3">待结算: ¥{pendingEarnings.toFixed(2)}</p>
|
||||
|
||||
<Button
|
||||
disabled={totalEarnings < 10}
|
||||
onClick={() => setShowWithdrawal(true)}
|
||||
className="w-full bg-app-brand hover:bg-app-brand-hover text-white h-8 text-xs"
|
||||
>
|
||||
{totalEarnings < 10 ? `满10元可提现` : "申请提现"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Stats */}
|
||||
<div className="grid grid-cols-2 gap-2 mb-3">
|
||||
<div className="bg-app-card/60 rounded-lg p-2.5 text-center">
|
||||
<Users className="w-4 h-4 text-app-brand mx-auto mb-1" />
|
||||
<p className="text-base font-bold text-app-text">{referralUsers}</p>
|
||||
<p className="text-app-text-muted text-xs">邀请人数</p>
|
||||
</div>
|
||||
<div className="bg-app-card/60 rounded-lg p-2.5 text-center">
|
||||
<Share2 className="w-4 h-4 text-app-brand mx-auto mb-1" />
|
||||
<p className="text-base font-bold text-app-text">{referralPurchases.length}</p>
|
||||
<p className="text-app-text-muted text-xs">成交订单</p>
|
||||
<button
|
||||
disabled={totalEarnings < 10}
|
||||
onClick={() => setShowWithdrawal(true)}
|
||||
className="btn-ios w-full glow disabled:opacity-50 disabled:cursor-not-allowed"
|
||||
>
|
||||
{totalEarnings < 10 ? `满10元可提现` : "申请提现"}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Referral link */}
|
||||
<div className="bg-app-card/60 rounded-xl p-3 border border-app-border mb-3">
|
||||
<p className="text-app-text text-xs font-medium mb-2">我的专属链接</p>
|
||||
<div className="flex gap-2 mb-2">
|
||||
<div className="flex-1 bg-app-bg rounded-lg px-2.5 py-1.5 text-app-text-muted text-xs truncate font-mono">
|
||||
{/* 数据统计 */}
|
||||
<div className="grid grid-cols-2 gap-4 mb-6">
|
||||
<div className="glass-card p-4 text-center">
|
||||
<div className="w-10 h-10 rounded-xl bg-[var(--ios-blue)]/20 flex items-center justify-center mx-auto mb-2">
|
||||
<Users className="w-5 h-5 text-[var(--ios-blue)]" />
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-white mb-0.5">{referralUsers}</p>
|
||||
<p className="text-[var(--app-text-tertiary)] text-xs">邀请人数</p>
|
||||
</div>
|
||||
<div className="glass-card p-4 text-center">
|
||||
<div className="w-10 h-10 rounded-xl bg-[var(--ios-purple)]/20 flex items-center justify-center mx-auto mb-2">
|
||||
<TrendingUp className="w-5 h-5 text-[var(--ios-purple)]" />
|
||||
</div>
|
||||
<p className="text-2xl font-bold text-white mb-0.5">{referralPurchases.length}</p>
|
||||
<p className="text-[var(--app-text-tertiary)] text-xs">成交订单</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* 专属链接 */}
|
||||
<div className="glass-card p-5 mb-6">
|
||||
<div className="flex items-center justify-between mb-3">
|
||||
<h3 className="text-white font-semibold">我的专属链接</h3>
|
||||
<span className="text-[var(--app-brand)] text-xs bg-[var(--app-brand-light)] px-2 py-1 rounded-full">
|
||||
{user.referralCode}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div className="flex gap-2 mb-4">
|
||||
<div className="flex-1 bg-[var(--app-bg-secondary)] rounded-xl px-4 py-3 text-[var(--app-text-secondary)] text-sm truncate font-mono">
|
||||
{referralLink}
|
||||
</div>
|
||||
<Button
|
||||
<button
|
||||
onClick={handleCopy}
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="border-app-border text-app-text hover:bg-app-card bg-transparent text-xs h-7 px-2"
|
||||
className="w-12 h-12 rounded-xl bg-[var(--app-brand-light)] flex items-center justify-center text-[var(--app-brand)] touch-feedback"
|
||||
>
|
||||
<Copy className="w-3 h-3 mr-1" />
|
||||
{copied ? "已复制" : "复制"}
|
||||
</Button>
|
||||
{copied ? <Check className="w-5 h-5" /> : <Copy className="w-5 h-5" />}
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-app-text-muted text-xs">
|
||||
邀请码: <span className="text-app-brand font-mono">{user.referralCode}</span>
|
||||
|
||||
<p className="text-[var(--app-text-tertiary)] text-xs">
|
||||
好友通过此链接购买,你将获得 {distributorShare}% 返利
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Share buttons - improved for WeChat/Soul */}
|
||||
<div className="space-y-2 mb-3">
|
||||
<Button
|
||||
{/* 分享按钮 */}
|
||||
<div className="space-y-3 mb-6">
|
||||
<button
|
||||
onClick={() => setShowPoster(true)}
|
||||
className="w-full bg-indigo-600 hover:bg-indigo-700 text-white py-4 text-xs"
|
||||
className="w-full glass-card p-4 flex items-center gap-4 touch-feedback"
|
||||
>
|
||||
<ImageIcon className="w-4 h-4 mr-2" />
|
||||
生成推广海报
|
||||
</Button>
|
||||
<Button
|
||||
<div className="w-12 h-12 rounded-xl bg-[var(--ios-indigo)]/20 flex items-center justify-center">
|
||||
<ImageIcon className="w-6 h-6 text-[var(--ios-indigo)]" />
|
||||
</div>
|
||||
<div className="flex-1 text-left">
|
||||
<p className="text-white font-medium">生成推广海报</p>
|
||||
<p className="text-[var(--app-text-tertiary)] text-xs">一键生成精美海报分享</p>
|
||||
</div>
|
||||
<ArrowRight className="w-5 h-5 text-[var(--app-text-tertiary)]" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleShareToWechat}
|
||||
className="w-full bg-green-600 hover:bg-green-700 text-white py-4 text-xs"
|
||||
className="w-full glass-card p-4 flex items-center gap-4 touch-feedback"
|
||||
>
|
||||
<MessageCircle className="w-4 h-4 mr-2" />
|
||||
分享到朋友圈
|
||||
</Button>
|
||||
<Button
|
||||
<div className="w-12 h-12 rounded-xl bg-[#07C160]/20 flex items-center justify-center">
|
||||
<MessageCircle className="w-6 h-6 text-[#07C160]" />
|
||||
</div>
|
||||
<div className="flex-1 text-left">
|
||||
<p className="text-white font-medium">分享到朋友圈</p>
|
||||
<p className="text-[var(--app-text-tertiary)] text-xs">复制文案发朋友圈</p>
|
||||
</div>
|
||||
<ArrowRight className="w-5 h-5 text-[var(--app-text-tertiary)]" />
|
||||
</button>
|
||||
|
||||
<button
|
||||
onClick={handleShare}
|
||||
variant="outline"
|
||||
className="w-full border-app-border text-app-text hover:bg-app-card bg-transparent py-4 text-xs"
|
||||
className="w-full glass-card p-4 flex items-center gap-4 touch-feedback"
|
||||
>
|
||||
更多分享方式
|
||||
</Button>
|
||||
<div className="w-12 h-12 rounded-xl bg-[var(--app-bg-secondary)] flex items-center justify-center">
|
||||
<Share2 className="w-6 h-6 text-[var(--app-text-secondary)]" />
|
||||
</div>
|
||||
<div className="flex-1 text-left">
|
||||
<p className="text-white font-medium">更多分享方式</p>
|
||||
<p className="text-[var(--app-text-tertiary)] text-xs">使用系统分享功能</p>
|
||||
</div>
|
||||
<ArrowRight className="w-5 h-5 text-[var(--app-text-tertiary)]" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<PosterModal
|
||||
isOpen={showPoster}
|
||||
onClose={() => setShowPoster(false)}
|
||||
referralLink={referralLink}
|
||||
referralCode={user.referralCode}
|
||||
nickname={user.nickname}
|
||||
/>
|
||||
|
||||
<WithdrawalModal
|
||||
isOpen={showWithdrawal}
|
||||
onClose={() => setShowWithdrawal(false)}
|
||||
availableAmount={totalEarnings}
|
||||
/>
|
||||
|
||||
{/* Recent earnings */}
|
||||
{/* 收益明细 */}
|
||||
{referralPurchases.length > 0 && (
|
||||
<div className="bg-app-card/60 rounded-xl border border-app-border">
|
||||
<div className="p-2.5 border-b border-app-border">
|
||||
<p className="text-app-text text-xs font-medium">收益明细</p>
|
||||
<div className="glass-card overflow-hidden">
|
||||
<div className="px-5 py-4 border-b border-[var(--app-separator)]">
|
||||
<h3 className="text-white font-semibold">收益明细</h3>
|
||||
</div>
|
||||
<div className="divide-y divide-app-border max-h-40 overflow-auto">
|
||||
{referralPurchases.slice(0, 5).map((purchase) => (
|
||||
<div key={purchase.id} className="p-2.5 flex items-center justify-between">
|
||||
<div>
|
||||
<p className="text-app-text text-xs">{purchase.type === "fullbook" ? "整本书" : "单节"}</p>
|
||||
<p className="text-app-text-muted text-xs">
|
||||
{new Date(purchase.createdAt).toLocaleDateString("zh-CN")}
|
||||
</p>
|
||||
<div className="max-h-60 overflow-auto scrollbar-hide">
|
||||
{referralPurchases.slice(0, 10).map((purchase, idx) => (
|
||||
<div
|
||||
key={purchase.id}
|
||||
className={`px-5 py-4 flex items-center justify-between ${idx !== referralPurchases.length - 1 ? 'border-b border-[var(--app-separator)]' : ''}`}
|
||||
>
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-[var(--app-brand-light)] flex items-center justify-center">
|
||||
<Gift className="w-5 h-5 text-[var(--app-brand)]" />
|
||||
</div>
|
||||
<div>
|
||||
<p className="text-white text-sm font-medium">
|
||||
{purchase.type === "fullbook" ? "整本书购买" : "单节购买"}
|
||||
</p>
|
||||
<p className="text-[var(--app-text-tertiary)] text-xs">
|
||||
{new Date(purchase.createdAt).toLocaleDateString("zh-CN")}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-app-brand text-sm font-semibold">
|
||||
<p className="text-[var(--app-brand)] font-semibold">
|
||||
+¥{(purchase.referrerEarnings || 0).toFixed(2)}
|
||||
</p>
|
||||
</div>
|
||||
@@ -227,7 +255,34 @@ export default function ReferralPage() {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* 空状态 */}
|
||||
{referralPurchases.length === 0 && (
|
||||
<div className="glass-card p-8 text-center">
|
||||
<div className="w-16 h-16 rounded-full bg-[var(--app-bg-secondary)] flex items-center justify-center mx-auto mb-4">
|
||||
<Gift className="w-8 h-8 text-[var(--app-text-tertiary)]" />
|
||||
</div>
|
||||
<p className="text-white font-medium mb-2">暂无收益记录</p>
|
||||
<p className="text-[var(--app-text-tertiary)] text-sm">
|
||||
分享专属链接,好友购买即可获得 {distributorShare}% 返利
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
</main>
|
||||
|
||||
<PosterModal
|
||||
isOpen={showPoster}
|
||||
onClose={() => setShowPoster(false)}
|
||||
referralLink={referralLink}
|
||||
referralCode={user.referralCode}
|
||||
nickname={user.nickname}
|
||||
/>
|
||||
|
||||
<WithdrawalModal
|
||||
isOpen={showWithdrawal}
|
||||
onClose={() => setShowWithdrawal(false)}
|
||||
availableAmount={totalEarnings}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
13
app/page.tsx
13
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 (
|
||||
<main className="min-h-screen bg-[#0a1628] text-white pb-20">
|
||||
<main className="min-h-screen bg-black text-white pb-20 page-transition">
|
||||
{/* 背景渐变效果 */}
|
||||
<div className="fixed inset-0 bg-gradient-to-b from-black via-[#0a0a0a] to-[#111111] -z-10" />
|
||||
|
||||
{/* 装饰性光晕 */}
|
||||
<div className="fixed top-0 left-1/2 -translate-x-1/2 w-[600px] h-[600px] bg-[var(--app-brand)] opacity-[0.03] blur-[150px] rounded-full -z-10" />
|
||||
|
||||
<BookCover />
|
||||
<BookIntro />
|
||||
<TableOfContents parts={parts} />
|
||||
|
||||
Reference in New Issue
Block a user