feat: Add help shortcuts to app header & footer (#2040)

WIP for https://github.com/webrecorder/browsertrix/issues/2041

<!-- Fixes #issue_number -->

### Changes

- Adds button to open embedded support guide
- Adds link to help forum
- Refactors app bar to look nicer on smaller screens
This commit is contained in:
sua yoo 2024-08-23 18:11:29 -07:00 committed by GitHub
parent 04c8b50423
commit acd3e1252d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 129 additions and 64 deletions

View File

@ -1,5 +1,5 @@
import { localized, msg, str } from "@lit/localize"; import { localized, msg, str } from "@lit/localize";
import type { SlDialog } from "@shoelace-style/shoelace"; import type { SlDialog, SlDrawer } from "@shoelace-style/shoelace";
import { nothing, render, type TemplateResult } from "lit"; import { nothing, render, type TemplateResult } from "lit";
import { customElement, property, query, state } from "lit/decorators.js"; import { customElement, property, query, state } from "lit/decorators.js";
import { when } from "lit/directives/when.js"; import { when } from "lit/directives/when.js";
@ -72,6 +72,9 @@ export class App extends LiteElement {
@query("#globalDialog") @query("#globalDialog")
private readonly globalDialog!: SlDialog; private readonly globalDialog!: SlDialog;
@query("#userGuideDrawer")
private readonly userGuideDrawer!: SlDrawer;
async connectedCallback() { async connectedCallback() {
let authState: AuthService["authState"] = null; let authState: AuthService["authState"] = null;
try { try {
@ -250,7 +253,9 @@ export class App extends LiteElement {
<div class="min-w-screen flex min-h-screen flex-col"> <div class="min-w-screen flex min-h-screen flex-col">
${this.renderNavBar()} ${this.renderAlertBanner()} ${this.renderNavBar()} ${this.renderAlertBanner()}
<main class="relative flex flex-auto">${this.renderPage()}</main> <main class="relative flex flex-auto">${this.renderPage()}</main>
<div class="border-t border-neutral-100">${this.renderFooter()}</div> <div class="mt-7 border-t border-neutral-100">
${this.renderFooter()}
</div>
</div> </div>
<sl-dialog <sl-dialog
@ -260,6 +265,25 @@ export class App extends LiteElement {
@sl-after-hide=${() => (this.globalDialogContent = {})} @sl-after-hide=${() => (this.globalDialogContent = {})}
>${this.globalDialogContent.body}</sl-dialog >${this.globalDialogContent.body}</sl-dialog
> >
<sl-drawer
id="userGuideDrawer"
label=${msg("User Guide")}
style="--body-spacing: 0; --footer-spacing: var(--sl-spacing-2x-small);"
>
<span slot="label" class="flex items-center gap-3">
<sl-icon name="book" class=""></sl-icon>
<span>${msg("User Guide")}</span>
</span>
<iframe
class="size-full"
src="https://docs.browsertrix.com/user-guide/"
></iframe>
<sl-button size="small" slot="footer" variant="text">
<sl-icon slot="suffix" name="box-arrow-up-right"></sl-icon>
${msg("Open in new window")}</sl-button
>
</sl-drawer>
`; `;
} }
@ -307,9 +331,9 @@ export class App extends LiteElement {
return html` return html`
<div class="border-b bg-neutral-50"> <div class="border-b bg-neutral-50">
<nav <nav
class="mx-auto box-border flex h-12 items-center justify-between px-3 xl:pl-6" class="box-border flex min-h-12 flex-wrap items-center gap-x-5 gap-y-3 p-3 leading-none md:py-0 xl:pl-6"
> >
<div class="flex items-center"> <div class="order-1 flex flex-1 items-center">
<a <a
class="items-between flex gap-2" class="items-between flex gap-2"
aria-label="home" aria-label="home"
@ -324,14 +348,14 @@ export class App extends LiteElement {
<div <div
class="${showFullLogo class="${showFullLogo
? "w-[10.5rem]" ? "w-[10.5rem]"
: "w-6 md:w-[10.5rem]"} h-6 bg-cover bg-no-repeat" : "w-6 lg:w-[10.5rem]"} h-6 bg-cover bg-no-repeat"
style="background-image: url(${brandLockupColor})" style="background-image: url(${brandLockupColor})"
role="img" role="img"
title="Browsertrix logo" title="Browsertrix logo"
></div> ></div>
</a> </a>
${when( ${when(
this.authService.authState, this.userInfo,
() => html` () => html`
${isSuperAdmin ${isSuperAdmin
? html` ? html`
@ -360,20 +384,29 @@ export class App extends LiteElement {
`, `,
)} )}
</div> </div>
<div class="grid auto-cols-max grid-flow-col items-center gap-5"> <div class="order-2 flex flex-grow-0 items-center gap-4 md:order-3">
${isSuperAdmin ${this.authState
? html`${this.userInfo && !isSuperAdmin
? html` ? html`
<a <button
class="font-medium text-neutral-500 hover:text-primary" class="flex items-center gap-2 leading-none text-neutral-500 hover:text-primary"
href="/crawls" @click=${() => void this.userGuideDrawer.show()}
@click=${this.navLink}
>${msg("Running Crawls")}</a
> >
<div class="hidden md:block">${this.renderFindCrawl()}</div> <sl-icon
name="book"
class="mt-px size-4 text-base"
></sl-icon>
<span class="sr-only lg:not-sr-only"
>${msg("User Guide")}</span
>
</button>
` `
: ""} : nothing}
${this.authService.authState <sl-dropdown
? html`<sl-dropdown placement="bottom-end" distance="4"> class="ml-auto"
placement="bottom-end"
distance="4"
>
<button slot="trigger"> <button slot="trigger">
<sl-avatar <sl-avatar
label=${msg("Open user menu")} label=${msg("Open user menu")}
@ -407,6 +440,21 @@ export class App extends LiteElement {
</sl-dropdown>` </sl-dropdown>`
: this.renderSignUpLink()} : this.renderSignUpLink()}
</div> </div>
${isSuperAdmin
? html`
<div
class="order-3 grid w-full auto-cols-max grid-flow-col items-center gap-5 md:order-2 md:w-auto"
>
<a
class="font-medium text-neutral-500 hover:text-primary"
href="/crawls"
@click=${this.navLink}
>${msg("Running Crawls")}</a
>
<div class="hidden md:block">${this.renderFindCrawl()}</div>
</div>
`
: nothing}
</nav> </nav>
</div> </div>
`; `;
@ -443,6 +491,7 @@ export class App extends LiteElement {
const orgNameLength = 50; const orgNameLength = 50;
return html` return html`
<div class="max-w-32 truncate sm:max-w-52 md:max-w-none">
${selectedOption.slug ${selectedOption.slug
? html` ? html`
<a <a
@ -458,6 +507,7 @@ export class App extends LiteElement {
${selectedOption.name.slice(0, orgNameLength)} ${selectedOption.name.slice(0, orgNameLength)}
</span> </span>
`} `}
</div>
${when( ${when(
orgs.length > 1, orgs.length > 1,
() => html` () => html`
@ -565,12 +615,12 @@ export class App extends LiteElement {
<div> <div>
<a <a
class="flex items-center gap-2 leading-none text-neutral-400 hover:text-primary" class="flex items-center gap-2 leading-none text-neutral-400 hover:text-primary"
href="https://docs.browsertrix.com" href="https://forum.webrecorder.net/c/help/5"
target="_blank" target="_blank"
rel="noopener" rel="noopener"
> >
<sl-icon name="book-half" class="size-4 text-base"></sl-icon> <sl-icon name="patch-question" class="size-4 text-base"></sl-icon>
${msg("Documentation")} <span class="sr-only lg:not-sr-only">${msg("Help Forum")}</span>
</a> </a>
</div> </div>
${this.version ${this.version

View File

@ -9,6 +9,7 @@ import "@shoelace-style/shoelace/dist/themes/light.css";
import "@shoelace-style/shoelace/dist/components/alert/alert"; import "@shoelace-style/shoelace/dist/components/alert/alert";
import "@shoelace-style/shoelace/dist/components/avatar/avatar"; import "@shoelace-style/shoelace/dist/components/avatar/avatar";
import "@shoelace-style/shoelace/dist/components/button/button"; import "@shoelace-style/shoelace/dist/components/button/button";
import "@shoelace-style/shoelace/dist/components/drawer/drawer";
import "@shoelace-style/shoelace/dist/components/icon/icon"; import "@shoelace-style/shoelace/dist/components/icon/icon";
import "@shoelace-style/shoelace/dist/components/input/input"; import "@shoelace-style/shoelace/dist/components/input/input";
import "@shoelace-style/shoelace/dist/components/checkbox/checkbox"; import "@shoelace-style/shoelace/dist/components/checkbox/checkbox";

View File

@ -340,6 +340,20 @@
border: 1px solid theme(colors.gray.200); border: 1px solid theme(colors.gray.200);
border-radius: var(--sl-input-border-radius-small); border-radius: var(--sl-input-border-radius-small);
} }
sl-drawer::part(header) {
--header-spacing: var(--sl-spacing-small);
}
sl-drawer::part(title) {
font-size: var(--font-size-base);
font-weight: var(--sl-font-weight-medium);
line-height: 1.5;
}
sl-drawer::part(footer) {
border-top: 1px solid var(--sl-panel-border-color);
}
} }
/* Following styles won't work with layers */ /* Following styles won't work with layers */