mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-14 10:26:19 +01:00
[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`
|
- `footer`
|
||||||
- Use the `popup-footer` component.
|
- Use the `popup-footer` component.
|
||||||
- Not every page will have a footer.
|
- 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
|
- default
|
||||||
- Whatever content you want in `main`.
|
- Whatever content you want in `main`.
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ import {
|
|||||||
IconButtonModule,
|
IconButtonModule,
|
||||||
ItemModule,
|
ItemModule,
|
||||||
NoItemsModule,
|
NoItemsModule,
|
||||||
|
SearchModule,
|
||||||
} from "@bitwarden/components";
|
} from "@bitwarden/components";
|
||||||
|
|
||||||
import { PopupFooterComponent } from "./popup-footer.component";
|
import { PopupFooterComponent } from "./popup-footer.component";
|
||||||
@ -103,6 +104,18 @@ class MockPopoutButtonComponent {}
|
|||||||
})
|
})
|
||||||
class MockCurrentAccountComponent {}
|
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({
|
@Component({
|
||||||
selector: "mock-vault-page",
|
selector: "mock-vault-page",
|
||||||
template: `
|
template: `
|
||||||
@ -114,6 +127,7 @@ class MockCurrentAccountComponent {}
|
|||||||
<mock-current-account></mock-current-account>
|
<mock-current-account></mock-current-account>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</popup-header>
|
</popup-header>
|
||||||
|
<mock-search slot="above-scroll-area"></mock-search>
|
||||||
<vault-placeholder></vault-placeholder>
|
<vault-placeholder></vault-placeholder>
|
||||||
</popup-page>
|
</popup-page>
|
||||||
`,
|
`,
|
||||||
@ -124,6 +138,7 @@ class MockCurrentAccountComponent {}
|
|||||||
MockAddButtonComponent,
|
MockAddButtonComponent,
|
||||||
MockPopoutButtonComponent,
|
MockPopoutButtonComponent,
|
||||||
MockCurrentAccountComponent,
|
MockCurrentAccountComponent,
|
||||||
|
MockSearchComponent,
|
||||||
VaultComponent,
|
VaultComponent,
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
|
@ -1,11 +1,26 @@
|
|||||||
<ng-content select="[slot=header]"></ng-content>
|
<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
|
<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 }"
|
[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
|
||||||
|
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>
|
<ng-content></ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
<span
|
<span
|
||||||
class="tw-absolute tw-inset-0 tw-flex tw-items-center tw-justify-center tw-text-main"
|
class="tw-absolute tw-inset-0 tw-flex tw-items-center tw-justify-center tw-text-main"
|
||||||
[ngClass]="{ 'tw-invisible': !loading }"
|
[ngClass]="{ 'tw-invisible': !loading }"
|
||||||
|
@ -8,7 +8,7 @@ import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.servic
|
|||||||
templateUrl: "popup-page.component.html",
|
templateUrl: "popup-page.component.html",
|
||||||
standalone: true,
|
standalone: true,
|
||||||
host: {
|
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],
|
imports: [CommonModule],
|
||||||
})
|
})
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
<div role="toolbar" [ariaLabel]="'filters' | i18n">
|
<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">
|
<ng-container *ngIf="organizations$ | async as organizations">
|
||||||
<bit-chip-select
|
<bit-chip-select
|
||||||
*ngIf="organizations.length"
|
*ngIf="organizations.length"
|
||||||
|
@ -22,10 +22,13 @@
|
|||||||
</bit-no-items>
|
</bit-no-items>
|
||||||
</div>
|
</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-v2-search> </app-vault-v2-search>
|
||||||
|
|
||||||
<app-vault-list-filters></app-vault-list-filters>
|
<app-vault-list-filters></app-vault-list-filters>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ng-container *ngIf="vaultState !== VaultStateEnum.Empty">
|
||||||
<div
|
<div
|
||||||
*ngIf="vaultState === VaultStateEnum.NoResults"
|
*ngIf="vaultState === VaultStateEnum.NoResults"
|
||||||
class="tw-flex tw-flex-col tw-justify-center tw-h-auto tw-pt-12"
|
class="tw-flex tw-flex-col tw-justify-center tw-h-auto tw-pt-12"
|
||||||
|
Loading…
Reference in New Issue
Block a user