diff --git a/src/entrypoints/authorize.ts b/src/entrypoints/authorize.ts
index 68c9fe7c4674..541028b9d6ee 100644
--- a/src/entrypoints/authorize.ts
+++ b/src/entrypoints/authorize.ts
@@ -1,4 +1,4 @@
-import { mdiAlertCircle, mdiLock, mdiCheck } from "@mdi/js";
+import { mdiAlertCircle, mdiLock, mdiCheck, mdiEye, mdiEyeOff } from "@mdi/js";
import { toASCII } from "punycode";
import { LocalizeFunc, computeLocalize } from "../common/translations/localize";
import { extractSearchParamsObject } from "../common/url/search-params";
@@ -6,6 +6,7 @@ import type { AuthProvider } from "../data/auth";
import type { DataEntryFlowStep } from "../data/data_entry_flow";
import "../resources/roboto";
import { getLocalLanguage, getTranslation } from "../util/common-translation";
+import type { HaFormSchema } from "../components/ha-form/types";
let localize: LocalizeFunc = () => "";
let localizeLoaded = false;
@@ -26,6 +27,7 @@ const loadLocalize = async () => {
loadLocalize();
const content = document.getElementById("content")!;
+
const escape = (text: string) =>
text.replace(//g, ">");
const icon = (path: string, clazz: string) =>
@@ -33,6 +35,78 @@ const icon = (path: string, clazz: string) =>
const errorRow = (message: string) => `
${icon(mdiAlertCircle, "error")} ${message}
`;
+const makeInput = (
+ item: HaFormSchema,
+ name: string,
+ currentFormData: FormData | null
+) => {
+ if (item.type === "string") {
+ const attributes: Record = {
+ placeholder: name,
+ name: item.name,
+ type:
+ item.name === "password"
+ ? "password"
+ : item.name === "code"
+ ? "number"
+ : "text",
+ autocomplete:
+ item.name === "username"
+ ? "username"
+ : item.name === "password"
+ ? "current-password"
+ : item.name === "code"
+ ? "one-time-code"
+ : undefined,
+ required: item.required,
+ };
+ if (item.name === "username" && currentFormData) {
+ attributes.value = currentFormData.get("username") || undefined;
+ }
+ if (item.name === "username" || item.name === "password") {
+ attributes.autocapitalize = "off";
+ attributes.autocorrect = "off";
+ }
+ const attributesStr = Object.entries(attributes)
+ .filter(([_key, value]) => value)
+ .map(([key, value]) => `${key}="${value}"`)
+ .join(" ");
+
+ let output = ``;
+ if (item.name === "password") {
+ output += ``;
+ }
+ return `${output}
`;
+ } else if (item.type === "select") {
+ const options = item.options.map(
+ (o) => ``
+ );
+ return ``;
+ }
+ return undefined;
+};
+
+window["togglePassword"] = (
+ e: MouseEvent & { currentTarget: HTMLButtonElement }
+) => {
+ const input = e.currentTarget.parentElement!.firstChild as HTMLInputElement;
+ if (input.type === "password") {
+ input.type = "text";
+ e.currentTarget.innerHTML = icon(mdiEyeOff, "");
+ } else {
+ input.type = "password";
+ e.currentTarget.innerHTML = icon(mdiEye, "");
+ }
+};
const showError = (error: string) => {
content.innerHTML = `
${icon(mdiAlertCircle, "error")}
@@ -155,9 +229,6 @@ const intro = async () => {
let storeToken = true;
const updateContainer = () => {
- const currentForm = document.querySelector("form");
- const currentFormData = currentForm && new FormData(currentForm);
-
let contents = "";
if (mode.name === "app")
@@ -170,6 +241,8 @@ const intro = async () => {
})}`;
if (step?.type === "form") {
+ const currentForm = document.querySelector("form");
+ const currentFormData = currentForm && new FormData(currentForm);
if (step.errors?.base) {
const error = localize(
`ui.panel.page-authorize.form.providers.${authProvider.type}.error.${step.errors.base}`
@@ -180,49 +253,9 @@ const intro = async () => {
const name = localize(
`ui.panel.page-authorize.form.providers.${authProvider.type}.step.${step.step_id}.data.${item.name}`
);
- if (item.type === "string") {
- const attributes: Record = {
- placeholder: name,
- name: item.name,
- type:
- item.name === "password"
- ? "password"
- : item.name === "code"
- ? "number"
- : "text",
- autocomplete:
- item.name === "username"
- ? "username"
- : item.name === "password"
- ? "current-password"
- : item.name === "code"
- ? "one-time-code"
- : undefined,
- required: item.required,
- };
- if (item.name === "username") {
- if (currentFormData)
- attributes.value = currentFormData.get("username") || undefined;
- attributes.autocapitalize = "off";
- attributes.autocorrect = "off";
- }
- const attributesStr = Object.entries(attributes)
- .filter(([_key, value]) => value)
- .map(([key, value]) => `${key}="${value}"`)
- .join(" ");
- contents += ``;
- } else if (item.type === "select") {
- const options = item.options.map(
- (o) => ``
- );
- contents += ``;
- }
+ const result = makeInput(item, name, currentFormData);
+ console.log("adding", result);
+ if (result) contents += result;
}
if (
step.step_id !== "select_mfa_module" &&
diff --git a/src/html/authorize.html.template b/src/html/authorize.html.template
index 5a2454444bb3..27012581f1a7 100644
--- a/src/html/authorize.html.template
+++ b/src/html/authorize.html.template
@@ -83,6 +83,7 @@
}
input::placeholder {
color: inherit;
+ opacity: var(--text-opacity);
}
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
@@ -91,6 +92,10 @@
input[type=number] {
appearance: textfield;
}
+ input:focus-visible + .bar, select:focus-visible + .bar {
+ background-color: var(--primary-color);
+ height: 4px;
+ }
.bar {
position: absolute;
background-color: var(--bar-color);
@@ -100,13 +105,27 @@
pointer-events: none;
transition: all 200ms;
}
+ .input-wrapper > button {
+ position: absolute;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ opacity: var(--text-opacity);
+
+ width: 40px;
+ height: 40px;
+ top: 4px;
+ right: 4px;
+ padding: 0;
+ border-radius: 20px;
+ background-color: transparent;
+ }
+ .input-wrapper > button:hover {
+ background-color: inherit;
+ }
input:is([type=text], [type=number], [type=password]):focus-visible, select:focus-visible {
outline: none;
}
- input:focus-visible + .bar, select:focus-visible + .bar {
- background-color: var(--primary-color);
- height: 4px;
- }
label {
display: flex;
align-items: center;
@@ -129,6 +148,7 @@
left: 16px;
top: 6px;
font-size: 12px;
+ opacity: var(--text-opacity);
pointer-events: none;
}
@supports (moz-appearance: none) {
@@ -153,6 +173,8 @@
border: none;
cursor: pointer;
white-space: nowrap;
+ }
+ .buttons > button {
height: 40px;
border-radius: 20px;
}
@@ -199,9 +221,7 @@
.input-wrapper {
background-color: rgb(0, 0, 0, 0.08);
--bar-color: rgb(0, 0, 0, 0.4);
- }
- input::placeholder, .name {
- opacity: 0.8;
+ --text-opacity: 0.8;
}
@media (prefers-color-scheme: dark) {
html {
@@ -219,9 +239,7 @@
.input-wrapper {
background-color: rgb(255, 255, 255, 0.05);
--bar-color: rgb(255, 255, 255, 0.4);
- }
- input::placeholder, .name {
- opacity: 0.6;
+ --text-opacity: 0.6;
}
}