mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-11 10:10:25 +01:00
[CL-334] transparent popup-header (#10242)
* add background input to popup header; update styles; update stories
This commit is contained in:
parent
2be34c3b8f
commit
4d3026d2ea
@ -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>
|
||||||
|
@ -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() {
|
||||||
|
@ -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
|
||||||
|
@ -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>
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
@ -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"
|
||||||
>
|
>
|
||||||
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user