Skip to content

设计令牌

CSS 变量

定义在 core/theme.css,所有组件中可直接使用。

css
/* 主色 */
--tr-primary: #fc4c02; /* Strava 橙 */

/* 背景 */
--tr-bg: #f8fafc; /* 页面背景 */
--tr-bg-card: #ffffff; /* 卡片背景 */
--tr-bg-card-hover: rgba(0, 0, 0, 0.02); /* 卡片悬停 */

/* 文本 */
--tr-text: #1e293b; /* 主文本 */
--tr-text-muted: #64748b; /* 次要文本 */

/* 训练类型 */
--tr-rest: #94a3b8; /* 休息-灰 */
--tr-recovery: #06b6d4; /* 恢复跑-青 */
--tr-easy: #22c55e; /* 有氧跑-绿 */
--tr-tempo: #f59e0b; /* 节奏跑-橙 */
--tr-interval: #ef4444; /* 间歇-红 */
--tr-lsd: #8b5cf6; /* LSD-紫 */
--tr-strength: #6366f1; /* 力量-靛蓝 */

/* 心率区间 */
--hr-zone-1: #3b82f6; /* Z1 蓝 */
--hr-zone-2: #06b6d4; /* Z2 青 */
--hr-zone-3: #22c55e; /* Z3 绿 */
--hr-zone-4: #f97316; /* Z4 橙 */
--hr-zone-5: #f87171; /* Z5 红 */

/* 间距 */
--tr-space-xs: 4px;
--tr-space-sm: 8px;
--tr-space-md: 16px;
--tr-space-lg: 24px;
--tr-space-xl: 32px;
--tr-space-2xl: 48px;

/* 圆角 */
--tr-radius-sm: 4px;
--tr-radius-md: 8px;
--tr-radius-lg: 12px;
--tr-radius-full: 9999px;

/* 字体 */
--tr-font-display: 'Inter', sans-serif; /* 标题/大数字 */
--tr-font-body: 'Inter', sans-serif; /* 正文 */
--tr-font-mono: 'JetBrains Mono', monospace; /* 数据显示 */

核心类型定义

ProgressStats (进度统计)

typescript
// core/types.ts
interface ProgressStats {
  totalDistance: number;
  totalSessions: number;
  currentWeek: number;
  totalWeeks: number;
  weeklyDistance: number;
  weeklyTarget: number;
  dailyDistances?: number[]; // [Mon=0, Tue=1, ..., Sun=6]
  dailyTargets?: number[]; // 每日计划距离,用于柱状图 100% 基准
}

ComputedProgressStats (扩展统计,由 compute-stats.ts 返回)

typescript
// utils/compute-stats.ts
interface ComputedProgressStats extends ProgressStats {
  weeklySessionCount: number; // 本周训练次数
  weeklyCalories: number; // 本周总卡路里
  weeklyAvgPace?: string; // 本周加权平均配速
}

WorkoutRecord (Strava 实际训练记录)

typescript
// core/types.ts
interface WorkoutRecord {
  date: string; // "2026-02-03"
  type: 'run' | 'walk' | 'strength' | 'rest';
  name: string; // "热身跑"
  timeRange?: string; // "19:52-20:09"
  location?: string; // "Fuzhou"
  duration: string; // "0:17:20"
  distance: number; // 2.31 (km)
  activeCalories: number;
  totalCalories: number;
  elevation: number; // 2 (m)
  avgPower?: number; // 160 (W)
  avgCadence?: number; // 177 (SPM)
  avgPace: string; // "7'29\"/km"
  avgHeartRate: number; // 135
  effort: EffortLevel; // 1-10
  effortDescription: 'Easy' | 'Moderate' | 'Hard' | 'All Out';
  zoneDistribution?: ZoneDistribution[];
}

interface ZoneDistribution {
  zone: 1 | 2 | 3 | 4 | 5;
  duration: string; // "35:20"
  percentage?: number; // 0-100
}

TrainingSession (计划训练)

typescript
// core/types.ts
interface TrainingSession {
  type: TrainingType;
  name: string; // "节奏跑"
  details: string; // 多行文本
  distance?: number; // 8 (km)
  duration?: number;
  targetHR?: { min: number; max: number };
  targetPace?: string; // "5:00/km"
  weekParity?: 'odd' | 'even'; // 单双周切换
  tips?: string; // 睡眠/饮食/补水建议 (多行文本)
}

TrainingCycle (训练周期)

typescript
// core/types.ts
interface TrainingCycle {
  name: string; // "基础期"
  weeks: number; // 12
  phase: 'base' | 'build' | 'peak' | 'taper';
  description?: string;
}

PersonalRecord (个人纪录)

typescript
// core/types.ts
interface PersonalRecord {
  distance: string; // "1km"
  time: string; // "4:30"
  date: string; // "2026-01-21"
  dateDisplay: string; // "2026年1月21日"
}

暗色模式

通过 VitePress 的 .dark class 自动激活:

css
.dark {
  --tr-bg: #0f172a;
  --tr-bg-card: #1e293b;
  --tr-bg-card-hover: rgba(255, 255, 255, 0.03);
  --tr-text: #f8fafc;
  --tr-text-muted: #94a3b8;
  --tr-border: #334155;
}

弹窗通用模式

所有弹窗遵循相同结构:

css
/* Overlay */
.{prefix}-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(8px);
  z-index: 1000;           /* WorkoutModal: 1010 */
  animation: {prefix}-fade-in 200ms ease-out;
}

/* Modal */
.{prefix}-modal {
  background: var(--tr-bg-card);
  border-radius: var(--tr-radius-lg);
  max-width: 440px;        /* WorkoutModal: 480px */
  max-height: 85vh;
  animation: {prefix}-slide-up 250ms cubic-bezier(0.16, 1, 0.3, 1);
}

/* Header */
.{prefix}-header {
  padding: 12px var(--tr-space-lg);  /* 紧凑头部 */
  position: sticky; top: 0;
  border-bottom: 1px solid var(--tr-border);
}

/* Close button */
.{prefix}-header__close {
  width: 28px; height: 28px;
  border-radius: var(--tr-radius-full);
}

响应式断点

css
/* 平板 */
@media (max-width: 768px) {
  .tr-progress__stats { grid-template-columns: repeat(2, 1fr); }
}

/* 移动端 - 弹窗变 bottom sheet */
@media (max-width: 480px) {
  .{prefix}-overlay { align-items: flex-end; padding: 0; }
  .{prefix}-modal {
    max-height: 90vh;
    border-radius: var(--tr-radius-lg) var(--tr-radius-lg) 0 0;
    animation: {prefix}-slide-up-mobile 300ms;  /* 从底部滑入 */
  }
  .tr-progress__stats { grid-template-columns: 1fr; }
  .tdm-workout__stats { grid-template-columns: repeat(2, 1fr); }
}

Contributors

Changelog

Discuss

Released under the CC BY-SA 4.0 License. (134a8ec)