From c8a009dda19080a4248ed25b70bc661a344cbddc Mon Sep 17 00:00:00 2001 From: Grzegorz Kucmierz Date: Fri, 27 Feb 2026 00:31:26 +0000 Subject: [PATCH] feat: update passwords tool UI, fix layout issues, and set PWA theme color --- index.html | 2 +- src/components/Header.vue | 8 +- src/components/InstallPrompt.vue | 10 +- src/components/tools/Passwords.vue | 201 ++++++++++++++++++++++++----- src/style.css | 13 ++ vite.config.js | 2 +- 6 files changed, 196 insertions(+), 40 deletions(-) diff --git a/index.html b/index.html index b71d848..8e0446a 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ - + Tools App diff --git a/src/components/Header.vue b/src/components/Header.vue index 76b7cc7..e06bfe9 100644 --- a/src/components/Header.vue +++ b/src/components/Header.vue @@ -31,7 +31,13 @@ onMounted(() => {
- +
@@ -19,6 +19,12 @@ let deferredPrompt = null const handleBeforeInstallPrompt = (e) => { // Prevent Chrome 67 and earlier from automatically showing the prompt e.preventDefault() + + // Only show install prompt if we are on the specific domain + if (window.location.hostname !== 'tools.7u.pl') { + return + } + // Stash the event so it can be triggered later. deferredPrompt = e // Update UI to notify the user they can add to home screen diff --git a/src/components/tools/Passwords.vue b/src/components/tools/Passwords.vue index cd7ad55..455de2c 100644 --- a/src/components/tools/Passwords.vue +++ b/src/components/tools/Passwords.vue @@ -104,11 +104,19 @@ const generatePasswords = () => {
- +
+ + + +
- +
+ + + +
@@ -122,7 +130,7 @@ const generatePasswords = () => {
@@ -138,6 +146,7 @@ const generatePasswords = () => { width: 100%; max-width: 800px; margin: 0 auto; + height: 100%; } .tool-panel { @@ -147,6 +156,27 @@ const generatePasswords = () => { display: flex; flex-direction: column; gap: 1.5rem; + max-height: 100%; + overflow-y: auto; +} + +/* Custom scrollbar for tool panel */ +.tool-panel::-webkit-scrollbar { + width: 8px; +} + +.tool-panel::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.1); + border-radius: 4px; +} + +.tool-panel::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.2); + border-radius: 4px; +} + +.tool-panel::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.3); } .tool-title { @@ -198,16 +228,17 @@ const generatePasswords = () => { background-color: var(--toggle-bg); border: 1px solid var(--toggle-border); border-radius: 4px; - transition: all 0.2s ease; + transition: all 0.3s ease; } -.checkbox-label:hover input ~ .checkmark { - border-color: var(--accent-cyan); +.checkbox-label:hover .checkmark { + border-color: var(--toggle-hover-border); } .checkbox-label input:checked ~ .checkmark { - background-color: var(--accent-cyan); - border-color: var(--accent-cyan); + background-color: var(--primary-accent); + border-color: var(--primary-accent); + box-shadow: 0 0 10px var(--primary-accent); } .checkmark:after { @@ -232,8 +263,8 @@ const generatePasswords = () => { .inputs-group { display: flex; - gap: 2rem; flex-wrap: wrap; + gap: 1.5rem; } .input-wrapper { @@ -245,69 +276,169 @@ const generatePasswords = () => { } .input-wrapper label { + color: var(--text-secondary); + font-weight: 500; font-size: 0.9rem; - color: var(--text-muted); - font-weight: 600; +} + +.number-control { + display: flex; + align-items: stretch; + gap: 0; +} + +.control-btn { + width: 42px; + display: flex; + align-items: center; + justify-content: center; + background-color: var(--toggle-bg); + border: 1px solid var(--toggle-border); + color: var(--text-color); + border-radius: 0; + font-size: 1.2rem; + cursor: pointer; + transition: all 0.2s; + user-select: none; +} + +.control-btn:first-child { + border-top-left-radius: 8px; + border-bottom-left-radius: 8px; + border-right: none; +} + +.control-btn:last-child { + border-top-right-radius: 8px; + border-bottom-right-radius: 8px; + border-left: none; +} + +.control-btn:hover { + background-color: var(--button-hover-bg); + border-color: var(--toggle-hover-border); + z-index: 1; +} + +.control-btn:active { + transform: scale(0.98); } .number-input { - background: var(--toggle-bg); + flex: 1; + padding: 0.8rem; + background-color: var(--toggle-bg); border: 1px solid var(--toggle-border); + border-radius: 0; color: var(--text-color); - padding: 10px 15px; - border-radius: 8px; font-size: 1rem; - outline: none; - transition: border-color 0.2s; + transition: border-color 0.3s; + text-align: center; + appearance: textfield; /* Remove default spinner */ + min-width: 0; +} + +.number-input::-webkit-outer-spin-button, +.number-input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; } .number-input:focus { - border-color: var(--accent-cyan); + outline: none; + border-color: var(--primary-accent); + box-shadow: 0 0 0 2px var(--toggle-active-shadow); + z-index: 2; + position: relative; } .action-area { display: flex; - justify-content: flex-end; /* Align button to right */ + justify-content: center; + margin-top: 1rem; + width: 100%; } -.generate-btn { +.btn-neon { width: 100%; - padding: 12px; + background: var(--button-bg); + border: 1px solid var(--button-border); + color: var(--button-text); + padding: 0.8rem 2rem; font-size: 1.1rem; - letter-spacing: 0.5px; + font-weight: 600; + border-radius: 12px; + cursor: pointer; + transition: all 0.3s ease; + text-transform: uppercase; + letter-spacing: 1px; + position: relative; + overflow: hidden; +} + +.btn-neon:hover { + background: var(--button-hover-bg); + box-shadow: var(--button-hover-shadow); + transform: translateY(-2px); + border-color: var(--toggle-hover-border); +} + +.btn-neon:active { + transform: translateY(1px); + box-shadow: var(--button-active-shadow); } .result-area { display: flex; flex-direction: column; gap: 0.5rem; + flex: 1; + min-height: 200px; } .result-area label { + color: var(--text-secondary); + font-weight: 500; font-size: 0.9rem; - color: var(--text-muted); - font-weight: 600; - border-left: 3px solid var(--accent-purple); - padding-left: 10px; } .result-textarea { width: 100%; - height: 300px; - background: rgba(0, 0, 0, 0.2); /* Slightly darker for contrast */ - color: var(--text-color); - border: 1px solid var(--accent-purple); + box-sizing: border-box; + height: 100%; + min-height: 200px; padding: 1rem; - border-radius: 8px; + background-color: rgba(0, 0, 0, 0.2); + border: 1px solid var(--toggle-border); + border-radius: 12px; + color: var(--text-strong); font-family: monospace; font-size: 1rem; - line-height: 1.5; resize: vertical; - outline: none; - box-sizing: border-box; + line-height: 1.6; } -:root[data-theme="light"] .result-textarea { - background: rgba(255, 255, 255, 0.5); +.result-textarea:focus { + outline: none; + border-color: var(--primary-accent); +} + +/* Scrollbar for textarea */ +.result-textarea::-webkit-scrollbar { + width: 8px; +} + +.result-textarea::-webkit-scrollbar-track { + background: rgba(0, 0, 0, 0.1); + border-radius: 4px; +} + +.result-textarea::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.2); + border-radius: 4px; +} + +.result-textarea::-webkit-scrollbar-thumb:hover { + background: rgba(255, 255, 255, 0.3); } diff --git a/src/style.css b/src/style.css index 2bba99e..5c6374c 100644 --- a/src/style.css +++ b/src/style.css @@ -1,3 +1,8 @@ +/* Box sizing reset */ +*, *::before, *::after { + box-sizing: border-box; +} + :root { font-family: system-ui, Avenir, Helvetica, Arial, sans-serif; line-height: 1.5; @@ -86,6 +91,14 @@ body { min-width: 320px; min-height: 100vh; overflow-x: hidden; + user-select: none; + -webkit-user-select: none; +} + +.selectable { + user-select: text; + -webkit-user-select: text; + cursor: text; } #app { diff --git a/vite.config.js b/vite.config.js index 878cca2..da055f8 100644 --- a/vite.config.js +++ b/vite.config.js @@ -14,7 +14,7 @@ export default defineConfig({ name: 'Tools App', short_name: 'Tools', description: 'A collection of useful tools', - theme_color: '#242424', + theme_color: '#4facfe', background_color: '#242424', display: 'standalone', orientation: 'portrait',