Skip to content

Commit 1b8b78b

Browse files
committed
feat(ConnectionsToolbar): improve layout and accessibility of controls
1 parent 8df4960 commit 1b8b78b

File tree

4 files changed

+74
-70
lines changed

4 files changed

+74
-70
lines changed

src/i18n/en.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ export default {
137137
actions: 'Actions',
138138
remove: 'Remove',
139139
noDataUsageYet: 'No data usage recorded yet',
140-
sortBy: 'Sort by:',
140+
sortBy: 'Sort by',
141141
rowsPerPage: 'Rows per page',
142142
ipShort: 'IP',
143143
na: 'N/A',

src/i18n/ru.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,11 +139,12 @@ export default {
139139
actions: 'Действия',
140140
remove: 'Удалить',
141141
noDataUsageYet: 'Записей об использовании данных пока нет',
142-
sortBy: 'Сортировать по:',
142+
sortBy: 'Сортировать по',
143143
ipShort: 'IP',
144144
na: 'Н/Д',
145145
show: 'Показать',
146146
noLatencyHistory: 'Нет истории задержки',
147147
dataUsageInfo:
148148
'Мониторинг использования данных выполняется на стороне клиента (браузер). Когда браузер закрыт, мониторинг, скорее всего, не будет работать.',
149+
rowsPerPage: 'Строк на странице',
149150
} satisfies Dict

src/i18n/zh.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@ export default {
139139
actions: '操作',
140140
remove: '移除',
141141
noDataUsageYet: '暂无数据用量记录',
142-
sortBy: '排序:',
142+
sortBy: '排序',
143143
rowsPerPage: '每页行数',
144144
ipShort: 'IP',
145145
na: '无',

src/pages/Connections/ConnectionsToolbar.tsx

Lines changed: 70 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ export const ConnectionsToolbar = (props: ConnectionsToolbarProps) => {
7777
}
7878

7979
return (
80-
<div class="flex w-full flex-wrap items-center gap-2">
81-
{/* Tabs and filters */}
82-
<div class="flex items-center gap-2">
80+
<div class="flex w-full flex-col gap-2">
81+
{/* Row 1: Tabs + Quick filter + Source IP filter */}
82+
<div class="flex flex-wrap items-center gap-2">
8383
<div class="tabs-box tabs gap-2 tabs-sm">
8484
<Index each={props.tabs()}>
8585
{(tab) => (
@@ -98,18 +98,18 @@ export const ConnectionsToolbar = (props: ConnectionsToolbarProps) => {
9898
</Index>
9999
</div>
100100

101-
<div class="flex items-center">
102-
<span class="mr-2 hidden lg:inline-block">{t('quickFilter')}:</span>
101+
<div class="flex items-center gap-2">
102+
<span class="hidden text-sm sm:inline-block">{t('quickFilter')}</span>
103103
<input
104104
type="checkbox"
105-
class="toggle"
105+
class="toggle toggle-sm"
106106
checked={props.enableQuickFilter()}
107107
onChange={(e) => props.setEnableQuickFilter(e.target.checked)}
108108
/>
109109
</div>
110110

111111
<select
112-
class="select flex-1 select-sm select-primary"
112+
class="select max-w-40 flex-1 select-sm select-primary"
113113
onChange={(e) => props.setSourceIPFilter(e.target.value)}
114114
>
115115
<option value="">{t('all')}</option>
@@ -131,67 +131,70 @@ export const ConnectionsToolbar = (props: ConnectionsToolbarProps) => {
131131
</select>
132132
</div>
133133

134-
{/* Sort controls */}
135-
<div class="flex items-center gap-2">
136-
<span class="w-32 text-sm sm:inline-block">{t('sortBy')}</span>
137-
<select
138-
class="select select-sm select-primary"
139-
value={props.sortColumn()}
140-
onChange={(e) => {
141-
const id = e.target.value
142-
props.setSortColumn(id)
143-
props.setSorting([{ id, desc: props.sortDesc() }])
144-
}}
145-
>
146-
<Index each={props.sortables()}>
147-
{(opt) => <option value={opt().id}>{t(opt().key)}</option>}
148-
</Index>
149-
</select>
150-
<Button
151-
class="btn btn-sm btn-primary"
152-
onClick={() => {
153-
const next = !props.sortDesc()
154-
props.setSortDesc(next)
155-
props.setSorting([{ id: props.sortColumn(), desc: next }])
156-
}}
157-
icon={
158-
props.sortDesc() ? <IconSortDescending /> : <IconSortAscending />
159-
}
160-
/>
161-
</div>
134+
{/* Row 2: Sort + Search + Actions */}
135+
<div class="flex flex-wrap items-center gap-2">
136+
<div class="flex shrink-0 items-center gap-1">
137+
<span class="hidden text-sm whitespace-nowrap sm:inline-block">
138+
{t('sortBy')}
139+
</span>
140+
<select
141+
class="select select-sm select-primary"
142+
value={props.sortColumn()}
143+
onChange={(e) => {
144+
const id = e.target.value
145+
props.setSortColumn(id)
146+
props.setSorting([{ id, desc: props.sortDesc() }])
147+
}}
148+
>
149+
<Index each={props.sortables()}>
150+
{(opt) => <option value={opt().id}>{t(opt().key)}</option>}
151+
</Index>
152+
</select>
153+
<Button
154+
class="btn btn-sm btn-primary"
155+
onClick={() => {
156+
const next = !props.sortDesc()
157+
props.setSortDesc(next)
158+
props.setSorting([{ id: props.sortColumn(), desc: next }])
159+
}}
160+
icon={
161+
props.sortDesc() ? <IconSortDescending /> : <IconSortAscending />
162+
}
163+
/>
164+
</div>
162165

163-
{/* Search and actions */}
164-
<div class="join flex flex-1 items-center">
165-
<input
166-
type="search"
167-
class="input input-sm join-item flex-1 input-primary"
168-
placeholder={t('search')}
169-
onInput={(e) => props.setGlobalFilter(e.target.value)}
170-
/>
171-
172-
<Button
173-
class="btn join-item btn-sm btn-primary"
174-
onClick={() => props.setPaused((paused) => !paused)}
175-
icon={props.paused() ? <IconPlayerPlay /> : <IconPlayerPause />}
176-
/>
177-
178-
<Button
179-
class="btn join-item btn-sm btn-primary"
180-
onClick={handleCloseConnections}
181-
icon={
182-
isClosingConnections() ? (
183-
<div class="loading loading-spinner" />
184-
) : (
185-
<IconX />
186-
)
187-
}
188-
/>
189-
190-
<Button
191-
class="btn join-item btn-sm btn-primary"
192-
onClick={props.onOpenSettings}
193-
icon={<IconSettings />}
194-
/>
166+
<div class="join flex min-w-0 flex-1 items-center">
167+
<input
168+
type="search"
169+
class="input input-sm join-item min-w-0 flex-1 input-primary"
170+
placeholder={t('search')}
171+
onInput={(e) => props.setGlobalFilter(e.target.value)}
172+
/>
173+
174+
<Button
175+
class="btn join-item btn-sm btn-primary"
176+
onClick={() => props.setPaused((paused) => !paused)}
177+
icon={props.paused() ? <IconPlayerPlay /> : <IconPlayerPause />}
178+
/>
179+
180+
<Button
181+
class="btn join-item btn-sm btn-primary"
182+
onClick={handleCloseConnections}
183+
icon={
184+
isClosingConnections() ? (
185+
<div class="loading loading-spinner" />
186+
) : (
187+
<IconX />
188+
)
189+
}
190+
/>
191+
192+
<Button
193+
class="btn join-item btn-sm btn-primary"
194+
onClick={props.onOpenSettings}
195+
icon={<IconSettings />}
196+
/>
197+
</div>
195198
</div>
196199
</div>
197200
)

0 commit comments

Comments
 (0)