mirror of
https://github.com/bitwarden/browser
synced 2025-12-16 08:13:42 +00:00
[CL-118][CL-164][PM-8019] collapsible side navigation (#6383)
This commit is contained in:
@@ -13,24 +13,28 @@
|
||||
>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="tw-flex tw-w-full">
|
||||
<aside
|
||||
[ngStyle]="
|
||||
variant === 'secondary' && {
|
||||
'--color-text-alt2': 'var(--color-text-main)',
|
||||
'--color-background-alt3': 'var(--color-secondary-100)',
|
||||
'--color-background-alt4': 'var(--color-secondary-300)'
|
||||
}
|
||||
"
|
||||
class="tw-sticky tw-inset-y-0 tw-h-screen tw-w-60 tw-overflow-auto tw-bg-background-alt3"
|
||||
>
|
||||
<ng-content select="[slot=sidebar]"></ng-content>
|
||||
</aside>
|
||||
<div class="tw-group tw-flex tw-w-full">
|
||||
<ng-content select="bit-side-nav, [slot=side-nav]"></ng-content>
|
||||
<main
|
||||
[id]="mainContentId"
|
||||
tabindex="-1"
|
||||
class="tw-overflow-auto tw-min-w-0 tw-flex-1 tw-bg-background tw-p-6"
|
||||
class="tw-overflow-auto tw-min-w-0 tw-flex-1 tw-bg-background tw-p-6 md:tw-ml-0 tw-ml-16"
|
||||
>
|
||||
<ng-content></ng-content>
|
||||
|
||||
<!-- overlay backdrop for side-nav -->
|
||||
<div
|
||||
*ngIf="{
|
||||
open: sideNavService.open$ | async
|
||||
} as data"
|
||||
class="tw-pointer-events-none tw-fixed tw-inset-0 tw-z-10 tw-bg-black tw-bg-opacity-0 motion-safe:tw-transition-colors md:tw-hidden"
|
||||
[ngClass]="[data.open ? 'tw-bg-opacity-30 md:tw-bg-opacity-0' : 'tw-bg-opacity-0']"
|
||||
>
|
||||
<div
|
||||
*ngIf="data.open"
|
||||
(click)="sideNavService.toggle()"
|
||||
class="tw-pointer-events-auto tw-h-full tw-w-full"
|
||||
></div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
import { Component, Input } from "@angular/core";
|
||||
import { CommonModule } from "@angular/common";
|
||||
import { Component } from "@angular/core";
|
||||
import { RouterModule } from "@angular/router";
|
||||
|
||||
import { LinkModule } from "../link";
|
||||
import { SideNavService } from "../navigation/side-nav.service";
|
||||
import { SharedModule } from "../shared";
|
||||
|
||||
export type LayoutVariant = "primary" | "secondary";
|
||||
|
||||
@Component({
|
||||
selector: "bit-layout",
|
||||
templateUrl: "layout.component.html",
|
||||
standalone: true,
|
||||
imports: [SharedModule, LinkModule, RouterModule],
|
||||
imports: [CommonModule, SharedModule, LinkModule, RouterModule],
|
||||
})
|
||||
export class LayoutComponent {
|
||||
protected mainContentId = "main-content";
|
||||
|
||||
@Input() variant: LayoutVariant = "primary";
|
||||
constructor(protected sideNavService: SideNavService) {}
|
||||
|
||||
focusMainContent() {
|
||||
document.getElementById(this.mainContentId)?.focus();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { RouterTestingModule } from "@angular/router/testing";
|
||||
import { Meta, StoryObj, componentWrapperDecorator, moduleMetadata } from "@storybook/angular";
|
||||
import { Meta, StoryObj, moduleMetadata } from "@storybook/angular";
|
||||
import { userEvent } from "@storybook/testing-library";
|
||||
|
||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||
@@ -7,6 +7,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
||||
import { CalloutModule } from "../callout";
|
||||
import { NavigationModule } from "../navigation";
|
||||
import { I18nMockService } from "../utils/i18n-mock.service";
|
||||
import { positionFixedWrapperDecorator } from "../utils/position-fixed-wrapper-decorator";
|
||||
|
||||
import { LayoutComponent } from "./layout.component";
|
||||
|
||||
@@ -14,16 +15,7 @@ export default {
|
||||
title: "Component Library/Layout",
|
||||
component: LayoutComponent,
|
||||
decorators: [
|
||||
componentWrapperDecorator(
|
||||
/**
|
||||
* Applying a CSS transform makes a `position: fixed` element act like it is `position: relative`
|
||||
* https://github.com/storybookjs/storybook/issues/8011#issue-490251969
|
||||
*/
|
||||
(story) =>
|
||||
/* HTML */ `<div class="tw-scale-100 tw-border-2 tw-border-solid tw-border-[red]">
|
||||
${story}
|
||||
</div>`,
|
||||
),
|
||||
positionFixedWrapperDecorator(),
|
||||
moduleMetadata({
|
||||
imports: [NavigationModule, RouterTestingModule, CalloutModule],
|
||||
providers: [
|
||||
@@ -31,6 +23,7 @@ export default {
|
||||
provide: I18nService,
|
||||
useFactory: () => {
|
||||
return new I18nMockService({
|
||||
toggleSideNavigation: "Toggle side navigation",
|
||||
skipToContent: "Skip to content",
|
||||
submenu: "submenu",
|
||||
toggleCollapse: "toggle collapse",
|
||||
@@ -40,6 +33,9 @@ export default {
|
||||
],
|
||||
}),
|
||||
],
|
||||
parameters: {
|
||||
chromatic: { viewports: [640, 1280] },
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
type Story = StoryObj<LayoutComponent>;
|
||||
@@ -47,7 +43,9 @@ type Story = StoryObj<LayoutComponent>;
|
||||
export const Empty: Story = {
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: /* HTML */ `<bit-layout></bit-layout>`,
|
||||
template: /* HTML */ `<bit-layout>
|
||||
<bit-side-nav></bit-side-nav>
|
||||
</bit-layout>`,
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -56,13 +54,9 @@ export const WithContent: Story = {
|
||||
props: args,
|
||||
template: /* HTML */ `
|
||||
<bit-layout>
|
||||
<nav slot="sidebar">
|
||||
<bit-nav-item text="Item A" icon="bwi-collection"></bit-nav-item>
|
||||
<bit-nav-item text="Item B" icon="bwi-collection"></bit-nav-item>
|
||||
<bit-nav-divider></bit-nav-divider>
|
||||
<bit-nav-item text="Item C" icon="bwi-collection"></bit-nav-item>
|
||||
<bit-nav-item text="Item D" icon="bwi-collection"></bit-nav-item>
|
||||
<bit-nav-group text="Tree example" icon="bwi-collection" [open]="true">
|
||||
<bit-side-nav>
|
||||
<bit-nav-item text="Item A" route="#" icon="bwi-lock"></bit-nav-item>
|
||||
<bit-nav-group text="Tree A" icon="bwi-family" [open]="true">
|
||||
<bit-nav-group
|
||||
text="Level 1 - with children (empty)"
|
||||
route="#"
|
||||
@@ -129,7 +123,141 @@ export const WithContent: Story = {
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
</bit-nav-group>
|
||||
</nav>
|
||||
<bit-nav-group text="Tree B" icon="bwi-collection" [open]="true">
|
||||
<bit-nav-group
|
||||
text="Level 1 - with children (empty)"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
></bit-nav-group>
|
||||
<bit-nav-item
|
||||
text="Level 1 - no children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
<bit-nav-group
|
||||
text="Level 1 - with children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
[open]="true"
|
||||
>
|
||||
<bit-nav-group
|
||||
text="Level 2 - with children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
[open]="true"
|
||||
>
|
||||
<bit-nav-item
|
||||
text="Level 3 - no children, no icon"
|
||||
route="#"
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
<bit-nav-group
|
||||
text="Level 3 - with children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
[open]="true"
|
||||
>
|
||||
<bit-nav-item
|
||||
text="Level 4 - no children, no icon"
|
||||
route="#"
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
</bit-nav-group>
|
||||
</bit-nav-group>
|
||||
<bit-nav-group
|
||||
text="Level 2 - with children (empty)"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
[open]="true"
|
||||
></bit-nav-group>
|
||||
<bit-nav-item
|
||||
text="Level 2 - no children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
</bit-nav-group>
|
||||
<bit-nav-item
|
||||
text="Level 1 - no children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
</bit-nav-group>
|
||||
<bit-nav-group text="Tree C" icon="bwi-key" [open]="true">
|
||||
<bit-nav-group
|
||||
text="Level 1 - with children (empty)"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
></bit-nav-group>
|
||||
<bit-nav-item
|
||||
text="Level 1 - no children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
<bit-nav-group
|
||||
text="Level 1 - with children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
[open]="true"
|
||||
>
|
||||
<bit-nav-group
|
||||
text="Level 2 - with children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
[open]="true"
|
||||
>
|
||||
<bit-nav-item
|
||||
text="Level 3 - no children, no icon"
|
||||
route="#"
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
<bit-nav-group
|
||||
text="Level 3 - with children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
[open]="true"
|
||||
>
|
||||
<bit-nav-item
|
||||
text="Level 4 - no children, no icon"
|
||||
route="#"
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
</bit-nav-group>
|
||||
</bit-nav-group>
|
||||
<bit-nav-group
|
||||
text="Level 2 - with children (empty)"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
[open]="true"
|
||||
></bit-nav-group>
|
||||
<bit-nav-item
|
||||
text="Level 2 - no children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
</bit-nav-group>
|
||||
<bit-nav-item
|
||||
text="Level 1 - no children"
|
||||
route="#"
|
||||
icon="bwi-collection"
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
</bit-nav-group>
|
||||
</bit-side-nav>
|
||||
<bit-callout title="Foobar"> Hello world! </bit-callout>
|
||||
</bit-layout>
|
||||
`,
|
||||
@@ -147,8 +275,8 @@ export const Secondary: Story = {
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: /* HTML */ `
|
||||
<bit-layout variant="secondary">
|
||||
<nav slot="sidebar">
|
||||
<bit-layout>
|
||||
<bit-side-nav variant="secondary">
|
||||
<bit-nav-item text="Item A" icon="bwi-collection"></bit-nav-item>
|
||||
<bit-nav-item text="Item B" icon="bwi-collection"></bit-nav-item>
|
||||
<bit-nav-divider></bit-nav-divider>
|
||||
@@ -221,7 +349,7 @@ export const Secondary: Story = {
|
||||
variant="tree"
|
||||
></bit-nav-item>
|
||||
</bit-nav-group>
|
||||
</nav>
|
||||
</bit-side-nav>
|
||||
<bit-callout title="Foobar"> Hello world! </bit-callout>
|
||||
</bit-layout>
|
||||
`,
|
||||
|
||||
Reference in New Issue
Block a user