mirror of
https://github.com/bitwarden/browser
synced 2025-01-23 01:33:02 +01:00
[CL-107] add bit-layout component (#6016)
* add bit-layout component * update bit-layout semantics * use bit-layout in sm-layout * remove redundant sm-layout story * move nav el inside of navigation component * Apply suggestions from code review Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * remove reference to layout_frontend in bit-layout * update stories * Update libs/components/src/layout/layout.stories.ts Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com> * run prettier --------- Co-authored-by: Oscar Hinton <Hinton@users.noreply.github.com>
This commit is contained in:
parent
839d7b7bb8
commit
35cc0da3cc
@ -1,10 +1,4 @@
|
|||||||
<div class="tw-flex tw-w-full">
|
<bit-layout>
|
||||||
<nav
|
<router-outlet slot="sidebar" name="sidebar"></router-outlet>
|
||||||
class="tw-fixed tw-max-h-screen tw-min-h-screen tw-w-60 tw-overflow-auto tw-bg-background-alt3"
|
<router-outlet></router-outlet>
|
||||||
>
|
</bit-layout>
|
||||||
<router-outlet name="sidebar"></router-outlet>
|
|
||||||
</nav>
|
|
||||||
<main class="tw-ml-60 tw-min-h-screen tw-min-w-0 tw-flex-1 tw-p-6">
|
|
||||||
<router-outlet></router-outlet>
|
|
||||||
</main>
|
|
||||||
</div>
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { NgModule } from "@angular/core";
|
import { NgModule } from "@angular/core";
|
||||||
|
|
||||||
import { NavigationModule } from "@bitwarden/components";
|
import { LayoutComponent as BitLayoutComponent, NavigationModule } from "@bitwarden/components";
|
||||||
import { SharedModule } from "@bitwarden/web-vault/app/shared/shared.module";
|
import { SharedModule } from "@bitwarden/web-vault/app/shared/shared.module";
|
||||||
|
|
||||||
import { LayoutComponent } from "./layout.component";
|
import { LayoutComponent } from "./layout.component";
|
||||||
@ -8,7 +8,7 @@ import { NavigationComponent } from "./navigation.component";
|
|||||||
import { OrgSwitcherComponent } from "./org-switcher.component";
|
import { OrgSwitcherComponent } from "./org-switcher.component";
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [SharedModule, NavigationModule],
|
imports: [SharedModule, NavigationModule, BitLayoutComponent],
|
||||||
declarations: [LayoutComponent, NavigationComponent, OrgSwitcherComponent],
|
declarations: [LayoutComponent, NavigationComponent, OrgSwitcherComponent],
|
||||||
})
|
})
|
||||||
export class LayoutModule {}
|
export class LayoutModule {}
|
||||||
|
@ -1,81 +0,0 @@
|
|||||||
import { Component, importProvidersFrom } from "@angular/core";
|
|
||||||
import { RouterModule } from "@angular/router";
|
|
||||||
import { Meta, Story, applicationConfig, moduleMetadata } from "@storybook/angular";
|
|
||||||
import { BehaviorSubject } from "rxjs";
|
|
||||||
|
|
||||||
import { OrganizationService } from "@bitwarden/common/admin-console/abstractions/organization/organization.service.abstraction";
|
|
||||||
import { Organization } from "@bitwarden/common/admin-console/models/domain/organization";
|
|
||||||
import { IconModule } from "@bitwarden/components";
|
|
||||||
import { PreloadedEnglishI18nModule } from "@bitwarden/web-vault/app/core/tests";
|
|
||||||
|
|
||||||
import { LayoutComponent } from "./layout.component";
|
|
||||||
import { LayoutModule } from "./layout.module";
|
|
||||||
import { NavigationComponent } from "./navigation.component";
|
|
||||||
|
|
||||||
class MockOrganizationService implements Partial<OrganizationService> {
|
|
||||||
private static _orgs = new BehaviorSubject<Organization[]>([]);
|
|
||||||
organizations$ = MockOrganizationService._orgs; // eslint-disable-line rxjs/no-exposed-subjects
|
|
||||||
}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "story-content",
|
|
||||||
template: ` <p class="tw-text-main">Content</p> `,
|
|
||||||
})
|
|
||||||
class StoryContentComponent {}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
title: "Web/Layout",
|
|
||||||
component: LayoutComponent,
|
|
||||||
decorators: [
|
|
||||||
moduleMetadata({
|
|
||||||
imports: [RouterModule, LayoutModule, IconModule],
|
|
||||||
declarations: [StoryContentComponent],
|
|
||||||
providers: [{ provide: OrganizationService, useClass: MockOrganizationService }],
|
|
||||||
}),
|
|
||||||
applicationConfig({
|
|
||||||
providers: [
|
|
||||||
importProvidersFrom(
|
|
||||||
RouterModule.forRoot(
|
|
||||||
[
|
|
||||||
{
|
|
||||||
path: "",
|
|
||||||
component: LayoutComponent,
|
|
||||||
children: [
|
|
||||||
{
|
|
||||||
path: "",
|
|
||||||
redirectTo: "secrets",
|
|
||||||
pathMatch: "full",
|
|
||||||
},
|
|
||||||
{
|
|
||||||
path: "secrets",
|
|
||||||
component: StoryContentComponent,
|
|
||||||
data: {
|
|
||||||
title: "secrets",
|
|
||||||
searchTitle: "searchSecrets",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
outlet: "sidebar",
|
|
||||||
path: "",
|
|
||||||
component: NavigationComponent,
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
{ useHash: true }
|
|
||||||
)
|
|
||||||
),
|
|
||||||
importProvidersFrom(PreloadedEnglishI18nModule),
|
|
||||||
],
|
|
||||||
}),
|
|
||||||
],
|
|
||||||
} as Meta;
|
|
||||||
|
|
||||||
const Template: Story = (args) => ({
|
|
||||||
props: args,
|
|
||||||
template: `
|
|
||||||
<router-outlet></router-outlet>
|
|
||||||
`,
|
|
||||||
});
|
|
||||||
|
|
||||||
export const Default = Template.bind({});
|
|
@ -1,22 +1,24 @@
|
|||||||
<a routerLink="." class="tw-m-5 tw-mt-7 tw-block">
|
<nav>
|
||||||
<bit-icon [icon]="logo"></bit-icon>
|
<a routerLink="." class="tw-m-5 tw-mt-7 tw-block">
|
||||||
</a>
|
<bit-icon [icon]="logo"></bit-icon>
|
||||||
|
</a>
|
||||||
|
|
||||||
<org-switcher [filter]="orgFilter" [hideNewButton]="true"></org-switcher>
|
<org-switcher [filter]="orgFilter" [hideNewButton]="true"></org-switcher>
|
||||||
<bit-nav-item icon="bwi-collection" [text]="'projects' | i18n" route="projects"></bit-nav-item>
|
<bit-nav-item icon="bwi-collection" [text]="'projects' | i18n" route="projects"></bit-nav-item>
|
||||||
<bit-nav-item icon="bwi-key" [text]="'secrets' | i18n" route="secrets"></bit-nav-item>
|
<bit-nav-item icon="bwi-key" [text]="'secrets' | i18n" route="secrets"></bit-nav-item>
|
||||||
<bit-nav-item
|
<bit-nav-item
|
||||||
icon="bwi-wrench"
|
icon="bwi-wrench"
|
||||||
[text]="'serviceAccounts' | i18n"
|
[text]="'serviceAccounts' | i18n"
|
||||||
route="service-accounts"
|
route="service-accounts"
|
||||||
></bit-nav-item>
|
></bit-nav-item>
|
||||||
<bit-nav-item
|
<bit-nav-item
|
||||||
icon="bwi-trash"
|
icon="bwi-trash"
|
||||||
[text]="'trash' | i18n"
|
[text]="'trash' | i18n"
|
||||||
route="trash"
|
route="trash"
|
||||||
*ngIf="isAdmin$ | async"
|
*ngIf="isAdmin$ | async"
|
||||||
></bit-nav-item>
|
></bit-nav-item>
|
||||||
<bit-nav-group icon="bwi-cog" [text]="'settings' | i18n" *ngIf="isAdmin$ | async">
|
<bit-nav-group icon="bwi-cog" [text]="'settings' | i18n" *ngIf="isAdmin$ | async">
|
||||||
<bit-nav-item [text]="'importData' | i18n" route="settings/import"></bit-nav-item>
|
<bit-nav-item [text]="'importData' | i18n" route="settings/import"></bit-nav-item>
|
||||||
<bit-nav-item [text]="'exportData' | i18n" route="settings/export"></bit-nav-item>
|
<bit-nav-item [text]="'exportData' | i18n" route="settings/export"></bit-nav-item>
|
||||||
</bit-nav-group>
|
</bit-nav-group>
|
||||||
|
</nav>
|
||||||
|
@ -13,6 +13,7 @@ export * from "./form-field";
|
|||||||
export * from "./icon-button";
|
export * from "./icon-button";
|
||||||
export * from "./icon";
|
export * from "./icon";
|
||||||
export * from "./input";
|
export * from "./input";
|
||||||
|
export * from "./layout";
|
||||||
export * from "./link";
|
export * from "./link";
|
||||||
export * from "./menu";
|
export * from "./menu";
|
||||||
export * from "./multi-select";
|
export * from "./multi-select";
|
||||||
|
1
libs/components/src/layout/index.ts
Normal file
1
libs/components/src/layout/index.ts
Normal file
@ -0,0 +1 @@
|
|||||||
|
export * from "./layout.component";
|
10
libs/components/src/layout/layout.component.html
Normal file
10
libs/components/src/layout/layout.component.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<div class="tw-flex tw-w-full">
|
||||||
|
<aside
|
||||||
|
class="tw-fixed tw-inset-y-0 tw-left-0 tw-h-screen tw-w-60 tw-overflow-auto tw-bg-background-alt3"
|
||||||
|
>
|
||||||
|
<ng-content select="[slot=sidebar]"></ng-content>
|
||||||
|
</aside>
|
||||||
|
<main class="tw-ml-60 tw-min-h-screen tw-min-w-0 tw-flex-1 tw-bg-background tw-p-6">
|
||||||
|
<ng-content></ng-content>
|
||||||
|
</main>
|
||||||
|
</div>
|
9
libs/components/src/layout/layout.component.ts
Normal file
9
libs/components/src/layout/layout.component.ts
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
import { Component } from "@angular/core";
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: "bit-layout",
|
||||||
|
templateUrl: "layout.component.html",
|
||||||
|
standalone: true,
|
||||||
|
imports: [],
|
||||||
|
})
|
||||||
|
export class LayoutComponent {}
|
64
libs/components/src/layout/layout.stories.ts
Normal file
64
libs/components/src/layout/layout.stories.ts
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
import { RouterTestingModule } from "@angular/router/testing";
|
||||||
|
import { Meta, StoryObj, componentWrapperDecorator, moduleMetadata } from "@storybook/angular";
|
||||||
|
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
|
||||||
|
import { CalloutModule } from "../callout";
|
||||||
|
import { NavigationModule } from "../navigation";
|
||||||
|
import { I18nMockService } from "../utils/i18n-mock.service";
|
||||||
|
|
||||||
|
import { LayoutComponent } from "./layout.component";
|
||||||
|
|
||||||
|
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>`
|
||||||
|
),
|
||||||
|
moduleMetadata({
|
||||||
|
imports: [NavigationModule, RouterTestingModule, CalloutModule],
|
||||||
|
providers: [
|
||||||
|
{
|
||||||
|
provide: I18nService,
|
||||||
|
useFactory: () => {
|
||||||
|
return new I18nMockService({});
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
} as Meta;
|
||||||
|
|
||||||
|
type Story = StoryObj<LayoutComponent>;
|
||||||
|
|
||||||
|
export const Empty: Story = {
|
||||||
|
render: (args) => ({
|
||||||
|
props: args,
|
||||||
|
template: /* HTML */ `<bit-layout></bit-layout>`,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
export const WithContent: Story = {
|
||||||
|
render: (args) => ({
|
||||||
|
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>
|
||||||
|
</nav>
|
||||||
|
<bit-callout title="Foobar"> Hello world! </bit-callout>
|
||||||
|
</bit-layout>
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user