Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .Jules/palette.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
## 2026-06-10 - [Initial UX check]
**Learning:** Checking for standard UX loading states.
**Action:** Need to add loading state to buttons.
## 2026-06-10 - [Accessible Async Loading States]
**Learning:** Vanilla JS forms need explicit UI feedback during async operations, but standard DOM methods like `e.target.querySelector` can fail if the click intercepted by child elements.
**Action:** Used `e.submitter` to robustly capture the submitting button, allowing temporary text modification (`⏳ Logging in...`), `disabled` state, and `aria-busy` attribute implementation within a `try/finally` block to ensure robust cleanup without adding custom CSS.
26 changes: 26 additions & 0 deletions web-demo/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,13 @@ class ClimaAI {

async handleLogin(e) {
e.preventDefault();
const submitBtn = e.submitter;
if (submitBtn) {
submitBtn.disabled = true;
submitBtn.setAttribute('aria-busy', 'true');
submitBtn.dataset.originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '⏳ Logging in...';
}
const email = document.getElementById('loginEmail').value;
const password = document.getElementById('loginPassword').value;

Expand All @@ -155,11 +162,24 @@ class ClimaAI {
this.checkSubscription();
} catch (error) {
this.showToast(error.message || 'Login failed', 'error');
} finally {
if (submitBtn) {
submitBtn.disabled = false;
submitBtn.removeAttribute('aria-busy');
submitBtn.innerHTML = submitBtn.dataset.originalText || submitBtn.innerHTML;
}
}
}

async handleRegister(e) {
e.preventDefault();
const submitBtn = e.submitter;
if (submitBtn) {
submitBtn.disabled = true;
submitBtn.setAttribute('aria-busy', 'true');
submitBtn.dataset.originalText = submitBtn.innerHTML;
submitBtn.innerHTML = '⏳ Signing up...';
}
const name = document.getElementById('registerName').value;
const email = document.getElementById('registerEmail').value;
const password = document.getElementById('registerPassword').value;
Expand All @@ -174,6 +194,12 @@ class ClimaAI {
this.checkSubscription();
} catch (error) {
this.showToast(error.message || 'Registration failed', 'error');
} finally {
if (submitBtn) {
submitBtn.disabled = false;
submitBtn.removeAttribute('aria-busy');
submitBtn.innerHTML = submitBtn.dataset.originalText || submitBtn.innerHTML;
}
}
}

Expand Down