Compare commits

...

10 Commits

Author SHA1 Message Date
Teffen Ellis
6047c63e6f web: Fix missing monospace font. 2025-10-08 00:05:10 +02:00
Teffen Ellis
af35192e1f web: Fix roles, labels, e2e test selecting incorrect group. 2025-10-08 00:04:27 +02:00
Teffen Ellis
85138c11d9 web: Fix search color inheritance. 2025-10-07 23:57:22 +02:00
Teffen Ellis
e5d2f08746 web: Fix labels, colors. 2025-10-07 23:54:52 +02:00
Teffen Ellis
5c12a44462 web: Fix labels. 2025-10-07 23:54:37 +02:00
Teffen Ellis
5307617b61 web: Fix selection disrupting click event. 2025-10-07 23:54:10 +02:00
Teffen Ellis
a24ffecba0 web: Fix colors. 2025-10-07 23:53:45 +02:00
Teffen Ellis
383a3bad38 web: Tidy classes. Add part selectors. 2025-10-07 21:53:48 +02:00
Teffen Ellis
47f6631c30 web: Clean up contrast. 2025-10-07 21:53:48 +02:00
Teffen Ellis
d7b801598a web: Flesh out minimal mobile layout. 2025-10-07 21:53:48 +02:00
15 changed files with 257 additions and 149 deletions

View File

@@ -1,10 +1,16 @@
import { Config, ConfigFromJSON, CurrentBrand, CurrentBrandFromJSON } from "@goauthentik/api";
import {
Config,
ConfigFromJSON,
CurrentBrand,
CurrentBrandFromJSON,
FlowLayoutEnum,
} from "@goauthentik/api";
export interface GlobalAuthentik {
_converted?: boolean;
locale?: string;
flow?: {
layout: string;
layout: FlowLayoutEnum;
};
config: Config;
brand: CurrentBrand;

View File

@@ -21,6 +21,9 @@
--ak-dark-background-light-ish: #212427;
--ak-dark-background-lighter: #2b2e33;
--ak-flow-background-color-contrast: var(--pf-global--Color--100);
--ak-flow-footer-color: var(--pf-global--Color--light-100);
/* PatternFly likes to override global variables for some reason */
--ak-global--Color--100: var(--pf-global--Color--100);
@@ -311,27 +314,38 @@ ak-tabs[vertical] {
display: block;
position: relative;
width: 100%;
flex: 1 1 auto;
place-content: center;
}
@media (max-width: 1199px) {
.pf-c-login__container {
display: flex;
flex-direction: column;
}
}
.ak-login-container {
height: calc(100vh - var(--pf-global--spacer--lg) - var(--pf-global--spacer--lg));
width: 35rem;
max-width: 35rem;
width: 100%;
display: flex;
flex-direction: column;
justify-content: space-between;
}
.pf-c-login__header {
flex-grow: 1;
}
.pf-c-login__footer {
flex-grow: 2;
color: var(--ak-flow-footer-color);
flex: 0 0 auto;
display: flex;
justify-content: end;
flex-direction: column;
}
@media (max-width: 768px) {
:root {
--ak-flow-footer-color: var(--ak-flow-background-color-contrast);
}
}
.pf-c-login__footer ul.pf-c-list.pf-m-inline {
justify-content: center;
padding: 2rem 0;
@@ -539,11 +553,16 @@ fieldset {
}
@media (min-height: 60rem) {
.pf-c-login.stacked .pf-c-login__main {
.pf-c-login[data-layout="stacked"] .pf-c-login__main {
margin-top: 13rem;
}
}
.pf-c-login[data-layout="sidebar_left"],
.pf-c-login[data-layout="sidebar_right"] {
--ak-flow-footer-color: var(--ak-flow-background-color-contrast);
}
.pf-c-data-list {
padding-inline-start: 0;
}

View File

@@ -394,11 +394,13 @@ select.pf-c-form-control {
}
.pf-c-notification-drawer {
--pf-c-notification-drawer--BackgroundColor: var(--ak-dark-background);
--pf-c-notification-drawer--BackgroundColor: var(--ak-dark-background) !important;
--pf-c-notification-drawer__header--BackgroundColor: var(
--ak-dark-background-lighter
) !important;
}
.pf-c-notification-drawer__header {
background-color: var(--ak-dark-background-lighter);
color: var(--ak-dark-foreground);
}

View File

@@ -66,8 +66,13 @@ export class AppIcon extends AKElement implements IAppIcon {
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));
filter: drop-shadow(hsl(0deg 0% 85%) 5px 5px 5px);
}
:host([theme="dark"]) .icon {
filter: drop-shadow(hsl(0deg 0% 11%) 5px 5px 4px);
}
div {
height: calc(var(--icon-height) + var(--icon-border) + var(--icon-border));
}
@@ -77,14 +82,14 @@ export class AppIcon extends AKElement implements IAppIcon {
render(): TemplateResult {
// prettier-ignore
return match([this.name, this.icon])
.with([undefined, undefined],
() => html`<div><i class="icon fas fa-question-circle" aria-hidden="true"></i></div>`)
.with([P.nullish, P.nullish],
() => html`<div><i aria-hidden="true" class="icon fas fa-question-circle"></i></div>`)
.with([P._, P.string.startsWith("fa://")],
([_name, icon]) => html`<div><i class="icon fas ${icon.replaceAll("fa://", "")}"></i></div>`)
([_name, icon]) => html`<div><i aria-hidden="true" class="icon fas ${icon.replaceAll("fa://", "")}"></i></div>`)
.with([P._, P.string],
([_name, icon]) => html`<img class="icon pf-c-avatar" src="${icon}" alt="${msg("Application Icon")}" />`)
.with([P.string, undefined],
([name]) => html`<span class="icon">${name.charAt(0).toUpperCase()}</span>`)
([_name, icon]) => html`<img aria-hidden="true" class="icon pf-c-avatar" src="${icon}" alt="${msg("Application Icon")}" />`)
.with([P.string, P.nullish],
([name]) => html`<span aria-hidden="true" class="icon">${name.charAt(0).toUpperCase()}</span>`)
.exhaustive();
}
}

View File

@@ -19,20 +19,24 @@ export interface IExpand {
@customElement("ak-expand")
export class Expand extends AKElement implements IExpand {
@property({ type: Boolean })
expanded = false;
public expanded = false;
@property({ type: String, attribute: "text-open" })
textOpen = msg("Show less");
public textOpen = msg("Show less");
@property({ type: String, attribute: "text-closed" })
textClosed = msg("Show more");
public textClosed = msg("Show more");
static styles = [
PFBase,
PFExpandableSection,
css`
.pf-c-expandable-section.pf-m-display-lg {
background-color: var(--pf-global--BackgroundColor--100);
.pf-c-expandable-section {
display: grid;
grid-template-columns: 1fr;
}
.pf-c-expandable-section__toggle {
user-select: none;
}
`,
];
@@ -46,7 +50,8 @@ export class Expand extends AKElement implements IExpand {
<button
type="button"
class="pf-c-expandable-section__toggle"
aria-expanded="${this.expanded}"
aria-expanded=${this.expanded ? "true" : "false"}
aria-controls="expandable-content"
@click=${() => {
this.expanded = !this.expanded;
}}
@@ -58,7 +63,11 @@ export class Expand extends AKElement implements IExpand {
>${this.expanded ? this.textOpen : this.textClosed}</span
>
</button>
<div class="pf-c-expandable-section__content" ?hidden=${!this.expanded}>
<div
id="expandable-content"
class="pf-c-expandable-section__content"
?hidden=${!this.expanded}
>
<slot></slot>
</div>
</div>`;

View File

@@ -48,6 +48,15 @@ import PFLogin from "@patternfly/patternfly/components/Login/login.css";
import PFTitle from "@patternfly/patternfly/components/Title/title.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
const FlowLayoutClasses = {
[FlowLayoutEnum.ContentLeft]: "pf-c-login__container",
[FlowLayoutEnum.ContentRight]: "pf-c-login__container content-right",
[FlowLayoutEnum.SidebarLeft]: "ak-login-container",
[FlowLayoutEnum.SidebarRight]: "ak-login-container",
[FlowLayoutEnum.Stacked]: "ak-login-container",
[FlowLayoutEnum.UnknownDefaultOpenApi]: "ak-login-container",
} as const satisfies Record<FlowLayoutEnum, string>;
@customElement("ak-flow-executor")
export class FlowExecutor
extends WithCapabilitiesConfig(WithBrandConfig(Interface))
@@ -73,7 +82,12 @@ export class FlowExecutor
--pf-c-background-image--BackgroundImage--sm: var(--ak-flow-background);
--pf-c-background-image--BackgroundImage--sm-2x: var(--ak-flow-background);
--pf-c-background-image--BackgroundImage--lg: var(--ak-flow-background);
@media (max-width: 768px) {
background: var(--pf-c-login__main--BackgroundColor) !important;
}
}
.ak-hidden {
display: none;
}
@@ -85,7 +99,7 @@ export class FlowExecutor
}
/* layouts */
@media (min-height: 60rem) {
.pf-c-login.stacked .pf-c-login__main {
.pf-c-login[data-layout="stacked"] .pf-c-login__main {
margin-top: 13rem;
}
}
@@ -95,33 +109,34 @@ export class FlowExecutor
"footer main"
". main";
}
.pf-c-login.sidebar_left {
.pf-c-login[data-layout="sidebar_left"] {
justify-content: flex-start;
padding-top: 0;
padding-bottom: 0;
}
.pf-c-login.sidebar_left .ak-login-container,
.pf-c-login.sidebar_right .ak-login-container {
height: 100vh;
.pf-c-login[data-layout="sidebar_left"] .ak-login-container,
.pf-c-login[data-layout="sidebar_right"] .ak-login-container {
height: 100%;
min-height: 100dvh;
background-color: var(--pf-c-login__main--BackgroundColor);
padding-left: var(--pf-global--spacer--lg);
padding-right: var(--pf-global--spacer--lg);
padding-inline: var(--pf-global--spacer--lg);
padding-block-end: var(--pf-global--spacer--xs);
}
.pf-c-login.sidebar_left .pf-c-list,
.pf-c-login.sidebar_right .pf-c-list {
.pf-c-login[data-layout="sidebar_left"] .pf-c-list,
.pf-c-login[data-layout="sidebar_right"] .pf-c-list {
color: #000;
}
.pf-c-login.sidebar_right {
.pf-c-login[data-layout="sidebar_right"] {
justify-content: flex-end;
padding-top: 0;
padding-bottom: 0;
}
:host([theme="dark"]) .pf-c-login.sidebar_left .ak-login-container,
:host([theme="dark"]) .pf-c-login.sidebar_right .ak-login-container {
:host([theme="dark"]) .pf-c-login[data-layout="sidebar_left"] .ak-login-container,
:host([theme="dark"]) .pf-c-login[data-layout="sidebar_right"] .ak-login-container {
background-color: var(--ak-dark-background);
}
:host([theme="dark"]) .pf-c-login.sidebar_left .pf-c-list,
:host([theme="dark"]) .pf-c-login.sidebar_right .pf-c-list {
:host([theme="dark"]) .pf-c-login[data-layout="sidebar_left"] .pf-c-list,
:host([theme="dark"]) .pf-c-login[data-layout="sidebar_right"] .pf-c-list {
color: var(--ak-dark-foreground);
}
.pf-c-brand {
@@ -352,26 +367,10 @@ export class FlowExecutor
//#region Render
getLayout(): string {
const prefilledFlow = globalAK()?.flow?.layout || FlowLayoutEnum.Stacked;
if (this.challenge) {
return this.challenge?.flowInfo?.layout || prefilledFlow;
}
return prefilledFlow;
}
getLayoutClass(): string {
const layout = this.getLayout();
switch (layout) {
case FlowLayoutEnum.ContentLeft:
return "pf-c-login__container";
case FlowLayoutEnum.ContentRight:
return "pf-c-login__container content-right";
case FlowLayoutEnum.Stacked:
default:
return "ak-login-container";
}
get layout(): FlowLayoutEnum {
return (
this.challenge?.flowInfo?.layout || globalAK()?.flow?.layout || FlowLayoutEnum.Stacked
);
}
async renderChallenge(): Promise<TemplateResult> {
@@ -548,6 +547,7 @@ export class FlowExecutor
return import("#flow/FlowInspector").then(
() =>
html`<ak-flow-inspector
id="flow-inspector"
class="pf-c-drawer__panel pf-m-width-33"
.flowSlug=${this.flowSlug}
></ak-flow-inspector>`,
@@ -555,18 +555,24 @@ export class FlowExecutor
}
render(): TemplateResult {
return html` <ak-locale-context>
<div class="pf-c-background-image"></div>
<div class="pf-c-page__drawer">
<div class="pf-c-drawer ${this.inspectorOpen ? "pf-m-expanded" : "pf-m-collapsed"}">
<div class="pf-c-drawer__main">
<div class="pf-c-drawer__content">
<div class="pf-c-drawer__body">
<div class="pf-c-login ${this.getLayout()}">
<div class="${this.getLayoutClass()}">
const { layout } = this;
return html`<ak-locale-context>
<div class="pf-c-background-image" part="background-image"></div>
<div class="pf-c-page__drawer" part="page-drawer">
<div
class="pf-c-drawer ${this.inspectorOpen ? "pf-m-expanded" : "pf-m-collapsed"}"
part="drawer"
>
<div class="pf-c-drawer__main" part="drawer-main">
<div class="pf-c-drawer__content" part="drawer-content">
<div class="pf-c-drawer__body" part="drawer-body">
<div class="pf-c-login" data-layout=${layout} part="flow">
<div class=${FlowLayoutClasses[layout]} part="flow-container">
<main
class="pf-c-login__main"
aria-label=${msg("Authentication form")}
part="flow-main"
>
${this.loading && this.challenge
? html`<ak-loading-overlay></ak-loading-overlay>`
@@ -583,6 +589,7 @@ export class FlowExecutor
${until(this.renderChallenge())}
</main>
<ak-brand-links
part="brand-links"
role="contentinfo"
aria-label=${msg("Site footer")}
class="pf-c-login__footer"
@@ -595,10 +602,11 @@ export class FlowExecutor
${this.inspectorAvailable && !this.inspectorOpen
? html`<button
aria-label=${this.inspectorOpen
? msg("Close inspector")
: msg("Open inspector")}
? msg("Close flow inspector")
: msg("Open flow inspector")}
aria-expanded=${this.inspectorOpen ? "true" : "false"}
class="inspector-toggle pf-c-button pf-m-primary"
aria-controls="flow-inspector"
@click=${() => {
this.inspectorOpen = true;
}}

View File

@@ -48,13 +48,17 @@ export class FlowInspector extends AKElement {
.pf-c-drawer__body {
height: 100dvh;
}
:host {
background-color: var(--pf-c-notification-drawer--BackgroundColor) !important;
}
.pf-c-notification-drawer__body {
/* compatibility-mode-fix */
& {
padding-inline: var(--pf-global--spacer--md);
padding-block: var(--pf-global--spacer--xs);
}
.pf-l-stack__item:last-child {
padding-block-end: var(--pf-global--spacer--md);
}

View File

@@ -25,6 +25,7 @@ export class FormStatic extends AKElement {
display: flex;
align-items: center;
justify-content: space-between;
flex-flow: wrap;
gap: var(--pf-global--spacer--sm);
}

View File

@@ -45,6 +45,12 @@ export class FlowCard extends AKElement {
padding: 0;
margin-top: 1em;
}
.pf-c-login__main-body {
--pf-c-login__main-body--md--PaddingLeft: var(--pf-global--spacer--md);
--pf-c-login__main-body--md--PaddingRight: var(--pf-global--spacer--md);
}
.pf-c-login__main-body:last-child {
padding-bottom: calc(var(--pf-c-login__main-header--PaddingTop) * 1.2);
}

View File

@@ -110,7 +110,7 @@ export class AuthenticatorEmailStage extends BaseStage<
placeholder="${msg("Please enter the code you received via email")}"
autofocus=""
autocomplete="one-time-code"
class="pf-c-form-control"
class="pf-c-form-control pf-m-monospace"
required
/>
${AKFormErrors({ errors: this.challenge.responseErrors?.code })}

View File

@@ -108,7 +108,7 @@ export class AuthenticatorSMSStage extends BaseStage<
placeholder="${msg("Please enter the code you received via SMS")}"
autofocus=""
autocomplete="one-time-code"
class="pf-c-form-control"
class="pf-c-form-control pf-m-monospace"
required
/>
${AKFormErrors({ errors: this.challenge.responseErrors?.code })}

View File

@@ -51,7 +51,7 @@ export class AuthenticatorValidateStageWebCode extends BaseDeviceStage<
autofocus
spellcheck="false"
autocomplete="one-time-code"
class="pf-c-form-control"
class="pf-c-form-control pf-m-monospace"
value="${PasswordManagerPrefill.totp || ""}"
required
/>

View File

@@ -16,7 +16,9 @@ import type { RACLaunchEndpointModal } from "#user/LibraryApplication/RACLaunchE
import { Application } from "@goauthentik/api";
import { msg } from "@lit/localize";
import { kebabCase } from "change-case";
import { msg, str } from "@lit/localize";
import { css, CSSResult, html, nothing, TemplateResult } from "lit";
import { customElement, property, query } from "lit/decorators.js";
import { classMap } from "lit/directives/class-map.js";
@@ -52,39 +54,53 @@ export class LibraryApplication extends AKElement {
justify-content: space-between;
flex-direction: column;
}
.pf-c-card__header a {
.launch-wrapper {
display: flex;
flex-direction: column;
justify-content: center;
}
a:hover {
text-decoration: none;
&: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;
display: box;
display: -webkit-box;
line-clamp: 2;
-webkit-line-clamp: 2;
box-orient: vertical;
-webkit-box-orient: vertical;
overflow: hidden;
}
`,
];
#openRACLaunchModal = () => {
this.racEndpointLaunch?.show();
};
renderExpansion(application: Application) {
const { me, uiConfig } = rootInterface<UserInterface>();
return html`<ak-expand textOpen=${msg("Fewer details")} textClosed=${msg("More details")}>
<div class="pf-c-content">
return html`<ak-expand text-open=${msg("Details")} text-closed=${msg("Details")}>
<div class="pf-c-content" part="card-expansion">
<small>${application.metaPublisher}</small>
</div>
${truncateWords(application.metaDescription || "", 10)}
<div id="app-description" part="card-description">
${truncateWords(application.metaDescription || "", 10)}
</div>
${uiConfig?.enabledFeatures.applicationEdit && me?.user.isSuperuser
? html`
<a
class="pf-c-button pf-m-control pf-m-small pf-m-block"
aria-label=${msg(str`Edit "${application.name}"`)}
href="${globalAK().api
.base}if/admin/#/core/applications/${application?.slug}"
>
@@ -99,51 +115,55 @@ export class LibraryApplication extends AKElement {
if (!this.application) {
return nothing;
}
if (this.application?.launchUrl === "goauthentik.io://providers/rac/launch") {
return html`<div class="pf-c-card__header">
<a
@click=${() => {
this.racEndpointLaunch?.show();
}}
>
<ak-app-icon
size=${PFSize.Large}
name=${this.application.name}
icon=${ifPresent(this.application.metaIcon)}
></ak-app-icon>
</a>
</div>
<div class="pf-c-card__title">
<a
@click=${() => {
this.racEndpointLaunch?.show();
}}
>
${this.application.name}
</a>
</div>
<ak-library-rac-endpoint-launch .app=${this.application}>
</ak-library-rac-endpoint-launch>`;
}
return html`<div class="pf-c-card__header">
<a
href="${ifPresent(this.application.launchUrl ?? "")}"
target="${ifPresent(this.application.openInNewTab, "_blank")}"
if (this.application.launchUrl === "goauthentik.io://providers/rac/launch") {
return html`<div
part="card-header"
class="pf-c-card__header pf-m-pressable"
role="button"
aria-label=${msg(
str`Open Remote Access Control launcher for "${this.application.name}"`,
)}
@click=${this.#openRACLaunchModal}
>
<ak-app-icon
part="card-header-icon"
size=${PFSize.Large}
name=${this.application.name}
icon=${ifPresent(this.application.metaIcon)}
></ak-app-icon>
</a>
</div>
<div class="pf-c-card__title">
<a
href="${ifPresent(this.application.launchUrl ?? "")}"
target="${ifPresent(this.application.openInNewTab, "_blank")}"
>${this.application.name}</a
</div>
<div
@click=${this.#openRACLaunchModal}
id="app-title"
class="pf-c-card__title pf-m-pressable"
part="card-title"
>
</div>`;
${this.application.name}
</div>
<ak-library-rac-endpoint-launch .app=${this.application}>
</ak-library-rac-endpoint-launch>`;
}
return html`<a
class="launch-wrapper"
part="card-header-link"
aria-label=${msg(str`Open "${this.application.name}"`)}
href=${ifPresent(this.application.launchUrl)}
target=${ifPresent(this.application.openInNewTab, "_blank")}
>
<div class="pf-c-card__header" part="card-header">
<ak-app-icon
part="card-header-icon"
size=${PFSize.Large}
name=${this.application.name}
icon=${ifPresent(this.application.metaIcon)}
></ak-app-icon>
</div>
<div id="app-title" class="pf-c-card__title" part="card-title">
${this.application.name}
</div>
</a>`;
}
render(): TemplateResult {
@@ -158,11 +178,21 @@ export class LibraryApplication extends AKElement {
this.application.metaPublisher !== "" ||
this.application.metaDescription !== "";
const classes = { "pf-m-selectable": this.selected, "pf-m-selected": this.selected };
const classes = {
"pf-m-selectable": this.selected,
"pf-m-selected": this.selected,
};
const styles = this.background ? { background: this.background } : {};
return html` <div
const applicationName = kebabCase(this.application.name);
return html`<div
role="gridcell"
class="pf-c-card pf-m-hoverable pf-m-compact ${classMap(classes)}"
style=${styleMap(styles)}
data-application-name=${ifPresent(applicationName)}
aria-labelledby="app-title"
aria-describedby="app-description"
>
${this.renderLaunch()}
<div class="expander"></div>

View File

@@ -1,4 +1,4 @@
import type { AppGroupEntry, AppGroupList } from "./types.js";
import type { AppGroupList } from "./types.js";
import { LayoutType } from "#common/ui/config";
@@ -6,6 +6,7 @@ import { AKElement } from "#elements/Base";
import type { Application } from "@goauthentik/api";
import { msg } from "@lit/localize";
import { css, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
@@ -78,11 +79,19 @@ export class LibraryPageApplicationList extends AKElement {
render() {
const [groupClass, groupGrid] = this.currentLayout;
return html`<div class="pf-l-grid pf-m-gutter">
${this.apps.map(([group, apps]: AppGroupEntry) => {
return html`<div class="pf-l-grid__item ${groupClass}">
return html`<div
class="pf-l-grid pf-m-gutter"
role="grid"
aria-label=${msg("Available applications")}
>
${this.apps.map(([group, apps], idx) => {
return html`<div
class="pf-l-grid__item ${groupClass}"
role="rowgroup"
aria-labelledby="app-group-${idx}"
>
<div class="pf-c-content app-group-header">
<h2>${group}</h2>
<h2 id="app-group-${idx}">${group}</h2>
</div>
<div class="pf-l-grid pf-m-gutter ${groupGrid}">
${apps.map((app: Application) => {

View File

@@ -17,6 +17,7 @@ import { css, html } from "lit";
import { customElement, property, query } from "lit/decorators.js";
import { ifDefined } from "lit/directives/if-defined.js";
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
import PFBase from "@patternfly/patternfly/patternfly-base.css";
import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";
@@ -40,21 +41,28 @@ export class LibraryPageApplicationSearch extends AKElement {
static styles = [
PFBase,
PFDisplay,
PFFormControl,
css`
input {
width: 30ch;
box-sizing: border-box;
border: 0;
border-bottom: 1px solid;
border-bottom-color: var(--ak-accent);
input[name="application-search"] {
background-color: transparent;
width: 30ch;
font-size: 1.5rem;
border-inline: none;
border-block-start: none;
&:focus,
&:hover {
--pf-c-form-control--BorderBottomColor: var(--ak-accent);
}
}
input:focus {
outline: 0;
}
:host([theme="dark"]) input {
color: var(--ak-dark-foreground) !important;
`,
// HACK: Fixes Lit Analyzer's outdated parser.
(css as typeof css) /*css*/ `
input[name="application-search"] {
@media not (prefers-contrast: more) {
outline: none;
}
}
`,
];
@@ -151,13 +159,14 @@ export class LibraryPageApplicationSearch extends AKElement {
render() {
return html`<input
name="application-search"
@input=${this.onInput}
@keydown=${this.onKeyDown}
type="text"
class="pf-u-display-none pf-u-display-block-on-md"
type="search"
class="pf-c-form-control pf-u-display-none pf-u-display-block-on-md"
autofocus
aria-label=${msg("Search for an application by name")}
placeholder=${msg("Search...")}
aria-label=${msg("Application search")}
placeholder=${msg("Search for an application by name...")}
value=${ifDefined(this.query)}
/>`;
}