Show invite message to super admin & layout fixes (#181)
This commit is contained in:
parent
fe31f551b2
commit
c18418ff09
@ -14,12 +14,12 @@ type LocaleNames = {
|
||||
@localized()
|
||||
export class LocalePicker extends LitElement {
|
||||
@state()
|
||||
private localeNames?: LocaleNames;
|
||||
private localeNames: LocaleNames = {} as LocaleNames;
|
||||
|
||||
private setLocaleName = (locale: LocaleCode) => {
|
||||
this.localeNames![locale] = new Intl.DisplayNames([locale], {
|
||||
this.localeNames[locale] = new Intl.DisplayNames([locale], {
|
||||
type: "language",
|
||||
}).of(locale);
|
||||
}).of(locale)!;
|
||||
};
|
||||
|
||||
async firstUpdated() {
|
||||
@ -63,22 +63,33 @@ export class LocalePicker extends LitElement {
|
||||
const selectedLocale = getLocale();
|
||||
|
||||
return html`
|
||||
<sl-select value=${selectedLocale} @sl-change=${this.localeChanged}>
|
||||
${allLocales.map(
|
||||
(locale) =>
|
||||
html`<sl-menu-item
|
||||
value=${locale}
|
||||
?selected=${locale === selectedLocale}
|
||||
>
|
||||
${this.localeNames![locale]}
|
||||
</sl-menu-item>`
|
||||
)}
|
||||
</sl-select>
|
||||
<sl-dropdown
|
||||
value=${selectedLocale}
|
||||
@sl-select=${this.localeChanged}
|
||||
placement="top-end"
|
||||
distance="4"
|
||||
hoist
|
||||
>
|
||||
<sl-button slot="trigger" size="small" caret
|
||||
>${this.localeNames[selectedLocale as LocaleCode]}</sl-button
|
||||
>
|
||||
<sl-menu>
|
||||
${allLocales.map(
|
||||
(locale) =>
|
||||
html`<sl-menu-item
|
||||
value=${locale}
|
||||
?checked=${locale === selectedLocale}
|
||||
>
|
||||
${this.localeNames[locale]}
|
||||
</sl-menu-item>`
|
||||
)}
|
||||
</sl-menu>
|
||||
</sl-dropdown>
|
||||
`;
|
||||
}
|
||||
|
||||
async localeChanged(event: Event) {
|
||||
const newLocale = (event.target as HTMLSelectElement).value as LocaleCode;
|
||||
async localeChanged(event: CustomEvent) {
|
||||
const newLocale = event.detail.item.value as LocaleCode;
|
||||
|
||||
if (newLocale !== getLocale()) {
|
||||
const url = new URL(window.location.href);
|
||||
|
@ -194,9 +194,7 @@ export class App extends LiteElement {
|
||||
<div class="min-w-screen min-h-screen flex flex-col">
|
||||
${this.renderNavBar()}
|
||||
<main class="relative flex-auto flex">${this.renderPage()}</main>
|
||||
<footer class="flex justify-center p-4 border-t">
|
||||
<btrix-locale-picker></btrix-locale-picker>
|
||||
</footer>
|
||||
<div class="border-t border-neutral-100">${this.renderFooter()}</div>
|
||||
</div>
|
||||
|
||||
<sl-dialog
|
||||
@ -217,34 +215,61 @@ export class App extends LiteElement {
|
||||
>
|
||||
<div>
|
||||
<a href="/archives" @click="${this.navLink}"
|
||||
><h1 class="text-base">${msg("Browsertrix Cloud")}</h1></a
|
||||
><h1 class="text-sm font-medium">
|
||||
${msg("Browsertrix Cloud")}
|
||||
</h1></a
|
||||
>
|
||||
</div>
|
||||
<div class="grid grid-flow-col gap-5 items-center">
|
||||
${this.authService.authState
|
||||
? html` <sl-dropdown placement="bottom-end">
|
||||
<div class="p-2" role="button" slot="trigger">
|
||||
${this.userInfo?.name || this.userInfo?.email}
|
||||
<span class="text-xs"
|
||||
><sl-icon name="chevron-down"></sl-icon
|
||||
></span>
|
||||
</div>
|
||||
<sl-menu>
|
||||
<sl-icon-button
|
||||
slot="trigger"
|
||||
name="person-circle"
|
||||
style="font-size: 1.5rem;"
|
||||
></sl-icon-button>
|
||||
|
||||
<sl-menu class="w-60 min-w-min max-w-full">
|
||||
<div class="px-7 py-2">
|
||||
${this.userInfo?.isAdmin
|
||||
? html`
|
||||
<div class="mb-2">
|
||||
<sl-tag
|
||||
class="uppercase"
|
||||
type="primary"
|
||||
size="small"
|
||||
>${msg("admin")}</sl-tag
|
||||
>
|
||||
</div>
|
||||
`
|
||||
: ""}
|
||||
<div class="font-medium text-neutral-700">
|
||||
${this.userInfo?.name}
|
||||
</div>
|
||||
<div class="text-sm text-neutral-500">
|
||||
${this.userInfo?.email}
|
||||
</div>
|
||||
</div>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item
|
||||
@click=${() => this.navigate(ROUTES.accountSettings)}
|
||||
>
|
||||
<sl-icon slot="prefix" name="gear"></sl-icon>
|
||||
${msg("Your account")}
|
||||
</sl-menu-item>
|
||||
${this.userInfo?.isAdmin
|
||||
? html` <sl-menu-item
|
||||
@click=${() => this.navigate(ROUTES.usersInvite)}
|
||||
>
|
||||
<sl-icon slot="prefix" name="person-plus"></sl-icon>
|
||||
${msg("Invite Users")}
|
||||
</sl-menu-item>`
|
||||
: ""}
|
||||
<sl-menu-item @click="${this.onLogOut}"
|
||||
>${msg("Log Out")}</sl-menu-item
|
||||
>
|
||||
<sl-divider></sl-divider>
|
||||
<sl-menu-item @click="${this.onLogOut}">
|
||||
<sl-icon slot="prefix" name="box-arrow-right"></sl-icon>
|
||||
${msg("Log Out")}
|
||||
</sl-menu-item>
|
||||
</sl-menu>
|
||||
</sl-dropdown>`
|
||||
: html`
|
||||
@ -266,17 +291,36 @@ export class App extends LiteElement {
|
||||
`;
|
||||
}
|
||||
|
||||
renderFooter() {
|
||||
return html`
|
||||
<footer
|
||||
class="w-full max-w-screen-lg mx-auto p-3 box-border flex justify-between"
|
||||
>
|
||||
<div>
|
||||
<sl-icon-button
|
||||
name="github"
|
||||
href="https://github.com/webrecorder/browsertrix-cloud"
|
||||
target="_blank"
|
||||
></sl-icon-button>
|
||||
</div>
|
||||
<div>
|
||||
<btrix-locale-picker></btrix-locale-picker>
|
||||
</div>
|
||||
</footer>
|
||||
`;
|
||||
}
|
||||
|
||||
renderPage() {
|
||||
switch (this.viewState.route) {
|
||||
case "signUp": {
|
||||
if (!this.isAppSettingsLoaded) {
|
||||
return html`<div
|
||||
class="w-full md:bg-gray-50 flex items-center justify-center"
|
||||
class="w-full md:bg-neutral-50 flex items-center justify-center"
|
||||
></div>`;
|
||||
}
|
||||
if (this.isRegistrationEnabled) {
|
||||
return html`<btrix-sign-up
|
||||
class="w-full md:bg-gray-50 flex items-center justify-center"
|
||||
class="w-full md:bg-neutral-50 flex items-center justify-center"
|
||||
@navigate="${this.onNavigateTo}"
|
||||
@logged-in="${this.onLoggedIn}"
|
||||
@log-out="${this.onLogOut}"
|
||||
@ -289,7 +333,7 @@ export class App extends LiteElement {
|
||||
|
||||
case "verify":
|
||||
return html`<btrix-verify
|
||||
class="w-full md:bg-gray-50 flex items-center justify-center"
|
||||
class="w-full md:bg-neutral-50 flex items-center justify-center"
|
||||
token="${this.viewState.params.token}"
|
||||
@navigate="${this.onNavigateTo}"
|
||||
@notify="${this.onNotify}"
|
||||
@ -300,7 +344,7 @@ export class App extends LiteElement {
|
||||
|
||||
case "join":
|
||||
return html`<btrix-join
|
||||
class="w-full md:bg-gray-50 flex items-center justify-center"
|
||||
class="w-full md:bg-neutral-50 flex items-center justify-center"
|
||||
@navigate="${this.onNavigateTo}"
|
||||
@logged-in="${this.onLoggedIn}"
|
||||
token="${this.viewState.params.token}"
|
||||
@ -309,7 +353,7 @@ export class App extends LiteElement {
|
||||
|
||||
case "acceptInvite":
|
||||
return html`<btrix-accept-invite
|
||||
class="w-full md:bg-gray-50 flex items-center justify-center"
|
||||
class="w-full md:bg-neutral-50 flex items-center justify-center"
|
||||
@navigate="${this.onNavigateTo}"
|
||||
@logged-in="${this.onLoggedIn}"
|
||||
@notify="${this.onNotify}"
|
||||
@ -322,7 +366,7 @@ export class App extends LiteElement {
|
||||
case "loginWithRedirect":
|
||||
case "forgotPassword":
|
||||
return html`<btrix-log-in
|
||||
class="w-full md:bg-gray-50 flex items-center justify-center"
|
||||
class="w-full md:bg-neutral-50 flex items-center justify-center"
|
||||
@navigate=${this.onNavigateTo}
|
||||
@logged-in=${this.onLoggedIn}
|
||||
.authState=${this.authService.authState}
|
||||
@ -332,7 +376,7 @@ export class App extends LiteElement {
|
||||
|
||||
case "resetPassword":
|
||||
return html`<btrix-reset-password
|
||||
class="w-full md:bg-gray-50 flex items-center justify-center"
|
||||
class="w-full md:bg-neutral-50 flex items-center justify-center"
|
||||
@navigate=${this.onNavigateTo}
|
||||
@logged-in=${this.onLoggedIn}
|
||||
.authState=${this.authService.authState}
|
||||
@ -352,7 +396,7 @@ export class App extends LiteElement {
|
||||
|
||||
case "archives":
|
||||
return html`<btrix-archives
|
||||
class="w-full max-w-screen-lg mx-auto p-2 md:py-8 box-border"
|
||||
class="w-full md:bg-neutral-50"
|
||||
@navigate="${this.onNavigateTo}"
|
||||
@need-login="${this.onNeedLogin}"
|
||||
.authState="${this.authService.authState}"
|
||||
@ -412,7 +456,7 @@ export class App extends LiteElement {
|
||||
|
||||
renderNotFoundPage() {
|
||||
return html`<btrix-not-found
|
||||
class="w-full md:bg-gray-50 flex items-center justify-center"
|
||||
class="w-full md:bg-neutral-50 flex items-center justify-center"
|
||||
></btrix-not-found>`;
|
||||
}
|
||||
|
||||
|
@ -18,34 +18,78 @@ export class Archives extends LiteElement {
|
||||
userInfo?: CurrentUser;
|
||||
|
||||
@state()
|
||||
archiveList?: ArchiveData[];
|
||||
private archiveList?: ArchiveData[];
|
||||
|
||||
@state()
|
||||
private isInviteComplete?: boolean;
|
||||
|
||||
async firstUpdated() {
|
||||
this.archiveList = await this.getArchives();
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!this.archiveList) {
|
||||
return html`<div
|
||||
class="w-full flex items-center justify-center my-24 text-4xl"
|
||||
>
|
||||
<sl-spinner></sl-spinner>
|
||||
if (!this.archiveList || !this.userInfo) {
|
||||
return html`
|
||||
<div class="flex items-center justify-center my-24 text-4xl">
|
||||
<sl-spinner></sl-spinner>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
if (this.userInfo.isAdmin && !this.archiveList.length) {
|
||||
return html`
|
||||
<div class="bg-white">
|
||||
<header
|
||||
class="w-full max-w-screen-lg mx-auto px-3 py-4 box-border md:py-8"
|
||||
>
|
||||
<h1 class="text-2xl font-medium">${msg("Archives")}</h1>
|
||||
<p class="mt-4 text-neutral-600">
|
||||
${msg("Invite users to start archiving.")}
|
||||
</p>
|
||||
</header>
|
||||
<hr />
|
||||
</div>
|
||||
<main class="w-full max-w-screen-lg mx-auto px-3 py-4 box-border">
|
||||
${this.renderAdminOnboarding()}
|
||||
</main>
|
||||
`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<div class="bg-white">
|
||||
<header
|
||||
class="w-full max-w-screen-lg mx-auto px-3 py-4 box-border md:py-8"
|
||||
>
|
||||
<h1 class="text-2xl font-medium">${msg("Archives")}</h1>
|
||||
</header>
|
||||
<hr />
|
||||
</div>
|
||||
<main class="w-full max-w-screen-lg mx-auto px-3 py-4 box-border">
|
||||
${this.renderArchives()}
|
||||
</main>
|
||||
`;
|
||||
}
|
||||
|
||||
private renderArchives() {
|
||||
if (!this.archiveList?.length) {
|
||||
return html`<div class="border rounded-lg bg-white p-4 md:p-8">
|
||||
<p class="text-neutral-400 text-center">
|
||||
${msg("You don't have any archives.")}
|
||||
</p>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
return html`<div class="grid gap-4">
|
||||
<h1 class="text-xl font-bold">${msg("Archives")}</h1>
|
||||
|
||||
return html`
|
||||
<ul class="border rounded-lg overflow-hidden">
|
||||
${this.archiveList.map(
|
||||
(archive, i) =>
|
||||
(archive) =>
|
||||
html`
|
||||
<li
|
||||
class="p-3 md:p-6 hover:bg-gray-50${i > 0 ? " border-t" : ""}"
|
||||
class="p-3 md:p-6 bg-white border-t first:border-t-0 text-primary hover:text-indigo-400"
|
||||
role="button"
|
||||
@click=${this.makeOnArchiveClick(archive)}
|
||||
>
|
||||
<span class="text-primary font-medium mr-2"
|
||||
<span class="font-medium mr-2 transition-colors"
|
||||
>${archive.name}</span
|
||||
>
|
||||
${this.userInfo &&
|
||||
@ -59,7 +103,33 @@ export class Archives extends LiteElement {
|
||||
`
|
||||
)}
|
||||
</ul>
|
||||
</div>`;
|
||||
`;
|
||||
}
|
||||
|
||||
private renderAdminOnboarding() {
|
||||
if (this.isInviteComplete) {
|
||||
return html`
|
||||
<div class="border rounded-lg bg-white p-4 md:p-8">
|
||||
<h2 class="text-2xl font-medium mb-4">${msg("Invite a User")}</h2>
|
||||
<sl-button @click=${() => (this.isInviteComplete = false)}
|
||||
>${msg("Send another invite")}</sl-button
|
||||
>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
return html`
|
||||
<div class="border rounded-lg bg-white p-4 md:p-8">
|
||||
<h2 class="text-2xl font-medium mb-4">${msg("Invite a User")}</h2>
|
||||
<p class="mb-4 text-neutral-600 text-sm">
|
||||
${msg("Each user will manage their own archive.")}
|
||||
</p>
|
||||
|
||||
<btrix-invite-form
|
||||
.authState=${this.authState}
|
||||
@success=${() => (this.isInviteComplete = true)}
|
||||
></btrix-invite-form>
|
||||
</div>
|
||||
`;
|
||||
}
|
||||
|
||||
async getArchives(): Promise<ArchiveData[]> {
|
||||
|
@ -20,6 +20,9 @@ import(
|
||||
import(
|
||||
/* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/dialog/dialog"
|
||||
);
|
||||
import(
|
||||
/* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/divider/divider"
|
||||
);
|
||||
import(
|
||||
/* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/form/form"
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user