Skip to content

Commit 703af29

Browse files
committed
Implement active navigation item highlighting by tracking which settings section header is currently stuck at the top of the viewport
1 parent 769c3b1 commit 703af29

3 files changed

Lines changed: 72 additions & 25 deletions

File tree

‎packages/ui/src/components/editor/settings/NavigationItem/NavigationItem.tsx‎

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import cn from 'classnames'
12
import styles from './NavigationItem.module.scss'
23

34
type Props = {
@@ -9,7 +10,13 @@ type Props = {
910

1011
export const NavigationItem: React.FC<Props> = (props) => {
1112
return (
12-
<a href={props.href} className={styles.container} onClick={props.on_click}>
13+
<a
14+
href={props.href}
15+
className={cn(styles.container, {
16+
[styles['container--active']]: props.is_active
17+
})}
18+
onClick={props.on_click}
19+
>
1320
<span>{props.label}</span>
1421
</a>
1522
)

‎packages/ui/src/components/editor/settings/Section/Section.tsx‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,18 @@ type Props = {
66
title: string
77
subtitle: React.ReactNode
88
children: React.ReactNode
9+
on_stuck_change?: (is_stuck: boolean) => void
910
}
1011

1112
export const Section = forwardRef<HTMLDivElement, Props>((props, ref) => {
1213
const marker_ref = useRef<HTMLDivElement>(null)
1314
const container_ref = useRef<HTMLDivElement | null>(null)
1415
const [is_stuck, set_is_stuck] = useState(false)
1516

17+
useEffect(() => {
18+
props.on_stuck_change?.(is_stuck)
19+
}, [is_stuck, props.on_stuck_change])
20+
1621
useEffect(() => {
1722
const marker = marker_ref.current
1823
const container = container_ref.current

‎packages/vscode/src/views/settings/frontend/Home/Home.tsx‎

Lines changed: 59 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import {
1616
type NavItem =
1717
| 'general'
1818
| 'model-providers'
19-
| 'code-completions'
2019
| 'edit-context'
20+
| 'code-completions'
2121
| 'intelligent-update'
2222
| 'commit-messages'
2323

@@ -30,8 +30,8 @@ const NAV_ITEMS_CONFIG: { id: NavItem; label: string }[] = [
3030
id: 'model-providers',
3131
label: dictionary.settings.MODEL_PROVIDERS_LABEL
3232
},
33-
{ id: 'code-completions', label: 'Code Completions' },
3433
{ id: 'edit-context', label: 'Edit Context' },
34+
{ id: 'code-completions', label: 'Code Completions' },
3535
{ id: 'intelligent-update', label: 'Intelligent Update' },
3636
{ id: 'commit-messages', label: 'Commit Messages' }
3737
]
@@ -47,10 +47,10 @@ type Props = {
4747

4848
// handlers
4949
set_providers: (providers: ProviderForClient[]) => void
50-
set_code_completions_configs: (configs: ConfigurationForClient[]) => void
51-
set_commit_messages_configs: (configs: ConfigurationForClient[]) => void
5250
set_edit_context_configs: (configs: ConfigurationForClient[]) => void
51+
set_code_completions_configs: (configs: ConfigurationForClient[]) => void
5352
set_intelligent_update_configs: (configs: ConfigurationForClient[]) => void
53+
set_commit_messages_configs: (configs: ConfigurationForClient[]) => void
5454
on_commit_instructions_change: (instructions: string) => void
5555
on_open_editor_settings: () => void
5656
on_add_provider: () => void
@@ -75,12 +75,29 @@ export const Home: React.FC<Props> = (props) => {
7575
const section_refs = useRef<Record<NavItem, HTMLDivElement | null>>({
7676
general: null,
7777
'model-providers': null,
78-
'code-completions': null,
7978
'edit-context': null,
79+
'code-completions': null,
8080
'intelligent-update': null,
8181
'commit-messages': null
8282
})
8383
const [commit_instructions, set_commit_instructions] = useState('')
84+
const [stuck_sections, set_stuck_sections] = useState(new Set<NavItem>())
85+
86+
const handle_stuck_change = (id: NavItem, is_stuck: boolean) => {
87+
set_stuck_sections((prev) => {
88+
const next = new Set(prev)
89+
if (is_stuck) {
90+
next.add(id)
91+
} else {
92+
next.delete(id)
93+
}
94+
return next
95+
})
96+
}
97+
98+
const nav_item_ids = NAV_ITEMS_CONFIG.map((item) => item.id)
99+
const active_nav_item_id =
100+
nav_item_ids.filter((id) => stuck_sections.has(id)).pop() || nav_item_ids[0]
84101

85102
useEffect(() => {
86103
set_commit_instructions(props.commit_message_instructions || '')
@@ -146,7 +163,7 @@ export const Home: React.FC<Props> = (props) => {
146163
key={id}
147164
href={`#${id}`}
148165
label={label}
149-
is_active={false}
166+
is_active={id === active_nav_item_id}
150167
on_click={(e) => handle_nav_click(e, id)}
151168
/>
152169
))}
@@ -157,6 +174,9 @@ export const Home: React.FC<Props> = (props) => {
157174
ref={(el) => (section_refs.current['general'] = el)}
158175
title="General"
159176
subtitle="General settings for the extension."
177+
on_stuck_change={(is_stuck) =>
178+
handle_stuck_change('general', is_stuck)
179+
}
160180
>
161181
<Item
162182
title="Open Editor Settings"
@@ -172,6 +192,9 @@ export const Home: React.FC<Props> = (props) => {
172192
ref={(el) => (section_refs.current['model-providers'] = el)}
173193
title="Model Providers"
174194
subtitle="Manage your model providers here. Add, edit, reorder, or delete providers as needed."
195+
on_stuck_change={(is_stuck) =>
196+
handle_stuck_change('model-providers', is_stuck)
197+
}
175198
>
176199
<ModelProvidersSection
177200
providers={props.providers}
@@ -185,10 +208,34 @@ export const Home: React.FC<Props> = (props) => {
185208
on_change_api_key={props.on_change_api_key}
186209
/>
187210
</Section>
211+
<Section
212+
ref={(el) => (section_refs.current['edit-context'] = el)}
213+
title={dictionary.settings.EDIT_CONTEXT_LABEL}
214+
subtitle={dictionary.settings.EDIT_CONTEXT_SUBTITLE}
215+
on_stuck_change={(is_stuck) =>
216+
handle_stuck_change('edit-context', is_stuck)
217+
}
218+
>
219+
<ApiToolConfigurationSection
220+
configurations={props.edit_context_configs}
221+
set_configurations={props.set_edit_context_configs}
222+
tool_name="EDIT_CONTEXT"
223+
can_have_default={false}
224+
on_add={() => props.on_add_config('EDIT_CONTEXT')}
225+
on_reorder={(reordered) =>
226+
props.on_reorder_configs('EDIT_CONTEXT', reordered)
227+
}
228+
on_edit={(id) => props.on_edit_config('EDIT_CONTEXT', id)}
229+
on_delete={(id) => props.on_delete_config('EDIT_CONTEXT', id)}
230+
/>
231+
</Section>
188232
<Section
189233
ref={(el) => (section_refs.current['code-completions'] = el)}
190234
title={dictionary.settings.CODE_COMPLETIONS_LABEL}
191235
subtitle={dictionary.settings.CODE_COMPLETIONS_SUBTITLE}
236+
on_stuck_change={(is_stuck) =>
237+
handle_stuck_change('code-completions', is_stuck)
238+
}
192239
>
193240
<ApiToolConfigurationSection
194241
configurations={props.code_completions_configs}
@@ -209,28 +256,13 @@ export const Home: React.FC<Props> = (props) => {
209256
}
210257
/>
211258
</Section>
212-
<Section
213-
ref={(el) => (section_refs.current['edit-context'] = el)}
214-
title={dictionary.settings.EDIT_CONTEXT_LABEL}
215-
subtitle={dictionary.settings.EDIT_CONTEXT_SUBTITLE}
216-
>
217-
<ApiToolConfigurationSection
218-
configurations={props.edit_context_configs}
219-
set_configurations={props.set_edit_context_configs}
220-
tool_name="EDIT_CONTEXT"
221-
can_have_default={false}
222-
on_add={() => props.on_add_config('EDIT_CONTEXT')}
223-
on_reorder={(reordered) =>
224-
props.on_reorder_configs('EDIT_CONTEXT', reordered)
225-
}
226-
on_edit={(id) => props.on_edit_config('EDIT_CONTEXT', id)}
227-
on_delete={(id) => props.on_delete_config('EDIT_CONTEXT', id)}
228-
/>
229-
</Section>
230259
<Section
231260
ref={(el) => (section_refs.current['intelligent-update'] = el)}
232261
title={dictionary.settings.INTELLIGENT_UPDATE_LABEL}
233262
subtitle={dictionary.settings.INTELLIGENT_UPDATE_SUBTITLE}
263+
on_stuck_change={(is_stuck) =>
264+
handle_stuck_change('intelligent-update', is_stuck)
265+
}
234266
>
235267
<ApiToolConfigurationSection
236268
configurations={props.intelligent_update_configs}
@@ -255,6 +287,9 @@ export const Home: React.FC<Props> = (props) => {
255287
ref={(el) => (section_refs.current['commit-messages'] = el)}
256288
title={dictionary.settings.COMMIT_MESSAGES_LABEL}
257289
subtitle="Configure models for generating commit messages, and customize the instructions used."
290+
on_stuck_change={(is_stuck) =>
291+
handle_stuck_change('commit-messages', is_stuck)
292+
}
258293
>
259294
<Item
260295
title="Commit Message Instructions"

0 commit comments

Comments
 (0)