feat: iOS app - design tokens, 22 pages, navigation, onboarding
@ -1,17 +1,186 @@
|
||||
//
|
||||
// AIStudyAppApp.swift
|
||||
// AIStudyApp
|
||||
//
|
||||
// Created by DSR on 2026/5/4.
|
||||
// AIStudyAppApp.swift - 根路由:引导流程 vs 主界面
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
@main
|
||||
struct AIStudyAppApp: App {
|
||||
@AppStorage("hasCompletedOnboarding") private var hasCompletedOnboarding = false
|
||||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
ContentView()
|
||||
if hasCompletedOnboarding {
|
||||
ContentView()
|
||||
.preferredColorScheme(.dark)
|
||||
} else {
|
||||
OnboardingFlowView(hasCompletedOnboarding: $hasCompletedOnboarding)
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Onboarding Flow (Splash → Welcome → Login → Onboarding → GoalSetup)
|
||||
// 对应 React: SplashPage, WelcomePage, LoginPage, OnboardingPage, GoalSetupPage
|
||||
|
||||
struct OnboardingFlowView: View {
|
||||
@Binding var hasCompletedOnboarding: Bool
|
||||
@State private var step = 0
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
switch step {
|
||||
case 0: SplashPage { withAnimation(.easeInOut(duration: 0.5)) { step = 1 } }
|
||||
case 1: WelcomePage { withAnimation { step = 2 } } onSkip: { hasCompletedOnboarding = true }
|
||||
case 2: LoginPage { step = 3 } onSkip: { hasCompletedOnboarding = true }
|
||||
case 3: OnboardingPage { step = 4 }
|
||||
case 4: GoalSetupPage { $0 ? (hasCompletedOnboarding = true) : (step = 0) }
|
||||
default: EmptyView()
|
||||
}
|
||||
}
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
|
||||
// Splash
|
||||
struct SplashPage: View {
|
||||
let onFinish: () -> Void
|
||||
var body: some View {
|
||||
ZStack {
|
||||
LinearGradient(colors: [Color(hex: "#0D0D20"), Color(hex: "#0F0F1A"), Color(hex: "#130D20")], startPoint: .top, endPoint: .bottom).ignoresSafeArea()
|
||||
Circle().fill(RadialGradient(colors: [Color(hex: "#7C6EFA", opacity: 0.25), .clear], center: .center, startRadius: 0, endRadius: 140)).frame(width: 280, height: 280).offset(y: -60).allowsHitTesting(false)
|
||||
Circle().fill(RadialGradient(colors: [Color(hex: "#F97316", opacity: 0.15), .clear], center: .center, startRadius: 0, endRadius: 100)).frame(width: 200, height: 200).offset(y: 180).allowsHitTesting(false)
|
||||
VStack(spacing: 0) {
|
||||
RoundedRectangle(cornerRadius: 28)
|
||||
.fill(LinearGradient(colors: [Color(hex: "#7C6EFA"), Color(hex: "#A78BFA"), Color(hex: "#F97316")], startPoint: .topLeading, endPoint: .bottomTrailing))
|
||||
.frame(width: 96, height: 96)
|
||||
.overlay(Image(systemName: "brain.head.profile").font(.system(size: 44)).foregroundColor(.white.opacity(0.8)))
|
||||
.shadow(color: Color(hex: "#7C6EFA", opacity: 0.5), radius: 40)
|
||||
.padding(.bottom, 24)
|
||||
Text("知习")
|
||||
.font(.system(size: 36, weight: .heavy)).tracking(-1)
|
||||
.foregroundStyle(LinearGradient(colors: [Color(hex: "#A78BFA"), Color(hex: "#F0F0FF"), Color(hex: "#F97316")], startPoint: .leading, endPoint: .trailing))
|
||||
Text("Z H I X I").font(.system(size: 13, weight: .medium)).foregroundColor(Color(hex: "#F0F0FF", opacity: 0.4)).tracking(3).padding(.top, 6)
|
||||
Text("AI-first 系统化学习").font(.system(size: 14)).foregroundColor(Color(hex: "#F0F0FF", opacity: 0.45)).tracking(0.5).padding(.top, 24)
|
||||
}
|
||||
VStack { Spacer()
|
||||
ZStack(alignment: .leading) { RoundedRectangle(cornerRadius: 2).fill(Color(hex: "#FFFFFF", opacity: 0.1)).frame(width: 40, height: 3); RoundedRectangle(cornerRadius: 2).fill(LinearGradient(colors: [.zxPurple, Color.zxOrange], startPoint: .leading, endPoint: .trailing)).frame(width: 24, height: 3) }
|
||||
.padding(.bottom, 80)
|
||||
}
|
||||
}
|
||||
.onAppear { DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { onFinish() } }
|
||||
}
|
||||
}
|
||||
|
||||
// Welcome
|
||||
struct WelcomePage: View {
|
||||
let onContinue: () -> Void; let onSkip: () -> Void
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ZXGradient.page.ignoresSafeArea()
|
||||
Circle().fill(RadialGradient(colors: [Color(hex: "#7C6EFA", opacity: 0.12), .clear], center: .topTrailing, startRadius: 0, endRadius: 260)).frame(width: 260, height: 260).offset(x: 80, y: -120).allowsHitTesting(false)
|
||||
VStack { Spacer()
|
||||
VStack(spacing: 14) {
|
||||
HStack(spacing: 6) { Image(systemName: "sparkles").font(.system(size: 12)); Text("AI 驱动").font(.system(size: 12, weight: .semibold)) }
|
||||
.foregroundColor(Color.zxAccent).padding(.horizontal, 12).padding(.vertical, 6).background(Color(hex: "#7C6EFA", opacity: 0.1)).clipShape(Capsule())
|
||||
Text("用 AI 重新定义\n你的学习方式").font(.system(size: 32, weight: .heavy)).tracking(-0.8).lineSpacing(4)
|
||||
VStack(spacing: 10) { FeatureRow(icon: "🧠", title: "主动回忆", desc: "基于间隔重复的智能复习"); FeatureRow(icon: "🎤", title: "费曼解释", desc: "用自己的话讲出来"); FeatureRow(icon: "📊", title: "AI 分析", desc: "发现知识薄弱点") }
|
||||
}
|
||||
VStack(spacing: 12) { Button { onContinue() } label: { Text("开始使用").font(.system(size: 16, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 56).background(ZXGradient.ctaButton).clipShape(RoundedRectangle(cornerRadius: 18)).shadow(color: Color(hex: "#7C6EFA", opacity: 0.4), radius: 20) }; Button { onSkip() } label: { Text("已有账号?立即登录").font(.system(size: 14, weight: .medium)).foregroundColor(Color(hex: "#F0F0FF", opacity: 0.7)) }.padding(.bottom, 32) }
|
||||
}.padding(.horizontal, 20)
|
||||
}
|
||||
}
|
||||
}
|
||||
struct FeatureRow: View { let icon: String; let title: String; let desc: String
|
||||
var body: some View { HStack(spacing: 14) { Text(icon).font(.system(size: 20)).frame(width: 40, height: 40).background(Color(hex: "#7C6EFA", opacity: 0.1)).clipShape(RoundedRectangle(cornerRadius: 12)); VStack(alignment: .leading, spacing: 2) { Text(title).font(.system(size: 14, weight: .semibold)).foregroundColor(Color.zxF0); Text(desc).font(.system(size: 12)).foregroundColor(Color.zxF04) } }.padding(.horizontal, 16).padding(.vertical, 14).background(Color.zxFill003).overlay(RoundedRectangle(cornerRadius: 16).stroke(Color.zxBorder006, lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 16)) }
|
||||
}
|
||||
|
||||
// Login
|
||||
struct LoginPage: View {
|
||||
let onContinue: () -> Void; let onSkip: () -> Void
|
||||
@State private var isEmail = false; @State private var phone = ""; @State private var email = ""; @State private var pw = ""; @State private var showPw = false
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color.zxBg0.ignoresSafeArea()
|
||||
Circle().fill(RadialGradient(colors: [Color(hex: "#7C6EFA", opacity: 0.1), .clear], center: .top, startRadius: 0, endRadius: 200)).frame(width: 200, height: 200).offset(y: -60).allowsHitTesting(false)
|
||||
VStack { Spacer()
|
||||
VStack(spacing: 24) {
|
||||
VStack(spacing: 6) { Text("欢迎登录").font(.system(size: 28, weight: .heavy)).tracking(-0.6); Text("使用手机号或邮箱登录").font(.system(size: 14)).foregroundColor(Color.zxF05) }
|
||||
HStack(spacing: 4) { tabBtn("手机号", !isEmail) { isEmail = false }; tabBtn("邮箱", isEmail) { isEmail = true } }.padding(4).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 12))
|
||||
if isEmail {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("邮箱").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxF035).tracking(0.5)
|
||||
ZXInputField(placeholder: "your@email.com", text: $email)
|
||||
}
|
||||
} else {
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("手机号").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxF035).tracking(0.5)
|
||||
HStack(spacing: 0) { Text("+86").font(.system(size: 14, weight: .semibold)).foregroundColor(Color.zxF0).padding(.trailing, 12).overlay(alignment: .trailing) { Rectangle().fill(Color.zxBorder01).frame(width: 1).padding(.vertical, 4) }.padding(.trailing, 12); TextField("手机号", text: $phone).keyboardType(.phonePad).font(.system(size: 15)).tint(Color.zxPurple) }.padding(.horizontal, 16).frame(height: 52).background(Color.zxFill004).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 14))
|
||||
}
|
||||
}
|
||||
ZXInputField(placeholder: "密码", text: $pw, isSecure: !showPw)
|
||||
HStack { Spacer(); Button { showPw.toggle() } label: { Image(systemName: showPw ? "eye" : "eye.slash").font(.system(size: 16)).foregroundColor(Color.zxF03) } }.padding(.trailing, 4)
|
||||
HStack { Spacer(); Button("忘记密码?") {}.font(.system(size: 13)).foregroundColor(Color.zxPurple) }
|
||||
Button { onContinue() } label: { Text("登录").font(.system(size: 16, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 56).background(ZXGradient.ctaButton).clipShape(RoundedRectangle(cornerRadius: 18)).shadow(color: Color(hex: "#7C6EFA", opacity: 0.4), radius: 20) }
|
||||
HStack(spacing: 12) { Rectangle().fill(Color.zxBorder008).frame(height: 1); Text("或").font(.system(size: 12)).foregroundColor(Color.zxF03); Rectangle().fill(Color.zxBorder008).frame(height: 1) }
|
||||
HStack(spacing: 12) { SocialLoginBtn(emoji: "💬", text: "微信登陆", color: .green) {}; SocialLoginBtn(emoji: "🍎", text: "Apple 登录", color: .white) {} }
|
||||
}.padding(.horizontal, 20).padding(.bottom, 32)
|
||||
}
|
||||
}
|
||||
}
|
||||
func tabBtn(_ t: String, _ active: Bool, _ a: @escaping () -> Void) -> some View { Button(action: a) { Text(t).font(.system(size: 13, weight: .semibold)).foregroundColor(active ? .white : Color.zxF05).frame(maxWidth: .infinity).frame(height: 36).background(active ? AnyView(ZXGradient.brand) : AnyView(Color.clear)).clipShape(RoundedRectangle(cornerRadius: 9)) } }
|
||||
}
|
||||
struct ZXInputField: View { let placeholder: String; @Binding var text: String; var isSecure = false
|
||||
var body: some View { HStack { if isSecure { SecureField(placeholder, text: $text) } else { TextField(placeholder, text: $text) } }.font(.system(size: 15)).tint(Color.zxPurple).padding(.horizontal, 16).frame(height: 52).background(Color.zxFill004).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 14)) }
|
||||
}
|
||||
struct SocialLoginBtn: View { let emoji: String; let text: String; let color: Color; let action: () -> Void
|
||||
var body: some View { Button(action: action) { HStack(spacing: 10) { Text(emoji).font(.system(size: 18)); Text(text).font(.system(size: 11, weight: .medium)) }.foregroundColor(Color.zxF007).frame(maxWidth: .infinity).frame(height: 52).background(Color.zxFill004).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 14)) } }
|
||||
}
|
||||
|
||||
// Onboarding
|
||||
struct OnboardingPage: View {
|
||||
let onContinue: () -> Void
|
||||
@State private var step = 0
|
||||
let titles = ["输入知识", "主动输出", "AI 分析", "掌握知识"]
|
||||
let descs = ["从任何地方收集并导入学习资料,构建你的专属知识库。", "通过间隔回忆和费曼解释法,将知识转化为长期记忆。", "AI 自动定位薄弱知识点,给出针对性的学习建议。", "系统性掌握每一个知识点,建立牢固的知识体系。"]
|
||||
let icons = ["square.and.arrow.down", "brain.head.profile", "sparkle.magnifyingglass", "chart.line.uptrend.xyaxis"]
|
||||
var body: some View {
|
||||
ZStack { ZXGradient.page.ignoresSafeArea()
|
||||
VStack(spacing: 0) { Spacer()
|
||||
HStack(spacing: 6) { ForEach(0..<4, id: \.self) { i in RoundedRectangle(cornerRadius: 2).fill(i == step ? AnyShapeStyle(ZXGradient.brand) : AnyShapeStyle(Color(hex: "#FFFFFF", opacity: 0.1))).frame(width: i == step ? 24 : 8, height: 4) } }
|
||||
VStack(spacing: 12) { Text(titles[step]).font(.system(size: 24, weight: .heavy)).tracking(-0.5); Text(descs[step]).font(.system(size: 14)).foregroundColor(Color.zxF04).lineSpacing(4).multilineTextAlignment(.center) }.padding(.top, 32).padding(.bottom, 40)
|
||||
Button { if step < 3 { withAnimation { step += 1 } } else { onContinue() } } label: { Text(step < 3 ? "下一步" : "开始使用").font(.system(size: 16, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 56).background(ZXGradient.ctaButton).clipShape(RoundedRectangle(cornerRadius: 18)).shadow(color: Color(hex: "#7C6EFA", opacity: 0.4), radius: 20) }
|
||||
Button("跳过") { onContinue() }.font(.system(size: 12)).foregroundColor(Color.zxF03).padding(.top, 12).padding(.bottom, 32)
|
||||
}.padding(.horizontal, 20)
|
||||
}
|
||||
}
|
||||
}
|
||||
struct GoalSetupPage: View {
|
||||
let onComplete: (Bool) -> Void // true = launch app
|
||||
@State private var selectedGoal = ""
|
||||
let goals = [("🧑🎓","备考考试","公考、考研、考证等"),("💼","职业技能","编程、设计、产品等"),("📚","通识学习","扩充知识面"),("🎯","自定义","设定自己的目标")]
|
||||
@State private var selectedMethod = ""
|
||||
let methods = ["间隔回忆","费曼技巧","AI 分析"]
|
||||
@State private var dailyMins = "30 分钟"
|
||||
let times = ["15 分钟","30 分钟","1 小时","不限制"]
|
||||
var body: some View {
|
||||
ZStack { ZXGradient.page.ignoresSafeArea()
|
||||
VStack(spacing: 0) { Spacer()
|
||||
Text("设定你的学习目标").font(.system(size: 24, weight: .heavy)).tracking(-0.5).foregroundColor(Color.zxF0).padding(.bottom, 24)
|
||||
ScrollView { VStack(spacing: 16) {
|
||||
VStack(alignment: .leading, spacing: 10) { Text("学习目标").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxF035).tracking(0.5)
|
||||
ForEach(goals, id: \.1) { g in let sel = selectedGoal == g.1; Button { selectedGoal = g.1 } label: { HStack(spacing: 12) { Text(g.0).font(.system(size: 22)).frame(width: 44, height: 44).background(sel ? Color(hex: "#7C6EFA", opacity: 0.15) : Color.zxFill005).clipShape(RoundedRectangle(cornerRadius: 12)); VStack(alignment: .leading, spacing: 2) { Text(g.1).font(.system(size: 15, weight: .semibold)).foregroundColor(sel ? Color.zxPurple : Color.zxF0); Text(g.2).font(.system(size: 12)).foregroundColor(Color.zxF04) }; Spacer(); Circle().stroke(sel ? Color.zxPurple : Color(hex: "#FFFFFF", opacity: 0.2), lineWidth: 2).frame(width: 22, height: 22).overlay { if sel { Circle().fill(Color.zxPurple).frame(width: 12, height: 12) } } }.padding(14).background(sel ? Color(hex: "#7C6EFA", opacity: 0.08) : Color.zxFill003).overlay(RoundedRectangle(cornerRadius: 16).stroke(sel ? Color(hex: "#7C6EFA", opacity: 0.25) : Color.zxBorder006, lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 16)) }.foregroundColor(.primary) }
|
||||
}
|
||||
VStack(alignment: .leading, spacing: 10) { Text("学习方法").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxF035).tracking(0.5)
|
||||
HStack(spacing: 8) { ForEach(methods, id: \.self) { m in let sel = selectedMethod == m; Button { selectedMethod = m } label: { Text(m).font(.system(size: 13)).fontWeight(sel ? .semibold : .regular).foregroundColor(sel ? Color.zxPurple : Color.zxF05).padding(.horizontal, 16).padding(.vertical, 10).background(sel ? Color(hex: "#7C6EFA", opacity: 0.1) : Color.zxFill003).overlay(RoundedRectangle(cornerRadius: 20).stroke(sel ? Color(hex: "#7C6EFA", opacity: 0.25) : Color.zxBorder006, lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 20)) }.foregroundColor(.primary) } }
|
||||
}
|
||||
VStack(alignment: .leading, spacing: 10) { Text("每日学习时间").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxF035).tracking(0.5)
|
||||
HStack(spacing: 8) { ForEach(times, id: \.self) { t in let sel = dailyMins == t; Button { dailyMins = t } label: { Text(t).font(.system(size: 12)).fontWeight(sel ? .semibold : .regular).foregroundColor(sel ? Color.zxPurple : Color.zxF05).frame(maxWidth: .infinity).frame(height: 40).background(sel ? Color(hex: "#7C6EFA", opacity: 0.1) : Color.zxFill003).overlay(RoundedRectangle(cornerRadius: 12).stroke(sel ? Color(hex: "#7C6EFA", opacity: 0.25) : Color.zxBorder006, lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 12)) }.foregroundColor(.primary) } }
|
||||
}
|
||||
} }.padding(.horizontal, 20)
|
||||
Button { onComplete(true) } label: { Text("开始学习").font(.system(size: 16, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 56).background(ZXGradient.ctaButton).clipShape(RoundedRectangle(cornerRadius: 18)).shadow(color: Color(hex: "#7C6EFA", opacity: 0.4), radius: 20) }.padding(.top, 24).padding(.bottom, 32).padding(.horizontal, 20)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,24 +1,111 @@
|
||||
//
|
||||
// ContentView.swift
|
||||
// AIStudyApp
|
||||
//
|
||||
// Created by DSR on 2026/5/4.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ContentView: View {
|
||||
@State private var selectedTab = "ai"
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
Image(systemName: "globe")
|
||||
.imageScale(.large)
|
||||
.foregroundStyle(.tint)
|
||||
Text("Hello, world!")
|
||||
ZStack {
|
||||
switch selectedTab {
|
||||
case "ai": NavigationStack { AIHomeView() }
|
||||
case "library": NavigationStack { LibraryHomeView() }
|
||||
case "study": NavigationStack { StudyHomeView() }
|
||||
case "analysis": NavigationStack { AnalysisHomeView() }
|
||||
case "profile": NavigationStack { ProfileView() }
|
||||
default: NavigationStack { AIHomeView() }
|
||||
}
|
||||
VStack { Spacer(); ZXTabBar(active: $selectedTab) }
|
||||
.ignoresSafeArea(edges: .bottom)
|
||||
}
|
||||
.padding()
|
||||
.ignoresSafeArea(edges: .bottom)
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
ContentView()
|
||||
// MARK: - AI Input Bar
|
||||
|
||||
struct ZXAIInputBar: View {
|
||||
@Binding var text: String
|
||||
let onSend: () -> Void
|
||||
var body: some View {
|
||||
HStack(spacing: 10) {
|
||||
Image(systemName: "sparkles").font(.system(size: 16)).foregroundColor(Color.zxPurple)
|
||||
TextField("问 AI 任何学习问题…", text: $text).font(.system(size: 14)).tint(Color.zxPurple)
|
||||
Spacer()
|
||||
Image(systemName: "mic.fill").font(.system(size: 18)).foregroundColor(Color.zxF03)
|
||||
Button(action: onSend) {
|
||||
Image(systemName: "arrow.up").font(.system(size: 14, weight: .bold)).foregroundColor(.white)
|
||||
.frame(width: 30, height: 30).background(ZXGradient.brand).clipShape(RoundedRectangle(cornerRadius: 9))
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 14).padding(.vertical, 10)
|
||||
.background(.ultraThinMaterial).background(Color.zxFill004)
|
||||
.overlay(RoundedRectangle(cornerRadius: 20).stroke(Color.zxBorder008, lineWidth: 1))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20))
|
||||
.padding(.horizontal, 20).padding(.bottom, 34)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Score Box
|
||||
|
||||
struct ZXScoreBox: View {
|
||||
let score: Int; let bg: Color; let fg: Color
|
||||
var body: some View {
|
||||
Text("\(score)").font(.system(size: 12, weight: .heavy)).foregroundColor(fg)
|
||||
.frame(width: 36, height: 36).background(bg).clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
}
|
||||
}
|
||||
|
||||
struct ZXTabBar: View {
|
||||
@Binding var active: String
|
||||
private let tabs = [
|
||||
("ai","AI","brain.head.profile"),
|
||||
("library","知识库","books.vertical.fill"),
|
||||
("study","学习","bolt.fill"),
|
||||
("analysis","分析","chart.bar.fill"),
|
||||
("profile","我的","person.fill"),
|
||||
]
|
||||
var body: some View {
|
||||
HStack(spacing: 0) {
|
||||
ForEach(tabs, id: \.0) { item in
|
||||
let on = item.0 == active
|
||||
Button { active = item.0 } label: {
|
||||
VStack(spacing: 4) {
|
||||
ZStack {
|
||||
if on {
|
||||
Circle().fill(Color.zxPurple.opacity(0.2))
|
||||
.frame(width: 28, height: 28).scaleEffect(1.4)
|
||||
}
|
||||
Image(systemName: item.2)
|
||||
.font(.system(size: 22, weight: on ? .semibold : .regular))
|
||||
.foregroundColor(on ? Color.zxPurple : Color(hex: "#F0F0FF", opacity: 0.35))
|
||||
}
|
||||
Text(item.1)
|
||||
.font(.system(size: 10, weight: on ? .semibold : .regular))
|
||||
.foregroundColor(on ? Color.zxPurple : Color(hex: "#F0F0FF", opacity: 0.35))
|
||||
}
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
.padding(.top, 6).padding(.bottom, 34).frame(height: 83)
|
||||
.background(.ultraThinMaterial).background(Color.zxBg0.opacity(0.95))
|
||||
.overlay(alignment: .top) {
|
||||
Rectangle().fill(Color.zxBorder008).frame(height: 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Shared Icon Button
|
||||
|
||||
struct ZXIconBtn: View {
|
||||
let icon: String; let size: CGFloat; var branded = false; let action: () -> Void
|
||||
var body: some View {
|
||||
Button(action: action) {
|
||||
Image(systemName: icon).font(.system(size: size * 0.44)).frame(width: size, height: size)
|
||||
}
|
||||
.foregroundColor(branded ? .white : Color.zxF05)
|
||||
.background(branded ? AnyView(ZXGradient.brand) : AnyView(Color(hex: "#FFFFFF", opacity: 0.05)))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.overlay { if !branded { RoundedRectangle(cornerRadius: 10).stroke(Color.zxBorder008, lineWidth: 1) } }
|
||||
}
|
||||
}
|
||||
|
||||
261
AIStudyApp/AIStudyApp/Core/DesignSystem/DesignTokens.swift
Normal file
@ -0,0 +1,261 @@
|
||||
//
|
||||
// DesignTokens.swift
|
||||
// AIStudyApp
|
||||
//
|
||||
// 1:1 像素级还原 React 原型的设计令牌
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - Hex Color Extension
|
||||
|
||||
extension Color {
|
||||
init(hex: String, opacity: Double = 1.0) {
|
||||
let hex = hex.trimmingCharacters(in: CharacterSet.alphanumerics.inverted)
|
||||
var int: UInt64 = 0
|
||||
Scanner(string: hex).scanHexInt64(&int)
|
||||
let r, g, b: UInt64
|
||||
switch hex.count {
|
||||
case 6:
|
||||
(r, g, b) = ((int >> 16) & 0xFF, (int >> 8) & 0xFF, int & 0xFF)
|
||||
case 8:
|
||||
(r, g, b) = ((int >> 24) & 0xFF, (int >> 16) & 0xFF, (int >> 8) & 0xFF)
|
||||
default:
|
||||
(r, g, b) = (0, 0, 0)
|
||||
}
|
||||
self.init(.sRGB, red: Double(r) / 255, green: Double(g) / 255, blue: Double(b) / 255, opacity: opacity)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - ZhiXi Colors (exact match from React index.css)
|
||||
|
||||
extension Color {
|
||||
// ── 背景 ──
|
||||
static let zxBg0 = Color(hex: "#0F0F1A")
|
||||
static let zxBg1 = Color(hex: "#12122A")
|
||||
static let zxBg2 = Color(hex: "#0A0A14") // phone shell
|
||||
static let zxBgSplash = Color(hex: "#0D0D20")
|
||||
|
||||
// ── 文字 ──
|
||||
static let zxF0 = Color(hex: "#F0F0FF")
|
||||
static let zxF05 = Color(hex: "#F0F0FF", opacity: 0.5)
|
||||
static let zxF04 = Color(hex: "#F0F0FF", opacity: 0.4)
|
||||
static let zxF03 = Color(hex: "#F0F0FF", opacity: 0.3)
|
||||
static let zxF007 = Color(hex: "#F0F0FF", opacity: 0.7)
|
||||
static let zxF006 = Color(hex: "#F0F0FF", opacity: 0.6)
|
||||
static let zxF0045 = Color(hex: "#F0F0FF", opacity: 0.45)
|
||||
|
||||
// ── 品牌色 ──
|
||||
static let zxPurple = Color(hex: "#7C6EFA")
|
||||
static let zxOrange = Color(hex: "#F97316")
|
||||
static let zxAccent = Color(hex: "#A78BFA")
|
||||
static let zxTeal = Color(hex: "#2DD4BF")
|
||||
static let zxGreen = Color(hex: "#34D399")
|
||||
static let zxYellow = Color(hex: "#F59E0B")
|
||||
static let zxRed = Color(hex: "#EF4444")
|
||||
static let zxCyan = Color(hex: "#4ECDC4")
|
||||
|
||||
static let zxF02 = Color(hex: "#F0F0FF", opacity: 0.2)
|
||||
static let zxFill01 = Color(hex: "#FFFFFF", opacity: 0.1)
|
||||
|
||||
// ── 边框/分割线 ──
|
||||
static let zxBorder008 = Color(hex: "#FFFFFF", opacity: 0.08)
|
||||
static let zxBorder006 = Color(hex: "#FFFFFF", opacity: 0.06)
|
||||
static let zxBorder004 = Color(hex: "#FFFFFF", opacity: 0.04)
|
||||
static let zxBorder01 = Color(hex: "#FFFFFF", opacity: 0.10)
|
||||
static let zxBorder015 = Color(hex: "#FFFFFF", opacity: 0.15)
|
||||
|
||||
// ── 半透明填充 ──
|
||||
static let zxFill003 = Color(hex: "#FFFFFF", opacity: 0.03)
|
||||
static let zxFill004 = Color(hex: "#FFFFFF", opacity: 0.04)
|
||||
static let zxFill005 = Color(hex: "#FFFFFF", opacity: 0.05)
|
||||
static let zxFill006 = Color(hex: "#FFFFFF", opacity: 0.06)
|
||||
static let zxFill008 = Color(hex: "#FFFFFF", opacity: 0.08)
|
||||
|
||||
// ── 彩色半透 ──
|
||||
static func zxPurpleBG(_ a: Double = 0.10) -> Color { Color(hex: "#7C6EFA", opacity: a) }
|
||||
static func zxOrangeBG(_ a: Double = 0.10) -> Color { Color(hex: "#F97316", opacity: a) }
|
||||
static func zxGreenBG(_ a: Double = 0.10) -> Color { Color(hex: "#34D399", opacity: a) }
|
||||
static func zxYellowBG(_ a: Double = 0.10) -> Color { Color(hex: "#F59E0B", opacity: a) }
|
||||
static func zxTealBG(_ a: Double = 0.10) -> Color { Color(hex: "#4ECDC4", opacity: a) }
|
||||
static func zxRedBG(_ a: Double = 0.15) -> Color { Color(hex: "#EF4444", opacity: a) }
|
||||
}
|
||||
|
||||
// MARK: - ZhiXi Gradients (exact match)
|
||||
|
||||
enum ZXGradient {
|
||||
// ── 页面背景 ──
|
||||
static let page = LinearGradient(
|
||||
colors: [Color(hex: "#0F0F1A"), Color(hex: "#12122A")],
|
||||
startPoint: .top, endPoint: .bottom
|
||||
)
|
||||
|
||||
// ── 品牌渐变 (135deg) ──
|
||||
static let brand = LinearGradient(
|
||||
colors: [Color(hex: "#7C6EFA"), Color(hex: "#F97316")],
|
||||
startPoint: .topLeading, endPoint: .bottomTrailing
|
||||
)
|
||||
|
||||
static let brandPurple = LinearGradient(
|
||||
colors: [Color(hex: "#7C6EFA"), Color(hex: "#9B8BFF")],
|
||||
startPoint: .leading, endPoint: .trailing
|
||||
)
|
||||
|
||||
// ── 思考卡片 ──
|
||||
static let thinkingCard = LinearGradient(
|
||||
colors: [
|
||||
Color(hex: "#7C6EFA", opacity: 0.08),
|
||||
Color(hex: "#F97316", opacity: 0.04)
|
||||
],
|
||||
startPoint: .topLeading, endPoint: .bottomTrailing
|
||||
)
|
||||
|
||||
// ── 进度卡片 ──
|
||||
static let progressCard = LinearGradient(
|
||||
colors: [
|
||||
Color(hex: "#7C6EFA", opacity: 0.10),
|
||||
Color(hex: "#F97316", opacity: 0.05)
|
||||
],
|
||||
startPoint: .topLeading, endPoint: .bottomTrailing
|
||||
)
|
||||
|
||||
// ── 反馈评分卡片 ──
|
||||
static let feedbackScore = LinearGradient(
|
||||
colors: [
|
||||
Color(hex: "#7C6EFA", opacity: 0.12),
|
||||
Color(hex: "#34D399", opacity: 0.06)
|
||||
],
|
||||
startPoint: .topLeading, endPoint: .bottomTrailing
|
||||
)
|
||||
|
||||
// ── Profile 卡片 ──
|
||||
static let profileCard = LinearGradient(
|
||||
colors: [
|
||||
Color(hex: "#7C6EFA", opacity: 0.15),
|
||||
Color(hex: "#F97316", opacity: 0.08)
|
||||
],
|
||||
startPoint: .topLeading, endPoint: .bottomTrailing
|
||||
)
|
||||
|
||||
// ── Splash ──
|
||||
static let splash = LinearGradient(
|
||||
colors: [
|
||||
Color(hex: "#0D0D20"),
|
||||
Color(hex: "#0F0F1A"),
|
||||
Color(hex: "#130D20")
|
||||
],
|
||||
startPoint: .top, endPoint: .bottom
|
||||
)
|
||||
|
||||
// ── 进度条 ──
|
||||
static let progressBar = LinearGradient(
|
||||
colors: [Color(hex: "#7C6EFA"), Color(hex: "#4ECDC4")],
|
||||
startPoint: .leading, endPoint: .trailing
|
||||
)
|
||||
|
||||
// ── CTA 按钮 ──
|
||||
static let ctaButton = LinearGradient(
|
||||
colors: [Color(hex: "#7C6EFA"), Color(hex: "#F97316")],
|
||||
startPoint: .topLeading, endPoint: .bottomTrailing
|
||||
)
|
||||
|
||||
static let ctaPurple = LinearGradient(
|
||||
colors: [Color(hex: "#7C6EFA"), Color(hex: "#9B8BFF")],
|
||||
startPoint: .topLeading, endPoint: .bottomTrailing
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - ZhiXi Radii
|
||||
|
||||
enum ZXRadius {
|
||||
static let xs: CGFloat = 2
|
||||
static let sm: CGFloat = 8
|
||||
static let md: CGFloat = 10
|
||||
static let lg: CGFloat = 12
|
||||
static let xl: CGFloat = 14
|
||||
static let xl2: CGFloat = 16
|
||||
static let xl3: CGFloat = 20
|
||||
static let button: CGFloat = 12
|
||||
static let buttonLg: CGFloat = 18
|
||||
static let icon: CGFloat = 10
|
||||
static let iconLg: CGFloat = 12
|
||||
static let avatar: CGFloat = 13
|
||||
}
|
||||
|
||||
// MARK: - ZhiXi Spacing
|
||||
|
||||
enum ZXSpacing {
|
||||
static let ss: CGFloat = 2
|
||||
static let xs: CGFloat = 4
|
||||
static let sm: CGFloat = 6
|
||||
static let md: CGFloat = 8
|
||||
static let lg: CGFloat = 10
|
||||
static let xl: CGFloat = 12
|
||||
static let xl2: CGFloat = 14
|
||||
static let xl3: CGFloat = 16
|
||||
static let xl4: CGFloat = 20
|
||||
static let xl5: CGFloat = 24
|
||||
static let xl6: CGFloat = 28
|
||||
|
||||
static let pageHPadding: CGFloat = 20
|
||||
static let statusBarH: CGFloat = 44
|
||||
static let tabBarH: CGFloat = 83
|
||||
static let homeIndicatorH: CGFloat = 34
|
||||
}
|
||||
|
||||
// MARK: - ZhiXi Sizing
|
||||
|
||||
enum ZXSize {
|
||||
static let iconBtn: CGFloat = 36
|
||||
static let iconSm: CGFloat = 14
|
||||
static let iconMd: CGFloat = 16
|
||||
static let iconLg: CGFloat = 18
|
||||
static let tabIcon: CGFloat = 22
|
||||
static let listIcon: CGFloat = 40
|
||||
static let libraryIcon: CGFloat = 44
|
||||
static let quickActionH: CGFloat = 72
|
||||
static let inputH: CGFloat = 44
|
||||
static let buttonH: CGFloat = 42
|
||||
static let buttonLgH: CGFloat = 52
|
||||
static let buttonXlH: CGFloat = 56
|
||||
static let progressH: CGFloat = 5
|
||||
static let searchIconBtn: CGFloat = 36
|
||||
static let avatarSm: CGFloat = 36
|
||||
static let avatarMd: CGFloat = 64
|
||||
static let avatarLg: CGFloat = 80
|
||||
static let sendBtn: CGFloat = 30
|
||||
static let scoreBox: CGFloat = 36
|
||||
static let weakBox: CGFloat = 40
|
||||
static let topBar: CGFloat = 3
|
||||
}
|
||||
|
||||
// MARK: - ZhiXi Typography (exact match from React)
|
||||
|
||||
enum ZXFont {
|
||||
// titleLarge: 22, heavy, -0.5
|
||||
static let titleLarge = (size: CGFloat(22), weight: Font.Weight.heavy, spacing: CGFloat(-0.5))
|
||||
// titleMedium: 20, heavy, -0.4
|
||||
static let titleMedium = (size: CGFloat(20), weight: Font.Weight.heavy, spacing: CGFloat(-0.4))
|
||||
// sectionTitle: 15, bold
|
||||
static let sectionTitle = (size: CGFloat(15), weight: Font.Weight.bold)
|
||||
// sectionTitle14: 14, bold
|
||||
static let subsectionTitle = (size: CGFloat(14), weight: Font.Weight.bold)
|
||||
// body: 13, semibold, 1.4
|
||||
static let body = (size: CGFloat(13), weight: Font.Weight.semibold, lineHeight: CGFloat(1.4))
|
||||
// bodySmall: 12, medium
|
||||
static let bodySmall = (size: CGFloat(12), weight: Font.Weight.medium)
|
||||
// caption: 10, bold
|
||||
static let caption = (size: CGFloat(10), weight: Font.Weight.bold)
|
||||
// captionSmall: 10, regular
|
||||
static let captionSmall = (size: CGFloat(10), weight: Font.Weight.regular)
|
||||
// labelXs: 9
|
||||
static let labelXs = (size: CGFloat(9), weight: Font.Weight.regular)
|
||||
// score: 12, heavy
|
||||
static let score = (size: CGFloat(12), weight: Font.Weight.heavy)
|
||||
// scoreLg: 22, heavy, 1
|
||||
static let scoreLarge = (size: CGFloat(22), weight: Font.Weight.heavy, lineHeight: CGFloat(1))
|
||||
// date: 12, medium
|
||||
static let date = (size: CGFloat(12), weight: Font.Weight.medium)
|
||||
// description: 12, regular, 0.4
|
||||
static let description = (size: CGFloat(12), weight: Font.Weight.regular, spacing: CGFloat(0.4))
|
||||
}
|
||||
145
AIStudyApp/AIStudyApp/Features/AI/AIHomeView.swift
Normal file
@ -0,0 +1,145 @@
|
||||
//
|
||||
// AIHomeView.swift - Page 6: AI Home
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct AIHomeView: View {
|
||||
@State private var text = ""
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ZXGradient.page.ignoresSafeArea()
|
||||
Circle().fill(RadialGradient(colors:[Color(hex:"#7C6EFA",opacity:0.1),.clear],center:.top,startRadius:0,endRadius:200))
|
||||
.frame(width:200,height:200).offset(x:80,y:-80).allowsHitTesting(false)
|
||||
|
||||
VStack(spacing:0){
|
||||
// Header
|
||||
HStack(alignment:.bottom){
|
||||
VStack(alignment:.leading,spacing:2){
|
||||
Text("今天").font(.system(size:12,weight:.medium)).foregroundColor(Color.zxF04)
|
||||
Text("AI 学习助手").font(.system(size:20,weight:.heavy)).foregroundColor(Color.zxF0).tracking(-0.4)
|
||||
}
|
||||
Spacer()
|
||||
ZXIconBtn(icon:"arrow.clockwise",size:36){}
|
||||
}
|
||||
.padding(.horizontal,20).padding(.top,ZXSpacing.statusBarH+16).padding(.bottom,12)
|
||||
|
||||
ScrollView {
|
||||
VStack(spacing:16){
|
||||
thinkingCard
|
||||
quickActions
|
||||
recentSection
|
||||
suggestionSection
|
||||
}
|
||||
.padding(.horizontal,20).padding(.bottom,100)
|
||||
}
|
||||
.scrollIndicators(.hidden)
|
||||
|
||||
inputBar
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var thinkingCard: some View {
|
||||
VStack(alignment:.leading,spacing:12){
|
||||
HStack{
|
||||
Image(systemName:"sparkles").font(.system(size:14)).foregroundColor(.white)
|
||||
.frame(width:28,height:28).background(ZXGradient.brandPurple).clipShape(RoundedRectangle(cornerRadius:8))
|
||||
Text("今日思考题").font(.system(size:12,weight:.bold)).foregroundColor(Color.zxAccent).tracking(0.5)
|
||||
Spacer()
|
||||
Text("待回答").font(.system(size:10,weight:.bold)).foregroundColor(Color(hex:"#FBA574"))
|
||||
.padding(.horizontal,8).padding(.vertical,2).background(Color(hex:"#F97316",opacity:0.2)).clipShape(Capsule())
|
||||
}
|
||||
Text("解释\"注意力机制\"在 Transformer 中的作用,不能使用搜索,用你自己的话说。")
|
||||
.font(.system(size:14,weight:.medium)).foregroundColor(Color.zxF0).lineSpacing(4)
|
||||
NavigationLink(destination: DailyThinkingPage()) {
|
||||
Text("开始回答").font(.system(size:13,weight:.bold)).foregroundColor(.white)
|
||||
.frame(maxWidth:.infinity).frame(height:42)
|
||||
.background(ZXGradient.brand).clipShape(RoundedRectangle(cornerRadius:12))
|
||||
}
|
||||
}
|
||||
.padding(16).background(ZXGradient.thinkingCard)
|
||||
.overlay(RoundedRectangle(cornerRadius:20).stroke(Color(hex:"#7C6EFA",opacity:0.1),lineWidth:1))
|
||||
.clipShape(RoundedRectangle(cornerRadius:20))
|
||||
}
|
||||
|
||||
private var quickActions: some View {
|
||||
HStack(spacing:12){
|
||||
ZXQuickAction(emoji:"🧠",label:"生成\n回忆测试")
|
||||
ZXQuickAction(emoji:"🔍",label:"分析\n薄弱点")
|
||||
ZXQuickAction(emoji:"🎤",label:"费曼\n解释练习")
|
||||
ZXQuickAction(emoji:"📅",label:"今日\n复习计划")
|
||||
}
|
||||
}
|
||||
|
||||
private var recentSection: some View {
|
||||
VStack(alignment:.leading,spacing:12){
|
||||
HStack{
|
||||
Text("最近 AI 互动").font(.system(size:14,weight:.bold)).foregroundColor(Color.zxF0)
|
||||
Spacer();Text("全部").font(.system(size:12)).foregroundColor(Color.zxPurple)
|
||||
}
|
||||
ZXAIInteractionRow(tag:"费曼复习",bg:Color(hex:"#7C6EFA",opacity:0.15),fg:Color.zxPurple,emoji:"🎤",
|
||||
title:"解释量子纠缠的核心概念",time:"2小时前",score:82){}
|
||||
ZXAIInteractionRow(tag:"薄弱点",bg:Color(hex:"#F97316",opacity:0.15),fg:Color(hex:"#FBA574"),emoji:"⚠️",
|
||||
title:"混淆了协方差和相关系数",time:"昨天",score:56){}
|
||||
ZXAIInteractionRow(tag:"回忆测试",bg:Color(hex:"#7C6EFA",opacity:0.15),fg:Color.zxAccent,emoji:"📝",
|
||||
title:"机器学习中的偏差-方差权衡",time:"2天前",score:91){}
|
||||
}
|
||||
}
|
||||
|
||||
private var suggestionSection: some View {
|
||||
VStack(alignment:.leading,spacing:10){
|
||||
Text("💡 你可以问 AI").font(.system(size:12,weight:.semibold)).foregroundColor(Color.zxF04)
|
||||
ForEach(["\"帮我测试机器学习这章的掌握情况\"","\"我最近的薄弱知识点有哪些?\"","\"生成一份本周的复习计划\""],id:\.self){s in
|
||||
HStack{
|
||||
Text(s).font(.system(size:12)).foregroundColor(Color(hex:"#F0F0FF",opacity:0.55)).lineSpacing(4)
|
||||
Spacer()
|
||||
Image(systemName:"arrow.up").font(.system(size:12)).foregroundColor(Color(hex:"#7C6EFA",opacity:0.5))
|
||||
}
|
||||
.padding(.horizontal,12).padding(.vertical,8)
|
||||
.background(Color(hex:"#7C6EFA",opacity:0.06)).clipShape(RoundedRectangle(cornerRadius:10))
|
||||
}
|
||||
}
|
||||
.padding(14).padding(.horizontal,2)
|
||||
.background(Color(hex:"#FFFFFF",opacity:0.02))
|
||||
.overlay(RoundedRectangle(cornerRadius:16).stroke(Color(hex:"#FFFFFF",opacity:0.04),lineWidth:1))
|
||||
.clipShape(RoundedRectangle(cornerRadius:16))
|
||||
}
|
||||
|
||||
private var inputBar: some View {
|
||||
HStack(spacing:10){
|
||||
Image(systemName:"sparkles").font(.system(size:16)).foregroundColor(Color.zxPurple)
|
||||
TextField("问 AI 任何学习问题…",text:$text).font(.system(size:14)).tint(Color.zxPurple)
|
||||
Spacer()
|
||||
Image(systemName:"mic.fill").font(.system(size:18)).foregroundColor(Color.zxF03)
|
||||
Button{}label:{
|
||||
Image(systemName:"arrow.up").font(.system(size:14,weight:.bold)).foregroundColor(.white)
|
||||
.frame(width:30,height:30).background(ZXGradient.brand).clipShape(RoundedRectangle(cornerRadius:9))
|
||||
}
|
||||
}
|
||||
.padding(.horizontal,14).padding(.vertical,10)
|
||||
.background(.ultraThinMaterial).background(Color.zxFill004)
|
||||
.overlay(RoundedRectangle(cornerRadius:20).stroke(Color.zxBorder008,lineWidth:1))
|
||||
.clipShape(RoundedRectangle(cornerRadius:20))
|
||||
.padding(.horizontal,20)
|
||||
.padding(.bottom,ZXSpacing.tabBarH+20)
|
||||
}
|
||||
}
|
||||
|
||||
// ── Shared UI pieces ──
|
||||
|
||||
struct ZXQuickAction: View {let emoji:String;let label:String
|
||||
var body: some View {VStack(spacing:6){Text(emoji).font(.system(size:20))
|
||||
Text(label).font(.system(size:10,weight:.semibold)).foregroundColor(Color.zxF006).multilineTextAlignment(.center).lineSpacing(4)}
|
||||
.frame(maxWidth:.infinity).frame(height:72).background(Color.zxFill003)
|
||||
.overlay(RoundedRectangle(cornerRadius:16).stroke(Color.zxBorder006,lineWidth:1)).clipShape(RoundedRectangle(cornerRadius:16))}}
|
||||
|
||||
struct ZXAIInteractionRow: View {let tag:String;let bg:Color;let fg:Color;let emoji:String;let title:String;let time:String;let score:Int;let action:()->Void
|
||||
var body: some View {Button(action:action){HStack(spacing:12){
|
||||
Text(emoji).font(.system(size:18)).frame(width:40,height:40).background(bg).clipShape(RoundedRectangle(cornerRadius:12))
|
||||
VStack(alignment:.leading,spacing:2){HStack(spacing:8){Text(tag).font(.system(size:10,weight:.bold)).foregroundColor(fg).tracking(0.3);Text(time).font(.system(size:10)).foregroundColor(Color.zxF03)};Text(title).font(.system(size:13,weight:.semibold)).foregroundColor(Color(hex:"#F0F0FF",opacity:0.8)).lineLimit(1)}
|
||||
Spacer()
|
||||
ZXScoreBox(score:score,bg:score>=80 ? Color.zxGreenBG(0.15) : score>=60 ? Color.zxOrangeBG(0.15):Color.zxRedBG(0.15),fg:score>=80 ? Color.zxGreen : score>=60 ? Color.zxOrange:Color.zxRed)}
|
||||
.padding(.horizontal,14).padding(.vertical,12).background(Color.zxFill003).overlay(RoundedRectangle(cornerRadius:16).stroke(Color.zxBorder006,lineWidth:1)).clipShape(RoundedRectangle(cornerRadius:16))}}
|
||||
}
|
||||
196
AIStudyApp/AIStudyApp/Features/AI/DailyThinkingPage.swift
Normal file
@ -0,0 +1,196 @@
|
||||
//
|
||||
// DailyThinkingPage.swift - Page 14: Daily Thinking
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct DailyThinkingPage: View {
|
||||
@State private var answer = ""
|
||||
@State private var submitted = false
|
||||
|
||||
var body: some View {
|
||||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
ZXBackHeader(title: "今日思考", subtitle: "过拟合", onBack: nil, trailing: {
|
||||
ZXIconBtn(icon: "bookmark", size: 36) {}
|
||||
})
|
||||
ScrollView { VStack(spacing: 16) {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
HStack {
|
||||
Image(systemName: "sparkles").foregroundColor(Color.zxAccent)
|
||||
Text("解释\"注意力机制\"在 Transformer 中的作用").font(.system(size: 15, weight: .bold)).foregroundColor(Color.zxF0)
|
||||
}
|
||||
Text("AI会从三个方面评估你的回答:核心概念理解 · 理论深度 · 实际应用能力").font(.system(size: 12)).foregroundColor(Color.zxF04)
|
||||
}
|
||||
.padding(16).background(ZXGradient.thinkingCard).clipShape(RoundedRectangle(cornerRadius: 16))
|
||||
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("你的回答").font(.system(size: 13, weight: .semibold)).foregroundColor(Color.zxF04)
|
||||
TextEditor(text: $answer)
|
||||
.font(.system(size: 13)).foregroundColor(Color.zxF0).tint(Color.zxPurple)
|
||||
.frame(minHeight: 160).scrollContentBackground(.hidden)
|
||||
.padding(12).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1))
|
||||
}
|
||||
|
||||
if !submitted {
|
||||
NavigationLink(destination: AIFeedbackPageView()) {
|
||||
Text("提交回答,获取 AI 反馈").font(.system(size: 14, weight: .bold)).foregroundColor(.white)
|
||||
.frame(maxWidth: .infinity).frame(height: 52)
|
||||
.background(ZXGradient.ctaPurple).clipShape(RoundedRectangle(cornerRadius: 16))
|
||||
.shadow(color: Color(hex: "#7C6EFA", opacity: 0.3), radius: 24)
|
||||
}
|
||||
}
|
||||
}.padding(.horizontal, 20).padding(.bottom, 120) }
|
||||
.scrollIndicators(.hidden)
|
||||
}
|
||||
}
|
||||
.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Back Header
|
||||
struct ZXBackHeader<T: View>: View {
|
||||
let title: String; let subtitle: String?; var onBack: (() -> Void)?
|
||||
@ViewBuilder var trailing: () -> T
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
var body: some View {
|
||||
HStack {
|
||||
Button { (onBack ?? { dismiss() })() } label: {
|
||||
Image(systemName: "chevron.left").font(.system(size: 18)).foregroundColor(Color.zxF007)
|
||||
.frame(width: 36, height: 36).background(Color.zxFill005).clipShape(RoundedRectangle(cornerRadius: 10))
|
||||
.overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.zxBorder008, lineWidth: 1))
|
||||
}
|
||||
VStack(spacing: 1) {
|
||||
Text(title).font(.system(size: 15, weight: .bold)).foregroundColor(Color.zxF0)
|
||||
if let s = subtitle { Text(s).font(.system(size: 11)).foregroundColor(Color.zxF03) }
|
||||
}.frame(maxWidth: .infinity)
|
||||
trailing()
|
||||
}
|
||||
.padding(.horizontal, 16).padding(.top, ZXSpacing.statusBarH + 8).padding(.bottom, 12)
|
||||
.background(Color.zxBg0)
|
||||
}
|
||||
}
|
||||
|
||||
// RecallTest
|
||||
struct RecallTestPage: View {
|
||||
@State private var input = ""
|
||||
var body: some View {
|
||||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
ZXBackHeader(title: "回忆测试", subtitle: "机器学习 · 偏差-方差权衡") {}
|
||||
ScrollView { VStack(spacing: 16) {
|
||||
Text("请回忆并写下你对「偏差-方差权衡」的理解").font(.system(size: 14)).foregroundColor(Color.zxF04)
|
||||
TextEditor(text: $input).frame(minHeight: 200).scrollContentBackground(.hidden).padding(12).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1))
|
||||
Button {} label: { Text("提交").font(.system(size: 14, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 52).background(ZXGradient.ctaPurple).clipShape(RoundedRectangle(cornerRadius: 16)) }
|
||||
}.padding(.horizontal, 20).padding(.bottom, 80) }.scrollIndicators(.hidden)
|
||||
}
|
||||
}.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
|
||||
// WeakPoints
|
||||
struct WeakPointsPage: View {
|
||||
var body: some View {
|
||||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
ZXBackHeader(title: "薄弱知识点", subtitle: "共 23 个待巩固") {}
|
||||
ScrollView { VStack(spacing: 12) {
|
||||
ZXWeakRow(score: 32, topic: "贝叶斯定理应用", lib: "机器学习", priority: "高")
|
||||
ZXWeakRow(score: 41, topic: "正态分布性质", lib: "高等数学", priority: "高")
|
||||
ZXWeakRow(score: 55, topic: "词根 spect- 相关词汇", lib: "英语词汇", priority: "中")
|
||||
ZXWeakRow(score: 48, topic: "协方差与相关系数", lib: "机器学习", priority: "中")
|
||||
ZXWeakRow(score: 36, topic: "梯度下降优化", lib: "机器学习", priority: "高")
|
||||
}.padding(.horizontal, 20).padding(.bottom, 80) }.scrollIndicators(.hidden)
|
||||
}
|
||||
}.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
|
||||
// AIFeedback - Page 15
|
||||
struct AIFeedbackPageView: View {
|
||||
var body: some View {
|
||||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
ZXBackHeader(title: "AI 反馈", subtitle: "今日思考 · 过拟合", trailing: {
|
||||
ZXIconBtn(icon: "bookmark", size: 36) {}
|
||||
})
|
||||
ScrollView { VStack(spacing: 16) {
|
||||
// Score
|
||||
HStack(spacing: 20) {
|
||||
ZStack {
|
||||
Circle().trim(from: 0, to: 0.78).stroke(ZXGradient.brand, style: StrokeStyle(lineWidth: 10, lineCap: .round)).rotationEffect(.degrees(-90)).frame(width: 80, height: 80)
|
||||
VStack(spacing: 0) { Text("78").font(.system(size: 22, weight: .heavy)).foregroundColor(Color.zxPurple); Text("/ 100").font(.system(size: 9)).foregroundColor(Color.zxF04) }
|
||||
}
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text("良好掌握").font(.system(size: 18, weight: .heavy)).foregroundColor(Color.zxF0)
|
||||
Text("理解核心概念,但缺少理论深度和解决方案").font(.system(size: 12)).foregroundColor(Color.zxF0045).lineSpacing(4)
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
.padding(20).background(ZXGradient.feedbackScore).clipShape(RoundedRectangle(cornerRadius: 20)).overlay(RoundedRectangle(cornerRadius: 20).stroke(Color(hex: "#7C6EFA", opacity: 0.2), lineWidth: 1))
|
||||
|
||||
// 你的回答
|
||||
VStack(alignment: .leading, spacing: 8) { Text("你的回答").font(.system(size: 13, weight: .semibold)).foregroundColor(Color.zxF04); Text("过拟合就像一个学生只会「死记硬背」考题,而不是真正理解知识…").font(.system(size: 13)).foregroundColor(Color.zxF007).lineSpacing(6).padding(14).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder006, lineWidth: 1)) }
|
||||
|
||||
// 答对的部分
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
HStack(spacing: 8) { Image(systemName: "checkmark.circle.fill").foregroundColor(Color.zxGreen); Text("答对的部分").font(.system(size: 14, weight: .bold)).foregroundColor(Color.zxF0) }
|
||||
ForEach([("正确识别出过拟合是\"记住训练数据\"而非\"学习规律\""),("使用了死记硬背类比,方向正确且贴切")], id: \.self) { s in
|
||||
HStack(alignment: .top, spacing: 12) { Circle().fill(Color.zxGreen).frame(width: 6, height: 6).padding(.top, 6); Text(s).font(.system(size: 13)).foregroundColor(Color(hex: "#F0F0FF", opacity: 0.75)).lineSpacing(4) }
|
||||
.padding(12).background(Color(hex: "#34D399", opacity: 0.07)).clipShape(RoundedRectangle(cornerRadius: 12)).overlay(RoundedRectangle(cornerRadius: 12).stroke(Color(hex: "#34D399", opacity: 0.18), lineWidth: 1))
|
||||
}
|
||||
}
|
||||
|
||||
// 需要完善
|
||||
VStack(alignment: .leading, spacing: 10) {
|
||||
HStack(spacing: 8) { Image(systemName: "exclamationmark.triangle.fill").foregroundColor(Color.zxYellow); Text("需要完善").font(.system(size: 14, weight: .bold)).foregroundColor(Color.zxF0) }
|
||||
ForEach([("缺少对「方差」和「偏差」权衡的说明", "过拟合本质是高方差问题,可以提到偏差-方差权衡"),("未提及正则化、Dropout 等解决方案", "完整答案通常要说明\"如何解决\"")], id: \.0) { p, d in
|
||||
VStack(alignment: .leading, spacing: 4) { Text(p).font(.system(size: 13, weight: .bold)).foregroundColor(Color.zxF0); Text(d).font(.system(size: 12)).foregroundColor(Color.zxF05).lineSpacing(4) }
|
||||
.padding(14).frame(maxWidth: .infinity, alignment: .leading).background(Color(hex: "#F59E0B", opacity: 0.07)).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color(hex: "#F59E0B", opacity: 0.18), lineWidth: 1))
|
||||
}
|
||||
}
|
||||
|
||||
// 参考答案
|
||||
VStack(alignment: .leading, spacing: 8) {
|
||||
Text("✨ 参考答案要点").font(.system(size: 13, weight: .bold)).foregroundColor(Color.zxAccent)
|
||||
Text("过拟合是模型复杂度过高导致的高方差问题。偏差-方差权衡是核心概念。解决方法包括:正则化、Dropout、数据增强、早停等。").font(.system(size: 13)).foregroundColor(Color.zxF007).lineSpacing(6)
|
||||
}.padding(16).background(Color(hex: "#7C6EFA", opacity: 0.07)).clipShape(RoundedRectangle(cornerRadius: 16)).overlay(RoundedRectangle(cornerRadius: 16).stroke(Color(hex: "#7C6EFA", opacity: 0.2), lineWidth: 1))
|
||||
|
||||
// 操作按钮
|
||||
Button {} label: { Label("加入待巩固,安排间隔复习", systemImage: "bolt.fill").font(.system(size: 14, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 52).background(ZXGradient.ctaPurple).clipShape(RoundedRectangle(cornerRadius: 16)).shadow(color: Color(hex: "#7C6EFA", opacity: 0.3), radius: 24) }
|
||||
HStack(spacing: 12) { ZXOutlineBtn(text: "深入提问"); ZXOutlineBtn(text: "再来一题") }
|
||||
}.padding(.horizontal, 20).padding(.bottom, 80) }.scrollIndicators(.hidden)
|
||||
}
|
||||
}.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
struct ZXOutlineBtn: View { let text: String
|
||||
var body: some View { Button {} label: { HStack(spacing: 4) { Text(text).font(.system(size: 13)); Image(systemName: "chevron.right").font(.system(size: 14)) }.foregroundColor(Color.zxF05).frame(maxWidth: .infinity).frame(height: 44).background(Color.zxFill005).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)) } }
|
||||
}
|
||||
|
||||
// AIChat - Page 11
|
||||
struct AIChatPage: View {
|
||||
@State private var msg = ""
|
||||
@State private var msgs: [(role: String, content: String)] = [("ai", "你好!我是你的 AI 学习助手。我可以帮你解答学习问题、分析薄弱点、制定复习计划。请告诉我你想学习什么?")]
|
||||
var body: some View {
|
||||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
ZXBackHeader(title: "AI 对话", subtitle: "学习助手") {}
|
||||
ScrollViewReader { proxy in ScrollView { VStack(spacing: 16) {
|
||||
ForEach(Array(msgs.enumerated()), id: \.offset) { i, m in
|
||||
HStack(alignment: .top, spacing: 8) {
|
||||
if m.role == "ai" {
|
||||
Image(systemName: "brain.head.profile").foregroundColor(Color.zxPurple).frame(width: 28, height: 28).background(Color(hex: "#7C6EFA", opacity: 0.15)).clipShape(Circle())
|
||||
}
|
||||
Text(m.content).font(.system(size: 14)).foregroundColor(m.role == "user" ? .white : Color.zxF007).padding(12).background(m.role == "user" ? AnyView(ZXGradient.brandPurple) : AnyView(Color.zxFill004)).clipShape(RoundedRectangle(cornerRadius: 16))
|
||||
if m.role == "user" { Circle().frame(width: 28, height: 28).foregroundColor(Color.zxPurpleBG(0.2)).overlay(Text("我").font(.system(size: 10, weight: .bold)).foregroundColor(Color.zxPurple)) }
|
||||
}
|
||||
.frame(maxWidth: .infinity, alignment: m.role == "user" ? .trailing : .leading)
|
||||
}
|
||||
}.padding(.horizontal, 20).padding(.bottom, 100).id("bottom") }.scrollIndicators(.hidden)
|
||||
.onChange(of: msgs.count) { withAnimation { proxy.scrollTo("bottom") } } }
|
||||
ZXAIInputBar(text: $msg, onSend: { guard !msg.isEmpty else { return }; msgs.append(("user", msg)); msg = ""; DispatchQueue.main.asyncAfter(deadline: .now() + 1) { msgs.append(("ai", "好的,我理解你的问题。建议你从基础概念开始,逐步深入理解。需要我帮你制定具体的学习计划吗?")) } })
|
||||
}
|
||||
}.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
148
AIStudyApp/AIStudyApp/Features/Analysis/AnalysisHomeView.swift
Normal file
@ -0,0 +1,148 @@
|
||||
//
|
||||
// AnalysisHomeView.swift - Page 9: Analysis Home
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct AnalysisHomeView: View {
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
HStack {
|
||||
Text("学习分析")
|
||||
.font(.system(size: 22, weight: .heavy)).foregroundColor(Color.zxF0).tracking(-0.5)
|
||||
Spacer()
|
||||
HStack(spacing: 4) {
|
||||
Text("近 7 天").font(.system(size: 12)).foregroundColor(Color.zxF05)
|
||||
Image(systemName: "chevron.down").font(.system(size: 10)).foregroundColor(Color.zxF04)
|
||||
}
|
||||
.padding(.horizontal, 12).padding(.vertical, 6)
|
||||
.background(Color.zxFill005)
|
||||
.clipShape(Capsule())
|
||||
.overlay(Capsule().stroke(Color.zxBorder008, lineWidth: 1))
|
||||
}
|
||||
.padding(.horizontal, 20).padding(.top, ZXSpacing.statusBarH + 16).padding(.bottom, 12)
|
||||
|
||||
ScrollView {
|
||||
VStack(spacing: 16) {
|
||||
HStack(spacing: 12) {
|
||||
ZXStatBadge(icon: "trophy.fill", label: "综合掌握", value: "65%", trend: "+8%", color: Color.zxPurple)
|
||||
ZXStatBadge(icon: "bolt.fill", label: "本周积分", value: "1,240", trend: "+320", color: Color.zxOrange)
|
||||
ZXStatBadge(icon: "exclamationmark.triangle.fill", label: "待巩固", value: "23", trend: "-5", color: Color.zxYellow)
|
||||
ZXStatBadge(icon: "chart.line.uptrend.xyaxis", label: "连续天", value: "14", trend: "🔥", color: Color.zxGreen)
|
||||
}
|
||||
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
HStack {
|
||||
Text("掌握度趋势").font(.system(size: 14, weight: .bold)).foregroundColor(Color.zxF0)
|
||||
Spacer()
|
||||
Text("↑ +8% 本周").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxGreen)
|
||||
}
|
||||
ZXChartView()
|
||||
}
|
||||
.padding(16)
|
||||
.background(Color.zxFill004)
|
||||
.overlay(RoundedRectangle(cornerRadius: 20).stroke(Color.zxBorder006, lineWidth: 1))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 20))
|
||||
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
HStack {
|
||||
HStack(spacing: 8) {
|
||||
Image(systemName: "exclamationmark.triangle.fill").font(.system(size: 14)).foregroundColor(Color.zxYellow)
|
||||
Text("薄弱知识点").font(.system(size: 15, weight: .bold)).foregroundColor(Color.zxF0)
|
||||
}
|
||||
Spacer()
|
||||
Text("全部 23 个").font(.system(size: 12)).foregroundColor(Color.zxPurple)
|
||||
}
|
||||
ZXWeakRow(score: 32, topic: "贝叶斯定理应用", lib: "机器学习", priority: "高")
|
||||
ZXWeakRow(score: 41, topic: "正态分布性质", lib: "高等数学", priority: "高")
|
||||
ZXWeakRow(score: 55, topic: "词根 spect- 相关词汇", lib: "英语词汇", priority: "中")
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
.padding(.bottom, 120)
|
||||
}
|
||||
.scrollIndicators(.hidden)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Stat Badge
|
||||
|
||||
struct ZXStatBadge: View {
|
||||
let icon: String; let label: String; let value: String; let trend: String; let color: Color
|
||||
var body: some View {
|
||||
VStack(spacing: 3) {
|
||||
Image(systemName: icon).font(.system(size: 14)).foregroundColor(color)
|
||||
Text(value).font(.system(size: 16, weight: .heavy)).foregroundColor(Color.zxF0)
|
||||
Text(label).font(.system(size: 9)).foregroundColor(Color.zxF04).multilineTextAlignment(.center)
|
||||
}
|
||||
.frame(maxWidth: .infinity).frame(height: 72).padding(.vertical, 4)
|
||||
.background(color.opacity(0.06))
|
||||
.overlay(RoundedRectangle(cornerRadius: 14).stroke(color.opacity(0.15), lineWidth: 1))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Weak Point Row
|
||||
|
||||
struct ZXWeakRow: View {
|
||||
let score: Int; let topic: String; let lib: String; let priority: String
|
||||
var body: some View {
|
||||
HStack(spacing: 12) {
|
||||
Text("\(score)").font(.system(size: 13, weight: .heavy)).foregroundColor(Color.zxYellow)
|
||||
.frame(width: 40, height: 40)
|
||||
.background(Color.zxYellowBG(0.15)).clipShape(RoundedRectangle(cornerRadius: 12))
|
||||
VStack(alignment: .leading, spacing: 2) {
|
||||
Text(topic).font(.system(size: 13, weight: .semibold)).foregroundColor(Color.zxF0)
|
||||
Text(lib).font(.system(size: 11)).foregroundColor(Color.zxF04)
|
||||
}.frame(maxWidth: .infinity, alignment: .leading)
|
||||
Text("\(priority)优先").font(.system(size: 11, weight: .bold))
|
||||
.foregroundColor(priority == "高" ? Color.zxRed : Color.zxYellow)
|
||||
.padding(.horizontal, 8).padding(.vertical, 3)
|
||||
.background((priority == "高" ? Color.zxRedBG(0.15) : Color.zxYellowBG(0.15)))
|
||||
.clipShape(Capsule())
|
||||
}
|
||||
.padding(.horizontal, 16).padding(.vertical, 12)
|
||||
.background(Color.zxYellowBG(0.06))
|
||||
.overlay(RoundedRectangle(cornerRadius: 14).stroke(Color(hex: "#F59E0B", opacity: 0.15), lineWidth: 1))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 14))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Chart View
|
||||
|
||||
struct ZXChartView: View {
|
||||
let data: [(String, CGFloat)] = [
|
||||
("一", 0.62), ("二", 0.65), ("三", 0.71), ("四", 0.68),
|
||||
("五", 0.75), ("六", 0.79), ("今", 0.78)
|
||||
]
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
GeometryReader { g in
|
||||
ZStack(alignment: .topLeading) {
|
||||
Path { path in
|
||||
let w = g.size.width / 7
|
||||
for (i, d) in data.enumerated() {
|
||||
let x = w * CGFloat(i) + w / 2
|
||||
let y = (1 - d.1) * g.size.height
|
||||
if i == 0 { path.move(to: CGPoint(x: x, y: y)) }
|
||||
else { path.addLine(to: CGPoint(x: x, y: y)) }
|
||||
}
|
||||
}
|
||||
.stroke(Color.zxPurple, style: StrokeStyle(lineWidth: 2, lineCap: .round, lineJoin: .round))
|
||||
}
|
||||
}
|
||||
.frame(height: 100)
|
||||
HStack(spacing: 0) {
|
||||
ForEach(data, id: \.0) { d in
|
||||
Text(d.0).font(.system(size: 9))
|
||||
.foregroundColor(Color(hex: "#F0F0FF", opacity: 0.35))
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
35
AIStudyApp/AIStudyApp/Features/Library/LibraryHomeView.swift
Normal file
@ -0,0 +1,35 @@
|
||||
//
|
||||
// LibraryHomeView.swift - Page 7
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct LibraryHomeView: View {
|
||||
@State private var s = ""
|
||||
var body: some View {
|
||||
ZStack { ZXGradient.page.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
HStack { Text("知识库").font(.system(size: 22, weight: .heavy)).foregroundColor(Color.zxF0).tracking(-0.5); Spacer(); ZXIconBtn(icon: "magnifyingglass", size: 36) {}; ZXIconBtn(icon: "plus", size: 36, branded: true) {} }
|
||||
.padding(.horizontal, 20).padding(.top, ZXSpacing.statusBarH + 16).padding(.bottom, 12)
|
||||
HStack(spacing: 8) { Image(systemName: "magnifyingglass").font(.system(size: 16)).foregroundColor(Color.zxF03); TextField("搜索知识库或知识点…", text: $s).font(.system(size: 14)).tint(Color.zxPurple) }
|
||||
.padding(.horizontal, 14).frame(height: 44).background(Color.zxFill004).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 14)).padding(.horizontal, 20).padding(.bottom, 16)
|
||||
ScrollView { VStack(spacing: 12) {
|
||||
NavigationLink(destination: LibraryDetailPage()) { ZLibraryCard(emoji: "🤖", name: "机器学习", desc: "ML基础 · 深度学习 · 实战项目", color: Color.zxPurple, items: 47, mastery: 72, tags: ["算法","数学","实战"], last: "今天") }
|
||||
NavigationLink(destination: LibraryDetailPage()) { ZLibraryCard(emoji: "📐", name: "高等数学", desc: "微积分 · 线代 · 概率论", color: Color.zxOrange, items: 93, mastery: 58, tags: ["公式","定理","习题"], last: "昨天") }
|
||||
NavigationLink(destination: LibraryDetailPage()) { ZLibraryCard(emoji: "📖", name: "英语词汇", desc: "GRE · 托福 · 商务英语", color: Color.zxTeal, items: 312, mastery: 84, tags: ["词根","语境","拼写"], last: "3天前") }
|
||||
NavigationLink(destination: LibraryDetailPage()) { ZLibraryCard(emoji: "🎨", name: "产品设计", desc: "UX 方法论 · 用研 · 交互规范", color: Color.zxYellow, items: 28, mastery: 43, tags: ["方法论","案例"], last: "1周前") }
|
||||
NavigationLink(destination: CreateLibraryPage()) {
|
||||
HStack(spacing: 8) { Image(systemName: "plus").font(.system(size: 16)); Text("创建新知识库").font(.system(size: 14, weight: .semibold)) }
|
||||
.foregroundColor(Color.zxF05).frame(maxWidth: .infinity).frame(height: 52).background(Color.zxFill003)
|
||||
.overlay(RoundedRectangle(cornerRadius: 16).strokeBorder(style: StrokeStyle(lineWidth: 1.5, dash: [6, 4]), antialiased: true).foregroundColor(Color.zxBorder01))
|
||||
.clipShape(RoundedRectangle(cornerRadius: 16))
|
||||
}
|
||||
}.padding(.horizontal, 20).padding(.bottom, 120) }.scrollIndicators(.hidden)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
struct ZLibraryCard: View { let emoji: String; let name: String; let desc: String; let color: Color; let items: Int; let mastery: Int; let tags: [String]; let last: String
|
||||
var body: some View { VStack(spacing: 0) { Rectangle().fill(ZXGradient.progressBar).frame(height: 3); HStack(spacing: 12) { Text(emoji).font(.system(size: 22)).frame(width: 44, height: 44).background(color.opacity(0.12)).clipShape(RoundedRectangle(cornerRadius: 13)).overlay(RoundedRectangle(cornerRadius: 13).stroke(color.opacity(0.3), lineWidth: 1)); VStack(alignment: .leading, spacing: 2) { Text(name).font(.system(size: 16, weight: .bold)).foregroundColor(Color.zxF0); Text(desc).font(.system(size: 12)).foregroundColor(Color.zxF04); Text("掌握 \(mastery)%").font(.system(size: 11)).foregroundColor(Color.zxF04) }; Spacer() }.padding(16); HStack { HStack(spacing: 4) { Image(systemName: "clock").font(.system(size: 10)); Text("\(items) 项 · \(last)").font(.system(size: 11)) }.foregroundColor(Color.zxF03); Spacer(); ForEach(tags.prefix(2), id: \.self) { t in Text(t).font(.system(size: 10, weight: .medium)).foregroundColor(Color.zxPurple).padding(.horizontal, 7).padding(.vertical, 2).background(Color(hex: "#7C6EFA", opacity: 0.08)).clipShape(Capsule()) } }.padding(.horizontal, 16).padding(.bottom, 12) }
|
||||
.background(Color.zxFill003).clipShape(RoundedRectangle(cornerRadius: 20)).overlay(RoundedRectangle(cornerRadius: 20).stroke(Color.zxBorder006, lineWidth: 1)) }
|
||||
}
|
||||
111
AIStudyApp/AIStudyApp/Features/Library/LibrarySubpages.swift
Normal file
@ -0,0 +1,111 @@
|
||||
//
|
||||
// LibrarySubpages.swift
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CreateLibraryPage: View {
|
||||
@State private var name = ""; @State private var desc = ""
|
||||
var body: some View {
|
||||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
ZXBackHeader(title: "创建知识库", subtitle: nil) {}
|
||||
ScrollView { VStack(spacing: 20) {
|
||||
VStack(alignment: .leading, spacing: 8) { Text("知识库名称").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxF035); TextField("例如:机器学习", text: $name).font(.system(size: 15)).tint(Color.zxPurple).padding(.horizontal, 16).frame(height: 52).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)) }
|
||||
VStack(alignment: .leading, spacing: 8) { Text("描述(可选)").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxF035); TextField("简单描述这个知识库的内容", text: $desc).font(.system(size: 15)).tint(Color.zxPurple).padding(.horizontal, 16).frame(height: 52).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)) }
|
||||
Button {} label: { Text("创建").font(.system(size: 14, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 52).background(ZXGradient.ctaPurple).clipShape(RoundedRectangle(cornerRadius: 16)) }
|
||||
}.padding(.horizontal, 20).padding(.top, 20) }.scrollIndicators(.hidden)
|
||||
}
|
||||
}.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
|
||||
struct LibraryDetailPage: View {
|
||||
var body: some View {
|
||||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
ZXBackHeader(title: "机器学习", subtitle: "47 个知识点 · 掌握 72%") {
|
||||
HStack(spacing: 8) { ZXIconBtn(icon: "magnifyingglass", size: 36) {}; ZXIconBtn(icon: "plus", size: 36, branded: true) {} }
|
||||
}
|
||||
ScrollView { VStack(spacing: 12) {
|
||||
NavigationLink(destination: KnowledgeDetailPage()) { ZXCardRow(emoji: "📝", title: "偏差-方差权衡", desc: "模型复杂度 · 泛化误差", status: "已掌握", c: Color.zxGreen) }
|
||||
NavigationLink(destination: KnowledgeDetailPage()) { ZXCardRow(emoji: "📝", title: "梯度下降优化", desc: "SGD · Adam · 学习率", status: "学习中", c: Color.zxOrange) }
|
||||
NavigationLink(destination: KnowledgeDetailPage()) { ZXCardRow(emoji: "📝", title: "正则化方法", desc: "L1 · L2 · Dropout", status: "待复习", c: Color.zxYellow) }
|
||||
NavigationLink(destination: KnowledgeDetailPage()) { ZXCardRow(emoji: "📝", title: "过拟合与欠拟合", desc: "偏差方差 · 模型选择", status: "已掌握", c: Color.zxGreen) }
|
||||
}.padding(.horizontal, 20).padding(.bottom, 80) }.scrollIndicators(.hidden)
|
||||
}
|
||||
}.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
struct ZXCardRow: View { let emoji: String; let title: String; let desc: String; let status: String; let c: Color
|
||||
var body: some View { HStack(spacing: 12) { Text(emoji).font(.system(size: 20)).frame(width: 40, height: 40).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 10)); VStack(alignment: .leading, spacing: 2) { Text(title).font(.system(size: 14, weight: .semibold)).foregroundColor(Color.zxF0); Text(desc).font(.system(size: 11)).foregroundColor(Color.zxF03) }; Spacer(); Text(status).font(.system(size: 10, weight: .semibold)).foregroundColor(c).padding(.horizontal, 8).padding(.vertical, 2).background(c.opacity(0.12)).clipShape(Capsule()) }
|
||||
.padding(14).background(Color.zxFill003).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder006, lineWidth: 1)) }
|
||||
}
|
||||
|
||||
struct AddKnowledgePage: View {
|
||||
@State private var title = ""; @State private var content = ""
|
||||
var body: some View {
|
||||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
ZXBackHeader(title: "添加知识点", subtitle: "机器学习") {}
|
||||
ScrollView { VStack(spacing: 16) {
|
||||
VStack(alignment: .leading, spacing: 8) { Text("标题").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxF035); TextField("输入知识点标题", text: $title).font(.system(size: 15)).tint(Color.zxPurple).padding(.horizontal, 16).frame(height: 52).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)) }
|
||||
VStack(alignment: .leading, spacing: 8) { Text("内容").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxF035); TextEditor(text: $content).frame(minHeight: 200).scrollContentBackground(.hidden).padding(12).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)) }
|
||||
Button {} label: { Text("保存").font(.system(size: 14, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 52).background(ZXGradient.ctaPurple).clipShape(RoundedRectangle(cornerRadius: 16)) }
|
||||
}.padding(.horizontal, 20).padding(.bottom, 80) }.scrollIndicators(.hidden)
|
||||
}
|
||||
}.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
|
||||
struct KnowledgeDetailPage: View {
|
||||
var body: some View {
|
||||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
ZXBackHeader(title: "知识点详情", subtitle: "机器学习") { ZXIconBtn(icon: "pencil", size: 36) {} }
|
||||
ScrollView { VStack(spacing: 16) {
|
||||
VStack(alignment: .leading, spacing: 8) { HStack { ZXChip(text: "算法", color: Color.zxPurple); ZXChip(text: "机器学习", color: Color.zxAccent); ZXChip(text: "需要复习", color: Color.zxYellow) }; Text("偏差-方差权衡").font(.system(size: 22, weight: .heavy)).foregroundColor(Color.zxF0); Text("偏差-方差权衡是机器学习模型选择的核心理念。").font(.system(size: 14)).foregroundColor(Color.zxF007).lineSpacing(6) }.padding(20).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 20)).overlay(RoundedRectangle(cornerRadius: 20).stroke(Color.zxBorder006, lineWidth: 1))
|
||||
HStack(spacing: 12) { Button {} label: { Label("开始复习", systemImage: "arrow.triangle.2.circlepath").font(.system(size: 14, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 44).background(ZXGradient.brandPurple).clipShape(RoundedRectangle(cornerRadius: 14)) }; Button {} label: { Label("费曼解释", systemImage: "mic.fill").font(.system(size: 14, weight: .semibold)).foregroundColor(Color.zxF05).frame(maxWidth: .infinity).frame(height: 44).background(Color.zxFill005).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)) } }
|
||||
}.padding(.horizontal, 20).padding(.bottom, 80) }.scrollIndicators(.hidden)
|
||||
}
|
||||
}.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
struct ZXChip: View { let text: String; let color: Color
|
||||
var body: some View { Text(text).font(.system(size: 10, weight: .semibold)).foregroundColor(color).padding(.horizontal, 8).padding(.vertical, 2).background(color.opacity(0.12)).clipShape(Capsule()) }
|
||||
}
|
||||
|
||||
struct ImportPage: View {
|
||||
var body: some View {
|
||||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
ZXBackHeader(title: "导入资料", subtitle: nil) {}
|
||||
ScrollView { VStack(spacing: 12) {
|
||||
ZXImportOption(icon: "camera.fill", title: "拍照导入", desc: "拍下书本或笔记,AI 自动识别")
|
||||
ZXImportOption(icon: "doc.text.fill", title: "文件导入", desc: "支持 PDF、Word、Markdown")
|
||||
ZXImportOption(icon: "link", title: "链接导入", desc: "粘贴网页链接,自动提取内容")
|
||||
ZXImportOption(icon: "photo.on.rectangle", title: "相册导入", desc: "从相册选择截图或图片")
|
||||
}.padding(.horizontal, 20).padding(.top, 16) }.scrollIndicators(.hidden)
|
||||
}
|
||||
}.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
struct ZXImportOption: View { let icon: String; let title: String; let desc: String
|
||||
var body: some View { Button {} label: { HStack(spacing: 14) { Image(systemName: icon).font(.system(size: 22)).foregroundColor(Color.zxPurple).frame(width: 48, height: 48).background(Color.zxPurpleBG(0.1)).clipShape(RoundedRectangle(cornerRadius: 14)); VStack(alignment: .leading, spacing: 2) { Text(title).font(.system(size: 15, weight: .semibold)).foregroundColor(Color.zxF0); Text(desc).font(.system(size: 12)).foregroundColor(Color.zxF04) }; Spacer(); Image(systemName: "chevron.right").font(.system(size: 12)).foregroundColor(Color.zxF03) }.padding(16).background(Color.zxFill003).clipShape(RoundedRectangle(cornerRadius: 16)).overlay(RoundedRectangle(cornerRadius: 16).stroke(Color.zxBorder006, lineWidth: 1)) }.foregroundColor(.primary) }
|
||||
}
|
||||
|
||||
struct EditKnowledgePage: View {
|
||||
@State private var title = "偏差-方差权衡"; @State private var content = "偏差衡量模型的预测与真实值之间的差异..."
|
||||
var body: some View {
|
||||
ZStack { Color.zxBg0.ignoresSafeArea()
|
||||
VStack(spacing: 0) {
|
||||
ZXBackHeader(title: "编辑知识点", subtitle: nil) {}
|
||||
ScrollView { VStack(spacing: 16) {
|
||||
VStack(alignment: .leading, spacing: 8) { Text("标题").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxF035); TextField("", text: $title).font(.system(size: 15)).tint(Color.zxPurple).padding(.horizontal, 16).frame(height: 52).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)) }
|
||||
VStack(alignment: .leading, spacing: 8) { Text("内容").font(.system(size: 12, weight: .semibold)).foregroundColor(Color.zxF035); TextEditor(text: $content).frame(minHeight: 200).scrollContentBackground(.hidden).padding(12).background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(Color.zxBorder008, lineWidth: 1)) }
|
||||
Button {} label: { Text("保存修改").font(.system(size: 14, weight: .bold)).foregroundColor(.white).frame(maxWidth: .infinity).frame(height: 52).background(ZXGradient.ctaPurple).clipShape(RoundedRectangle(cornerRadius: 16)) }
|
||||
}.padding(.horizontal, 20).padding(.bottom, 80) }.scrollIndicators(.hidden)
|
||||
}
|
||||
}.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
63
AIStudyApp/AIStudyApp/Features/Profile/ProfileView.swift
Normal file
@ -0,0 +1,63 @@
|
||||
//
|
||||
// ProfileView.swift - Page 10: Profile
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct ProfileView: View {
|
||||
var body: some View {
|
||||
ZStack {
|
||||
ZXGradient.page.ignoresSafeArea()
|
||||
ScrollView {
|
||||
VStack(spacing: 16) {
|
||||
HStack {
|
||||
Text("我的").font(.system(size: 22, weight: .heavy)).foregroundColor(Color.zxF0).tracking(-0.5)
|
||||
Spacer()
|
||||
ZXIconBtn(icon: "bell", size: 36) {}
|
||||
ZXIconBtn(icon: "gearshape", size: 36) {}
|
||||
}
|
||||
.padding(.horizontal, 20).padding(.top, ZXSpacing.statusBarH + 16).padding(.bottom, 4)
|
||||
profileCard
|
||||
VStack(spacing: 0) {
|
||||
ZXProfileMenuRow(emoji: "🎯", title: "学习目标设置", desc: "调整你的学习目标")
|
||||
ZXProfileMenuRow(emoji: "🔔", title: "复习提醒", desc: "间隔复习通知设置")
|
||||
ZXProfileMenuRow(emoji: "📊", title: "学习报告", desc: "周报 · 月报 · 成就")
|
||||
ZXProfileMenuRow(emoji: "🧩", title: "学习方法偏好", desc: "回忆 · 费曼 · 间隔")
|
||||
ZXProfileMenuRow(emoji: "☁️", title: "数据同步与备份", desc: "云端同步设置")
|
||||
}
|
||||
.background(Color.zxFill004).clipShape(RoundedRectangle(cornerRadius: 20))
|
||||
.overlay(RoundedRectangle(cornerRadius: 20).stroke(Color.zxBorder006, lineWidth: 1))
|
||||
achievementsSection.padding(.bottom, 120)
|
||||
}
|
||||
.padding(.horizontal, 20)
|
||||
}
|
||||
.scrollIndicators(.hidden)
|
||||
}
|
||||
}
|
||||
private var profileCard: some View {
|
||||
VStack(spacing: 16) {
|
||||
HStack {
|
||||
ZStack { Circle().frame(width: 80, height: 80).foregroundColor(Color.zxPurpleBG(0.2)); Text("🧑🎓").font(.system(size: 36)) }
|
||||
VStack(alignment: .leading, spacing: 4) { Text("学习者").font(.system(size: 20, weight: .bold)).foregroundColor(Color.zxF0); Text("user@example.com").font(.system(size: 12)).foregroundColor(Color.zxF04) }
|
||||
Spacer(); Image(systemName: "chevron.right").font(.system(size: 14)).foregroundColor(Color.zxF03)
|
||||
}
|
||||
HStack(spacing: 0) { ZXProfileStat(value: "14", label: "连续天", color: Color.zxOrange); ZXProfileStat(value: "47", label: "知识点", color: Color.zxPurple); ZXProfileStat(value: "1,240", label: "积分", color: Color.zxTeal) }
|
||||
}
|
||||
.padding(20).background(ZXGradient.profileCard).overlay(RoundedRectangle(cornerRadius: 20).stroke(Color(hex: "#7C6EFA", opacity: 0.2), lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 20))
|
||||
}
|
||||
private var achievementsSection: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
Text("成就").font(.system(size: 15, weight: .bold)).foregroundColor(Color.zxF0)
|
||||
HStack(spacing: 8) { ZXAchievementBadge(emoji: "🔥", label: "连续 14 天", color: Color.zxOrange); ZXAchievementBadge(emoji: "🧠", label: "费曼达人", color: Color.zxPurple); ZXAchievementBadge(emoji: "📚", label: "知识收藏家", color: Color.zxTeal); ZXAchievementBadge(emoji: "⚡", label: "速学者", color: Color.zxYellow) }
|
||||
}
|
||||
}
|
||||
}
|
||||
struct ZXProfileStat: View { let v: String; let l: String; let c: Color; var body: some View { VStack(spacing: 2) { Text(v).font(.system(size: 18, weight: .bold)).foregroundColor(c); Text(l).font(.system(size: 11)).foregroundColor(Color.zxF04) }.frame(maxWidth: .infinity) }
|
||||
init(value: String, label: String, color: Color) { self.v = value; self.l = label; self.c = color }
|
||||
}
|
||||
struct ZXProfileMenuRow: View { let emoji: String; let title: String; let desc: String
|
||||
var body: some View { HStack(spacing: 12) { Text(emoji).font(.system(size: 20)).frame(width: 36, height: 36).background(Color.zxFill006).clipShape(RoundedRectangle(cornerRadius: 10)); VStack(alignment: .leading, spacing: 2) { Text(title).font(.system(size: 14, weight: .semibold)).foregroundColor(Color.zxF0); Text(desc).font(.system(size: 11)).foregroundColor(Color.zxF03) }; Spacer(); Image(systemName: "chevron.right").font(.system(size: 12)).foregroundColor(Color.zxF03) }.padding(.horizontal, 16).padding(.vertical, 14) }
|
||||
}
|
||||
struct ZXAchievementBadge: View { let emoji: String; let label: String; let color: Color
|
||||
var body: some View { VStack(spacing: 6) { Text(emoji).font(.system(size: 24)).frame(width: 48, height: 48).background(color.opacity(0.12)).clipShape(RoundedRectangle(cornerRadius: 14)).overlay(RoundedRectangle(cornerRadius: 14).stroke(color.opacity(0.25), lineWidth: 1)); Text(label).font(.system(size: 10, weight: .semibold)).foregroundColor(Color.zxF04) }.frame(maxWidth: .infinity) }
|
||||
}
|
||||
50
AIStudyApp/AIStudyApp/Features/Study/StudyHomeView.swift
Normal file
@ -0,0 +1,50 @@
|
||||
//
|
||||
// StudyHomeView.swift - Page 8
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct StudyHomeView: View {
|
||||
@State private var ts: [ZXSTask] = [
|
||||
.init(t: "机器学习 - 回忆测试", tp: "回忆测试", c: Color.zxPurple, m: 10, d: true),
|
||||
.init(t: "高数 - 间隔复习 8 题", tp: "间隔复习", c: Color.zxOrange, m: 15, d: true),
|
||||
.init(t: "英语词汇 - 25 个待复习", tp: "词汇复习", c: Color.zxTeal, m: 8, d: false),
|
||||
.init(t: "注意力机制 - 费曼解释", tp: "费曼练习", c: Color.zxAccent, m: 12, d: false),
|
||||
.init(t: "产品设计 - 薄弱点复习", tp: "薄弱点", c: Color.zxYellow, m: 10, d: false),
|
||||
]
|
||||
private let wb: [CGFloat] = [0.3, 0.7, 1.0, 0.4, 0.9, 0.6, 0.2]
|
||||
private let dl = ["一","二","三","四","五","六","日"]
|
||||
|
||||
var body: some View {
|
||||
ZStack { ZXGradient.page.ignoresSafeArea()
|
||||
ScrollView { VStack(spacing: 16) {
|
||||
HStack { VStack(alignment: .leading, spacing: 2) { Text("周四,1月16日").font(.system(size: 12, weight: .medium)).foregroundColor(Color.zxF04); Text("学习工作台").font(.system(size: 20, weight: .heavy)).foregroundColor(Color.zxF0).tracking(-0.4) }; Spacer()
|
||||
HStack(spacing: 4) { Image(systemName: "flame.fill").font(.system(size: 14)).foregroundColor(Color.zxOrange); Text("14 天连续").font(.system(size: 13, weight: .bold)).foregroundColor(Color.zxOrange) }.padding(.horizontal, 12).padding(.vertical, 6).background(Color.zxOrangeBG(0.1)).clipShape(Capsule()).overlay(Capsule().stroke(Color(hex: "#F97316", opacity: 0.2), lineWidth: 1)) }
|
||||
.padding(.horizontal, 20).padding(.top, ZXSpacing.statusBarH + 16).padding(.bottom, 4)
|
||||
pc
|
||||
VStack(alignment: .leading, spacing: 12) { HStack { Text("今日任务").font(.system(size: 15, weight: .bold)).foregroundColor(Color.zxF0); Spacer(); HStack(spacing: 4) { Image(systemName: "calendar").font(.system(size: 12)).foregroundColor(Color.zxF04); Text("AI 自动排期").font(.system(size: 12)).foregroundColor(Color.zxF04) } }
|
||||
ForEach($ts) { $t in ZXSTaskRow(task: t) { t.d.toggle() } } }
|
||||
VStack(alignment: .leading, spacing: 14) { Text("本周学习活跃").font(.system(size: 15, weight: .bold)).foregroundColor(Color.zxF0)
|
||||
HStack(alignment: .bottom, spacing: 8) { ForEach(0..<7, id: \.self) { i in VStack(spacing: 8) { RoundedRectangle(cornerRadius: 6).fill(i == 6 ? Color.zxFill01 : Color(hex: "#7C6EFA", opacity: wb[i] * 0.9 + 0.1)).frame(height: wb[i] * 60); Text(dl[i]).font(.system(size: 10, weight: i == 2 ? .bold : .regular)).foregroundColor(i == 2 ? Color.zxPurple : Color.zxF03) }.frame(maxWidth: .infinity) } }
|
||||
HStack { Text("总计 3.5 小时").font(.system(size: 11)).foregroundColor(Color.zxF03); Spacer(); Text("日均 30 分钟").font(.system(size: 11)).foregroundColor(Color.zxF03) } }
|
||||
.padding(.bottom, 120) }
|
||||
.padding(.horizontal, 20) }
|
||||
.scrollIndicators(.hidden) }
|
||||
}
|
||||
private var pc: some View { let dn = ts.filter(\.d).count; let pct = CGFloat(dn) / 5
|
||||
return VStack(spacing: 12) { HStack { VStack(alignment: .leading, spacing: 2) { Text("今日进度").font(.system(size: 13, weight: .medium)).foregroundColor(Color.zxF05); HStack(alignment: .lastTextBaseline, spacing: 6) { Text("\(dn)").font(.system(size: 26, weight: .black)).foregroundColor(Color.zxF0); Text("/ 5"); Text("个任务").font(.system(size: 14, weight: .medium)).foregroundColor(Color.zxF04) } }; Spacer()
|
||||
ZStack { Circle().trim(from: 0, to: pct).stroke(ZXGradient.brand, style: StrokeStyle(lineWidth: 8, lineCap: .round)).rotationEffect(.degrees(-90)).frame(width: 64, height: 64); Text("\(Int(pct * 100))%").font(.system(size: 14, weight: .heavy)).foregroundColor(Color.zxPurple) } }
|
||||
ZStack(alignment: .leading) { RoundedRectangle(cornerRadius: 3).fill(Color.zxFill008).frame(height: 6); RoundedRectangle(cornerRadius: 3).fill(LinearGradient(colors: [Color.zxPurple, Color.zxAccent], startPoint: .leading, endPoint: .trailing)).frame(width: max(6, pct * (UIScreen.main.bounds.width - 72)), height: 6) }
|
||||
HStack { VStack(alignment: .leading, spacing: 2) { Text("\(dn * 12) 分钟").font(.system(size: 13, weight: .bold)).foregroundColor(Color.zxF0); Text("已学").font(.system(size: 10)).foregroundColor(Color.zxF04) }; Spacer(); VStack(spacing: 2) { Text("\((5 - dn) * 11) 分钟").font(.system(size: 13, weight: .bold)).foregroundColor(Color.zxF0); Text("剩余").font(.system(size: 10)).foregroundColor(Color.zxF04) }; Spacer(); VStack(alignment: .trailing, spacing: 2) { Text("+5 点").font(.system(size: 13, weight: .bold)).foregroundColor(Color.zxF0); Text("掌握").font(.system(size: 10)).foregroundColor(Color.zxF04) } } }
|
||||
.padding(16).background(ZXGradient.progressCard).overlay(RoundedRectangle(cornerRadius: 20).stroke(Color(hex: "#7C6EFA", opacity: 0.15), lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 20)) }
|
||||
}
|
||||
|
||||
struct ZXSTask: Identifiable { let id = UUID(); let t: String; let tp: String; let c: Color; let m: Int; var d: Bool }
|
||||
struct ZXSTaskRow: View { let task: ZXSTask; var action: () -> Void
|
||||
var body: some View { Button(action: action) { HStack(spacing: 12) { Image(systemName: task.d ? "checkmark.circle.fill" : "circle").font(.system(size: 20)).foregroundColor(task.d ? Color.zxGreen : Color.zxF02)
|
||||
VStack(alignment: .leading, spacing: 4) { Text(task.t).font(.system(size: 13, weight: .semibold)).foregroundColor(task.d ? Color.zxF04 : Color.zxF0).strikethrough(task.d); HStack(spacing: 8) { Text(task.tp).font(.system(size: 10, weight: .semibold)).foregroundColor(task.c).padding(.horizontal, 6).padding(.vertical, 1).background(task.c.opacity(0.12)).clipShape(Capsule()); Text("约 \(task.m) 分钟").font(.system(size: 10)).foregroundColor(Color.zxF035) } }
|
||||
Spacer(); if !task.d { Image(systemName: "play.fill").font(.system(size: 14)).foregroundColor(.white).frame(width: 32, height: 32).background(ZXGradient.brand).clipShape(RoundedRectangle(cornerRadius: 10)) } }
|
||||
.padding(.horizontal, 16).padding(.vertical, 12).background(task.d ? Color.zxFill003 : Color.zxFill005).overlay(RoundedRectangle(cornerRadius: 14).stroke(task.d ? Color(hex: "#FFFFFF", opacity: 0.05) : Color.zxBorder008, lineWidth: 1)).clipShape(RoundedRectangle(cornerRadius: 14)).opacity(task.d ? 0.6 : 1) }.foregroundColor(.primary) }
|
||||
}
|
||||
|
||||
extension Color { static let zxF035 = Color(hex: "#F0F0FF", opacity: 0.35) }
|
||||
112
AIStudyApp/README.md
Normal file
@ -0,0 +1,112 @@
|
||||
# 知习 ZhiXi — iOS App
|
||||
|
||||
AI-first 系统化学习 App,SwiftUI + 深色主题。
|
||||
|
||||
## 导航关系
|
||||
|
||||
```
|
||||
Splash(2s 自动跳转)
|
||||
↓
|
||||
Welcome(欢迎页)→ 已有账号 → Login
|
||||
↓ 开始使用
|
||||
Login(手机号/邮箱登录)
|
||||
↓ 登录成功
|
||||
Onboarding(4 步引导:输入知识 / 主动输出 / AI 分析 / 掌握知识)
|
||||
↓ 下一步
|
||||
GoalSetup(学习目标 / 方法 / 时间)
|
||||
↓ 开始学习
|
||||
┌──────────────────────────────────────────────────────┐
|
||||
│ 5-Tab 主界面 │
|
||||
│ │
|
||||
│ [AI] [知识库] [学习] [分析] [我的] │
|
||||
│ │ │ │ │ │ │
|
||||
│ ├─ 开始回答 ├─ 卡片点击 ├─ 任务点击 │ │ │
|
||||
│ │ → Daily │ → Detail │ → Recall │ │ │
|
||||
│ │ Thinking │ │ / Feedbk │ │ │
|
||||
│ │ ├─ 创建 │ │ │ │
|
||||
│ ├─ 快捷操作 │ → Create │ │ │ │
|
||||
│ │ → Recall │ │ │ │ │
|
||||
│ │ / Weak │ ┌ 知识点 │ │ │ │
|
||||
│ │ │ ├ Detail │ │ │ │
|
||||
│ └─ 互动列表 │ │ → KnwlD │ │ │ │
|
||||
│ → AIChat │ ├ Add │ │ │ │
|
||||
│ │ ├ Import │ │ │ │
|
||||
│ │ └ Edit │ │ │ │
|
||||
└──────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
## 页面清单(对照 React 原型 22 页)
|
||||
|
||||
| # | 页面 | 文件 | 状态 |
|
||||
|---|------|------|------|
|
||||
| 1 | Splash 启动页 | `AIStudyAppApp.swift` → `SplashPage` | ✅ |
|
||||
| 2 | Welcome 欢迎页 | `AIStudyAppApp.swift` → `WelcomePage` | ✅ |
|
||||
| 3 | Login 登录页 | `AIStudyAppApp.swift` → `LoginPage` | ✅ |
|
||||
| 4 | Onboarding 引导页 | `AIStudyAppApp.swift` → `OnboardingPage` | ✅ |
|
||||
| 5 | GoalSetup 目标设置 | `AIStudyAppApp.swift` → `GoalSetupPage` | ✅ |
|
||||
| 6 | AIHome AI 首页 | `Features/AI/AIHomeView.swift` | ✅ |
|
||||
| 7 | LibraryHome 知识库首页 | `Features/Library/LibraryHomeView.swift` | ✅ |
|
||||
| 8 | StudyHome 学习工作台 | `Features/Study/StudyHomeView.swift` | ✅ |
|
||||
| 9 | AnalysisHome 学习分析 | `Features/Analysis/AnalysisHomeView.swift` | ✅ |
|
||||
| 10 | Profile 我的 | `Features/Profile/ProfileView.swift` | ✅ |
|
||||
| 11 | AIChat AI 对话 | `Features/AI/DailyThinkingPage.swift` → `AIChatPage` | ✅ |
|
||||
| 14 | DailyThinking 今日思考 | `Features/AI/DailyThinkingPage.swift` | ✅ |
|
||||
| 13 | RecallTest 回忆测试 | `Features/AI/DailyThinkingPage.swift` → `RecallTestPage` | ✅ |
|
||||
| 16 | WeakPoints 薄弱点分析 | `Features/AI/DailyThinkingPage.swift` → `WeakPointsPage` | ✅ |
|
||||
| 15 | AIFeedback AI 反馈 | `Features/AI/DailyThinkingPage.swift` → `AIFeedbackPageView` | ✅ |
|
||||
| 18 | CreateLibrary 创建知识库 | `Features/Library/LibrarySubpages.swift` | ✅ |
|
||||
| 19 | LibraryDetail 知识库详情 | `Features/Library/LibrarySubpages.swift` | ✅ |
|
||||
| 20 | AddKnowledge 添加知识点 | `Features/Library/LibrarySubpages.swift` | ✅ |
|
||||
| 21 | Import 导入资料 | `Features/Library/LibrarySubpages.swift` | ✅ |
|
||||
| 22 | KnowledgeDetail 知识点详情 | `Features/Library/LibrarySubpages.swift` | ✅ |
|
||||
| 23 | EditKnowledge 编辑知识点 | `Features/Library/LibrarySubpages.swift` | ✅ |
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
AIStudyApp/
|
||||
├── AIStudyAppApp.swift # 根路由 + Splash/Welcome/Login/Onboarding/GoalSetup
|
||||
├── ContentView.swift # 5-Tab 主界面 + ZXTabBar + ZXIconBtn + ZXScoreBox + ZXAIInputBar
|
||||
├── Core/
|
||||
│ └── DesignSystem/
|
||||
│ └── DesignTokens.swift # 颜色 / 渐变 / 圆角 / 间距 / 字号
|
||||
└── Features/
|
||||
├── AI/
|
||||
│ ├── AIHomeView.swift # AI 首页
|
||||
│ └── DailyThinkingPage.swift # 今日思考 / AI 对话 / 回忆测试 / 薄弱点 / AI 反馈
|
||||
├── Library/
|
||||
│ ├── LibraryHomeView.swift # 知识库首页
|
||||
│ └── LibrarySubpages.swift # 创建 / 详情 / 添加 / 导入 / 知识点详情 / 编辑
|
||||
├── Study/
|
||||
│ └── StudyHomeView.swift # 学习工作台
|
||||
├── Analysis/
|
||||
│ └── AnalysisHomeView.swift # 学习分析
|
||||
└── Profile/
|
||||
└── ProfileView.swift # 我的页
|
||||
```
|
||||
|
||||
## 设计系统
|
||||
|
||||
| 类别 | Token | 值 |
|
||||
|------|-------|-----|
|
||||
| 主背景 | `Color.zxBg0` | `#0F0F1A` |
|
||||
| 页面渐变 | `ZXGradient.page` | `#0F0F1A → #12122A` |
|
||||
| 品牌紫 | `Color.zxPurple` | `#7C6EFA` |
|
||||
| 品牌橙 | `Color.zxOrange` | `#F97316` |
|
||||
| 文字主色 | `Color.zxF0` | `#F0F0FF` |
|
||||
| 卡片圆角 | `ZXRadius.xl3` | `20` |
|
||||
| 按钮高度 | `ZXSize.buttonH` | `42` |
|
||||
| 页面水平间距 | `ZXSpacing.pageHPadding` | `20` |
|
||||
| 状态栏高度 | `ZXSpacing.statusBarH` | `44` |
|
||||
| TabBar 高度 | `ZXSpacing.tabBarH` | `83` |
|
||||
|
||||
以上全部从 React 原型 1:1 像素级提取。
|
||||
|
||||
## 运行
|
||||
|
||||
Xcode 打开 `AIStudyApp.xcodeproj`,选择 iPhone 17 Pro 模拟器,`Cmd+R`。
|
||||
|
||||
```
|
||||
Clean Build 之前先:
|
||||
rm -rf ~/Library/Developer/Xcode/DerivedData/AIStudyApp-*
|
||||
```
|
||||
@ -1,282 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="light" lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" name="viewport"/>
|
||||
<title>AI 助手 - 知习</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
"colors": {
|
||||
"on-secondary-fixed": "#2c0050",
|
||||
"background": "#f9f9fd",
|
||||
"secondary-fixed": "#f0dbff",
|
||||
"on-secondary": "#ffffff",
|
||||
"tertiary-fixed": "#e1e0ff",
|
||||
"error-container": "#ffdad6",
|
||||
"inverse-surface": "#2e3034",
|
||||
"tertiary-fixed-dim": "#c0c1ff",
|
||||
"on-primary-fixed": "#001c39",
|
||||
"surface-bright": "#f9f9fd",
|
||||
"on-secondary-container": "#440076",
|
||||
"tertiary": "#4648d4",
|
||||
"primary-fixed-dim": "#a4c9ff",
|
||||
"outline": "#717783",
|
||||
"on-tertiary-fixed-variant": "#2f2ebe",
|
||||
"on-tertiary-container": "#fffbff",
|
||||
"primary": "#005da7",
|
||||
"secondary-fixed-dim": "#deb7ff",
|
||||
"on-primary-fixed-variant": "#004883",
|
||||
"inverse-on-surface": "#f0f0f4",
|
||||
"error": "#ba1a1a",
|
||||
"on-primary-container": "#fdfcff",
|
||||
"on-primary": "#ffffff",
|
||||
"surface-container-low": "#f3f3f7",
|
||||
"surface-container-highest": "#e2e2e6",
|
||||
"on-tertiary-fixed": "#07006c",
|
||||
"surface-dim": "#d9dade",
|
||||
"inverse-primary": "#a4c9ff",
|
||||
"surface-variant": "#e2e2e6",
|
||||
"surface-container-lowest": "#ffffff",
|
||||
"surface-tint": "#0060ac",
|
||||
"primary-container": "#2976c7",
|
||||
"surface": "#f9f9fd",
|
||||
"on-surface-variant": "#414751",
|
||||
"on-background": "#1a1c1f",
|
||||
"surface-container-high": "#e8e8ec",
|
||||
"on-error-container": "#93000a",
|
||||
"secondary": "#8135c5",
|
||||
"on-secondary-fixed-variant": "#670fac",
|
||||
"outline-variant": "#c1c7d3",
|
||||
"on-tertiary": "#ffffff",
|
||||
"on-surface": "#1a1c1f",
|
||||
"on-error": "#ffffff",
|
||||
"secondary-container": "#ba70ff",
|
||||
"primary-fixed": "#d4e3ff",
|
||||
"tertiary-container": "#6063ee",
|
||||
"surface-container": "#ededf1"
|
||||
},
|
||||
"borderRadius": {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
"spacing": {
|
||||
"xl": "64px",
|
||||
"md": "24px",
|
||||
"container-margin": "20px",
|
||||
"base": "8px",
|
||||
"sm": "12px",
|
||||
"lg": "40px",
|
||||
"xs": "4px",
|
||||
"gutter": "16px",
|
||||
"safe-bottom": "env(safe-area-inset-bottom)",
|
||||
"safe-top": "env(safe-area-inset-top)"
|
||||
},
|
||||
"fontFamily": {
|
||||
"h3": ["Manrope", "sans-serif"],
|
||||
"h2": ["Manrope", "sans-serif"],
|
||||
"label-caps": ["Manrope", "sans-serif"],
|
||||
"body-md": ["Manrope", "sans-serif"],
|
||||
"body-lg": ["Manrope", "sans-serif"],
|
||||
"h1": ["Manrope", "sans-serif"]
|
||||
},
|
||||
"fontSize": {
|
||||
"h3": ["22px", { "lineHeight": "1.3", "letterSpacing": "0", "fontWeight": "600" }],
|
||||
"h2": ["28px", { "lineHeight": "1.3", "letterSpacing": "-0.01em", "fontWeight": "600" }],
|
||||
"label-caps": ["12px", { "lineHeight": "1.0", "letterSpacing": "0.05em", "fontWeight": "600" }],
|
||||
"body-md": ["15px", { "lineHeight": "1.5", "letterSpacing": "0", "fontWeight": "400" }],
|
||||
"body-lg": ["17px", { "lineHeight": "1.6", "letterSpacing": "-0.01em", "fontWeight": "400" }],
|
||||
"h1": ["34px", { "lineHeight": "1.2", "letterSpacing": "-0.02em", "fontWeight": "700" }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
/* Custom scrollbar for web view */
|
||||
::-webkit-scrollbar {
|
||||
width: 4px;
|
||||
}
|
||||
::-webkit-scrollbar-track {
|
||||
background: transparent;
|
||||
}
|
||||
::-webkit-scrollbar-thumb {
|
||||
background: #e2e2e6;
|
||||
border-radius: 4px;
|
||||
}
|
||||
/* Ambient AI Glow */
|
||||
.ai-glow {
|
||||
background: radial-gradient(circle at top right, rgba(129, 53, 197, 0.08) 0%, rgba(0, 93, 167, 0.05) 40%, rgba(249, 249, 253, 0) 70%);
|
||||
}
|
||||
.ai-message-gradient {
|
||||
background: linear-gradient(135deg, rgba(212, 227, 255, 0.3) 0%, rgba(225, 224, 255, 0.3) 100%);
|
||||
}
|
||||
.glass-input {
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
backdrop-filter: blur(24px);
|
||||
-webkit-backdrop-filter: blur(24px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
box-shadow: 0 8px 32px rgba(0, 93, 167, 0.04), inset 0 1px 2px rgba(255, 255, 255, 0.8);
|
||||
}
|
||||
.btn-press:active {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-background text-on-background min-h-screen flex flex-col font-body-md overflow-hidden relative">
|
||||
<!-- Ambient Background Glow -->
|
||||
<div class="fixed inset-0 pointer-events-none ai-glow z-0"></div>
|
||||
<!-- TopAppBar -->
|
||||
<header class="bg-white/80 dark:bg-slate-900/80 backdrop-blur-xl docked full-width top-0 sticky border-b border-slate-200/50 dark:border-slate-800/50 shadow-sm dark:shadow-none flex justify-between items-center w-full px-5 py-3 z-40">
|
||||
<div class="flex items-center gap-3">
|
||||
<button class="w-8 h-8 flex items-center justify-center text-on-surface hover:bg-surface-variant/50 rounded-full transition-colors btn-press -ml-1">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'wght' 400;">arrow_back_ios_new</span>
|
||||
</button>
|
||||
<div class="flex flex-col">
|
||||
<span class="font-['Manrope'] font-bold text-xl text-slate-900 dark:text-slate-50 tracking-tight leading-none">AI 助手</span>
|
||||
<span class="text-[11px] text-outline font-medium mt-0.5 flex items-center gap-1">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-tertiary"></span>
|
||||
当前学习:认知心理学 · 记忆的编码与提取
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
<button class="w-10 h-10 flex items-center justify-center text-outline hover:opacity-80 transition-opacity Active: scale-95 transition-transform duration-150 rounded-full hover:bg-surface-variant/50">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'wght' 300;">settings</span>
|
||||
</button>
|
||||
</header>
|
||||
<!-- Main Chat Canvas -->
|
||||
<main class="flex-1 overflow-y-auto px-container-margin pt-md pb-32 z-10 relative scroll-smooth flex flex-col gap-xl">
|
||||
<!-- Welcome / Context Intro -->
|
||||
<div class="flex flex-col items-center justify-center mt-lg mb-md text-center">
|
||||
<div class="w-16 h-16 rounded-2xl ai-message-gradient flex items-center justify-center mb-sm shadow-[0_8px_24px_rgba(70,72,212,0.12)]">
|
||||
<span class="material-symbols-outlined text-tertiary text-3xl" style="font-variation-settings: 'wght' 200;">auto_awesome</span>
|
||||
</div>
|
||||
<h2 class="font-h2 text-h2 text-on-surface mb-2">准备好深入探索了吗?</h2>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant max-w-[280px]">针对「认知心理学 · 记忆的编码与提取」,我可以为你提供更深度的解析或测验。</p>
|
||||
</div>
|
||||
<!-- Dialogue Area -->
|
||||
<div class="flex flex-col gap-lg">
|
||||
<!-- User Message -->
|
||||
<div class="flex justify-end">
|
||||
<div class="max-w-[85%] bg-surface-container-high text-on-surface px-sm py-sm rounded-2xl rounded-tr-sm shadow-[0_2px_12px_rgba(0,0,0,0.02)]">
|
||||
<p class="font-body-md text-body-md">关于“情境依存性记忆”,如果我在图书馆复习,考试时在教室,是不是会影响提取?</p>
|
||||
</div>
|
||||
</div>
|
||||
<!-- AI Message -->
|
||||
<div class="flex justify-start items-start gap-3">
|
||||
<div class="w-8 h-8 rounded-full ai-message-gradient flex items-center justify-center flex-shrink-0 mt-1 border border-white/50">
|
||||
<span class="material-symbols-outlined text-tertiary text-[18px]" style="font-variation-settings: 'wght' 300;">colors_spark</span>
|
||||
</div>
|
||||
<div class="max-w-[85%]">
|
||||
<div class="bg-white/60 backdrop-blur-md px-md py-sm rounded-3xl rounded-tl-sm shadow-[0_4px_24px_rgba(0,93,167,0.03)] border border-white/40">
|
||||
<p class="font-body-md text-body-md text-on-surface leading-relaxed mb-4">
|
||||
这是一个非常经典的问题!是的,根据**情境依存性记忆 (Context-Dependent Memory)** 的原理,外部环境线索确实会影响记忆的提取。
|
||||
</p>
|
||||
<!-- Structured Content inside AI response -->
|
||||
<div class="bg-surface-container-lowest/50 rounded-xl p-3 border border-surface-variant/50 mb-3">
|
||||
<h4 class="font-label-caps text-label-caps text-primary mb-1 uppercase tracking-wider">核心机制</h4>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant text-[14px]">
|
||||
当你编码(学习)信息时,周围的环境(如气味、光线、声音,甚至背景音乐)会一并被编码为提取线索。如果提取(考试)时的环境与编码时一致,这些线索能帮助你更容易地唤起记忆。这就是著名的“潜水员实验”所证明的。
|
||||
</p>
|
||||
</div>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant text-[14px] leading-relaxed">
|
||||
为了克服这种环境差异带来的影响,你可以尝试**多情境复习**,或者在脑海中**主动重构**学习时的情境。
|
||||
</p>
|
||||
</div>
|
||||
<!-- Feedback actions -->
|
||||
<div class="flex items-center gap-2 mt-2 ml-2">
|
||||
<button class="text-outline-variant hover:text-primary transition-colors btn-press flex items-center gap-1">
|
||||
<span class="material-symbols-outlined text-[16px]">thumb_up</span>
|
||||
</button>
|
||||
<button class="text-outline-variant hover:text-error transition-colors btn-press flex items-center gap-1">
|
||||
<span class="material-symbols-outlined text-[16px]">thumb_down</span>
|
||||
</button>
|
||||
<button class="text-outline-variant hover:text-tertiary transition-colors btn-press flex items-center gap-1 ml-2">
|
||||
<span class="material-symbols-outlined text-[16px]">content_copy</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- Bottom Interaction Area -->
|
||||
<div class="fixed bottom-[88px] left-0 w-full px-container-margin z-30 pointer-events-none flex flex-col gap-4">
|
||||
<!-- Quick Actions (Scrollable) -->
|
||||
<div class="overflow-x-auto no-scrollbar pointer-events-auto -mx-container-margin px-container-margin pb-2">
|
||||
<div class="flex gap-2 w-max">
|
||||
<button class="px-4 py-2 rounded-full bg-surface-container-lowest/80 backdrop-blur-md border border-outline-variant/30 text-[13px] font-medium text-on-surface-variant whitespace-nowrap btn-press shadow-sm hover:bg-white transition-colors">
|
||||
用更简单的话解释
|
||||
</button>
|
||||
<button class="px-4 py-2 rounded-full bg-surface-container-lowest/80 backdrop-blur-md border border-outline-variant/30 text-[13px] font-medium text-on-surface-variant whitespace-nowrap btn-press shadow-sm hover:bg-white transition-colors">
|
||||
给我举个例子
|
||||
</button>
|
||||
<button class="px-4 py-2 rounded-full bg-surface-container-lowest/80 backdrop-blur-md border border-outline-variant/30 text-[13px] font-medium text-on-surface-variant whitespace-nowrap btn-press shadow-sm hover:bg-white transition-colors">
|
||||
我哪里理解错了?
|
||||
</button>
|
||||
<button class="px-4 py-2 rounded-full bg-surface-container-lowest/80 backdrop-blur-md border border-outline-variant/30 text-[13px] font-medium text-on-surface-variant whitespace-nowrap btn-press shadow-sm hover:bg-white transition-colors flex items-center gap-1">
|
||||
<span class="material-symbols-outlined text-[14px] text-tertiary">school</span>
|
||||
用费曼方式讲给我听
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Input Area -->
|
||||
<div class="pointer-events-auto glass-input rounded-3xl p-2 flex items-end gap-2 mb-safe-bottom">
|
||||
<button class="w-10 h-10 rounded-full flex items-center justify-center text-on-surface-variant hover:bg-surface-variant/50 transition-colors btn-press shrink-0 mb-1">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'wght' 300;">add_circle</span>
|
||||
</button>
|
||||
<div class="flex-1 relative flex items-center min-h-[48px]">
|
||||
<textarea class="w-full bg-transparent border-none focus:ring-0 resize-none font-body-md text-body-md text-on-surface placeholder:text-outline-variant py-3 px-2 max-h-[120px] overflow-y-auto" placeholder="继续追问,或输入新问题..." rows="1" style="caret-color: #005da7;"></textarea>
|
||||
</div>
|
||||
<div class="flex items-center gap-1 shrink-0 mb-1">
|
||||
<button class="w-10 h-10 rounded-full flex items-center justify-center text-on-surface-variant hover:bg-surface-variant/50 transition-colors btn-press">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'wght' 300;">mic</span>
|
||||
</button>
|
||||
<button class="w-10 h-10 rounded-full bg-primary text-white shadow-md flex items-center justify-center btn-press">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'wght' 400;">arrow_upward</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- BottomNavBar -->
|
||||
<nav class="bg-white/80 dark:bg-slate-900/80 backdrop-blur-2xl fixed bottom-0 w-full z-50 rounded-t-none border-t border-slate-200/50 dark:border-slate-800/50 shadow-[0_-4px_24px_rgba(0,0,0,0.04)] fixed bottom-0 left-0 w-full flex justify-around items-center px-4 pt-2 pb-safe-offset-2 pb-[env(safe-area-inset-bottom)] md:hidden">
|
||||
<a class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 hover:bg-slate-50/50 dark:hover:bg-slate-800/50 Active: scale-90 transition-transform duration-200 p-2 rounded-xl" href="#">
|
||||
<span class="material-symbols-outlined mb-1" style="font-variation-settings: 'wght' 300;">menu_book</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">学习</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 hover:bg-slate-50/50 dark:hover:bg-slate-800/50 Active: scale-90 transition-transform duration-200 p-2 rounded-xl" href="#">
|
||||
<span class="material-symbols-outlined mb-1" style="font-variation-settings: 'wght' 300;">database</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">知识库</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center justify-center text-blue-500 dark:text-blue-400 font-bold hover:bg-slate-50/50 dark:hover:bg-slate-800/50 Active: scale-90 transition-transform duration-200 p-2 rounded-xl" href="#">
|
||||
<span class="material-symbols-outlined mb-1" style="font-variation-settings: 'FILL' 1, 'wght' 400;">auto_awesome</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">AI 助手</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 hover:bg-slate-50/50 dark:hover:bg-slate-800/50 Active: scale-90 transition-transform duration-200 p-2 rounded-xl" href="#">
|
||||
<span class="material-symbols-outlined mb-1" style="font-variation-settings: 'wght' 300;">person</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">我的</span>
|
||||
</a>
|
||||
</nav>
|
||||
<!-- Web Navigation Cluster (Hidden on Mobile) -->
|
||||
<nav class="hidden md:flex fixed top-0 right-5 h-[64px] items-center gap-6 z-50">
|
||||
<a class="font-body-md text-slate-400 hover:text-slate-900 transition-colors" href="#">学习</a>
|
||||
<a class="font-body-md text-slate-400 hover:text-slate-900 transition-colors" href="#">知识库</a>
|
||||
<a class="font-body-md text-blue-600 font-semibold transition-colors" href="#">AI 助手</a>
|
||||
<a class="font-body-md text-slate-400 hover:text-slate-900 transition-colors" href="#">我的</a>
|
||||
</nav>
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 429 KiB |
@ -1,306 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
|
||||
<title>本次学习分析</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
"colors": {
|
||||
"on-surface-variant": "#414751",
|
||||
"surface-container-lowest": "#ffffff",
|
||||
"error-container": "#ffdad6",
|
||||
"on-tertiary": "#ffffff",
|
||||
"primary-container": "#2976c7",
|
||||
"on-surface": "#1a1c1f",
|
||||
"on-error-container": "#93000a",
|
||||
"secondary-fixed": "#f0dbff",
|
||||
"surface-container-high": "#e8e8ec",
|
||||
"primary": "#005da7",
|
||||
"on-secondary": "#ffffff",
|
||||
"on-error": "#ffffff",
|
||||
"on-primary-fixed-variant": "#004883",
|
||||
"outline": "#717783",
|
||||
"on-secondary-fixed-variant": "#670fac",
|
||||
"surface-container-highest": "#e2e2e6",
|
||||
"on-tertiary-fixed-variant": "#2f2ebe",
|
||||
"secondary-fixed-dim": "#deb7ff",
|
||||
"surface-variant": "#e2e2e6",
|
||||
"outline-variant": "#c1c7d3",
|
||||
"inverse-on-surface": "#f0f0f4",
|
||||
"surface-container": "#ededf1",
|
||||
"surface-dim": "#d9dade",
|
||||
"tertiary-fixed": "#e1e0ff",
|
||||
"surface-bright": "#f9f9fd",
|
||||
"tertiary": "#4648d4",
|
||||
"surface": "#f9f9fd",
|
||||
"on-tertiary-container": "#fffbff",
|
||||
"on-secondary-fixed": "#2c0050",
|
||||
"primary-fixed": "#d4e3ff",
|
||||
"on-primary-container": "#fdfcff",
|
||||
"inverse-surface": "#2e3034",
|
||||
"on-primary-fixed": "#001c39",
|
||||
"primary-fixed-dim": "#a4c9ff",
|
||||
"on-tertiary-fixed": "#07006c",
|
||||
"surface-tint": "#0060ac",
|
||||
"secondary-container": "#ba70ff",
|
||||
"tertiary-container": "#6063ee",
|
||||
"error": "#ba1a1a",
|
||||
"tertiary-fixed-dim": "#c0c1ff",
|
||||
"background": "#f9f9fd",
|
||||
"on-background": "#1a1c1f",
|
||||
"on-secondary-container": "#440076",
|
||||
"inverse-primary": "#a4c9ff",
|
||||
"surface-container-low": "#f3f3f7",
|
||||
"on-primary": "#ffffff",
|
||||
"secondary": "#8135c5"
|
||||
},
|
||||
"borderRadius": {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
"spacing": {
|
||||
"sm": "12px",
|
||||
"xs": "4px",
|
||||
"xl": "64px",
|
||||
"base": "8px",
|
||||
"lg": "40px",
|
||||
"gutter": "16px",
|
||||
"md": "24px",
|
||||
"container-margin": "20px"
|
||||
},
|
||||
"fontFamily": {
|
||||
"h3": ["Manrope"],
|
||||
"label-caps": ["Manrope"],
|
||||
"body-md": ["Manrope"],
|
||||
"body-lg": ["Manrope"],
|
||||
"h2": ["Manrope"],
|
||||
"h1": ["Manrope"]
|
||||
},
|
||||
"fontSize": {
|
||||
"h3": ["22px", { "lineHeight": "1.3", "letterSpacing": "0", "fontWeight": "600" }],
|
||||
"label-caps": ["12px", { "lineHeight": "1.0", "letterSpacing": "0.05em", "fontWeight": "600" }],
|
||||
"body-md": ["15px", { "lineHeight": "1.5", "letterSpacing": "0", "fontWeight": "400" }],
|
||||
"body-lg": ["17px", { "lineHeight": "1.6", "letterSpacing": "-0.01em", "fontWeight": "400" }],
|
||||
"h2": ["28px", { "lineHeight": "1.3", "letterSpacing": "-0.01em", "fontWeight": "600" }],
|
||||
"h1": ["34px", { "lineHeight": "1.2", "letterSpacing": "-0.02em", "fontWeight": "700" }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.glass-panel {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
backdrop-filter: blur(24px);
|
||||
-webkit-backdrop-filter: blur(24px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
box-shadow: 0 40px 60px -15px rgba(0, 93, 167, 0.05);
|
||||
}
|
||||
.ai-glow-text {
|
||||
background: linear-gradient(135deg, #005da7 0%, #8135c5 100%);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
.ai-glow-bg {
|
||||
background: linear-gradient(135deg, #005da7 0%, #8135c5 100%);
|
||||
}
|
||||
.progress-ring-circle {
|
||||
transition: stroke-dashoffset 1s ease-in-out;
|
||||
transform: rotate(-90deg);
|
||||
transform-origin: 50% 50%;
|
||||
}
|
||||
.mesh-bg {
|
||||
background-color: #f9f9fd;
|
||||
background-image: radial-gradient(at 80% 0%, hsla(289,85%,88%,0.3) 0px, transparent 50%),
|
||||
radial-gradient(at 0% 50%, hsla(211,85%,88%,0.3) 0px, transparent 50%);
|
||||
background-attachment: fixed;
|
||||
}
|
||||
.premium-tab-bar {
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: blur(32px);
|
||||
-webkit-backdrop-filter: blur(32px);
|
||||
border-top: 1px solid rgba(255, 255, 255, 0.5);
|
||||
box-shadow: 0 -4px 24px -8px rgba(0, 93, 167, 0.08);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="mesh-bg text-on-background font-body-md min-h-screen flex flex-col pb-[100px]">
|
||||
<!-- TopAppBar -->
|
||||
<header class="bg-white/70 dark:bg-slate-900/70 backdrop-blur-xl docked full-width top-0 sticky border-b border-white/10 shadow-[0_8px_32px_0_rgba(74,144,226,0.05)] z-40 flex justify-between items-center w-full px-6 py-4">
|
||||
<div class="flex items-center gap-sm">
|
||||
<button class="text-primary active:scale-95 transition-transform duration-200">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 0;">arrow_back</span>
|
||||
</button>
|
||||
</div>
|
||||
<h1 class="font-manrope font-bold text-lg tracking-tight text-primary-container">本次学习分析</h1>
|
||||
<div class="flex items-center gap-sm">
|
||||
<button class="text-primary active:scale-95 transition-transform duration-200">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 0;">ios_share</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Main Content Canvas -->
|
||||
<main class="flex-grow flex flex-col items-center px-container-margin pt-md pb-xl gap-md max-w-3xl mx-auto w-full">
|
||||
<!-- AI Summary Card -->
|
||||
<section class="glass-panel rounded-xl p-md w-full flex flex-col gap-sm relative overflow-hidden">
|
||||
<div class="absolute top-0 left-0 w-full h-1 ai-glow-bg opacity-70"></div>
|
||||
<div class="flex items-center gap-xs mb-xs">
|
||||
<span class="material-symbols-outlined text-secondary" style="font-variation-settings: 'FILL' 1;">auto_awesome</span>
|
||||
<span class="font-label-caps text-label-caps text-secondary uppercase tracking-widest">AI Insight</span>
|
||||
</div>
|
||||
<p class="font-h3 text-h3 text-on-surface leading-relaxed font-bold">
|
||||
你已经初步掌握了神经网络的基础架构,但在激活函数的作用上还有待加强。
|
||||
</p>
|
||||
</section>
|
||||
<!-- Bento Grid Layout for Stats and Details -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-md w-full">
|
||||
<!-- Mastery Score (Premium Ring) -->
|
||||
<section class="glass-panel rounded-xl p-md flex flex-col items-center justify-center gap-base relative">
|
||||
<h2 class="font-label-caps text-label-caps text-on-surface-variant uppercase tracking-widest absolute top-md left-md">掌握度</h2>
|
||||
<div class="relative w-32 h-32 mt-sm">
|
||||
<svg class="w-full h-full" viewbox="0 0 100 100">
|
||||
<!-- Background track -->
|
||||
<circle class="text-surface-variant stroke-current opacity-30" cx="50" cy="50" fill="transparent" r="40" stroke-width="8"></circle>
|
||||
<!-- Gradient definitions -->
|
||||
<defs>
|
||||
<lineargradient id="ringGradient" x1="0%" x2="100%" y1="0%" y2="100%">
|
||||
<stop offset="0%" stop-color="#005da7"></stop>
|
||||
<stop offset="100%" stop-color="#8135c5"></stop>
|
||||
</lineargradient>
|
||||
</defs>
|
||||
<!-- Progress track (85%) -->
|
||||
<circle class="progress-ring-circle" cx="50" cy="50" fill="transparent" r="40" stroke="url(#ringGradient)" stroke-dasharray="251.2" stroke-dashoffset="37.68" stroke-linecap="round" stroke-width="8"></circle>
|
||||
</svg>
|
||||
<div class="absolute inset-0 flex items-center justify-center flex-col">
|
||||
<span class="font-h2 text-h2 text-primary font-bold">85%</span>
|
||||
<span class="font-label-caps text-label-caps text-on-surface-variant mt-1">优秀</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Next Review Suggestion -->
|
||||
<section class="glass-panel rounded-xl p-md flex flex-col justify-between gap-sm">
|
||||
<div class="flex items-center gap-xs">
|
||||
<span class="material-symbols-outlined text-primary" style="font-variation-settings: 'FILL' 0;">update</span>
|
||||
<h2 class="font-label-caps text-label-caps text-on-surface-variant uppercase tracking-widest">下一次复习建议</h2>
|
||||
</div>
|
||||
<div class="flex-grow flex items-center">
|
||||
<div>
|
||||
<p class="font-h2 text-h2 text-on-surface mb-xs font-bold">明天上午 10:00</p>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant">根据艾宾浩斯遗忘曲线,此时复习效果最佳。</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Strengths & Weaknesses -->
|
||||
<section class="glass-panel rounded-xl p-md w-full md:col-span-2 flex flex-col md:flex-row gap-lg">
|
||||
<!-- Strengths -->
|
||||
<div class="flex-1 flex flex-col gap-sm">
|
||||
<div class="flex items-center gap-xs">
|
||||
<div class="w-6 h-6 rounded-full bg-primary-fixed flex items-center justify-center">
|
||||
<span class="material-symbols-outlined text-primary text-[14px]" style="font-variation-settings: 'FILL' 1;">check</span>
|
||||
</div>
|
||||
<h3 class="font-h3 text-h3 text-on-surface text-[18px]">优势</h3>
|
||||
</div>
|
||||
<ul class="flex flex-col gap-xs pl-8">
|
||||
<li class="font-body-md text-body-md text-on-surface-variant flex items-center gap-xs">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-primary"></span>
|
||||
概念回忆清晰
|
||||
</li>
|
||||
<li class="font-body-md text-body-md text-on-surface-variant flex items-center gap-xs">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-primary"></span>
|
||||
架构逻辑准确
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Weaknesses -->
|
||||
<div class="flex-1 flex flex-col gap-sm">
|
||||
<div class="flex items-center gap-xs">
|
||||
<div class="w-6 h-6 rounded-full bg-error-container flex items-center justify-center">
|
||||
<span class="material-symbols-outlined text-error text-[14px]" style="font-variation-settings: 'FILL' 1;">priority_high</span>
|
||||
</div>
|
||||
<h3 class="font-h3 text-h3 text-on-surface text-[18px]">薄弱点</h3>
|
||||
</div>
|
||||
<ul class="flex flex-col gap-xs pl-8">
|
||||
<li class="font-body-md text-body-md text-on-surface-variant flex items-center gap-xs">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-error"></span>
|
||||
ReLU 与 Sigmoid 的差异理解
|
||||
</li>
|
||||
<li class="font-body-md text-body-md text-on-surface-variant flex items-center gap-xs">
|
||||
<span class="w-1.5 h-1.5 rounded-full bg-error"></span>
|
||||
反向传播推导细节
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Improvement Suggestions -->
|
||||
<section class="glass-panel rounded-xl p-md w-full md:col-span-2 flex flex-col gap-sm">
|
||||
<div class="flex items-center gap-xs mb-xs">
|
||||
<span class="material-symbols-outlined text-secondary" style="font-variation-settings: 'FILL' 0;">lightbulb</span>
|
||||
<h3 class="font-h3 text-h3 text-on-surface text-[18px]">改进建议</h3>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-sm">
|
||||
<div class="bg-surface rounded-lg p-sm border border-outline-variant flex items-start gap-sm">
|
||||
<span class="material-symbols-outlined text-primary mt-1" style="font-variation-settings: 'FILL' 0;">menu_book</span>
|
||||
<div>
|
||||
<p class="font-body-lg text-body-lg text-on-surface font-medium">重读章节 4.2 (间隔复习)</p>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant text-[13px] mt-1">深入理解激活函数的非线性特征,建议使用费曼技巧向自己解释。</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="bg-surface rounded-lg p-sm border border-outline-variant flex items-start gap-sm">
|
||||
<span class="material-symbols-outlined text-primary mt-1" style="font-variation-settings: 'FILL' 0;">quiz</span>
|
||||
<div>
|
||||
<p class="font-body-lg text-body-lg text-on-surface font-medium">尝试一次练习测验</p>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant text-[13px] mt-1">通过 5 道针对性题目巩固记忆。</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
<!-- Action Buttons Layout -->
|
||||
<div class="w-full flex flex-col gap-sm mt-lg">
|
||||
<button class="w-full py-4 px-6 rounded-full border border-primary text-primary font-body-lg font-bold shadow-sm active:scale-95 transition-transform duration-200 flex items-center justify-center gap-xs hover:bg-surface-container-highest bg-transparent">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 0;">forum</span>
|
||||
继续追问
|
||||
</button>
|
||||
<button class="w-full py-4 px-6 rounded-full ai-glow-bg text-white font-body-lg font-bold shadow-md active:scale-95 transition-transform duration-200 flex items-center justify-center gap-xs hover:opacity-90">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 0;">add_task</span>
|
||||
加入复习
|
||||
</button>
|
||||
</div>
|
||||
</main>
|
||||
<!-- Bottom Navigation -->
|
||||
<nav class="premium-tab-bar fixed bottom-0 w-full px-6 py-4 pb-8 z-50 flex justify-between items-center rounded-t-3xl">
|
||||
<div class="flex flex-col items-center gap-1 cursor-pointer text-on-surface-variant">
|
||||
<span class="material-symbols-outlined text-[28px]" style="font-variation-settings: 'FILL' 0;">auto_awesome</span>
|
||||
<span class="text-[10px] font-semibold">AI</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-1 cursor-pointer text-on-surface-variant">
|
||||
<span class="material-symbols-outlined text-[28px]" style="font-variation-settings: 'FILL' 0;">auto_stories</span>
|
||||
<span class="text-[10px] font-semibold">知识库</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-1 cursor-pointer text-primary">
|
||||
<div class="relative">
|
||||
<span class="material-symbols-outlined text-[28px]" style="font-variation-settings: 'FILL' 1;">school</span>
|
||||
<div class="absolute -top-1 -right-1 w-2.5 h-2.5 bg-error rounded-full border-2 border-white"></div>
|
||||
</div>
|
||||
<span class="text-[10px] font-semibold">学习</span>
|
||||
</div>
|
||||
<div class="flex flex-col items-center gap-1 cursor-pointer text-on-surface-variant">
|
||||
<span class="material-symbols-outlined text-[28px]" style="font-variation-settings: 'FILL' 0;">person</span>
|
||||
<span class="text-[10px] font-semibold">我的</span>
|
||||
</div>
|
||||
</nav>
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 215 KiB |
@ -1,145 +0,0 @@
|
||||
---
|
||||
name: Ethereal Intelligence
|
||||
colors:
|
||||
surface: '#f9f9fd'
|
||||
surface-dim: '#d9dade'
|
||||
surface-bright: '#f9f9fd'
|
||||
surface-container-lowest: '#ffffff'
|
||||
surface-container-low: '#f3f3f7'
|
||||
surface-container: '#ededf1'
|
||||
surface-container-high: '#e8e8ec'
|
||||
surface-container-highest: '#e2e2e6'
|
||||
on-surface: '#1a1c1f'
|
||||
on-surface-variant: '#414751'
|
||||
inverse-surface: '#2e3034'
|
||||
inverse-on-surface: '#f0f0f4'
|
||||
outline: '#717783'
|
||||
outline-variant: '#c1c7d3'
|
||||
surface-tint: '#0060ac'
|
||||
primary: '#005da7'
|
||||
on-primary: '#ffffff'
|
||||
primary-container: '#2976c7'
|
||||
on-primary-container: '#fdfcff'
|
||||
inverse-primary: '#a4c9ff'
|
||||
secondary: '#8135c5'
|
||||
on-secondary: '#ffffff'
|
||||
secondary-container: '#ba70ff'
|
||||
on-secondary-container: '#440076'
|
||||
tertiary: '#4648d4'
|
||||
on-tertiary: '#ffffff'
|
||||
tertiary-container: '#6063ee'
|
||||
on-tertiary-container: '#fffbff'
|
||||
error: '#ba1a1a'
|
||||
on-error: '#ffffff'
|
||||
error-container: '#ffdad6'
|
||||
on-error-container: '#93000a'
|
||||
primary-fixed: '#d4e3ff'
|
||||
primary-fixed-dim: '#a4c9ff'
|
||||
on-primary-fixed: '#001c39'
|
||||
on-primary-fixed-variant: '#004883'
|
||||
secondary-fixed: '#f0dbff'
|
||||
secondary-fixed-dim: '#deb7ff'
|
||||
on-secondary-fixed: '#2c0050'
|
||||
on-secondary-fixed-variant: '#670fac'
|
||||
tertiary-fixed: '#e1e0ff'
|
||||
tertiary-fixed-dim: '#c0c1ff'
|
||||
on-tertiary-fixed: '#07006c'
|
||||
on-tertiary-fixed-variant: '#2f2ebe'
|
||||
background: '#f9f9fd'
|
||||
on-background: '#1a1c1f'
|
||||
surface-variant: '#e2e2e6'
|
||||
typography:
|
||||
h1:
|
||||
fontFamily: Manrope
|
||||
fontSize: 34px
|
||||
fontWeight: '700'
|
||||
lineHeight: '1.2'
|
||||
letterSpacing: -0.02em
|
||||
h2:
|
||||
fontFamily: Manrope
|
||||
fontSize: 28px
|
||||
fontWeight: '600'
|
||||
lineHeight: '1.3'
|
||||
letterSpacing: -0.01em
|
||||
h3:
|
||||
fontFamily: Manrope
|
||||
fontSize: 22px
|
||||
fontWeight: '600'
|
||||
lineHeight: '1.3'
|
||||
letterSpacing: '0'
|
||||
body-lg:
|
||||
fontFamily: Manrope
|
||||
fontSize: 17px
|
||||
fontWeight: '400'
|
||||
lineHeight: '1.6'
|
||||
letterSpacing: -0.01em
|
||||
body-md:
|
||||
fontFamily: Manrope
|
||||
fontSize: 15px
|
||||
fontWeight: '400'
|
||||
lineHeight: '1.5'
|
||||
letterSpacing: '0'
|
||||
label-caps:
|
||||
fontFamily: Manrope
|
||||
fontSize: 12px
|
||||
fontWeight: '600'
|
||||
lineHeight: '1.0'
|
||||
letterSpacing: 0.05em
|
||||
rounded:
|
||||
sm: 0.25rem
|
||||
DEFAULT: 0.5rem
|
||||
md: 0.75rem
|
||||
lg: 1rem
|
||||
xl: 1.5rem
|
||||
full: 9999px
|
||||
spacing:
|
||||
base: 8px
|
||||
xs: 4px
|
||||
sm: 12px
|
||||
md: 24px
|
||||
lg: 40px
|
||||
xl: 64px
|
||||
container-margin: 20px
|
||||
gutter: 16px
|
||||
---
|
||||
|
||||
## Brand & Style
|
||||
The brand personality is centered on "Enlightened Learning"—a synthesis of high-tech AI capabilities and human-centric intuition. This design system targets a young, intellectually curious demographic that values depth over speed.
|
||||
|
||||
The visual style merges **Apple Minimalism** with **Futuristic Glassmorphism**. It prioritizes extreme "breathability" and a sense of calm focus. The UI should feel like a quiet, high-tech sanctuary for thought. Key attributes include high-blur translucency, expansive negative space, and a "light-as-air" depth model that avoids heavy physical metaphors in favor of ethereal, glowing digital surfaces.
|
||||
|
||||
## Colors
|
||||
The palette is anchored by a luminous off-white background to reduce eye strain and establish a premium feel. The primary and secondary colors are used sparingly for interactive elements and brand accents.
|
||||
|
||||
To represent the "AI-first" nature of the product, use a signature gradient (the "AI Glow") for progress indicators, active states, and special AI-driven insights. Functional neutrals follow Apple’s grayscale hierarchy but use a slight blue tint in the shadows to maintain the cool, sophisticated atmosphere.
|
||||
|
||||
## Typography
|
||||
Manrope provides a modern, geometric clarity that feels more "tech-forward" than standard San Francisco while maintaining excellent legibility.
|
||||
|
||||
The typographic hierarchy emphasizes whitespace through generous line heights (1.5x - 1.6x for body text). Headlines use slightly tighter tracking to feel "locked" and authoritative, while labels use expanded tracking for a premium, airy feel. Use "Ink-Black" (#1D1D1F) for primary text to ensure high contrast without the harshness of pure black.
|
||||
|
||||
## Layout & Spacing
|
||||
The layout follows a fluid, safe-area-driven model typical of iOS, but with significantly increased vertical margins to promote the "calm" atmosphere.
|
||||
|
||||
A 4-column grid is used for mobile portrait views. Elements should never feel "packed." Use the `lg` (40px) and `xl` (64px) spacing units to separate major content sections, creating a sense of luxury and focus. Component internal padding should be generous, typically starting at `md` (24px) for cards and containers.
|
||||
|
||||
## Elevation & Depth
|
||||
This design system utilizes **Luminous Stratification** rather than traditional heavy shadows.
|
||||
|
||||
- **The Base:** The #FBFBFF background acts as the canvas.
|
||||
- **Glassmorphism:** AI-interaction zones and input fields use a high-saturation backdrop blur (20px-30px) with a 1px semi-transparent white border (0.1 opacity) to simulate frosted glass.
|
||||
- **Gentle Shadows:** Floating cards use "Ambient Shadows"—extremely diffused (40px-60px blur), low-opacity (5%) shadows with a subtle tint of the primary blue to prevent a "dirty" look.
|
||||
- **AI Glow:** The highest level of depth is reserved for active AI processes, which emit a soft, localized outer glow using the signature gradient.
|
||||
|
||||
## Shapes
|
||||
Shapes follow a "Squircle" logic to align with Apple’s hardware and software aesthetic.
|
||||
|
||||
Standard components (buttons, small cards) use a 16px (1rem) radius. Larger container cards use a 24px (1.5rem) radius. Interactive inputs use a fully rounded "pill" shape or the 16px standard to maintain consistency. The goal is to avoid sharp corners entirely, reinforcing the "human-centric" and "soft" brand personality.
|
||||
|
||||
## Components
|
||||
- **Buttons:** Primary buttons use the AI Glow gradient with white text. Secondary buttons are glass-morphic with a 1px border. All buttons have a high-press scale effect (shrink to 0.96) for tactile feedback.
|
||||
- **Input Fields:** These are the centerpiece of the "AI-first" experience. Use a high-blur glass background with a subtle inner shadow. Place the cursor/caret in the primary blue.
|
||||
- **Cards:** Content is housed in "Floating Containers"—white or ultra-light gray backgrounds with the previously defined ambient shadows and no visible border.
|
||||
- **Thin-Stroke Icons:** Use a consistent 1.5pt or 2pt stroke weight. Icons should be open-ended and minimalist, avoiding fills unless in an active state.
|
||||
- **AI Learning Progress:** Use a custom "Liquid Trace" component—a thin, glowing gradient line that pulses gently as the user moves through deep-learning modules.
|
||||
- **Chips/Tags:** Small, pill-shaped elements with light blue or violet tinted backgrounds (0.1 opacity) and matching colored text.
|
||||
@ -1,275 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="light" lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>知习 - 知识库</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
"colors": {
|
||||
"on-surface-variant": "#414751",
|
||||
"surface-container-lowest": "#ffffff",
|
||||
"error-container": "#ffdad6",
|
||||
"on-tertiary": "#ffffff",
|
||||
"primary-container": "#2976c7",
|
||||
"on-surface": "#1a1c1f",
|
||||
"on-error-container": "#93000a",
|
||||
"secondary-fixed": "#f0dbff",
|
||||
"surface-container-high": "#e8e8ec",
|
||||
"primary": "#005da7",
|
||||
"on-secondary": "#ffffff",
|
||||
"on-error": "#ffffff",
|
||||
"on-primary-fixed-variant": "#004883",
|
||||
"outline": "#717783",
|
||||
"on-secondary-fixed-variant": "#670fac",
|
||||
"surface-container-highest": "#e2e2e6",
|
||||
"on-tertiary-fixed-variant": "#2f2ebe",
|
||||
"secondary-fixed-dim": "#deb7ff",
|
||||
"surface-variant": "#e2e2e6",
|
||||
"outline-variant": "#c1c7d3",
|
||||
"inverse-on-surface": "#f0f0f4",
|
||||
"surface-container": "#ededf1",
|
||||
"surface-dim": "#d9dade",
|
||||
"tertiary-fixed": "#e1e0ff",
|
||||
"surface-bright": "#f9f9fd",
|
||||
"tertiary": "#4648d4",
|
||||
"surface": "#f9f9fd",
|
||||
"on-tertiary-container": "#fffbff",
|
||||
"on-secondary-fixed": "#2c0050",
|
||||
"primary-fixed": "#d4e3ff",
|
||||
"on-primary-container": "#fdfcff",
|
||||
"inverse-surface": "#2e3034",
|
||||
"on-primary-fixed": "#001c39",
|
||||
"primary-fixed-dim": "#a4c9ff",
|
||||
"on-tertiary-fixed": "#07006c",
|
||||
"surface-tint": "#0060ac",
|
||||
"secondary-container": "#ba70ff",
|
||||
"tertiary-container": "#6063ee",
|
||||
"error": "#ba1a1a",
|
||||
"tertiary-fixed-dim": "#c0c1ff",
|
||||
"background": "#f9f9fd",
|
||||
"on-background": "#1a1c1f",
|
||||
"on-secondary-container": "#440076",
|
||||
"inverse-primary": "#a4c9ff",
|
||||
"surface-container-low": "#f3f3f7",
|
||||
"on-primary": "#ffffff",
|
||||
"secondary": "#8135c5"
|
||||
},
|
||||
"borderRadius": {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
"spacing": {
|
||||
"sm": "12px",
|
||||
"xs": "4px",
|
||||
"xl": "64px",
|
||||
"base": "8px",
|
||||
"lg": "40px",
|
||||
"gutter": "16px",
|
||||
"md": "24px",
|
||||
"container-margin": "20px"
|
||||
},
|
||||
"fontFamily": {
|
||||
"h3": ["Manrope"],
|
||||
"label-caps": ["Manrope"],
|
||||
"body-md": ["Manrope"],
|
||||
"body-lg": ["Manrope"],
|
||||
"h2": ["Manrope"],
|
||||
"h1": ["Manrope"]
|
||||
},
|
||||
"fontSize": {
|
||||
"h3": ["22px", {"lineHeight": "1.3", "letterSpacing": "0", "fontWeight": "600"}],
|
||||
"label-caps": ["12px", {"lineHeight": "1.0", "letterSpacing": "0.05em", "fontWeight": "600"}],
|
||||
"body-md": ["15px", {"lineHeight": "1.5", "letterSpacing": "0", "fontWeight": "400"}],
|
||||
"body-lg": ["17px", {"lineHeight": "1.6", "letterSpacing": "-0.01em", "fontWeight": "400"}],
|
||||
"h2": ["28px", {"lineHeight": "1.3", "letterSpacing": "-0.01em", "fontWeight": "600"}],
|
||||
"h1": ["34px", {"lineHeight": "1.2", "letterSpacing": "-0.02em", "fontWeight": "700"}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
background-color: #f9f9fd;
|
||||
background-image:
|
||||
radial-gradient(circle at 10% 0%, rgba(212, 227, 255, 0.4) 0%, transparent 50%),
|
||||
radial-gradient(circle at 90% 20%, rgba(240, 219, 255, 0.4) 0%, transparent 50%);
|
||||
background-attachment: fixed;
|
||||
}
|
||||
.glass-panel {
|
||||
background: rgba(255, 255, 255, 0.6);
|
||||
backdrop-filter: blur(24px);
|
||||
-webkit-backdrop-filter: blur(24px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||
}
|
||||
.ambient-shadow {
|
||||
box-shadow: 0 20px 40px rgba(0, 93, 167, 0.05);
|
||||
}
|
||||
.ai-glow {
|
||||
box-shadow: 0 0 20px rgba(0, 93, 167, 0.2);
|
||||
}
|
||||
.liquid-trace {
|
||||
background: linear-gradient(180deg, #a4c9ff 0%, #005da7 50%, #f3f3f7 100%);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="text-on-background font-body-md antialiased pb-24 selection:bg-primary-container selection:text-on-primary-container">
|
||||
<!-- TopAppBar -->
|
||||
<header class="bg-white/70 dark:bg-slate-900/70 backdrop-blur-xl docked full-width top-0 sticky border-b border-white/10 shadow-[0_8px_32px_0_rgba(74,144,226,0.05)] z-40">
|
||||
<div class="flex justify-between items-center w-full px-6 py-4">
|
||||
<div class="flex items-center gap-3">
|
||||
<img alt="User profile avatar" class="w-10 h-10 rounded-full object-cover border border-outline-variant/30" data-alt="A clean, modern headshot of an individual used as a digital profile avatar. The portrait should be warmly lit against a minimal, soft background, embodying a friendly and professional digital presence suitable for a high-tech application. The aesthetic should be clean, approachable, and high-resolution." src="https://lh3.googleusercontent.com/aida-public/AB6AXuCE677kHSGjU2L-VHPtfs3Ww2mO5xxYtBs0TMFQPzuR0xAE4OQdDOR07COZAlc3jpQ1ZU4BsitmVXwN9_ytDnrQqxU7xWKVRd2Q0jD0fR8eN82t2l4ZcYRX-0QRbUuxrm87NM7Qp9r1CZsvM1fsCs1T7pNw8l68Ev2FzcYIqPmaNAwoe7vleEkNwM8l5q0bpNkwR_vowqDOUFfte0X6g4up7nfIgpTx8UgLYN_sOzT2hdsBVZ_D7JzHti8l3KbP3usPTXodT7xZ"/>
|
||||
</div>
|
||||
<h1 class="font-manrope font-bold text-lg tracking-tight text-blue-600 dark:text-blue-400">知习</h1>
|
||||
<button class="text-slate-400 hover:opacity-80 transition-opacity active:scale-95 transition-transform duration-200">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 0, 'wght' 300;">notifications</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<main class="px-container-margin pt-md flex flex-col gap-lg max-w-2xl mx-auto">
|
||||
<!-- Header & Search Section -->
|
||||
<section class="flex flex-col gap-md">
|
||||
<div>
|
||||
<h2 class="font-h2 text-h2 text-on-surface mb-xs">知识库</h2>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant">探索您的学习路径与认知架构</p>
|
||||
</div>
|
||||
<!-- Search Bar -->
|
||||
<div class="relative glass-panel rounded-full flex items-center px-4 py-3 ambient-shadow">
|
||||
<span class="material-symbols-outlined text-outline mr-3" style="font-variation-settings: 'wght' 300;">search</span>
|
||||
<input class="bg-transparent border-none focus:ring-0 text-on-surface w-full font-body-md placeholder:text-outline-variant" placeholder="搜索概念、课程或笔记..." type="text"/>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Current Knowledge Base Card (Bento Style) -->
|
||||
<section>
|
||||
<div class="glass-panel rounded-[32px] p-md ambient-shadow relative overflow-hidden group">
|
||||
<!-- Decorative Glow -->
|
||||
<div class="absolute -top-20 -right-20 w-64 h-64 bg-primary-fixed-dim/30 rounded-full blur-[60px] pointer-events-none"></div>
|
||||
<div class="flex justify-between items-start relative z-10">
|
||||
<div class="flex flex-col gap-2">
|
||||
<span class="inline-flex items-center px-3 py-1 rounded-full bg-primary-fixed/50 text-on-primary-fixed-variant font-label-caps text-label-caps w-fit">当前焦点</span>
|
||||
<h3 class="font-h1 text-h1 text-on-surface tracking-tight mt-1">认知心理学</h3>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant max-w-[80%]">深入理解人类心智的信息处理机制,掌握高效学习的底层逻辑。</p>
|
||||
</div>
|
||||
<div class="w-16 h-16 rounded-2xl bg-surface-container-highest flex items-center justify-center shrink-0">
|
||||
<span class="material-symbols-outlined text-primary text-3xl" style="font-variation-settings: 'wght' 300;">psychology</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-8 flex items-center gap-4 relative z-10">
|
||||
<div class="flex-1 h-1.5 bg-surface-variant rounded-full overflow-hidden">
|
||||
<div class="h-full bg-primary w-[35%] rounded-full relative">
|
||||
<div class="absolute right-0 top-0 h-full w-4 bg-white/50 blur-[2px]"></div>
|
||||
</div>
|
||||
</div>
|
||||
<span class="font-label-caps text-label-caps text-on-surface-variant">35% 完成</span>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Learning Journey Path -->
|
||||
<section class="pl-4 pb-12">
|
||||
<h3 class="font-h3 text-h3 text-on-surface mb-8">学习旅程</h3>
|
||||
<div class="relative">
|
||||
<!-- The Liquid Trace Line -->
|
||||
<div class="absolute left-[27px] top-4 bottom-0 w-1 rounded-full liquid-trace opacity-50"></div>
|
||||
<div class="flex flex-col gap-xl">
|
||||
<!-- Completed Node -->
|
||||
<div class="flex items-start gap-md group">
|
||||
<div class="relative z-10 flex flex-col items-center shrink-0 w-14">
|
||||
<div class="w-14 h-14 rounded-full bg-surface-container-highest flex items-center justify-center border-4 border-surface-bright transition-transform group-hover:scale-105">
|
||||
<span class="material-symbols-outlined text-primary" style="font-variation-settings: 'FILL' 1, 'wght' 400;">check_circle</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-3 flex-1">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="font-label-caps text-label-caps text-outline block">第 1 天</span>
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded-full bg-surface-variant text-on-surface-variant font-label-caps text-[10px]">主动回忆</span>
|
||||
</div>
|
||||
<h4 class="font-h3 text-h3 text-on-surface-variant">认知基础:感知与模式识别</h4>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Active Node -->
|
||||
<div class="flex items-start gap-md group">
|
||||
<div class="relative z-10 flex flex-col items-center shrink-0 w-14">
|
||||
<!-- Pulse effect -->
|
||||
<div class="absolute inset-0 bg-primary-fixed rounded-full animate-ping opacity-20"></div>
|
||||
<div class="w-14 h-14 rounded-full bg-primary flex items-center justify-center border-4 border-surface-bright ai-glow shadow-lg relative z-10">
|
||||
<span class="material-symbols-outlined text-on-primary" style="font-variation-settings: 'FILL' 1, 'wght' 300;">target</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-1 flex-1">
|
||||
<div class="glass-panel p-4 rounded-2xl ambient-shadow border border-primary-fixed">
|
||||
<div class="flex items-center gap-2 mb-1">
|
||||
<span class="font-label-caps text-label-caps text-primary block">第 2 天 • 当前</span>
|
||||
<span class="inline-flex items-center px-2 py-0.5 rounded-full bg-primary-fixed/50 text-on-primary-fixed-variant font-label-caps text-[10px]">检索练习</span>
|
||||
</div>
|
||||
<h4 class="font-h3 text-h3 text-on-surface mb-2">注意力机制:焦点与过滤</h4>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant mb-4 text-sm">探讨选择性注意和分配性注意,理解多任务处理的神话与现实。</p>
|
||||
<button class="w-full py-3 rounded-xl bg-gradient-to-r from-primary to-primary-container text-white font-body-md font-medium flex items-center justify-center gap-2 hover:opacity-90 active:scale-[0.98] transition-all">
|
||||
<span class="material-symbols-outlined text-sm" style="font-variation-settings: 'wght' 300;">play_arrow</span>
|
||||
继续学习
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Future Node 1 -->
|
||||
<div class="flex items-start gap-md group opacity-60">
|
||||
<div class="relative z-10 flex flex-col items-center shrink-0 w-14">
|
||||
<div class="w-12 h-12 rounded-full bg-surface-container flex items-center justify-center border-4 border-surface-bright mt-1">
|
||||
<span class="material-symbols-outlined text-outline-variant" style="font-variation-settings: 'wght' 300;">lock</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-3 flex-1">
|
||||
<span class="font-label-caps text-label-caps text-outline-variant mb-1 block">第 3 天</span>
|
||||
<h4 class="font-h3 text-h3 text-outline">记忆模型:工作与长期记忆</h4>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Future Node 2 -->
|
||||
<div class="flex items-start gap-md group opacity-40">
|
||||
<div class="relative z-10 flex flex-col items-center shrink-0 w-14">
|
||||
<div class="w-10 h-10 rounded-full bg-surface-container-low flex items-center justify-center border-4 border-surface-bright mt-2">
|
||||
<div class="w-2 h-2 rounded-full bg-outline-variant"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-3 flex-1">
|
||||
<span class="font-label-caps text-label-caps text-outline-variant mb-1 block">第 4 天</span>
|
||||
<h4 class="font-h3 text-h3 text-outline">知识表征:心智模型</h4>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<!-- BottomNavBar -->
|
||||
<nav class="bg-white/80 dark:bg-slate-950/80 backdrop-blur-2xl docked full-width bottom-0 fixed rounded-t-[32px] border-t border-white/20 shadow-[0_-10px_40px_rgba(74,144,226,0.1)] fixed bottom-0 left-0 w-full z-50 flex justify-around items-center px-4 pb-8 pt-4">
|
||||
<a class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 px-4 py-2 hover:text-blue-500 transition-colors active:scale-90 transition-all duration-300 ease-out" href="#">
|
||||
<span class="material-symbols-outlined mb-1" style="font-variation-settings: 'wght' 300;">school</span>
|
||||
<span class="font-manrope text-[11px] font-medium tracking-wide">学习</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center justify-center text-blue-600 dark:text-blue-400 bg-blue-50/50 dark:bg-blue-900/20 rounded-2xl px-4 py-2 hover:text-blue-500 transition-colors active:scale-90 transition-all duration-300 ease-out" href="#">
|
||||
<span class="material-symbols-outlined mb-1" style="font-variation-settings: 'FILL' 1, 'wght' 400;">database</span>
|
||||
<span class="font-manrope text-[11px] font-medium tracking-wide">知识库</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 px-4 py-2 hover:text-blue-500 transition-colors active:scale-90 transition-all duration-300 ease-out" href="#">
|
||||
<span class="material-symbols-outlined mb-1" style="font-variation-settings: 'wght' 300;">smart_toy</span>
|
||||
<span class="font-manrope text-[11px] font-medium tracking-wide">AI 助手</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 px-4 py-2 hover:text-blue-500 transition-colors active:scale-90 transition-all duration-300 ease-out" href="#">
|
||||
<span class="material-symbols-outlined mb-1" style="font-variation-settings: 'wght' 300;">person</span>
|
||||
<span class="font-manrope text-[11px] font-medium tracking-wide">我的</span>
|
||||
</a>
|
||||
</nav>
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 265 KiB |
@ -1,322 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>ZhiXi - 学习</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
"colors": {
|
||||
"on-secondary-fixed": "#2c0050",
|
||||
"background": "#f9f9fd",
|
||||
"secondary-fixed": "#f0dbff",
|
||||
"on-secondary": "#ffffff",
|
||||
"tertiary-fixed": "#e1e0ff",
|
||||
"error-container": "#ffdad6",
|
||||
"inverse-surface": "#2e3034",
|
||||
"tertiary-fixed-dim": "#c0c1ff",
|
||||
"on-primary-fixed": "#001c39",
|
||||
"surface-bright": "#f9f9fd",
|
||||
"on-secondary-container": "#440076",
|
||||
"tertiary": "#4648d4",
|
||||
"primary-fixed-dim": "#a4c9ff",
|
||||
"outline": "#717783",
|
||||
"on-tertiary-fixed-variant": "#2f2ebe",
|
||||
"on-tertiary-container": "#fffbff",
|
||||
"primary": "#005da7",
|
||||
"secondary-fixed-dim": "#deb7ff",
|
||||
"on-primary-fixed-variant": "#004883",
|
||||
"inverse-on-surface": "#f0f0f4",
|
||||
"error": "#ba1a1a",
|
||||
"on-primary-container": "#fdfcff",
|
||||
"on-primary": "#ffffff",
|
||||
"surface-container-low": "#f3f3f7",
|
||||
"surface-container-highest": "#e2e2e6",
|
||||
"on-tertiary-fixed": "#07006c",
|
||||
"surface-dim": "#d9dade",
|
||||
"inverse-primary": "#a4c9ff",
|
||||
"surface-variant": "#e2e2e6",
|
||||
"surface-container-lowest": "#ffffff",
|
||||
"surface-tint": "#0060ac",
|
||||
"primary-container": "#2976c7",
|
||||
"surface": "#f9f9fd",
|
||||
"on-surface-variant": "#414751",
|
||||
"on-background": "#1a1c1f",
|
||||
"surface-container-high": "#e8e8ec",
|
||||
"on-error-container": "#93000a",
|
||||
"secondary": "#8135c5",
|
||||
"on-secondary-fixed-variant": "#670fac",
|
||||
"outline-variant": "#c1c7d3",
|
||||
"on-tertiary": "#ffffff",
|
||||
"on-surface": "#1a1c1f",
|
||||
"on-error": "#ffffff",
|
||||
"secondary-container": "#ba70ff",
|
||||
"primary-fixed": "#d4e3ff",
|
||||
"tertiary-container": "#6063ee",
|
||||
"surface-container": "#ededf1"
|
||||
},
|
||||
"borderRadius": {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
"spacing": {
|
||||
"xl": "64px",
|
||||
"md": "24px",
|
||||
"container-margin": "20px",
|
||||
"base": "8px",
|
||||
"sm": "12px",
|
||||
"lg": "40px",
|
||||
"xs": "4px",
|
||||
"gutter": "16px"
|
||||
},
|
||||
"fontFamily": {
|
||||
"h3": [
|
||||
"Manrope"
|
||||
],
|
||||
"h2": [
|
||||
"Manrope"
|
||||
],
|
||||
"label-caps": [
|
||||
"Manrope"
|
||||
],
|
||||
"body-md": [
|
||||
"Manrope"
|
||||
],
|
||||
"body-lg": [
|
||||
"Manrope"
|
||||
],
|
||||
"h1": [
|
||||
"Manrope"
|
||||
]
|
||||
},
|
||||
"fontSize": {
|
||||
"h3": [
|
||||
"22px",
|
||||
{
|
||||
"lineHeight": "1.3",
|
||||
"letterSpacing": "0",
|
||||
"fontWeight": "600"
|
||||
}
|
||||
],
|
||||
"h2": [
|
||||
"28px",
|
||||
{
|
||||
"lineHeight": "1.3",
|
||||
"letterSpacing": "-0.01em",
|
||||
"fontWeight": "600"
|
||||
}
|
||||
],
|
||||
"label-caps": [
|
||||
"12px",
|
||||
{
|
||||
"lineHeight": "1.0",
|
||||
"letterSpacing": "0.05em",
|
||||
"fontWeight": "600"
|
||||
}
|
||||
],
|
||||
"body-md": [
|
||||
"15px",
|
||||
{
|
||||
"lineHeight": "1.5",
|
||||
"letterSpacing": "0",
|
||||
"fontWeight": "400"
|
||||
}
|
||||
],
|
||||
"body-lg": [
|
||||
"17px",
|
||||
{
|
||||
"lineHeight": "1.6",
|
||||
"letterSpacing": "-0.01em",
|
||||
"fontWeight": "400"
|
||||
}
|
||||
],
|
||||
"h1": [
|
||||
"34px",
|
||||
{
|
||||
"lineHeight": "1.2",
|
||||
"letterSpacing": "-0.02em",
|
||||
"fontWeight": "700"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
background-color: #f9f9fd;
|
||||
background-image: radial-gradient(at 0% 0%, hsla(242,100%,92%,1) 0, transparent 50%), radial-gradient(at 100% 0%, hsla(212,100%,92%,1) 0, transparent 50%);
|
||||
background-attachment: fixed;
|
||||
}
|
||||
.glass-card {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
backdrop-filter: blur(24px);
|
||||
-webkit-backdrop-filter: blur(24px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||
box-shadow: 0 8px 32px 0 rgba(0, 93, 167, 0.05);
|
||||
}
|
||||
.ai-glow-btn {
|
||||
background: linear-gradient(135deg, #005da7, #4648d4);
|
||||
box-shadow: 0 4px 15px rgba(70, 72, 212, 0.3);
|
||||
transition: transform 0.15s ease-in-out;
|
||||
}
|
||||
.ai-glow-btn:active {
|
||||
transform: scale(0.96);
|
||||
}
|
||||
.liquid-trace {
|
||||
background: linear-gradient(90deg, #a4c9ff, #6063ee, #a4c9ff);
|
||||
background-size: 200% auto;
|
||||
animation: pulse-glow 3s infinite linear;
|
||||
}
|
||||
@keyframes pulse-glow {
|
||||
0% { background-position: 0% center; }
|
||||
100% { background-position: 200% center; }
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="text-on-surface pb-[100px] min-h-screen">
|
||||
<!-- TopAppBar -->
|
||||
<header class="bg-white/80 dark:bg-slate-900/80 backdrop-blur-xl docked full-width top-0 sticky border-b border-slate-200/50 dark:border-slate-800/50 shadow-sm dark:shadow-none flex justify-between items-center w-full px-5 py-3 z-40">
|
||||
<div class="flex items-center gap-3">
|
||||
<button class="text-slate-900 dark:text-slate-50 hover:opacity-80 transition-opacity p-2 -ml-2 rounded-full hover:bg-surface-container">
|
||||
<span class="material-symbols-outlined text-[20px]">arrow_back_ios_new</span>
|
||||
</button>
|
||||
<h1 class="font-['Manrope'] font-bold text-xl text-slate-900 dark:text-slate-50">知习</h1>
|
||||
</div>
|
||||
<button class="text-blue-500 dark:text-blue-400 hover:opacity-80 transition-opacity p-2 rounded-full hover:bg-surface-container">
|
||||
<span class="material-symbols-outlined text-[24px]">settings</span>
|
||||
</button>
|
||||
</header>
|
||||
<main class="max-w-4xl mx-auto px-container-margin pt-md pb-xl">
|
||||
<!-- Page Header -->
|
||||
<div class="mb-lg">
|
||||
<h2 class="font-h1 text-h1 text-on-surface mb-xs">学习</h2>
|
||||
<p class="font-body-lg text-body-lg text-outline">让每一次学习都进入闭环</p>
|
||||
</div>
|
||||
<!-- Learning Loop Visual -->
|
||||
<div class="mb-lg flex items-center justify-center gap-2 text-primary font-label-caps text-label-caps bg-primary-fixed/30 py-3 px-4 rounded-full w-fit mx-auto glass-card">
|
||||
<span class="flex items-center gap-1"><span class="material-symbols-outlined text-[16px]">input</span> 输入</span>
|
||||
<span class="material-symbols-outlined text-[14px] text-outline-variant">arrow_forward</span>
|
||||
<span class="flex items-center gap-1"><span class="material-symbols-outlined text-[16px]">output</span> 输出</span>
|
||||
<span class="material-symbols-outlined text-[14px] text-outline-variant">arrow_forward</span>
|
||||
<span class="flex items-center gap-1"><span class="material-symbols-outlined text-[16px]">feedback</span> 反馈</span>
|
||||
<span class="material-symbols-outlined text-[14px] text-outline-variant">arrow_forward</span>
|
||||
<span class="flex items-center gap-1"><span class="material-symbols-outlined text-[16px]">cycle</span> 复习</span>
|
||||
</div>
|
||||
<!-- Bento Grid Layout -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-md">
|
||||
<!-- Today's Study Card (Spans full width on mobile, 1 col on md) -->
|
||||
<div class="glass-card rounded-xl p-md flex flex-col justify-between md:col-span-2 relative overflow-hidden">
|
||||
<div class="absolute top-0 left-0 w-full h-[2px] liquid-trace"></div>
|
||||
<div>
|
||||
<div class="flex justify-between items-start mb-sm">
|
||||
<span class="bg-secondary-container/20 text-secondary px-3 py-1 rounded-full font-label-caps text-label-caps">今日重点</span>
|
||||
<span class="flex items-center gap-1 font-body-md text-body-md text-outline">
|
||||
<span class="material-symbols-outlined text-[18px]">timer</span> 20 mins
|
||||
</span>
|
||||
</div>
|
||||
<h3 class="font-h2 text-h2 text-on-surface mb-xs">认知心理学:记忆的编码与提取</h3>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant mb-md">进入知识内化的关键阶段,建议通过主动回忆来加强神经连接。</p>
|
||||
</div>
|
||||
<div class="flex justify-end mt-sm">
|
||||
<button class="ai-glow-btn text-on-primary font-body-md text-body-md font-medium px-6 py-3 rounded-full flex items-center gap-2 w-full md:w-auto justify-center">
|
||||
<span class="material-symbols-outlined" data-weight="fill" style="font-variation-settings: 'FILL' 1;">play_arrow</span>
|
||||
开始主动回忆
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Active Recall Module -->
|
||||
<div class="glass-card rounded-xl p-md flex flex-col justify-center text-center items-center">
|
||||
<div class="w-12 h-12 rounded-full bg-tertiary-container/10 flex items-center justify-center mb-sm">
|
||||
<span class="material-symbols-outlined text-[28px] text-tertiary">psychiatry</span>
|
||||
</div>
|
||||
<h3 class="font-h3 text-h3 text-on-surface mb-xs">先试着用自己的话说出来</h3>
|
||||
<p class="font-body-md text-body-md text-outline mb-md">不要急着看答案,先回忆一次</p>
|
||||
<button class="bg-white border border-outline-variant text-on-surface font-body-md text-body-md font-medium px-5 py-2 rounded-full hover:bg-surface-container transition-colors w-full">
|
||||
快速自我测试
|
||||
</button>
|
||||
</div>
|
||||
<!-- Weak Point Consolidation -->
|
||||
<div class="glass-card rounded-xl p-md flex flex-col">
|
||||
<h3 class="font-h3 text-h3 text-on-surface mb-sm flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-error">target</span> 需要再巩固的地方
|
||||
</h3>
|
||||
<ul class="space-y-sm flex-1">
|
||||
<li class="flex items-start gap-3 p-3 bg-surface-container-lowest/50 rounded-lg border border-outline-variant/30">
|
||||
<span class="material-symbols-outlined text-[20px] text-primary mt-0.5">smart_toy</span>
|
||||
<div>
|
||||
<p class="font-body-md text-body-md font-medium text-on-surface">ReLU vs Sigmoid difference</p>
|
||||
<p class="font-body-md text-body-md text-outline text-[13px] mt-1">AI 诊断:在上次测验中概念混淆</p>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Today's Review Module (Spans full width) -->
|
||||
<div class="glass-card rounded-xl p-md md:col-span-2">
|
||||
<h3 class="font-h3 text-h3 text-on-surface mb-md flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-secondary">history_edu</span> 今天适合复习
|
||||
</h3>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 gap-sm">
|
||||
<!-- Review Item 1 -->
|
||||
<div class="p-4 bg-surface-container-lowest/60 rounded-lg border border-outline-variant/50 flex justify-between items-center">
|
||||
<div>
|
||||
<h4 class="font-body-lg text-body-lg font-medium text-on-surface">微观经济学基础</h4>
|
||||
<div class="flex items-center gap-1 mt-1 text-error font-body-md text-body-md text-[13px]">
|
||||
<span class="material-symbols-outlined text-[14px]">trending_down</span> 记忆曲线衰减预警
|
||||
</div>
|
||||
</div>
|
||||
<button class="bg-primary-container text-on-primary-container font-body-md text-body-md px-4 py-2 rounded-full hover:opacity-90 transition-opacity">
|
||||
复习
|
||||
</button>
|
||||
</div>
|
||||
<!-- Review Item 2 -->
|
||||
<div class="p-4 bg-surface-container-lowest/60 rounded-lg border border-outline-variant/50 flex justify-between items-center">
|
||||
<div>
|
||||
<h4 class="font-body-lg text-body-lg font-medium text-on-surface">线性代数核心定理</h4>
|
||||
<div class="flex items-center gap-1 mt-1 text-outline font-body-md text-body-md text-[13px]">
|
||||
<span class="material-symbols-outlined text-[14px]">schedule</span> 距上次复习 3 天
|
||||
</div>
|
||||
</div>
|
||||
<button class="bg-primary-container text-on-primary-container font-body-md text-body-md px-4 py-2 rounded-full hover:opacity-90 transition-opacity">
|
||||
复习
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- BottomNavBar -->
|
||||
<nav class="bg-white/80 dark:bg-slate-900/80 backdrop-blur-2xl fixed bottom-0 w-full z-50 rounded-t-none border-t border-slate-200/50 dark:border-slate-800/50 shadow-[0_-4px_24px_rgba(0,0,0,0.04)] fixed bottom-0 left-0 w-full flex justify-around items-center px-4 pt-2 pb-safe-offset-2 pb-4 md:hidden">
|
||||
<a class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 hover:bg-slate-50/50 dark:hover:bg-slate-800/50 p-2 rounded-lg transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px] mb-1" data-icon="menu_book">menu_book</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">学习</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 hover:bg-slate-50/50 dark:hover:bg-slate-800/50 p-2 rounded-lg transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px] mb-1" data-icon="database">database</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">知识库</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center justify-center text-blue-500 dark:text-blue-400 font-bold hover:bg-slate-50/50 dark:hover:bg-slate-800/50 p-2 rounded-lg transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px] mb-1" data-icon="auto_awesome" data-weight="fill" style="font-variation-settings: 'FILL' 1;">auto_awesome</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">AI 助手</span>
|
||||
</a>
|
||||
<a class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 hover:bg-slate-50/50 dark:hover:bg-slate-800/50 p-2 rounded-lg transition-colors" href="#">
|
||||
<span class="material-symbols-outlined text-[24px] mb-1" data-icon="person">person</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">我的</span>
|
||||
</a>
|
||||
</nav>
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 230 KiB |
@ -1,239 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover" name="viewport"/>
|
||||
<title>知习 - 认知心理学 · 记忆</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
"colors": {
|
||||
"on-secondary-fixed": "#2c0050",
|
||||
"background": "#f9f9fd",
|
||||
"secondary-fixed": "#f0dbff",
|
||||
"on-secondary": "#ffffff",
|
||||
"tertiary-fixed": "#e1e0ff",
|
||||
"error-container": "#ffdad6",
|
||||
"inverse-surface": "#2e3034",
|
||||
"tertiary-fixed-dim": "#c0c1ff",
|
||||
"on-primary-fixed": "#001c39",
|
||||
"surface-bright": "#f9f9fd",
|
||||
"on-secondary-container": "#440076",
|
||||
"tertiary": "#4648d4",
|
||||
"primary-fixed-dim": "#a4c9ff",
|
||||
"outline": "#717783",
|
||||
"on-tertiary-fixed-variant": "#2f2ebe",
|
||||
"on-tertiary-container": "#fffbff",
|
||||
"primary": "#005da7",
|
||||
"secondary-fixed-dim": "#deb7ff",
|
||||
"on-primary-fixed-variant": "#004883",
|
||||
"inverse-on-surface": "#f0f0f4",
|
||||
"error": "#ba1a1a",
|
||||
"on-primary-container": "#fdfcff",
|
||||
"on-primary": "#ffffff",
|
||||
"surface-container-low": "#f3f3f7",
|
||||
"surface-container-highest": "#e2e2e6",
|
||||
"on-tertiary-fixed": "#07006c",
|
||||
"surface-dim": "#d9dade",
|
||||
"inverse-primary": "#a4c9ff",
|
||||
"surface-variant": "#e2e2e6",
|
||||
"surface-container-lowest": "#ffffff",
|
||||
"surface-tint": "#0060ac",
|
||||
"primary-container": "#2976c7",
|
||||
"surface": "#f9f9fd",
|
||||
"on-surface-variant": "#414751",
|
||||
"on-background": "#1a1c1f",
|
||||
"surface-container-high": "#e8e8ec",
|
||||
"on-error-container": "#93000a",
|
||||
"secondary": "#8135c5",
|
||||
"on-secondary-fixed-variant": "#670fac",
|
||||
"outline-variant": "#c1c7d3",
|
||||
"on-tertiary": "#ffffff",
|
||||
"on-surface": "#1a1c1f",
|
||||
"on-error": "#ffffff",
|
||||
"secondary-container": "#ba70ff",
|
||||
"primary-fixed": "#d4e3ff",
|
||||
"tertiary-container": "#6063ee",
|
||||
"surface-container": "#ededf1"
|
||||
},
|
||||
"borderRadius": {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
"spacing": {
|
||||
"xl": "64px",
|
||||
"md": "24px",
|
||||
"container-margin": "20px",
|
||||
"base": "8px",
|
||||
"sm": "12px",
|
||||
"lg": "40px",
|
||||
"xs": "4px",
|
||||
"gutter": "16px"
|
||||
},
|
||||
"fontFamily": {
|
||||
"h3": ["Manrope"],
|
||||
"h2": ["Manrope"],
|
||||
"label-caps": ["Manrope"],
|
||||
"body-md": ["Manrope"],
|
||||
"body-lg": ["Manrope"],
|
||||
"h1": ["Manrope"]
|
||||
},
|
||||
"fontSize": {
|
||||
"h3": ["22px", { "lineHeight": "1.3", "letterSpacing": "0", "fontWeight": "600" }],
|
||||
"h2": ["28px", { "lineHeight": "1.3", "letterSpacing": "-0.01em", "fontWeight": "600" }],
|
||||
"label-caps": ["12px", { "lineHeight": "1.0", "letterSpacing": "0.05em", "fontWeight": "600" }],
|
||||
"body-md": ["15px", { "lineHeight": "1.5", "letterSpacing": "0", "fontWeight": "400" }],
|
||||
"body-lg": ["17px", { "lineHeight": "1.6", "letterSpacing": "-0.01em", "fontWeight": "400" }],
|
||||
"h1": ["34px", { "lineHeight": "1.2", "letterSpacing": "-0.02em", "fontWeight": "700" }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
font-family: 'Manrope', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
||||
background-color: #f9f9fd;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 0, 'wght' 300, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
.ai-glow-btn {
|
||||
background: linear-gradient(135deg, #005da7 0%, #4648d4 100%);
|
||||
box-shadow: 0 8px 24px rgba(70, 72, 212, 0.25);
|
||||
transition: transform 0.15s ease, box-shadow 0.15s ease;
|
||||
}
|
||||
.ai-glow-btn:active {
|
||||
transform: scale(0.96);
|
||||
box-shadow: 0 4px 12px rgba(70, 72, 212, 0.15);
|
||||
}
|
||||
.glass-panel {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
backdrop-filter: blur(24px);
|
||||
-webkit-backdrop-filter: blur(24px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.ambient-shadow {
|
||||
box-shadow: 0 20px 40px rgba(0, 93, 167, 0.04);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="text-on-background bg-background min-h-screen flex flex-col pb-safe">
|
||||
<!-- Top Navigation (Task-Focused Context: No Bottom Nav or global TopAppBar) -->
|
||||
<header class="sticky top-0 z-40 bg-surface/80 backdrop-blur-xl border-b border-surface-container-high px-5 py-3 flex justify-between items-center w-full transition-all duration-300">
|
||||
<button class="w-10 h-10 flex items-center justify-center rounded-full hover:bg-surface-container transition-colors active:scale-95 text-on-surface-variant">
|
||||
<span class="material-symbols-outlined">arrow_back</span>
|
||||
</button>
|
||||
<div class="flex-1 text-center">
|
||||
<h1 class="font-h3 text-h3 text-on-background tracking-tight">认知心理学 · 记忆</h1>
|
||||
</div>
|
||||
<button class="w-10 h-10 flex items-center justify-center rounded-full hover:bg-surface-container transition-colors active:scale-95 text-on-surface-variant">
|
||||
<span class="material-symbols-outlined">more_horiz</span>
|
||||
</button>
|
||||
</header>
|
||||
<main class="flex-1 px-5 lg:px-10 max-w-3xl mx-auto w-full pt-6 pb-24 flex flex-col gap-xl">
|
||||
<!-- Reading Area -->
|
||||
<section class="flex flex-col gap-lg animate-fade-in-up">
|
||||
<header>
|
||||
<h2 class="font-h1 text-h1 text-on-background mb-4">理解编码与提取</h2>
|
||||
</header>
|
||||
<!-- Learning Objectives -->
|
||||
<div class="glass-panel ambient-shadow rounded-xl p-md">
|
||||
<h3 class="font-label-caps text-label-caps text-primary mb-3 uppercase flex items-center gap-2">
|
||||
<span class="material-symbols-outlined text-[16px]">flag</span>
|
||||
本节目标
|
||||
</h3>
|
||||
<ul class="flex flex-col gap-2">
|
||||
<li class="flex items-start gap-3">
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-primary mt-2 flex-shrink-0"></div>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant">区分记忆的三个主要阶段:编码、存储和提取。</p>
|
||||
</li>
|
||||
<li class="flex items-start gap-3">
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-primary mt-2 flex-shrink-0"></div>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant">解释“深度加工”理论如何影响信息留存率。</p>
|
||||
</li>
|
||||
<li class="flex items-start gap-3">
|
||||
<div class="w-1.5 h-1.5 rounded-full bg-primary mt-2 flex-shrink-0"></div>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant">掌握至少两种利用上下文线索促进记忆提取的方法。</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<!-- Reading Content -->
|
||||
<article class="font-body-lg text-body-lg text-on-background leading-relaxed space-y-6">
|
||||
<p>
|
||||
在认知心理学中,记忆通常被概念化为一个信息处理系统,类似于计算机。这个过程可以划分为三个基本且连续的阶段:编码(Encoding)、存储(Storage)和提取(Retrieval)。
|
||||
</p>
|
||||
<p>
|
||||
<strong class="text-on-primary-fixed-variant">编码</strong>是将外部感官信息转化为大脑能够处理和存储的神经表征的过程。这就如同我们在键盘上输入文字,将其转化为计算机能识别的代码。编码的质量直接决定了后续记忆的牢固程度。
|
||||
</p>
|
||||
<!-- Key Knowledge Highlight -->
|
||||
<div class="my-6 bg-surface-container-lowest border-l-4 border-tertiary rounded-r-xl p-5 ambient-shadow">
|
||||
<div class="flex items-center gap-2 mb-2 text-tertiary">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 1;">lightbulb</span>
|
||||
<span class="font-label-caps text-label-caps uppercase">核心概念 : 深度加工理论 (Levels of Processing)</span>
|
||||
</div>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant m-0">
|
||||
由 Craik 和 Lockhart (1972) 提出,该理论认为信息的留存不仅仅取决于我们重复它的次数,更取决于我们加工它的“深度”。关注词语的含义(语义加工)比仅仅关注它的声音或外观能产生更强韧的记忆痕迹。
|
||||
</p>
|
||||
</div>
|
||||
<p>
|
||||
当我们试图回想某事时,我们进入了<strong class="text-on-primary-fixed-variant">提取</strong>阶段。提取是从记忆库中搜寻并唤起已存储信息的过程。提取的成功不仅依赖于信息是否完好地存储,还很大程度上依赖于是否存在合适的“提取线索”(Retrieval Cues)。
|
||||
</p>
|
||||
</article>
|
||||
</section>
|
||||
<hr class="border-surface-container-high"/>
|
||||
<!-- Active Recall Area -->
|
||||
<section class="flex flex-col gap-6" id="active-recall-section">
|
||||
<header class="text-center">
|
||||
<h2 class="font-h2 text-h2 text-on-background mb-2">现在试着回忆一下</h2>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant">请不用翻看上面的内容,尝试用自己的话解释刚刚的知识点。</p>
|
||||
</header>
|
||||
<!-- Recall Input Area -->
|
||||
<div class="relative w-full rounded-xl glass-panel ambient-shadow overflow-hidden transition-all focus-within:ring-2 focus-within:ring-primary focus-within:border-transparent">
|
||||
<textarea class="w-full min-h-[200px] p-6 bg-transparent border-none resize-none focus:ring-0 font-body-md text-body-md text-on-background placeholder:text-outline-variant" placeholder="例如:记忆分为三个步骤... 深度加工是指..."></textarea>
|
||||
<!-- Voice Input & Controls -->
|
||||
<div class="absolute bottom-4 right-4 flex items-center gap-3">
|
||||
<button class="w-12 h-12 rounded-full bg-surface-container hover:bg-surface-container-high transition-colors flex items-center justify-center text-primary active:scale-95 shadow-sm">
|
||||
<span class="material-symbols-outlined">mic</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Methodological Shortcuts -->
|
||||
<div class="flex flex-wrap gap-3 justify-center">
|
||||
<button class="px-4 py-2 rounded-full border border-surface-container-highest bg-surface-container-lowest text-on-surface-variant font-body-md text-[14px] hover:bg-surface-container transition-colors flex items-center gap-2 active:scale-95">
|
||||
<span class="material-symbols-outlined text-[18px]">psychology</span>
|
||||
用更简单的话解释
|
||||
</button>
|
||||
<button class="px-4 py-2 rounded-full border border-surface-container-highest bg-surface-container-lowest text-on-surface-variant font-body-md text-[14px] hover:bg-surface-container transition-colors flex items-center gap-2 active:scale-95">
|
||||
<span class="material-symbols-outlined text-[18px]">extension</span>
|
||||
给我一个例子
|
||||
</button>
|
||||
<button class="px-4 py-2 rounded-full border border-surface-container-highest bg-surface-container-lowest text-on-surface-variant font-body-md text-[14px] hover:bg-surface-container transition-colors flex items-center gap-2 active:scale-95">
|
||||
<span class="material-symbols-outlined text-[18px]">search_insights</span>
|
||||
提示我遗漏了什么
|
||||
</button>
|
||||
</div>
|
||||
<!-- Primary Action -->
|
||||
<div class="mt-4 flex justify-center">
|
||||
<button class="ai-glow-btn px-8 py-4 rounded-xl text-on-primary font-h3 text-[18px] w-full max-w-md flex items-center justify-center gap-2">
|
||||
<span class="material-symbols-outlined" style="font-variation-settings: 'FILL' 1;">auto_awesome</span>
|
||||
交给 AI 分析
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 225 KiB |
@ -1,394 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html class="light" lang="en"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>ZhiXi - Profile & Settings</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
"colors": {
|
||||
"on-secondary-fixed": "#2c0050",
|
||||
"background": "#f9f9fd",
|
||||
"secondary-fixed": "#f0dbff",
|
||||
"on-secondary": "#ffffff",
|
||||
"tertiary-fixed": "#e1e0ff",
|
||||
"error-container": "#ffdad6",
|
||||
"inverse-surface": "#2e3034",
|
||||
"tertiary-fixed-dim": "#c0c1ff",
|
||||
"on-primary-fixed": "#001c39",
|
||||
"surface-bright": "#f9f9fd",
|
||||
"on-secondary-container": "#440076",
|
||||
"tertiary": "#4648d4",
|
||||
"primary-fixed-dim": "#a4c9ff",
|
||||
"outline": "#717783",
|
||||
"on-tertiary-fixed-variant": "#2f2ebe",
|
||||
"on-tertiary-container": "#fffbff",
|
||||
"primary": "#005da7",
|
||||
"secondary-fixed-dim": "#deb7ff",
|
||||
"on-primary-fixed-variant": "#004883",
|
||||
"inverse-on-surface": "#f0f0f4",
|
||||
"error": "#ba1a1a",
|
||||
"on-primary-container": "#fdfcff",
|
||||
"on-primary": "#ffffff",
|
||||
"surface-container-low": "#f3f3f7",
|
||||
"surface-container-highest": "#e2e2e6",
|
||||
"on-tertiary-fixed": "#07006c",
|
||||
"surface-dim": "#d9dade",
|
||||
"inverse-primary": "#a4c9ff",
|
||||
"surface-variant": "#e2e2e6",
|
||||
"surface-container-lowest": "#ffffff",
|
||||
"surface-tint": "#0060ac",
|
||||
"primary-container": "#2976c7",
|
||||
"surface": "#f9f9fd",
|
||||
"on-surface-variant": "#414751",
|
||||
"on-background": "#1a1c1f",
|
||||
"surface-container-high": "#e8e8ec",
|
||||
"on-error-container": "#93000a",
|
||||
"secondary": "#8135c5",
|
||||
"on-secondary-fixed-variant": "#670fac",
|
||||
"outline-variant": "#c1c7d3",
|
||||
"on-tertiary": "#ffffff",
|
||||
"on-surface": "#1a1c1f",
|
||||
"on-error": "#ffffff",
|
||||
"secondary-container": "#ba70ff",
|
||||
"primary-fixed": "#d4e3ff",
|
||||
"tertiary-container": "#6063ee",
|
||||
"surface-container": "#ededf1"
|
||||
},
|
||||
"borderRadius": {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
"spacing": {
|
||||
"xl": "64px",
|
||||
"md": "24px",
|
||||
"container-margin": "20px",
|
||||
"base": "8px",
|
||||
"sm": "12px",
|
||||
"lg": "40px",
|
||||
"xs": "4px",
|
||||
"gutter": "16px"
|
||||
},
|
||||
"fontFamily": {
|
||||
"h3": ["Manrope"],
|
||||
"h2": ["Manrope"],
|
||||
"label-caps": ["Manrope"],
|
||||
"body-md": ["Manrope"],
|
||||
"body-lg": ["Manrope"],
|
||||
"h1": ["Manrope"]
|
||||
},
|
||||
"fontSize": {
|
||||
"h3": ["22px", { "lineHeight": "1.3", "letterSpacing": "0", "fontWeight": "600" }],
|
||||
"h2": ["28px", { "lineHeight": "1.3", "letterSpacing": "-0.01em", "fontWeight": "600" }],
|
||||
"label-caps": ["12px", { "lineHeight": "1.0", "letterSpacing": "0.05em", "fontWeight": "600" }],
|
||||
"body-md": ["15px", { "lineHeight": "1.5", "letterSpacing": "0", "fontWeight": "400" }],
|
||||
"body-lg": ["17px", { "lineHeight": "1.6", "letterSpacing": "-0.01em", "fontWeight": "400" }],
|
||||
"h1": ["34px", { "lineHeight": "1.2", "letterSpacing": "-0.02em", "fontWeight": "700" }]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
.material-symbols-outlined {
|
||||
font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
.material-symbols-outlined.filled {
|
||||
font-variation-settings: 'FILL' 1, 'wght' 400, 'GRAD' 0, 'opsz' 24;
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gradient-to-br from-surface via-surface to-primary-fixed-dim/20 text-on-surface antialiased font-body-md selection:bg-primary-fixed selection:text-on-primary-fixed relative">
|
||||
<!-- Decorative Background Paths -->
|
||||
<div class="fixed inset-0 overflow-hidden pointer-events-none -z-10">
|
||||
<svg class="absolute top-0 right-0 w-full h-[600px] opacity-30 mix-blend-multiply dark:opacity-20 dark:mix-blend-screen" fill="none" viewbox="0 0 400 600" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M400 0H0V100C100 100 200 200 200 300C200 400 300 500 400 500V0Z" fill="url(#paint0_linear)"></path>
|
||||
<path d="M400 600C300 600 200 500 200 400C200 300 100 200 0 200V600H400Z" fill="url(#paint1_linear)"></path>
|
||||
<defs>
|
||||
<lineargradient gradientunits="userSpaceOnUse" id="paint0_linear" x1="200" x2="200" y1="0" y2="500">
|
||||
<stop stop-color="#D4E3FF"></stop>
|
||||
<stop offset="1" stop-color="#D4E3FF" stop-opacity="0"></stop>
|
||||
</lineargradient>
|
||||
<lineargradient gradientunits="userSpaceOnUse" id="paint1_linear" x1="200" x2="200" y1="200" y2="600">
|
||||
<stop stop-color="#F0DBFF"></stop>
|
||||
<stop offset="1" stop-color="#F0DBFF" stop-opacity="0"></stop>
|
||||
</lineargradient>
|
||||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<!-- TopAppBar from JSON -->
|
||||
<header class="bg-white/60 dark:bg-slate-900/60 backdrop-blur-xl docked full-width top-0 sticky z-40 border-b border-white/20">
|
||||
<div class="flex justify-between items-center w-full px-5 py-3">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="w-8 h-8 rounded-full bg-primary-fixed flex items-center justify-center overflow-hidden">
|
||||
<span class="material-symbols-outlined text-on-primary-fixed text-[20px]">person</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="font-['Manrope'] font-bold text-xl text-slate-900 dark:text-slate-50">知习</div>
|
||||
<button class="hover:opacity-80 transition-opacity Active: scale-95 transition-transform duration-150 text-blue-500 dark:text-blue-400">
|
||||
<span class="material-symbols-outlined">settings</span>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
<main class="max-w-md mx-auto pt-lg pb-32">
|
||||
<!-- Profile Header -->
|
||||
<section class="flex flex-col items-center px-container-margin">
|
||||
<div class="relative w-24 h-24 rounded-full overflow-hidden shadow-[0_8px_30px_rgba(0,0,0,0.08)] mb-sm border-2 border-surface-container-lowest">
|
||||
<img alt="Profile Photo" class="w-full h-full object-cover" data-alt="A highly detailed, cinematic headshot of a young professional male in his late 20s, featuring short dark hair and a calm, intellectual expression. The lighting is high-key and airy, creating a minimalist, Apple-like aesthetic with soft, diffused white light. The background is an abstract, ultra-clean light gray gradient with a subtle hint of cool blue, reflecting a serene, high-tech sanctuary environment." src="https://lh3.googleusercontent.com/aida-public/AB6AXuC7e2iYy788XFD3zf_LHXlcz18RJtJnMI5w5265E_gCfKXn2fSX_tLmHLFtOdZr4Tg2gUQSIc6JkJ3C_Rj-VraIbN2usG-JRaSqjM_fQmHorg9pkboW8Nk7eU7_mMX3OnjiBf5PnjCdQZQKVmEFP5hhrjVwR_f-G4RqURKr0E6Cgsub5bHs_Abj1yS_0t9PO3aojNwoavgqBqtmk0ZTa-RkArjCDkf4WHKH0JDnwOYoaPq9ZRlhizxqFWqHepccEnVrBgPK3iFo"/>
|
||||
</div>
|
||||
<h1 class="font-h2 text-h2 text-on-surface">Alex Mercer</h1>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant mt-xs bg-surface-container-lowest/80 backdrop-blur-md border border-white/40 px-3 py-1 rounded-full shadow-sm">今天也在把知识变清楚</p>
|
||||
</section>
|
||||
<!-- Learning Overview Stats -->
|
||||
<section class="grid grid-cols-2 gap-sm px-container-margin mt-lg">
|
||||
<div class="bg-surface-container-lowest/80 backdrop-blur-xl rounded-xl p-md shadow-[0_4px_40px_rgba(0,0,0,0.03)] border border-white/40 flex flex-col items-start">
|
||||
<div class="w-8 h-8 rounded-full bg-primary-fixed/50 flex items-center justify-center text-primary mb-sm">
|
||||
<span class="material-symbols-outlined text-[18px]">local_fire_department</span>
|
||||
</div>
|
||||
<h3 class="font-h2 text-h2 text-on-surface mb-1">14 <span class="font-body-md text-body-md text-on-surface-variant">天</span></h3>
|
||||
<p class="font-label-caps text-label-caps text-outline uppercase tracking-wider">Learning Streak</p>
|
||||
</div>
|
||||
<div class="bg-surface-container-lowest/80 backdrop-blur-xl rounded-xl p-md shadow-[0_4px_40px_rgba(0,0,0,0.03)] border border-white/40 flex flex-col items-start">
|
||||
<div class="w-8 h-8 rounded-full bg-secondary-fixed/50 flex items-center justify-center text-secondary mb-sm">
|
||||
<span class="material-symbols-outlined text-[18px]">calendar_month</span>
|
||||
</div>
|
||||
<h3 class="font-h2 text-h2 text-on-surface mb-1">24 <span class="font-body-md text-body-md text-on-surface-variant">次</span></h3>
|
||||
<p class="font-label-caps text-label-caps text-outline uppercase tracking-wider">Studies this Month</p>
|
||||
</div>
|
||||
<div class="bg-surface-container-lowest/80 backdrop-blur-xl rounded-xl p-md shadow-[0_4px_40px_rgba(0,0,0,0.03)] border border-white/40 flex flex-col items-start">
|
||||
<div class="w-8 h-8 rounded-full bg-tertiary-fixed/50 flex items-center justify-center text-tertiary mb-sm">
|
||||
<span class="material-symbols-outlined text-[18px]">all_inclusive</span>
|
||||
</div>
|
||||
<h3 class="font-h2 text-h2 text-on-surface mb-1">12 <span class="font-body-md text-body-md text-on-surface-variant">个</span></h3>
|
||||
<p class="font-label-caps text-label-caps text-outline uppercase tracking-wider">Closed Loops</p>
|
||||
</div>
|
||||
<div class="bg-surface-container-lowest/80 backdrop-blur-xl rounded-xl p-md shadow-[0_4px_40px_rgba(0,0,0,0.03)] border border-white/40 flex flex-col items-start">
|
||||
<div class="w-8 h-8 rounded-full bg-primary-fixed/30 flex items-center justify-center text-primary mb-sm">
|
||||
<span class="material-symbols-outlined text-[18px]">schedule</span>
|
||||
</div>
|
||||
<h3 class="font-h2 text-h2 text-on-surface mb-1">128 <span class="font-body-md text-body-md text-on-surface-variant">hrs</span></h3>
|
||||
<p class="font-label-caps text-label-caps text-outline uppercase tracking-wider">Total Study</p>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Blue Learning Activity Map -->
|
||||
<section class="mx-container-margin mt-lg bg-surface-container-lowest/80 backdrop-blur-xl rounded-xl shadow-[0_4px_40px_rgba(0,0,0,0.03)] border border-white/40 p-md">
|
||||
<div class="flex justify-between items-end mb-sm">
|
||||
<div>
|
||||
<h2 class="font-h3 text-h3 text-on-surface">学习活跃图</h2>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant mt-1">过去 90 天,你的学习投入记录</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap gap-1 mt-md">
|
||||
<!-- Simulated 90 day grid squares with varying activity -->
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-secondary text-white"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-secondary text-white"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-secondary text-white"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-secondary text-white"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-secondary text-white"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-secondary text-white"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-container"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-secondary text-white"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-primary-fixed"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
<div class="w-3 h-3 rounded-[3px] bg-surface-container-highest"></div>
|
||||
</div>
|
||||
<div class="flex items-center justify-end gap-2 mt-sm">
|
||||
<span class="font-label-caps text-[10px] text-outline">Less</span>
|
||||
<div class="flex gap-[2px]">
|
||||
<div class="w-2.5 h-2.5 rounded-[2px] bg-surface-container-highest"></div>
|
||||
<div class="w-2.5 h-2.5 rounded-[2px] bg-primary-fixed"></div>
|
||||
<div class="w-2.5 h-2.5 rounded-[2px] bg-primary-container"></div>
|
||||
<div class="w-2.5 h-2.5 rounded-[2px] bg-primary"></div>
|
||||
<div class="w-2.5 h-2.5 rounded-[2px] bg-secondary"></div>
|
||||
</div>
|
||||
<span class="font-label-caps text-[10px] text-outline">More</span>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Items to Consolidate -->
|
||||
<h2 class="px-container-margin mt-xl mb-sm font-label-caps text-label-caps text-outline uppercase tracking-wider">待巩固项</h2>
|
||||
<section class="flex flex-col gap-sm px-container-margin">
|
||||
<div class="bg-surface-container-lowest/80 backdrop-blur-xl rounded-xl p-md shadow-[0_4px_40px_rgba(0,0,0,0.03)] border border-white/40">
|
||||
<div class="flex justify-between items-start mb-sm">
|
||||
<div>
|
||||
<h3 class="font-h3 text-h3 text-on-surface">记忆曲线</h3>
|
||||
<p class="font-body-md text-sm text-outline mt-1">认知心理学基础</p>
|
||||
</div>
|
||||
<span class="bg-error-container text-on-error-container font-label-caps text-[10px] px-2 py-1 rounded-md uppercase tracking-wide">Pending</span>
|
||||
</div>
|
||||
<div class="bg-surface-container-low rounded-lg p-sm mb-sm border border-surface-container-highest">
|
||||
<div class="flex gap-2">
|
||||
<span class="material-symbols-outlined text-tertiary text-[18px]">auto_awesome</span>
|
||||
<p class="font-body-md text-[14px] text-on-surface-variant leading-relaxed">今晚复习一次,并尝试主动回忆</p>
|
||||
</div>
|
||||
</div>
|
||||
<button class="w-full py-2 bg-primary text-on-primary font-body-md rounded-lg shadow-sm hover:bg-surface-tint transition-colors active:scale-[0.98]">
|
||||
Go Consolidate
|
||||
</button>
|
||||
</div>
|
||||
<div class="bg-surface-container-lowest/80 backdrop-blur-xl rounded-xl p-md shadow-[0_4px_40px_rgba(0,0,0,0.03)] border border-white/40">
|
||||
<div class="flex justify-between items-start mb-sm">
|
||||
<div>
|
||||
<h3 class="font-h3 text-h3 text-on-surface">激活函数的作用</h3>
|
||||
<p class="font-body-md text-sm text-outline mt-1">高级神经网络</p>
|
||||
</div>
|
||||
<span class="bg-surface-container-high text-on-surface-variant font-label-caps text-[10px] px-2 py-1 rounded-md uppercase tracking-wide">Added to Review</span>
|
||||
</div>
|
||||
<div class="bg-surface-container-low rounded-lg p-sm mb-sm border border-surface-container-highest">
|
||||
<div class="flex gap-2">
|
||||
<span class="material-symbols-outlined text-tertiary text-[18px]">auto_awesome</span>
|
||||
<p class="font-body-md text-[14px] text-on-surface-variant leading-relaxed">用一个例子解释它为什么必要</p>
|
||||
</div>
|
||||
</div>
|
||||
<button class="w-full py-2 bg-primary/10 text-primary font-body-md rounded-lg border border-primary/20 hover:bg-primary/20 transition-colors active:scale-[0.98]">
|
||||
Review Again
|
||||
</button>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Recent Learning History -->
|
||||
<h2 class="px-container-margin mt-xl mb-sm font-label-caps text-label-caps text-outline uppercase tracking-wider">最近学习记录</h2>
|
||||
<section class="mx-container-margin bg-surface-container-lowest/80 backdrop-blur-xl rounded-xl shadow-[0_4px_40px_rgba(0,0,0,0.03)] border border-white/40 p-md relative overflow-hidden">
|
||||
<div class="absolute left-6 top-6 bottom-6 w-px bg-surface-container-highest"></div>
|
||||
<div class="flex flex-col gap-md relative z-10">
|
||||
<div class="flex gap-sm items-start">
|
||||
<div class="w-8 h-8 rounded-full bg-primary flex-shrink-0 flex items-center justify-center text-white border-2 border-surface-container-lowest shadow-sm z-10">
|
||||
<span class="material-symbols-outlined text-[16px]">check_circle</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-body-md text-on-surface font-medium">完成一次主动回忆</p>
|
||||
<p class="font-body-md text-sm text-outline mt-1">认知心理学 · 23 分钟</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-sm items-start">
|
||||
<div class="w-8 h-8 rounded-full bg-surface-container-high flex-shrink-0 flex items-center justify-center text-on-surface-variant border-2 border-surface-container-lowest shadow-sm z-10">
|
||||
<span class="material-symbols-outlined text-[16px]">analytics</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-body-md text-on-surface font-medium">生成 AI 分析</p>
|
||||
<p class="font-body-md text-sm text-outline mt-1">神经网络基础</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-sm items-start">
|
||||
<div class="w-8 h-8 rounded-full bg-surface-container-high flex-shrink-0 flex items-center justify-center text-on-surface-variant border-2 border-surface-container-lowest shadow-sm z-10">
|
||||
<span class="material-symbols-outlined text-[16px]">history_edu</span>
|
||||
</div>
|
||||
<div>
|
||||
<p class="font-body-md text-on-surface font-medium">复习了 2 个待巩固项</p>
|
||||
<p class="font-body-md text-sm text-outline mt-1">微积分速成</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
<!-- BottomNavBar from JSON -->
|
||||
<nav class="bg-white/80 dark:bg-slate-900/80 backdrop-blur-2xl fixed bottom-0 w-full z-50 rounded-t-none border-t border-slate-200/50 dark:border-slate-800/50 shadow-[0_-4px_24px_rgba(0,0,0,0.04)] fixed bottom-0 left-0 w-full flex justify-around items-center px-4 pt-2 pb-safe-offset-2 pb-6">
|
||||
<button class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 hover:bg-slate-50/50 dark:hover:bg-slate-800/50 Active: scale-90 transition-transform duration-200 p-2 rounded-lg">
|
||||
<span class="material-symbols-outlined text-[24px] mb-1">menu_book</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">学习</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 hover:bg-slate-50/50 dark:hover:bg-slate-800/50 Active: scale-90 transition-transform duration-200 p-2 rounded-lg">
|
||||
<span class="material-symbols-outlined text-[24px] mb-1">database</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">知识库</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center justify-center text-slate-400 dark:text-slate-500 hover:bg-slate-50/50 dark:hover:bg-slate-800/50 Active: scale-90 transition-transform duration-200 p-2 rounded-lg">
|
||||
<span class="material-symbols-outlined text-[24px] mb-1">auto_awesome</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">AI 助手</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center justify-center text-blue-500 dark:text-blue-400 font-bold hover:bg-slate-50/50 dark:hover:bg-slate-800/50 Active: scale-90 transition-transform duration-200 p-2 rounded-lg">
|
||||
<span class="material-symbols-outlined filled text-[24px] mb-1">person</span>
|
||||
<span class="font-['Manrope'] text-[10px] font-medium tracking-wide">我的</span>
|
||||
</button>
|
||||
</nav>
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 163 KiB |
@ -1,267 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html lang="zh-CN"><head>
|
||||
<meta charset="utf-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>知习 - AI-First Learning Home</title>
|
||||
<script src="https://cdn.tailwindcss.com?plugins=forms,container-queries"></script>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&display=swap" rel="stylesheet"/>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap" rel="stylesheet"/>
|
||||
<script id="tailwind-config">
|
||||
tailwind.config = {
|
||||
darkMode: "class",
|
||||
theme: {
|
||||
extend: {
|
||||
"colors": {
|
||||
"primary-container": "#2976c7",
|
||||
"on-error-container": "#93000a",
|
||||
"on-primary-container": "#fdfcff",
|
||||
"on-secondary": "#ffffff",
|
||||
"primary-fixed": "#d4e3ff",
|
||||
"primary-fixed-dim": "#a4c9ff",
|
||||
"on-tertiary-container": "#fffbff",
|
||||
"on-primary-fixed-variant": "#004883",
|
||||
"outline": "#717783",
|
||||
"tertiary-fixed-dim": "#c0c1ff",
|
||||
"on-background": "#1a1c1f",
|
||||
"on-surface-variant": "#414751",
|
||||
"on-primary": "#ffffff",
|
||||
"on-secondary-fixed-variant": "#670fac",
|
||||
"secondary-fixed-dim": "#deb7ff",
|
||||
"tertiary": "#4648d4",
|
||||
"surface-container-highest": "#e2e2e6",
|
||||
"surface-container-high": "#e8e8ec",
|
||||
"on-secondary-container": "#440076",
|
||||
"on-tertiary-fixed-variant": "#2f2ebe",
|
||||
"on-error": "#ffffff",
|
||||
"on-tertiary-fixed": "#07006c",
|
||||
"on-surface": "#1a1c1f",
|
||||
"surface-tint": "#0060ac",
|
||||
"surface-container": "#ededf1",
|
||||
"secondary-fixed": "#f0dbff",
|
||||
"inverse-on-surface": "#f0f0f4",
|
||||
"surface-container-low": "#f3f3f7",
|
||||
"on-secondary-fixed": "#2c0050",
|
||||
"inverse-primary": "#a4c9ff",
|
||||
"primary": "#005da7",
|
||||
"surface-variant": "#e2e2e6",
|
||||
"error-container": "#ffdad6",
|
||||
"surface-bright": "#f9f9fd",
|
||||
"tertiary-fixed": "#e1e0ff",
|
||||
"surface": "#f9f9fd",
|
||||
"outline-variant": "#c1c7d3",
|
||||
"surface-dim": "#d9dade",
|
||||
"tertiary-container": "#6063ee",
|
||||
"secondary": "#8135c5",
|
||||
"error": "#ba1a1a",
|
||||
"secondary-container": "#ba70ff",
|
||||
"background": "#f9f9fd",
|
||||
"surface-container-lowest": "#ffffff",
|
||||
"on-primary-fixed": "#001c39",
|
||||
"inverse-surface": "#2e3034",
|
||||
"on-tertiary": "#ffffff"
|
||||
},
|
||||
"borderRadius": {
|
||||
"DEFAULT": "0.25rem",
|
||||
"lg": "0.5rem",
|
||||
"xl": "0.75rem",
|
||||
"full": "9999px"
|
||||
},
|
||||
"spacing": {
|
||||
"sm": "12px",
|
||||
"xs": "4px",
|
||||
"xl": "64px",
|
||||
"base": "8px",
|
||||
"lg": "40px",
|
||||
"gutter": "16px",
|
||||
"md": "24px",
|
||||
"container-margin": "20px"
|
||||
},
|
||||
"fontFamily": {
|
||||
"h3": ["Manrope"],
|
||||
"label-caps": ["Manrope"],
|
||||
"body-md": ["Manrope"],
|
||||
"body-lg": ["Manrope"],
|
||||
"h2": ["Manrope"],
|
||||
"h1": ["Manrope"]
|
||||
},
|
||||
"fontSize": {
|
||||
"h3": ["22px", {"lineHeight": "1.3", "letterSpacing": "0", "fontWeight": "600"}],
|
||||
"label-caps": ["12px", {"lineHeight": "1.0", "letterSpacing": "0.05em", "fontWeight": "600"}],
|
||||
"body-md": ["15px", {"lineHeight": "1.5", "letterSpacing": "0", "fontWeight": "400"}],
|
||||
"body-lg": ["17px", {"lineHeight": "1.6", "letterSpacing": "-0.01em", "fontWeight": "400"}],
|
||||
"h2": ["28px", {"lineHeight": "1.3", "letterSpacing": "-0.01em", "fontWeight": "600"}],
|
||||
"h1": ["34px", {"lineHeight": "1.2", "letterSpacing": "-0.02em", "fontWeight": "700"}]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style>
|
||||
body {
|
||||
background-color: #FAFAFC;
|
||||
}
|
||||
|
||||
.mesh-bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
z-index: -2;
|
||||
background:
|
||||
radial-gradient(circle at 15% 50%, rgba(41, 118, 199, 0.04) 0%, transparent 50%),
|
||||
radial-gradient(circle at 85% 30%, rgba(129, 53, 197, 0.03) 0%, transparent 50%);
|
||||
}
|
||||
|
||||
.geometric-lines {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
z-index: -1;
|
||||
opacity: 0.4;
|
||||
background-image:
|
||||
linear-gradient(rgba(41, 118, 199, 0.05) 1px, transparent 1px),
|
||||
linear-gradient(90deg, rgba(41, 118, 199, 0.05) 1px, transparent 1px);
|
||||
background-size: 40px 40px;
|
||||
mask-image: radial-gradient(ellipse at center, black 0%, transparent 70%);
|
||||
-webkit-mask-image: radial-gradient(ellipse at center, black 0%, transparent 70%);
|
||||
}
|
||||
|
||||
.glass-card {
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
backdrop-filter: blur(24px);
|
||||
-webkit-backdrop-filter: blur(24px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||
box-shadow: 0 10px 40px -10px rgba(0, 93, 167, 0.08);
|
||||
}
|
||||
|
||||
@keyframes breathe {
|
||||
0%, 100% { box-shadow: 0 0 20px rgba(41, 118, 199, 0.1), 0 0 40px rgba(129, 53, 197, 0.05); }
|
||||
50% { box-shadow: 0 0 30px rgba(41, 118, 199, 0.2), 0 0 50px rgba(129, 53, 197, 0.1); }
|
||||
}
|
||||
|
||||
.ai-input-glow {
|
||||
animation: breathe 4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.light-shadow {
|
||||
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.04);
|
||||
}
|
||||
|
||||
.floating-nav {
|
||||
background: rgba(255, 255, 255, 0.85);
|
||||
backdrop-filter: blur(32px);
|
||||
-webkit-backdrop-filter: blur(32px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.4);
|
||||
box-shadow: 0 -4px 30px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
</style>
|
||||
<style>
|
||||
body {
|
||||
min-height: max(884px, 100dvh);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="font-body-md text-body-md text-on-surface antialiased min-h-screen relative pb-[120px]">
|
||||
<!-- Decorative Background Elements -->
|
||||
<div class="mesh-bg"></div>
|
||||
<div class="geometric-lines"></div>
|
||||
<!-- TopAppBar -->
|
||||
<header class="w-full pt-16 pb-6 px-6 z-40 relative">
|
||||
<div class="flex flex-col items-center justify-center w-full">
|
||||
<h1 class="font-h1 text-h1 text-primary tracking-tight">知习</h1>
|
||||
<p class="font-body-md text-body-md text-on-surface-variant mt-2 text-center opacity-80">今天想把哪块知识变清楚?</p>
|
||||
</div>
|
||||
</header>
|
||||
<!-- Main Content -->
|
||||
<main class="px-container-margin w-full max-w-2xl mx-auto flex flex-col gap-12 items-center relative z-10">
|
||||
<!-- AI Input Area -->
|
||||
<div class="w-full glass-card rounded-[32px] p-2 flex flex-col ai-input-glow transition-all duration-300">
|
||||
<div class="px-md py-4 w-full">
|
||||
<textarea class="w-full bg-transparent border-none focus:ring-0 resize-none font-body-lg text-body-lg text-on-surface placeholder:text-outline-variant h-28 caret-primary" placeholder="问我知识点、上传资料,或开始一次主动回忆"></textarea>
|
||||
</div>
|
||||
<div class="flex justify-between items-center px-4 pb-2 pt-2">
|
||||
<div class="flex gap-2">
|
||||
<button aria-label="Upload" class="p-2.5 rounded-full hover:bg-surface-container-highest/50 text-outline transition-colors">
|
||||
<span class="material-symbols-outlined" style='font-variation-settings: "wght" 300;'>attach_file</span>
|
||||
</button>
|
||||
<button aria-label="Voice" class="p-2.5 rounded-full hover:bg-surface-container-highest/50 text-outline transition-colors">
|
||||
<span class="material-symbols-outlined" style='font-variation-settings: "wght" 300;'>mic</span>
|
||||
</button>
|
||||
</div>
|
||||
<button aria-label="Send" class="bg-primary hover:bg-primary/90 text-on-primary rounded-full w-12 h-12 flex items-center justify-center active:scale-95 transition-all shadow-lg shadow-primary/20">
|
||||
<span class="material-symbols-outlined" style='font-variation-settings: "wght" 400, "FILL" 1;'>arrow_upward</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Quick Actions Grid -->
|
||||
<div class="grid grid-cols-4 gap-4 w-full px-2">
|
||||
<button class="flex flex-col items-center gap-3 group active:scale-95 transition-transform">
|
||||
<div class="w-16 h-16 rounded-2xl bg-white light-shadow flex items-center justify-center text-secondary group-hover:bg-secondary/5 transition-colors border border-white/50">
|
||||
<span class="material-symbols-outlined text-[28px]" style='font-variation-settings: "wght" 300;'>psychology</span>
|
||||
</div>
|
||||
<span class="font-label-caps text-label-caps text-on-surface-variant opacity-80">主动回忆</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center gap-3 group active:scale-95 transition-transform">
|
||||
<div class="w-16 h-16 rounded-2xl bg-white light-shadow flex items-center justify-center text-primary group-hover:bg-primary/5 transition-colors border border-white/50">
|
||||
<span class="material-symbols-outlined text-[28px]" style='font-variation-settings: "wght" 300;'>upload_file</span>
|
||||
</div>
|
||||
<span class="font-label-caps text-label-caps text-on-surface-variant opacity-80">导入资料</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center gap-3 group active:scale-95 transition-transform">
|
||||
<div class="w-16 h-16 rounded-2xl bg-white light-shadow flex items-center justify-center text-tertiary group-hover:bg-tertiary/5 transition-colors border border-white/50">
|
||||
<span class="material-symbols-outlined text-[28px]" style='font-variation-settings: "wght" 300;'>history</span>
|
||||
</div>
|
||||
<span class="font-label-caps text-label-caps text-on-surface-variant opacity-80">复习一下</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center gap-3 group active:scale-95 transition-transform">
|
||||
<div class="w-16 h-16 rounded-2xl bg-white light-shadow flex items-center justify-center text-primary-container group-hover:bg-primary-container/5 transition-colors border border-white/50">
|
||||
<span class="material-symbols-outlined text-[28px]" style='font-variation-settings: "wght" 300;'>auto_awesome</span>
|
||||
</div>
|
||||
<span class="font-label-caps text-label-caps text-on-surface-variant opacity-80">AI 分析</span>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Current Learning Card -->
|
||||
<div class="w-full mt-4">
|
||||
<div class="bg-white/90 rounded-[28px] p-6 light-shadow flex flex-col gap-5 relative overflow-hidden border border-white/60"><div class="absolute left-0 top-0 bottom-0 w-1.5 bg-gradient-to-b from-primary via-primary to-secondary"></div>
|
||||
<div class="flex items-center justify-between">
|
||||
<span class="font-label-caps text-[11px] text-outline uppercase tracking-[0.1em]">Current Learning</span>
|
||||
<span class="material-symbols-outlined text-outline-variant" style='font-variation-settings: "wght" 300;'>more_horiz</span>
|
||||
</div>
|
||||
<h3 class="font-h3 text-[24px] text-on-surface leading-tight font-bold">认知心理学基础</h3>
|
||||
<div class="bg-primary/5 rounded-[20px] p-5 flex gap-4 items-start border border-primary/10">
|
||||
<span class="material-symbols-outlined text-primary mt-0.5" style='font-variation-settings: "wght" 400, "FILL" 1;'>lightbulb</span>
|
||||
<div>
|
||||
<span class="font-label-caps text-[13px] text-primary block mb-1.5 font-bold">AI Suggestion</span>
|
||||
<p class="font-body-md text-[15px] text-on-surface-variant leading-relaxed">建议今天先复习记忆编码部分</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
<!-- Premium Apple-style BottomNavBar -->
|
||||
<div class="fixed bottom-6 left-1/2 -translate-x-1/2 w-[90%] max-w-sm z-50">
|
||||
<nav class="floating-nav rounded-full px-2 py-2 flex justify-between items-center">
|
||||
<!-- Active Tab: AI -->
|
||||
<button class="flex flex-col items-center justify-center text-primary bg-primary/10 rounded-full px-5 py-2.5 active:scale-95 transition-all duration-300">
|
||||
<span class="material-symbols-outlined mb-0.5 text-[22px]" style='font-variation-settings: "wght" 400, "FILL" 1;'>smart_toy</span>
|
||||
<span class="font-manrope text-[10px] font-bold tracking-wide">AI</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center justify-center text-outline px-4 py-2 hover:text-primary transition-colors active:scale-95 duration-300">
|
||||
<span class="material-symbols-outlined mb-0.5 text-[22px]" style='font-variation-settings: "wght" 300;'>database</span>
|
||||
<span class="font-manrope text-[10px] font-medium tracking-wide">知识库</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center justify-center text-outline px-4 py-2 hover:text-primary transition-colors active:scale-95 duration-300">
|
||||
<span class="material-symbols-outlined mb-0.5 text-[22px]" style='font-variation-settings: "wght" 300;'>school</span>
|
||||
<span class="font-manrope text-[10px] font-medium tracking-wide">学习</span>
|
||||
</button>
|
||||
<button class="flex flex-col items-center justify-center text-outline px-4 py-2 hover:text-primary transition-colors active:scale-95 duration-300">
|
||||
<span class="material-symbols-outlined mb-0.5 text-[22px]" style='font-variation-settings: "wght" 300;'>person</span>
|
||||
<span class="font-manrope text-[10px] font-medium tracking-wide">我的</span>
|
||||
</button>
|
||||
</nav>
|
||||
</div>
|
||||
</body></html>
|
||||
|
Before Width: | Height: | Size: 340 KiB |