Archived
feat: make desktop navigation sections collapsible
This commit is contained in:
committed by
Federico Jaramillo Martinez
parent
f7eff88e00
commit
9a3f2ce64f
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"@jmfederico/pi-web": patch
|
||||
---
|
||||
|
||||
Make navigation sections collapsible on desktop and auto-collapse completed context sections after selections.
|
||||
@@ -1,5 +1,5 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { defaultNavigationSection, expandedNavigationSection, isNavigationSectionCollapsed, toggleNavigationSection } from "./navigationState";
|
||||
import { collapsedNavigationSectionsAfterSelection, defaultNavigationSection, expandedNavigationSection, isNavigationSectionCollapsed, toggleCollapsedNavigationSection, toggleNavigationSection } from "./navigationState";
|
||||
|
||||
describe("navigationState", () => {
|
||||
it("defaults to the first incomplete selection section", () => {
|
||||
@@ -16,15 +16,22 @@ describe("navigationState", () => {
|
||||
expect(expandedNavigationSection("none", state)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("only collapses sections in mobile navigation layouts", () => {
|
||||
it("uses the mobile accordion state on mobile layouts", () => {
|
||||
const state = { selectedProject: {}, selectedWorkspace: {} };
|
||||
|
||||
expect(isNavigationSectionCollapsed("projects", { isMobileLayout: false, expanded: "sessions", state })).toBe(false);
|
||||
expect(isNavigationSectionCollapsed("projects", { isMobileLayout: true, expanded: "sessions", state })).toBe(true);
|
||||
expect(isNavigationSectionCollapsed("sessions", { isMobileLayout: true, expanded: "sessions", state })).toBe(false);
|
||||
});
|
||||
|
||||
it("toggles the effective section, including the implicit default section", () => {
|
||||
it("uses independent collapsed sections on desktop layouts", () => {
|
||||
const state = { selectedProject: {}, selectedWorkspace: {} };
|
||||
|
||||
expect(isNavigationSectionCollapsed("projects", { isMobileLayout: false, expanded: "sessions", state })).toBe(false);
|
||||
expect(isNavigationSectionCollapsed("projects", { isMobileLayout: false, expanded: "sessions", state, collapsedSections: ["projects"] })).toBe(true);
|
||||
expect(isNavigationSectionCollapsed("sessions", { isMobileLayout: false, expanded: "sessions", state, collapsedSections: ["projects"] })).toBe(false);
|
||||
});
|
||||
|
||||
it("toggles the effective mobile section, including the implicit default section", () => {
|
||||
const state = { selectedProject: undefined, selectedWorkspace: undefined };
|
||||
|
||||
expect(toggleNavigationSection(undefined, "projects", { isMobileLayout: true, state })).toBe("none");
|
||||
@@ -37,4 +44,17 @@ describe("navigationState", () => {
|
||||
|
||||
expect(toggleNavigationSection("projects", "projects", { isMobileLayout: false, state })).toBe("projects");
|
||||
});
|
||||
|
||||
it("toggles desktop sections independently", () => {
|
||||
expect(toggleCollapsedNavigationSection([], "projects")).toEqual(["projects"]);
|
||||
expect(toggleCollapsedNavigationSection(["machines", "projects"], "projects")).toEqual(["machines"]);
|
||||
expect(toggleCollapsedNavigationSection(["sessions"], "machines")).toEqual(["machines", "sessions"]);
|
||||
});
|
||||
|
||||
it("collapses completed desktop sections and expands the next section after selection", () => {
|
||||
expect(collapsedNavigationSectionsAfterSelection([], "machines")).toEqual(["machines"]);
|
||||
expect(collapsedNavigationSectionsAfterSelection(["workspaces"], "projects")).toEqual(["machines", "projects"]);
|
||||
expect(collapsedNavigationSectionsAfterSelection([], "workspaces")).toEqual(["machines", "projects", "workspaces"]);
|
||||
expect(collapsedNavigationSectionsAfterSelection(["sessions"], "sessions")).toEqual(["machines", "projects", "workspaces"]);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { ReactiveController, ReactiveControllerHost } from "lit";
|
||||
|
||||
export type NavigationSection = "machines" | "projects" | "workspaces" | "sessions";
|
||||
export const NAVIGATION_SECTION_ORDER = ["machines", "projects", "workspaces", "sessions"] as const;
|
||||
export type NavigationSection = (typeof NAVIGATION_SECTION_ORDER)[number];
|
||||
export type ExpandedNavigationSection = NavigationSection | "none" | undefined;
|
||||
|
||||
export interface NavigationSelectionState {
|
||||
@@ -19,8 +20,9 @@ export function expandedNavigationSection(expanded: ExpandedNavigationSection, s
|
||||
return expanded ?? defaultNavigationSection(state);
|
||||
}
|
||||
|
||||
export function isNavigationSectionCollapsed(section: NavigationSection, options: { isMobileLayout: boolean; expanded: ExpandedNavigationSection; state: NavigationSelectionState }): boolean {
|
||||
return options.isMobileLayout && expandedNavigationSection(options.expanded, options.state) !== section;
|
||||
export function isNavigationSectionCollapsed(section: NavigationSection, options: { isMobileLayout: boolean; expanded: ExpandedNavigationSection; state: NavigationSelectionState; collapsedSections?: readonly NavigationSection[] | undefined }): boolean {
|
||||
if (options.isMobileLayout) return expandedNavigationSection(options.expanded, options.state) !== section;
|
||||
return options.collapsedSections?.includes(section) ?? false;
|
||||
}
|
||||
|
||||
export function toggleNavigationSection(expanded: ExpandedNavigationSection, section: NavigationSection, options: { isMobileLayout: boolean; state: NavigationSelectionState }): ExpandedNavigationSection {
|
||||
@@ -32,8 +34,32 @@ export function expandNavigationSection(expanded: ExpandedNavigationSection, sec
|
||||
return isMobileLayout ? section : expanded;
|
||||
}
|
||||
|
||||
export class MobileNavigationController implements ReactiveController {
|
||||
export function toggleCollapsedNavigationSection(collapsedSections: readonly NavigationSection[], section: NavigationSection): NavigationSection[] {
|
||||
const collapsed = new Set(collapsedSections);
|
||||
if (collapsed.has(section)) collapsed.delete(section);
|
||||
else collapsed.add(section);
|
||||
return orderedNavigationSections(collapsed);
|
||||
}
|
||||
|
||||
export function collapsedNavigationSectionsAfterSelection(collapsedSections: readonly NavigationSection[], selectedSection: NavigationSection): NavigationSection[] {
|
||||
const selectedIndex = NAVIGATION_SECTION_ORDER.indexOf(selectedSection);
|
||||
const collapsed = new Set(collapsedSections);
|
||||
const collapseThroughIndex = selectedSection === "sessions" ? selectedIndex - 1 : selectedIndex;
|
||||
for (const section of NAVIGATION_SECTION_ORDER.slice(0, collapseThroughIndex + 1)) collapsed.add(section);
|
||||
|
||||
const next = nextNavigationSection(selectedSection);
|
||||
if (next !== undefined) collapsed.delete(next);
|
||||
if (selectedSection === "sessions") collapsed.delete("sessions");
|
||||
return orderedNavigationSections(collapsed);
|
||||
}
|
||||
|
||||
export function nextNavigationSection(section: NavigationSection): NavigationSection | undefined {
|
||||
return NAVIGATION_SECTION_ORDER[NAVIGATION_SECTION_ORDER.indexOf(section) + 1];
|
||||
}
|
||||
|
||||
export class NavigationSectionsController implements ReactiveController {
|
||||
private expanded: ExpandedNavigationSection;
|
||||
private collapsedSections: readonly NavigationSection[] = [];
|
||||
|
||||
hostConnected(): void {
|
||||
return;
|
||||
@@ -56,15 +82,33 @@ export class MobileNavigationController implements ReactiveController {
|
||||
isMobileLayout: this.isMobileLayout(),
|
||||
expanded: this.expanded,
|
||||
state: this.getState(),
|
||||
collapsedSections: this.collapsedSections,
|
||||
});
|
||||
}
|
||||
|
||||
toggle(section: NavigationSection): void {
|
||||
this.setExpanded(toggleNavigationSection(this.expanded, section, { isMobileLayout: this.isMobileLayout(), state: this.getState() }));
|
||||
if (this.isMobileLayout()) {
|
||||
this.setExpanded(toggleNavigationSection(this.expanded, section, { isMobileLayout: true, state: this.getState() }));
|
||||
return;
|
||||
}
|
||||
this.setCollapsedSections(toggleCollapsedNavigationSection(this.collapsedSections, section));
|
||||
}
|
||||
|
||||
expand(section: NavigationSection): void {
|
||||
this.setExpanded(expandNavigationSection(this.expanded, section, this.isMobileLayout()));
|
||||
if (this.isMobileLayout()) {
|
||||
this.setExpanded(expandNavigationSection(this.expanded, section, true));
|
||||
return;
|
||||
}
|
||||
this.setCollapsedSections(this.collapsedSections.filter((collapsedSection) => collapsedSection !== section));
|
||||
}
|
||||
|
||||
advanceAfterSelection(section: NavigationSection): void {
|
||||
if (this.isMobileLayout()) {
|
||||
const next = nextNavigationSection(section);
|
||||
if (next !== undefined) this.expand(next);
|
||||
return;
|
||||
}
|
||||
this.setCollapsedSections(collapsedNavigationSectionsAfterSelection(this.collapsedSections, section));
|
||||
}
|
||||
|
||||
open(section: NavigationSection, openNavigationView: () => void): void {
|
||||
@@ -78,4 +122,19 @@ export class MobileNavigationController implements ReactiveController {
|
||||
this.expanded = expanded;
|
||||
this.host.requestUpdate();
|
||||
}
|
||||
|
||||
private setCollapsedSections(collapsedSections: readonly NavigationSection[]): void {
|
||||
if (navigationSectionListsEqual(this.collapsedSections, collapsedSections)) return;
|
||||
this.collapsedSections = collapsedSections;
|
||||
this.host.requestUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
function orderedNavigationSections(sections: Iterable<NavigationSection>): NavigationSection[] {
|
||||
const sectionSet = new Set(sections);
|
||||
return NAVIGATION_SECTION_ORDER.filter((section) => sectionSet.has(section));
|
||||
}
|
||||
|
||||
function navigationSectionListsEqual(first: readonly NavigationSection[], second: readonly NavigationSection[]): boolean {
|
||||
return first.length === second.length && first.every((section, index) => section === second[index]);
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ export class MachineList extends LitElement {
|
||||
if (!this.collapsible) return "Machines";
|
||||
const selectedSummary = this.selected?.name ?? "No machine selected";
|
||||
const selectedTitle = this.selected?.baseUrl ?? selectedSummary;
|
||||
return html`<button class="section-toggle" aria-expanded=${String(!this.collapsed)} @click=${() => { this.onToggleCollapsed?.(); }}><span class="section-title"><span class="section-name">${this.collapsed ? "▸" : "▾"} Machines</span><small class="section-selected" title=${selectedTitle}>${selectedSummary}</small></span><small class="section-count">${this.machines.length}</small></button>`;
|
||||
return html`<button class="section-toggle" aria-expanded=${String(!this.collapsed)} @click=${() => { this.onToggleCollapsed?.(); }}><span class="section-title"><span class="section-name">${this.collapsed ? "▸" : "▾"} Machines</span>${this.collapsed ? html`<small class="section-selected" title=${selectedTitle}>${selectedSummary}</small>` : null}</span><small class="section-count">${this.machines.length}</small></button>`;
|
||||
}
|
||||
|
||||
private toggleMenu(machineId: string, target: EventTarget | null): void {
|
||||
|
||||
@@ -27,7 +27,7 @@ import { loadExternalPlugins } from "../plugins/external";
|
||||
import { PluginRegistry, installPluginRuntimeScope, installWorkspacePanelScope } from "../plugins/registry";
|
||||
import { queryNamespace, readNamespacedString, setNamespacedQueryKey } from "../namespacedQueryArgs";
|
||||
import { AppShellController } from "../appShell/appShellController";
|
||||
import { MobileNavigationController, type NavigationSection } from "../appShell/navigationState";
|
||||
import { NavigationSectionsController, type NavigationSection } from "../appShell/navigationState";
|
||||
import { PanelCollapseController, mainViewClass } from "../appShell/panelCollapseController";
|
||||
import { readRoute, writeRoute, type AppRoute } from "../route";
|
||||
import { readSettingsSection, writeSettingsSection, type SettingsSection } from "../settingsRoute";
|
||||
@@ -127,7 +127,7 @@ export class PiWebApp extends LitElement {
|
||||
private readonly terminalSelection = new SessionStorageTerminalSelectionMemory();
|
||||
private readonly appShell = new AppShellController(this);
|
||||
private readonly panelCollapse = new PanelCollapseController(this);
|
||||
private readonly mobileNavigation = new MobileNavigationController(
|
||||
private readonly navigationSections = new NavigationSectionsController(
|
||||
this,
|
||||
() => this.state,
|
||||
() => this.appShell.isMobileNavigationLayout,
|
||||
@@ -777,10 +777,10 @@ export class PiWebApp extends LitElement {
|
||||
.selectedMachine=${this.state.selectedMachine}
|
||||
.machineStatuses=${this.state.machineStatuses}
|
||||
.machineActivities=${this.state.machineActivities}
|
||||
.machinesCollapsed=${this.mobileNavigation.isCollapsed("machines")}
|
||||
.onToggleMachines=${() => { this.mobileNavigation.toggle("machines"); }}
|
||||
.machinesCollapsed=${this.navigationSections.isCollapsed("machines")}
|
||||
.onToggleMachines=${() => { this.navigationSections.toggle("machines"); }}
|
||||
.onSelectMachine=${(machine: Machine) => this.withChatScrollTransition(async () => {
|
||||
this.mobileNavigation.expand("projects");
|
||||
this.navigationSections.advanceAfterSelection("machines");
|
||||
await this.selectMachineWithMemory(machine);
|
||||
})}
|
||||
.onRemoveMachine=${(machine: Machine) => { void this.removeMachine(machine); }}
|
||||
@@ -796,32 +796,42 @@ export class PiWebApp extends LitElement {
|
||||
.sessionActivities=${this.state.sessionActivities}
|
||||
.selectedSession=${this.state.selectedSession}
|
||||
.canStartSession=${!!this.state.selectedWorkspace}
|
||||
.collapsible=${this.appShell.isMobileNavigationLayout}
|
||||
.projectsCollapsed=${this.mobileNavigation.isCollapsed("projects")}
|
||||
.workspacesCollapsed=${this.mobileNavigation.isCollapsed("workspaces")}
|
||||
.sessionsCollapsed=${this.mobileNavigation.isCollapsed("sessions")}
|
||||
.collapsible=${true}
|
||||
.compact=${this.appShell.isMobileNavigationLayout}
|
||||
.projectsCollapsed=${this.navigationSections.isCollapsed("projects")}
|
||||
.workspacesCollapsed=${this.navigationSections.isCollapsed("workspaces")}
|
||||
.sessionsCollapsed=${this.navigationSections.isCollapsed("sessions")}
|
||||
.workspaceLabelItems=${(workspace: Workspace) => this.workspaceLabelItems(workspace)}
|
||||
.refreshControl=${this.appShell.shouldShowAppRefreshInHeader() ? this.renderAppRefresh() : undefined}
|
||||
.onShowActions=${() => { this.setState({ actionPaletteOpen: true }); }}
|
||||
.onToggleProjects=${() => { this.mobileNavigation.toggle("projects"); }}
|
||||
.onToggleWorkspaces=${() => { this.mobileNavigation.toggle("workspaces"); }}
|
||||
.onToggleSessions=${() => { this.mobileNavigation.toggle("sessions"); }}
|
||||
.onToggleProjects=${() => { this.navigationSections.toggle("projects"); }}
|
||||
.onToggleWorkspaces=${() => { this.navigationSections.toggle("workspaces"); }}
|
||||
.onToggleSessions=${() => { this.navigationSections.toggle("sessions"); }}
|
||||
.onSelectProject=${(project: Project) => this.withChatScrollTransition(async () => {
|
||||
this.mobileNavigation.expand("workspaces");
|
||||
this.navigationSections.advanceAfterSelection("projects");
|
||||
await this.workspaces.selectProject(project);
|
||||
})}
|
||||
.onCloseProject=${(project: Project) => this.projects.closeProject(project.id)}
|
||||
.onSelectWorkspace=${(workspace: Workspace) => this.withChatScrollTransition(async () => {
|
||||
this.mobileNavigation.expand("sessions");
|
||||
this.navigationSections.advanceAfterSelection("workspaces");
|
||||
await this.workspaces.selectWorkspace(workspace);
|
||||
})}
|
||||
.onDeleteWorkspace=${(workspace: Workspace) => { void this.deleteWorkspace(workspace); }}
|
||||
.onArchivedCollapsed=${() => { this.sessions.clearSelectionAfterArchivedCollapse(); }}
|
||||
.onStartSession=${() => openChatAfter(() => this.sessions.startSession())}
|
||||
.onSelectSession=${(session: SessionInfo) => openChatAfter(() => this.sessions.selectSession(session))}
|
||||
.onStartSession=${() => openChatAfter(() => {
|
||||
this.navigationSections.advanceAfterSelection("sessions");
|
||||
return this.sessions.startSession();
|
||||
})}
|
||||
.onSelectSession=${(session: SessionInfo) => openChatAfter(() => {
|
||||
this.navigationSections.advanceAfterSelection("sessions");
|
||||
return this.sessions.selectSession(session);
|
||||
})}
|
||||
.onArchiveSession=${(session: SessionInfo) => this.sessions.archiveSession(session)}
|
||||
.onArchiveSessionWithDescendants=${(session: SessionInfo) => this.sessions.archiveSessionWithDescendants(session)}
|
||||
.onRestoreSession=${(session: SessionInfo) => openChatAfter(() => this.sessions.restoreSession(session))}
|
||||
.onRestoreSession=${(session: SessionInfo) => openChatAfter(() => {
|
||||
this.navigationSections.advanceAfterSelection("sessions");
|
||||
return this.sessions.restoreSession(session);
|
||||
})}
|
||||
.onDeleteCachedNewSession=${(session: SessionInfo) => this.sessions.deleteCachedNewSession(session)}
|
||||
.onDetachParentSession=${(session: SessionInfo) => this.sessions.detachParent(session)}
|
||||
></app-navigation-panel>
|
||||
@@ -829,7 +839,7 @@ export class PiWebApp extends LitElement {
|
||||
}
|
||||
|
||||
private openNavigationSection(section: NavigationSection): void {
|
||||
this.mobileNavigation.open(section, () => { this.selectMainView("navigation"); });
|
||||
this.navigationSections.open(section, () => { this.selectMainView("navigation"); });
|
||||
}
|
||||
|
||||
private visibleWorkspacePanels(): QualifiedWorkspacePanelContribution[] {
|
||||
|
||||
@@ -77,7 +77,7 @@ export class ProjectList extends LitElement {
|
||||
if (!this.collapsible) return "Projects";
|
||||
const selectedSummary = this.selected?.name ?? "No project selected";
|
||||
const selectedTitle = this.selected?.path ?? selectedSummary;
|
||||
return html`<button class="section-toggle" aria-expanded=${String(!this.collapsed)} @click=${() => { this.onToggleCollapsed?.(); }}><span class="section-title"><span class="section-name">${this.collapsed ? "▸" : "▾"} Projects</span><small class="section-selected" title=${selectedTitle}>${selectedSummary}</small></span><small class="section-count">${this.projects.length}</small></button>`;
|
||||
return html`<button class="section-toggle" aria-expanded=${String(!this.collapsed)} @click=${() => { this.onToggleCollapsed?.(); }}><span class="section-title"><span class="section-name">${this.collapsed ? "▸" : "▾"} Projects</span>${this.collapsed ? html`<small class="section-selected" title=${selectedTitle}>${selectedSummary}</small>` : null}</span><small class="section-count">${this.projects.length}</small></button>`;
|
||||
}
|
||||
|
||||
private renderActivity(project: Project) {
|
||||
|
||||
@@ -95,7 +95,7 @@ export class SessionList extends LitElement {
|
||||
const selectedTitle = this.selected?.path ?? selectedSummary;
|
||||
return html`
|
||||
<h2>
|
||||
<button class="section-toggle" aria-expanded=${String(!this.collapsed)} @click=${() => { this.onToggleCollapsed?.(); }}><span class="section-title"><span class="section-name">${this.collapsed ? "▸" : "▾"} Sessions</span><small class="section-selected" title=${selectedTitle}>${selectedSummary}</small></span><small class="section-count">${sessionCount}</small></button>
|
||||
<button class="section-toggle" aria-expanded=${String(!this.collapsed)} @click=${() => { this.onToggleCollapsed?.(); }}><span class="section-title"><span class="section-name">${this.collapsed ? "▸" : "▾"} Sessions</span>${this.collapsed ? html`<small class="section-selected" title=${selectedTitle}>${selectedSummary}</small>` : null}</span><small class="section-count">${sessionCount}</small></button>
|
||||
<button ?disabled=${!this.canStart} @click=${(event: MouseEvent) => { event.stopPropagation(); this.onStart?.(); }}>+</button>
|
||||
</h2>
|
||||
`;
|
||||
|
||||
@@ -79,7 +79,7 @@ export class WorkspaceList extends LitElement {
|
||||
if (!this.collapsible) return "Workspaces";
|
||||
const selectedSummary = this.selected === undefined ? "No workspace selected" : `${this.selected.label}${this.selected.isMain ? " · main" : ""} · ${this.selected.path}`;
|
||||
const selectedTitle = this.selected?.path ?? selectedSummary;
|
||||
return html`<button class="section-toggle" aria-expanded=${String(!this.collapsed)} @click=${() => { this.onToggleCollapsed?.(); }}><span class="section-title"><span class="section-name">${this.collapsed ? "▸" : "▾"} Workspaces</span><small class="section-selected" title=${selectedTitle}>${selectedSummary}</small></span><small class="section-count">${this.workspaces.length}</small></button>`;
|
||||
return html`<button class="section-toggle" aria-expanded=${String(!this.collapsed)} @click=${() => { this.onToggleCollapsed?.(); }}><span class="section-title"><span class="section-name">${this.collapsed ? "▸" : "▾"} Workspaces</span>${this.collapsed ? html`<small class="section-selected" title=${selectedTitle}>${selectedSummary}</small>` : null}</span><small class="section-count">${this.workspaces.length}</small></button>`;
|
||||
}
|
||||
|
||||
private renderActivity(workspace: Workspace): TemplateResult | undefined {
|
||||
|
||||
@@ -27,6 +27,7 @@ export class AppNavigationPanel extends LitElement {
|
||||
@property({ attribute: false }) workspaceLabelItems: (workspace: Workspace) => WorkspaceLabelItem[] = () => [];
|
||||
@property({ attribute: false }) refreshControl: unknown;
|
||||
@property({ type: Boolean, reflect: true }) collapsible = false;
|
||||
@property({ type: Boolean, reflect: true }) compact = false;
|
||||
@property({ type: Boolean }) machinesCollapsed = false;
|
||||
@property({ type: Boolean }) projectsCollapsed = false;
|
||||
@property({ type: Boolean }) workspacesCollapsed = false;
|
||||
@@ -120,20 +121,24 @@ export class AppNavigationPanel extends LitElement {
|
||||
|
||||
static override styles = css`
|
||||
:host { display: flex; flex-direction: column; min-height: 0; overflow: hidden; }
|
||||
:host([collapsible]) { flex: 1 1 auto; }
|
||||
:host([compact]) { flex: 1 1 auto; }
|
||||
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); }
|
||||
:host([collapsible]) header { display: none; }
|
||||
:host([compact]) header { display: none; }
|
||||
.header-actions { display: flex; align-items: center; gap: 8px; }
|
||||
machine-list, 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; }
|
||||
:host([collapsible]) machine-list,
|
||||
:host([collapsible]) project-list,
|
||||
:host([collapsible]) workspace-list,
|
||||
:host([collapsible]) session-list { flex: 1 1 auto; max-height: none; min-height: 0; overflow: hidden; }
|
||||
:host([collapsible]) machine-list[collapsed],
|
||||
:host([collapsible]) project-list[collapsed],
|
||||
:host([collapsible]) workspace-list[collapsed],
|
||||
:host([collapsible]) session-list[collapsed] { flex: 0 0 auto; min-height: auto; overflow: hidden; }
|
||||
machine-list[collapsed],
|
||||
project-list[collapsed],
|
||||
workspace-list[collapsed],
|
||||
session-list[collapsed] { flex: 0 0 auto; min-height: auto; overflow: hidden; }
|
||||
:host([compact]) machine-list,
|
||||
:host([compact]) project-list,
|
||||
:host([compact]) workspace-list,
|
||||
:host([compact]) session-list { flex: 1 1 auto; max-height: none; min-height: 0; overflow: hidden; }
|
||||
:host([compact]) machine-list[collapsed],
|
||||
:host([compact]) project-list[collapsed],
|
||||
:host([compact]) workspace-list[collapsed],
|
||||
:host([compact]) session-list[collapsed] { flex: 0 0 auto; min-height: auto; overflow: hidden; }
|
||||
button { border: 1px solid var(--pi-border); border-radius: 8px; background: var(--pi-surface); color: var(--pi-text); padding: 7px 9px; cursor: pointer; }
|
||||
`;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user