[PM-8602-8603] Sticky search & filters (#9846)
* add "above-scroll-area" to popup page so that content can be excluded from the scroll area * move filters and search above the scrollable area * move bottom border to popup-page component * fix duplicate scrollbar on popup page * update padding to match popup header * move all content of the popup page within the `main` element * update documentation for `above-scroll-area` slot * hide scrollable content when loading
This commit is contained in:
parent
06b370ee75
commit
26a3f6b8ec
|
@ -41,6 +41,9 @@ page looks nice when the extension is popped out.
|
|||
- `footer`
|
||||
- Use the `popup-footer` component.
|
||||
- Not every page will have a footer.
|
||||
- `above-scroll-area`
|
||||
- When the page content overflows, this content will be "stuck" to the top of the page upon
|
||||
scrolling.
|
||||
- default
|
||||
- Whatever content you want in `main`.
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@ import {
|
|||
IconButtonModule,
|
||||
ItemModule,
|
||||
NoItemsModule,
|
||||
SearchModule,
|
||||
} from "@bitwarden/components";
|
||||
|
||||
import { PopupFooterComponent } from "./popup-footer.component";
|
||||
|
@ -103,6 +104,18 @@ class MockPopoutButtonComponent {}
|
|||
})
|
||||
class MockCurrentAccountComponent {}
|
||||
|
||||
@Component({
|
||||
selector: "mock-search",
|
||||
template: `
|
||||
<div class="tw-p-4">
|
||||
<bit-search placeholder="Search"> </bit-search>
|
||||
</div>
|
||||
`,
|
||||
standalone: true,
|
||||
imports: [SearchModule],
|
||||
})
|
||||
class MockSearchComponent {}
|
||||
|
||||
@Component({
|
||||
selector: "mock-vault-page",
|
||||
template: `
|
||||
|
@ -114,6 +127,7 @@ class MockCurrentAccountComponent {}
|
|||
<mock-current-account></mock-current-account>
|
||||
</ng-container>
|
||||
</popup-header>
|
||||
<mock-search slot="above-scroll-area"></mock-search>
|
||||
<vault-placeholder></vault-placeholder>
|
||||
</popup-page>
|
||||
`,
|
||||
|
@ -124,6 +138,7 @@ class MockCurrentAccountComponent {}
|
|||
MockAddButtonComponent,
|
||||
MockPopoutButtonComponent,
|
||||
MockCurrentAccountComponent,
|
||||
MockSearchComponent,
|
||||
VaultComponent,
|
||||
],
|
||||
})
|
||||
|
|
|
@ -1,10 +1,25 @@
|
|||
<ng-content select="[slot=header]"></ng-content>
|
||||
<main class="tw-flex-1 tw-overflow-y-auto tw-h-full 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 }">
|
||||
<ng-content select="[slot=above-scroll-area]"></ng-content>
|
||||
</div>
|
||||
<div
|
||||
class="tw-max-w-screen-sm tw-mx-auto tw-p-3 tw-overflow-y-auto 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"
|
||||
[ngClass]="{ 'tw-invisible': loading }"
|
||||
>
|
||||
<ng-content></ng-content>
|
||||
<!-- 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
|
||||
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"
|
||||
>
|
||||
<ng-content></ng-content>
|
||||
</div>
|
||||
</div>
|
||||
<span
|
||||
class="tw-absolute tw-inset-0 tw-flex tw-items-center tw-justify-center tw-text-main"
|
||||
|
|
|
@ -8,7 +8,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||
templateUrl: "popup-page.component.html",
|
||||
standalone: true,
|
||||
host: {
|
||||
class: "tw-h-full tw-flex tw-flex-col tw-flex-1 tw-overflow-y-auto",
|
||||
class: "tw-h-full tw-flex tw-flex-col tw-flex-1 tw-overflow-y-hidden",
|
||||
},
|
||||
imports: [CommonModule],
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div role="toolbar" [ariaLabel]="'filters' | i18n">
|
||||
<form [formGroup]="filterForm" class="tw-flex tw-flex-wrap tw-gap-2 tw-mb-6 tw-mt-2">
|
||||
<form [formGroup]="filterForm" class="tw-flex tw-flex-wrap tw-gap-2 tw-mt-2">
|
||||
<ng-container *ngIf="organizations$ | async as organizations">
|
||||
<bit-chip-select
|
||||
*ngIf="organizations.length"
|
||||
|
|
|
@ -22,10 +22,13 @@
|
|||
</bit-no-items>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="vaultState !== VaultStateEnum.Empty">
|
||||
<!-- Show search & filters outside of the scroll area of the page -->
|
||||
<div slot="above-scroll-area" class="tw-p-4" *ngIf="vaultState !== VaultStateEnum.Empty">
|
||||
<app-vault-v2-search> </app-vault-v2-search>
|
||||
|
||||
<app-vault-list-filters></app-vault-list-filters>
|
||||
</div>
|
||||
|
||||
<ng-container *ngIf="vaultState !== VaultStateEnum.Empty">
|
||||
<div
|
||||
*ngIf="vaultState === VaultStateEnum.NoResults"
|
||||
class="tw-flex tw-flex-col tw-justify-center tw-h-auto tw-pt-12"
|
||||
|
|
Loading…
Reference in New Issue