feat: add frontend design system and responsive shell

This commit is contained in:
liyy 2026-08-28 12:25:20 +08:00
parent 98505f3a91
commit ab3eacefba
7 changed files with 41 additions and 2 deletions

View File

@ -0,0 +1,4 @@
<script setup lang="ts">
withDefaults(defineProps<{ variant?: 'primary' | 'secondary' | 'soft' }>(), { variant: 'primary' })
</script>
<template><button :class="['base-button', `base-button--${variant}`]"><slot /></button></template>

View File

@ -0,0 +1 @@
<template><section class="base-card"><slot /></section></template>

View File

@ -0,0 +1,2 @@
<script setup lang="ts">defineProps<{ title: string; description?: string }>()</script>
<template><div class="empty-state"><div class="empty-state__icon"></div><h3>{{ title }}</h3><p v-if="description">{{ description }}</p><slot /></div></template>

View File

@ -0,0 +1,2 @@
<script setup lang="ts">defineProps<{ message?: string }>()</script>
<template><div class="error-state"><strong>暂时无法加载</strong><p>{{ message ?? '请检查服务是否已启动,然后重试。' }}</p><button class="base-button base-button--secondary">重新加载</button></div></template>

View File

@ -1 +1,2 @@
:root{font-family:Arial,"PingFang SC",sans-serif;color:#1a1f2e;background:#f7f6f2;font-synthesis:none}*{box-sizing:border-box}body{margin:0}.app-shell{min-height:100vh}.sidebar{position:fixed;inset:0 auto 0 0;width:220px;padding:16px 10px;background:#fff;border-right:1px solid #e8e6e0;display:flex;flex-direction:column;gap:7px}.brand{height:36px;display:flex;align-items:center;gap:9px}.brand span{display:grid;place-items:center;width:28px;height:28px;background:#2b4c8f;border-radius:8px;color:white}.nav-item{border:0;background:transparent;color:#6b7280;height:40px;border-radius:10px;text-align:left;padding:0 12px;cursor:pointer;font-size:13px}.nav-item.active{background:#2b4c8f;color:#fff}.sidebar-spacer{flex:1}.content{margin-left:220px;padding:32px;max-width:1250px}header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:20px}h1{font-size:24px;margin:0 0 5px}h2{margin:0 0 8px}p{font-size:13px;color:#6b7280;margin:0;line-height:1.5}.primary{height:40px;border:0;border-radius:10px;padding:0 16px;background:#2b4c8f;color:#fff;font-weight:600;cursor:pointer}.welcome{background:#fff;border:1px solid #e8e6e0;border-radius:16px;padding:24px}.mobile-tabs{display:none}@media(max-width:767px){.sidebar{display:none}.content{margin:0;padding:28px 24px 110px}.content header{margin-bottom:24px}.content h1{font-size:22px}.mobile-tabs{position:fixed;display:flex;z-index:2;left:16px;right:16px;bottom:16px;height:70px;background:#fff;border:1px solid #e8e6e0;border-radius:30px;box-shadow:0 4px 12px rgba(27,45,91,.08);justify-content:space-around;padding:8px}.mobile-tabs button{border:0;background:transparent;color:#9ca2ad;font-size:10px;display:flex;flex-direction:column;align-items:center;gap:4px;border-radius:24px;padding:7px 9px}.mobile-tabs button.active{background:#2b4c8f;color:#fff}.mobile-tabs span{font-size:17px}.primary{height:36px;padding:0 11px;font-size:12px}}
@import url('../../../deliverables/design/design-tokens.css');
:root{font-family:var(--font-sans);color:var(--text-primary);background:var(--bg-canvas);font-synthesis:none}*{box-sizing:border-box}body{margin:0}.app-shell{min-height:100vh}.sidebar{position:fixed;inset:0 auto 0 0;width:var(--sidebar-width-desktop);padding:16px 10px;background:var(--bg-card);border-right:1px solid var(--border-subtle);display:flex;flex-direction:column;gap:7px}.brand{height:36px;display:flex;align-items:center;gap:9px}.brand span{display:grid;place-items:center;width:28px;height:28px;background:var(--primary);border-radius:var(--radius-sm);color:var(--on-accent)}.nav-item{border:0;background:transparent;color:var(--text-secondary);height:40px;border-radius:10px;text-align:left;padding:0 12px;cursor:pointer;font-size:13px}.nav-item.active{background:var(--primary);color:var(--on-accent)}.sidebar-spacer{flex:1}.content{margin-left:var(--sidebar-width-desktop);padding:var(--padding-desktop);max-width:1250px}header{display:flex;align-items:flex-start;justify-content:space-between;margin-bottom:20px}h1{font:var(--fw-h1) var(--fs-h1)/var(--lh-h1) var(--ff-h1);margin:0 0 5px}h2{margin:0 0 8px}p{font:var(--fw-subtitle) var(--fs-subtitle)/var(--lh-subtitle) var(--ff-subtitle);color:var(--text-secondary);margin:0}.primary,.base-button{height:var(--btn-height);border:0;border-radius:var(--radius-btn);padding:0 16px;background:var(--primary);color:var(--on-accent);font:var(--fw-button) var(--fs-button)/var(--lh-button) var(--ff-button);cursor:pointer}.base-button--secondary{background:transparent;border:1px solid var(--primary);color:var(--primary)}.base-button--soft{background:var(--success-soft);color:var(--success)}.base-card{background:var(--bg-card);border:1px solid var(--border-subtle);border-radius:var(--radius-lg);padding:var(--card-padding-desktop)}.welcome{background:var(--bg-card);border:1px solid var(--border-subtle);border-radius:var(--radius-lg);padding:var(--card-padding-desktop)}.mobile-tabs{display:none}.empty-state,.error-state{text-align:center;padding:40px 20px;border:1px dashed var(--border-subtle);border-radius:var(--radius-lg);background:var(--bg-card)}.empty-state__icon{font-size:28px;color:var(--text-muted)}.empty-state h3,.error-state strong{display:block;margin:10px 0 6px}.error-state strong{color:var(--danger)}@media(max-width:767px){.sidebar{display:none}.content{margin:0;padding:28px 24px 110px}.content header{margin-bottom:24px}.content h1{font-size:22px}.mobile-tabs{position:fixed;display:flex;z-index:2;left:16px;right:16px;bottom:16px;height:70px;background:var(--bg-card);border:1px solid var(--border-subtle);border-radius:30px;box-shadow:var(--shadow-level-2);justify-content:space-around;padding:8px}.mobile-tabs button{border:0;background:transparent;color:var(--text-muted);font-size:10px;display:flex;flex-direction:column;align-items:center;gap:4px;border-radius:24px;padding:7px 9px}.mobile-tabs button.active{background:var(--primary);color:var(--on-accent)}.mobile-tabs span{font-size:17px}.primary,.base-button{height:36px;padding:0 11px;font-size:12px}.base-card{padding:var(--card-padding-mobile)}}

View File

@ -1,3 +1,7 @@
<script setup lang="ts">
import BaseCard from '../../components/base/BaseCard.vue'
</script>
<template>
<section class="welcome"><h2>备考通已就绪</h2><p>前端工程架构已启动后续任务将逐页还原原型并接入真实数据</p></section>
<BaseCard><h2>备考通已就绪</h2><p>前端工程架构已启动后续任务将逐页还原原型并接入真实数据</p></BaseCard>
</template>

25
docs/checks/task-03.md Normal file
View File

@ -0,0 +1,25 @@
# 任务 03 检查记录:前端基础视觉系统与响应式壳层
日期2026-08-28
## 命令检查
- `pnpm typecheck`通过server、client
- `pnpm build`通过server、client
- 设计 Token 已由全局样式引用:通过。
- 基础卡片、按钮、空状态、错误状态组件已建立:通过。
- PC 侧栏和 Mobile 底部导航共用业务状态:通过。
## 原型截图对比
- 对照原型的视觉基线检查了浅米白画布、白色卡片、深蓝主色、16px 卡片圆角、PC 侧栏和移动底部胶囊导航。
- 当前页面仍是骨架,数据卡、图表和业务内容尚未实现;这些差异属于后续页面任务,未在本任务中伪造填充。
## 浏览器操作
- 之前已通过浏览器打开入口并点击导航验证选中态。
- 本任务修改后,原有浏览器标签页因开发服务重启显示不可访问,当前自动化环境无法刷新该标签页;已通过命令构建和 CSS/组件检查确认无编译问题,浏览器回归待服务稳定后补做。
## 当前结论
前端基础目录、设计 Token、基础组件和响应式壳层已完成页面级原型对齐将在对应业务页面实现时逐页截图复核。