Skip to content

Commit 4bd9377

Browse files
committed
merge: 响应式设计上线
2 parents cf40423 + 481c269 commit 4bd9377

10 files changed

Lines changed: 1783 additions & 448 deletions

File tree

docs/DESIGN_SYSTEM_RESEARCH.md

Lines changed: 805 additions & 0 deletions
Large diffs are not rendered by default.

docs/RESPONSIVE_DESIGN_RESEARCH.md

Lines changed: 419 additions & 0 deletions
Large diffs are not rendered by default.

platform/src/app/[locale]/layout.tsx

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,25 @@
11
import type { Metadata } from 'next'
2-
import { Noto_Sans_SC } from 'next/font/google'
2+
import { Inter, Noto_Sans_SC } from 'next/font/google'
33
import { NextIntlClientProvider } from 'next-intl'
44
import { getMessages } from 'next-intl/server'
55
import { notFound } from 'next/navigation'
66
import '../globals.css'
77
import { routing } from '@/i18n/routing'
88
import BackToTop from '@/components/BackToTop'
9-
import { ThemeProvider } from '@/components/ThemeProvider'
109

10+
// Inter - 英文主字体(高端感)
11+
const inter = Inter({
12+
subsets: ['latin'],
13+
variable: '--font-inter',
14+
display: 'swap',
15+
})
16+
17+
// Noto Sans SC - 中文主字体
1118
const notoSansSC = Noto_Sans_SC({
1219
subsets: ['latin'],
1320
weight: ['400', '500', '600', '700'],
1421
variable: '--font-sans',
22+
display: 'swap',
1523
})
1624

1725
export function generateStaticParams() {
@@ -36,8 +44,8 @@ export async function generateMetadata({
3644
}
3745

3846
const ogDescriptions = {
39-
en: 'One person, one company. AI builds it; you own 100%. 13 chapters, 111 tests, battle-tested methodology.',
40-
zh: '一个人就是一家公司。AI 帮你做,你拥有 100% 股权。13 章课程,111 个测试,实战验证的方法论。',
47+
en: 'One person, one company. AI builds it; you own 100%. 11 chapters, 111 tests, battle-tested methodology.',
48+
zh: '一个人就是一家公司。AI 帮你做,你拥有 100% 股权。11 章课程,111 个测试,实战验证的方法论。',
4149
}
4250

4351
return {
@@ -101,14 +109,12 @@ export default async function LocaleLayout({
101109
const messages = await getMessages()
102110

103111
return (
104-
<html lang={locale} className={notoSansSC.variable} suppressHydrationWarning>
112+
<html lang={locale} className={`${inter.variable} ${notoSansSC.variable}`}>
105113
<body className="font-sans antialiased">
106-
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
107-
<NextIntlClientProvider messages={messages}>
108-
{children}
109-
<BackToTop />
110-
</NextIntlClientProvider>
111-
</ThemeProvider>
114+
<NextIntlClientProvider messages={messages}>
115+
{children}
116+
<BackToTop />
117+
</NextIntlClientProvider>
112118
</body>
113119
</html>
114120
)

platform/src/app/[locale]/page.tsx

Lines changed: 140 additions & 149 deletions
Large diffs are not rendered by default.

platform/src/app/globals.css

Lines changed: 113 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -2,60 +2,34 @@
22
@tailwind components;
33
@tailwind utilities;
44

5-
/* Light mode (default) */
6-
:root {
7-
--surface-dim: #DED8E1;
8-
--surface: #FFFBFE;
9-
--surface-container: #F3EDF7;
10-
--surface-container-high: #ECE6F0;
11-
--surface-container-highest: #E6E0E9;
12-
--primary: #6750A4;
13-
--primary-container: #EADDFF;
14-
--primary-container-high: #D0BCFF;
15-
--on-primary: #21005D;
16-
--on-surface: #1C1B1F;
17-
--on-surface-variant: #49454F;
18-
--outline: #79747E;
19-
--outline-variant: #CAC4D0;
20-
--success: #006C4E;
21-
--danger: #BA1A1A;
22-
--warning: #8B5000;
23-
--body-bg: #FFFBFE;
24-
--body-color: #1C1B1F;
5+
/* ===== 基础样式 ===== */
6+
html {
7+
scroll-behavior: smooth;
258
}
269

27-
/* Dark mode */
28-
.dark {
29-
--surface-dim: #0f0f0f;
30-
--surface: #1C1B1F;
31-
--surface-container: #211F26;
32-
--surface-container-high: #2B2930;
33-
--surface-container-highest: #36343B;
34-
--primary: #d0bcff;
35-
--primary-container: #4F378B;
36-
--primary-container-high: #5A4694;
37-
--on-primary: #381E72;
38-
--on-surface: #E6E1E5;
39-
--on-surface-variant: #CAC4D0;
40-
--outline: #938F99;
41-
--outline-variant: #49454F;
42-
--success: #8BD3A8;
43-
--danger: #F2B8B5;
44-
--warning: #F9CB9C;
45-
--body-bg: #0f0f0f;
46-
--body-color: #E6E1E5;
10+
body {
11+
background-color: #141218;
12+
color: #E6E1E5;
13+
font-feature-settings: 'kern' 1, 'liga' 1;
14+
-webkit-font-smoothing: antialiased;
15+
-moz-osx-font-smoothing: grayscale;
4716
}
4817

49-
html {
50-
scroll-behavior: smooth;
18+
/* ===== 选中文字样式 ===== */
19+
::selection {
20+
background-color: rgba(208, 188, 255, 0.3);
21+
color: #E8DEF8;
5122
}
5223

53-
body {
54-
background-color: var(--body-bg);
55-
color: var(--body-color);
56-
transition: background-color 0.3s ease, color 0.2s ease;
24+
/* ===== M3 Elevation ===== */
25+
@layer utilities {
26+
.elevation-0 { box-shadow: none; }
27+
.elevation-1 { box-shadow: 0 1px 3px 1px rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.3); }
28+
.elevation-2 { box-shadow: 0 2px 6px 2px rgba(0, 0, 0, 0.15), 0 1px 2px 0 rgba(0, 0, 0, 0.3); }
29+
.elevation-3 { box-shadow: 0 4px 8px 3px rgba(0, 0, 0, 0.15), 0 1px 3px 0 rgba(0, 0, 0, 0.3); }
5730
}
5831

32+
/* ===== 动画 ===== */
5933
@keyframes shimmer {
6034
0% { background-position: -200% 0; }
6135
100% { background-position: 200% 0; }
@@ -65,15 +39,100 @@ body {
6539
animation: shimmer 1.5s infinite;
6640
background: linear-gradient(
6741
90deg,
68-
rgba(128, 128, 128, 0.1) 25%,
69-
rgba(128, 128, 128, 0.2) 50%,
70-
rgba(128, 128, 128, 0.1) 75%
42+
rgba(255, 255, 255, 0.04) 25%,
43+
rgba(255, 255, 255, 0.1) 50%,
44+
rgba(255, 255, 255, 0.04) 75%
7145
);
7246
background-size: 200% 100%;
7347
}
7448

75-
/* M3 Elevation */
76-
.elevation-0 { box-shadow: none; }
77-
.elevation-1 { box-shadow: 0 1px 3px rgba(0,0,0,0.12); }
78-
.elevation-2 { box-shadow: 0 4px 8px rgba(0,0,0,0.12); }
79-
.elevation-3 { box-shadow: 0 8px 24px rgba(0,0,0,0.16); }
49+
/* ===== 标题样式优化 ===== */
50+
h1, h2, h3, h4, h5, h6 {
51+
text-wrap: balance;
52+
}
53+
54+
/* ===== 段落样式优化 ===== */
55+
p {
56+
text-wrap: pretty;
57+
}
58+
59+
/* ===== 响应式字体(按比例缩放)=====
60+
* 使用 clamp(min, preferred, max) 实现动态缩放
61+
* preferred 使用 vw 单位,让字体随视口宽度缩放
62+
*
63+
* 示例:clamp(32px, 4vw, 64px)
64+
* → 最小 32px,最大 64px,中间值按视口宽度 4% 缩放
65+
*/
66+
@layer utilities {
67+
/* Hero 标题:32px - 80px */
68+
.text-responsive-hero {
69+
font-size: clamp(2rem, 5vw, 5rem);
70+
line-height: 1.15;
71+
}
72+
73+
/* 章节标题:28px - 48px */
74+
.text-responsive-section {
75+
font-size: clamp(1.75rem, 3.5vw, 3rem);
76+
line-height: 1.2;
77+
}
78+
79+
/* 副标题:16px - 24px */
80+
.text-responsive-subtitle {
81+
font-size: clamp(1rem, 2vw, 1.5rem);
82+
line-height: 1.6;
83+
}
84+
85+
/* 正文:14px - 18px */
86+
.text-responsive-body {
87+
font-size: clamp(0.875rem, 1.5vw, 1.125rem);
88+
line-height: 1.7;
89+
}
90+
91+
/* 按钮:16px - 20px */
92+
.text-responsive-button {
93+
font-size: clamp(1rem, 1.8vw, 1.25rem);
94+
}
95+
96+
/* 卡片标题:16px - 20px */
97+
.text-responsive-card {
98+
font-size: clamp(1rem, 1.8vw, 1.25rem);
99+
}
100+
101+
/* 小字:12px - 14px */
102+
.text-responsive-small {
103+
font-size: clamp(0.75rem, 1.2vw, 0.875rem);
104+
}
105+
}
106+
107+
/* ===== 响应式间距(按比例缩放)===== */
108+
@layer utilities {
109+
/* 章节上下间距:64px - 128px */
110+
.py-responsive-section {
111+
padding-top: clamp(4rem, 8vw, 8rem);
112+
padding-bottom: clamp(4rem, 8vw, 8rem);
113+
}
114+
115+
/* 卡片内边距:24px - 48px */
116+
.p-responsive-card {
117+
padding: clamp(1.5rem, 3vw, 3rem);
118+
}
119+
120+
/* 按钮内边距:16px - 32px */
121+
.px-responsive-button {
122+
padding-left: clamp(1rem, 2vw, 2rem);
123+
padding-right: clamp(1rem, 2vw, 2rem);
124+
}
125+
126+
.py-responsive-button {
127+
padding-top: clamp(0.75rem, 1.5vw, 1.25rem);
128+
padding-bottom: clamp(0.75rem, 1.5vw, 1.25rem);
129+
}
130+
}
131+
132+
/* ===== 响应式容器宽度 ===== */
133+
@layer utilities {
134+
/* 自适应容器:600px - 1200px */
135+
.max-w-responsive {
136+
max-width: clamp(37.5rem, 75vw, 75rem);
137+
}
138+
}

platform/src/components/BackToTop.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ export default function BackToTop() {
2424
onClick={scrollToTop}
2525
aria-label={t('tooltip')}
2626
title={t('tooltip')}
27-
className="fixed bottom-6 right-6 z-50 flex h-10 w-10 items-center justify-center rounded-full bg-surface-container text-onsurface shadow-m3-2 transition-opacity hover:bg-surface-container-high focus:outline-none focus:ring-2 focus:ring-primary/50"
27+
className="fixed bottom-6 right-6 z-50 flex h-10 w-10 items-center justify-center rounded-full bg-gray-800 text-white shadow-lg transition-opacity hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-gray-500"
2828
>
2929
<svg
3030
xmlns="http://www.w3.org/2000/svg"

platform/src/components/Navigation.tsx

Lines changed: 36 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import { useState, useEffect } from 'react'
44
import { useTranslations } from 'next-intl'
55
import { Link, useRouter } from '@/i18n/navigation'
66
import LanguageSwitcher from './LanguageSwitcher'
7-
import { ThemeToggle } from './ThemeToggle'
87

98
interface User {
109
id: string
@@ -37,50 +36,53 @@ export default function Navigation() {
3736
}
3837

3938
return (
40-
<nav className="fixed top-0 left-0 right-0 z-50 bg-surface-dim/90 backdrop-blur-lg border-b border-outline-variant/50">
39+
<nav className="fixed top-0 left-0 right-0 z-50 bg-surface/80 backdrop-blur-md border-b border-outline-variant">
4140
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
42-
<div className="flex items-center justify-between h-20">
43-
{/* M3 Title Large */}
44-
<Link href="/" className="text-[22px] font-medium text-onsurface">
41+
<div className="flex items-center justify-between h-16">
42+
<Link href="/" className="font-bold text-xl text-on-surface">
4543
CEO of One
4644
</Link>
4745

48-
{/* Desktop nav — M3 Body Small */}
46+
{/* Desktop nav */}
4947
<div className="hidden sm:flex items-center gap-6">
50-
<Link href="/courses" className="text-onsurface font-medium text-[14px]">
48+
<Link href="/courses" className="text-on-surface font-medium text-sm">
5149
{t('courses')}
5250
</Link>
53-
<Link href="/profile" className="text-onsurface-variant hover:text-onsurface transition-colors text-[14px]">
51+
<Link href="/profile" className="text-on-surface-variant hover:text-on-surface transition-colors text-sm">
5452
{t('myCourses')}
5553
</Link>
56-
<Link href="/dashboard" className="text-onsurface-variant hover:text-onsurface transition-colors text-[14px]">
54+
<Link href="/dashboard" className="text-on-surface-variant hover:text-on-surface transition-colors text-sm">
5755
{t('dashboard')}
5856
</Link>
59-
<Link href="/graduation" className="text-onsurface-variant hover:text-onsurface transition-colors text-[14px]">
57+
<Link href="/graduation" className="text-on-surface-variant hover:text-on-surface transition-colors text-sm">
6058
{t('graduate')}
6159
</Link>
6260
{user ? (
6361
<div className="flex items-center gap-3">
64-
<span className="text-onsurface text-[14px]">{t('greeting', { name: user.name })}</span>
65-
<button onClick={handleLogout} className="text-onsurface-variant hover:text-onsurface text-[14px] cursor-pointer">
62+
<span className="text-on-surface text-sm">{t('greeting', { name: user.name })}</span>
63+
<button onClick={handleLogout} className="text-on-surface-variant hover:text-on-surface text-sm cursor-pointer">
6664
{t('logout')}
6765
</button>
6866
</div>
6967
) : (
70-
<Link href="/auth" className="text-onsurface-variant hover:text-onsurface transition-colors text-[14px]">
68+
<Link href="/auth" className="text-on-surface-variant hover:text-on-surface transition-colors text-sm">
7169
{t('login')}
7270
</Link>
7371
)}
74-
<ThemeToggle />
75-
<LanguageSwitcher />
76-
<a href="https://github.com/AIwork4me/ceo-of-one" target="_blank" rel="noopener noreferrer" className="text-onsurface-variant hover:text-onsurface transition-colors text-[14px]">
72+
<a
73+
href="https://github.com/AIwork4me/ceo-of-one"
74+
target="_blank"
75+
rel="noopener noreferrer"
76+
className="text-on-surface-variant hover:text-on-surface transition-colors text-sm"
77+
>
7778
⭐ GitHub
7879
</a>
80+
<LanguageSwitcher />
7981
</div>
8082

8183
{/* Mobile hamburger */}
8284
<button
83-
className="sm:hidden text-onsurface text-xl cursor-pointer"
85+
className="sm:hidden text-on-surface text-xl cursor-pointer"
8486
onClick={() => setMenuOpen(!menuOpen)}
8587
>
8688
{menuOpen ? '✕' : '☰'}
@@ -90,25 +92,30 @@ export default function Navigation() {
9092
{/* Mobile menu */}
9193
{menuOpen && (
9294
<div className="sm:hidden pb-4 flex flex-col gap-3">
93-
<Link href="/courses" className="text-onsurface text-[14px]" onClick={() => setMenuOpen(false)}>{t('courses')}</Link>
94-
<Link href="/profile" className="text-onsurface-variant text-[14px]" onClick={() => setMenuOpen(false)}>{t('myCourses')}</Link>
95-
<Link href="/dashboard" className="text-onsurface-variant text-[14px]" onClick={() => setMenuOpen(false)}>{t('dashboard')}</Link>
96-
<Link href="/graduation" className="text-onsurface-variant text-[14px]" onClick={() => setMenuOpen(false)}>{t('graduate')}</Link>
95+
<Link href="/courses" className="text-on-surface text-sm" onClick={() => setMenuOpen(false)}>{t('courses')}</Link>
96+
<Link href="/profile" className="text-on-surface-variant text-sm" onClick={() => setMenuOpen(false)}>{t('myCourses')}</Link>
97+
<Link href="/dashboard" className="text-on-surface-variant text-sm" onClick={() => setMenuOpen(false)}>{t('dashboard')}</Link>
98+
<Link href="/graduation" className="text-on-surface-variant text-sm" onClick={() => setMenuOpen(false)}>{t('graduate')}</Link>
9799
{user ? (
98100
<>
99-
<span className="text-onsurface text-[14px]">{t('greeting', { name: user.name })}</span>
100-
<button onClick={handleLogout} className="text-onsurface-variant text-[14px] text-left cursor-pointer" >{t('logout')}</button>
101+
<span className="text-on-surface text-sm">{t('greeting', { name: user.name })}</span>
102+
<button onClick={handleLogout} className="text-on-surface-variant text-sm text-left cursor-pointer" >{t('logout')}</button>
101103
</>
102104
) : (
103-
<Link href="/auth" className="text-onsurface-variant text-[14px]" onClick={() => setMenuOpen(false)}>{t('login')}</Link>
105+
<Link href="/auth" className="text-on-surface-variant text-sm" onClick={() => setMenuOpen(false)}>{t('login')}</Link>
104106
)}
105-
<div className="flex items-center gap-4 pt-2">
106-
<ThemeToggle />
107-
<LanguageSwitcher />
108-
</div>
109-
<a href="https://github.com/AIwork4me/ceo-of-one" target="_blank" rel="noopener noreferrer" className="text-onsurface-variant text-[14px]" onClick={() => setMenuOpen(false)}>
107+
<a
108+
href="https://github.com/AIwork4me/ceo-of-one"
109+
target="_blank"
110+
rel="noopener noreferrer"
111+
className="text-on-surface-variant hover:text-on-surface text-sm"
112+
onClick={() => setMenuOpen(false)}
113+
>
110114
⭐ GitHub
111115
</a>
116+
<div className="pt-2">
117+
<LanguageSwitcher />
118+
</div>
112119
</div>
113120
)}
114121
</div>

0 commit comments

Comments
 (0)