web: refine workspace sidebar navigation
This commit is contained in:
@@ -159,6 +159,9 @@ Deno.test("workspace Tickets surface provides Kanban and lifecycle controls", as
|
|||||||
const ticketsNav = await Deno.readTextFile(
|
const ticketsNav = await Deno.readTextFile(
|
||||||
new URL("../sidebar/TicketsNavSection.svelte", import.meta.url),
|
new URL("../sidebar/TicketsNavSection.svelte", import.meta.url),
|
||||||
);
|
);
|
||||||
|
const objectivesNav = await Deno.readTextFile(
|
||||||
|
new URL("../sidebar/ObjectivesNavSection.svelte", import.meta.url),
|
||||||
|
);
|
||||||
const ticketsLoad = await Deno.readTextFile(
|
const ticketsLoad = await Deno.readTextFile(
|
||||||
new URL(
|
new URL(
|
||||||
"./../../../routes/w/[workspaceId]/tickets/+page.ts",
|
"./../../../routes/w/[workspaceId]/tickets/+page.ts",
|
||||||
@@ -204,8 +207,15 @@ Deno.test("workspace Tickets surface provides Kanban and lifecycle controls", as
|
|||||||
|
|
||||||
assert(
|
assert(
|
||||||
ticketsNav.includes("workspaceRoute(workspaceId, '/tickets')") &&
|
ticketsNav.includes("workspaceRoute(workspaceId, '/tickets')") &&
|
||||||
ticketsNav.includes("Open Tickets"),
|
ticketsNav.includes('class="primary-nav-link"') &&
|
||||||
"Tickets sidebar section should link to the workspace Tickets surface",
|
ticketsNav.includes(">Tickets</a>") &&
|
||||||
|
!ticketsNav.includes("Open Tickets") &&
|
||||||
|
!ticketsNav.includes("workspace tickets") &&
|
||||||
|
objectivesNav.includes('class="primary-nav-link"') &&
|
||||||
|
objectivesNav.includes(">Objectives</a>") &&
|
||||||
|
!objectivesNav.includes("Open Objectives") &&
|
||||||
|
!objectivesNav.includes("workspace objectives"),
|
||||||
|
"Tickets and Objectives should each be a single sidebar link",
|
||||||
);
|
);
|
||||||
assert(
|
assert(
|
||||||
ticketsLoad.includes("?limit=1000") &&
|
ticketsLoad.includes("?limit=1000") &&
|
||||||
|
|||||||
@@ -33,8 +33,8 @@
|
|||||||
min-width: 0;
|
min-width: 0;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 0.55rem;
|
gap: 0.55rem;
|
||||||
color: var(--workspace-muted, #53606e);
|
color: var(--text-muted);
|
||||||
font-family: var(--workspace-font-mono, monospace);
|
font-family: var(--font-mono);
|
||||||
font-size: 0.84rem;
|
font-size: 0.84rem;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.workspace-breadcrumbs a:hover {
|
.workspace-breadcrumbs a:hover {
|
||||||
color: var(--workspace-ink, #151b23);
|
color: var(--text-strong);
|
||||||
text-decoration: underline;
|
text-decoration: underline;
|
||||||
text-underline-offset: 0.22rem;
|
text-underline-offset: 0.22rem;
|
||||||
}
|
}
|
||||||
@@ -68,7 +68,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.workspace-breadcrumbs span[aria-current='page'] {
|
.workspace-breadcrumbs span[aria-current='page'] {
|
||||||
color: var(--workspace-ink, #151b23);
|
color: var(--text-strong);
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -11,12 +11,10 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="nav-section">
|
<section class="nav-section">
|
||||||
<header class="section-header">
|
<a
|
||||||
<span>Objectives</span>
|
class="primary-nav-link"
|
||||||
</header>
|
class:active={currentPath.startsWith(objectivesHref)}
|
||||||
|
href={objectivesHref}
|
||||||
<a class="objective-link" class:active={currentPath.startsWith(objectivesHref)} href={objectivesHref}>
|
aria-current={currentPath.startsWith(objectivesHref) ? 'page' : undefined}
|
||||||
<span class="item-title">Open Objectives</span>
|
>Objectives</a>
|
||||||
<span class="item-meta">workspace objectives</span>
|
|
||||||
</a>
|
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -15,6 +15,12 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<aside class="sidebar-frame" class:folded aria-label="Sidebar">
|
<aside class="sidebar-frame" class:folded aria-label="Sidebar">
|
||||||
|
{#if !folded}
|
||||||
|
<div class="sidebar-frame-content">
|
||||||
|
{@render children()}
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
<div class="sidebar-control-row">
|
<div class="sidebar-control-row">
|
||||||
<button
|
<button
|
||||||
class="sidebar-fold-button"
|
class="sidebar-fold-button"
|
||||||
@@ -37,10 +43,4 @@
|
|||||||
{/if}
|
{/if}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if !folded}
|
|
||||||
<div class="sidebar-frame-content">
|
|
||||||
{@render children()}
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
</aside>
|
</aside>
|
||||||
|
|||||||
@@ -11,12 +11,10 @@
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<section class="nav-section">
|
<section class="nav-section">
|
||||||
<header class="section-header">
|
<a
|
||||||
<span>Tickets</span>
|
class="primary-nav-link"
|
||||||
</header>
|
class:active={currentPath.startsWith(ticketsHref)}
|
||||||
|
href={ticketsHref}
|
||||||
<a class="objective-link" class:active={currentPath.startsWith(ticketsHref)} href={ticketsHref}>
|
aria-current={currentPath.startsWith(ticketsHref) ? 'page' : undefined}
|
||||||
<span class="item-title">Open Tickets</span>
|
>Tickets</a>
|
||||||
<span class="item-meta">workspace tickets</span>
|
|
||||||
</a>
|
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@@ -78,9 +78,9 @@
|
|||||||
|
|
||||||
<nav class="sidebar-sections" aria-label="Workspace sections">
|
<nav class="sidebar-sections" aria-label="Workspace sections">
|
||||||
<RepositoriesNavSection {repositories} {repositoriesError} {currentPath} {workspaceId} />
|
<RepositoriesNavSection {repositories} {repositoriesError} {currentPath} {workspaceId} />
|
||||||
|
<TicketsNavSection {currentPath} {workspaceId} />
|
||||||
<ObjectivesNavSection {currentPath} {workspaceId} />
|
<ObjectivesNavSection {currentPath} {workspaceId} />
|
||||||
<MemoryNavSection {currentPath} {workspaceId} />
|
<MemoryNavSection {currentPath} {workspaceId} />
|
||||||
<TicketsNavSection {currentPath} {workspaceId} />
|
|
||||||
<WorkersNavSection {currentPath} {workspaceId} />
|
<WorkersNavSection {currentPath} {workspaceId} />
|
||||||
</nav>
|
</nav>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -4,17 +4,26 @@
|
|||||||
.sidebar-frame {
|
.sidebar-frame {
|
||||||
grid-column: 1;
|
grid-column: 1;
|
||||||
grid-row: 1 / 3;
|
grid-row: 1 / 3;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
width: clamp(220px, 20vw, 280px);
|
width: clamp(220px, 20vw, 280px);
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
overflow-y: auto;
|
overflow: hidden;
|
||||||
padding: var(--space-4) var(--space-3);
|
padding-block: var(--space-4);
|
||||||
border-right: 1px solid var(--line);
|
border-right: 1px solid var(--line);
|
||||||
}
|
}
|
||||||
.sidebar-frame.folded {
|
.sidebar-frame.folded {
|
||||||
width: max-content;
|
width: max-content;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
padding-inline: var(--space-2);
|
padding-inline: 0;
|
||||||
|
}
|
||||||
|
.sidebar-frame-content {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
min-height: 0;
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-inline: var(--space-3);
|
||||||
}
|
}
|
||||||
.sidebar-frame-content,
|
.sidebar-frame-content,
|
||||||
.global-sidebar,
|
.global-sidebar,
|
||||||
@@ -40,11 +49,13 @@
|
|||||||
gap: var(--space-1);
|
gap: var(--space-1);
|
||||||
}
|
}
|
||||||
.sidebar-control-row {
|
.sidebar-control-row {
|
||||||
margin-bottom: var(--space-2);
|
margin-top: auto;
|
||||||
|
padding: var(--space-4) var(--space-3) 0;
|
||||||
}
|
}
|
||||||
.sidebar-frame.folded .sidebar-control-row {
|
.sidebar-frame.folded .sidebar-control-row {
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
margin-bottom: 0;
|
padding-inline: var(--space-2);
|
||||||
|
padding-top: 0;
|
||||||
}
|
}
|
||||||
.sidebar-title-row {
|
.sidebar-title-row {
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -116,7 +127,7 @@
|
|||||||
}
|
}
|
||||||
.sidebar-sections {
|
.sidebar-sections {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: var(--space-5);
|
gap: var(--space-3);
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
}
|
}
|
||||||
.nav-section {
|
.nav-section {
|
||||||
@@ -165,6 +176,7 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
list-style: none;
|
list-style: none;
|
||||||
}
|
}
|
||||||
|
.primary-nav-link,
|
||||||
.nav-item,
|
.nav-item,
|
||||||
.objective-link,
|
.objective-link,
|
||||||
.sidebar-link {
|
.sidebar-link {
|
||||||
@@ -179,6 +191,13 @@
|
|||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
transition: background-color 140ms ease, color 140ms ease;
|
transition: background-color 140ms ease, color 140ms ease;
|
||||||
}
|
}
|
||||||
|
.primary-nav-link {
|
||||||
|
color: var(--text-strong);
|
||||||
|
font-size: 0.9rem;
|
||||||
|
font-weight: 700;
|
||||||
|
}
|
||||||
|
a.primary-nav-link:hover,
|
||||||
|
a.primary-nav-link:focus-visible,
|
||||||
a.nav-item:hover,
|
a.nav-item:hover,
|
||||||
a.nav-item:focus-visible,
|
a.nav-item:focus-visible,
|
||||||
a.objective-link:hover,
|
a.objective-link:hover,
|
||||||
@@ -187,11 +206,13 @@
|
|||||||
a.sidebar-link:focus-visible {
|
a.sidebar-link:focus-visible {
|
||||||
background: var(--interactive-hover);
|
background: var(--interactive-hover);
|
||||||
}
|
}
|
||||||
|
a.primary-nav-link.active,
|
||||||
a.nav-item.active,
|
a.nav-item.active,
|
||||||
a.objective-link.active,
|
a.objective-link.active,
|
||||||
a.sidebar-link.active {
|
a.sidebar-link.active {
|
||||||
background: var(--interactive-selected);
|
background: var(--interactive-selected);
|
||||||
}
|
}
|
||||||
|
a.primary-nav-link.active,
|
||||||
a.nav-item.active .item-title,
|
a.nav-item.active .item-title,
|
||||||
a.objective-link.active .item-title,
|
a.objective-link.active .item-title,
|
||||||
a.sidebar-link.active {
|
a.sidebar-link.active {
|
||||||
|
|||||||
Reference in New Issue
Block a user