From e297ff27efa536d25b834adb70df6724cee2386a Mon Sep 17 00:00:00 2001 From: Yury Kossakovsky Date: Fri, 12 Dec 2025 08:47:34 -0700 Subject: [PATCH] feat: improve welcome page ux and remove beta/stable switch commands - add click-to-toggle password visibility (replaces hold-to-reveal) - add copy button for username fields - add "keeping up to date" section with update commands - remove switch-beta/switch-stable from commands list and docs --- CLAUDE.md | 3 -- welcome/app.js | 95 +++++++++++++++++++++++++++++++++------------- welcome/index.html | 25 ++++++++++++ 3 files changed, 93 insertions(+), 30 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index 26f0553..d3b5e36 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -38,9 +38,6 @@ make logs s= # View logs for specific service make status # Show container status make monitor # Live CPU/memory monitoring make restarts # Show restart count per container - -make switch-beta # Switch to beta (develop branch) -make switch-stable # Switch to stable (main branch) ``` diff --git a/welcome/app.js b/welcome/app.js index e7a98da..1e2c98a 100644 --- a/welcome/app.js +++ b/welcome/app.js @@ -238,9 +238,7 @@ { cmd: 'make doctor', desc: 'Run system diagnostics' }, { cmd: 'make update', desc: 'Update system and services' }, { cmd: 'make update-preview', desc: 'Preview available updates' }, - { cmd: 'make clean', desc: 'Remove unused Docker resources' }, - { cmd: 'make switch-beta', desc: 'Switch to beta (develop branch)' }, - { cmd: 'make switch-stable', desc: 'Switch to stable (main branch)' } + { cmd: 'make clean', desc: 'Remove unused Docker resources' } ]; // DOM Elements @@ -251,6 +249,41 @@ const errorToast = document.getElementById('error-toast'); const errorMessage = document.getElementById('error-message'); + /** + * Create a copy button for any text + */ + function createCopyButton(textToCopy) { + const copyBtn = document.createElement('button'); + copyBtn.className = 'p-1.5 rounded-lg hover:bg-surface-400 transition-colors focus:outline-none focus:ring-2 focus:ring-brand/50'; + copyBtn.innerHTML = ` + + + + + `; + copyBtn.title = 'Copy to clipboard'; + + copyBtn.addEventListener('click', async () => { + try { + await navigator.clipboard.writeText(textToCopy); + const copyIcon = copyBtn.querySelector('.copy-icon'); + const checkIcon = copyBtn.querySelector('.check-icon'); + copyIcon.classList.add('hidden'); + checkIcon.classList.remove('hidden'); + setTimeout(() => { + copyIcon.classList.remove('hidden'); + checkIcon.classList.add('hidden'); + }, 2000); + } catch (err) { + console.error('Failed to copy:', err); + } + }); + + return copyBtn; + } + /** * Show error toast */ @@ -284,34 +317,34 @@ const toggleBtn = document.createElement('button'); toggleBtn.className = 'p-1.5 rounded-lg hover:bg-surface-400 transition-colors focus:outline-none focus:ring-2 focus:ring-brand/50'; toggleBtn.innerHTML = ` - + + `; - toggleBtn.title = 'Hold to reveal'; + toggleBtn.title = 'Toggle visibility'; - // Show password on mouse down, hide on mouse up/leave - const showPassword = () => { - passwordSpan.textContent = passwordSpan.dataset.password; - passwordSpan.dataset.hidden = 'false'; - }; - const hidePassword = () => { - passwordSpan.textContent = '*'.repeat(Math.min(password.length, 12)); - passwordSpan.dataset.hidden = 'true'; - }; + // Toggle password visibility on click + toggleBtn.addEventListener('click', () => { + const isHidden = passwordSpan.dataset.hidden === 'true'; + const eyeOpen = toggleBtn.querySelector('.eye-open'); + const eyeClosed = toggleBtn.querySelector('.eye-closed'); - toggleBtn.addEventListener('mousedown', (e) => { - e.preventDefault(); - showPassword(); + if (isHidden) { + passwordSpan.textContent = passwordSpan.dataset.password; + passwordSpan.dataset.hidden = 'false'; + eyeOpen.classList.add('hidden'); + eyeClosed.classList.remove('hidden'); + } else { + passwordSpan.textContent = '*'.repeat(Math.min(password.length, 12)); + passwordSpan.dataset.hidden = 'true'; + eyeOpen.classList.remove('hidden'); + eyeClosed.classList.add('hidden'); + } }); - toggleBtn.addEventListener('mouseup', hidePassword); - toggleBtn.addEventListener('mouseleave', hidePassword); - toggleBtn.addEventListener('touchstart', (e) => { - e.preventDefault(); - showPassword(); - }); - toggleBtn.addEventListener('touchend', hidePassword); // Copy button const copyBtn = document.createElement('button'); @@ -380,9 +413,11 @@ let fields = []; if (creds.username) { fields.push(` -
+
Username: - ${escapeHtml(creds.username)} +
+ ${escapeHtml(creds.username)} +
`); } @@ -458,11 +493,17 @@ ${credentialsHtml} `; - // Add password fields after card is created + // Add password fields and copy buttons after card is created if (serviceData.credentials) { const creds = serviceData.credentials; setTimeout(() => { + if (creds.username) { + const userContainer = card.querySelector(`#user-${key} .flex.items-center`); + if (userContainer) { + userContainer.appendChild(createCopyButton(creds.username)); + } + } if (creds.password) { const pwdContainer = card.querySelector(`#pwd-${key}`); if (pwdContainer) { diff --git a/welcome/index.html b/welcome/index.html index eff6008..1b188b3 100644 --- a/welcome/index.html +++ b/welcome/index.html @@ -122,6 +122,31 @@
+ +
+
+
+ + + +
+

Keeping Up to Date

+
+
+

Keep your services up to date with the latest features and security patches:

+
+
+ make update-preview + Preview available updates before applying +
+
+ make update + Update all services to the latest versions +
+
+
+
+