mirror of
https://github.com/bitwarden/browser.git
synced 2024-11-11 10:10:25 +01:00
[PM-8380] Browser Refresh - Virtual scrolling (#10646)
* [PM-8380] Add option to disable content padding for popup page * [PM-8380] Add cdkVirtualScroll to vault list items and fixed item heights * [PM-8380] Move item height constants to item component
This commit is contained in:
parent
7da1082849
commit
ade01c9d07
@ -17,7 +17,8 @@
|
|||||||
[ngClass]="{ 'tw-invisible': loading }"
|
[ngClass]="{ 'tw-invisible': loading }"
|
||||||
>
|
>
|
||||||
<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-flex-1 tw-flex tw-flex-col tw-h-full tw-w-full"
|
||||||
|
[ngClass]="{ 'tw-p-3': !disablePadding }"
|
||||||
>
|
>
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { Component, Input, inject, signal } from "@angular/core";
|
import { booleanAttribute, Component, inject, Input, 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,9 @@ export class PopupPageComponent {
|
|||||||
|
|
||||||
@Input() loading = false;
|
@Input() loading = false;
|
||||||
|
|
||||||
|
@Input({ transform: booleanAttribute })
|
||||||
|
disablePadding = false;
|
||||||
|
|
||||||
protected scrolled = signal(false);
|
protected scrolled = signal(false);
|
||||||
isScrolled = this.scrolled.asReadonly();
|
isScrolled = this.scrolled.asReadonly();
|
||||||
|
|
||||||
|
@ -17,47 +17,50 @@
|
|||||||
{{ description }}
|
{{ description }}
|
||||||
</div>
|
</div>
|
||||||
<bit-item-group>
|
<bit-item-group>
|
||||||
<bit-item *ngFor="let cipher of ciphers">
|
<cdk-virtual-scroll-viewport [itemSize]="ItemHeight">
|
||||||
<a
|
<bit-item *cdkVirtualFor="let cipher of ciphers">
|
||||||
bit-item-content
|
<a
|
||||||
(click)="onViewCipher(cipher)"
|
bit-item-content
|
||||||
[appA11yTitle]="'viewItemTitle' | i18n: cipher.name"
|
(click)="onViewCipher(cipher)"
|
||||||
>
|
[appA11yTitle]="'viewItemTitle' | i18n: cipher.name"
|
||||||
<app-vault-icon slot="start" [cipher]="cipher"></app-vault-icon>
|
class="{{ ItemHeightClass }}"
|
||||||
<span data-testid="item-name">{{ cipher.name }}</span>
|
>
|
||||||
<i
|
<app-vault-icon slot="start" [cipher]="cipher"></app-vault-icon>
|
||||||
*ngIf="cipher.organizationId"
|
<span data-testid="item-name">{{ cipher.name }}</span>
|
||||||
appOrgIcon
|
<i
|
||||||
[tierType]="cipher.organization.productTierType"
|
*ngIf="cipher.organizationId"
|
||||||
[size]="'small'"
|
appOrgIcon
|
||||||
[appA11yTitle]="orgIconTooltip(cipher)"
|
[tierType]="cipher.organization.productTierType"
|
||||||
></i>
|
[size]="'small'"
|
||||||
<i
|
[appA11yTitle]="orgIconTooltip(cipher)"
|
||||||
*ngIf="cipher.hasAttachments"
|
></i>
|
||||||
class="bwi bwi-paperclip bwi-sm"
|
<i
|
||||||
[appA11yTitle]="'attachments' | i18n"
|
*ngIf="cipher.hasAttachments"
|
||||||
></i>
|
class="bwi bwi-paperclip bwi-sm"
|
||||||
<span slot="secondary">{{ cipher.subTitle }}</span>
|
[appA11yTitle]="'attachments' | i18n"
|
||||||
</a>
|
></i>
|
||||||
<ng-container slot="end">
|
<span slot="secondary">{{ cipher.subTitle }}</span>
|
||||||
<bit-item-action *ngIf="showAutofillButton">
|
</a>
|
||||||
<button
|
<ng-container slot="end">
|
||||||
type="button"
|
<bit-item-action *ngIf="showAutofillButton">
|
||||||
bitBadge
|
<button
|
||||||
variant="primary"
|
type="button"
|
||||||
(click)="doAutofill(cipher)"
|
bitBadge
|
||||||
[title]="'autofillTitle' | i18n: cipher.name"
|
variant="primary"
|
||||||
[attr.aria-label]="'autofillTitle' | i18n: cipher.name"
|
(click)="doAutofill(cipher)"
|
||||||
>
|
[title]="'autofillTitle' | i18n: cipher.name"
|
||||||
{{ "autoFill" | i18n }}
|
[attr.aria-label]="'autofillTitle' | i18n: cipher.name"
|
||||||
</button>
|
>
|
||||||
</bit-item-action>
|
{{ "autoFill" | i18n }}
|
||||||
<app-item-copy-actions [cipher]="cipher"></app-item-copy-actions>
|
</button>
|
||||||
<app-item-more-options
|
</bit-item-action>
|
||||||
[cipher]="cipher"
|
<app-item-copy-actions [cipher]="cipher"></app-item-copy-actions>
|
||||||
[hideAutofillOptions]="showAutofillButton"
|
<app-item-more-options
|
||||||
></app-item-more-options>
|
[cipher]="cipher"
|
||||||
</ng-container>
|
[hideAutofillOptions]="showAutofillButton"
|
||||||
</bit-item>
|
></app-item-more-options>
|
||||||
|
</ng-container>
|
||||||
|
</bit-item>
|
||||||
|
</cdk-virtual-scroll-viewport>
|
||||||
</bit-item-group>
|
</bit-item-group>
|
||||||
</bit-section>
|
</bit-section>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { ScrollingModule } from "@angular/cdk/scrolling";
|
||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { booleanAttribute, Component, EventEmitter, Input, Output } from "@angular/core";
|
import { booleanAttribute, Component, EventEmitter, Input, Output } from "@angular/core";
|
||||||
import { Router, RouterLink } from "@angular/router";
|
import { Router, RouterLink } from "@angular/router";
|
||||||
@ -6,6 +7,8 @@ import { JslibModule } from "@bitwarden/angular/jslib.module";
|
|||||||
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
import {
|
import {
|
||||||
BadgeModule,
|
BadgeModule,
|
||||||
|
BitItemHeight,
|
||||||
|
BitItemHeightClass,
|
||||||
ButtonModule,
|
ButtonModule,
|
||||||
IconButtonModule,
|
IconButtonModule,
|
||||||
ItemModule,
|
ItemModule,
|
||||||
@ -35,12 +38,16 @@ import { ItemMoreOptionsComponent } from "../item-more-options/item-more-options
|
|||||||
ItemCopyActionsComponent,
|
ItemCopyActionsComponent,
|
||||||
ItemMoreOptionsComponent,
|
ItemMoreOptionsComponent,
|
||||||
OrgIconDirective,
|
OrgIconDirective,
|
||||||
|
ScrollingModule,
|
||||||
],
|
],
|
||||||
selector: "app-vault-list-items-container",
|
selector: "app-vault-list-items-container",
|
||||||
templateUrl: "vault-list-items-container.component.html",
|
templateUrl: "vault-list-items-container.component.html",
|
||||||
standalone: true,
|
standalone: true,
|
||||||
})
|
})
|
||||||
export class VaultListItemsContainerComponent {
|
export class VaultListItemsContainerComponent {
|
||||||
|
protected ItemHeightClass = BitItemHeightClass;
|
||||||
|
protected ItemHeight = BitItemHeight;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of ciphers to display.
|
* The list of ciphers to display.
|
||||||
*/
|
*/
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<popup-page [loading]="loading$ | async">
|
<popup-page [loading]="loading$ | async" disablePadding>
|
||||||
<popup-header slot="header" [pageTitle]="'vault' | i18n">
|
<popup-header slot="header" [pageTitle]="'vault' | i18n">
|
||||||
<ng-container slot="end">
|
<ng-container slot="end">
|
||||||
<app-new-item-dropdown [initialValues]="newItemItemValues$ | async"></app-new-item-dropdown>
|
<app-new-item-dropdown [initialValues]="newItemItemValues$ | async"></app-new-item-dropdown>
|
||||||
@ -54,7 +54,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ng-container *ngIf="vaultState === null">
|
<div *ngIf="vaultState === null" cdkVirtualScrollingElement class="tw-h-full tw-p-3">
|
||||||
<app-autofill-vault-list-items></app-autofill-vault-list-items>
|
<app-autofill-vault-list-items></app-autofill-vault-list-items>
|
||||||
<app-vault-list-items-container
|
<app-vault-list-items-container
|
||||||
[title]="'favorites' | i18n"
|
[title]="'favorites' | i18n"
|
||||||
@ -67,6 +67,6 @@
|
|||||||
id="allItems"
|
id="allItems"
|
||||||
disableSectionMargin
|
disableSectionMargin
|
||||||
></app-vault-list-items-container>
|
></app-vault-list-items-container>
|
||||||
</ng-container>
|
</div>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</popup-page>
|
</popup-page>
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { ScrollingModule } from "@angular/cdk/scrolling";
|
||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { Component, OnDestroy, OnInit } from "@angular/core";
|
import { Component, OnDestroy, OnInit } from "@angular/core";
|
||||||
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
import { takeUntilDestroyed } from "@angular/core/rxjs-interop";
|
||||||
@ -51,6 +52,7 @@ enum VaultState {
|
|||||||
RouterLink,
|
RouterLink,
|
||||||
VaultV2SearchComponent,
|
VaultV2SearchComponent,
|
||||||
NewItemDropdownV2Component,
|
NewItemDropdownV2Component,
|
||||||
|
ScrollingModule,
|
||||||
],
|
],
|
||||||
providers: [VaultUiOnboardingService],
|
providers: [VaultUiOnboardingService],
|
||||||
})
|
})
|
||||||
|
@ -1 +1,3 @@
|
|||||||
export * from "./item.module";
|
export * from "./item.module";
|
||||||
|
|
||||||
|
export { BitItemHeight, BitItemHeightClass } from "./item.component";
|
||||||
|
@ -5,6 +5,20 @@ import { A11yRowDirective } from "../a11y/a11y-row.directive";
|
|||||||
|
|
||||||
import { ItemActionComponent } from "./item-action.component";
|
import { ItemActionComponent } from "./item-action.component";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class used to set the height of a bit item's inner content.
|
||||||
|
*/
|
||||||
|
export const BitItemHeightClass = `tw-h-[52px]`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The height of a bit item in pixels. Includes any margin, padding, or border. Used by the virtual scroll
|
||||||
|
* to estimate how many items can be displayed at once and how large the virtual container should be.
|
||||||
|
* Needs to be updated if the item height or spacing changes.
|
||||||
|
*
|
||||||
|
* 52px + 5.25px bottom margin + 1px border = 58.25px
|
||||||
|
*/
|
||||||
|
export const BitItemHeight = 58.25; //
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "bit-item",
|
selector: "bit-item",
|
||||||
standalone: true,
|
standalone: true,
|
||||||
|
Loading…
Reference in New Issue
Block a user