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 *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
/* ===== iOS/Apple Design System Colors ===== */
|
||||||
--background: oklch(1 0 0);
|
--background: oklch(1 0 0);
|
||||||
--foreground: oklch(0.145 0 0);
|
--foreground: oklch(0.145 0 0);
|
||||||
--card: oklch(1 0 0);
|
--card: oklch(1 0 0);
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
--chart-3: oklch(0.398 0.07 227.392);
|
--chart-3: oklch(0.398 0.07 227.392);
|
||||||
--chart-4: oklch(0.828 0.189 84.429);
|
--chart-4: oklch(0.828 0.189 84.429);
|
||||||
--chart-5: oklch(0.769 0.188 70.08);
|
--chart-5: oklch(0.769 0.188 70.08);
|
||||||
--radius: 0.625rem;
|
--radius: 1rem;
|
||||||
--sidebar: oklch(0.985 0 0);
|
--sidebar: oklch(0.985 0 0);
|
||||||
--sidebar-foreground: oklch(0.145 0 0);
|
--sidebar-foreground: oklch(0.145 0 0);
|
||||||
--sidebar-primary: oklch(0.205 0 0);
|
--sidebar-primary: oklch(0.205 0 0);
|
||||||
@@ -38,14 +39,51 @@
|
|||||||
--sidebar-border: oklch(0.922 0 0);
|
--sidebar-border: oklch(0.922 0 0);
|
||||||
--sidebar-ring: oklch(0.708 0 0);
|
--sidebar-ring: oklch(0.708 0 0);
|
||||||
|
|
||||||
/* Custom app tokens */
|
/* ===== Apple Frosted Glass Design Tokens ===== */
|
||||||
--app-bg: #0a1628;
|
/* 深色主题背景 - 模拟iOS深色模式 */
|
||||||
--app-card: #0f2137;
|
--app-bg: #000000;
|
||||||
--app-brand: #38bdac;
|
--app-bg-secondary: #1c1c1e;
|
||||||
--app-brand-hover: #2da396;
|
--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: #ffffff;
|
||||||
--app-text-muted: #9ca3af;
|
--app-text-secondary: rgba(235, 235, 245, 0.6);
|
||||||
--app-border: rgba(75, 85, 99, 0.5);
|
--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 {
|
.dark {
|
||||||
@@ -84,8 +122,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
--font-sans: "Geist", "Geist Fallback";
|
/* iOS San Francisco字体栈 */
|
||||||
--font-mono: "Geist Mono", "Geist Mono Fallback";
|
--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-background: var(--background);
|
||||||
--color-foreground: var(--foreground);
|
--color-foreground: var(--foreground);
|
||||||
--color-card: var(--card);
|
--color-card: var(--card);
|
||||||
@@ -110,10 +150,11 @@
|
|||||||
--color-chart-3: var(--chart-3);
|
--color-chart-3: var(--chart-3);
|
||||||
--color-chart-4: var(--chart-4);
|
--color-chart-4: var(--chart-4);
|
||||||
--color-chart-5: var(--chart-5);
|
--color-chart-5: var(--chart-5);
|
||||||
--radius-sm: calc(var(--radius) - 4px);
|
--radius-sm: calc(var(--radius) - 8px);
|
||||||
--radius-md: calc(var(--radius) - 2px);
|
--radius-md: calc(var(--radius) - 4px);
|
||||||
--radius-lg: var(--radius);
|
--radius-lg: var(--radius);
|
||||||
--radius-xl: calc(var(--radius) + 4px);
|
--radius-xl: calc(var(--radius) + 4px);
|
||||||
|
--radius-2xl: calc(var(--radius) + 8px);
|
||||||
--color-sidebar: var(--sidebar);
|
--color-sidebar: var(--sidebar);
|
||||||
--color-sidebar-foreground: var(--sidebar-foreground);
|
--color-sidebar-foreground: var(--sidebar-foreground);
|
||||||
--color-sidebar-primary: var(--sidebar-primary);
|
--color-sidebar-primary: var(--sidebar-primary);
|
||||||
@@ -125,7 +166,7 @@
|
|||||||
|
|
||||||
/* Custom semantic tokens for app */
|
/* Custom semantic tokens for app */
|
||||||
--color-app-bg: var(--app-bg);
|
--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: var(--app-brand);
|
||||||
--color-app-brand-hover: var(--app-brand-hover);
|
--color-app-brand-hover: var(--app-brand-hover);
|
||||||
--color-app-text: var(--app-text);
|
--color-app-text: var(--app-text);
|
||||||
@@ -137,7 +178,335 @@
|
|||||||
* {
|
* {
|
||||||
@apply border-border outline-ring/50;
|
@apply border-border outline-ring/50;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
/* 启用iOS平滑滚动 */
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
text-rendering: optimizeLegibility;
|
||||||
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground;
|
@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 { useState, useEffect } from "react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { ChevronLeft, Copy, Share2, Users, Wallet, MessageCircle, ImageIcon } from "lucide-react"
|
import { ChevronLeft, Copy, Share2, Users, Wallet, MessageCircle, ImageIcon, TrendingUp, Gift, Check, ArrowRight } from "lucide-react"
|
||||||
import { Button } from "@/components/ui/button"
|
|
||||||
import { useStore, type Purchase } from "@/lib/store"
|
import { useStore, type Purchase } from "@/lib/store"
|
||||||
import { PosterModal } from "@/components/modules/referral/poster-modal"
|
import { PosterModal } from "@/components/modules/referral/poster-modal"
|
||||||
import { WithdrawalModal } from "@/components/modules/referral/withdrawal-modal"
|
import { WithdrawalModal } from "@/components/modules/referral/withdrawal-modal"
|
||||||
@@ -30,10 +29,10 @@ export default function ReferralPage() {
|
|||||||
|
|
||||||
if (!isLoggedIn || !user) {
|
if (!isLoggedIn || !user) {
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-app-bg text-app-text flex items-center justify-center pb-20">
|
<div className="min-h-screen bg-black text-white flex items-center justify-center pb-20">
|
||||||
<div className="text-center">
|
<div className="text-center glass-card p-8">
|
||||||
<p className="text-app-text-muted mb-4">请先登录</p>
|
<p className="text-[var(--app-text-secondary)] mb-4">请先登录</p>
|
||||||
<Link href="/" className="text-app-brand hover:underline">
|
<Link href="/" className="btn-ios inline-block">
|
||||||
返回首页
|
返回首页
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -83,143 +82,172 @@ export default function ReferralPage() {
|
|||||||
alert("朋友圈文案已复制!\n\n打开微信 → 发朋友圈 → 粘贴即可")
|
alert("朋友圈文案已复制!\n\n打开微信 → 发朋友圈 → 粘贴即可")
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleShareToSoul = async () => {
|
|
||||||
const shareText = `在Soul派对房听卡若讲了好多真实的创业故事,他把这些故事整理成了一本书《一场SOUL的创业实验场》,推荐给你们~
|
|
||||||
|
|
||||||
每天早上6-9点直播,这本书就是直播内容的精华版。
|
|
||||||
|
|
||||||
链接: ${referralLink}`
|
|
||||||
await navigator.clipboard.writeText(shareText)
|
|
||||||
alert("Soul分享文案已复制!\n\n打开Soul → 发动态 → 粘贴即可")
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-app-bg text-app-text pb-24">
|
<div className="min-h-screen bg-black text-white pb-24 page-transition">
|
||||||
{/* Header */}
|
{/* 背景光效 */}
|
||||||
<header className="sticky top-0 z-50 bg-app-bg/90 backdrop-blur-md border-b border-app-border">
|
<div className="fixed inset-0 -z-10">
|
||||||
<div className="max-w-xs mx-auto px-4 py-3 flex items-center">
|
<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" />
|
||||||
<Link href="/my" className="flex items-center gap-1 text-app-text-muted hover:text-app-text">
|
</div>
|
||||||
<ChevronLeft className="w-5 h-5" />
|
|
||||||
|
{/* 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>
|
</Link>
|
||||||
<h1 className="flex-1 text-center text-sm font-semibold">分销中心</h1>
|
<h1 className="flex-1 text-center font-semibold">分销中心</h1>
|
||||||
<div className="w-5" />
|
<div className="w-8" />
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<main className="max-w-xs mx-auto px-4 py-4">
|
<main className="max-w-md mx-auto px-4 py-6">
|
||||||
{/* 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="relative glass-card-heavy p-6 mb-6 overflow-hidden">
|
||||||
<div className="flex items-center justify-between mb-3">
|
{/* 背景装饰 */}
|
||||||
<div className="flex items-center gap-2">
|
<div className="absolute top-0 right-0 w-32 h-32 bg-[var(--app-brand)] opacity-[0.15] blur-[50px] rounded-full" />
|
||||||
<Wallet className="w-4 h-4 text-app-brand" />
|
|
||||||
<span className="text-app-text-muted text-xs">累计收益</span>
|
<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>
|
</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>
|
<button
|
||||||
<p className="text-app-text-muted text-xs mb-3">待结算: ¥{pendingEarnings.toFixed(2)}</p>
|
disabled={totalEarnings < 10}
|
||||||
|
onClick={() => setShowWithdrawal(true)}
|
||||||
<Button
|
className="btn-ios w-full glow disabled:opacity-50 disabled:cursor-not-allowed"
|
||||||
disabled={totalEarnings < 10}
|
>
|
||||||
onClick={() => setShowWithdrawal(true)}
|
{totalEarnings < 10 ? `满10元可提现` : "申请提现"}
|
||||||
className="w-full bg-app-brand hover:bg-app-brand-hover text-white h-8 text-xs"
|
</button>
|
||||||
>
|
|
||||||
{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>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Referral link */}
|
{/* 数据统计 */}
|
||||||
<div className="bg-app-card/60 rounded-xl p-3 border border-app-border mb-3">
|
<div className="grid grid-cols-2 gap-4 mb-6">
|
||||||
<p className="text-app-text text-xs font-medium mb-2">我的专属链接</p>
|
<div className="glass-card p-4 text-center">
|
||||||
<div className="flex gap-2 mb-2">
|
<div className="w-10 h-10 rounded-xl bg-[var(--ios-blue)]/20 flex items-center justify-center mx-auto 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">
|
<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}
|
{referralLink}
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<button
|
||||||
onClick={handleCopy}
|
onClick={handleCopy}
|
||||||
size="sm"
|
className="w-12 h-12 rounded-xl bg-[var(--app-brand-light)] flex items-center justify-center text-[var(--app-brand)] touch-feedback"
|
||||||
variant="outline"
|
|
||||||
className="border-app-border text-app-text hover:bg-app-card bg-transparent text-xs h-7 px-2"
|
|
||||||
>
|
>
|
||||||
<Copy className="w-3 h-3 mr-1" />
|
{copied ? <Check className="w-5 h-5" /> : <Copy className="w-5 h-5" />}
|
||||||
{copied ? "已复制" : "复制"}
|
</button>
|
||||||
</Button>
|
|
||||||
</div>
|
</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>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Share buttons - improved for WeChat/Soul */}
|
{/* 分享按钮 */}
|
||||||
<div className="space-y-2 mb-3">
|
<div className="space-y-3 mb-6">
|
||||||
<Button
|
<button
|
||||||
onClick={() => setShowPoster(true)}
|
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" />
|
<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)]" />
|
||||||
</Button>
|
</div>
|
||||||
<Button
|
<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}
|
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" />
|
<div className="w-12 h-12 rounded-xl bg-[#07C160]/20 flex items-center justify-center">
|
||||||
分享到朋友圈
|
<MessageCircle className="w-6 h-6 text-[#07C160]" />
|
||||||
</Button>
|
</div>
|
||||||
<Button
|
<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}
|
onClick={handleShare}
|
||||||
variant="outline"
|
className="w-full glass-card p-4 flex items-center gap-4 touch-feedback"
|
||||||
className="w-full border-app-border text-app-text hover:bg-app-card bg-transparent py-4 text-xs"
|
|
||||||
>
|
>
|
||||||
更多分享方式
|
<div className="w-12 h-12 rounded-xl bg-[var(--app-bg-secondary)] flex items-center justify-center">
|
||||||
</Button>
|
<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>
|
</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 && (
|
{referralPurchases.length > 0 && (
|
||||||
<div className="bg-app-card/60 rounded-xl border border-app-border">
|
<div className="glass-card overflow-hidden">
|
||||||
<div className="p-2.5 border-b border-app-border">
|
<div className="px-5 py-4 border-b border-[var(--app-separator)]">
|
||||||
<p className="text-app-text text-xs font-medium">收益明细</p>
|
<h3 className="text-white font-semibold">收益明细</h3>
|
||||||
</div>
|
</div>
|
||||||
<div className="divide-y divide-app-border max-h-40 overflow-auto">
|
<div className="max-h-60 overflow-auto scrollbar-hide">
|
||||||
{referralPurchases.slice(0, 5).map((purchase) => (
|
{referralPurchases.slice(0, 10).map((purchase, idx) => (
|
||||||
<div key={purchase.id} className="p-2.5 flex items-center justify-between">
|
<div
|
||||||
<div>
|
key={purchase.id}
|
||||||
<p className="text-app-text text-xs">{purchase.type === "fullbook" ? "整本书" : "单节"}</p>
|
className={`px-5 py-4 flex items-center justify-between ${idx !== referralPurchases.length - 1 ? 'border-b border-[var(--app-separator)]' : ''}`}
|
||||||
<p className="text-app-text-muted text-xs">
|
>
|
||||||
{new Date(purchase.createdAt).toLocaleDateString("zh-CN")}
|
<div className="flex items-center gap-3">
|
||||||
</p>
|
<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>
|
</div>
|
||||||
<p className="text-app-brand text-sm font-semibold">
|
<p className="text-[var(--app-brand)] font-semibold">
|
||||||
+¥{(purchase.referrerEarnings || 0).toFixed(2)}
|
+¥{(purchase.referrerEarnings || 0).toFixed(2)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -227,7 +255,34 @@ export default function ReferralPage() {
|
|||||||
</div>
|
</div>
|
||||||
</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>
|
</main>
|
||||||
|
|
||||||
|
<PosterModal
|
||||||
|
isOpen={showPoster}
|
||||||
|
onClose={() => setShowPoster(false)}
|
||||||
|
referralLink={referralLink}
|
||||||
|
referralCode={user.referralCode}
|
||||||
|
nickname={user.nickname}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<WithdrawalModal
|
||||||
|
isOpen={showWithdrawal}
|
||||||
|
onClose={() => setShowWithdrawal(false)}
|
||||||
|
availableAmount={totalEarnings}
|
||||||
|
/>
|
||||||
</div>
|
</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 { Footer } from "@/components/footer"
|
||||||
import { getBookStructure } from "@/lib/book-file-system"
|
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 const dynamic = 'force-dynamic';
|
||||||
|
|
||||||
export default async function HomePage() {
|
export default async function HomePage() {
|
||||||
const parts = getBookStructure()
|
const parts = getBookStructure()
|
||||||
|
|
||||||
return (
|
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 />
|
<BookCover />
|
||||||
<BookIntro />
|
<BookIntro />
|
||||||
<TableOfContents parts={parts} />
|
<TableOfContents parts={parts} />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client"
|
"use client"
|
||||||
import { useState, useEffect } from "react"
|
import { useState, useEffect } from "react"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Button } from "@/components/ui/button"
|
||||||
import { BookOpen } from "lucide-react"
|
import { BookOpen, Sparkles } from "lucide-react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { getFullBookPrice, getAllSections } from "@/lib/book-data"
|
import { getFullBookPrice, getAllSections } from "@/lib/book-data"
|
||||||
import { useStore } from "@/lib/store"
|
import { useStore } from "@/lib/store"
|
||||||
@@ -22,82 +22,95 @@ export function BookCover() {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="relative min-h-[85vh] flex flex-col items-center justify-center px-4 py-8 overflow-hidden bg-app-bg">
|
<section className="relative min-h-[90vh] flex flex-col items-center justify-center px-4 py-12 overflow-hidden safe-top">
|
||||||
{/* Background decorative lines - simplified */}
|
{/* 动态光效背景 */}
|
||||||
<div className="absolute inset-0 overflow-hidden opacity-50">
|
<div className="absolute inset-0 overflow-hidden">
|
||||||
<svg className="absolute w-full h-full" viewBox="0 0 800 600" fill="none">
|
{/* 主光晕 */}
|
||||||
<path
|
<div className="absolute top-1/4 left-1/2 -translate-x-1/2 w-[500px] h-[500px] bg-[var(--app-brand)] opacity-[0.08] blur-[120px] rounded-full animate-pulse" />
|
||||||
d="M-100 300 Q 200 100, 400 200 T 900 150"
|
{/* 次光晕 */}
|
||||||
stroke="rgba(56, 189, 172, 0.2)"
|
<div className="absolute bottom-1/4 left-1/4 w-[300px] h-[300px] bg-[var(--ios-blue)] opacity-[0.05] blur-[100px] rounded-full" />
|
||||||
strokeWidth="1"
|
<div className="absolute top-1/3 right-1/4 w-[200px] h-[200px] bg-[var(--ios-purple)] opacity-[0.04] blur-[80px] rounded-full" />
|
||||||
strokeDasharray="8 8"
|
|
||||||
fill="none"
|
|
||||||
/>
|
|
||||||
</svg>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Content - more compact for mobile */}
|
{/* 装饰性网格线 */}
|
||||||
<div className="relative z-10 w-full max-w-sm mx-auto text-center">
|
<div className="absolute inset-0 opacity-[0.02]" style={{
|
||||||
{/* Soul badge */}
|
backgroundImage: `linear-gradient(var(--app-text) 1px, transparent 1px), linear-gradient(90deg, var(--app-text) 1px, transparent 1px)`,
|
||||||
<div className="inline-flex items-center gap-2 px-3 py-1.5 rounded-full bg-app-card/80 backdrop-blur-md border border-app-brand/30 mb-6">
|
backgroundSize: '60px 60px'
|
||||||
<span className="text-app-brand text-sm font-medium">Soul · 派对房</span>
|
}} />
|
||||||
|
|
||||||
|
{/* 内容区域 */}
|
||||||
|
<div className="relative z-10 w-full max-w-md mx-auto text-center">
|
||||||
|
{/* Soul 徽章 - 毛玻璃效果 */}
|
||||||
|
<div className="inline-flex items-center gap-2 px-4 py-2 glass-card mb-8">
|
||||||
|
<Sparkles className="w-4 h-4 text-[var(--app-brand)]" />
|
||||||
|
<span className="text-[var(--app-brand)] text-sm font-medium tracking-wide">Soul · 派对房</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Main title - smaller on mobile */}
|
{/* 主标题 - iOS风格大字体 */}
|
||||||
<h1 className="text-3xl font-bold mb-3 leading-tight text-app-text">
|
<h1 className="text-4xl sm:text-5xl font-bold mb-4 leading-[1.15] text-white tracking-tight">
|
||||||
一场SOUL的
|
一场SOUL的
|
||||||
<br />
|
<br />
|
||||||
创业实验场
|
<span className="bg-gradient-to-r from-[var(--app-brand)] to-[var(--ios-teal)] bg-clip-text text-transparent">
|
||||||
|
创业实验场
|
||||||
|
</span>
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
{/* Subtitle */}
|
{/* 副标题 */}
|
||||||
<p className="text-app-text-muted text-sm mb-4">来自Soul派对房的真实商业故事</p>
|
<p className="text-[var(--app-text-secondary)] text-base mb-4">
|
||||||
|
来自Soul派对房的真实商业故事
|
||||||
|
</p>
|
||||||
|
|
||||||
{/* Quote - smaller */}
|
{/* 引用语 */}
|
||||||
<p className="text-app-text-muted/80 italic text-sm mb-6">"社会不是靠努力,是靠洞察与选择"</p>
|
<p className="text-[var(--app-text-tertiary)] italic text-sm mb-8 px-4">
|
||||||
|
"社会不是靠努力,是靠洞察与选择"
|
||||||
|
</p>
|
||||||
|
|
||||||
{/* Price info - compact card */}
|
{/* 价格信息卡片 - 毛玻璃效果 */}
|
||||||
<div className="bg-app-card/60 backdrop-blur-md rounded-xl p-4 mb-6 border border-app-border">
|
<div className="glass-card-light p-5 mb-8">
|
||||||
<div className="flex items-center justify-center gap-6 text-sm">
|
<div className="flex items-center justify-center gap-8">
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p className="text-xl font-bold text-app-brand">¥{fullBookPrice.toFixed(1)}</p>
|
<p className="text-3xl font-bold text-[var(--app-brand)] glow-text">
|
||||||
<p className="text-app-text-muted text-xs">整本价格</p>
|
¥{fullBookPrice.toFixed(1)}
|
||||||
|
</p>
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-xs mt-1">整本价格</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="w-px h-8 bg-app-border" />
|
<div className="w-px h-12 bg-[var(--app-separator)]" />
|
||||||
<div className="text-center">
|
<div className="text-center">
|
||||||
<p className="text-xl font-bold text-app-text">{sectionsCount}</p>
|
<p className="text-3xl font-bold text-white">{sectionsCount}</p>
|
||||||
<p className="text-app-text-muted text-xs">商业案例</p>
|
<p className="text-[var(--app-text-tertiary)] text-xs mt-1">商业案例</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Author info - compact */}
|
{/* 作者信息 */}
|
||||||
<div className="flex justify-between items-center px-2 mb-6 text-sm">
|
<div className="flex justify-between items-center px-4 mb-8">
|
||||||
<div className="text-left">
|
<div className="text-left">
|
||||||
<p className="text-app-text-muted text-xs">作者</p>
|
<p className="text-[var(--app-text-tertiary)] text-xs mb-0.5">作者</p>
|
||||||
<p className="text-app-brand font-medium">卡若</p>
|
<p className="text-[var(--app-brand)] font-semibold">卡若</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<p className="text-app-text-muted text-xs">每日直播</p>
|
<p className="text-[var(--app-text-tertiary)] text-xs mb-0.5">每日直播</p>
|
||||||
<p className="text-app-text font-medium">06:00-09:00</p>
|
<p className="text-white font-semibold">06:00-09:00</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* CTA Button */}
|
{/* CTA按钮 - iOS风格 */}
|
||||||
<Link href="/chapters" className="block">
|
<Link href="/chapters" className="block touch-feedback">
|
||||||
<Button
|
<button className="btn-ios w-full flex items-center justify-center gap-2 glow">
|
||||||
size="lg"
|
|
||||||
className="w-full bg-app-brand hover:bg-app-brand-hover text-white py-5 text-base rounded-xl flex items-center justify-center gap-2"
|
|
||||||
>
|
|
||||||
<BookOpen className="w-5 h-5" />
|
<BookOpen className="w-5 h-5" />
|
||||||
立即阅读
|
<span>立即阅读</span>
|
||||||
</Button>
|
</button>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
||||||
<p className="text-app-text-muted text-xs mt-4">首章免费 · 部分章节3天后解锁</p>
|
<p className="text-[var(--app-text-tertiary)] text-xs mt-5">
|
||||||
|
首章免费 · 部分章节3天后解锁
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Modals */}
|
{/* 底部渐变遮罩 */}
|
||||||
|
<div className="absolute bottom-0 left-0 right-0 h-32 bg-gradient-to-t from-black to-transparent" />
|
||||||
|
|
||||||
|
{/* 弹窗 */}
|
||||||
<AuthModal isOpen={isAuthOpen} onClose={() => setIsAuthOpen(false)} />
|
<AuthModal isOpen={isAuthOpen} onClose={() => setIsAuthOpen(false)} />
|
||||||
<PaymentModal
|
<PaymentModal
|
||||||
isOpen={isPaymentOpen}
|
isOpen={isPaymentOpen}
|
||||||
|
|||||||
@@ -1,30 +1,51 @@
|
|||||||
export function BookIntro() {
|
export function BookIntro() {
|
||||||
return (
|
return (
|
||||||
<section className="py-16 px-4">
|
<section className="py-12 px-4">
|
||||||
<div className="max-w-2xl mx-auto">
|
<div className="max-w-2xl mx-auto">
|
||||||
{/* Glass card */}
|
{/* 毛玻璃卡片 */}
|
||||||
<div className="bg-[#0f2137]/80 backdrop-blur-xl rounded-2xl p-8 border border-[#38bdac]/20">
|
<div className="glass-card-heavy p-6 sm:p-8">
|
||||||
{/* Quote */}
|
{/* 引用图标 */}
|
||||||
<blockquote className="text-lg md:text-xl text-gray-200 leading-relaxed mb-6">
|
<div className="w-10 h-10 rounded-xl bg-[var(--app-brand-light)] flex items-center justify-center mb-6">
|
||||||
"这不是一本教你成功的鸡汤书。这是我每天早上6点到9点,在Soul派对房和几百个陌生人分享的真实故事。"
|
<svg className="w-5 h-5 text-[var(--app-brand)]" fill="currentColor" viewBox="0 0 24 24">
|
||||||
|
<path d="M14.017 21v-7.391c0-5.704 3.731-9.57 8.983-10.609l.995 2.151c-2.432.917-3.995 3.638-3.995 5.849h4v10h-9.983zm-14.017 0v-7.391c0-5.704 3.748-9.57 9-10.609l.996 2.151c-2.433.917-3.996 3.638-3.996 5.849h3.983v10h-9.983z"/>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 引用内容 */}
|
||||||
|
<blockquote className="text-lg sm:text-xl text-white leading-relaxed mb-6 font-light">
|
||||||
|
这不是一本教你成功的鸡汤书。
|
||||||
|
<span className="text-[var(--app-text-secondary)]">
|
||||||
|
这是我每天早上6点到9点,在Soul派对房和几百个陌生人分享的真实故事。
|
||||||
|
</span>
|
||||||
</blockquote>
|
</blockquote>
|
||||||
|
|
||||||
{/* Author */}
|
{/* 作者签名 */}
|
||||||
<p className="text-[#38bdac] text-lg">— 卡若</p>
|
<div className="flex items-center gap-3 mb-8">
|
||||||
|
<div className="w-10 h-10 rounded-full bg-gradient-to-br from-[var(--app-brand)] to-[var(--ios-teal)] flex items-center justify-center text-white font-semibold text-sm">
|
||||||
|
卡
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<p className="text-[var(--app-brand)] font-semibold">卡若</p>
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-xs">Soul派对房主理人</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Stats */}
|
{/* 分隔线 */}
|
||||||
<div className="mt-8 pt-6 border-t border-gray-700/50 grid grid-cols-3 gap-4 text-center">
|
<div className="separator-ios mx-0 mb-6" />
|
||||||
<div>
|
|
||||||
<p className="text-2xl md:text-3xl font-bold text-white">55+</p>
|
{/* 统计数据 */}
|
||||||
<p className="text-gray-400 text-sm">真实案例</p>
|
<div className="grid grid-cols-3 gap-4 text-center">
|
||||||
|
<div className="p-3">
|
||||||
|
<p className="text-2xl sm:text-3xl font-bold text-white mb-1">55+</p>
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-xs">真实案例</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="p-3 border-x border-[var(--app-separator)]">
|
||||||
<p className="text-2xl md:text-3xl font-bold text-white">11</p>
|
<p className="text-2xl sm:text-3xl font-bold text-white mb-1">11</p>
|
||||||
<p className="text-gray-400 text-sm">核心章节</p>
|
<p className="text-[var(--app-text-tertiary)] text-xs">核心章节</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="p-3">
|
||||||
<p className="text-2xl md:text-3xl font-bold text-white">100+</p>
|
<p className="text-2xl sm:text-3xl font-bold text-white mb-1">100+</p>
|
||||||
<p className="text-gray-400 text-sm">商业洞察</p>
|
<p className="text-[var(--app-text-tertiary)] text-xs">商业洞察</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { usePathname } from "next/navigation"
|
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 { useState } from "react"
|
||||||
import { QRCodeModal } from "./modules/marketing/qr-code-modal"
|
import { QRCodeModal } from "./modules/marketing/qr-code-modal"
|
||||||
|
|
||||||
@@ -10,20 +10,23 @@ export function BottomNav() {
|
|||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
const [showQRModal, setShowQRModal] = useState(false)
|
const [showQRModal, setShowQRModal] = useState(false)
|
||||||
|
|
||||||
if (pathname.startsWith("/documentation")) {
|
// 在文档页面和管理后台不显示底部导航
|
||||||
|
if (pathname.startsWith("/documentation") || pathname.startsWith("/admin")) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{ href: "/", icon: Home, label: "首页" },
|
{ href: "/", icon: Home, label: "首页" },
|
||||||
|
{ href: "/chapters", icon: BookOpen, label: "目录" },
|
||||||
{ action: () => setShowQRModal(true), icon: MessageCircle, label: "派对群" },
|
{ action: () => setShowQRModal(true), icon: MessageCircle, label: "派对群" },
|
||||||
{ href: "/my", icon: User, label: "我的" },
|
{ href: "/my", icon: User, label: "我的" },
|
||||||
]
|
]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<nav className="fixed bottom-0 left-0 right-0 z-40 bg-[#0f2137]/95 backdrop-blur-md border-t border-gray-700/50">
|
{/* iOS风格底部导航 */}
|
||||||
<div className="flex items-center justify-around py-3 max-w-lg mx-auto">
|
<nav className="fixed bottom-0 left-0 right-0 z-40 glass-nav safe-bottom">
|
||||||
|
<div className="flex items-center justify-around py-2 max-w-lg mx-auto">
|
||||||
{navItems.map((item, index) => {
|
{navItems.map((item, index) => {
|
||||||
const isActive = item.href ? pathname === item.href : false
|
const isActive = item.href ? pathname === item.href : false
|
||||||
const Icon = item.icon
|
const Icon = item.icon
|
||||||
@@ -33,10 +36,18 @@ export function BottomNav() {
|
|||||||
<button
|
<button
|
||||||
key={index}
|
key={index}
|
||||||
onClick={item.action}
|
onClick={item.action}
|
||||||
className="flex flex-col items-center py-2 px-6 text-gray-400 hover:text-[#38bdac] transition-colors"
|
className="flex flex-col items-center py-2 px-4 sm:px-6 touch-feedback transition-all duration-200"
|
||||||
>
|
>
|
||||||
<Icon className="w-6 h-6 mb-1" />
|
<div className={`w-7 h-7 flex items-center justify-center mb-1 transition-colors ${
|
||||||
<span className="text-xs">{item.label}</span>
|
isActive ? "text-[var(--app-brand)]" : "text-[var(--app-text-tertiary)]"
|
||||||
|
}`}>
|
||||||
|
<Icon className="w-6 h-6" strokeWidth={isActive ? 2.5 : 1.5} />
|
||||||
|
</div>
|
||||||
|
<span className={`text-[10px] font-medium transition-colors ${
|
||||||
|
isActive ? "text-[var(--app-brand)]" : "text-[var(--app-text-tertiary)]"
|
||||||
|
}`}>
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -45,12 +56,22 @@ export function BottomNav() {
|
|||||||
<Link
|
<Link
|
||||||
key={index}
|
key={index}
|
||||||
href={item.href!}
|
href={item.href!}
|
||||||
className={`flex flex-col items-center py-2 px-6 transition-colors ${
|
className="flex flex-col items-center py-2 px-4 sm:px-6 touch-feedback transition-all duration-200"
|
||||||
isActive ? "text-[#38bdac]" : "text-gray-400 hover:text-white"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<Icon className="w-6 h-6 mb-1" />
|
<div className={`w-7 h-7 flex items-center justify-center mb-1 transition-colors ${
|
||||||
<span className="text-xs">{item.label}</span>
|
isActive ? "text-[var(--app-brand)]" : "text-[var(--app-text-tertiary)]"
|
||||||
|
}`}>
|
||||||
|
<Icon className="w-6 h-6" strokeWidth={isActive ? 2.5 : 1.5} />
|
||||||
|
</div>
|
||||||
|
<span className={`text-[10px] font-medium transition-colors ${
|
||||||
|
isActive ? "text-[var(--app-brand)]" : "text-[var(--app-text-tertiary)]"
|
||||||
|
}`}>
|
||||||
|
{item.label}
|
||||||
|
</span>
|
||||||
|
{/* 激活指示器 */}
|
||||||
|
{isActive && (
|
||||||
|
<div className="absolute -bottom-0.5 w-1 h-1 rounded-full bg-[var(--app-brand)]" />
|
||||||
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
import { useState, useEffect } from "react"
|
import { useState, useEffect } from "react"
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { ChevronLeft, Lock, Share2, BookOpen, Clock, MessageCircle } from "lucide-react"
|
import { ChevronLeft, Lock, Share2, BookOpen, Clock, MessageCircle, ChevronRight, Sparkles } from "lucide-react"
|
||||||
import { Button } from "@/components/ui/button"
|
|
||||||
import { type Section, getFullBookPrice, isSectionUnlocked } from "@/lib/book-data"
|
import { type Section, getFullBookPrice, isSectionUnlocked } from "@/lib/book-data"
|
||||||
import { useStore } from "@/lib/store"
|
import { useStore } from "@/lib/store"
|
||||||
import { AuthModal } from "./modules/auth/auth-modal"
|
import { AuthModal } from "./modules/auth/auth-modal"
|
||||||
@@ -26,6 +25,7 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
|
|||||||
const [isQRModalOpen, setIsQRModalOpen] = useState(false)
|
const [isQRModalOpen, setIsQRModalOpen] = useState(false)
|
||||||
const [paymentType, setPaymentType] = useState<"section" | "fullbook">("section")
|
const [paymentType, setPaymentType] = useState<"section" | "fullbook">("section")
|
||||||
const [fullBookPrice, setFullBookPrice] = useState(9.9)
|
const [fullBookPrice, setFullBookPrice] = useState(9.9)
|
||||||
|
const [readingProgress, setReadingProgress] = useState(0)
|
||||||
|
|
||||||
const { user, isLoggedIn, hasPurchased, settings } = useStore()
|
const { user, isLoggedIn, hasPurchased, settings } = useStore()
|
||||||
const distributorShare = settings?.distributorShare || 90
|
const distributorShare = settings?.distributorShare || 90
|
||||||
@@ -37,6 +37,19 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
|
|||||||
setFullBookPrice(getFullBookPrice())
|
setFullBookPrice(getFullBookPrice())
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
|
// 阅读进度追踪
|
||||||
|
useEffect(() => {
|
||||||
|
const handleScroll = () => {
|
||||||
|
const scrollTop = window.scrollY
|
||||||
|
const docHeight = document.documentElement.scrollHeight - window.innerHeight
|
||||||
|
const progress = Math.min((scrollTop / docHeight) * 100, 100)
|
||||||
|
setReadingProgress(progress)
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('scroll', handleScroll)
|
||||||
|
return () => window.removeEventListener('scroll', handleScroll)
|
||||||
|
}, [])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
async function loadContent() {
|
async function loadContent() {
|
||||||
try {
|
try {
|
||||||
@@ -110,17 +123,29 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
|
|||||||
const previewContent = content.slice(0, 500)
|
const previewContent = content.slice(0, 500)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="min-h-screen bg-[#0a1628] text-white pb-20">
|
<div className="min-h-screen bg-black text-white pb-20 page-transition">
|
||||||
{/* Header */}
|
{/* 阅读进度条 */}
|
||||||
<header className="sticky top-0 z-50 bg-[#0a1628]/90 backdrop-blur-md border-b border-gray-800">
|
<div className="fixed top-0 left-0 right-0 z-[60] h-0.5 bg-[var(--app-bg-secondary)]">
|
||||||
<div className="max-w-3xl mx-auto px-4 py-4 flex items-center justify-between">
|
<div
|
||||||
<Link href="/chapters" className="flex items-center gap-2 text-gray-400 hover:text-white transition-colors">
|
className="h-full bg-[var(--app-brand)] transition-all duration-150"
|
||||||
<ChevronLeft className="w-5 h-5" />
|
style={{ width: `${readingProgress}%` }}
|
||||||
<span className="hidden sm:inline">目录</span>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Header - iOS风格毛玻璃 */}
|
||||||
|
<header className="sticky top-0 z-50 glass-nav safe-top">
|
||||||
|
<div className="max-w-3xl mx-auto px-4 py-3 flex items-center justify-between">
|
||||||
|
<Link
|
||||||
|
href="/chapters"
|
||||||
|
className="w-9 h-9 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>
|
</Link>
|
||||||
<div className="text-center flex-1 px-4">
|
<div className="text-center flex-1 px-4">
|
||||||
<p className="text-gray-500 text-xs">{partTitle}</p>
|
<p className="text-[var(--app-text-tertiary)] text-xs">{partTitle}</p>
|
||||||
{chapterTitle && <p className="text-gray-400 text-sm truncate">{chapterTitle}</p>}
|
{chapterTitle && (
|
||||||
|
<p className="text-[var(--app-text-secondary)] text-sm truncate">{chapterTitle}</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<ReferralShare
|
<ReferralShare
|
||||||
@@ -133,147 +158,169 @@ export function ChapterContent({ section, partTitle, chapterTitle }: ChapterCont
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* Content */}
|
{/* 阅读内容 */}
|
||||||
<main className="max-w-3xl mx-auto px-4 py-8">
|
<main className="max-w-2xl mx-auto px-5 sm:px-6 py-8">
|
||||||
{/* Title */}
|
{/* 标题区域 */}
|
||||||
<div className="mb-8">
|
<div className="mb-10">
|
||||||
<div className="flex items-center gap-2 text-[#38bdac] text-sm mb-2">
|
<div className="flex items-center gap-2 mb-4">
|
||||||
<BookOpen className="w-4 h-4" />
|
<span className="text-[var(--app-brand)] text-sm font-medium bg-[var(--app-brand-light)] px-3 py-1 rounded-full">
|
||||||
<span>{section.id}</span>
|
{section.id}
|
||||||
|
</span>
|
||||||
{section.unlockAfterDays && !section.isFree && (
|
{section.unlockAfterDays && !section.isFree && (
|
||||||
<span className="ml-2 px-2 py-0.5 bg-orange-500/20 text-orange-400 text-xs rounded-full flex items-center gap-1">
|
<span className="px-3 py-1 bg-[var(--ios-orange)]/20 text-[var(--ios-orange)] text-xs rounded-full flex items-center gap-1">
|
||||||
<Clock className="w-3 h-3" />
|
<Clock className="w-3 h-3" />
|
||||||
{isUnlocked ? "已免费解锁" : `${section.unlockAfterDays}天后免费`}
|
{isUnlocked ? "已免费解锁" : `${section.unlockAfterDays}天后免费`}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<h1 className="text-2xl md:text-3xl font-bold text-white leading-tight">{section.title}</h1>
|
<h1 className="text-2xl sm:text-3xl font-bold text-white leading-tight tracking-tight">
|
||||||
|
{section.title}
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="flex items-center justify-center py-20">
|
// 骨架屏加载
|
||||||
<div className="w-8 h-8 border-2 border-[#38bdac] border-t-transparent rounded-full animate-spin" />
|
<div className="space-y-4">
|
||||||
|
{[...Array(8)].map((_, i) => (
|
||||||
|
<div key={i} className="skeleton h-4 rounded" style={{ width: `${Math.random() * 40 + 60}%` }} />
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
) : canAccess ? (
|
) : canAccess ? (
|
||||||
<>
|
<>
|
||||||
<article className="prose prose-invert prose-lg max-w-none">
|
{/* 正文内容 - 书籍阅读风格 */}
|
||||||
<div className="text-gray-300 leading-relaxed whitespace-pre-line">
|
<article className="book-content">
|
||||||
|
<div className="text-[var(--app-text-secondary)] leading-[1.9] text-[17px]">
|
||||||
{content.split("\n").map((paragraph, index) => (
|
{content.split("\n").map((paragraph, index) => (
|
||||||
<p key={index} className="mb-4">
|
paragraph.trim() && (
|
||||||
{paragraph}
|
<p key={index} className="mb-6 text-justify">
|
||||||
</p>
|
{paragraph}
|
||||||
|
</p>
|
||||||
|
)
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
{/* Join Party Group CTA */}
|
{/* 进群引导 CTA */}
|
||||||
<div className="mt-12 bg-gradient-to-r from-[#38bdac]/10 to-[#1a3a4a]/50 rounded-2xl p-6 border border-[#38bdac]/30">
|
<div className="mt-16 glass-card-heavy p-6 overflow-hidden relative">
|
||||||
<div className="flex items-center gap-4">
|
<div className="absolute top-0 right-0 w-24 h-24 bg-[var(--app-brand)] opacity-[0.1] blur-[40px] rounded-full" />
|
||||||
<div className="w-12 h-12 rounded-full bg-[#38bdac]/20 flex items-center justify-center flex-shrink-0">
|
<div className="relative flex items-center gap-4">
|
||||||
<MessageCircle className="w-6 h-6 text-[#38bdac]" />
|
<div className="w-14 h-14 rounded-2xl bg-[var(--app-brand-light)] flex items-center justify-center flex-shrink-0">
|
||||||
|
<MessageCircle className="w-7 h-7 text-[var(--app-brand)]" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<div className="flex-1 min-w-0">
|
||||||
<h3 className="text-white font-semibold mb-1">想听更多商业故事?</h3>
|
<h3 className="text-white font-semibold mb-1">想听更多商业故事?</h3>
|
||||||
<p className="text-gray-400 text-sm">每天早上6-9点,卡若在Soul派对房分享真实案例</p>
|
<p className="text-[var(--app-text-tertiary)] text-sm">每天早上6-9点,卡若在Soul派对房分享真实案例</p>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<button
|
||||||
onClick={() => setIsQRModalOpen(true)}
|
onClick={() => setIsQRModalOpen(true)}
|
||||||
className="bg-[#38bdac] hover:bg-[#2da396] text-white whitespace-nowrap"
|
className="btn-ios whitespace-nowrap flex-shrink-0"
|
||||||
>
|
>
|
||||||
加入派对群
|
加入派对群
|
||||||
</Button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div>
|
<div>
|
||||||
<article className="prose prose-invert prose-lg max-w-none relative">
|
{/* 预览内容 */}
|
||||||
<div className="text-gray-300 leading-relaxed whitespace-pre-line">
|
<article className="book-content relative">
|
||||||
|
<div className="text-[var(--app-text-secondary)] leading-[1.9] text-[17px]">
|
||||||
{previewContent.split("\n").map((paragraph, index) => (
|
{previewContent.split("\n").map((paragraph, index) => (
|
||||||
<p key={index} className="mb-4">
|
paragraph.trim() && (
|
||||||
{paragraph}
|
<p key={index} className="mb-6 text-justify">
|
||||||
</p>
|
{paragraph}
|
||||||
|
</p>
|
||||||
|
)
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="absolute bottom-0 left-0 right-0 h-40 bg-gradient-to-t from-[#0a1628] to-transparent" />
|
<div className="absolute bottom-0 left-0 right-0 h-48 bg-gradient-to-t from-black to-transparent" />
|
||||||
</article>
|
</article>
|
||||||
|
|
||||||
{/* Purchase prompt */}
|
{/* 购买提示 - 毛玻璃风格 */}
|
||||||
<div className="mt-8 bg-[#0f2137]/80 backdrop-blur-xl rounded-2xl p-8 border border-gray-700/50 text-center">
|
<div className="mt-8 glass-card-heavy p-8 text-center overflow-hidden relative">
|
||||||
<div className="w-16 h-16 mx-auto mb-4 rounded-full bg-gray-800/50 flex items-center justify-center">
|
<div className="absolute top-0 left-1/2 -translate-x-1/2 w-40 h-40 bg-[var(--app-brand)] opacity-[0.08] blur-[60px] rounded-full" />
|
||||||
<Lock className="w-8 h-8 text-gray-500" />
|
|
||||||
</div>
|
|
||||||
<h3 className="text-xl font-semibold text-white mb-2">解锁完整内容</h3>
|
|
||||||
<p className="text-gray-400 mb-6">
|
|
||||||
{isLoggedIn ? "购买本节或整本书以阅读完整内容" : "登录后购买即可阅读完整内容"}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
{section.unlockAfterDays && (
|
<div className="relative">
|
||||||
<p className="text-orange-400 text-sm mb-4 flex items-center justify-center gap-1">
|
<div className="w-20 h-20 mx-auto mb-6 rounded-2xl bg-[var(--app-bg-secondary)] flex items-center justify-center">
|
||||||
<Clock className="w-4 h-4" />
|
<Lock className="w-10 h-10 text-[var(--app-text-tertiary)]" />
|
||||||
本节将在{section.unlockAfterDays}天后免费解锁
|
</div>
|
||||||
|
<h3 className="text-2xl font-semibold text-white mb-2">解锁完整内容</h3>
|
||||||
|
<p className="text-[var(--app-text-secondary)] mb-8">
|
||||||
|
{isLoggedIn ? "购买本节或整本书以阅读完整内容" : "登录后购买即可阅读完整内容"}
|
||||||
</p>
|
</p>
|
||||||
)}
|
|
||||||
|
|
||||||
<div className="flex flex-col sm:flex-row gap-4 justify-center">
|
{section.unlockAfterDays && (
|
||||||
<Button
|
<div className="inline-flex items-center gap-2 px-4 py-2 mb-6 rounded-full bg-[var(--ios-orange)]/10 text-[var(--ios-orange)]">
|
||||||
onClick={() => handlePurchaseClick("section")}
|
<Clock className="w-4 h-4" />
|
||||||
variant="outline"
|
<span className="text-sm">本节将在{section.unlockAfterDays}天后免费解锁</span>
|
||||||
className="border-gray-600 text-white hover:bg-gray-700/50 px-6 py-5"
|
</div>
|
||||||
>
|
)}
|
||||||
购买本节 ¥{section.price}
|
|
||||||
</Button>
|
<div className="flex flex-col sm:flex-row gap-4 justify-center mb-6">
|
||||||
<Button
|
<button
|
||||||
onClick={() => handlePurchaseClick("fullbook")}
|
onClick={() => handlePurchaseClick("section")}
|
||||||
className="bg-[#38bdac] hover:bg-[#2da396] text-white px-6 py-5"
|
className="btn-ios-secondary px-8 py-4"
|
||||||
>
|
>
|
||||||
购买全书 ¥{fullBookPrice.toFixed(1)}
|
购买本节 ¥{section.price}
|
||||||
<span className="ml-2 text-xs opacity-80">省82%</span>
|
</button>
|
||||||
</Button>
|
<button
|
||||||
|
onClick={() => handlePurchaseClick("fullbook")}
|
||||||
|
className="btn-ios px-8 py-4 glow flex items-center justify-center gap-2"
|
||||||
|
>
|
||||||
|
<Sparkles className="w-4 h-4" />
|
||||||
|
购买全书 ¥{fullBookPrice.toFixed(1)}
|
||||||
|
<span className="text-xs opacity-80 ml-1">省82%</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-sm">
|
||||||
|
分享本书,他人购买你可获得 <span className="text-[var(--app-brand)]">{distributorShare}%返利</span>
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="text-gray-500 text-sm mt-4">
|
|
||||||
分享本书,他人购买你可获得 <span className="text-[#38bdac]">{distributorShare}%返利</span>
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Join Party Group */}
|
{/* 进群引导 */}
|
||||||
<div className="mt-8 bg-gradient-to-r from-[#38bdac]/10 to-[#1a3a4a]/50 rounded-2xl p-6 border border-[#38bdac]/30">
|
<div className="mt-8 glass-card p-6">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<div className="w-12 h-12 rounded-full bg-[#38bdac]/20 flex items-center justify-center flex-shrink-0">
|
<div className="w-14 h-14 rounded-2xl bg-[var(--app-brand-light)] flex items-center justify-center flex-shrink-0">
|
||||||
<MessageCircle className="w-6 h-6 text-[#38bdac]" />
|
<MessageCircle className="w-7 h-7 text-[var(--app-brand)]" />
|
||||||
</div>
|
</div>
|
||||||
<div className="flex-1">
|
<div className="flex-1 min-w-0">
|
||||||
<h3 className="text-white font-semibold mb-1">不想花钱?来派对群免费听!</h3>
|
<h3 className="text-white font-semibold mb-1">不想花钱?来派对群免费听!</h3>
|
||||||
<p className="text-gray-400 text-sm">每天早上6-9点,卡若在Soul派对房免费分享</p>
|
<p className="text-[var(--app-text-tertiary)] text-sm">每天早上6-9点,卡若在Soul派对房免费分享</p>
|
||||||
</div>
|
</div>
|
||||||
<Button
|
<button
|
||||||
onClick={() => setIsQRModalOpen(true)}
|
onClick={() => setIsQRModalOpen(true)}
|
||||||
className="bg-[#38bdac] hover:bg-[#2da396] text-white whitespace-nowrap"
|
className="btn-ios whitespace-nowrap flex-shrink-0"
|
||||||
>
|
>
|
||||||
加入派对群
|
加入
|
||||||
</Button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Navigation */}
|
{/* 底部导航 */}
|
||||||
<div className="mt-12 pt-8 border-t border-gray-800 flex justify-between">
|
<div className="mt-16 pt-8 border-t border-[var(--app-separator)] flex justify-between items-center">
|
||||||
<Link href="/chapters" className="text-gray-400 hover:text-white transition-colors">
|
<Link
|
||||||
← 返回目录
|
href="/chapters"
|
||||||
|
className="flex items-center gap-2 text-[var(--app-text-secondary)] hover:text-white transition-colors touch-feedback"
|
||||||
|
>
|
||||||
|
<ChevronLeft className="w-4 h-4" />
|
||||||
|
<span>返回目录</span>
|
||||||
</Link>
|
</Link>
|
||||||
<button
|
<button
|
||||||
onClick={handleShare}
|
onClick={handleShare}
|
||||||
className="text-[#38bdac] hover:text-[#4fd4c4] transition-colors flex items-center gap-2"
|
className="flex items-center gap-2 text-[var(--app-brand)] touch-feedback"
|
||||||
>
|
>
|
||||||
<Share2 className="w-4 h-4" />
|
<Share2 className="w-4 h-4" />
|
||||||
分享赚 ¥{((section.price * distributorShare) / 100).toFixed(1)}
|
<span>分享赚 ¥{((section.price * distributorShare) / 100).toFixed(1)}</span>
|
||||||
|
<ChevronRight className="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</main>
|
</main>
|
||||||
|
|
||||||
{/* Modals */}
|
{/* 弹窗 */}
|
||||||
<AuthModal isOpen={isAuthOpen} onClose={() => setIsAuthOpen(false)} />
|
<AuthModal isOpen={isAuthOpen} onClose={() => setIsAuthOpen(false)} />
|
||||||
<PaymentModal
|
<PaymentModal
|
||||||
isOpen={isPaymentOpen}
|
isOpen={isPaymentOpen}
|
||||||
|
|||||||
@@ -2,10 +2,39 @@
|
|||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
return (
|
return (
|
||||||
<footer className="py-6 px-4 border-t border-gray-800 pb-24">
|
<footer className="py-8 px-4 pb-28">
|
||||||
<div className="max-w-xs mx-auto text-center">
|
<div className="max-w-md mx-auto">
|
||||||
<p className="text-white text-sm font-medium mb-1">一场SOUL的创业实验场</p>
|
{/* 分隔线 */}
|
||||||
<p className="text-gray-500 text-xs">© 2025 卡若 · 每日直播 06:00-09:00</p>
|
<div className="separator-ios mx-0 mb-6" />
|
||||||
|
|
||||||
|
<div className="text-center">
|
||||||
|
{/* Logo/品牌 */}
|
||||||
|
<div className="inline-flex items-center gap-2 mb-3">
|
||||||
|
<div className="w-6 h-6 rounded-lg bg-[var(--app-brand-light)] flex items-center justify-center">
|
||||||
|
<span className="text-[var(--app-brand)] text-xs font-bold">S</span>
|
||||||
|
</div>
|
||||||
|
<span className="text-white font-semibold">一场SOUL的创业实验场</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 信息 */}
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-xs mb-4">
|
||||||
|
每日直播 06:00-09:00 · Soul派对房
|
||||||
|
</p>
|
||||||
|
|
||||||
|
{/* 链接 */}
|
||||||
|
<div className="flex items-center justify-center gap-6 text-xs text-[var(--app-text-tertiary)] mb-4">
|
||||||
|
<a href="/about" className="hover:text-white transition-colors">关于我们</a>
|
||||||
|
<span className="w-1 h-1 rounded-full bg-[var(--app-separator)]" />
|
||||||
|
<a href="#" className="hover:text-white transition-colors">用户协议</a>
|
||||||
|
<span className="w-1 h-1 rounded-full bg-[var(--app-separator)]" />
|
||||||
|
<a href="#" className="hover:text-white transition-colors">隐私政策</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 版权 */}
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-xs">
|
||||||
|
© {new Date().getFullYear()} 卡若 · All rights reserved
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
|
|
||||||
import type React from "react"
|
import type React from "react"
|
||||||
import { useState, useEffect } from "react"
|
import { useState, useEffect } from "react"
|
||||||
import { X, CheckCircle, Bitcoin, Globe, Copy, Check, QrCode } from "lucide-react"
|
import { X, CheckCircle, Bitcoin, Globe, Copy, Check, QrCode, Shield, Users } from "lucide-react"
|
||||||
import { Button } from "@/components/ui/button"
|
|
||||||
import { useStore } from "@/lib/store"
|
import { useStore } from "@/lib/store"
|
||||||
|
|
||||||
const WechatIcon = () => (
|
const WechatIcon = () => (
|
||||||
@@ -65,10 +64,8 @@ export function PaymentModal({ isOpen, onClose, type, sectionId, sectionTitle, a
|
|||||||
}
|
}
|
||||||
|
|
||||||
const handlePayment = async () => {
|
const handlePayment = async () => {
|
||||||
// 直接显示支付二维码/详情页面
|
|
||||||
setShowQRCode(true)
|
setShowQRCode(true)
|
||||||
|
|
||||||
// 如果有跳转链接,尝试打开
|
|
||||||
if (paymentMethod === "wechat" && paymentConfig.wechat?.qrCode) {
|
if (paymentMethod === "wechat" && paymentConfig.wechat?.qrCode) {
|
||||||
const link = paymentConfig.wechat.qrCode
|
const link = paymentConfig.wechat.qrCode
|
||||||
if (link.startsWith("http") || link.startsWith("weixin://")) {
|
if (link.startsWith("http") || link.startsWith("weixin://")) {
|
||||||
@@ -98,7 +95,6 @@ export function PaymentModal({ isOpen, onClose, type, sectionId, sectionTitle, a
|
|||||||
if (success) {
|
if (success) {
|
||||||
setIsSuccess(true)
|
setIsSuccess(true)
|
||||||
|
|
||||||
// 支付成功后跳转微信群
|
|
||||||
const groupUrl = paymentConfig.wechat?.groupQrCode
|
const groupUrl = paymentConfig.wechat?.groupQrCode
|
||||||
if (groupUrl) {
|
if (groupUrl) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@@ -122,6 +118,7 @@ export function PaymentModal({ isOpen, onClose, type, sectionId, sectionTitle, a
|
|||||||
name: string
|
name: string
|
||||||
icon: React.ReactNode
|
icon: React.ReactNode
|
||||||
color: string
|
color: string
|
||||||
|
iconBg: string
|
||||||
enabled: boolean
|
enabled: boolean
|
||||||
extra?: string
|
extra?: string
|
||||||
}[] = [
|
}[] = [
|
||||||
@@ -129,21 +126,24 @@ export function PaymentModal({ isOpen, onClose, type, sectionId, sectionTitle, a
|
|||||||
id: "wechat",
|
id: "wechat",
|
||||||
name: "微信支付",
|
name: "微信支付",
|
||||||
icon: <WechatIcon />,
|
icon: <WechatIcon />,
|
||||||
color: "bg-[#07C160]",
|
color: "#07C160",
|
||||||
|
iconBg: "rgba(7, 193, 96, 0.15)",
|
||||||
enabled: paymentConfig.wechat?.enabled ?? true,
|
enabled: paymentConfig.wechat?.enabled ?? true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "alipay",
|
id: "alipay",
|
||||||
name: "支付宝",
|
name: "支付宝",
|
||||||
icon: <AlipayIcon />,
|
icon: <AlipayIcon />,
|
||||||
color: "bg-[#1677FF]",
|
color: "#1677FF",
|
||||||
|
iconBg: "rgba(22, 119, 255, 0.15)",
|
||||||
enabled: paymentConfig.alipay?.enabled ?? true,
|
enabled: paymentConfig.alipay?.enabled ?? true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: "usdt",
|
id: "usdt",
|
||||||
name: `USDT (${paymentConfig.usdt?.network || "TRC20"})`,
|
name: `USDT (${paymentConfig.usdt?.network || "TRC20"})`,
|
||||||
icon: <Bitcoin className="w-5 h-5" />,
|
icon: <Bitcoin className="w-5 h-5" />,
|
||||||
color: "bg-[#26A17B]",
|
color: "#26A17B",
|
||||||
|
iconBg: "rgba(38, 161, 123, 0.15)",
|
||||||
enabled: paymentConfig.usdt?.enabled ?? true,
|
enabled: paymentConfig.usdt?.enabled ?? true,
|
||||||
extra: `≈ $${usdtAmount}`,
|
extra: `≈ $${usdtAmount}`,
|
||||||
},
|
},
|
||||||
@@ -151,7 +151,8 @@ export function PaymentModal({ isOpen, onClose, type, sectionId, sectionTitle, a
|
|||||||
id: "paypal",
|
id: "paypal",
|
||||||
name: "PayPal",
|
name: "PayPal",
|
||||||
icon: <Globe className="w-5 h-5" />,
|
icon: <Globe className="w-5 h-5" />,
|
||||||
color: "bg-[#003087]",
|
color: "#003087",
|
||||||
|
iconBg: "rgba(0, 48, 135, 0.15)",
|
||||||
enabled: paymentConfig.paypal?.enabled ?? false,
|
enabled: paymentConfig.paypal?.enabled ?? false,
|
||||||
extra: `≈ $${paypalAmount}`,
|
extra: `≈ $${paypalAmount}`,
|
||||||
},
|
},
|
||||||
@@ -159,7 +160,7 @@ export function PaymentModal({ isOpen, onClose, type, sectionId, sectionTitle, a
|
|||||||
|
|
||||||
const availableMethods = paymentMethods.filter((m) => m.enabled)
|
const availableMethods = paymentMethods.filter((m) => m.enabled)
|
||||||
|
|
||||||
// 二维码/详情页面
|
// 二维码/详情页面 - iOS毛玻璃风格
|
||||||
if (showQRCode) {
|
if (showQRCode) {
|
||||||
const isCrypto = paymentMethod === "usdt"
|
const isCrypto = paymentMethod === "usdt"
|
||||||
const isPaypal = paymentMethod === "paypal"
|
const isPaypal = paymentMethod === "paypal"
|
||||||
@@ -169,7 +170,7 @@ export function PaymentModal({ isOpen, onClose, type, sectionId, sectionTitle, a
|
|||||||
let address = ""
|
let address = ""
|
||||||
let displayAmount = `¥${amount.toFixed(2)}`
|
let displayAmount = `¥${amount.toFixed(2)}`
|
||||||
let title = "扫码支付"
|
let title = "扫码支付"
|
||||||
let hint = "支付完成后,请点击下方已完成支付按钮"
|
let hint = "支付完成后,请点击下方按钮确认"
|
||||||
let qrCodeUrl = ""
|
let qrCodeUrl = ""
|
||||||
|
|
||||||
if (isCrypto) {
|
if (isCrypto) {
|
||||||
@@ -193,87 +194,110 @@ export function PaymentModal({ isOpen, onClose, type, sectionId, sectionTitle, a
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center">
|
||||||
<div className="absolute inset-0 bg-black/70 backdrop-blur-sm" onClick={onClose} />
|
<div className="absolute inset-0 bg-black/60 backdrop-blur-md modal-overlay" onClick={onClose} />
|
||||||
<div className="relative w-full max-w-md bg-[#0f2137] rounded-2xl border border-gray-700/50 shadow-2xl overflow-hidden">
|
<div className="relative w-full sm:max-w-md glass-modal overflow-hidden safe-bottom modal-content sm:m-4">
|
||||||
<button onClick={onClose} className="absolute top-4 right-4 p-2 text-gray-400 hover:text-white z-10">
|
{/* 顶部把手 - 仅移动端 */}
|
||||||
<X className="w-5 h-5" />
|
<div className="flex justify-center pt-3 pb-2 sm:hidden">
|
||||||
|
<div className="w-9 h-1 rounded-full bg-[var(--app-text-tertiary)]" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={onClose}
|
||||||
|
className="absolute top-4 right-4 w-8 h-8 rounded-full bg-[var(--app-bg-secondary)] flex items-center justify-center text-[var(--app-text-secondary)] hover:text-white z-10 touch-feedback"
|
||||||
|
>
|
||||||
|
<X className="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<div className="p-6 pt-12">
|
<div className="p-6 pt-4 sm:pt-10">
|
||||||
{/* 标题 */}
|
{/* 标题 */}
|
||||||
<h3 className="text-xl font-semibold text-white text-center mb-4">{title}</h3>
|
<h3 className="text-xl font-semibold text-white text-center mb-2">{title}</h3>
|
||||||
|
|
||||||
{/* 金额显示 */}
|
{/* 金额显示 */}
|
||||||
<div className="text-center mb-6">
|
<div className="text-center mb-6">
|
||||||
<p className="text-3xl font-bold text-[#38bdac]">{displayAmount}</p>
|
<p className="text-4xl font-bold text-[var(--app-brand)] glow-text">{displayAmount}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* QR Code Display */}
|
{/* QR Code Display */}
|
||||||
{(isWechat || isAlipay) && (
|
{(isWechat || isAlipay) && (
|
||||||
<div className="flex flex-col items-center mb-6">
|
<div className="flex flex-col items-center mb-6">
|
||||||
<div className="w-48 h-48 bg-white rounded-xl p-3 mb-4 flex items-center justify-center">
|
<div className="w-52 h-52 bg-white rounded-2xl p-4 mb-4 flex items-center justify-center shadow-lg">
|
||||||
{qrCodeUrl ? (
|
{qrCodeUrl ? (
|
||||||
<img
|
<img
|
||||||
src={qrCodeUrl || "/placeholder.svg"}
|
src={qrCodeUrl || "/placeholder.svg"}
|
||||||
alt="支付二维码"
|
alt="支付二维码"
|
||||||
className="w-full h-full object-contain"
|
className="w-full h-full object-contain rounded-lg"
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-col items-center text-gray-400">
|
<div className="flex flex-col items-center text-gray-400">
|
||||||
<QrCode className="w-16 h-16 mb-2" />
|
<QrCode className="w-16 h-16 mb-2" />
|
||||||
<span className="text-sm">请在后台配置收款码</span>
|
<span className="text-sm text-center">请在后台配置收款码</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<p className="text-gray-400 text-sm">{hint}</p>
|
<p className="text-[var(--app-text-tertiary)] text-sm">{hint}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Crypto/PayPal Address */}
|
{/* Crypto/PayPal Address */}
|
||||||
{(isCrypto || isPaypal) && (
|
{(isCrypto || isPaypal) && (
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<div className="bg-[#0a1628] rounded-xl p-4 border border-gray-700/30">
|
<div className="glass-card p-4">
|
||||||
<p className="text-gray-400 text-sm mb-2">
|
<p className="text-[var(--app-text-tertiary)] text-xs mb-2">
|
||||||
{isCrypto ? `收款地址 (${paymentConfig.usdt?.network})` : "PayPal账户"}
|
{isCrypto ? `收款地址 (${paymentConfig.usdt?.network})` : "PayPal账户"}
|
||||||
</p>
|
</p>
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<p className="text-white text-sm break-all flex-1 font-mono">{address || "请在后台配置收款地址"}</p>
|
<p className="text-white text-sm break-all flex-1 font-mono bg-[var(--app-bg-secondary)] p-3 rounded-lg">
|
||||||
|
{address || "请在后台配置收款地址"}
|
||||||
|
</p>
|
||||||
{address && (
|
{address && (
|
||||||
<button
|
<button
|
||||||
onClick={() => handleCopyAddress(address)}
|
onClick={() => handleCopyAddress(address)}
|
||||||
className="text-[#38bdac] hover:text-[#4fd4c4]"
|
className="w-10 h-10 rounded-xl bg-[var(--app-brand-light)] flex items-center justify-center text-[var(--app-brand)] touch-feedback"
|
||||||
>
|
>
|
||||||
{copied ? <Check className="w-5 h-5" /> : <Copy className="w-5 h-5" />}
|
{copied ? <Check className="w-5 h-5" /> : <Copy className="w-5 h-5" />}
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-gray-500 text-sm mt-2 text-center">{hint}</p>
|
<p className="text-[var(--app-text-tertiary)] text-sm mt-3 text-center">{hint}</p>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* 提示信息 */}
|
{/* 提示信息 */}
|
||||||
<div className="bg-[#38bdac]/10 border border-[#38bdac]/30 rounded-xl p-3 mb-4">
|
<div className="glass-card p-4 mb-6 border-[var(--app-brand)]/20">
|
||||||
<p className="text-[#38bdac] text-sm text-center">支付完成后,系统将自动开通阅读权限</p>
|
<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">
|
||||||
|
<Shield className="w-5 h-5 text-[var(--app-brand)]" />
|
||||||
|
</div>
|
||||||
|
<p className="text-[var(--app-text-secondary)] text-sm flex-1">
|
||||||
|
支付完成后,系统将自动开通阅读权限
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Action Buttons */}
|
{/* Action Buttons */}
|
||||||
<div className="flex gap-3">
|
<div className="flex gap-3">
|
||||||
<Button
|
<button
|
||||||
onClick={() => setShowQRCode(false)}
|
onClick={() => setShowQRCode(false)}
|
||||||
variant="outline"
|
className="btn-ios-secondary flex-1"
|
||||||
className="flex-1 border-gray-600 text-white hover:bg-gray-700/50 bg-transparent"
|
|
||||||
>
|
>
|
||||||
返回
|
返回
|
||||||
</Button>
|
</button>
|
||||||
<Button
|
<button
|
||||||
onClick={confirmPayment}
|
onClick={confirmPayment}
|
||||||
disabled={isProcessing}
|
disabled={isProcessing}
|
||||||
className="flex-1 bg-[#38bdac] hover:bg-[#2da396] text-white"
|
className="btn-ios flex-1 glow disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isProcessing ? "处理中..." : "已完成支付"}
|
{isProcessing ? (
|
||||||
</Button>
|
<div className="flex items-center justify-center gap-2">
|
||||||
|
<div className="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
||||||
|
处理中...
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
"已完成支付"
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -285,98 +309,133 @@ export function PaymentModal({ isOpen, onClose, type, sectionId, sectionTitle, a
|
|||||||
if (isSuccess) {
|
if (isSuccess) {
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||||
<div className="absolute inset-0 bg-black/70 backdrop-blur-sm" />
|
<div className="absolute inset-0 bg-black/60 backdrop-blur-md modal-overlay" />
|
||||||
<div className="relative w-full max-w-md bg-[#0f2137] rounded-2xl border border-gray-700/50 overflow-hidden">
|
<div className="relative w-full max-w-sm glass-modal overflow-hidden modal-content">
|
||||||
<div className="p-8 text-center">
|
<div className="p-8 text-center">
|
||||||
<div className="w-20 h-20 mx-auto mb-4 rounded-full bg-[#38bdac]/20 flex items-center justify-center">
|
{/* 成功动画 */}
|
||||||
<CheckCircle className="w-10 h-10 text-[#38bdac]" />
|
<div className="w-24 h-24 mx-auto mb-6 rounded-full bg-[var(--app-brand-light)] flex items-center justify-center">
|
||||||
|
<CheckCircle className="w-12 h-12 text-[var(--app-brand)]" />
|
||||||
</div>
|
</div>
|
||||||
<h3 className="text-xl font-semibold text-white mb-2">支付成功</h3>
|
<h3 className="text-2xl font-semibold text-white mb-2">支付成功</h3>
|
||||||
<p className="text-gray-400">{type === "fullbook" ? "您已解锁全部内容" : "您已解锁本节内容"}</p>
|
<p className="text-[var(--app-text-secondary)] mb-4">
|
||||||
{paymentConfig.wechat?.groupQrCode && <p className="text-[#07C160] text-sm mt-4">正在跳转到微信群...</p>}
|
{type === "fullbook" ? "您已解锁全部内容" : "您已解锁本节内容"}
|
||||||
|
</p>
|
||||||
|
{paymentConfig.wechat?.groupQrCode && (
|
||||||
|
<div className="glass-card p-4 mt-4">
|
||||||
|
<div className="flex items-center justify-center gap-2 text-[#07C160]">
|
||||||
|
<Users className="w-5 h-5" />
|
||||||
|
<span className="text-sm">正在跳转到读者社群...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 主支付选择页面
|
// 主支付选择页面 - iOS风格
|
||||||
return (
|
return (
|
||||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
<div className="fixed inset-0 z-50 flex items-end sm:items-center justify-center">
|
||||||
<div className="absolute inset-0 bg-black/70 backdrop-blur-sm" onClick={onClose} />
|
<div className="absolute inset-0 bg-black/60 backdrop-blur-md modal-overlay" onClick={onClose} />
|
||||||
<div className="relative w-full max-w-md bg-[#0f2137] rounded-2xl border border-gray-700/50 shadow-2xl overflow-hidden max-h-[90vh] overflow-y-auto">
|
<div className="relative w-full sm:max-w-md glass-modal overflow-hidden safe-bottom modal-content sm:m-4 max-h-[90vh] overflow-y-auto scrollbar-hide">
|
||||||
|
{/* 顶部把手 - 仅移动端 */}
|
||||||
|
<div className="flex justify-center pt-3 pb-2 sm:hidden sticky top-0 bg-transparent">
|
||||||
|
<div className="w-9 h-1 rounded-full bg-[var(--app-text-tertiary)]" />
|
||||||
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
className="absolute top-4 right-4 p-2 text-gray-400 hover:text-white transition-colors z-10"
|
className="absolute top-4 right-4 w-8 h-8 rounded-full bg-[var(--app-bg-secondary)] flex items-center justify-center text-[var(--app-text-secondary)] hover:text-white z-10 touch-feedback"
|
||||||
>
|
>
|
||||||
<X className="w-5 h-5" />
|
<X className="w-4 h-4" />
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div className="p-6 pt-12 border-b border-gray-700/50">
|
<div className="px-6 pt-2 sm:pt-10 pb-4">
|
||||||
<h3 className="text-lg font-semibold text-white mb-1">确认支付</h3>
|
<h3 className="text-xl font-semibold text-white mb-1">确认支付</h3>
|
||||||
<p className="text-gray-400 text-sm">
|
<p className="text-[var(--app-text-tertiary)] text-sm">
|
||||||
{type === "fullbook" ? "购买整本书,解锁全部内容" : `购买: ${sectionTitle}`}
|
{type === "fullbook" ? "购买整本书,解锁全部内容" : `购买: ${sectionTitle}`}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Amount */}
|
{/* Amount */}
|
||||||
<div className="p-6 border-b border-gray-700/50 text-center">
|
<div className="px-6 py-6 text-center border-y border-[var(--app-separator)]">
|
||||||
<p className="text-gray-400 text-sm mb-1">支付金额</p>
|
<p className="text-[var(--app-text-tertiary)] text-sm mb-2">支付金额</p>
|
||||||
<p className="text-4xl font-bold text-white">¥{amount.toFixed(2)}</p>
|
<p className="text-5xl font-bold text-white">¥{amount.toFixed(2)}</p>
|
||||||
{(paymentMethod === "usdt" || paymentMethod === "paypal") && (
|
{(paymentMethod === "usdt" || paymentMethod === "paypal") && (
|
||||||
<p className="text-[#38bdac] text-sm mt-1">≈ ${paymentMethod === "usdt" ? usdtAmount : paypalAmount} USD</p>
|
<p className="text-[var(--app-brand)] text-sm mt-2">
|
||||||
|
≈ ${paymentMethod === "usdt" ? usdtAmount : paypalAmount} USD
|
||||||
|
</p>
|
||||||
)}
|
)}
|
||||||
{user?.referredBy && (
|
{user?.referredBy && (
|
||||||
<p className="text-[#38bdac] text-sm mt-2">
|
<div className="inline-flex items-center gap-2 mt-4 px-4 py-2 rounded-full bg-[var(--app-brand-light)]">
|
||||||
通过邀请注册,{settings?.distributorShare || 90}%将返还给推荐人
|
<Users className="w-4 h-4 text-[var(--app-brand)]" />
|
||||||
</p>
|
<span className="text-[var(--app-brand)] text-sm">
|
||||||
|
推荐人将获得 {settings?.distributorShare || 90}% 返佣
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Payment Methods */}
|
{/* Payment Methods */}
|
||||||
<div className="p-6 space-y-3">
|
<div className="p-6">
|
||||||
<p className="text-gray-400 text-sm mb-3">选择支付方式</p>
|
<p className="text-[var(--app-text-tertiary)] text-sm mb-4">选择支付方式</p>
|
||||||
{availableMethods.map((method) => (
|
<div className="space-y-3">
|
||||||
<button
|
{availableMethods.map((method) => (
|
||||||
key={method.id}
|
<button
|
||||||
onClick={() => setPaymentMethod(method.id)}
|
key={method.id}
|
||||||
className={`w-full p-4 rounded-xl border flex items-center gap-4 transition-all ${
|
onClick={() => setPaymentMethod(method.id)}
|
||||||
paymentMethod === method.id
|
className={`w-full p-4 rounded-xl flex items-center gap-4 transition-all touch-feedback ${
|
||||||
? "border-[#38bdac] bg-[#38bdac]/10"
|
paymentMethod === method.id
|
||||||
: "border-gray-700 hover:border-gray-600 hover:bg-[#162840]"
|
? "glass-card-light border-[var(--app-brand)]/30"
|
||||||
}`}
|
: "glass-card hover:border-[var(--glass-border-light)]"
|
||||||
>
|
}`}
|
||||||
<div className={`w-10 h-10 rounded-lg ${method.color} flex items-center justify-center text-white`}>
|
>
|
||||||
{method.icon}
|
<div
|
||||||
</div>
|
className="w-12 h-12 rounded-xl flex items-center justify-center"
|
||||||
<div className="flex-1 text-left">
|
style={{ backgroundColor: method.iconBg, color: method.color }}
|
||||||
<span className="text-white">{method.name}</span>
|
>
|
||||||
{method.extra && <span className="text-gray-400 text-sm ml-2">{method.extra}</span>}
|
{method.icon}
|
||||||
</div>
|
</div>
|
||||||
{paymentMethod === method.id && <CheckCircle className="w-5 h-5 text-[#38bdac]" />}
|
<div className="flex-1 text-left">
|
||||||
</button>
|
<span className="text-white font-medium">{method.name}</span>
|
||||||
))}
|
{method.extra && (
|
||||||
{availableMethods.length === 0 && <p className="text-gray-500 text-center py-4">暂无可用支付方式</p>}
|
<span className="text-[var(--app-text-tertiary)] text-sm ml-2">{method.extra}</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
{paymentMethod === method.id && (
|
||||||
|
<div className="w-6 h-6 rounded-full bg-[var(--app-brand)] flex items-center justify-center">
|
||||||
|
<Check className="w-4 h-4 text-white" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</button>
|
||||||
|
))}
|
||||||
|
{availableMethods.length === 0 && (
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-center py-8">暂无可用支付方式</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Submit Button */}
|
{/* Submit Button */}
|
||||||
<div className="p-6 pt-0">
|
<div className="p-6 pt-0">
|
||||||
<Button
|
<button
|
||||||
onClick={handlePayment}
|
onClick={handlePayment}
|
||||||
disabled={isProcessing || availableMethods.length === 0}
|
disabled={isProcessing || availableMethods.length === 0}
|
||||||
className="w-full bg-[#38bdac] hover:bg-[#2da396] text-white py-6 text-lg"
|
className="btn-ios w-full glow text-lg disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isProcessing ? (
|
{isProcessing ? (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center justify-center gap-2">
|
||||||
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
<div className="w-5 h-5 border-2 border-white border-t-transparent rounded-full animate-spin" />
|
||||||
处理中...
|
处理中...
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
`确认支付 ¥${amount.toFixed(2)}`
|
`确认支付 ¥${amount.toFixed(2)}`
|
||||||
)}
|
)}
|
||||||
</Button>
|
</button>
|
||||||
<p className="text-gray-500 text-xs text-center mt-3">支付即表示同意《用户协议》和《隐私政策》</p>
|
<p className="text-[var(--app-text-tertiary)] text-xs text-center mt-4">
|
||||||
|
支付即表示同意《用户协议》和《隐私政策》
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import { useState, useEffect } from "react"
|
import { useState, useEffect } from "react"
|
||||||
import { Button } from "@/components/ui/button"
|
import { Zap, BookOpen, Check, TrendingUp } from "lucide-react"
|
||||||
import { Zap, BookOpen } from "lucide-react"
|
|
||||||
import { getFullBookPrice, getAllSections } from "@/lib/book-data"
|
import { getFullBookPrice, getAllSections } from "@/lib/book-data"
|
||||||
import { useStore } from "@/lib/store"
|
import { useStore } from "@/lib/store"
|
||||||
import { AuthModal } from "./modules/auth/auth-modal"
|
import { AuthModal } from "./modules/auth/auth-modal"
|
||||||
@@ -30,57 +29,111 @@ export function PurchaseSection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="py-8 px-4 bg-app-bg">
|
<section className="py-12 px-4">
|
||||||
<div className="max-w-sm mx-auto">
|
<div className="max-w-md mx-auto">
|
||||||
{/* Pricing cards - stacked on mobile */}
|
{/* 区域标题 */}
|
||||||
<div className="space-y-3">
|
<div className="text-center mb-8">
|
||||||
{/* Single section */}
|
<h2 className="text-xl font-semibold text-white mb-2">选择购买方式</h2>
|
||||||
<div className="bg-app-card/60 backdrop-blur-xl rounded-xl p-4 border border-app-border">
|
<p className="text-[var(--app-text-tertiary)] text-sm">一次付费,永久阅读</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 定价卡片 */}
|
||||||
|
<div className="space-y-4">
|
||||||
|
{/* 单节购买 */}
|
||||||
|
<div className="glass-card p-5 touch-feedback cursor-pointer">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-4">
|
||||||
<BookOpen className="w-5 h-5 text-app-text-muted" />
|
<div className="w-12 h-12 rounded-xl bg-[var(--app-bg-secondary)] flex items-center justify-center">
|
||||||
|
<BookOpen className="w-6 h-6 text-[var(--app-text-secondary)]" />
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-app-text font-medium text-sm">单节购买</h3>
|
<h3 className="text-white font-semibold mb-0.5">单节购买</h3>
|
||||||
<p className="text-app-text-muted text-xs">按兴趣选择</p>
|
<p className="text-[var(--app-text-tertiary)] text-sm">按兴趣选择章节</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="text-right">
|
<div className="text-right">
|
||||||
<span className="text-xl font-bold text-app-text">¥1</span>
|
<p className="text-2xl font-bold text-white">¥1</p>
|
||||||
<span className="text-app-text-muted text-xs">/节</span>
|
<p className="text-[var(--app-text-tertiary)] text-xs">/节</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Full book - highlighted */}
|
{/* 整本购买 - 推荐 */}
|
||||||
<div className="bg-gradient-to-br from-app-brand/20 to-app-card backdrop-blur-xl rounded-xl p-4 border border-app-brand/30 relative">
|
<div className="relative">
|
||||||
<span className="absolute -top-2 right-3 bg-app-brand text-white text-xs px-2 py-0.5 rounded-full">
|
{/* 推荐标签 */}
|
||||||
推荐
|
<div className="absolute -top-3 left-1/2 -translate-x-1/2 z-10">
|
||||||
</span>
|
<span className="inline-flex items-center gap-1 px-3 py-1 rounded-full bg-[var(--app-brand)] text-white text-xs font-medium shadow-lg">
|
||||||
|
<Zap className="w-3 h-3" />
|
||||||
<div className="flex items-center justify-between mb-3">
|
最划算
|
||||||
<div className="flex items-center gap-3">
|
</span>
|
||||||
<Zap className="w-5 h-5 text-app-brand" />
|
|
||||||
<div>
|
|
||||||
<h3 className="text-app-text font-medium text-sm">整本购买</h3>
|
|
||||||
<p className="text-app-text-muted text-xs">全部{sectionsCount}节 · 后续更新免费</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="text-right">
|
|
||||||
<span className="text-xl font-bold text-app-text">¥{fullBookPrice.toFixed(1)}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Button
|
<div
|
||||||
onClick={handlePurchase}
|
onClick={handlePurchase}
|
||||||
className="w-full bg-app-brand hover:bg-app-brand-hover text-white rounded-lg h-10 text-sm"
|
className="glass-card-heavy p-5 cursor-pointer touch-feedback border-[var(--app-brand)]/30 relative overflow-hidden"
|
||||||
>
|
>
|
||||||
立即购买
|
{/* 背景光效 */}
|
||||||
</Button>
|
<div className="absolute top-0 right-0 w-32 h-32 bg-[var(--app-brand)] opacity-[0.08] blur-[60px] rounded-full" />
|
||||||
|
|
||||||
|
<div className="relative">
|
||||||
|
<div className="flex items-center justify-between mb-4">
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<div className="w-12 h-12 rounded-xl bg-[var(--app-brand-light)] flex items-center justify-center">
|
||||||
|
<Zap className="w-6 h-6 text-[var(--app-brand)]" />
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 className="text-white font-semibold mb-0.5">整本购买</h3>
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-sm">
|
||||||
|
全部 {sectionsCount} 节内容
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="text-right">
|
||||||
|
<p className="text-3xl font-bold text-[var(--app-brand)]">¥{fullBookPrice.toFixed(1)}</p>
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-xs line-through">¥{sectionsCount}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 权益列表 */}
|
||||||
|
<div className="space-y-2 mb-5">
|
||||||
|
{[
|
||||||
|
"解锁全部 " + sectionsCount + " 节商业案例",
|
||||||
|
"后续更新内容免费阅读",
|
||||||
|
"专属读者社群入群资格",
|
||||||
|
"分销返佣最高90%"
|
||||||
|
].map((benefit, idx) => (
|
||||||
|
<div key={idx} className="flex items-center gap-2">
|
||||||
|
<div className="w-4 h-4 rounded-full bg-[var(--app-brand-light)] flex items-center justify-center">
|
||||||
|
<Check className="w-2.5 h-2.5 text-[var(--app-brand)]" />
|
||||||
|
</div>
|
||||||
|
<span className="text-[var(--app-text-secondary)] text-sm">{benefit}</span>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* 购买按钮 */}
|
||||||
|
<button className="btn-ios w-full glow flex items-center justify-center gap-2">
|
||||||
|
<span>立即购买</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Dynamic pricing note */}
|
{/* 动态定价说明 */}
|
||||||
<p className="mt-3 text-center text-app-text-muted text-xs">动态定价: 每新增一章节,整本价格+¥1</p>
|
<div className="mt-6 glass-card p-4">
|
||||||
|
<div className="flex items-center gap-3">
|
||||||
|
<div className="w-10 h-10 rounded-xl bg-[var(--ios-orange)]/20 flex items-center justify-center">
|
||||||
|
<TrendingUp className="w-5 h-5 text-[var(--ios-orange)]" />
|
||||||
|
</div>
|
||||||
|
<div className="flex-1">
|
||||||
|
<p className="text-white text-sm font-medium mb-0.5">动态定价机制</p>
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-xs">
|
||||||
|
每新增一章节,整本价格 +¥1,早买早优惠
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<AuthModal isOpen={isAuthOpen} onClose={() => setIsAuthOpen(false)} />
|
<AuthModal isOpen={isAuthOpen} onClose={() => setIsAuthOpen(false)} />
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
"use client"
|
"use client"
|
||||||
|
|
||||||
import Link from "next/link"
|
import Link from "next/link"
|
||||||
import { ChevronRight } from "lucide-react"
|
import { ChevronRight, BookOpen, FileText } from "lucide-react"
|
||||||
import { Part } from "@/lib/book-data"
|
import { Part } from "@/lib/book-data"
|
||||||
|
|
||||||
interface TableOfContentsProps {
|
interface TableOfContentsProps {
|
||||||
@@ -10,54 +10,79 @@ interface TableOfContentsProps {
|
|||||||
|
|
||||||
export function TableOfContents({ parts }: TableOfContentsProps) {
|
export function TableOfContents({ parts }: TableOfContentsProps) {
|
||||||
return (
|
return (
|
||||||
<section className="py-16 px-4">
|
<section className="py-12 px-4">
|
||||||
<div className="max-w-2xl mx-auto">
|
<div className="max-w-2xl mx-auto">
|
||||||
{/* Section title */}
|
{/* 区域标题 */}
|
||||||
<h2 className="text-gray-400 text-sm mb-8">全书 {parts.length} 篇</h2>
|
<div className="flex items-center justify-between mb-6">
|
||||||
|
<h2 className="text-[var(--app-text-secondary)] text-sm font-medium">
|
||||||
|
全书目录
|
||||||
|
</h2>
|
||||||
|
<span className="text-[var(--app-text-tertiary)] text-xs">
|
||||||
|
共 {parts.length} 篇
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Parts list */}
|
{/* 章节列表 - iOS列表风格 */}
|
||||||
<div className="space-y-6">
|
<div className="glass-card overflow-hidden mb-8">
|
||||||
{parts.map((part) => (
|
{parts.map((part, index) => (
|
||||||
<Link key={part.id} href={`/chapters?part=${part.id}`} className="block group">
|
<Link
|
||||||
<div className="bg-[#0f2137]/60 backdrop-blur-md rounded-xl p-6 border border-transparent hover:border-[#38bdac]/30 transition-all duration-300">
|
key={part.id}
|
||||||
<div className="flex items-start justify-between">
|
href={`/chapters?part=${part.id}`}
|
||||||
<div className="flex gap-4">
|
className="block touch-feedback"
|
||||||
<span className="text-[#38bdac] font-mono text-lg">{part.number}</span>
|
>
|
||||||
<div>
|
<div className={`list-item-ios ${index === 0 ? 'rounded-t-xl' : ''} ${index === parts.length - 1 ? 'rounded-b-xl border-b-0' : ''}`}>
|
||||||
<h3 className="text-white text-xl font-semibold mb-1 group-hover:text-[#38bdac] transition-colors">
|
<div className="flex items-center gap-4 flex-1 min-w-0">
|
||||||
{part.title}
|
{/* 序号标识 */}
|
||||||
</h3>
|
<div className="w-10 h-10 rounded-xl bg-[var(--app-brand-light)] flex items-center justify-center flex-shrink-0">
|
||||||
<p className="text-gray-400">{part.subtitle}</p>
|
<span className="text-[var(--app-brand)] font-bold text-sm">{part.number}</span>
|
||||||
<p className="text-gray-500 text-sm mt-2">
|
</div>
|
||||||
{part.chapters.length} 章 · {part.chapters.reduce((acc, c) => acc + c.sections.length, 0)} 节
|
|
||||||
</p>
|
{/* 内容 */}
|
||||||
</div>
|
<div className="flex-1 min-w-0">
|
||||||
|
<h3 className="text-white font-semibold text-base truncate mb-0.5">
|
||||||
|
{part.title}
|
||||||
|
</h3>
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-sm truncate">
|
||||||
|
{part.subtitle}
|
||||||
|
</p>
|
||||||
|
<p className="text-[var(--app-text-tertiary)] text-xs mt-1">
|
||||||
|
{part.chapters.length} 章 · {part.chapters.reduce((acc, c) => acc + c.sections.length, 0)} 节
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<ChevronRight className="w-5 h-5 text-gray-500 group-hover:text-[#38bdac] transition-colors" />
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* 箭头 */}
|
||||||
|
<ChevronRight className="w-5 h-5 text-[var(--app-text-tertiary)] flex-shrink-0" />
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Additional content */}
|
{/* 附加内容 - 序言和尾声 */}
|
||||||
<div className="mt-8 pt-8 border-t border-gray-700/50">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
<div className="grid grid-cols-2 gap-4">
|
<Link href="/chapters?section=preface" className="block touch-feedback">
|
||||||
<Link href="/chapters?section=preface" className="block group">
|
<div className="glass-card p-4 h-full">
|
||||||
<div className="bg-[#0f2137]/40 backdrop-blur-md rounded-xl p-4 border border-transparent hover:border-[#38bdac]/30 transition-all">
|
<div className="flex items-center gap-2 mb-2">
|
||||||
<p className="text-gray-400 text-sm">序言</p>
|
<BookOpen className="w-4 h-4 text-[var(--ios-blue)]" />
|
||||||
<p className="text-white group-hover:text-[#38bdac] transition-colors">
|
<span className="text-[var(--app-text-tertiary)] text-xs">序言</span>
|
||||||
为什么我每天早上6点在Soul开播?
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
<p className="text-white text-sm leading-relaxed text-ellipsis-2">
|
||||||
<Link href="/chapters?section=epilogue" className="block group">
|
为什么我每天早上6点在Soul开播?
|
||||||
<div className="bg-[#0f2137]/40 backdrop-blur-md rounded-xl p-4 border border-transparent hover:border-[#38bdac]/30 transition-all">
|
</p>
|
||||||
<p className="text-gray-400 text-sm">尾声</p>
|
</div>
|
||||||
<p className="text-white group-hover:text-[#38bdac] transition-colors">努力不是关键,选择才是</p>
|
</Link>
|
||||||
|
|
||||||
|
<Link href="/chapters?section=epilogue" className="block touch-feedback">
|
||||||
|
<div className="glass-card p-4 h-full">
|
||||||
|
<div className="flex items-center gap-2 mb-2">
|
||||||
|
<FileText className="w-4 h-4 text-[var(--ios-purple)]" />
|
||||||
|
<span className="text-[var(--app-text-tertiary)] text-xs">尾声</span>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
<p className="text-white text-sm leading-relaxed text-ellipsis-2">
|
||||||
</div>
|
努力不是关键,选择才是
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
4
记忆.md
4
记忆.md
@@ -69,7 +69,7 @@
|
|||||||
- **独创模式**:「云阿米巴」(核心心法:①分不属于对方的钱;②按创造价值分钱;③用稳定流量+便捷私域体系绑定合作方;拒绝分股份,现金激励更有效)。
|
- **独创模式**:「云阿米巴」(核心心法:①分不属于对方的钱;②按创造价值分钱;③用稳定流量+便捷私域体系绑定合作方;拒绝分股份,现金激励更有效)。
|
||||||
|
|
||||||
### **人脉与联系方式**
|
### **人脉与联系方式**
|
||||||
- **关键人脉**:夏茜、杨红、王诚鹏、章卫国、陈佳亮、李冰(木子)、慧娟(拉多)、陈裕彬、陈雪融、王路、黄鹭、庄建忠(庄老师)、吉咪宇(小吉)、李长俊、陈华宇(樊登陈总)、骆剑峰、陈鹭明(明哥)、李嘉柔(嘉柔)、天行、婼瑄(小吉或阿猫)。
|
- **关键人脉**:夏茜、王诚鹏、章卫国、陈佳亮、李冰(木子)、慧娟(拉多)、陈裕彬、陈雪融、王路、黄鹭、庄建忠(庄老师)、吉咪宇(小吉)、李长俊、陈华宇(樊登陈总)、骆剑峰、陈鹭明(明哥)、李嘉柔(嘉柔)、天行、婼瑄(小吉或阿猫)。
|
||||||
- **联系方式**:电话15880802661;微信28533368。
|
- **联系方式**:电话15880802661;微信28533368。
|
||||||
|
|
||||||
### **技术与数据信息**(仅限内部使用)
|
### **技术与数据信息**(仅限内部使用)
|
||||||
@@ -124,6 +124,6 @@
|
|||||||
- 融资计划:Pre-A轮融资300万,用于流量投放(60%)、系统升级(30%)、团队扩张(10%)。
|
- 融资计划:Pre-A轮融资300万,用于流量投放(60%)、系统升级(30%)、团队扩张(10%)。
|
||||||
|
|
||||||
### **卡若风格文章要求**
|
### **卡若风格文章要求**
|
||||||
- **结构**:开头自问自答→主体故事/反思(含具体数据,如“30个抖音号日播放量1万+”“10家企业月均分润1.2万”)→结尾行动指引(例:“现在扫码加微信,领取《私域云阿米巴操作手册》”)。
|
- **结构**:开头自问自答→主体故事/反思(含具体数据,如“”“10家企业月均分润1.2万”)→结尾行动指引(例:“现在扫码加微信,领取《私域云阿米巴操作手册》”)。
|
||||||
- **语言**:简洁直接(例:“别等了!流量不会自己来,现在行动才是关键!”);挑战传统(例:“别再求合作方签对赌协议,分现钱比占股更实在!”)。
|
- **语言**:简洁直接(例:“别等了!流量不会自己来,现在行动才是关键!”);挑战传统(例:“别再求合作方签对赌协议,分现钱比占股更实在!”)。
|
||||||
- **字数**:不低于2000字,数据需引用官方报告(如艾瑞咨询、企业后台数据)或聊天记录,避免臆造。
|
- **字数**:不低于2000字,数据需引用官方报告(如艾瑞咨询、企业后台数据)或聊天记录,避免臆造。
|
||||||
|
|||||||
Reference in New Issue
Block a user