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()
|
@localized()
|
||||||
export class LocalePicker extends LitElement {
|
export class LocalePicker extends LitElement {
|
||||||
@state()
|
@state()
|
||||||
private localeNames?: LocaleNames;
|
private localeNames: LocaleNames = {} as LocaleNames;
|
||||||
|
|
||||||
private setLocaleName = (locale: LocaleCode) => {
|
private setLocaleName = (locale: LocaleCode) => {
|
||||||
this.localeNames![locale] = new Intl.DisplayNames([locale], {
|
this.localeNames[locale] = new Intl.DisplayNames([locale], {
|
||||||
type: "language",
|
type: "language",
|
||||||
}).of(locale);
|
}).of(locale)!;
|
||||||
};
|
};
|
||||||
|
|
||||||
async firstUpdated() {
|
async firstUpdated() {
|
||||||
@ -63,22 +63,33 @@ export class LocalePicker extends LitElement {
|
|||||||
const selectedLocale = getLocale();
|
const selectedLocale = getLocale();
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<sl-select value=${selectedLocale} @sl-change=${this.localeChanged}>
|
<sl-dropdown
|
||||||
${allLocales.map(
|
value=${selectedLocale}
|
||||||
(locale) =>
|
@sl-select=${this.localeChanged}
|
||||||
html`<sl-menu-item
|
placement="top-end"
|
||||||
value=${locale}
|
distance="4"
|
||||||
?selected=${locale === selectedLocale}
|
hoist
|
||||||
>
|
>
|
||||||
${this.localeNames![locale]}
|
<sl-button slot="trigger" size="small" caret
|
||||||
</sl-menu-item>`
|
>${this.localeNames[selectedLocale as LocaleCode]}</sl-button
|
||||||
)}
|
>
|
||||||
</sl-select>
|
<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) {
|
async localeChanged(event: CustomEvent) {
|
||||||
const newLocale = (event.target as HTMLSelectElement).value as LocaleCode;
|
const newLocale = event.detail.item.value as LocaleCode;
|
||||||
|
|
||||||
if (newLocale !== getLocale()) {
|
if (newLocale !== getLocale()) {
|
||||||
const url = new URL(window.location.href);
|
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">
|
<div class="min-w-screen min-h-screen flex flex-col">
|
||||||
${this.renderNavBar()}
|
${this.renderNavBar()}
|
||||||
<main class="relative flex-auto flex">${this.renderPage()}</main>
|
<main class="relative flex-auto flex">${this.renderPage()}</main>
|
||||||
<footer class="flex justify-center p-4 border-t">
|
<div class="border-t border-neutral-100">${this.renderFooter()}</div>
|
||||||
<btrix-locale-picker></btrix-locale-picker>
|
|
||||||
</footer>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<sl-dialog
|
<sl-dialog
|
||||||
@ -217,34 +215,61 @@ export class App extends LiteElement {
|
|||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
<a href="/archives" @click="${this.navLink}"
|
<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>
|
||||||
<div class="grid grid-flow-col gap-5 items-center">
|
<div class="grid grid-flow-col gap-5 items-center">
|
||||||
${this.authService.authState
|
${this.authService.authState
|
||||||
? html` <sl-dropdown placement="bottom-end">
|
? html` <sl-dropdown placement="bottom-end">
|
||||||
<div class="p-2" role="button" slot="trigger">
|
<sl-icon-button
|
||||||
${this.userInfo?.name || this.userInfo?.email}
|
slot="trigger"
|
||||||
<span class="text-xs"
|
name="person-circle"
|
||||||
><sl-icon name="chevron-down"></sl-icon
|
style="font-size: 1.5rem;"
|
||||||
></span>
|
></sl-icon-button>
|
||||||
</div>
|
|
||||||
<sl-menu>
|
<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
|
<sl-menu-item
|
||||||
@click=${() => this.navigate(ROUTES.accountSettings)}
|
@click=${() => this.navigate(ROUTES.accountSettings)}
|
||||||
>
|
>
|
||||||
|
<sl-icon slot="prefix" name="gear"></sl-icon>
|
||||||
${msg("Your account")}
|
${msg("Your account")}
|
||||||
</sl-menu-item>
|
</sl-menu-item>
|
||||||
${this.userInfo?.isAdmin
|
${this.userInfo?.isAdmin
|
||||||
? html` <sl-menu-item
|
? html` <sl-menu-item
|
||||||
@click=${() => this.navigate(ROUTES.usersInvite)}
|
@click=${() => this.navigate(ROUTES.usersInvite)}
|
||||||
>
|
>
|
||||||
|
<sl-icon slot="prefix" name="person-plus"></sl-icon>
|
||||||
${msg("Invite Users")}
|
${msg("Invite Users")}
|
||||||
</sl-menu-item>`
|
</sl-menu-item>`
|
||||||
: ""}
|
: ""}
|
||||||
<sl-menu-item @click="${this.onLogOut}"
|
<sl-divider></sl-divider>
|
||||||
>${msg("Log Out")}</sl-menu-item
|
<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-menu>
|
||||||
</sl-dropdown>`
|
</sl-dropdown>`
|
||||||
: html`
|
: 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() {
|
renderPage() {
|
||||||
switch (this.viewState.route) {
|
switch (this.viewState.route) {
|
||||||
case "signUp": {
|
case "signUp": {
|
||||||
if (!this.isAppSettingsLoaded) {
|
if (!this.isAppSettingsLoaded) {
|
||||||
return html`<div
|
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>`;
|
></div>`;
|
||||||
}
|
}
|
||||||
if (this.isRegistrationEnabled) {
|
if (this.isRegistrationEnabled) {
|
||||||
return html`<btrix-sign-up
|
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}"
|
@navigate="${this.onNavigateTo}"
|
||||||
@logged-in="${this.onLoggedIn}"
|
@logged-in="${this.onLoggedIn}"
|
||||||
@log-out="${this.onLogOut}"
|
@log-out="${this.onLogOut}"
|
||||||
@ -289,7 +333,7 @@ export class App extends LiteElement {
|
|||||||
|
|
||||||
case "verify":
|
case "verify":
|
||||||
return html`<btrix-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}"
|
token="${this.viewState.params.token}"
|
||||||
@navigate="${this.onNavigateTo}"
|
@navigate="${this.onNavigateTo}"
|
||||||
@notify="${this.onNotify}"
|
@notify="${this.onNotify}"
|
||||||
@ -300,7 +344,7 @@ export class App extends LiteElement {
|
|||||||
|
|
||||||
case "join":
|
case "join":
|
||||||
return html`<btrix-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}"
|
@navigate="${this.onNavigateTo}"
|
||||||
@logged-in="${this.onLoggedIn}"
|
@logged-in="${this.onLoggedIn}"
|
||||||
token="${this.viewState.params.token}"
|
token="${this.viewState.params.token}"
|
||||||
@ -309,7 +353,7 @@ export class App extends LiteElement {
|
|||||||
|
|
||||||
case "acceptInvite":
|
case "acceptInvite":
|
||||||
return html`<btrix-accept-invite
|
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}"
|
@navigate="${this.onNavigateTo}"
|
||||||
@logged-in="${this.onLoggedIn}"
|
@logged-in="${this.onLoggedIn}"
|
||||||
@notify="${this.onNotify}"
|
@notify="${this.onNotify}"
|
||||||
@ -322,7 +366,7 @@ export class App extends LiteElement {
|
|||||||
case "loginWithRedirect":
|
case "loginWithRedirect":
|
||||||
case "forgotPassword":
|
case "forgotPassword":
|
||||||
return html`<btrix-log-in
|
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}
|
@navigate=${this.onNavigateTo}
|
||||||
@logged-in=${this.onLoggedIn}
|
@logged-in=${this.onLoggedIn}
|
||||||
.authState=${this.authService.authState}
|
.authState=${this.authService.authState}
|
||||||
@ -332,7 +376,7 @@ export class App extends LiteElement {
|
|||||||
|
|
||||||
case "resetPassword":
|
case "resetPassword":
|
||||||
return html`<btrix-reset-password
|
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}
|
@navigate=${this.onNavigateTo}
|
||||||
@logged-in=${this.onLoggedIn}
|
@logged-in=${this.onLoggedIn}
|
||||||
.authState=${this.authService.authState}
|
.authState=${this.authService.authState}
|
||||||
@ -352,7 +396,7 @@ export class App extends LiteElement {
|
|||||||
|
|
||||||
case "archives":
|
case "archives":
|
||||||
return html`<btrix-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}"
|
@navigate="${this.onNavigateTo}"
|
||||||
@need-login="${this.onNeedLogin}"
|
@need-login="${this.onNeedLogin}"
|
||||||
.authState="${this.authService.authState}"
|
.authState="${this.authService.authState}"
|
||||||
@ -412,7 +456,7 @@ export class App extends LiteElement {
|
|||||||
|
|
||||||
renderNotFoundPage() {
|
renderNotFoundPage() {
|
||||||
return html`<btrix-not-found
|
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>`;
|
></btrix-not-found>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -18,34 +18,78 @@ export class Archives extends LiteElement {
|
|||||||
userInfo?: CurrentUser;
|
userInfo?: CurrentUser;
|
||||||
|
|
||||||
@state()
|
@state()
|
||||||
archiveList?: ArchiveData[];
|
private archiveList?: ArchiveData[];
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private isInviteComplete?: boolean;
|
||||||
|
|
||||||
async firstUpdated() {
|
async firstUpdated() {
|
||||||
this.archiveList = await this.getArchives();
|
this.archiveList = await this.getArchives();
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
if (!this.archiveList) {
|
if (!this.archiveList || !this.userInfo) {
|
||||||
return html`<div
|
return html`
|
||||||
class="w-full flex items-center justify-center my-24 text-4xl"
|
<div class="flex items-center justify-center my-24 text-4xl">
|
||||||
>
|
<sl-spinner></sl-spinner>
|
||||||
<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>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return html`<div class="grid gap-4">
|
return html`
|
||||||
<h1 class="text-xl font-bold">${msg("Archives")}</h1>
|
|
||||||
|
|
||||||
<ul class="border rounded-lg overflow-hidden">
|
<ul class="border rounded-lg overflow-hidden">
|
||||||
${this.archiveList.map(
|
${this.archiveList.map(
|
||||||
(archive, i) =>
|
(archive) =>
|
||||||
html`
|
html`
|
||||||
<li
|
<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"
|
role="button"
|
||||||
@click=${this.makeOnArchiveClick(archive)}
|
@click=${this.makeOnArchiveClick(archive)}
|
||||||
>
|
>
|
||||||
<span class="text-primary font-medium mr-2"
|
<span class="font-medium mr-2 transition-colors"
|
||||||
>${archive.name}</span
|
>${archive.name}</span
|
||||||
>
|
>
|
||||||
${this.userInfo &&
|
${this.userInfo &&
|
||||||
@ -59,7 +103,33 @@ export class Archives extends LiteElement {
|
|||||||
`
|
`
|
||||||
)}
|
)}
|
||||||
</ul>
|
</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[]> {
|
async getArchives(): Promise<ArchiveData[]> {
|
||||||
|
@ -20,6 +20,9 @@ import(
|
|||||||
import(
|
import(
|
||||||
/* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/dialog/dialog"
|
/* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/dialog/dialog"
|
||||||
);
|
);
|
||||||
|
import(
|
||||||
|
/* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/divider/divider"
|
||||||
|
);
|
||||||
import(
|
import(
|
||||||
/* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/form/form"
|
/* webpackChunkName: "shoelace" */ "@shoelace-style/shoelace/dist/components/form/form"
|
||||||
);
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user