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:
Jens L
2023-07-28 14:25:56 +02:00
committed by GitHub
parent 5803c39e91
commit 782d95b4a3
17 changed files with 301 additions and 207 deletions

View 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>`;
}
}

View 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>&nbsp;${msg("Edit")}
</a>
`
: html``}
</ak-expand>
</div>`;
}
}