mirror of
https://github.com/bitwarden/browser
synced 2025-12-10 13:23:34 +00:00
[CL-847] Card consolidation (#16952)
* created shared card directive * WIP * use base card in anon layout * use bit-card for pricing card component * add base card to integration cards * add base card to reports cards * add base card to integration card * use card content on report card * use base card directive on base component * update dirt card to use bit-card * run prettier. fix whitespace * add missing imports to report list stories * add base card story and docs
This commit is contained in:
@@ -48,11 +48,11 @@
|
||||
<ng-container *ngTemplateOutlet="defaultContent"></ng-container>
|
||||
</div>
|
||||
} @else {
|
||||
<div
|
||||
class="tw-rounded-2xl tw-mb-6 sm:tw-mb-10 tw-mx-auto tw-w-full sm:tw-bg-background sm:tw-border sm:tw-border-solid sm:tw-border-secondary-300 sm:tw-p-8"
|
||||
<bit-base-card
|
||||
class="!tw-rounded-2xl tw-mb-6 sm:tw-mb-10 tw-mx-auto tw-w-full tw-bg-transparent tw-border-none tw-shadow-none sm:tw-bg-background sm:tw-border sm:tw-border-solid sm:tw-border-secondary-100 sm:tw-shadow sm:tw-p-8"
|
||||
>
|
||||
<ng-container *ngTemplateOutlet="defaultContent"></ng-container>
|
||||
</div>
|
||||
</bit-base-card>
|
||||
}
|
||||
<ng-content select="[slot=secondary]"></ng-content>
|
||||
</div>
|
||||
|
||||
@@ -21,6 +21,7 @@ import { ClientType } from "@bitwarden/common/enums";
|
||||
import { EnvironmentService } from "@bitwarden/common/platform/abstractions/environment.service";
|
||||
import { PlatformUtilsService } from "@bitwarden/common/platform/abstractions/platform-utils.service";
|
||||
|
||||
import { BaseCardComponent } from "../card";
|
||||
import { IconModule } from "../icon";
|
||||
import { SharedModule } from "../shared";
|
||||
import { TypographyModule } from "../typography";
|
||||
@@ -32,7 +33,14 @@ export type AnonLayoutMaxWidth = "md" | "lg" | "xl" | "2xl" | "3xl" | "4xl";
|
||||
@Component({
|
||||
selector: "auth-anon-layout",
|
||||
templateUrl: "./anon-layout.component.html",
|
||||
imports: [IconModule, CommonModule, TypographyModule, SharedModule, RouterModule],
|
||||
imports: [
|
||||
IconModule,
|
||||
CommonModule,
|
||||
TypographyModule,
|
||||
SharedModule,
|
||||
RouterModule,
|
||||
BaseCardComponent,
|
||||
],
|
||||
})
|
||||
export class AnonLayoutComponent implements OnInit, OnChanges {
|
||||
@HostBinding("class")
|
||||
|
||||
14
libs/components/src/card/base-card/base-card.component.ts
Normal file
14
libs/components/src/card/base-card/base-card.component.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
import { BaseCardDirective } from "./base-card.directive";
|
||||
|
||||
/**
|
||||
* The base card component is a container that applies our standard card border and box-shadow.
|
||||
* In most cases using our `<bit-card>` component should suffice.
|
||||
*/
|
||||
@Component({
|
||||
selector: "bit-base-card",
|
||||
template: `<ng-content></ng-content>`,
|
||||
hostDirectives: [BaseCardDirective],
|
||||
})
|
||||
export class BaseCardComponent {}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { Directive } from "@angular/core";
|
||||
|
||||
@Directive({
|
||||
host: {
|
||||
class:
|
||||
"tw-box-border tw-block tw-bg-background tw-text-main tw-border tw-border-solid tw-border-secondary-100 tw-shadow tw-rounded-xl",
|
||||
},
|
||||
})
|
||||
export class BaseCardDirective {}
|
||||
23
libs/components/src/card/base-card/base-card.mdx
Normal file
23
libs/components/src/card/base-card/base-card.mdx
Normal file
@@ -0,0 +1,23 @@
|
||||
import { Meta, Primary, Controls, Canvas, Title, Description } from "@storybook/addon-docs";
|
||||
|
||||
import * as stories from "./base-card.stories";
|
||||
|
||||
<Meta of={stories} />
|
||||
|
||||
```ts
|
||||
import { BaseCardComponent } from "@bitwarden/components";
|
||||
```
|
||||
|
||||
<Title />
|
||||
<Description />
|
||||
|
||||
<Canvas of={stories.Default} />
|
||||
|
||||
## BaseCardDirective
|
||||
|
||||
There is also a `BaseCardDirective` available for use as a hostDirective if need be. But, most
|
||||
likely using `<bit-base-card>` in your template will do.
|
||||
|
||||
```ts
|
||||
import { BaseCardDirective } from "@bitwarden/components";
|
||||
```
|
||||
41
libs/components/src/card/base-card/base-card.stories.ts
Normal file
41
libs/components/src/card/base-card/base-card.stories.ts
Normal file
@@ -0,0 +1,41 @@
|
||||
import { Meta, StoryObj, moduleMetadata } from "@storybook/angular";
|
||||
|
||||
import { AnchorLinkDirective } from "../../link";
|
||||
import { TypographyModule } from "../../typography";
|
||||
|
||||
import { BaseCardComponent } from "./base-card.component";
|
||||
|
||||
export default {
|
||||
title: "Component Library/Cards/BaseCard",
|
||||
component: BaseCardComponent,
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
imports: [AnchorLinkDirective, TypographyModule],
|
||||
}),
|
||||
],
|
||||
parameters: {
|
||||
design: {
|
||||
type: "figma",
|
||||
url: "https://www.figma.com/design/Zt3YSeb6E6lebAffrNLa0h/Tailwind-Component-Library?node-id=16329-28355&t=b5tDKylm5sWm2yKo-4",
|
||||
},
|
||||
},
|
||||
} as Meta;
|
||||
|
||||
type Story = StoryObj<BaseCardComponent>;
|
||||
|
||||
/** Cards are presentational containers. */
|
||||
export const Default: Story = {
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: /*html*/ `
|
||||
<bit-base-card>
|
||||
<p bitTypography="body1" class="!tw-mb-0">
|
||||
The <code><bit-base-card></code> component is a container that applies our standard border and box-shadow. In most cases, <code><bit-card></code> should be used for consistency
|
||||
</p>
|
||||
<p bitTypography="body1" class="!tw-mb-0">
|
||||
<code><bit-base-card></code> is used in the <a bitLink href="/?path=/story/web-reports-card--enabled">ReportCardComponent</a> and <strong>IntegrationsCardComponent</strong> since they have custom padding requirements
|
||||
</p>
|
||||
</bit-base-card>
|
||||
`,
|
||||
}),
|
||||
};
|
||||
2
libs/components/src/card/base-card/index.ts
Normal file
2
libs/components/src/card/base-card/index.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
export * from "./base-card.component";
|
||||
export * from "./base-card.directive";
|
||||
7
libs/components/src/card/card-content.component.ts
Normal file
7
libs/components/src/card/card-content.component.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
import { Component } from "@angular/core";
|
||||
|
||||
@Component({
|
||||
selector: "bit-card-content",
|
||||
template: `<div class="tw-p-4 [@media(min-width:650px)]:tw-p-6"><ng-content></ng-content></div>`,
|
||||
})
|
||||
export class CardContentComponent {}
|
||||
@@ -1,12 +1,14 @@
|
||||
import { ChangeDetectionStrategy, Component } from "@angular/core";
|
||||
|
||||
import { BaseCardDirective } from "./base-card/base-card.directive";
|
||||
|
||||
@Component({
|
||||
selector: "bit-card",
|
||||
template: `<ng-content></ng-content>`,
|
||||
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||
host: {
|
||||
class:
|
||||
"tw-box-border tw-block tw-bg-background tw-text-main tw-border-solid tw-border-b tw-border-0 tw-border-b-secondary-300 [&:not(bit-layout_*)]:tw-rounded-lg [&:not(bit-layout_*)]:tw-border-b-shadow tw-py-4 bit-compact:tw-py-3 tw-px-3 bit-compact:tw-px-2",
|
||||
class: "tw-p-4 [@media(min-width:650px)]:tw-p-6",
|
||||
},
|
||||
hostDirectives: [BaseCardDirective],
|
||||
})
|
||||
export class CardComponent {}
|
||||
|
||||
@@ -11,7 +11,7 @@ import { I18nMockService } from "../utils/i18n-mock.service";
|
||||
import { CardComponent } from "./card.component";
|
||||
|
||||
export default {
|
||||
title: "Component Library/Card",
|
||||
title: "Component Library/Cards/Card",
|
||||
component: CardComponent,
|
||||
decorators: [
|
||||
moduleMetadata({
|
||||
@@ -84,16 +84,3 @@ export const WithinSections: Story = {
|
||||
`,
|
||||
}),
|
||||
};
|
||||
|
||||
export const WithoutBorderRadius: Story = {
|
||||
render: (args) => ({
|
||||
props: args,
|
||||
template: /*html*/ `
|
||||
<bit-layout>
|
||||
<bit-card>
|
||||
<p bitTypography="body1" class="!tw-mb-0">Cards used in <code class="tw-text-danger-700">bit-layout</code> will not have a border radius</p>
|
||||
</bit-card>
|
||||
</bit-layout>
|
||||
`,
|
||||
}),
|
||||
};
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
export * from "./base-card";
|
||||
export * from "./card.component";
|
||||
export * from "./card-content.component";
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<div class="tw-flex-col">
|
||||
<span bitTypography="body2" class="tw-flex tw-text-muted">{{ title }}</span>
|
||||
<div class="tw-flex tw-items-baseline tw-gap-2">
|
||||
<span bitTypography="h1">{{ value }}</span>
|
||||
<span bitTypography="body2">{{ "cardMetrics" | i18n: maxValue }}</span>
|
||||
<bit-card>
|
||||
<div class="tw-flex tw-flex-col tw-gap-1.5">
|
||||
<span bitTypography="body2" class="tw-flex tw-text-muted">{{ title }}</span>
|
||||
<div class="tw-flex tw-items-baseline tw-gap-2">
|
||||
<span bitTypography="h1" class="!tw-mb-0">{{ value }}</span>
|
||||
<span bitTypography="body2">{{ "cardMetrics" | i18n: maxValue }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</bit-card>
|
||||
|
||||
@@ -4,18 +4,14 @@ import { CommonModule } from "@angular/common";
|
||||
import { Component, Input } from "@angular/core";
|
||||
|
||||
import { JslibModule } from "@bitwarden/angular/jslib.module";
|
||||
import { TypographyModule } from "@bitwarden/components";
|
||||
import { TypographyModule, CardComponent as BitCardComponent } from "@bitwarden/components";
|
||||
|
||||
// FIXME(https://bitwarden.atlassian.net/browse/CL-764): Migrate to OnPush
|
||||
// eslint-disable-next-line @angular-eslint/prefer-on-push-component-change-detection
|
||||
@Component({
|
||||
selector: "dirt-card",
|
||||
templateUrl: "./card.component.html",
|
||||
imports: [CommonModule, TypographyModule, JslibModule],
|
||||
host: {
|
||||
class:
|
||||
"tw-box-border tw-bg-background tw-block tw-text-main tw-border-solid tw-border tw-border-secondary-300 tw-border [&:not(bit-layout_*)]:tw-rounded-lg tw-rounded-lg tw-p-6",
|
||||
},
|
||||
imports: [CommonModule, TypographyModule, JslibModule, BitCardComponent],
|
||||
})
|
||||
export class CardComponent {
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
<div
|
||||
class="tw-box-border tw-bg-background tw-text-main tw-border tw-border-secondary-100 tw-rounded-3xl tw-p-8 tw-shadow-sm tw-size-full tw-flex tw-flex-col"
|
||||
>
|
||||
<bit-card class="tw-size-full tw-flex tw-flex-col">
|
||||
<!-- Title Section with Active Badge -->
|
||||
<div class="tw-flex tw-items-center tw-justify-between tw-mb-2">
|
||||
<ng-content select="[slot=title]"></ng-content>
|
||||
@@ -82,4 +80,4 @@
|
||||
}
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</bit-card>
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
BadgeVariant,
|
||||
ButtonModule,
|
||||
ButtonType,
|
||||
CardComponent,
|
||||
IconModule,
|
||||
TypographyModule,
|
||||
} from "@bitwarden/components";
|
||||
@@ -20,7 +21,7 @@ import {
|
||||
@Component({
|
||||
selector: "billing-pricing-card",
|
||||
templateUrl: "./pricing-card.component.html",
|
||||
imports: [BadgeModule, ButtonModule, IconModule, TypographyModule, CurrencyPipe],
|
||||
imports: [BadgeModule, ButtonModule, IconModule, TypographyModule, CurrencyPipe, CardComponent],
|
||||
})
|
||||
export class PricingCardComponent {
|
||||
readonly tagline = input.required<string>();
|
||||
|
||||
Reference in New Issue
Block a user