1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-09-23 03:22:50 +02:00

[CL-334] transparent popup-header (#10242)

* add background input to popup header; update styles; update stories
This commit is contained in:
Will Martin 2024-07-24 17:35:57 -04:00 committed by GitHub
parent 2be34c3b8f
commit 4d3026d2ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 66 additions and 13 deletions

View File

@ -1,5 +1,11 @@
<header <header
class="tw-p-4 tw-border-0 tw-border-solid tw-border-b tw-border-secondary-300 tw-bg-background" class="tw-p-4 tw-transition-colors tw-duration-200 tw-border-0 tw-border-b tw-border-solid"
[ngClass]="{
'tw-bg-background-alt tw-border-transparent':
this.background === 'alt' && !pageContentScrolled(),
'tw-bg-background tw-border-secondary-300':
(this.background === 'alt' && pageContentScrolled()) || this.background === 'default'
}"
> >
<div class="tw-max-w-screen-sm tw-mx-auto tw-flex tw-justify-between tw-w-full"> <div class="tw-max-w-screen-sm tw-mx-auto tw-flex tw-justify-between tw-w-full">
<div class="tw-inline-flex tw-items-center tw-gap-2 tw-h-9"> <div class="tw-inline-flex tw-items-center tw-gap-2 tw-h-9">
@ -11,7 +17,10 @@
[ariaLabel]="'back' | i18n" [ariaLabel]="'back' | i18n"
[bitAction]="backAction" [bitAction]="backAction"
></button> ></button>
<h1 bitTypography="h3" class="!tw-mb-0.5 tw-text-headers">{{ pageTitle }}</h1> <h1 *ngIf="pageTitle" bitTypography="h3" class="!tw-mb-0.5 tw-text-headers">
{{ pageTitle }}
</h1>
<ng-content></ng-content>
</div> </div>
<div class="tw-inline-flex tw-items-center tw-gap-2 tw-h-9"> <div class="tw-inline-flex tw-items-center tw-gap-2 tw-h-9">
<ng-content select="[slot=end]"></ng-content> <ng-content select="[slot=end]"></ng-content>

View File

@ -1,6 +1,6 @@
import { BooleanInput, coerceBooleanProperty } from "@angular/cdk/coercion"; import { BooleanInput, coerceBooleanProperty } from "@angular/cdk/coercion";
import { CommonModule, Location } from "@angular/common"; import { CommonModule, Location } from "@angular/common";
import { Component, Input } from "@angular/core"; import { Component, Input, Signal, inject } from "@angular/core";
import { JslibModule } from "@bitwarden/angular/jslib.module"; import { JslibModule } from "@bitwarden/angular/jslib.module";
import { import {
@ -10,6 +10,8 @@ import {
TypographyModule, TypographyModule,
} from "@bitwarden/components"; } from "@bitwarden/components";
import { PopupPageComponent } from "./popup-page.component";
@Component({ @Component({
selector: "popup-header", selector: "popup-header",
templateUrl: "popup-header.component.html", templateUrl: "popup-header.component.html",
@ -17,6 +19,12 @@ import {
imports: [TypographyModule, CommonModule, IconButtonModule, JslibModule, AsyncActionsModule], imports: [TypographyModule, CommonModule, IconButtonModule, JslibModule, AsyncActionsModule],
}) })
export class PopupHeaderComponent { export class PopupHeaderComponent {
protected pageContentScrolled: Signal<boolean> = inject(PopupPageComponent).isScrolled;
/** Background color */
@Input()
background: "default" | "alt" = "default";
/** Display the back button, which uses Location.back() to go back one page in history */ /** Display the back button, which uses Location.back() to go back one page in history */
@Input() @Input()
get showBackButton() { get showBackButton() {

View File

@ -74,6 +74,9 @@ Basic usage example:
- `showBackButton`: optional, defaults to `false` - `showBackButton`: optional, defaults to `false`
- Toggles the back button to appear. The back button uses `Location.back()` to navigate back one - Toggles the back button to appear. The back button uses `Location.back()` to navigate back one
page in history. page in history.
- `background`: optional
- `"default"` uses a white background
- `"alt"` uses a transparent background
**Slots** **Slots**
@ -92,6 +95,12 @@ Usage example:
</popup-header> </popup-header>
``` ```
### Transparent header
<Canvas>
<Story of={stories.TransparentHeader} />
</Canvas>
Common interactive elements to insert into the `end` slot are: Common interactive elements to insert into the `end` slot are:
- `app-current-account`: shows current account and switcher - `app-current-account`: shows current account and switcher

View File

@ -303,6 +303,7 @@ export default {
MockSettingsPageComponent, MockSettingsPageComponent,
MockVaultPagePoppedComponent, MockVaultPagePoppedComponent,
NoItemsModule, NoItemsModule,
VaultComponent,
], ],
providers: [ providers: [
{ {
@ -311,6 +312,7 @@ export default {
return new I18nMockService({ return new I18nMockService({
back: "Back", back: "Back",
loading: "Loading", loading: "Loading",
search: "Search",
}); });
}, },
}, },
@ -421,3 +423,20 @@ export const Loading: Story = {
`, `,
}), }),
}; };
export const TransparentHeader: Story = {
render: (args) => ({
props: args,
template: /* HTML */ `
<extension-container>
<popup-page>
<popup-header slot="header" background="alt"
><span class="tw-italic tw-text-main">🤠 Custom Content</span></popup-header
>
<vault-placeholder></vault-placeholder>
</popup-page>
</extension-container>
`,
}),
};

View File

@ -1,20 +1,21 @@
<ng-content select="[slot=header]"></ng-content> <ng-content select="[slot=header]"></ng-content>
<main class="tw-flex-1 tw-overflow-hidden tw-flex tw-flex-col tw-relative tw-bg-background-alt"> <main class="tw-flex-1 tw-overflow-hidden tw-flex tw-flex-col tw-relative tw-bg-background-alt">
<div #nonScrollable [ngClass]="{ 'tw-invisible': loading }"> <div
#nonScrollable
class="tw-transition-colors tw-duration-200 tw-border-0 tw-border-b tw-border-solid"
[ngClass]="{
'tw-invisible': loading || nonScrollable.childElementCount === 0,
'tw-border-secondary-300': scrolled(),
'tw-border-transparent': !scrolled()
}"
>
<ng-content select="[slot=above-scroll-area]"></ng-content> <ng-content select="[slot=above-scroll-area]"></ng-content>
</div> </div>
<div <div
class="tw-max-w-screen-sm tw-mx-auto tw-overflow-y-auto tw-flex tw-flex-col tw-w-full tw-h-full" class="tw-max-w-screen-sm tw-mx-auto tw-overflow-y-auto tw-flex tw-flex-col tw-w-full tw-h-full"
(scroll)="handleScroll($event)"
[ngClass]="{ 'tw-invisible': loading }" [ngClass]="{ 'tw-invisible': loading }"
> >
<!-- Only shown when the `slot=above-scroll-area` is populated -->
<!-- The first div will "stick" and show a bottom border when content is scrolled -->
<!-- The second div is displayed on top of the first to hide it until the content is scrolled -->
<ng-container *ngIf="nonScrollable.children.length">
<div class="tw-sticky tw-min-h-[1px] tw-bg-secondary-300 tw-top-0"></div>
<div class="tw-relative tw-z-10 tw-min-h-[2px] tw-bg-background-alt -tw-mt-[2px]"></div>
</ng-container>
<div <div
class="tw-max-w-screen-sm tw-mx-auto tw-p-3 tw-flex-1 tw-flex tw-flex-col tw-h-full tw-w-full" class="tw-max-w-screen-sm tw-mx-auto tw-p-3 tw-flex-1 tw-flex tw-flex-col tw-h-full tw-w-full"
> >

View File

@ -1,5 +1,5 @@
import { CommonModule } from "@angular/common"; import { CommonModule } from "@angular/common";
import { Component, Input, inject } from "@angular/core"; import { Component, Input, inject, signal } from "@angular/core";
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service"; import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
@ -17,6 +17,13 @@ export class PopupPageComponent {
@Input() loading = false; @Input() loading = false;
protected scrolled = signal(false);
isScrolled = this.scrolled.asReadonly();
/** Accessible loading label for the spinner. Defaults to "loading" */ /** Accessible loading label for the spinner. Defaults to "loading" */
@Input() loadingText?: string = this.i18nService.t("loading"); @Input() loadingText?: string = this.i18nService.t("loading");
handleScroll(event: Event) {
this.scrolled.set((event.currentTarget as HTMLElement).scrollTop !== 0);
}
} }