Fix crawl list action menu positioning (#1399)
Refactors `btrix-crawl-list` dropdown action menu to use `sl-dropdown` auto-positioning to fix menu clipping
This commit is contained in:
parent
b15c5ccddd
commit
ffc8b75ea8
@ -11,23 +11,22 @@
|
|||||||
* </btrix-crawl-list>
|
* </btrix-crawl-list>
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
import type { TemplateResult } from "lit";
|
||||||
import { LitElement, html, css } from "lit";
|
import { LitElement, html, css } from "lit";
|
||||||
import {
|
import {
|
||||||
customElement,
|
customElement,
|
||||||
property,
|
property,
|
||||||
query,
|
query,
|
||||||
queryAssignedElements,
|
queryAssignedElements,
|
||||||
state,
|
|
||||||
} from "lit/decorators.js";
|
} from "lit/decorators.js";
|
||||||
import { msg, localized, str } from "@lit/localize";
|
import { msg, localized, str } from "@lit/localize";
|
||||||
import type { SlMenu } from "@shoelace-style/shoelace";
|
|
||||||
import queryString from "query-string";
|
import queryString from "query-string";
|
||||||
|
|
||||||
import type { Button } from "./button";
|
|
||||||
import { RelativeDuration } from "./relative-duration";
|
import { RelativeDuration } from "./relative-duration";
|
||||||
import type { Crawl } from "../types/crawler";
|
import type { Crawl } from "../types/crawler";
|
||||||
import { srOnly, truncate, dropdown } from "../utils/css";
|
import { srOnly, truncate } from "../utils/css";
|
||||||
import type { NavigateEvent } from "../utils/LiteElement";
|
import type { NavigateEvent } from "../utils/LiteElement";
|
||||||
|
import type { OverflowDropdown } from "./overflow-dropdown";
|
||||||
|
|
||||||
const mediumBreakpointCss = css`30rem`;
|
const mediumBreakpointCss = css`30rem`;
|
||||||
const largeBreakpointCss = css`60rem`;
|
const largeBreakpointCss = css`60rem`;
|
||||||
@ -75,7 +74,6 @@ const hostVars = css`
|
|||||||
export class CrawlListItem extends LitElement {
|
export class CrawlListItem extends LitElement {
|
||||||
static styles = [
|
static styles = [
|
||||||
truncate,
|
truncate,
|
||||||
dropdown,
|
|
||||||
rowCss,
|
rowCss,
|
||||||
columnCss,
|
columnCss,
|
||||||
hostVars,
|
hostVars,
|
||||||
@ -96,12 +94,6 @@ export class CrawlListItem extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown {
|
|
||||||
contain: content;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 99;
|
|
||||||
}
|
|
||||||
|
|
||||||
.col {
|
.col {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -172,10 +164,6 @@ export class CrawlListItem extends LitElement {
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action sl-icon-button {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
`,
|
`,
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -194,42 +182,15 @@ export class CrawlListItem extends LitElement {
|
|||||||
@query(".row")
|
@query(".row")
|
||||||
row!: HTMLElement;
|
row!: HTMLElement;
|
||||||
|
|
||||||
// TODO consolidate with btrix-combobox
|
@query("btrix-overflow-dropdown")
|
||||||
@query(".dropdown")
|
dropdownMenu!: OverflowDropdown;
|
||||||
dropdown!: HTMLElement;
|
|
||||||
|
|
||||||
@query(".dropdownTrigger")
|
|
||||||
dropdownTrigger!: Button;
|
|
||||||
|
|
||||||
@queryAssignedElements({ selector: "sl-menu", slot: "menu" })
|
|
||||||
private menuArr!: Array<SlMenu>;
|
|
||||||
|
|
||||||
@state()
|
|
||||||
private dropdownIsOpen?: boolean;
|
|
||||||
|
|
||||||
@state()
|
|
||||||
private hasMenuItems?: boolean;
|
|
||||||
|
|
||||||
// TODO localize
|
// TODO localize
|
||||||
private numberFormatter = new Intl.NumberFormat(undefined, {
|
private numberFormatter = new Intl.NumberFormat(undefined, {
|
||||||
notation: "compact",
|
notation: "compact",
|
||||||
});
|
});
|
||||||
|
|
||||||
willUpdate(changedProperties: Map<string, any>) {
|
|
||||||
if (changedProperties.has("dropdownIsOpen")) {
|
|
||||||
if (this.dropdownIsOpen) {
|
|
||||||
this.openDropdown();
|
|
||||||
} else {
|
|
||||||
this.closeDropdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`${this.renderRow()}${this.renderDropdown()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderRow() {
|
|
||||||
const search =
|
const search =
|
||||||
this.collectionId || this.workflowId
|
this.collectionId || this.workflowId
|
||||||
? `?${queryString.stringify(
|
? `?${queryString.stringify(
|
||||||
@ -240,15 +201,16 @@ export class CrawlListItem extends LitElement {
|
|||||||
{ skipEmptyString: true }
|
{ skipEmptyString: true }
|
||||||
)}`
|
)}`
|
||||||
: "";
|
: "";
|
||||||
return html`<a
|
return html`<div
|
||||||
class="item row"
|
class="item row"
|
||||||
role="button"
|
role="button"
|
||||||
href="/orgs/${this.orgSlug}/items/${this.crawl?.type}/${this.crawl
|
|
||||||
?.id}${search}"
|
|
||||||
@click=${async (e: MouseEvent) => {
|
@click=${async (e: MouseEvent) => {
|
||||||
|
if (e.target === this.dropdownMenu) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await this.updateComplete;
|
await this.updateComplete;
|
||||||
const href = (e.currentTarget as HTMLAnchorElement).href;
|
const href = `/orgs/${this.orgSlug}/items/${this.crawl?.type}/${this.crawl?.id}${search}`;
|
||||||
// TODO consolidate with LiteElement navTo
|
// TODO consolidate with LiteElement navTo
|
||||||
const evt: NavigateEvent = new CustomEvent("navigate", {
|
const evt: NavigateEvent = new CustomEvent("navigate", {
|
||||||
detail: { url: href },
|
detail: { url: href },
|
||||||
@ -361,33 +323,12 @@ export class CrawlListItem extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
${this.renderActions()}
|
${this.renderActions()}
|
||||||
</a>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderDropdown() {
|
private safeRender(
|
||||||
return html`<div
|
render: (crawl: Crawl) => string | TemplateResult<1> | undefined
|
||||||
class="dropdown hidden"
|
) {
|
||||||
aria-hidden=${!this.dropdownIsOpen}
|
|
||||||
@animationend=${(e: AnimationEvent) => {
|
|
||||||
const el = e.target as HTMLDivElement;
|
|
||||||
if (e.animationName === "dropdownShow") {
|
|
||||||
el.classList.remove("animateShow");
|
|
||||||
}
|
|
||||||
if (e.animationName === "dropdownHide") {
|
|
||||||
el.classList.add("hidden");
|
|
||||||
el.classList.remove("animateHide");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<slot
|
|
||||||
name="menu"
|
|
||||||
@slotchange=${() => (this.hasMenuItems = this.menuArr.length > 0)}
|
|
||||||
@sl-select=${() => (this.dropdownIsOpen = false)}
|
|
||||||
></slot>
|
|
||||||
</div> `;
|
|
||||||
}
|
|
||||||
|
|
||||||
private safeRender(render: (crawl: Crawl) => any) {
|
|
||||||
if (!this.crawl) {
|
if (!this.crawl) {
|
||||||
return html`<sl-skeleton></sl-skeleton>`;
|
return html`<sl-skeleton></sl-skeleton>`;
|
||||||
}
|
}
|
||||||
@ -399,7 +340,7 @@ export class CrawlListItem extends LitElement {
|
|||||||
if (!crawl.firstSeed)
|
if (!crawl.firstSeed)
|
||||||
return html`<span class="truncate">${crawl.id}</span>`;
|
return html`<span class="truncate">${crawl.id}</span>`;
|
||||||
const remainder = crawl.seedCount - 1;
|
const remainder = crawl.seedCount - 1;
|
||||||
let nameSuffix: any = "";
|
let nameSuffix: string | TemplateResult<1> = "";
|
||||||
if (remainder) {
|
if (remainder) {
|
||||||
if (remainder === 1) {
|
if (remainder === 1) {
|
||||||
nameSuffix = html`<span class="additionalUrls"
|
nameSuffix = html`<span class="additionalUrls"
|
||||||
@ -417,56 +358,19 @@ export class CrawlListItem extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private renderActions() {
|
private renderActions() {
|
||||||
if (!this.hasMenuItems) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
return html` <div class="col action">
|
return html` <div class="col action">
|
||||||
<sl-icon-button
|
<btrix-overflow-dropdown>
|
||||||
class="dropdownTrigger"
|
<slot
|
||||||
label=${msg("Actions")}
|
name="menu"
|
||||||
name="three-dots-vertical"
|
@click=${(e: MouseEvent) => {
|
||||||
@click=${(e: MouseEvent) => {
|
// Prevent navigation to detail view
|
||||||
// Prevent anchor link default behavior
|
e.preventDefault();
|
||||||
e.preventDefault();
|
e.stopPropagation();
|
||||||
// Stop prop to anchor link
|
}}
|
||||||
e.stopPropagation();
|
></slot>
|
||||||
this.dropdownIsOpen = !this.dropdownIsOpen;
|
</btrix-overflow-dropdown>
|
||||||
}}
|
|
||||||
@focusout=${(e: FocusEvent) => {
|
|
||||||
const relatedTarget = e.relatedTarget as HTMLElement;
|
|
||||||
if (relatedTarget) {
|
|
||||||
if (this.menuArr[0]?.contains(relatedTarget)) {
|
|
||||||
// Keep dropdown open if moving to menu selection
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.row?.isEqualNode(relatedTarget)) {
|
|
||||||
// Handle with click event
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.dropdownIsOpen = false;
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
</sl-icon-button>
|
|
||||||
</div>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private repositionDropdown() {
|
|
||||||
const { x, y } = this.dropdownTrigger.getBoundingClientRect();
|
|
||||||
this.dropdown.style.left = `${x + window.scrollX}px`;
|
|
||||||
this.dropdown.style.top = `${y + window.scrollY - 8}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private openDropdown() {
|
|
||||||
this.repositionDropdown();
|
|
||||||
this.dropdown.classList.add("animateShow");
|
|
||||||
this.dropdown.classList.remove("hidden");
|
|
||||||
}
|
|
||||||
|
|
||||||
private closeDropdown() {
|
|
||||||
this.dropdown.classList.add("animateHide");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@localized()
|
@localized()
|
||||||
|
@ -48,3 +48,4 @@ import("./code");
|
|||||||
import("./pw-strength-alert");
|
import("./pw-strength-alert");
|
||||||
import("./search-combobox");
|
import("./search-combobox");
|
||||||
import("./meter");
|
import("./meter");
|
||||||
|
import("./overflow-dropdown");
|
||||||
|
57
frontend/src/components/overflow-dropdown.ts
Normal file
57
frontend/src/components/overflow-dropdown.ts
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
import { LitElement, html, css } from "lit";
|
||||||
|
import { customElement, state, queryAssignedElements } from "lit/decorators.js";
|
||||||
|
import { msg, localized } from "@lit/localize";
|
||||||
|
import type { SlMenu } from "@shoelace-style/shoelace";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dropdown for additional actions.
|
||||||
|
*
|
||||||
|
* Usage:
|
||||||
|
* ```ts
|
||||||
|
* <btrix-overflow-dropdown>
|
||||||
|
* <sl-menu>
|
||||||
|
* <sl-menu-item>Item 1</sl-menu-item>
|
||||||
|
* <sl-menu-item>Item 2</sl-menu-item>
|
||||||
|
* </sl-menu>
|
||||||
|
*< /btrix-overflow-dropdown>
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
@localized()
|
||||||
|
@customElement("btrix-overflow-dropdown")
|
||||||
|
export class OverflowDropdown extends LitElement {
|
||||||
|
static style = [
|
||||||
|
css`
|
||||||
|
.trigger {
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.trigger[disabled] {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
@state()
|
||||||
|
private hasMenuItems?: boolean;
|
||||||
|
|
||||||
|
@queryAssignedElements({ selector: "sl-menu", flatten: true })
|
||||||
|
private menu!: Array<SlMenu>;
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`
|
||||||
|
<sl-dropdown ?disabled=${!this.hasMenuItems}>
|
||||||
|
<sl-icon-button
|
||||||
|
slot="trigger"
|
||||||
|
class="trigger"
|
||||||
|
label=${msg("Actions")}
|
||||||
|
name="three-dots-vertical"
|
||||||
|
?disabled=${!this.hasMenuItems}
|
||||||
|
>
|
||||||
|
</sl-icon-button>
|
||||||
|
<slot
|
||||||
|
@slotchange=${() => (this.hasMenuItems = this.menu.length > 0)}
|
||||||
|
></slot>
|
||||||
|
</sl-dropdown>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
}
|
@ -11,23 +11,23 @@
|
|||||||
* </btrix-workflow-list>
|
* </btrix-workflow-list>
|
||||||
* ```
|
* ```
|
||||||
*/
|
*/
|
||||||
|
import type { TemplateResult } from "lit";
|
||||||
import { LitElement, html, css } from "lit";
|
import { LitElement, html, css } from "lit";
|
||||||
import {
|
import {
|
||||||
property,
|
property,
|
||||||
query,
|
query,
|
||||||
queryAssignedElements,
|
queryAssignedElements,
|
||||||
state,
|
|
||||||
customElement,
|
customElement,
|
||||||
} from "lit/decorators.js";
|
} from "lit/decorators.js";
|
||||||
import { msg, localized, str } from "@lit/localize";
|
import { msg, localized, str } from "@lit/localize";
|
||||||
import type { SlIconButton, SlMenu } from "@shoelace-style/shoelace";
|
|
||||||
|
|
||||||
import { RelativeDuration } from "./relative-duration";
|
import { RelativeDuration } from "./relative-duration";
|
||||||
import type { ListWorkflow } from "../types/crawler";
|
import type { ListWorkflow } from "../types/crawler";
|
||||||
import { srOnly, truncate, dropdown } from "../utils/css";
|
import { srOnly, truncate } from "../utils/css";
|
||||||
import type { NavigateEvent } from "../utils/LiteElement";
|
import type { NavigateEvent } from "../utils/LiteElement";
|
||||||
import { humanizeSchedule } from "../utils/cron";
|
import { humanizeSchedule } from "../utils/cron";
|
||||||
import { numberFormatter } from "../utils/number";
|
import { numberFormatter } from "../utils/number";
|
||||||
|
import type { OverflowDropdown } from "./overflow-dropdown";
|
||||||
|
|
||||||
const mediumBreakpointCss = css`30rem`;
|
const mediumBreakpointCss = css`30rem`;
|
||||||
const largeBreakpointCss = css`60rem`;
|
const largeBreakpointCss = css`60rem`;
|
||||||
@ -74,7 +74,6 @@ const hostVars = css`
|
|||||||
export class WorkflowListItem extends LitElement {
|
export class WorkflowListItem extends LitElement {
|
||||||
static styles = [
|
static styles = [
|
||||||
truncate,
|
truncate,
|
||||||
dropdown,
|
|
||||||
rowCss,
|
rowCss,
|
||||||
columnCss,
|
columnCss,
|
||||||
hostVars,
|
hostVars,
|
||||||
@ -84,8 +83,7 @@ export class WorkflowListItem extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.item {
|
.item {
|
||||||
contain: content;
|
contain: size;
|
||||||
content-visibility: auto;
|
|
||||||
contain-intrinsic-height: auto 4rem;
|
contain-intrinsic-height: auto 4rem;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
transition-property: background-color, box-shadow, margin;
|
transition-property: background-color, box-shadow, margin;
|
||||||
@ -99,11 +97,7 @@ export class WorkflowListItem extends LitElement {
|
|||||||
.item:focus-within {
|
.item:focus-within {
|
||||||
background-color: var(--sl-color-neutral-50);
|
background-color: var(--sl-color-neutral-50);
|
||||||
}
|
}
|
||||||
.dropdown {
|
|
||||||
contain: content;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 99;
|
|
||||||
}
|
|
||||||
.item:hover {
|
.item:hover {
|
||||||
background-color: var(--sl-color-neutral-50);
|
background-color: var(--sl-color-neutral-50);
|
||||||
margin-left: calc(-1 * var(--row-offset));
|
margin-left: calc(-1 * var(--row-offset));
|
||||||
@ -196,10 +190,6 @@ export class WorkflowListItem extends LitElement {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.action sl-icon-button {
|
|
||||||
font-size: 1rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (min-width: ${largeBreakpointCss}) {
|
@media only screen and (min-width: ${largeBreakpointCss}) {
|
||||||
.action {
|
.action {
|
||||||
border-left: 1px solid var(--sl-panel-border-color);
|
border-left: 1px solid var(--sl-panel-border-color);
|
||||||
@ -217,52 +207,30 @@ export class WorkflowListItem extends LitElement {
|
|||||||
@query(".row")
|
@query(".row")
|
||||||
row!: HTMLElement;
|
row!: HTMLElement;
|
||||||
|
|
||||||
// TODO consolidate with btrix-combobox
|
@query("btrix-overflow-dropdown")
|
||||||
@query(".dropdown")
|
dropdownMenu!: OverflowDropdown;
|
||||||
dropdown!: HTMLElement;
|
|
||||||
|
|
||||||
@query(".dropdownTrigger")
|
|
||||||
dropdownTrigger!: SlIconButton;
|
|
||||||
|
|
||||||
@queryAssignedElements({ selector: "sl-menu", slot: "menu" })
|
|
||||||
private menuArr!: Array<SlMenu>;
|
|
||||||
|
|
||||||
@state()
|
|
||||||
private dropdownIsOpen?: boolean;
|
|
||||||
|
|
||||||
private numberFormatter = numberFormatter(undefined, {
|
private numberFormatter = numberFormatter(undefined, {
|
||||||
notation: "compact",
|
notation: "compact",
|
||||||
});
|
});
|
||||||
|
|
||||||
willUpdate(changedProperties: Map<string, any>) {
|
|
||||||
if (changedProperties.has("dropdownIsOpen")) {
|
|
||||||
if (this.dropdownIsOpen) {
|
|
||||||
this.openDropdown();
|
|
||||||
} else {
|
|
||||||
this.closeDropdown();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
return html`${this.renderRow()}${this.renderDropdown()}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
renderRow() {
|
|
||||||
const notSpecified = html`<span class="notSpecified" role="presentation"
|
const notSpecified = html`<span class="notSpecified" role="presentation"
|
||||||
>---</span
|
>---</span
|
||||||
>`;
|
>`;
|
||||||
|
|
||||||
return html`<a
|
return html`<div
|
||||||
class="item row"
|
class="item row"
|
||||||
role="button"
|
role="button"
|
||||||
href=${`/orgs/${this.orgSlug}/workflows/crawl/${this.workflow?.id}#${
|
|
||||||
this.workflow?.isCrawlRunning ? "watch" : "crawls"
|
|
||||||
}`}
|
|
||||||
@click=${async (e: MouseEvent) => {
|
@click=${async (e: MouseEvent) => {
|
||||||
|
if (e.target === this.dropdownMenu) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
await this.updateComplete;
|
await this.updateComplete;
|
||||||
const href = (e.currentTarget as HTMLAnchorElement).href;
|
const href = `/orgs/${this.orgSlug}/workflows/crawl/${
|
||||||
|
this.workflow?.id
|
||||||
|
}#${this.workflow?.isCrawlRunning ? "watch" : "crawls"}`;
|
||||||
// TODO consolidate with LiteElement navTo
|
// TODO consolidate with LiteElement navTo
|
||||||
const evt: NavigateEvent = new CustomEvent("navigate", {
|
const evt: NavigateEvent = new CustomEvent("navigate", {
|
||||||
detail: { url: href },
|
detail: { url: href },
|
||||||
@ -422,59 +390,23 @@ export class WorkflowListItem extends LitElement {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col action">
|
<div class="col action">
|
||||||
<sl-icon-button
|
<btrix-overflow-dropdown>
|
||||||
class="dropdownTrigger"
|
<slot
|
||||||
name="three-dots-vertical"
|
name="menu"
|
||||||
label=${msg("Actions")}
|
@click=${(e: MouseEvent) => {
|
||||||
@click=${(e: MouseEvent) => {
|
// Prevent navigation to detail view
|
||||||
// Prevent anchor link default behavior
|
e.preventDefault();
|
||||||
e.preventDefault();
|
e.stopPropagation();
|
||||||
// Stop prop to anchor link
|
}}
|
||||||
e.stopPropagation();
|
></slot>
|
||||||
this.dropdownIsOpen = !this.dropdownIsOpen;
|
</btrix-overflow-dropdown>
|
||||||
}}
|
|
||||||
@focusout=${(e: FocusEvent) => {
|
|
||||||
const relatedTarget = e.relatedTarget as HTMLElement;
|
|
||||||
if (relatedTarget) {
|
|
||||||
if (this.menuArr[0]?.contains(relatedTarget)) {
|
|
||||||
// Keep dropdown open if moving to menu selection
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (this.row?.isEqualNode(relatedTarget)) {
|
|
||||||
// Handle with click event
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.dropdownIsOpen = false;
|
|
||||||
}}
|
|
||||||
></sl-icon-button>
|
|
||||||
</div>
|
</div>
|
||||||
</a>`;
|
</div>`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderDropdown() {
|
private safeRender(
|
||||||
return html`<div
|
render: (workflow: ListWorkflow) => string | TemplateResult<1>
|
||||||
class="dropdown hidden"
|
) {
|
||||||
aria-hidden=${!this.dropdownIsOpen}
|
|
||||||
@animationend=${(e: AnimationEvent) => {
|
|
||||||
const el = e.target as HTMLDivElement;
|
|
||||||
if (e.animationName === "dropdownShow") {
|
|
||||||
el.classList.remove("animateShow");
|
|
||||||
}
|
|
||||||
if (e.animationName === "dropdownHide") {
|
|
||||||
el.classList.add("hidden");
|
|
||||||
el.classList.remove("animateHide");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<slot
|
|
||||||
name="menu"
|
|
||||||
@sl-select=${() => (this.dropdownIsOpen = false)}
|
|
||||||
></slot>
|
|
||||||
</div> `;
|
|
||||||
}
|
|
||||||
|
|
||||||
private safeRender(render: (workflow: ListWorkflow) => any) {
|
|
||||||
if (!this.workflow) {
|
if (!this.workflow) {
|
||||||
return html`<sl-skeleton></sl-skeleton>`;
|
return html`<sl-skeleton></sl-skeleton>`;
|
||||||
}
|
}
|
||||||
@ -488,7 +420,7 @@ export class WorkflowListItem extends LitElement {
|
|||||||
if (!workflow.firstSeed)
|
if (!workflow.firstSeed)
|
||||||
return html`<span class="truncate">${workflow.id}</span>`;
|
return html`<span class="truncate">${workflow.id}</span>`;
|
||||||
const remainder = workflow.seedCount - 1;
|
const remainder = workflow.seedCount - 1;
|
||||||
let nameSuffix: any = "";
|
let nameSuffix: string | TemplateResult<1> = "";
|
||||||
if (remainder) {
|
if (remainder) {
|
||||||
if (remainder === 1) {
|
if (remainder === 1) {
|
||||||
nameSuffix = html`<span class="additionalUrls"
|
nameSuffix = html`<span class="additionalUrls"
|
||||||
@ -505,22 +437,6 @@ export class WorkflowListItem extends LitElement {
|
|||||||
>${nameSuffix}
|
>${nameSuffix}
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
private repositionDropdown() {
|
|
||||||
const { x, y } = this.dropdownTrigger.getBoundingClientRect();
|
|
||||||
this.dropdown.style.left = `${x + window.scrollX}px`;
|
|
||||||
this.dropdown.style.top = `${y + window.scrollY - 8}px`;
|
|
||||||
}
|
|
||||||
|
|
||||||
private openDropdown() {
|
|
||||||
this.repositionDropdown();
|
|
||||||
this.dropdown.classList.add("animateShow");
|
|
||||||
this.dropdown.classList.remove("hidden");
|
|
||||||
}
|
|
||||||
|
|
||||||
private closeDropdown() {
|
|
||||||
this.dropdown.classList.add("animateHide");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@localized()
|
@localized()
|
||||||
|
Loading…
Reference in New Issue
Block a user