Add Prettier and ESLint tooling (Refs #77)

This commit is contained in:
2026-10-09 15:56:13 -04:00
parent 8ed059b8d3
commit 16469e2d43
711 changed files with 99737 additions and 28286 deletions
+103 -22
View File
@@ -11,12 +11,32 @@
const groups = $derived(visibleNavigation(role));
const attention = $derived.by(() => {
if (!$fleet.receivedAt) return null;
const statuses = $fleetServers.map(server => ({ server, state: serverHealth(server, $uiNow).state }));
const servers = statuses.filter(({ server, state }) => !['online', 'starting', 'provisioning'].includes(state)
|| $fleet.operations.some(operation => operation.server === server.name && operation.state === 'attention')).length;
const hosts = $fleet.hostAttention ?? new Set(statuses.filter(({ server, state }) => server.host && state === 'host-offline').map(({ server }) => server.host!.id)).size;
const maintenance = $fleet.operations.filter(operation => operation.kind === 'maintenance' && operation.state === 'attention').length;
return { '/': servers, '/hosts': hosts, '/maintenance': maintenance } as Record<string, number>;
const statuses = $fleetServers.map((server) => ({
server,
state: serverHealth(server, $uiNow).state
}));
const servers = statuses.filter(
({ server, state }) =>
!['online', 'starting', 'provisioning'].includes(state) ||
$fleet.operations.some(
(operation) =>
operation.server === server.name && operation.state === 'attention'
)
).length;
const hosts =
$fleet.hostAttention ??
new Set(
statuses
.filter(({ server, state }) => server.host && state === 'host-offline')
.map(({ server }) => server.host!.id)
).size;
const maintenance = $fleet.operations.filter(
(operation) => operation.kind === 'maintenance' && operation.state === 'attention'
).length;
return { '/': servers, '/hosts': hosts, '/maintenance': maintenance } as Record<
string,
number
>;
});
</script>
@@ -24,25 +44,86 @@
{#each groups as group (group.id)}
<section aria-labelledby={`${id}-${group.id}`}>
<h2 id={`${id}-${group.id}`}>{group.label}</h2>
<ul>{#each group.items as item (item.href)}
<li><a href={item.href} aria-current={navigationItemActive(item, $page.url.pathname) ? 'page' : undefined}
aria-label={attention && attention[item.href] > 0 ? `${item.label}, ${attention[item.href]} ${attention[item.href] === 1 ? 'needs' : 'need'} attention` : undefined} onclick={() => onNavigate?.()}>
<span>{item.label}</span>
{#if attention && attention[item.href] > 0}<span class="attention" aria-hidden="true">{attention[item.href]}</span>{/if}
</a></li>
{/each}</ul>
<ul>
{#each group.items as item (item.href)}
<li>
<a
href={item.href}
aria-current={navigationItemActive(item, $page.url.pathname)
? 'page'
: undefined}
aria-label={attention && attention[item.href] > 0
? `${item.label}, ${attention[item.href]} ${attention[item.href] === 1 ? 'needs' : 'need'} attention`
: undefined}
onclick={() => onNavigate?.()}
>
<span>{item.label}</span>
{#if attention && attention[item.href] > 0}<span
class="attention"
aria-hidden="true">{attention[item.href]}</span
>{/if}
</a>
</li>
{/each}
</ul>
</section>
{/each}
</nav>
<style>
nav { display: grid; gap: var(--space-4); min-width: 0; }
h2 { margin: 0 0 var(--space-1); padding: 0 var(--space-3); color: var(--text-tertiary); font-size: var(--text-xs); font-weight: var(--weight-semibold); letter-spacing: var(--tracking-label); text-transform: uppercase; }
ul { list-style: none; padding: 0; margin: 0; }
a { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); min-height: 32px; padding: 5px var(--space-3); border-radius: var(--radius-sm); color: var(--text-secondary); font-size: var(--text-sm); text-decoration: none; }
a:hover { color: var(--text-primary); background: var(--surface-raised); }
a[aria-current] { color: var(--text-primary); background: var(--surface-raised); box-shadow: inset 2px 0 var(--accent-primary); font-weight: var(--weight-semibold); }
a:focus-visible { outline-offset: -2px; }
.attention { color: var(--state-warning); font-variant-numeric: tabular-nums; font-size: var(--text-xs); font-weight: var(--weight-semibold); }
@media (max-width: 960px) { a { min-height: 44px; } }
nav {
display: grid;
gap: var(--space-4);
min-width: 0;
}
h2 {
margin: 0 0 var(--space-1);
padding: 0 var(--space-3);
color: var(--text-tertiary);
font-size: var(--text-xs);
font-weight: var(--weight-semibold);
letter-spacing: var(--tracking-label);
text-transform: uppercase;
}
ul {
list-style: none;
padding: 0;
margin: 0;
}
a {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--space-2);
min-height: 32px;
padding: 5px var(--space-3);
border-radius: var(--radius-sm);
color: var(--text-secondary);
font-size: var(--text-sm);
text-decoration: none;
}
a:hover {
color: var(--text-primary);
background: var(--surface-raised);
}
a[aria-current] {
color: var(--text-primary);
background: var(--surface-raised);
box-shadow: inset 2px 0 var(--accent-primary);
font-weight: var(--weight-semibold);
}
a:focus-visible {
outline-offset: -2px;
}
.attention {
color: var(--state-warning);
font-variant-numeric: tabular-nums;
font-size: var(--text-xs);
font-weight: var(--weight-semibold);
}
@media (max-width: 960px) {
a {
min-height: 44px;
}
}
</style>