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

@ -1,5 +1,6 @@
import "@goauthentik/admin/applications/ApplicationForm";
import "@goauthentik/admin/applications/wizard/ApplicationWizard";
import { PFSize } from "@goauthentik/app/elements/Spinner";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { uiConfig } from "@goauthentik/common/ui/config";
import MDApplication from "@goauthentik/docs/core/applications.md";
@ -11,13 +12,12 @@ import { getURLParam } from "@goauthentik/elements/router/RouteMatch";
import { PaginatedResponse } from "@goauthentik/elements/table/Table";
import { TableColumn } from "@goauthentik/elements/table/Table";
import { TablePage } from "@goauthentik/elements/table/TablePage";
import "@goauthentik/user/LibraryApplication/AppIcon";
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 PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css";
import PFCard from "@patternfly/patternfly/components/Card/card.css";
import { Application, CoreApi } from "@goauthentik/api";
@ -56,13 +56,8 @@ export class ApplicationListPage extends TablePage<Application> {
static get styles(): CSSResult[] {
return super.styles.concat(
PFAvatar,
PFCard,
css`
:host {
--icon-height: 2rem;
--icon-border: 0.25rem;
}
/* Fix alignment issues with images in tables */
.pf-c-table tbody > tr > * {
vertical-align: middle;
@ -76,14 +71,6 @@ export class ApplicationListPage extends TablePage<Application> {
.pf-c-sidebar.pf-m-gutter > .pf-c-sidebar__main > * + * {
margin-left: calc(var(--pf-c-sidebar__main--child--MarginLeft) / 2);
}
.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));
}
`,
);
}
@ -137,24 +124,9 @@ export class ApplicationListPage extends TablePage<Application> {
</ak-forms-delete-bulk>`;
}
renderIcon(item: Application): TemplateResult {
if (item?.metaIcon) {
if (item.metaIcon.startsWith("fa://")) {
const icon = item.metaIcon.replaceAll("fa://", "");
return html`<i class="icon fas ${icon}"></i>`;
}
return html`<img
class="icon pf-c-avatar"
src="${ifDefined(item.metaIcon)}"
alt="${msg("Application Icon")}"
/>`;
}
return html`<span class="icon">${item?.name.charAt(0).toUpperCase()}</span>`;
}
row(item: Application): TemplateResult[] {
return [
this.renderIcon(item),
html`<ak-app-icon size=${PFSize.Medium} .app=${item}></ak-app-icon>`,
html`<a href="#/core/applications/${item.slug}">
<div>${item.name}</div>
${item.metaPublisher ? html`<small>${item.metaPublisher}</small>` : html``}

View File

@ -2,6 +2,7 @@ import "@goauthentik/admin/applications/ApplicationAuthorizeChart";
import "@goauthentik/admin/applications/ApplicationCheckAccessForm";
import "@goauthentik/admin/applications/ApplicationForm";
import "@goauthentik/admin/policies/BoundPoliciesList";
import { PFSize } from "@goauthentik/app/elements/Spinner";
import { DEFAULT_CONFIG } from "@goauthentik/common/api/config";
import { AKElement } from "@goauthentik/elements/Base";
import "@goauthentik/elements/EmptyState";
@ -9,6 +10,7 @@ import "@goauthentik/elements/PageHeader";
import "@goauthentik/elements/Tabs";
import "@goauthentik/elements/buttons/SpinnerButton";
import "@goauthentik/elements/events/ObjectChangelog";
import "@goauthentik/user/LibraryApplication/AppIcon";
import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit";
@ -80,11 +82,15 @@ export class ApplicationViewPage extends AKElement {
render(): TemplateResult {
return html`<ak-page-header
icon=${this.application?.metaIcon || ""}
header=${this.application?.name || msg("Loading")}
description=${ifDefined(this.application?.metaPublisher)}
.iconImage=${true}
>
<ak-app-icon
size=${PFSize.Small}
slot="icon"
.app=${this.application}
></ak-app-icon>
</ak-page-header>
${this.renderApp()}`;
}

View File

@ -1,7 +1,7 @@
import { AKElement } from "@goauthentik/elements/Base";
import { msg } from "@lit/localize";
import { CSSResult, TemplateResult, html } from "lit";
import { CSSResult, TemplateResult, css, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import PFExpandableSection from "@patternfly/patternfly/components/ExpandableSection/expandable-section.css";
@ -19,7 +19,15 @@ export class Expand extends AKElement {
textClosed = msg("Show more");
static get styles(): CSSResult[] {
return [PFBase, PFExpandableSection];
return [
PFBase,
PFExpandableSection,
css`
.pf-c-expandable-section.pf-m-display-lg {
background-color: var(--pf-global--BackgroundColor--100);
}
`,
];
}
render(): TemplateResult {

View File

@ -91,6 +91,11 @@ export class PageHeader extends AKElement {
.notification-trigger.has-notifications {
color: var(--pf-global--active-color--100);
}
h1 {
display: flex;
flex-direction: row;
align-items: center !important;
}
`,
];
}
@ -120,10 +125,10 @@ export class PageHeader extends AKElement {
renderIcon(): TemplateResult {
if (this.icon) {
if (this.iconImage && !this.icon.startsWith("fa://")) {
return html`<img class="pf-icon" src="${this.icon}" alt="page icon" />&nbsp;`;
return html`<img class="pf-icon" src="${this.icon}" alt="page icon" />`;
}
const icon = this.icon.replaceAll("fa://", "fa ");
return html`<i class=${icon}></i>&nbsp;`;
return html`<i class=${icon}></i>`;
}
return html``;
}
@ -147,8 +152,8 @@ export class PageHeader extends AKElement {
<section class="pf-c-page__main-section pf-m-light">
<div class="pf-c-content">
<h1>
${this.renderIcon()}
<slot name="header"> ${this.header} </slot>
<slot name="icon">${this.renderIcon()}</slot>&nbsp;
<slot name="header">${this.header}</slot>
</h1>
${this.description ? html`<p>${this.description}</p>` : html``}
</div>

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

@ -1,6 +1,7 @@
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";
@ -8,7 +9,6 @@ import { CSSResult, TemplateResult, css, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import PFAvatar from "@patternfly/patternfly/components/Avatar/avatar.css";
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";
@ -31,24 +31,10 @@ export class LibraryApplication extends AKElement {
PFBase,
PFCard,
PFButton,
PFAvatar,
css`
:host {
--icon-height: 4rem;
--icon-border: 0.25rem;
}
.pf-c-card {
--pf-c-card--BoxShadow: var(--pf-global--BoxShadow--md);
}
.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)
);
}
.pf-c-card__header {
justify-content: space-between;
flex-direction: column;
@ -58,13 +44,8 @@ export class LibraryApplication extends AKElement {
flex-direction: column;
justify-content: center;
}
.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));
a:hover {
text-decoration: none;
}
.expander {
flex-grow: 1;
@ -80,21 +61,6 @@ export class LibraryApplication extends AKElement {
];
}
renderIcon(): TemplateResult {
if (this.application?.metaIcon) {
if (this.application.metaIcon.startsWith("fa://")) {
const icon = this.application.metaIcon.replaceAll("fa://", "");
return html`<i class="icon fas ${icon}"></i>`;
}
return html`<img
class="icon pf-c-avatar"
src="${ifDefined(this.application.metaIcon)}"
alt="${msg("Application Icon")}"
/>`;
}
return html`<span class="icon">${this.application?.name.charAt(0).toUpperCase()}</span>`;
}
render(): TemplateResult {
if (!this.application) {
return html`<ak-spinner></ak-spinner>`;
@ -111,7 +77,7 @@ export class LibraryApplication extends AKElement {
href="${ifDefined(this.application.launchUrl ?? "")}"
target="${ifDefined(this.application.openInNewTab ? "_blank" : undefined)}"
>
${this.renderIcon()}
<ak-app-icon .app=${this.application}></ak-app-icon>
</a>
</div>
<div class="pf-c-card__title">