diff --git a/apps/web/src/app/modules/shared.module.ts b/apps/web/src/app/modules/shared.module.ts index 1bfbe632918..90d4faa922a 100644 --- a/apps/web/src/app/modules/shared.module.ts +++ b/apps/web/src/app/modules/shared.module.ts @@ -64,6 +64,7 @@ import { FormFieldModule, SubmitButtonModule, MenuModule, + TabsModule, } from "@bitwarden/components"; import { PasswordStrengthComponent } from "../components/password-strength.component"; @@ -138,6 +139,7 @@ registerLocaleData(localeZhTw, "zh-TW"); MenuModule, FormFieldModule, SubmitButtonModule, + TabsModule, ], exports: [ CommonModule, @@ -157,6 +159,7 @@ registerLocaleData(localeZhTw, "zh-TW"); FormFieldModule, PasswordStrengthComponent, SubmitButtonModule, + TabsModule, ], providers: [DatePipe], bootstrap: [], diff --git a/libs/components/src/index.ts b/libs/components/src/index.ts index cb45e12228e..f7c8962b638 100644 --- a/libs/components/src/index.ts +++ b/libs/components/src/index.ts @@ -6,3 +6,4 @@ export * from "./form-field"; export * from "./menu"; export * from "./utils/i18n-mock.service"; export * from "./submit-button"; +export * from "./tabs"; diff --git a/libs/components/src/tabs/index.ts b/libs/components/src/tabs/index.ts new file mode 100644 index 00000000000..9b45ff1d43b --- /dev/null +++ b/libs/components/src/tabs/index.ts @@ -0,0 +1,3 @@ +export * from "./tabs.module"; +export * from "./tab-group.component"; +export * from "./tab-item.component"; diff --git a/libs/components/src/tabs/tab-group.component.html b/libs/components/src/tabs/tab-group.component.html new file mode 100644 index 00000000000..aa29a2f58af --- /dev/null +++ b/libs/components/src/tabs/tab-group.component.html @@ -0,0 +1,6 @@ +
+ +
diff --git a/libs/components/src/tabs/tab-group.component.ts b/libs/components/src/tabs/tab-group.component.ts new file mode 100644 index 00000000000..856ab1f1e22 --- /dev/null +++ b/libs/components/src/tabs/tab-group.component.ts @@ -0,0 +1,7 @@ +import { Component } from "@angular/core"; + +@Component({ + selector: "bit-tab-group", + templateUrl: "./tab-group.component.html", +}) +export class TabGroupComponent {} diff --git a/libs/components/src/tabs/tab-item.component.html b/libs/components/src/tabs/tab-item.component.html new file mode 100644 index 00000000000..951cfb3be18 --- /dev/null +++ b/libs/components/src/tabs/tab-item.component.html @@ -0,0 +1,26 @@ + + + + + + + + + diff --git a/libs/components/src/tabs/tab-item.component.ts b/libs/components/src/tabs/tab-item.component.ts new file mode 100644 index 00000000000..749775e91bf --- /dev/null +++ b/libs/components/src/tabs/tab-item.component.ts @@ -0,0 +1,59 @@ +import { Component, Input } from "@angular/core"; + +@Component({ + selector: "bit-tab-item", + templateUrl: "./tab-item.component.html", +}) +export class TabItemComponent { + @Input() route: string; // ['/route'] + @Input() disabled = false; + + get baseClassList(): string[] { + return [ + "tw-block", + "tw-relative", + "tw-py-2", + "tw-px-4", + "tw-leading-5", + "tw-text-left", + "tw-font-semibold", + "tw-bg-transparent", + "tw-transition", + "tw-rounded-t", + "tw-border-0", + "tw-border-t-4", + "tw-border-t-transparent", + "tw-border-b", + "tw-border-b-secondary-300", + "tw-border-solid", + "tw-cursor-pointer", + "tw-box-border", + "tw-text-main", + "hover:tw-underline", + "hover:tw-text-main", + "focus:tw-z-10", + "focus:tw-outline-none", + "focus:tw-ring-2", + "focus:tw-ring-primary-700", + "disabled:tw-bg-secondary-100", + "disabled:tw-text-muted", + "disabled:tw-no-underline", + "disabled:tw-cursor-not-allowed", + ]; + } + + get activeClassList(): string { + return [ + "tw-border-x", + "tw-border-x-secondary-300", + "tw-border-t-primary-500", + "tw-border-b-transparent", + "tw-bg-background", + "tw-text-primary-500", + "hover:tw-border-t-primary-700", + "hover:!tw-text-primary-700", + "focus:tw-border-t-primary-700", + "focus:tw-text-primary-700", + ].join(" "); + } +} diff --git a/libs/components/src/tabs/tabs.module.ts b/libs/components/src/tabs/tabs.module.ts new file mode 100644 index 00000000000..016bde504a5 --- /dev/null +++ b/libs/components/src/tabs/tabs.module.ts @@ -0,0 +1,13 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { RouterModule } from "@angular/router"; + +import { TabGroupComponent } from "./tab-group.component"; +import { TabItemComponent } from "./tab-item.component"; + +@NgModule({ + imports: [CommonModule, RouterModule], + exports: [TabGroupComponent, TabItemComponent], + declarations: [TabGroupComponent, TabItemComponent], +}) +export class TabsModule {} diff --git a/libs/components/src/tabs/tabs.stories.ts b/libs/components/src/tabs/tabs.stories.ts new file mode 100644 index 00000000000..15ee57fa7d5 --- /dev/null +++ b/libs/components/src/tabs/tabs.stories.ts @@ -0,0 +1,84 @@ +import { CommonModule } from "@angular/common"; +import { Component } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { Meta, moduleMetadata, Story } from "@storybook/angular"; + +import { TabGroupComponent } from "./tab-group.component"; +import { TabItemComponent } from "./tab-item.component"; + +@Component({ + selector: "bit-tab-active-dummy", + template: "Router - Active selected", +}) +class ActiveDummyComponent {} + +@Component({ + selector: "bit-tab-item-2-dummy", + template: "Router - Item 2 selected", +}) +class ItemTwoDummyComponent {} + +@Component({ + selector: "bit-tab-item-3-dummy", + template: "Router - Item 3 selected", +}) +class ItemThreeDummyComponent {} + +@Component({ + selector: "bit-tab-disabled-dummy", + template: "Router - Disabled selected", +}) +class DisabledDummyComponent {} + +export default { + title: "Component Library/Tabs", + component: TabGroupComponent, + decorators: [ + moduleMetadata({ + declarations: [ + TabGroupComponent, + TabItemComponent, + ActiveDummyComponent, + ItemTwoDummyComponent, + ItemThreeDummyComponent, + DisabledDummyComponent, + ], + imports: [ + CommonModule, + RouterModule.forRoot( + [ + { path: "", redirectTo: "active", pathMatch: "full" }, + { path: "active", component: ActiveDummyComponent }, + { path: "item-2", component: ItemTwoDummyComponent }, + { path: "item-3", component: ItemThreeDummyComponent }, + { path: "disabled", component: DisabledDummyComponent }, + ], + { useHash: true } + ), + ], + }), + ], + parameters: { + design: { + type: "figma", + url: "https://www.figma.com/file/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=1881%3A17922", + }, + }, +} as Meta; + +const TabGroupTemplate: Story = (args: TabGroupComponent) => ({ + props: args, + template: ` + + Active + Item 2 + Item 3 + Disabled + +
+ +
+ `, +}); + +export const TabGroup = TabGroupTemplate.bind({}); diff --git a/libs/components/tailwind.config.base.js b/libs/components/tailwind.config.base.js index fd0caec7490..31ff19cb501 100644 --- a/libs/components/tailwind.config.base.js +++ b/libs/components/tailwind.config.base.js @@ -60,6 +60,8 @@ module.exports = { info: "var(--color-info-500)", primary: { 300: "var(--color-primary-300)", + 500: "var(--color-primary-500)", + 700: "var(--color-primary-700)", }, }, ringOffsetColor: ({ theme }) => ({