Allow layout to expand on wide displays (related to #643)
Changed .pulse-shell from fixed 95rem cap to fluid clamp(95rem, 92vw, 120rem) to match standard monitoring dashboard behavior (Proxmox, Grafana, Portainer). On laptops/small screens: unchanged (capped at 1520px) On 1080p displays: expands to ~1766px usable width On 4K/ultrawide: expands up to 1920px max for readability Added back 2xl column widths (totaling ~1720px) that properly fit within the expanded shell, giving wide-display users more breathing room while maintaining proportional scaling across all breakpoints. Changed files: - index.css: Update .pulse-shell max-width to use clamp() - Dashboard.tsx: Add 2xl column widths calculated for expanded shell - GuestRow.tsx: Add matching 2xl column widths
This commit is contained in:
parent
68caf5592b
commit
4f9ba7a285
3 changed files with 23 additions and 23 deletions
|
|
@ -912,7 +912,7 @@ export function Dashboard(props: DashboardProps) {
|
|||
<thead>
|
||||
<tr class="bg-gray-50 dark:bg-gray-700/50 text-gray-600 dark:text-gray-300 border-b border-gray-200 dark:border-gray-600">
|
||||
<th
|
||||
class="pl-4 pr-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[160px] sm:w-[200px] lg:w-[240px] xl:w-[280px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue-500"
|
||||
class="pl-4 pr-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[160px] sm:w-[200px] lg:w-[240px] xl:w-[280px] 2xl:w-[380px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-blue-500"
|
||||
onClick={() => handleSort('name')}
|
||||
onKeyDown={(e) => e.key === 'Enter' && handleSort('name')}
|
||||
tabindex="0"
|
||||
|
|
@ -922,63 +922,63 @@ export function Dashboard(props: DashboardProps) {
|
|||
Name {sortKey() === 'name' && (sortDirection() === 'asc' ? '▲' : '▼')}
|
||||
</th>
|
||||
<th
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[48px] sm:w-[56px] lg:w-[60px] xl:w-[64px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[48px] sm:w-[56px] lg:w-[60px] xl:w-[64px] 2xl:w-[87px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
onClick={() => handleSort('type')}
|
||||
>
|
||||
Type {sortKey() === 'type' && (sortDirection() === 'asc' ? '▲' : '▼')}
|
||||
</th>
|
||||
<th
|
||||
class="px-1.5 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wide w-[44px] sm:w-[52px] lg:w-[60px] xl:w-[68px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
class="px-1.5 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wide w-[44px] sm:w-[52px] lg:w-[60px] xl:w-[68px] 2xl:w-[92px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
onClick={() => handleSort('vmid')}
|
||||
>
|
||||
VMID {sortKey() === 'vmid' && (sortDirection() === 'asc' ? '▲' : '▼')}
|
||||
</th>
|
||||
<th
|
||||
class="px-1.5 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wide w-[60px] sm:w-[70px] lg:w-[80px] xl:w-[92px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
class="px-1.5 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wide w-[60px] sm:w-[70px] lg:w-[80px] xl:w-[92px] 2xl:w-[125px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
onClick={() => handleSort('uptime')}
|
||||
>
|
||||
Uptime {sortKey() === 'uptime' && (sortDirection() === 'asc' ? '▲' : '▼')}
|
||||
</th>
|
||||
<th
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px] 2xl:w-[204px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
onClick={() => handleSort('cpu')}
|
||||
>
|
||||
CPU {sortKey() === 'cpu' && (sortDirection() === 'asc' ? '▲' : '▼')}
|
||||
</th>
|
||||
<th
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px] 2xl:w-[204px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
onClick={() => handleSort('memory')}
|
||||
>
|
||||
Memory {sortKey() === 'memory' && (sortDirection() === 'asc' ? '▲' : '▼')}
|
||||
</th>
|
||||
<th
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px] 2xl:w-[204px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
onClick={() => handleSort('disk')}
|
||||
>
|
||||
Disk {sortKey() === 'disk' && (sortDirection() === 'asc' ? '▲' : '▼')}
|
||||
</th>
|
||||
<th
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] 2xl:w-[106px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
onClick={() => handleSort('diskRead')}
|
||||
>
|
||||
Disk Read{' '}
|
||||
{sortKey() === 'diskRead' && (sortDirection() === 'asc' ? '▲' : '▼')}
|
||||
</th>
|
||||
<th
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] 2xl:w-[106px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
onClick={() => handleSort('diskWrite')}
|
||||
>
|
||||
Disk Write{' '}
|
||||
{sortKey() === 'diskWrite' && (sortDirection() === 'asc' ? '▲' : '▼')}
|
||||
</th>
|
||||
<th
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] 2xl:w-[106px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
onClick={() => handleSort('networkIn')}
|
||||
>
|
||||
Net In {sortKey() === 'networkIn' && (sortDirection() === 'asc' ? '▲' : '▼')}
|
||||
</th>
|
||||
<th
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
class="px-2 py-1 text-left text-[11px] sm:text-xs font-medium uppercase tracking-wider w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] 2xl:w-[106px] cursor-pointer hover:bg-gray-200 dark:hover:bg-gray-600"
|
||||
onClick={() => handleSort('networkOut')}
|
||||
>
|
||||
Net Out{' '}
|
||||
|
|
|
|||
|
|
@ -398,7 +398,7 @@ export function GuestRow(props: GuestRowProps) {
|
|||
// Get first cell styling
|
||||
const firstCellClass = createMemo(() => {
|
||||
const base =
|
||||
'py-0.5 pr-2 whitespace-nowrap relative w-[160px] sm:w-[200px] lg:w-[240px] xl:w-[280px]';
|
||||
'py-0.5 pr-2 whitespace-nowrap relative w-[160px] sm:w-[200px] lg:w-[240px] xl:w-[280px] 2xl:w-[380px]';
|
||||
const indent = props.isGroupedView ? GROUPED_FIRST_CELL_INDENT : DEFAULT_FIRST_CELL_INDENT;
|
||||
return `${base} ${indent}`;
|
||||
});
|
||||
|
|
@ -534,7 +534,7 @@ export function GuestRow(props: GuestRowProps) {
|
|||
</td>
|
||||
|
||||
{/* Type */}
|
||||
<td class="py-0.5 px-2 whitespace-nowrap w-[48px] sm:w-[56px] lg:w-[60px] xl:w-[64px]">
|
||||
<td class="py-0.5 px-2 whitespace-nowrap w-[48px] sm:w-[56px] lg:w-[60px] xl:w-[64px] 2xl:w-[87px]">
|
||||
<div class="flex h-[24px] items-center">
|
||||
<span
|
||||
class={`inline-block px-1.5 py-0.5 text-xs font-medium rounded ${
|
||||
|
|
@ -549,13 +549,13 @@ export function GuestRow(props: GuestRowProps) {
|
|||
</td>
|
||||
|
||||
{/* VMID */}
|
||||
<td class="py-0.5 px-1.5 whitespace-nowrap w-[44px] sm:w-[52px] lg:w-[60px] xl:w-[68px] text-sm text-gray-600 dark:text-gray-400 align-middle">
|
||||
<td class="py-0.5 px-1.5 whitespace-nowrap w-[44px] sm:w-[52px] lg:w-[60px] xl:w-[68px] 2xl:w-[92px] text-sm text-gray-600 dark:text-gray-400 align-middle">
|
||||
{props.guest.vmid}
|
||||
</td>
|
||||
|
||||
{/* Uptime */}
|
||||
<td
|
||||
class={`py-0.5 px-1.5 w-[60px] sm:w-[70px] lg:w-[80px] xl:w-[92px] text-sm whitespace-nowrap align-middle ${
|
||||
class={`py-0.5 px-1.5 w-[60px] sm:w-[70px] lg:w-[80px] xl:w-[92px] 2xl:w-[125px] text-sm whitespace-nowrap align-middle ${
|
||||
props.guest.uptime < 3600 ? 'text-orange-500' : 'text-gray-600 dark:text-gray-400'
|
||||
}`}
|
||||
>
|
||||
|
|
@ -565,7 +565,7 @@ export function GuestRow(props: GuestRowProps) {
|
|||
</td>
|
||||
|
||||
{/* CPU */}
|
||||
<td class="py-0.5 px-2 w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px]">
|
||||
<td class="py-0.5 px-2 w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px] 2xl:w-[204px]">
|
||||
<Show when={isRunning()} fallback={<span class="text-sm text-gray-400">-</span>}>
|
||||
<MetricBar
|
||||
value={cpuPercent()}
|
||||
|
|
@ -581,7 +581,7 @@ export function GuestRow(props: GuestRowProps) {
|
|||
</td>
|
||||
|
||||
{/* Memory */}
|
||||
<td class="py-0.5 px-2 w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px]">
|
||||
<td class="py-0.5 px-2 w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px] 2xl:w-[204px]">
|
||||
<div title={memoryTooltip() ?? undefined}>
|
||||
<Show when={isRunning()} fallback={<span class="text-sm text-gray-400">-</span>}>
|
||||
<MetricBar
|
||||
|
|
@ -595,7 +595,7 @@ export function GuestRow(props: GuestRowProps) {
|
|||
</td>
|
||||
|
||||
{/* Disk – surface usage even if guest is currently stopped so users can see last reported values */}
|
||||
<td class="py-0.5 px-2 w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px]">
|
||||
<td class="py-0.5 px-2 w-[100px] sm:w-[110px] lg:w-[130px] xl:w-[150px] 2xl:w-[204px]">
|
||||
<Show
|
||||
when={hasDiskUsage()}
|
||||
fallback={
|
||||
|
|
@ -618,24 +618,24 @@ export function GuestRow(props: GuestRowProps) {
|
|||
</td>
|
||||
|
||||
{/* Disk I/O */}
|
||||
<td class="py-0.5 px-2 w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px]">
|
||||
<td class="py-0.5 px-2 w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] 2xl:w-[106px]">
|
||||
<div class="flex h-[24px] items-center">
|
||||
<IOMetric value={props.guest.diskRead} disabled={!isRunning()} />
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-0.5 px-2 w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px]">
|
||||
<td class="py-0.5 px-2 w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] 2xl:w-[106px]">
|
||||
<div class="flex h-[24px] items-center">
|
||||
<IOMetric value={props.guest.diskWrite} disabled={!isRunning()} />
|
||||
</div>
|
||||
</td>
|
||||
|
||||
{/* Network I/O */}
|
||||
<td class="py-0.5 px-2 w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px]">
|
||||
<td class="py-0.5 px-2 w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] 2xl:w-[106px]">
|
||||
<div class="flex h-[24px] items-center">
|
||||
<IOMetric value={props.guest.networkIn} disabled={!isRunning()} />
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-0.5 px-2 w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px]">
|
||||
<td class="py-0.5 px-2 w-[56px] sm:w-[62px] lg:w-[70px] xl:w-[78px] 2xl:w-[106px]">
|
||||
<div class="flex h-[24px] items-center">
|
||||
<IOMetric value={props.guest.networkOut} disabled={!isRunning()} />
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@
|
|||
@layer components {
|
||||
.pulse-shell {
|
||||
width: 100%;
|
||||
max-width: 95rem;
|
||||
max-width: clamp(95rem, 92vw, 120rem);
|
||||
margin-inline: auto;
|
||||
padding-inline: clamp(1rem, 3vw, 3.25rem);
|
||||
transition: padding-inline 0.3s ease;
|
||||
|
|
|
|||
Loading…
Reference in a new issue