fix: keep navigation headings visible

This commit is contained in:
Federico Jaramillo Martinez
2026-05-28 15:06:55 +02:00
parent 3bd4773c87
commit 1c1740aeab
5 changed files with 66 additions and 48 deletions
@@ -0,0 +1,5 @@
---
"@jmfederico/pi-web": patch
---
Keep left navigation section titles visible while project, workspace, and session lists scroll.
+23 -19
View File
@@ -44,27 +44,31 @@ export class ProjectList extends LitElement {
return html`
<section>
<h2>${this.renderHeading()}</h2>
${this.collapsed ? null : this.projects.map((project) => html`
<div
class=${`action-row ${this.selected?.id === project.id ? "selected" : ""}`}
tabindex="0"
title=${project.path}
@click=${(event: MouseEvent) => { activateSelectableRow(event, () => this.onSelect?.(project)); }}
@keydown=${(event: KeyboardEvent) => { activateSelectableRowFromKeyboard(event, () => this.onSelect?.(project)); }}
>
<div class="action-main">
<span class="action-name">${project.name}</span><small>${this.renderActivity(project)}${project.path}</small>
</div>
<div class="action-menu">
<button class="action-menu-toggle" title="Project actions" aria-label=${`Actions for ${project.name}`} @click=${(event: MouseEvent) => { event.stopPropagation(); this.toggleMenu(project.id, event.currentTarget); }}>⋯</button>
${this.openMenuProjectId === project.id ? html`
<div class="action-menu-panel" style=${this.menuStyle}>
<button title="Close project" @click=${() => { this.close(project); }}>Close</button>
${this.collapsed ? null : html`
<div class="list-body">
${this.projects.map((project) => html`
<div
class=${`action-row ${this.selected?.id === project.id ? "selected" : ""}`}
tabindex="0"
title=${project.path}
@click=${(event: MouseEvent) => { activateSelectableRow(event, () => this.onSelect?.(project)); }}
@keydown=${(event: KeyboardEvent) => { activateSelectableRowFromKeyboard(event, () => this.onSelect?.(project)); }}
>
<div class="action-main">
<span class="action-name">${project.name}</span><small>${this.renderActivity(project)}${project.path}</small>
</div>
` : null}
</div>
<div class="action-menu">
<button class="action-menu-toggle" title="Project actions" aria-label=${`Actions for ${project.name}`} @click=${(event: MouseEvent) => { event.stopPropagation(); this.toggleMenu(project.id, event.currentTarget); }}>⋯</button>
${this.openMenuProjectId === project.id ? html`
<div class="action-menu-panel" style=${this.menuStyle}>
<button title="Close project" @click=${() => { this.close(project); }}>Close</button>
</div>
` : null}
</div>
</div>
`)}
</div>
`)}
`}
</section>
`;
}
+9 -5
View File
@@ -76,11 +76,15 @@ export class SessionList extends LitElement {
return html`
<section>
${this.renderHeading(activeRows.length + archivedRows.length)}
${this.collapsed ? null : activeRows.map((row) => this.renderSession(row, descendantCounts.get(row.session.id) ?? 0))}
${this.collapsed ? null : archivedRows.length > 0 ? html`
<h2 class="subheading"><button class="section-toggle" aria-expanded=${String(this.archivedExpanded)} @click=${() => { this.toggleArchived(); }}><span>${this.archivedExpanded ? "▾" : "▸"} Archived</span><small>${archivedRows.length}</small></button></h2>
${this.archivedExpanded ? archivedRows.map((row) => this.renderSession(row, descendantCounts.get(row.session.id) ?? 0)) : null}
` : null}
${this.collapsed ? null : html`
<div class="list-body">
${activeRows.map((row) => this.renderSession(row, descendantCounts.get(row.session.id) ?? 0))}
${archivedRows.length > 0 ? html`
<h2 class="subheading"><button class="section-toggle" aria-expanded=${String(this.archivedExpanded)} @click=${() => { this.toggleArchived(); }}><span>${this.archivedExpanded ? "▾" : "▸"} Archived</span><small>${archivedRows.length}</small></button></h2>
${this.archivedExpanded ? archivedRows.map((row) => this.renderSession(row, descendantCounts.get(row.session.id) ?? 0)) : null}
` : null}
</div>
`}
</section>
`;
}
+22 -18
View File
@@ -49,24 +49,28 @@ export class WorkspaceList extends LitElement {
return html`
<section>
<h2>${this.renderHeading()}</h2>
${this.collapsed ? null : this.workspaces.map((workspace) => {
const label = workspacePrimaryLabel(workspace);
const items = this.workspaceLabelItems(workspace);
return html`
<div
class=${`action-row workspace-row ${this.selected?.id === workspace.id ? "selected" : ""}`}
tabindex="0"
title=${label}
@click=${(event: MouseEvent) => { activateSelectableRow(event, () => this.onSelect?.(workspace)); }}
@keydown=${(event: KeyboardEvent) => { this.handleWorkspaceKeydown(event, workspace); }}
>
<div class="action-main">
${this.renderWorkspaceMain(label, items, workspace)}
</div>
${this.renderWorkspaceMenu(label, items, workspace)}
</div>
`;
})}
${this.collapsed ? null : html`
<div class="list-body">
${this.workspaces.map((workspace) => {
const label = workspacePrimaryLabel(workspace);
const items = this.workspaceLabelItems(workspace);
return html`
<div
class=${`action-row workspace-row ${this.selected?.id === workspace.id ? "selected" : ""}`}
tabindex="0"
title=${label}
@click=${(event: MouseEvent) => { activateSelectableRow(event, () => this.onSelect?.(workspace)); }}
@keydown=${(event: KeyboardEvent) => { this.handleWorkspaceKeydown(event, workspace); }}
>
<div class="action-main">
${this.renderWorkspaceMain(label, items, workspace)}
</div>
${this.renderWorkspaceMenu(label, items, workspace)}
</div>
`;
})}
</div>
`}
</section>
`;
}
+7 -6
View File
@@ -55,8 +55,8 @@ export const appStyles = css`
aside { grid-column: 1; display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
header { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 12px; border-bottom: 1px solid var(--pi-border); }
.header-actions { display: flex; align-items: center; gap: 8px; }
project-list, workspace-list { flex: 0 0 auto; max-height: 26%; overflow: auto; border-bottom: 1px solid var(--pi-border-muted); }
session-list { flex: 1 1 auto; min-height: 0; overflow: auto; }
project-list, workspace-list { flex: 0 0 auto; max-height: 26%; min-height: 0; overflow: hidden; border-bottom: 1px solid var(--pi-border-muted); }
session-list { flex: 1 1 auto; min-height: 0; overflow: hidden; }
main { grid-column: 3; display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.context-bar { position: relative; flex: 0 0 auto; min-width: 0; display: none; align-items: center; gap: 0; padding: 6px 0; border-bottom: 1px solid var(--pi-border-muted); background: var(--pi-bg); }
.context-bar::before, .context-bar::after { content: ""; position: absolute; top: 0; bottom: 0; z-index: 2; width: 20px; opacity: 0; pointer-events: none; transition: opacity .15s ease; }
@@ -135,7 +135,7 @@ export const appStyles = css`
main.navigation-view .mobile-navigation-panel { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }
main.navigation-view .mobile-navigation-panel project-list,
main.navigation-view .mobile-navigation-panel workspace-list,
main.navigation-view .mobile-navigation-panel session-list { flex: 1 1 auto; max-height: none; min-height: 0; overflow: auto; }
main.navigation-view .mobile-navigation-panel session-list { flex: 1 1 auto; max-height: none; min-height: 0; overflow: hidden; }
main.navigation-view .mobile-navigation-panel project-list[collapsed],
main.navigation-view .mobile-navigation-panel workspace-list[collapsed],
main.navigation-view .mobile-navigation-panel session-list[collapsed] { flex: 0 0 auto; min-height: auto; overflow: hidden; }
@@ -201,10 +201,11 @@ export const workspacePanelStyles = css`
`;
export const listStyles = css`
:host { display: block; color: var(--pi-text); font: 14px system-ui, sans-serif; }
:host { display: flex; flex-direction: column; min-height: 0; overflow: hidden; color: var(--pi-text); font: 14px system-ui, sans-serif; }
:host([collapsed]) { flex: 0 0 auto; min-height: auto; overflow: hidden; }
section { padding: 10px; }
h2 { display: flex; justify-content: space-between; align-items: center; gap: 8px; margin: 0 0 8px; color: var(--pi-muted); font-size: 12px; text-transform: uppercase; }
section { box-sizing: border-box; flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; padding: 10px; }
h2 { flex: 0 0 auto; display: flex; justify-content: space-between; align-items: center; gap: 8px; margin: 0 0 8px; color: var(--pi-muted); font-size: 12px; text-transform: uppercase; }
.list-body { flex: 1 1 auto; min-height: 0; overflow: auto; }
button { border: 1px solid var(--pi-border); border-radius: 8px; background: var(--pi-surface); color: var(--pi-text); padding: 7px 9px; cursor: pointer; }
section > button { display: block; width: 100%; text-align: left; margin: 6px 0; }
.subheading { margin-top: 14px; }