Skip to content

Commit 70aa341

Browse files
committed
Feature: Make the Network panes the same as Full
- Added PgUp/PgDn, Home/End, and ←/→ arrow handling - Remove :hover CSS - Make items look the same as in the Full view
1 parent 9beab68 commit 70aa341

2 files changed

Lines changed: 95 additions & 19 deletions

File tree

apps/desktop/src/lib/file-explorer/NetworkBrowser.svelte

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
} from '$lib/network-store.svelte'
2222
import type { NetworkHost } from './types'
2323
import { updateLeftPaneState, updateRightPaneState, type PaneState, type PaneFileEntry } from '$lib/tauri-commands'
24+
import { handleNavigationShortcut } from './keyboard-shortcuts'
25+
26+
/** Row height for host list (matches Full list) */
27+
const HOST_ROW_HEIGHT = 20
2428
2529
interface Props {
2630
paneId?: 'left' | 'right'
@@ -38,6 +42,10 @@
3842
// Local cursor state
3943
let cursorIndex = $state(0)
4044
45+
// Container tracking for PageUp/PageDown
46+
let listContainer: HTMLDivElement | undefined = $state()
47+
let containerHeight = $state(0)
48+
4149
// Refresh stale shares when component mounts (entering network view)
4250
onMount(() => {
4351
refreshAllStaleShares()
@@ -89,26 +97,59 @@
8997
}
9098
}
9199
100+
/** Scrolls to make the cursor visible */
101+
function scrollToIndex(index: number) {
102+
if (!listContainer) return
103+
const targetTop = index * HOST_ROW_HEIGHT
104+
const targetBottom = targetTop + HOST_ROW_HEIGHT
105+
const scrollTop = listContainer.scrollTop
106+
const viewportBottom = scrollTop + containerHeight
107+
108+
if (targetTop < scrollTop) {
109+
listContainer.scrollTop = targetTop
110+
} else if (targetBottom > viewportBottom) {
111+
listContainer.scrollTop = targetBottom - containerHeight
112+
}
113+
}
114+
92115
// Handle keyboard navigation
93116
export function handleKeyDown(e: KeyboardEvent): boolean {
94117
if (hosts.length === 0) return false
95118
119+
// Try centralized navigation shortcuts first (PageUp, PageDown, Home, End, Option+arrows)
120+
const visibleItems = Math.max(1, Math.floor(containerHeight / HOST_ROW_HEIGHT))
121+
const navResult = handleNavigationShortcut(e, {
122+
currentIndex: cursorIndex,
123+
totalCount: hosts.length,
124+
visibleItems,
125+
})
126+
if (navResult?.handled) {
127+
e.preventDefault()
128+
cursorIndex = navResult.newIndex
129+
scrollToIndex(cursorIndex)
130+
return true
131+
}
132+
96133
switch (e.key) {
97134
case 'ArrowDown':
98135
e.preventDefault()
99136
cursorIndex = Math.min(cursorIndex + 1, hosts.length - 1)
137+
scrollToIndex(cursorIndex)
100138
return true
101139
case 'ArrowUp':
102140
e.preventDefault()
103141
cursorIndex = Math.max(cursorIndex - 1, 0)
142+
scrollToIndex(cursorIndex)
104143
return true
105-
case 'Home':
144+
case 'ArrowLeft':
106145
e.preventDefault()
107146
cursorIndex = 0
147+
scrollToIndex(cursorIndex)
108148
return true
109-
case 'End':
149+
case 'ArrowRight':
110150
e.preventDefault()
111151
cursorIndex = hosts.length - 1
152+
scrollToIndex(cursorIndex)
112153
return true
113154
case 'Enter':
114155
e.preventDefault()
@@ -279,7 +320,7 @@
279320
<span class="col-shares">Shares</span>
280321
<span class="col-status">Status</span>
281322
</div>
282-
<div class="host-list">
323+
<div class="host-list" bind:this={listContainer} bind:clientHeight={containerHeight}>
283324
{#each hosts as host, index (host.id)}
284325
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
285326
<div
@@ -359,13 +400,9 @@
359400
360401
.host-row {
361402
display: flex;
362-
padding: 4px 8px;
403+
height: 20px;
404+
padding: var(--spacing-xxs) var(--spacing-sm);
363405
cursor: default;
364-
border-bottom: 1px solid var(--color-border-secondary);
365-
}
366-
367-
.host-row:hover {
368-
background-color: var(--color-bg-hover);
369406
}
370407
371408
.host-row.is-under-cursor {

apps/desktop/src/lib/file-explorer/ShareBrowser.svelte

Lines changed: 49 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
updateKnownShare,
2020
} from '$lib/tauri-commands'
2121
import NetworkLoginForm from './NetworkLoginForm.svelte'
22+
import { handleNavigationShortcut } from './keyboard-shortcuts'
23+
24+
/** Row height for share list (matches Full list) */
25+
const SHARE_ROW_HEIGHT = 20
2226
2327
interface Props {
2428
/** The host we're browsing */
@@ -53,6 +57,10 @@
5357
// Track authenticated credentials for mounting
5458
let authenticatedCredentials = $state<{ username: string; password: string } | null>(null)
5559
60+
// Container tracking for PageUp/PageDown
61+
let listContainer: HTMLDivElement | undefined = $state()
62+
let containerHeight = $state(0)
63+
5664
// Load shares on mount
5765
onMount(async () => {
5866
await loadShares()
@@ -216,6 +224,21 @@
216224
}
217225
}
218226
227+
/** Scrolls to make the cursor visible */
228+
function scrollToIndex(index: number) {
229+
if (!listContainer) return
230+
const targetTop = index * SHARE_ROW_HEIGHT
231+
const targetBottom = targetTop + SHARE_ROW_HEIGHT
232+
const scrollTop = listContainer.scrollTop
233+
const viewportBottom = scrollTop + containerHeight
234+
235+
if (targetTop < scrollTop) {
236+
listContainer.scrollTop = targetTop
237+
} else if (targetBottom > viewportBottom) {
238+
listContainer.scrollTop = targetBottom - containerHeight
239+
}
240+
}
241+
219242
export function handleKeyDown(e: KeyboardEvent): boolean {
220243
if (showLoginForm) {
221244
// Login form handles its own keyboard events
@@ -226,22 +249,42 @@
226249
return false
227250
}
228251
252+
if (sortedShares.length === 0) return false
253+
254+
// Try centralized navigation shortcuts first (PageUp, PageDown, Home, End, Option+arrows)
255+
const visibleItems = Math.max(1, Math.floor(containerHeight / SHARE_ROW_HEIGHT))
256+
const navResult = handleNavigationShortcut(e, {
257+
currentIndex: cursorIndex,
258+
totalCount: sortedShares.length,
259+
visibleItems,
260+
})
261+
if (navResult?.handled) {
262+
e.preventDefault()
263+
cursorIndex = navResult.newIndex
264+
scrollToIndex(cursorIndex)
265+
return true
266+
}
267+
229268
switch (e.key) {
230269
case 'ArrowDown':
231270
e.preventDefault()
232271
cursorIndex = Math.min(cursorIndex + 1, sortedShares.length - 1)
272+
scrollToIndex(cursorIndex)
233273
return true
234274
case 'ArrowUp':
235275
e.preventDefault()
236276
cursorIndex = Math.max(cursorIndex - 1, 0)
277+
scrollToIndex(cursorIndex)
237278
return true
238-
case 'Home':
279+
case 'ArrowLeft':
239280
e.preventDefault()
240281
cursorIndex = 0
282+
scrollToIndex(cursorIndex)
241283
return true
242-
case 'End':
284+
case 'ArrowRight':
243285
e.preventDefault()
244286
cursorIndex = sortedShares.length - 1
287+
scrollToIndex(cursorIndex)
245288
return true
246289
case 'Enter':
247290
e.preventDefault()
@@ -304,7 +347,7 @@
304347
<span class="host-name">{host.name}</span>
305348
<span class="share-count">{sortedShares.length} {sortedShares.length === 1 ? 'share' : 'shares'}</span>
306349
</div>
307-
<div class="share-list">
350+
<div class="share-list" bind:this={listContainer} bind:clientHeight={containerHeight}>
308351
{#each sortedShares as share, index (share.name)}
309352
<!-- svelte-ignore a11y_no_noninteractive_element_interactions -->
310353
<div
@@ -449,14 +492,10 @@
449492
.share-row {
450493
display: flex;
451494
align-items: center;
452-
gap: 8px;
453-
padding: 8px 12px;
495+
gap: var(--spacing-sm);
496+
height: 20px;
497+
padding: var(--spacing-xxs) var(--spacing-sm);
454498
cursor: default;
455-
border-bottom: 1px solid var(--color-border-secondary);
456-
}
457-
458-
.share-row:hover {
459-
background-color: var(--color-bg-hover);
460499
}
461500
462501
.share-row.is-under-cursor {

0 commit comments

Comments
 (0)