feat: 落地 Warm Kitchen Ledger 原型,宽屏左导航 + 双栏布局

新增 ledger.css 设计令牌与桌面端布局,AppRail 左导航、PageHead 桌面页头、ResultsColumn 常驻结果栏;做菜/菜谱/发现/我的/设置/帮助/关于各页做桌面窄屏双形态适配,窄屏仍走原有底部标签栏与弹层交互。
This commit is contained in:
toor
2026-10-22 03:30:56 +08:00
committed by trae-solo-agent
parent 7049eb02a8
commit 7408591fac
18 changed files with 3604 additions and 383 deletions
@@ -59,7 +59,7 @@ function remove(name: string) {
@ion-input="onInput"
@keydown.enter.prevent="add()"
/>
<div v-if="suggestions.length" class="ingredient-input-row" role="listbox" aria-label="食材建议">
<div v-if="suggestions.length" class="ingredient-input-row ingredient-input-suggestions" role="listbox" aria-label="食材建议">
<button v-for="item in suggestions" :key="item.name" type="button" class="ingredient-suggestion" role="option" @click="add(item.name)">
<span aria-hidden="true">{{ item.emoji }}</span> {{ item.name }}
</button>
@@ -67,7 +67,10 @@ function remove(name: string) {
<p v-else-if="message" class="ingredient-input-message" role="status">
{{ message }}
</p>
<TransitionGroup v-if="selected.length" tag="div" name="ingredient-token" class="ingredient-input-row" aria-label="已选食材">
<p v-if="!selected.length" class="ingredient-input-empty">
还没选食材 —— 下面挑几样,或者直接搜名字
</p>
<TransitionGroup v-if="selected.length" tag="div" name="ingredient-token" class="ingredient-input-row ingredient-input-tokens" aria-label="已选食材">
<button v-for="name in selected" :key="name" type="button" class="ingredient-token" :aria-label="`移除${name}`" @click="remove(name)">
{{ name }}<ion-icon :icon="ioniconsClose" aria-hidden="true" />
</button>
@@ -128,6 +131,9 @@ function remove(name: string) {
font-size: 13px;
color: var(--ion-color-medium);
}
.ingredient-input-empty {
display: none;
}
.ingredient-token-enter-active,
.ingredient-token-leave-active {
transition:
@@ -145,6 +151,86 @@ function remove(name: string) {
.ingredient-token-move {
transition: transform 0.24s cubic-bezier(0.2, 0.8, 0.2, 1);
}
@media (min-width: 1024px) {
/* 桌面端:已选食材在上面的托盘里,搜索框在下面 */
.ingredient-input {
display: flex;
flex-direction: column;
gap: 12px;
margin-bottom: 24px;
}
.ingredient-input-field {
order: 3;
padding-inline: 0;
padding-bottom: 0;
--background: var(--ledger-surface);
--box-shadow: inset 0 0 0 1px var(--ledger-border);
--border-radius: var(--ledger-r-pill);
--color: var(--ledger-text);
--icon-color: var(--ledger-text-mute);
--placeholder-color: var(--ledger-text-mute);
--placeholder-opacity: 1;
--height: 44px;
border-radius: var(--ledger-r-pill);
background: var(--ledger-surface);
}
.ingredient-input-suggestions {
order: 4;
flex-wrap: wrap;
padding: 0;
overflow: visible;
}
.ingredient-input-message {
order: 5;
padding: 0;
}
.ingredient-input-tokens {
order: 1;
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 8px;
min-height: 62px;
padding: 12px;
overflow: visible;
border: 1px solid var(--ledger-border);
border-radius: var(--ledger-r-lg);
background: var(--ledger-surface);
box-shadow: var(--ledger-sh-sm);
}
.ingredient-input-empty {
order: 2;
display: flex;
align-items: center;
min-height: 62px;
padding: 12px;
margin: 0;
border: 1px solid var(--ledger-border);
border-radius: var(--ledger-r-lg);
background: var(--ledger-surface);
box-shadow: var(--ledger-sh-sm);
color: var(--ledger-text-mute);
font-size: var(--ledger-t-13);
}
.ingredient-token {
height: 34px;
padding: 0 8px 0 12px;
border-radius: var(--ledger-r-pill);
background: var(--ledger-primary-soft);
color: var(--ledger-primary-ink);
font-size: var(--ledger-t-14);
}
.ingredient-suggestion {
height: 34px;
border: 1px solid var(--ledger-border);
border-radius: var(--ledger-r-pill);
background: var(--ledger-surface);
color: var(--ledger-text);
font-size: var(--ledger-t-14);
}
}
@media (prefers-reduced-motion: reduce) {
.ingredient-token-enter-active,
.ingredient-token-leave-active,