Header tiles: Trackers dropdown, dashboard and quick add as hoverable monochrome tiles
All checks were successful
Deploy production / deploy (push) Successful in 2m48s
All checks were successful
Deploy production / deploy (push) Successful in 2m48s
Lift + tint on hover, visible focus ring, aria-current for the dashboard, colourful icons on a black-and-white surface, prefers-reduced-motion respected.
This commit is contained in:
@@ -248,7 +248,7 @@
|
||||
class={[
|
||||
'absolute top-full z-50 max-h-[75vh] overflow-y-auto rounded-md border border-border bg-popover p-1 text-popover-foreground shadow-md',
|
||||
item.href === '/trackers'
|
||||
? 'left-1/2 grid w-[min(36rem,calc(100vw-2rem))] -translate-x-1/2 grid-cols-2 gap-x-1'
|
||||
? 'left-1/2 grid w-[min(36rem,calc(100vw-2rem))] -translate-x-1/2 grid-cols-2 gap-1.5 p-2'
|
||||
: 'left-0 w-72'
|
||||
]}
|
||||
aria-label={menu.label}
|
||||
@@ -266,10 +266,12 @@
|
||||
<a
|
||||
href={project.external ? project.href : resolve(project.href)}
|
||||
rel={project.external ? 'external' : undefined}
|
||||
class="flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent"
|
||||
class={item.href === '/trackers'
|
||||
? 'tile flex items-center gap-2.5 p-2 text-sm'
|
||||
: 'flex items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent'}
|
||||
>
|
||||
{#if item.href === '/trackers'}
|
||||
<TrackerIcon name={project.name} class="size-9" />
|
||||
<TrackerIcon name={project.name} class="tile-icon size-9" />
|
||||
{:else}
|
||||
<span
|
||||
class="flex size-8 shrink-0 items-center justify-center rounded border border-border bg-[var(--site-surface)] text-[var(--site-muted)]"
|
||||
@@ -301,22 +303,25 @@
|
||||
</nav>
|
||||
<div class="hidden items-center gap-1 md:flex">
|
||||
{#if data.isOwner}
|
||||
<Button
|
||||
<a
|
||||
href={resolve('/start')}
|
||||
variant={current('/start') ? 'secondary' : 'ghost'}
|
||||
size="sm"
|
||||
class="gap-1.5"
|
||||
class="tile flex h-8 items-center gap-1.5 px-2.5 text-sm"
|
||||
aria-current={current('/start') ? 'page' : undefined}
|
||||
title="Dashboard (g then d)"
|
||||
aria-keyshortcuts="g d"
|
||||
><LayoutDashboard size={16} aria-hidden="true" />dashboard</Button
|
||||
><span class="tile-icon accent-dashboard size-5"
|
||||
><LayoutDashboard size={13} aria-hidden="true" /></span
|
||||
>dashboard</a
|
||||
>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
<button
|
||||
type="button"
|
||||
class="tile flex size-8 items-center justify-center"
|
||||
onclick={openQuickAdd}
|
||||
aria-label="Quick add task"
|
||||
title="Quick add task (g then t)"
|
||||
aria-keyshortcuts="g t"><Plus size={18} aria-hidden="true" /></Button
|
||||
aria-keyshortcuts="g t"
|
||||
><span class="tile-icon accent-add size-5"><Plus size={14} aria-hidden="true" /></span
|
||||
></button
|
||||
>
|
||||
{/if}
|
||||
<Button
|
||||
@@ -352,16 +357,25 @@
|
||||
>
|
||||
<nav class="flex flex-col gap-1" aria-label="Mobile navigation">
|
||||
{#if data.isOwner}
|
||||
<Button
|
||||
href={resolve('/start')}
|
||||
variant="outline"
|
||||
class="mb-2 justify-start gap-2"
|
||||
onclick={() => (menuOpen = false)}
|
||||
><LayoutDashboard size={16} aria-hidden="true" />dashboard</Button
|
||||
>
|
||||
<Button variant="outline" class="mb-2 justify-start gap-2" onclick={openQuickAdd}
|
||||
><Plus size={16} aria-hidden="true" />quick add task</Button
|
||||
>
|
||||
<div class="mb-2 grid grid-cols-2 gap-1.5">
|
||||
<a
|
||||
href={resolve('/start')}
|
||||
class="tile flex items-center gap-2 p-2 text-sm"
|
||||
aria-current={current('/start') ? 'page' : undefined}
|
||||
onclick={() => (menuOpen = false)}
|
||||
><span class="tile-icon accent-dashboard size-7"
|
||||
><LayoutDashboard size={15} aria-hidden="true" /></span
|
||||
>dashboard</a
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="tile flex items-center gap-2 p-2 text-left text-sm"
|
||||
onclick={openQuickAdd}
|
||||
><span class="tile-icon accent-add size-7"
|
||||
><Plus size={16} aria-hidden="true" /></span
|
||||
>add task</button
|
||||
>
|
||||
</div>
|
||||
{/if}
|
||||
{#each navigation as item (item.href)}
|
||||
<Button
|
||||
@@ -372,15 +386,15 @@
|
||||
>
|
||||
{#if menus[item.href]}
|
||||
{#if item.href === '/trackers'}
|
||||
<div class="ml-3 grid grid-cols-2 gap-1 border-l border-border pl-3">
|
||||
<div class="ml-3 grid grid-cols-2 gap-1.5 border-l border-border py-1 pl-3">
|
||||
{#each menus[item.href].items as project (project.name)}
|
||||
<!-- eslint-disable svelte/no-navigation-without-resolve -->
|
||||
<a
|
||||
href={project.external ? project.href : resolve(project.href)}
|
||||
class="flex min-w-0 items-center gap-2 rounded-md px-1.5 py-1.5 text-sm hover:bg-accent hover:text-accent-foreground"
|
||||
class="tile flex min-w-0 items-center gap-2 p-1.5 text-sm"
|
||||
onclick={() => (menuOpen = false)}
|
||||
><TrackerIcon name={project.name} class="size-7" /><span class="truncate"
|
||||
>{project.name}</span
|
||||
><TrackerIcon name={project.name} class="tile-icon size-7" /><span
|
||||
class="truncate">{project.name}</span
|
||||
></a
|
||||
>
|
||||
<!-- eslint-enable svelte/no-navigation-without-resolve -->
|
||||
@@ -485,6 +499,73 @@
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
/* Header tiles: monochrome surface (border, hover tint, lift), colourful content.
|
||||
Used by the Trackers dropdown, the dashboard and quick add buttons. */
|
||||
.tile {
|
||||
position: relative;
|
||||
border: 1px solid color-mix(in oklab, var(--foreground) 9%, transparent);
|
||||
border-radius: 0.6rem;
|
||||
background: color-mix(in oklab, var(--foreground) 2%, transparent);
|
||||
color: var(--foreground);
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
transition:
|
||||
transform 160ms cubic-bezier(0.2, 0.8, 0.2, 1),
|
||||
background-color 160ms ease,
|
||||
border-color 160ms ease,
|
||||
box-shadow 160ms ease;
|
||||
}
|
||||
.tile:hover {
|
||||
background: color-mix(in oklab, var(--foreground) 6%, transparent);
|
||||
border-color: color-mix(in oklab, var(--foreground) 22%, transparent);
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 6px 16px -10px rgb(0 0 0 / 0.45);
|
||||
}
|
||||
.tile:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: none;
|
||||
}
|
||||
.tile:focus-visible {
|
||||
outline: 2px solid var(--foreground);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
.tile[aria-current='page'] {
|
||||
background: color-mix(in oklab, var(--foreground) 9%, transparent);
|
||||
border-color: color-mix(in oklab, var(--foreground) 35%, transparent);
|
||||
}
|
||||
.tile :global(.tile-icon) {
|
||||
transition: transform 160ms cubic-bezier(0.2, 0.8, 0.2, 1);
|
||||
}
|
||||
.tile:hover :global(.tile-icon) {
|
||||
transform: scale(1.06);
|
||||
}
|
||||
.accent-dashboard,
|
||||
.accent-add {
|
||||
display: inline-flex;
|
||||
flex-shrink: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
border-radius: 0.35rem;
|
||||
color: #fff;
|
||||
}
|
||||
.accent-dashboard {
|
||||
background-image: linear-gradient(135deg, #6366f1, #8b5cf6);
|
||||
}
|
||||
.accent-add {
|
||||
background-image: linear-gradient(135deg, #10b981, #0d9488);
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.tile,
|
||||
.tile :global(.tile-icon) {
|
||||
transition:
|
||||
background-color 160ms ease,
|
||||
border-color 160ms ease;
|
||||
}
|
||||
.tile:hover,
|
||||
.tile:hover :global(.tile-icon) {
|
||||
transform: none;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1100px) and (min-height: 700px) {
|
||||
.cod-footer {
|
||||
display: none;
|
||||
|
||||
Reference in New Issue
Block a user