style: refine Today environment header
This commit is contained in:
@@ -99,14 +99,53 @@ describe('TodayEnvironmentStrip', () => {
|
||||
expect(goldDate?.getAttribute('aria-label')).toBe('市场日期 2026-09-15')
|
||||
})
|
||||
|
||||
it('keeps mobile content to a horizontal calendar row and two stacked source columns', () => {
|
||||
it('shows edit-line state only when attention is required', async () => {
|
||||
const fresh = await mountStrip({ environment: { ...environment, gold: { ...environment.gold!, status: 'fresh' } } })
|
||||
expect(fresh.querySelector('.today-environment')?.classList.contains('has-attention')).toBe(false)
|
||||
expect(fresh.querySelector('.today-environment__status')?.textContent).toBe('')
|
||||
|
||||
const refreshing = await mountStrip({ environment, loading: true })
|
||||
expect(refreshing.querySelector('.today-environment')?.classList.contains('is-refreshing')).toBe(true)
|
||||
expect(refreshing.querySelector('.today-environment__status')?.textContent).toContain('更新中')
|
||||
|
||||
const failed = await mountStrip({ environment, failed: true })
|
||||
expect(failed.querySelector('.today-environment')?.classList.contains('has-attention')).toBe(true)
|
||||
expect(failed.querySelector('.today-environment__status')?.textContent).toContain('更新失败 · 上次信息')
|
||||
})
|
||||
|
||||
it('renders unavailable sources as two-line placeholders without adding a status row', async () => {
|
||||
const host = await mountStrip({ environment: {
|
||||
calendar: environment.calendar,
|
||||
weather: { status: 'unavailable' },
|
||||
gold: { status: 'unavailable' },
|
||||
} })
|
||||
expect(host.querySelectorAll('.today-environment__skeleton')).toHaveLength(4)
|
||||
expect(host.querySelectorAll('.today-environment__weather > .today-environment__skeleton')).toHaveLength(2)
|
||||
expect(host.querySelectorAll('.today-environment__gold > .today-environment__skeleton')).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('uses the approved cream edit-line typography and separators', () => {
|
||||
const css = readFileSync(resolve(process.cwd(), 'src/style.css'), 'utf8')
|
||||
expect(css).toContain('.today-environment__status:not(.today-environment__state){position:absolute;width:1px;height:1px;')
|
||||
expect(css).toContain('@container(max-width:559px){.today-environment{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);')
|
||||
expect(css).toContain('.today-environment__calendar{grid-column:1/-1;grid-row:1;display:flex;flex-direction:row;padding-right:0}')
|
||||
expect(css).toContain('.today-environment__weather,.today-environment__gold{display:flex;flex-direction:column;align-items:flex-start;gap:2px}')
|
||||
expect(css).toContain('.today-environment{grid-column:1/-1;position:relative;min-width:0;min-height:40px;')
|
||||
expect(css).toContain('color:#302a24;font-size:14px;font-weight:650')
|
||||
expect(css).toContain('color:#655b50;font-size:12px;font-weight:450')
|
||||
expect(css).toContain('color:#8b8275;font-size:11px;font-weight:400')
|
||||
expect(css).toContain('.today-environment:after{content:"";position:absolute;left:10px;right:10px;bottom:0;height:1px;background:#e4d5c0}')
|
||||
expect(css).toContain('.today-environment.has-attention:before{content:"";width:2px;height:14px;background:#f15a29')
|
||||
expect(css).not.toContain('border-left:1px solid var(--border-cream)')
|
||||
expect(css).not.toMatch(/\.today-environment[^}]*gradient|\.today-environment[^}]*box-shadow|\.today-environment[^}]*backdrop-filter/)
|
||||
})
|
||||
|
||||
it('keeps mobile content to exactly two parent rows with stacked source columns', () => {
|
||||
const css = readFileSync(resolve(process.cwd(), 'src/style.css'), 'utf8')
|
||||
expect(css).toContain('@container(max-width:559px){.today-environment{min-height:68px;display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);grid-template-rows:auto auto;column-gap:14px;')
|
||||
expect(css).toContain('.today-environment__calendar{grid-column:1/-1;grid-row:1;display:flex;flex-direction:row;')
|
||||
expect(css).toContain('.today-environment__weather,.today-environment__gold{display:flex;flex-direction:column;align-items:flex-start;gap:2px;overflow:visible}')
|
||||
expect(css).toContain('.today-environment__gold{grid-column:2;grid-row:2;padding-left:14px}')
|
||||
expect(css).toContain('.today-environment__gold:before{content:"";position:absolute;left:0;top:4px;width:1px;height:14px;background:#e4d5c0}')
|
||||
expect(css).toContain('.today-environment__calendar-main--desktop,.today-environment__gold-date--desktop{display:none}')
|
||||
expect(css).toContain('.today-environment__calendar-main--mobile,.today-environment__gold-date--mobile{display:inline}')
|
||||
expect(css).not.toContain('.today-environment__calendar{padding-right:42%}')
|
||||
const mobileBlock = css.slice(css.indexOf('@container(max-width:559px){.today-environment'), css.indexOf('/* Solid cream material system'))
|
||||
expect(mobileBlock).not.toContain('text-overflow:ellipsis')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -100,7 +100,12 @@ const weatherObservation = computed(() => {
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="today-environment" aria-label="今日环境信息" :aria-busy="loading">
|
||||
<div
|
||||
class="today-environment"
|
||||
:class="{ 'is-refreshing': loading && !!environment, 'has-attention': (loading && !!environment) || failed }"
|
||||
aria-label="今日环境信息"
|
||||
:aria-busy="loading"
|
||||
>
|
||||
<span v-if="!environment && loading" class="today-environment__state today-environment__status" role="status" aria-live="polite">环境信息加载中…</span>
|
||||
<span v-else-if="!environment" class="today-environment__state today-environment__status" role="status" aria-live="polite">环境信息暂不可用</span>
|
||||
<template v-else>
|
||||
@@ -108,18 +113,30 @@ const weatherObservation = computed(() => {
|
||||
<strong class="today-environment__calendar-main--desktop">{{ calendar.solar_date }} {{ calendar.weekday }}</strong>
|
||||
<strong class="today-environment__calendar-main--mobile" :aria-label="`${calendar.solar_date} ${calendar.weekday}`">{{ mobileCalendarDate }}</strong>
|
||||
<small>{{ calendar.lunar_date }}</small>
|
||||
<span class="today-environment__status" role="status" aria-live="polite"><template v-if="loading">更新中</template><template v-else-if="failed">更新失败 · 上次信息</template></span>
|
||||
</span>
|
||||
<span class="today-environment__item today-environment__weather" :class="`is-${weatherStatus}`">
|
||||
<strong v-if="weatherStatus !== 'unavailable'">{{ environment.weather?.location || '宁波海曙' }} · {{ weatherText }}<template v-if="environment.weather?.temperature_c != null"> {{ environment.weather.temperature_c }}°C</template></strong>
|
||||
<strong v-else>宁波海曙天气暂不可用</strong>
|
||||
<small v-if="weatherStatus !== 'unavailable'">{{ weatherObservation }}<template v-if="weatherStatus === 'stale'"> · 缓存</template></small>
|
||||
<template v-if="weatherStatus !== 'unavailable'">
|
||||
<strong>{{ environment.weather?.location || '宁波海曙' }} · {{ weatherText }}<template v-if="environment.weather?.temperature_c != null"> {{ environment.weather.temperature_c }}°C</template></strong>
|
||||
<small>{{ weatherObservation }}<template v-if="weatherStatus === 'stale'"> · 缓存</template></small>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="today-environment__skeleton" aria-hidden="true"></span>
|
||||
<span class="today-environment__skeleton today-environment__skeleton--short" aria-hidden="true"></span>
|
||||
<span class="sr-only">宁波海曙天气暂不可用</span>
|
||||
</template>
|
||||
</span>
|
||||
<span class="today-environment__item today-environment__gold" :class="`is-${goldStatus}`">
|
||||
<strong v-if="goldStatus !== 'unavailable' && goldPrice">{{ environment.gold?.symbol || environment.gold?.contract || 'Au99.99' }} ¥{{ goldPrice }}/g</strong>
|
||||
<strong v-else>Au99.99 暂不可用</strong>
|
||||
<small><template v-if="goldStatus !== 'unavailable'">上金所延时<template v-if="goldMarketDate"> · <span class="today-environment__gold-date today-environment__gold-date--desktop">{{ goldMarketDate }}</span><span class="today-environment__gold-date today-environment__gold-date--mobile" :title="`市场日期 ${goldMarketDate}`" :aria-label="`市场日期 ${goldMarketDate}`">{{ mobileGoldMarketDate }}</span></template></template><template v-if="goldStatus === 'stale'"> · 缓存</template></small>
|
||||
<template v-if="goldStatus !== 'unavailable' && goldPrice">
|
||||
<strong>{{ environment.gold?.symbol || environment.gold?.contract || 'Au99.99' }} ¥{{ goldPrice }}/g</strong>
|
||||
<small>上金所延时<template v-if="goldMarketDate"> · <span class="today-environment__gold-date today-environment__gold-date--desktop">{{ goldMarketDate }}</span><span class="today-environment__gold-date today-environment__gold-date--mobile" :title="`市场日期 ${goldMarketDate}`" :aria-label="`市场日期 ${goldMarketDate}`">{{ mobileGoldMarketDate }}</span></template><template v-if="goldStatus === 'stale'"> · 缓存</template></small>
|
||||
</template>
|
||||
<template v-else>
|
||||
<span class="today-environment__skeleton" aria-hidden="true"></span>
|
||||
<span class="today-environment__skeleton today-environment__skeleton--short" aria-hidden="true"></span>
|
||||
<span class="sr-only">Au99.99 暂不可用</span>
|
||||
</template>
|
||||
</span>
|
||||
<span class="today-environment__status" role="status" aria-live="polite"><template v-if="loading">更新中…</template><template v-else-if="failed">更新失败,显示上次信息</template></span>
|
||||
</template>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user