web: app icons v2 (#6410)
* fix more icons stuff Signed-off-by: Jens Langhammer <jens@goauthentik.io> * refactor app icon into separate component Signed-off-by: Jens Langhammer <jens@goauthentik.io> * update locale Signed-off-by: Jens Langhammer <jens@goauthentik.io> * make app icon work correctly in admin list and app view page Signed-off-by: Jens Langhammer <jens@goauthentik.io> --------- Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
		
							
								
								
									
										80
									
								
								web/src/user/LibraryApplication/AppIcon.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								web/src/user/LibraryApplication/AppIcon.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,80 @@
 | 
			
		||||
import { AKElement } from "@goauthentik/app/elements/Base";
 | 
			
		||||
import { PFSize } from "@goauthentik/app/elements/Spinner";
 | 
			
		||||
 | 
			
		||||
import { msg } from "@lit/localize";
 | 
			
		||||
import { CSSResult, TemplateResult, css, html } from "lit";
 | 
			
		||||
import { customElement, property } from "lit/decorators.js";
 | 
			
		||||
import { ifDefined } from "lit/directives/if-defined.js";
 | 
			
		||||
 | 
			
		||||
import PFFAIcons from "@patternfly/patternfly/base/patternfly-fa-icons.css";
 | 
			
		||||
import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css";
 | 
			
		||||
 | 
			
		||||
import { Application } from "@goauthentik/api";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-app-icon")
 | 
			
		||||
export class AppIcon extends AKElement {
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    app?: Application;
 | 
			
		||||
 | 
			
		||||
    @property()
 | 
			
		||||
    size: PFSize = PFSize.Large;
 | 
			
		||||
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
        return [
 | 
			
		||||
            PFFAIcons,
 | 
			
		||||
            PFAvatar,
 | 
			
		||||
            css`
 | 
			
		||||
                :host([size="pf-m-lg"]) {
 | 
			
		||||
                    --icon-height: 4rem;
 | 
			
		||||
                    --icon-border: 0.25rem;
 | 
			
		||||
                }
 | 
			
		||||
                :host([size="pf-m-md"]) {
 | 
			
		||||
                    --icon-height: 2rem;
 | 
			
		||||
                    --icon-border: 0.125rem;
 | 
			
		||||
                }
 | 
			
		||||
                :host([size="pf-m-sm"]) {
 | 
			
		||||
                    --icon-height: 1rem;
 | 
			
		||||
                    --icon-border: 0.125rem;
 | 
			
		||||
                }
 | 
			
		||||
                .pf-c-avatar {
 | 
			
		||||
                    --pf-c-avatar--BorderRadius: 0;
 | 
			
		||||
                    --pf-c-avatar--Height: calc(
 | 
			
		||||
                        var(--icon-height) + var(--icon-border) + var(--icon-border)
 | 
			
		||||
                    );
 | 
			
		||||
                    --pf-c-avatar--Width: calc(
 | 
			
		||||
                        var(--icon-height) + var(--icon-border) + var(--icon-border)
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
                .icon {
 | 
			
		||||
                    font-size: var(--icon-height);
 | 
			
		||||
                    color: var(--ak-global--Color--100);
 | 
			
		||||
                    padding: var(--icon-border);
 | 
			
		||||
                    max-height: calc(var(--icon-height) + var(--icon-border) + var(--icon-border));
 | 
			
		||||
                    line-height: calc(var(--icon-height) + var(--icon-border) + var(--icon-border));
 | 
			
		||||
                    filter: drop-shadow(5px 5px 5px rgba(128, 128, 128, 0.25));
 | 
			
		||||
                }
 | 
			
		||||
                div {
 | 
			
		||||
                    height: calc(var(--icon-height) + var(--icon-border) + var(--icon-border));
 | 
			
		||||
                }
 | 
			
		||||
            `,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        if (!this.app) {
 | 
			
		||||
            return html`<div><i class="icon fas fa-question-circle"></i></div>`;
 | 
			
		||||
        }
 | 
			
		||||
        if (this.app?.metaIcon) {
 | 
			
		||||
            if (this.app.metaIcon.startsWith("fa://")) {
 | 
			
		||||
                const icon = this.app.metaIcon.replaceAll("fa://", "");
 | 
			
		||||
                return html`<div><i class="icon fas ${icon}"></i></div>`;
 | 
			
		||||
            }
 | 
			
		||||
            return html`<img
 | 
			
		||||
                class="icon pf-c-avatar"
 | 
			
		||||
                src="${ifDefined(this.app.metaIcon)}"
 | 
			
		||||
                alt="${msg("Application Icon")}"
 | 
			
		||||
            />`;
 | 
			
		||||
        }
 | 
			
		||||
        return html`<span class="icon">${this.app?.name.charAt(0).toUpperCase()}</span>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										109
									
								
								web/src/user/LibraryApplication/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								web/src/user/LibraryApplication/index.ts
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,109 @@
 | 
			
		||||
import { truncateWords } from "@goauthentik/common/utils";
 | 
			
		||||
import { AKElement, rootInterface } from "@goauthentik/elements/Base";
 | 
			
		||||
import "@goauthentik/elements/Expand";
 | 
			
		||||
import "@goauthentik/user/LibraryApplication/AppIcon";
 | 
			
		||||
import { UserInterface } from "@goauthentik/user/UserInterface";
 | 
			
		||||
 | 
			
		||||
import { msg } from "@lit/localize";
 | 
			
		||||
import { CSSResult, TemplateResult, css, html } from "lit";
 | 
			
		||||
import { customElement, property } from "lit/decorators.js";
 | 
			
		||||
import { ifDefined } from "lit/directives/if-defined.js";
 | 
			
		||||
 | 
			
		||||
import PFButton from "@patternfly/patternfly/components/Button/button.css";
 | 
			
		||||
import PFCard from "@patternfly/patternfly/components/Card/card.css";
 | 
			
		||||
import PFBase from "@patternfly/patternfly/patternfly-base.css";
 | 
			
		||||
 | 
			
		||||
import { Application } from "@goauthentik/api";
 | 
			
		||||
 | 
			
		||||
@customElement("ak-library-app")
 | 
			
		||||
export class LibraryApplication extends AKElement {
 | 
			
		||||
    @property({ attribute: false })
 | 
			
		||||
    application?: Application;
 | 
			
		||||
 | 
			
		||||
    @property({ type: Boolean })
 | 
			
		||||
    selected = false;
 | 
			
		||||
 | 
			
		||||
    @property()
 | 
			
		||||
    background = "";
 | 
			
		||||
 | 
			
		||||
    static get styles(): CSSResult[] {
 | 
			
		||||
        return [
 | 
			
		||||
            PFBase,
 | 
			
		||||
            PFCard,
 | 
			
		||||
            PFButton,
 | 
			
		||||
            css`
 | 
			
		||||
                .pf-c-card {
 | 
			
		||||
                    --pf-c-card--BoxShadow: var(--pf-global--BoxShadow--md);
 | 
			
		||||
                }
 | 
			
		||||
                .pf-c-card__header {
 | 
			
		||||
                    justify-content: space-between;
 | 
			
		||||
                    flex-direction: column;
 | 
			
		||||
                }
 | 
			
		||||
                .pf-c-card__header a {
 | 
			
		||||
                    display: flex;
 | 
			
		||||
                    flex-direction: column;
 | 
			
		||||
                    justify-content: center;
 | 
			
		||||
                }
 | 
			
		||||
                a:hover {
 | 
			
		||||
                    text-decoration: none;
 | 
			
		||||
                }
 | 
			
		||||
                .expander {
 | 
			
		||||
                    flex-grow: 1;
 | 
			
		||||
                }
 | 
			
		||||
                .pf-c-card__title {
 | 
			
		||||
                    text-align: center;
 | 
			
		||||
                    /* This is not ideal as it hard limits us to 2 lines of text for the title
 | 
			
		||||
                    of the application. In theory that should be fine for most cases, but ideally
 | 
			
		||||
                    we don't do this */
 | 
			
		||||
                    height: 48px;
 | 
			
		||||
                }
 | 
			
		||||
            `,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    render(): TemplateResult {
 | 
			
		||||
        if (!this.application) {
 | 
			
		||||
            return html`<ak-spinner></ak-spinner>`;
 | 
			
		||||
        }
 | 
			
		||||
        const me = rootInterface<UserInterface>()?.me;
 | 
			
		||||
        return html` <div
 | 
			
		||||
            class="pf-c-card pf-m-hoverable pf-m-compact ${this.selected
 | 
			
		||||
                ? "pf-m-selectable pf-m-selected"
 | 
			
		||||
                : ""}"
 | 
			
		||||
            style=${this.background !== "" ? `background: ${this.background} !important` : ""}
 | 
			
		||||
        >
 | 
			
		||||
            <div class="pf-c-card__header">
 | 
			
		||||
                <a
 | 
			
		||||
                    href="${ifDefined(this.application.launchUrl ?? "")}"
 | 
			
		||||
                    target="${ifDefined(this.application.openInNewTab ? "_blank" : undefined)}"
 | 
			
		||||
                >
 | 
			
		||||
                    <ak-app-icon .app=${this.application}></ak-app-icon>
 | 
			
		||||
                </a>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="pf-c-card__title">
 | 
			
		||||
                <a
 | 
			
		||||
                    href="${ifDefined(this.application.launchUrl ?? "")}"
 | 
			
		||||
                    target="${ifDefined(this.application.openInNewTab ? "_blank" : undefined)}"
 | 
			
		||||
                    >${this.application.name}</a
 | 
			
		||||
                >
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="expander"></div>
 | 
			
		||||
            <ak-expand textOpen=${msg("Less details")} textClosed=${msg("More details")}>
 | 
			
		||||
                <div class="pf-c-content">
 | 
			
		||||
                    <small>${this.application.metaPublisher}</small>
 | 
			
		||||
                </div>
 | 
			
		||||
                ${truncateWords(this.application.metaDescription || "", 10)}
 | 
			
		||||
                ${rootInterface()?.uiConfig?.enabledFeatures.applicationEdit && me?.user.isSuperuser
 | 
			
		||||
                    ? html`
 | 
			
		||||
                          <a
 | 
			
		||||
                              class="pf-c-button pf-m-control pf-m-small pf-m-block"
 | 
			
		||||
                              href="/if/admin/#/core/applications/${this.application?.slug}"
 | 
			
		||||
                          >
 | 
			
		||||
                              <i class="fas fa-pencil-alt"></i> ${msg("Edit")}
 | 
			
		||||
                          </a>
 | 
			
		||||
                      `
 | 
			
		||||
                    : html``}
 | 
			
		||||
            </ak-expand>
 | 
			
		||||
        </div>`;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user