From 2e85f4bd16429f323b7fac635b70cf98b66c57a2 Mon Sep 17 00:00:00 2001
From: Christiaan Goossens
<9487666+christiaangoossens@users.noreply.github.com>
Date: Sun, 13 Jul 2025 19:50:48 +0200
Subject: [PATCH] Small UX touchups (#84)
* Small touchups
* Disable sso view on mobile
---
.../auth_oidc/static/injection.js | 66 +++++++++++++++----
1 file changed, 54 insertions(+), 12 deletions(-)
diff --git a/custom_components/auth_oidc/static/injection.js b/custom_components/auth_oidc/static/injection.js
index 27ce458..9612ae1 100644
--- a/custom_components/auth_oidc/static/injection.js
+++ b/custom_components/auth_oidc/static/injection.js
@@ -5,24 +5,26 @@ function safeSetTextContent(element, value) {
textNode.textContent = value
}
-const SSO_NAME = window.sso_name || "Single Sign-On"
-
let firstFocus = true
let showCodeOverride = null
-function showCode() {
- if (showCodeOverride !== null) return showCodeOverride
-
+function isMobile() {
const clientId = new URL(location.href).searchParams.get("client_id")
return clientId && clientId.startsWith("https://home-assistant.io/iOS") || clientId.startsWith("https://home-assistant.io/android")
}
+function showCode() {
+ if (showCodeOverride !== null) return showCodeOverride
+ return isMobile()
+}
+
let ssoButton = null
let codeMessage = null
let codeToggle = null
let codeToggleText = null
function update() {
+ const sso_name = window.sso_name || "Single Sign-On"
const loginHeader = document.querySelector(".card-content > ha-auth-flow > form > h1")
const authForm = document.querySelector("ha-auth-form")
const codeField = document.querySelector(".mdc-text-field__input[name=code]")
@@ -30,15 +32,17 @@ function update() {
const errorAlert = document.querySelector("ha-auth-form ha-alert[alert-type=error]")
const loginOptionList = document.querySelector("ha-pick-auth-provider")?.shadowRoot?.querySelector("mwc-list")
- safeSetTextContent(loginHeader, "Log in to Home Assistant")
-
+ // ====
+ // Code input
if (codeField) {
if (codeField.placeholder !== "One-time code") {
codeField.placeholder = "One-time code"
codeField.autofocus = false
codeField.autocomplete = "off"
+
if (firstFocus) {
firstFocus = false
+
if (document.activeElement === codeField) {
setTimeout(() => {
codeField.blur()
@@ -57,23 +61,30 @@ function update() {
}
}
}
+
if (errorAlert && errorAlert.textContent.trim().length === 0) {
errorAlert.setAttribute("title", "Invalid Code")
}
+
authForm.style.display = showCode() ? "" : "none"
loginButton.style.display = showCode() ? "" : "none"
}
if (authForm && !codeMessage) {
codeMessage = document.createElement("p")
- codeMessage.innerText = `Login to Home Assistant in a web browser and enter the code you are given here`
+ codeMessage.innerHTML = `Please login on a different device to continue.
You can also use your mobile webbrowser.`
authForm.parentElement.insertBefore(codeMessage, authForm)
}
+
if (codeMessage) {
codeMessage.style.display = showCode() ? "" : "none"
}
- if (loginOptionList && !codeToggle) {
+ safeSetTextContent(loginButton, codeField ? "Log in with code" : "Log in")
+
+ // ====
+ // Toggle button
+ if (loginOptionList && !codeToggle && !isMobile()) {
codeToggle = document.createElement("ha-list-item")
codeToggle.setAttribute("hasmeta", "")
codeToggleText = document.createTextNode("")
@@ -82,10 +93,21 @@ function update() {
codeToggleIcon.setAttribute("slot", "meta")
codeToggle.appendChild(codeToggleIcon)
+ let ranHandler = false;
codeToggle.addEventListener("click", () => {
+ ranHandler = true;
showCodeOverride = !showCode()
update()
})
+
+ loginOptionList.addEventListener("click", (ev) => {
+ if (!ranHandler) {
+ showCodeOverride = false;
+ codeMessage = null;
+ }
+ ranHandler = false;
+ })
+
loginOptionList.appendChild(codeToggle)
}
@@ -94,13 +116,19 @@ function update() {
}
if (codeToggleText) {
- codeToggleText.textContent = showCode() ? SSO_NAME : "Login Code"
+ codeToggleText.textContent = showCode() ? "Single-Sign On" : "One-time device code"
}
+ // ====
+ // SSO Page
+ const shouldShowSSOButton = !showCode() && !!codeField
+ const isOurScreen = showCode() || shouldShowSSOButton
+
if (loginButton && !ssoButton) {
ssoButton = document.createElement("mwc-button")
+ ssoButton.id = "sso_button"
ssoButton.classList.add("sso")
- ssoButton.innerText = "Log in with " + SSO_NAME
+ ssoButton.innerText = "Log in with " + sso_name
ssoButton.setAttribute("raised", "")
ssoButton.style.marginRight = "1em"
ssoButton.addEventListener("click", () => {
@@ -108,13 +136,25 @@ function update() {
})
loginButton.parentElement.prepend(ssoButton)
}
+
if (ssoButton) {
ssoButton.style.display = (!showCode() && codeField) ? "" : "none"
}
- safeSetTextContent(loginButton, codeField ? "Log in with code" : "Log in")
+ // ====
+ // Header hidden on our screens
+ if (loginHeader) {
+ if (isOurScreen) {
+ // Hide the header on our screens
+ loginHeader.style.display = "none"
+ } else {
+ // Show the header on the login screen
+ loginHeader.style.display = ""
+ }
+ }
}
+// Hide the content until ready
let ready = false
document.querySelector(".content").style.display = "none"
@@ -133,6 +173,8 @@ setTimeout(() => {
if (!ready) {
console.warn("hass-oidc-auth: Document was not ready after 300ms seconds, force displaying. This may indicate a problem with the UI injection.")
}
+
+ // Force display the content
document.querySelector(".content").style.display = "";
update();
}, 300)
\ No newline at end of file