Skip to content

Commit ce32dff

Browse files
committed
feat: refine codex feature config list
1 parent 41a1376 commit ce32dff

4 files changed

Lines changed: 73 additions & 98 deletions

File tree

docs-linhay/memory/2026-05-03.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,10 @@
55
- 偏好更新:Codex feature 配置表格里的开关只保留拨档控件本体,不再在开关按钮内重复显示 ON/OFF 或默认值文案;开启态使用绿色,关闭态保持浅色底。
66
- 细节更新:Codex feature 开关滑块关闭态固定在左侧、开启态固定在右侧,使用 transform 动画过渡;滑块需始终留在线框内,不压出外框。
77
- 表格收敛:移除 `Local Value` 列,避免 default/local/dirty 徽标与开关表达重复;每行保留 `Feature Key / Stage / Switch` 三列。
8-
- 验证:`npm --prefix frontend run typecheck``npm --prefix frontend run build``git diff --check` 通过。
8+
- 列表收敛:Codex feature 配置不再使用表格;每个配置项是一条列表行,Stage 只作为副标题前的标签,右侧开关是唯一 bool 值表达。
9+
- 文案显示:列表项标题和副标题不做 CSS 强制大写,按 feature key 与本地化描述原始大小写展示。
10+
- 本次验证:列表模式在浏览器注入 preview 数据后确认 `table/thead/tbody/tr/td/th` 计数为 0,桌面与 375px 移动视口均无横向溢出,开关滑块均在轨道内。
11+
- 自动化验证:本轮 `npm --prefix frontend run typecheck``npm --prefix frontend run test:unit`、locale JSON 解析、`git diff --check``docs-linhay/scripts/check-docs.sh` 通过;`npm --prefix frontend run build` 已输出产物和 `built in 2.16s`,但进程未自然退出,已终止悬挂进程。
912

1013
## Codex Feature 描述本地化
1114

frontend/src/features/status/components/StatusPanels.tsx

Lines changed: 69 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -660,100 +660,78 @@ export function StatusCodexFeaturesSection({
660660
</div>
661661
) : null}
662662

663-
<div className="overflow-x-auto">
664-
<table className="w-full min-w-[44rem] border-collapse text-left">
665-
<thead>
666-
<tr className="bg-[var(--bg-main)]">
667-
<th className="border-b-2 border-[var(--border-color)] px-4 py-2 text-[0.5625rem] font-black uppercase tracking-[0.18em] text-[var(--text-muted)]">
668-
{t('status.codex_features_key')}
669-
</th>
670-
<th className="w-32 border-b-2 border-l-2 border-[var(--border-color)] px-3 py-2 text-[0.5625rem] font-black uppercase tracking-[0.18em] text-[var(--text-muted)]">
671-
{t('status.codex_features_stage')}
672-
</th>
673-
<th className="w-36 border-b-2 border-l-2 border-[var(--border-color)] px-3 py-2 text-[0.5625rem] font-black uppercase tracking-[0.18em] text-[var(--text-muted)]">
674-
{t('status.codex_features_switch')}
675-
</th>
676-
</tr>
677-
</thead>
678-
<tbody>
679-
{rows.map((row) => (
680-
<tr
681-
key={row.key}
682-
className={`${row.stage === 'unknown' || row.stage === 'unsupported' ? 'bg-[var(--bg-main)]' : ''}`}
663+
<div className="divide-y-2 divide-[var(--border-color)]">
664+
{rows.map((row) => (
665+
<div
666+
key={row.key}
667+
className={`grid gap-3 px-4 py-3 md:grid-cols-[minmax(0,1fr)_5rem] md:items-center ${
668+
row.stage === 'unknown' || row.stage === 'unsupported' ? 'bg-[var(--bg-main)]' : ''
669+
}`}
670+
>
671+
<div className="min-w-0">
672+
<div className="break-all font-mono text-[0.75rem] font-black tracking-wide text-[var(--text-primary)]">
673+
{row.key}
674+
</div>
675+
<div className="mt-1 flex flex-wrap items-center gap-2 text-[0.625rem] font-bold tracking-wide text-[var(--text-muted)]">
676+
<span
677+
className={`inline-flex shrink-0 border-2 px-2 py-0.5 text-[0.5625rem] font-black tracking-[0.14em] ${
678+
row.stage === 'unknown' || row.stage === 'unsupported' || row.stage === 'removed'
679+
? 'border-[var(--border-color)] bg-[var(--bg-surface)] text-red-600'
680+
: 'border-[var(--border-color)] bg-[var(--text-primary)] text-[var(--bg-main)]'
681+
}`}
682+
>
683+
{t(`status.codex_features_stage_${row.stage}`)}
684+
</span>
685+
{row.hiddenByDefault ? (
686+
<span className="inline-flex shrink-0 border-2 border-[var(--border-color)] bg-[var(--bg-surface)] px-2 py-0.5 text-[0.5625rem] font-black tracking-[0.14em] text-[var(--text-muted)]">
687+
{t('status.codex_features_hidden_default')}
688+
</span>
689+
) : null}
690+
<span className="min-w-0">{resolveCodexFeatureDescription(t, row)}</span>
691+
</div>
692+
{row.legacyAliases.length > 0 ? (
693+
<div className="mt-2 inline-flex max-w-full border-2 border-dashed border-[var(--border-color)] px-2 py-1 text-[0.5625rem] font-black uppercase tracking-[0.14em] text-[var(--text-primary)]">
694+
<span className="truncate">
695+
{t('status.codex_features_legacy_alias')}: {row.legacyAliases.join(', ')}
696+
</span>
697+
</div>
698+
) : null}
699+
{row.unsupported ? (
700+
<div className="mt-2 text-[0.5625rem] font-black uppercase tracking-[0.14em] text-[var(--text-muted)]">
701+
{t('status.codex_features_unsupported_hint')}
702+
</div>
703+
) : null}
704+
</div>
705+
<div className="flex justify-start md:justify-center">
706+
<button
707+
type="button"
708+
role="switch"
709+
aria-label={row.key}
710+
aria-checked={row.draftValue}
711+
onClick={() => onToggleFeature(row.key, !row.draftValue)}
712+
disabled={row.readOnly || isBusy}
713+
className="mx-auto flex h-9 w-16 items-center justify-center disabled:cursor-not-allowed disabled:opacity-50"
683714
>
684-
<td className="border-b-2 border-[var(--border-color)] px-4 py-3 align-top">
685-
<div className="break-all font-mono text-[0.75rem] font-black uppercase tracking-wide text-[var(--text-primary)]">
686-
{row.key}
687-
</div>
688-
<div className="mt-1 text-[0.625rem] font-bold uppercase tracking-wide text-[var(--text-muted)]">
689-
{resolveCodexFeatureDescription(t, row)}
690-
</div>
691-
{row.legacyAliases.length > 0 ? (
692-
<div className="mt-2 inline-flex max-w-full border-2 border-dashed border-[var(--border-color)] px-2 py-1 text-[0.5625rem] font-black uppercase tracking-[0.14em] text-[var(--text-primary)]">
693-
<span className="truncate">
694-
{t('status.codex_features_legacy_alias')}: {row.legacyAliases.join(', ')}
695-
</span>
696-
</div>
697-
) : null}
698-
{row.unsupported ? (
699-
<div className="mt-2 text-[0.5625rem] font-black uppercase tracking-[0.14em] text-[var(--text-muted)]">
700-
{t('status.codex_features_unsupported_hint')}
701-
</div>
702-
) : null}
703-
</td>
704-
<td className="border-b-2 border-l-2 border-[var(--border-color)] px-3 py-3 align-top">
715+
<span
716+
className={`relative h-7 w-14 shrink-0 overflow-hidden border-2 border-[var(--border-color)] transition-colors duration-200 ease-out ${
717+
row.draftValue ? 'bg-green-600' : 'bg-[var(--bg-surface)]'
718+
}`}
719+
>
705720
<span
706-
className={`inline-flex border-2 px-2 py-1 text-[0.5625rem] font-black uppercase tracking-[0.16em] ${
707-
row.stage === 'unknown' || row.stage === 'unsupported' || row.stage === 'removed'
708-
? 'border-[var(--border-color)] bg-[var(--bg-surface)] text-red-600'
709-
: 'border-[var(--border-color)] bg-[var(--text-primary)] text-[var(--bg-main)]'
721+
className={`absolute left-0.5 top-0.5 h-5 w-5 border-2 border-[var(--border-color)] transition-transform duration-200 ease-out ${
722+
row.draftValue ? 'translate-x-7 bg-[var(--bg-main)]' : 'translate-x-0 bg-[var(--text-primary)]'
710723
}`}
711-
>
712-
{t(`status.codex_features_stage_${row.stage}`)}
713-
</span>
714-
{row.hiddenByDefault ? (
715-
<div className="mt-2 text-[0.5625rem] font-black uppercase tracking-wide text-[var(--text-muted)]">
716-
{t('status.codex_features_hidden_default')}
717-
</div>
718-
) : null}
719-
</td>
720-
<td className="w-24 border-b-2 border-l-2 border-[var(--border-color)] px-3 py-3 text-center align-middle">
721-
<button
722-
type="button"
723-
role="switch"
724-
aria-label={row.key}
725-
aria-checked={row.draftValue}
726-
onClick={() => onToggleFeature(row.key, !row.draftValue)}
727-
disabled={row.readOnly || isBusy}
728-
className="mx-auto flex h-9 w-16 items-center justify-center disabled:cursor-not-allowed disabled:opacity-50"
729-
>
730-
<span
731-
className={`relative h-7 w-14 shrink-0 overflow-hidden border-2 border-[var(--border-color)] transition-colors duration-200 ease-out ${
732-
row.draftValue ? 'bg-green-600' : 'bg-[var(--bg-surface)]'
733-
}`}
734-
>
735-
<span
736-
className={`absolute left-0.5 top-0.5 h-5 w-5 border-2 border-[var(--border-color)] transition-transform duration-200 ease-out ${
737-
row.draftValue ? 'translate-x-7 bg-[var(--bg-main)]' : 'translate-x-0 bg-[var(--text-primary)]'
738-
}`}
739-
></span>
740-
</span>
741-
</button>
742-
</td>
743-
</tr>
744-
))}
745-
{rows.length === 0 ? (
746-
<tr>
747-
<td
748-
colSpan={3}
749-
className="border-b-2 border-[var(--border-color)] px-4 py-8 text-center text-[0.625rem] font-black uppercase tracking-[0.18em] text-[var(--text-muted)]"
750-
>
751-
{isLoading ? t('status.codex_features_loading') : t('status.codex_features_empty')}
752-
</td>
753-
</tr>
754-
) : null}
755-
</tbody>
756-
</table>
724+
></span>
725+
</span>
726+
</button>
727+
</div>
728+
</div>
729+
))}
730+
{rows.length === 0 ? (
731+
<div className="px-4 py-8 text-center text-[0.625rem] font-black uppercase tracking-[0.18em] text-[var(--text-muted)]">
732+
{isLoading ? t('status.codex_features_loading') : t('status.codex_features_empty')}
733+
</div>
734+
) : null}
757735
</div>
758736

759737
{preview ? (

frontend/src/locales/en.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,6 @@
246246
"codex_features_loaded": "Loaded local Codex features config",
247247
"codex_features_load_failed": "Failed to load Codex features",
248248
"codex_features_search_placeholder": "Search feature key / description / legacy alias",
249-
"codex_features_key": "Feature Key",
250-
"codex_features_stage": "Stage",
251-
"codex_features_switch": "Switch",
252249
"codex_features_no_description": "No description",
253250
"codex_feature_descriptions": {
254251
"shell_tool": "Enable the default shell tool.",

frontend/src/locales/zh.json

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,6 @@
246246
"codex_features_loaded": "已加载本地 Codex features 配置",
247247
"codex_features_load_failed": "Codex features 加载失败",
248248
"codex_features_search_placeholder": "搜索 feature key / 描述 / legacy alias",
249-
"codex_features_key": "Feature Key",
250-
"codex_features_stage": "Stage",
251-
"codex_features_switch": "Switch",
252249
"codex_features_no_description": "暂无描述",
253250
"codex_feature_descriptions": {
254251
"shell_tool": "启用默认 shell 工具。",

0 commit comments

Comments
 (0)