[CL-285] Add default loading state to popup-page (#10040)
This commit is contained in:
parent
bc7c6dd04e
commit
154f15fa58
|
@ -3628,5 +3628,8 @@
|
||||||
},
|
},
|
||||||
"addAccount": {
|
"addAccount": {
|
||||||
"message": "Add account"
|
"message": "Add account"
|
||||||
|
},
|
||||||
|
"loading": {
|
||||||
|
"message": "Loading"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,14 @@ page looks nice when the extension is popped out.
|
||||||
- default
|
- default
|
||||||
- Whatever content you want in `main`.
|
- Whatever content you want in `main`.
|
||||||
|
|
||||||
|
**Inputs**
|
||||||
|
|
||||||
|
- `loading`
|
||||||
|
- When `true`, displays a loading state overlay instead of the default content. Defaults to
|
||||||
|
`false`.
|
||||||
|
- `loadingText`
|
||||||
|
- Custom text to be applied to the loading element for screenreaders only. Defaults to "Loading".
|
||||||
|
|
||||||
Basic usage example:
|
Basic usage example:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
|
@ -137,8 +145,20 @@ When the browser extension is popped out, the "popout" button should not be pass
|
||||||
<Story of={stories.PoppedOut} />
|
<Story of={stories.PoppedOut} />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
|
# Other stories
|
||||||
|
|
||||||
## Centered Content
|
## Centered Content
|
||||||
|
|
||||||
|
An example of how to center the default content.
|
||||||
|
|
||||||
<Canvas>
|
<Canvas>
|
||||||
<Story of={stories.CenteredContent} />
|
<Story of={stories.CenteredContent} />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
|
## Loading
|
||||||
|
|
||||||
|
An example of what the loading state looks like.
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Story of={stories.Loading} />
|
||||||
|
</Canvas>
|
||||||
|
|
|
@ -62,27 +62,6 @@ class VaultComponent {
|
||||||
protected data = Array.from(Array(20).keys());
|
protected data = Array.from(Array(20).keys());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "generator-placeholder",
|
|
||||||
template: ` <div class="tw-text-main">generator stuff here</div> `,
|
|
||||||
standalone: true,
|
|
||||||
})
|
|
||||||
class GeneratorComponent {}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "send-placeholder",
|
|
||||||
template: ` <div class="tw-text-main">send some stuff</div> `,
|
|
||||||
standalone: true,
|
|
||||||
})
|
|
||||||
class SendComponent {}
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: "settings-placeholder",
|
|
||||||
template: ` <div class="tw-text-main">change your settings</div> `,
|
|
||||||
standalone: true,
|
|
||||||
})
|
|
||||||
class SettingsComponent {}
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "mock-add-button",
|
selector: "mock-add-button",
|
||||||
template: `
|
template: `
|
||||||
|
@ -186,7 +165,7 @@ class MockVaultPagePoppedComponent {}
|
||||||
<mock-current-account></mock-current-account>
|
<mock-current-account></mock-current-account>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</popup-header>
|
</popup-header>
|
||||||
<generator-placeholder></generator-placeholder>
|
<div class="tw-text-main">Generator content here</div>
|
||||||
</popup-page>
|
</popup-page>
|
||||||
`,
|
`,
|
||||||
standalone: true,
|
standalone: true,
|
||||||
|
@ -196,7 +175,6 @@ class MockVaultPagePoppedComponent {}
|
||||||
MockAddButtonComponent,
|
MockAddButtonComponent,
|
||||||
MockPopoutButtonComponent,
|
MockPopoutButtonComponent,
|
||||||
MockCurrentAccountComponent,
|
MockCurrentAccountComponent,
|
||||||
GeneratorComponent,
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
class MockGeneratorPageComponent {}
|
class MockGeneratorPageComponent {}
|
||||||
|
@ -212,7 +190,7 @@ class MockGeneratorPageComponent {}
|
||||||
<mock-current-account></mock-current-account>
|
<mock-current-account></mock-current-account>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</popup-header>
|
</popup-header>
|
||||||
<send-placeholder></send-placeholder>
|
<div class="tw-text-main">Send content here</div>
|
||||||
</popup-page>
|
</popup-page>
|
||||||
`,
|
`,
|
||||||
standalone: true,
|
standalone: true,
|
||||||
|
@ -222,7 +200,6 @@ class MockGeneratorPageComponent {}
|
||||||
MockAddButtonComponent,
|
MockAddButtonComponent,
|
||||||
MockPopoutButtonComponent,
|
MockPopoutButtonComponent,
|
||||||
MockCurrentAccountComponent,
|
MockCurrentAccountComponent,
|
||||||
SendComponent,
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
class MockSendPageComponent {}
|
class MockSendPageComponent {}
|
||||||
|
@ -238,7 +215,7 @@ class MockSendPageComponent {}
|
||||||
<mock-current-account></mock-current-account>
|
<mock-current-account></mock-current-account>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
</popup-header>
|
</popup-header>
|
||||||
<settings-placeholder></settings-placeholder>
|
<div class="tw-text-main">Settings content here</div>
|
||||||
</popup-page>
|
</popup-page>
|
||||||
`,
|
`,
|
||||||
standalone: true,
|
standalone: true,
|
||||||
|
@ -248,7 +225,6 @@ class MockSendPageComponent {}
|
||||||
MockAddButtonComponent,
|
MockAddButtonComponent,
|
||||||
MockPopoutButtonComponent,
|
MockPopoutButtonComponent,
|
||||||
MockCurrentAccountComponent,
|
MockCurrentAccountComponent,
|
||||||
SettingsComponent,
|
|
||||||
],
|
],
|
||||||
})
|
})
|
||||||
class MockSettingsPageComponent {}
|
class MockSettingsPageComponent {}
|
||||||
|
@ -312,6 +288,7 @@ export default {
|
||||||
useFactory: () => {
|
useFactory: () => {
|
||||||
return new I18nMockService({
|
return new I18nMockService({
|
||||||
back: "Back",
|
back: "Back",
|
||||||
|
loading: "Loading",
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -406,3 +383,19 @@ export const CenteredContent: Story = {
|
||||||
`,
|
`,
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const Loading: Story = {
|
||||||
|
render: (args) => ({
|
||||||
|
props: args,
|
||||||
|
template: /* HTML */ `
|
||||||
|
<extension-container>
|
||||||
|
<popup-tab-navigation>
|
||||||
|
<popup-page [loading]="true">
|
||||||
|
<popup-header slot="header" pageTitle="Page Header"></popup-header>
|
||||||
|
Content would go here
|
||||||
|
</popup-page>
|
||||||
|
</popup-tab-navigation>
|
||||||
|
</extension-container>
|
||||||
|
`,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
|
@ -1,7 +1,16 @@
|
||||||
<ng-content select="[slot=header]"></ng-content>
|
<ng-content select="[slot=header]"></ng-content>
|
||||||
<main class="tw-bg-background-alt tw-flex-1 tw-overflow-y-auto tw-h-full">
|
<main class="tw-flex-1 tw-overflow-y-auto tw-h-full tw-relative tw-bg-background-alt">
|
||||||
<div class="tw-max-w-screen-sm tw-mx-auto tw-p-3 tw-overflow-y-auto tw-h-full">
|
<div
|
||||||
|
class="tw-max-w-screen-sm tw-mx-auto tw-p-3 tw-overflow-y-auto tw-h-full"
|
||||||
|
[ngClass]="{ 'tw-invisible': loading }"
|
||||||
|
>
|
||||||
<ng-content></ng-content>
|
<ng-content></ng-content>
|
||||||
</div>
|
</div>
|
||||||
|
<span
|
||||||
|
class="tw-absolute tw-inset-0 tw-flex tw-items-center tw-justify-center tw-text-main"
|
||||||
|
[ngClass]="{ 'tw-invisible': !loading }"
|
||||||
|
>
|
||||||
|
<i class="bwi bwi-spinner bwi-lg bwi-spin" [attr.aria-label]="loadingText"></i>
|
||||||
|
</span>
|
||||||
</main>
|
</main>
|
||||||
<ng-content select="[slot=footer]"></ng-content>
|
<ng-content select="[slot=footer]"></ng-content>
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
import { Component } from "@angular/core";
|
import { CommonModule } from "@angular/common";
|
||||||
|
import { Component, Input, inject } from "@angular/core";
|
||||||
|
|
||||||
|
import { I18nService } from "@bitwarden/common/platform/abstractions/i18n.service";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: "popup-page",
|
selector: "popup-page",
|
||||||
|
@ -7,5 +10,13 @@ import { Component } from "@angular/core";
|
||||||
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-auto",
|
||||||
},
|
},
|
||||||
|
imports: [CommonModule],
|
||||||
})
|
})
|
||||||
export class PopupPageComponent {}
|
export class PopupPageComponent {
|
||||||
|
protected i18nService = inject(I18nService);
|
||||||
|
|
||||||
|
@Input() loading = false;
|
||||||
|
|
||||||
|
/** Accessible loading label for the spinner. Defaults to "loading" */
|
||||||
|
@Input() loadingText?: string = this.i18nService.t("loading");
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue