style(hosts,docker): Move search bar to its own row above filters

- Consistent with Kubernetes page layout
- Search bar now takes full width on top row
- Filter toggles on second row below search
This commit is contained in:
rcourtman 2025-12-12 23:41:37 +00:00
parent fa5fde56e6
commit ca8cd0e3b4
2 changed files with 400 additions and 406 deletions

View file

@ -107,9 +107,9 @@ export const DockerFilter: Component<DockerFilterProps> = (props) => {
return ( return (
<Card class="docker-filter mb-3" padding="sm"> <Card class="docker-filter mb-3" padding="sm">
<div class="flex flex-col lg:flex-row gap-3"> <div class="flex flex-col gap-3">
<div class="flex gap-2 flex-1 items-center"> {/* Search - full width on its own row */}
<div class="relative flex-1"> <div class="relative">
<input <input
ref={(el) => { ref={(el) => {
searchInputEl = el; searchInputEl = el;
@ -298,8 +298,8 @@ export const DockerFilter: Component<DockerFilterProps> = (props) => {
</div> </div>
</Show> </Show>
</div> </div>
</div>
{/* Filters - second row */}
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<Show when={props.statusFilter && props.setStatusFilter}> <Show when={props.statusFilter && props.setStatusFilter}>
<div class="inline-flex rounded-lg bg-gray-100 p-0.5 dark:bg-gray-700"> <div class="inline-flex rounded-lg bg-gray-100 p-0.5 dark:bg-gray-700">
@ -307,8 +307,7 @@ export const DockerFilter: Component<DockerFilterProps> = (props) => {
type="button" type="button"
aria-pressed={props.statusFilter?.() === 'all'} aria-pressed={props.statusFilter?.() === 'all'}
onClick={() => props.setStatusFilter?.('all')} onClick={() => props.setStatusFilter?.('all')}
class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${ class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${props.statusFilter?.() === 'all'
props.statusFilter?.() === 'all'
? 'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm' ? 'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100' : 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
}`} }`}
@ -322,8 +321,7 @@ export const DockerFilter: Component<DockerFilterProps> = (props) => {
onClick={() => onClick={() =>
props.setStatusFilter?.(props.statusFilter?.() === 'online' ? 'all' : 'online') props.setStatusFilter?.(props.statusFilter?.() === 'online' ? 'all' : 'online')
} }
class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${ class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${props.statusFilter?.() === 'online'
props.statusFilter?.() === 'online'
? 'bg-white dark:bg-gray-800 text-green-600 dark:text-green-400 shadow-sm' ? 'bg-white dark:bg-gray-800 text-green-600 dark:text-green-400 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100' : 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
}`} }`}
@ -339,8 +337,7 @@ export const DockerFilter: Component<DockerFilterProps> = (props) => {
props.statusFilter?.() === 'degraded' ? 'all' : 'degraded', props.statusFilter?.() === 'degraded' ? 'all' : 'degraded',
) )
} }
class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${ class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${props.statusFilter?.() === 'degraded'
props.statusFilter?.() === 'degraded'
? 'bg-white dark:bg-gray-800 text-amber-600 dark:text-amber-400 shadow-sm' ? 'bg-white dark:bg-gray-800 text-amber-600 dark:text-amber-400 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100' : 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
}`} }`}
@ -356,8 +353,7 @@ export const DockerFilter: Component<DockerFilterProps> = (props) => {
props.statusFilter?.() === 'offline' ? 'all' : 'offline', props.statusFilter?.() === 'offline' ? 'all' : 'offline',
) )
} }
class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${ class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${props.statusFilter?.() === 'offline'
props.statusFilter?.() === 'offline'
? 'bg-white dark:bg-gray-800 text-red-600 dark:text-red-400 shadow-sm' ? 'bg-white dark:bg-gray-800 text-red-600 dark:text-red-400 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100' : 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
}`} }`}
@ -373,8 +369,7 @@ export const DockerFilter: Component<DockerFilterProps> = (props) => {
<button <button
type="button" type="button"
onClick={() => props.setGroupingMode?.('grouped')} onClick={() => props.setGroupingMode?.('grouped')}
class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${ class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${props.groupingMode?.() === 'grouped'
props.groupingMode?.() === 'grouped'
? 'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm' ? 'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100' : 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
}`} }`}
@ -384,8 +379,7 @@ export const DockerFilter: Component<DockerFilterProps> = (props) => {
<button <button
type="button" type="button"
onClick={() => props.setGroupingMode?.('flat')} onClick={() => props.setGroupingMode?.('flat')}
class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${ class={`px-2.5 py-1 text-xs font-medium rounded-md transition-all ${props.groupingMode?.() === 'flat'
props.groupingMode?.() === 'flat'
? 'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm' ? 'bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 shadow-sm'
: 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100' : 'text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100'
}`} }`}

View file

@ -109,9 +109,9 @@ export const HostsFilter: Component<HostsFilterProps> = (props) => {
return ( return (
<Card class="hosts-filter mb-3" padding="sm"> <Card class="hosts-filter mb-3" padding="sm">
<div class="flex flex-col lg:flex-row gap-3"> <div class="flex flex-col gap-3">
<div class="flex gap-2 flex-1 items-center"> {/* Search - full width on its own row */}
<div class="relative flex-1"> <div class="relative">
<input <input
ref={(el) => { ref={(el) => {
searchInputEl = el; searchInputEl = el;
@ -300,8 +300,8 @@ export const HostsFilter: Component<HostsFilterProps> = (props) => {
</div> </div>
</Show> </Show>
</div> </div>
</div>
{/* Filters - second row */}
<div class="flex flex-wrap items-center gap-2"> <div class="flex flex-wrap items-center gap-2">
<div class="inline-flex rounded-lg bg-gray-100 p-0.5 dark:bg-gray-700"> <div class="inline-flex rounded-lg bg-gray-100 p-0.5 dark:bg-gray-700">
<button <button