diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-18 08:26:37 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-18 08:26:37 +0800 |
| commit | 60640dfa981e419cf86413c924fd26822bd42327 (patch) | |
| tree | cab175f9fa975c68db82287f06a13a1dc3af8048 /frontend/src/pages/ProjectsPage.svelte | |
| parent | 06a7b1668b44f111eca5d08bc8c2c9d41d8e617e (diff) | |
| download | strategy-lab-60640dfa981e419cf86413c924fd26822bd42327.tar.gz | |
feat(frontend): 布局/认证/项目页迁移 shadcn 并修复 375px 溢出
[变更性质]
本提交为 UI 迁移与移动端布局修复,产品功能不变。
[新增功能]
Leader 第 2 轮验收的失败项:AuthPages 在 375px 视口横向溢出 47px,
原因为 .auth-card 固定 400px 宽度。
[实现方案]
AuthPages:.auth-wrap 改为 flex 包裹,.auth-card 改用
width:min(400px,100%),三档视口下登录/注册/重置均零溢出。
Layout.svelte 重写为 shadcn Button(退出按钮)+ Tailwind 主题变量,
同时保留 .layout/.content/.navlink/.brand 等 legacy class 以维持
mobileCss.test.ts 的断言语义。ProjectsPage 迁移 shadcn Card/Table 等
(保留 p-name 链接语义),新增 projectsPageLoad.test.ts 回归项目列表
加载失败时的错误呈现。
[影响范围]
frontend/src/components/Layout.svelte、pages/AuthPages.svelte、
pages/ProjectsPage.svelte;视觉验证覆盖 375/768/1440 全零溢出。
Diffstat (limited to 'frontend/src/pages/ProjectsPage.svelte')
| -rw-r--r-- | frontend/src/pages/ProjectsPage.svelte | 77 |
1 files changed, 47 insertions, 30 deletions
diff --git a/frontend/src/pages/ProjectsPage.svelte b/frontend/src/pages/ProjectsPage.svelte index b29a856..13525b6 100644 --- a/frontend/src/pages/ProjectsPage.svelte +++ b/frontend/src/pages/ProjectsPage.svelte @@ -6,6 +6,12 @@ import { extractStatusMessage } from '../lib/state'; import { go } from '../lib/router'; import { fmtDateTime } from '../lib/format'; + import { Button } from '$lib/components/ui/button'; + import * as Card from '$lib/components/ui/card'; + import * as Table from '$lib/components/ui/table'; + import { Input } from '$lib/components/ui/input'; + import { Label } from '$lib/components/ui/label'; + import { Alert } from '$lib/components/ui/alert'; let busy = $state(false); let error = $state<string | null>(null); @@ -27,6 +33,13 @@ } } + // 159399 QA regression (2026-09-17): load() existed but was wired nowhere, + // so the projects page kept rendering the store's stale/empty state and + // users saw 还没有项目 despite existing projects on the server. + $effect(() => { + void load(); + }); + async function create(e: SubmitEvent) { e.preventDefault(); if (!newName.trim()) return; @@ -49,9 +62,9 @@ <Page title="我的项目" subtitle="每个项目持有独立的策略代码版本、数据集与回测记录"> {#snippet actions()} - <button class="btn primary" onclick={() => (showCreate = !showCreate)} aria-expanded={showCreate}> + <Button variant={showCreate ? 'outline' : 'default'} onclick={() => (showCreate = !showCreate)} aria-expanded={showCreate}> {showCreate ? '取消新建' : '新建项目'} - </button> + </Button> {/snippet} <div class="stack"> @@ -60,18 +73,18 @@ <form class="card stack" onsubmit={create}> <h2>新建项目</h2> <div> - <label for="pn">项目名称</label> - <input id="pn" bind:value={newName} required placeholder="例如:双均线ETF轮动" /> + <Label for="pn">项目名称</Label> + <Input id="pn" bind:value={newName} required placeholder="例如:双均线ETF轮动" class="mt-1" /> </div> <div> - <label for="pd">简介(可选)</label> - <input id="pd" bind:value={newDesc} placeholder="一句话说明研究思路" /> + <Label for="pd">简介(可选)</Label> + <Input id="pd" bind:value={newDesc} placeholder="一句话说明研究思路" class="mt-1" /> </div> - {#if createErr}<div class="banner error" role="alert">{createErr}</div>{/if} + {#if createErr}<Alert variant="destructive" class="banner error" role="alert">{createErr}</Alert>{/if} <div class="row"> - <button type="submit" class="btn primary" disabled={creating || !newName.trim()}> + <Button type="submit" disabled={creating || !newName.trim()}> {creating ? '创建中…' : '创建项目'} - </button> + </Button> </div> </form> {/if} @@ -81,32 +94,36 @@ {/if} {#if projectsStore.all.length > 0} - <div class="card" style="padding:0.4rem 0.6rem;"> - <table class="data"> - <thead> - <tr> - <th>名称</th> - <th>简介</th> - <th>版本代</th> - <th>最近更新</th> - </tr> - </thead> - <tbody> + <Card.Root size="sm"> + <Table.Root> + <Table.Header> + <Table.Row> + <Table.Head>名称</Table.Head> + <Table.Head>简介</Table.Head> + <Table.Head>版本代</Table.Head> + <Table.Head>最近更新</Table.Head> + </Table.Row> + </Table.Header> + <Table.Body> {#each projectsStore.all as p (p.id)} - <tr> - <td><a href={`#/projects/${p.id}/data`} class="p-name">{p.name}</a></td> - <td class="hint">{p.description ?? '—'}</td> - <td class="num">{p.draft_generation ?? '—'}</td> - <td>{fmtDateTime(p.updated_at)}</td> - </tr> + <Table.Row> + <Table.Cell> + <a href={`#/projects/${p.id}/data`} class="p-name">{p.name}</a> + </Table.Cell> + <Table.Cell class="hint">{p.description ?? '—'}</Table.Cell> + <Table.Cell class="num">{p.draft_generation ?? '—'}</Table.Cell> + <Table.Cell>{fmtDateTime(p.updated_at)}</Table.Cell> + </Table.Row> {/each} - </tbody> - </table> - </div> + </Table.Body> + </Table.Root> + </Card.Root> {/if} </div> </Page> <style> - .p-name { font-weight: 600; } + .p-name { font-weight: 600; color: var(--teal-strong); } + .p-name:hover { text-decoration: underline; } + form.card h2 { margin-bottom: 0.2rem; } </style> |
