# feed_list 清單層元件基準

> 目前路徑：元件已搬到 `design-system/`；現行組裝入口與檔案位置以 `../COMPONENTS.md` 為準。下文的 `prototype/*` 是 worker 交付當時的歷史路徑，保留作執行紀錄。

## 結論

[confirmed] 已完成可直接組裝的四條 root stack 清單層元件族：共同核心只有一套 `.stock-row`，今日、自選、市場以容器與狀態變體擴充；「我的」維持空殼並只提供筆記彙總入口。交付檔為 `prototype/lists.css` 與 `prototype/preview-lists.html`，不含 JavaScript，未修改 `tokens.css` 或其他 worker 檔案。

[confirmed] 價格、漲跌幅、迷你走勢、推薦理由與未定資訊均以骨架佔位；預覽中的 `2330 台積電`、`2408 南亞科` 只用於展示已知名稱／代號，沒有填入價格、漲跌幅、成交量或選股理由。漲／跌／平只以「漲態／跌態／平態」展示元件語意狀態，不構成個股資料。

[confirmed] `lists.css` 所有顏色、間距與字級均引用 `prototype/tokens.css` 既有變數；唯一彩色語意只出現在 `.stock-row--up`、`.stock-row--down`、`.stock-row--flat` 的 `.stock-row__change`。

## 1. 元件族盤點

[confirmed] 下表的「共用／專屬元件」來自本輪已落地的 HTML/CSS；OPEN 欄則維持 `unknown`，沒有由 worker 代定。

| root stack | 共用元件 | 專屬／加掛元件 | 不在本輪決定 |
|---|---|---|---|
| 今日 Feed | `.list-stack`、`.list-section-header`、`.stock-list`、`.stock-row`、骨架、`.empty-state` | `.feed-list`、`.feed-card`、`.reason-slot`、`.filter-strip` / `.filter-chip` | [unknown] 分組依據、排序、篩選名稱、推薦理由內容、選股邏輯 |
| 自選 | 同一套 `.stock-row` | `.list-edit-toolbar`、`.batch-bar`、`.drag-handle`、`.selection-control`、`.delete-control` | [unknown] 預設排序、批次動作業務規則 |
| 市場 | 同一套 `.stock-row`、`.list-section-header` | `.segmented-control`，固定容器選項為產業／排行／大盤 | [unknown] 各分類實際資訊與排序 |
| 我的 | `.list-stack`、骨架 | `.profile-shell`、`.destination-list` / `.destination-row` | [unknown] 設定細項；本輪只有筆記彙總入口 |

[confirmed] 共用股票列沒有為四條 stack 各做一套。差異只由 modifier class、leading/action 插槽與外層容器組合產生。

## 2. 重新觀察材料與證據邊界

- [confirmed] 現行 `DECISIONS.md` D0、D4、D5、D7 定義本輪是可沿用元件基準；今日是 Feed；個股由清單 push；我的只做空殼 + 筆記彙總；資訊位使用骨架。這些是本輪制度與已定事項。
- [confirmed] H1 `a-guided-brief/index.html` 實際存在「分組標籤 → 重點卡 → 一般 row」的層級；`styles.css` 實際把 focus card、watch row、divider row 分成不同密度。這只支持「同一清單層需要 row/card 密度變體」的素材觀察，不支持 H1 的內容、排序或資訊層級已採用。
- [confirmed] 0730 `app-shell.html` 實際存在 `feed-head`、`verdict-card`、`filter-row`、`discover-card`；`app.css` 實際把卡片、chip、空狀態分開定義。這只支持「分組、篩選、卡片、空狀態可拆成獨立元件」的素材觀察，不沿用其選股、判讀或舊 nav 結論。
- [unknown] H1 與 0730 的內容是否曾經真人驗證、是否有採用數據；本輪沒有把 Prototype 完整度視為證據。
- [coverage gap] 無。規格點名的 `AGENTS.md`、`DECISIONS.md`、`tokens.css`、H1 與 0730 可讀素材皆可讀取。

## 3. 股票列核心契約

必要 DOM：

```html
<article class="stock-row stock-row--up">
  <span class="stock-row__leading"><!-- 可省略／選取／拖曳 --></span>
  <button class="stock-row__primary" type="button">
    <span class="stock-row__identity">
      <span class="stock-row__name">股票名稱</span>
      <span class="stock-row__code">代號</span>
    </span>
    <span class="stock-row__quote"><!-- 價格與漲跌 --></span>
    <span class="stock-row__sparkline"><!-- 一律骨架 --></span>
  </button>
  <span class="stock-row__action"><!-- 加入、自選狀態、刪除或 chevron --></span>
</article>
```

[confirmed] `.stock-row` 不直接使用 `<button>`，因為右側動作、拖曳、刪除與選取本身也可能是按鈕；用非互動容器 + `.stock-row__primary` 避免巢狀 button，下一個 agent 可安全接 push handler。

[confirmed] 下表每個狀態／變體都已在 `preview-lists.html` 展示，或由相同 selector 明確定義。

| 狀態／變體 | class / attribute | 視覺與行為契約 |
|---|---|---|
| 漲 | `.stock-row--up` | 只有 `.stock-row__change` 使用 `--color-up`；數值未接時仍放骨架 |
| 跌 | `.stock-row--down` | 只有 `.stock-row__change` 使用 `--color-down` |
| 平 | `.stock-row--flat` | `.stock-row__change` 使用 `--color-flat` |
| pressed | `:active` 或 `.is-pressed` | 使用 `--color-accent-weak` 與縮放；不新增色票 |
| 已加入自選 | `.row-action--watch[aria-pressed="true"]` 或 `.is-watchlisted` | 灰階實心狀態，保留 `aria-pressed` |
| 未加入自選 | `.row-action--watch[aria-pressed="false"]` | 灰階空狀態 |
| 可拖曳 | `.stock-row--draggable` + `.drag-handle` | leading 顯示拖曳控制；實際 reorder 行為由組裝端接入 |
| 不可拖曳 | 不放 `.drag-handle` | leading 可省略，不保留無意義空間 |
| 載入 | `.stock-row--loading[aria-busy="true"]` | identity 兩條、quote 兩條、sparkline 一塊；action 隱藏、不可互動 |
| 選取 | `.is-selected` + `.selection-control[aria-pressed="true"]` | 灰階選取底與明確控制狀態；若組裝端採 listbox，才在正確 role 結構內加 `aria-selected` |
| 卡片 | `.stock-row--card` | 同一 DOM 加 border/radius/shadow，不複製另一套 row |
| 緊湊 | `.stock-row--compact` | 降低垂直密度，槽位與狀態不變 |

## 4. Feed、自選、市場、我的差異

- [confirmed] 今日：`.feed-list` 提供分組，`.feed-card` 組合共用股票列與 `.reason-slot`；`.filter-chip` 完成 selected / unselected / disabled。內容只放「分組標題位」「篩選 A」等結構文字與骨架。
- [confirmed] 自選：正常態只用 `.stock-row`；編輯態在 leading 放 `.drag-handle`、action 放 `.delete-control`；批次態換成 `.selection-control` 並接 `.batch-bar`。三種模式不改股票列內容 DOM。
- [confirmed] 市場：`.segmented-control` 承載產業／排行／大盤切換；其下仍用 `.list-section-header` + `.stock-row`，沒有另做市場卡片。
- [confirmed] 我的：`.profile-shell__placeholder` 保留未定資訊，唯一實際入口是 `.destination-row` 的「筆記彙總」。沒有發明設定項。
- [unknown] 批次操作要提供刪除、移動群組或其他行為；目前 `.batch-bar` 只提供插槽，不代定業務動作。

## 5. 骨架佔位規則

[confirmed] 下表是 `lists.css` 已實作的統一規則，不是金融資料或推算值。

| 資訊類型 | 固定規則 | class |
|---|---|---|
| 一般兩行文字 | 第一條 72%，第二條 52%；條間距 `--space-2` | `.skeleton-text-group--two-line` |
| 單行長／中／短 | 72% / 52% / 34% | `.skeleton-line--long` / `--medium` / `--short` |
| 股票數字位 | 右對齊；主行填滿 quote 槽、次行 64% | `.skeleton-text-group--numeric` |
| 獨立數字 | 26%，且最小寬度 `--space-12` | `.skeleton-line--number` |
| 迷你走勢 | 專屬矩形填滿 `.stock-row__sparkline`；不畫線、不填假走勢 | `.skeleton-block--sparkline` |
| 載入清單 | 至少重複同一 `.stock-row--loading` 結構；筆數由組裝端依 viewport 決定 | `.stock-row--loading` |

[confirmed] 所有骨架底色均為 `--color-skeleton`，沒有在個別元件重設灰階色。`--color-skeleton-shimmer` 目前未啟用，避免為靜態基準加入不必要動畫。

[inferred] 72 / 52 / 34 / 26% 是版位比例，不是產品數據；它們用來避免每個後續 agent 重新發明骨架寬度。若 PO 希望跨 worker 統一，建議未來在 `tokens.css` 增加 skeleton ratio tokens，本 worker未修改 token 契約。

## 6. 完整元件清單（組裝說明）

[confirmed] 下表每列都對應 `lists.css` 的現有 class；狀態、DOM 與 token 欄是本次可直接組裝的實作契約。

| 元件名（class） | 用途 | 狀態 | 變體 | 必要 DOM | token 依賴 |
|---|---|---|---|---|---|
| `.list-stack` | 四條 root stack 的清單層根容器 | default | flush 由 content 控制 | root 包 `.list-stack__content` | bg/text/font |
| `.list-stack__content` | 內容 padding 與 section gap | default | `--flush` | `.list-stack` 直屬內容 | spacing |
| `.list-section` | 通用內容分組 | default | 無 | header + list | spacing |
| `.stock-list` | 一般股票列集合 | default / busy 由外層 aria 表示 | 無 | 多個 `.stock-row` | spacing |
| `.feed-list` | Feed 分組與卡片集合 | default / `aria-busy` | 無 | section header + cards / loading rows | spacing |
| `.list-section-header` | 分組標題、輔助文字、右側動作 | default | copy/meta/action 可省略 | `__copy` + `__title`，選配 eyebrow/meta/action | text/spacing |
| `.filter-strip` | 可橫向滾動的 chip 容器 | default | 無 | 多個 `.filter-chip` | spacing |
| `.filter-chip` | Feed 篩選 | unselected / selected / disabled | 無 | button + `aria-pressed` 或 disabled | accent/border/radius/text/spacing/duration |
| `.segmented-control` | 市場分類切換 | selected / unselected | 固定三欄容器 | role tablist + 三個 `__option` | surface/border/radius/spacing/shadow |
| `.stock-row` | 股票列共同外殼 | pressed / selected / disabled / loading | `--up` / `--down` / `--flat` / `--card` / `--compact` / `--draggable` | leading + primary + action | surface/divider/border/radius/spacing/duration |
| `.stock-row__primary` | 進入個股的主要點擊區 | active / focus | button 或 anchor | identity + quote + sparkline | text/spacing/focus/duration |
| `.stock-row__identity` | 股票名稱、代號、輔助 meta | default / loading | 無 | name + code，可選 meta | text/font-mono/spacing |
| `.stock-row__quote` | 價格、漲跌槽 | up / down / flat / loading | 無 | price + change 或 numeric skeleton | text/font-mono/up/down/flat/spacing |
| `.stock-row__sparkline` | 迷你走勢槽 | skeleton | 無 | `.skeleton-block--sparkline` | skeleton/radius/spacing |
| `.stock-row__leading` | 編輯／選取前置控制槽 | empty / populated | drag / select | control button | spacing |
| `.stock-row__action` | 右側動作槽 | empty / populated | watch / delete / chevron | action button | spacing |
| `.row-action` | 加入自選或通用右側動作 | pressed / watchlisted / unwatchlisted | `--watch` | button + `aria-pressed` | accent-weak/text/radius/spacing |
| `.drag-handle` | 自選排序控制 | idle / active | 無 | button，實際拖曳由組裝端接 | text/radius/spacing |
| `.selection-control` | 批次選取 | selected / unselected | 無 | button + `aria-pressed` | accent/inverse/border/radius |
| `.delete-control` | 自選刪除入口 | idle / focus | 無 | button | surface/text/radius/spacing |
| `.feed-card` | 今日重點卡外殼 | default | 無 | stock-row + reason-slot | surface/border/radius/shadow |
| `.reason-slot` | Feed 推薦理由承載位 | skeleton / populated | 無 | label + content；本輪只展示 skeleton | surface/divider/text/radius/spacing |
| `.empty-state` | Feed / 自選 / 市場空狀態 | default | mark、CTA 可省略 | mark + title + copy + optional action | surface/border/radius/text/spacing |
| `.list-edit-toolbar` | 自選正常／編輯模式切換列 | normal / editing | 無 | label + actions | surface/border/radius/spacing |
| `.batch-bar` | 自選批次摘要與動作 | none-selected / selected 由內容表示 | 無 | summary + actions | surface/border/radius/spacing |
| `.text-action` | toolbar / empty-state 文字動作 | default / focus | `--filled` | button | accent/inverse/text/radius/spacing |
| `.destination-list` | 非股票目的地集合 | default | 無 | 多個 destination-row | surface/border/radius |
| `.destination-row` | 「我的」等清單入口列 | active / focus | 無 | copy(title/meta) + chevron | text/divider/spacing |
| `.profile-shell` | 「我的」空殼 | default | 無 | placeholder + destination-list | spacing |
| `.profile-shell__placeholder` | 未定設定區骨架 | skeleton | 無 | skeleton lines | surface/border/radius/spacing |
| `.skeleton-line` | 文字／數字骨架 | default | long / medium / short / number | inline span | skeleton/radius/spacing |
| `.skeleton-text-group` | 一致的多行骨架排版 | default | `--two-line` / `--numeric` | 兩個 skeleton-line | skeleton/spacing |
| `.skeleton-block--sparkline` | 迷你走勢骨架 | default | 無 | block span | skeleton |

## 7. 與 shell_nav 的接縫契約

- [inferred] shell 的內容區提供「扣除 status bar、root header、bottom nav 與 safe bottom 後」的可用高度；`lists.css` 不自行重算 shell 高度。
- [inferred] 垂直 scroll 由 shell 的 root stack 內容容器持有。`.list-stack` 與 `.list-stack__content` 不設定 `height` / `overflow-y`，避免雙層捲動；Feed chip 的水平 scroll 仍由 `.filter-strip` 自己持有。
- [inferred] root header 是否吸頂由 shell 負責；`.list-section-header` 預設不吸頂。若後續要 section sticky，應由組裝端新增 shell-level modifier，不改基本元件。
- [inferred] shell 需提供完整可用寬度；`.list-stack` 接受 `width: auto`，內容預設用 `--space-4` padding。若 shell 已提供左右 padding，組裝端改用 `.list-stack__content--flush`，避免雙 padding。
- [inferred] bottom safe area 與 nav 遮擋補償由 shell 負責；清單層不加 `--navbar-height` 或 `--safe-bottom`，否則在不含 nav 的 push stack 會重複留白。
- [unknown] shell_nav 最終內容容器 class 名與它是否選擇 container-owned scroll；PO 需要在整合時收斂。清單端唯一硬需求是「只能有一個垂直 scroll owner」。

建議整合形態：

```html
<div class="[shell-scroll-owner]">
  <main class="list-stack">
    <div class="list-stack__content">...</div>
  </main>
</div>
```

## 8. OPEN 與 token 建議

- [unknown] 今日 Feed 的選股、排序、分組與理由內容；未實作。
- [unknown] 要讓新手看懂籌碼 K 線的哪一段；清單只 push 到個股，不承擔判讀。
- [unknown] 四條 stack 實際資料欄位；price / change / reason / sparkline 均保留槽位。
- [unknown] 我的設定細項；沒有建立設定 row。
- [inferred] 非阻斷 token 建議：若未來要跨元件一致控制 disabled，可新增 `--opacity-disabled`；若要跨 worker 共用骨架比例，可新增 `--skeleton-width-long`、`--skeleton-width-medium`、`--skeleton-width-short`、`--skeleton-width-number`。目前未修改 `tokens.css`。

## 9. 驗證

- [confirmed] 以 HTML5 parser 檢查 `preview-lists.html`：零解析錯誤，且沒有巢狀 button。
- [confirmed] 機械比對 `lists.css` 的 `var(...)`：所有引用均可在 `tokens.css` 解析，沒有缺少 token 名稱。
- [confirmed] 搜尋 `lists.css`：沒有硬寫 hex / rgb / hsl 顏色，沒有硬寫 font-size、margin、padding 或 gap 的 px 值。
- [confirmed] 以 macOS Quick Look 實際渲染 `preview-lists.html`：元件展示頁可讀，股票列的 identity / quote / sparkline / action 槽位與主要狀態可辨識。

## 追加：utilities.css import

- [confirmed] `prototype/lists.css` 已在 `tokens.css` 之後 import `utilities.css`，載入順序為 tokens → utilities → domain CSS。
- [confirmed] 機械搜尋 `prototype/lists.css` 與 `prototype/preview-lists.html`，目前兩者都沒有實際使用 `.visually-hidden`。
- [inferred] 因此此 import 對目前清單預覽屬預防性依賴；它先確保後續只載入 `lists.css` 的組裝頁一旦使用跨 domain utility，仍可解析 `.visually-hidden`。
- [coverage gap] 無；兩個指定檔案皆可完整搜尋。
