feat: apply standard login page design
ci / gitleaks (push) Successful in 1m27s
ci / docker (push) Successful in 9m25s

This commit is contained in:
2026-09-20 09:11:35 +08:00
parent ed123b710f
commit f7e7404c31
4 changed files with 59 additions and 9 deletions
+7 -5
View File
@@ -1511,13 +1511,15 @@ onUnmounted(() => {
<template>
<div v-if="!authReady" class="center loading-brand"><img class="loading-logo" src="/dodo-logo.svg" alt=""><span class="loader" /><span>正在打开 dodo</span></div>
<div v-else-if="!authenticated" class="auth-shell">
<section class="auth-card">
<div class="brand brand-lockup"><img class="brand-logo" src="/dodo-logo.svg" alt=""><span class="brand-wordmark">dodo</span></div><p>{{ initialized ? '欢迎回来,继续把生活理顺。' : '创建你的 dodo' }}</p>
<form class="auth-card" aria-labelledby="auth-title" @submit.prevent="submitAuth">
<div class="auth-brand"><div class="brand brand-lockup"><img class="brand-logo" src="/dodo-logo.svg" alt=""><span class="brand-wordmark">dodo</span></div></div>
<div class="auth-heading"><h1 id="auth-title">{{ initialized ? '欢迎回来' : '创建你的 dodo' }}</h1><p>{{ initialized ? '登录后继续处理今天的事项。' : '创建账号后开始整理你的事项。' }}</p></div>
<label>用户名<input v-model="username" autocomplete="username" placeholder="你的用户名"></label>
<label>密码<input v-model="password" type="password" autocomplete="current-password" placeholder="至少 12 位" @keyup.enter="submitAuth"></label>
<button class="primary" @click="submitAuth">{{ initialized ? '登录' : '开始使用' }}</button>
<label>密码<input v-model="password" type="password" autocomplete="current-password" placeholder="至少 12 位"></label>
<button type="submit" class="primary">{{ initialized ? '登录' : '开始使用' }}</button>
<small v-if="error" role="alert">{{ error }}</small>
</section>
<p v-if="initialized" class="auth-footnote">登录后继续你的清单</p>
</form>
</div>
<div v-else class="shell" :class="{ 'today-active': activeView==='today', 'sidebar-collapsed': sidebarCollapsed, 'detail-open': Boolean(selectedTask), 'memo-detail-open': activeView==='memos' && memoDetailOpen, 'mobile-sidebar-open': mobileSidebar }">
<div v-if="mobileSidebar || mobileDetail" class="scrim" @click="mobileSidebar=false;mobileDetail=false" />
File diff suppressed because one or more lines are too long
+21 -1
View File
@@ -481,7 +481,27 @@ describe('completion feedback motion', () => {
expect(css).toContain('@media(prefers-reduced-motion:reduce){.task-row.just-completed,.habit-row.just-completed,.task-row.just-completed .task-check-mark,.habit-row.just-completed .task-check-mark{animation:none}.task-row.completion-exiting,.habit-row.completion-exiting{animation:none}}')
})
it('syncs the browser IANA timezone before loading user task data', () => {
it('stacks the desktop calendar copy to align with weather and gold', () => {
expect(css).toContain('@media(min-width:721px){.today-environment__calendar{flex-direction:column;align-items:flex-start;gap:0}.today-environment__calendar small{margin-top:2px;font-size:10.5px}}')
})
it('uses the approved internal-standard login composition and material tokens', () => {
expect(app).toContain('class="auth-brand"')
expect(app).toContain('class="brand brand-lockup"')
expect(app).toContain('<h1 id="auth-title">{{ initialized ? \'欢迎回来\' : \'创建你的 dodo\' }}</h1>')
expect(app).toContain("{{ initialized ? '登录后继续处理今天的事项。' : '创建账号后开始整理你的事项。' }}")
expect(app).toContain('<p v-if="initialized" class="auth-footnote">登录后继续你的清单</p>')
expect(app).toContain('<form class="auth-card" aria-labelledby="auth-title" @submit.prevent="submitAuth">')
expect(app).toContain('<button type="submit" class="primary">')
expect(css).toMatch(/\.auth-card\{[^}]*width:min\(400px,100%\)[^}]*padding:36px[^}]*border:1px solid var\(--border-cream\)[^}]*border-radius:var\(--radius-card\)/)
expect(css).toContain('.auth-brand .brand{gap:9px;font-size:28px;letter-spacing:-2px}')
expect(css).toContain('.auth-brand .brand-logo{width:34px;height:34px}')
expect(css).toMatch(/\.auth-card input\{[^}]*min-height:46px[^}]*background:var\(--surface-raised\)/)
expect(css).toContain('.auth-card>.primary{min-height:46px}')
expect(css).toMatch(/@media\(max-width:930px\)\{\.auth-shell\{padding:18px\}\.auth-card\{padding:30px 24px\}/)
})
it('syncs browser IANA timezone before loading user task data', () => {
expect(app).toContain("Intl.DateTimeFormat().resolvedOptions().timeZone")
expect(app).toContain("await api('/me', { method: 'PATCH', body: JSON.stringify({ timezone }) })")
const bootstrapBlock = app.slice(app.indexOf('async function bootstrap()'), app.indexOf('async function submitAuth()'))