@@ -5,6 +5,7 @@ import type {
55 CodexFeatureRow ,
66 CodexFeatureStageFilter ,
77} from '../model/codexFeatureConfig' ;
8+ import { groupCodexFeatureRows } from '../model/codexFeatureConfig' ;
89import { renderCodexValueEditor } from '../model/codexValueEditor' ;
910
1011const codexFeatureStageFilters : CodexFeatureStageFilter [ ] = [
@@ -72,6 +73,13 @@ export default function StatusCodexFeaturesSection({
7273 const visibleCount = rows . length ;
7374 const totalCount = snapshot ?. items . filter ( ( item ) => item . section === 'features' ) . length || 0 ;
7475 const isBusy = isLoading || isSaving ;
76+ const groupedRows = groupCodexFeatureRows ( rows ) ;
77+
78+ function resolveGroupTitle ( groupId : string ) {
79+ const translationKey = `status.codex_features_group_${ groupId } ` ;
80+ const translated = t ( translationKey ) ;
81+ return translated !== translationKey ? translated : groupId ;
82+ }
7583
7684 return (
7785 < section className = "relative overflow-hidden border-2 border-[var(--border-color)] bg-[var(--bg-surface)]" >
@@ -132,50 +140,66 @@ export default function StatusCodexFeaturesSection({
132140 </ div >
133141 ) : null }
134142
135- < div className = "divide-y-2 divide-[var(--border-color)]" >
136- { rows . map ( ( row ) => (
137- < div
138- key = { row . key }
139- className = { `grid gap-3 px-4 py-3 md:grid-cols-[minmax(0,1fr)_5rem] md:items-center ${
140- row . stage === 'unknown' || row . stage === 'unsupported' ? 'bg-[var(--bg-main)]' : ''
141- } `}
142- >
143- < div className = "min-w-0" >
144- < div className = "break-all font-mono text-[length:var(--font-size-ui-md)] font-black tracking-wide text-[var(--text-primary)]" >
145- { row . key }
143+ < div >
144+ { groupedRows . map ( ( group , groupIndex ) => (
145+ < div key = { group . id } className = { `${ groupIndex > 0 ? 'border-t-2 border-[var(--border-color)]' : '' } ` } >
146+ < div className = "flex flex-wrap items-center justify-between gap-2 border-b-2 border-dashed border-[var(--border-color)] bg-[var(--bg-main)] px-4 py-2" >
147+ < div className = "text-[length:var(--font-size-ui-xs)] font-black italic uppercase tracking-[0.18em] text-[var(--text-primary)]" >
148+ { resolveGroupTitle ( group . id ) }
149+ </ div >
150+ < div className = "text-[length:var(--font-size-ui-xs)] font-black uppercase tracking-[0.18em] text-[var(--text-muted)]" >
151+ { group . rows . length } { t ( 'design_system.items' ) }
146152 </ div >
147- < div className = "mt-1 flex flex-wrap items-center gap-2 text-[length:var(--font-size-ui-sm)] font-bold tracking-wide text-[var(--text-muted)]" >
148- < span
149- className = { `inline-flex shrink-0 border-2 px-2 py-0.5 text-[length:var(--font-size-ui-xs)] font-black tracking-[0.14em] ${
150- row . stage === 'unknown' || row . stage === 'unsupported' || row . stage === 'removed'
151- ? 'border-[var(--border-color)] bg-[var(--bg-surface)] text-[var(--color-status-danger)]'
152- : 'border-[var(--border-color)] bg-[var(--text-primary)] text-[var(--bg-main)]'
153+ </ div >
154+ < div className = "divide-y-2 divide-[var(--border-color)]" >
155+ { group . rows . map ( ( row ) => (
156+ < div
157+ key = { row . key }
158+ className = { `grid gap-3 px-4 py-3 md:grid-cols-[minmax(0,1fr)_5rem] md:items-center ${
159+ row . stage === 'unknown' || row . stage === 'unsupported' ? 'bg-[var(--bg-main)]' : ''
153160 } `}
154161 >
155- { t ( `status.codex_features_stage_${ row . stage } ` ) }
156- </ span >
157- { row . hiddenByDefault ? (
158- < span className = "inline-flex shrink-0 border-2 border-[var(--border-color)] bg-[var(--bg-surface)] px-2 py-0.5 text-[length:var(--font-size-ui-xs)] font-black tracking-[0.14em] text-[var(--text-muted)]" >
159- { t ( 'status.codex_features_hidden_default' ) }
160- </ span >
161- ) : null }
162- < span className = "min-w-0" > { resolveCodexFeatureDescription ( t , row ) } </ span >
163- </ div >
164- { row . legacyAliases . length > 0 ? (
165- < div className = "mt-2 inline-flex max-w-full border-2 border-dashed border-[var(--border-color)] px-2 py-1 text-[length:var(--font-size-ui-xs)] font-black uppercase tracking-[0.14em] text-[var(--text-primary)]" >
166- < span className = "truncate" >
167- { t ( 'status.codex_features_legacy_alias' ) } : { row . legacyAliases . join ( ', ' ) }
168- </ span >
162+ < div className = "min-w-0" >
163+ < div className = "break-all font-mono text-[length:var(--font-size-ui-md)] font-black tracking-wide text-[var(--text-primary)]" >
164+ { row . key }
165+ </ div >
166+ < div className = "mt-1 flex flex-wrap items-center gap-2 text-[length:var(--font-size-ui-sm)] font-bold tracking-wide text-[var(--text-muted)]" >
167+ < span
168+ className = { `inline-flex shrink-0 border-2 px-2 py-0.5 text-[length:var(--font-size-ui-xs)] font-black tracking-[0.14em] ${
169+ row . stage === 'unknown' || row . stage === 'unsupported' || row . stage === 'removed'
170+ ? 'border-[var(--border-color)] bg-[var(--bg-surface)] text-[var(--color-status-danger)]'
171+ : 'border-[var(--border-color)] bg-[var(--text-primary)] text-[var(--bg-main)]'
172+ } `}
173+ >
174+ { t ( `status.codex_features_stage_${ row . stage } ` ) }
175+ </ span >
176+ { row . hiddenByDefault ? (
177+ < span className = "inline-flex shrink-0 border-2 border-[var(--border-color)] bg-[var(--bg-surface)] px-2 py-0.5 text-[length:var(--font-size-ui-xs)] font-black tracking-[0.14em] text-[var(--text-muted)]" >
178+ { t ( 'status.codex_features_hidden_default' ) }
179+ </ span >
180+ ) : null }
181+ < span className = "min-w-0" > { resolveCodexFeatureDescription ( t , row ) } </ span >
182+ </ div >
183+ { row . legacyAliases . length > 0 ? (
184+ < div className = "mt-2 inline-flex max-w-full border-2 border-dashed border-[var(--border-color)] px-2 py-1 text-[length:var(--font-size-ui-xs)] font-black uppercase tracking-[0.14em] text-[var(--text-primary)]" >
185+ < span className = "truncate" >
186+ { t ( 'status.codex_features_legacy_alias' ) } : { row . legacyAliases . join ( ', ' ) }
187+ </ span >
188+ </ div >
189+ ) : null }
190+ { row . unsupported ? (
191+ < div className = "mt-2 text-[length:var(--font-size-ui-xs)] font-black uppercase tracking-[0.14em] text-[var(--text-muted)]" >
192+ { t ( 'status.codex_features_unsupported_hint' ) }
193+ </ div >
194+ ) : null }
195+ </ div >
196+ < div className = "flex justify-start md:justify-center" >
197+ < div className = "w-full max-w-[22rem]" >
198+ { renderCodexValueEditor ( row , row . readOnly || isBusy , onChangeFeature ) }
199+ </ div >
200+ </ div >
169201 </ div >
170- ) : null }
171- { row . unsupported ? (
172- < div className = "mt-2 text-[length:var(--font-size-ui-xs)] font-black uppercase tracking-[0.14em] text-[var(--text-muted)]" >
173- { t ( 'status.codex_features_unsupported_hint' ) }
174- </ div >
175- ) : null }
176- </ div >
177- < div className = "flex justify-start md:justify-center" >
178- < div className = "w-full max-w-[22rem]" > { renderCodexValueEditor ( row , row . readOnly || isBusy , onChangeFeature ) } </ div >
202+ ) ) }
179203 </ div >
180204 </ div >
181205 ) ) }
0 commit comments