From 36cb7930480fed985c51ef0e2ccdb38f3498dc1e Mon Sep 17 00:00:00 2001 From: syntaxbullet Date: Mon, 9 Feb 2026 23:16:26 +0100 Subject: [PATCH] feat: Implement image import functionality, restructure control panel layout, and apply glassmorphism styling to controls. --- src/components/Navbar.astro | 28 ++-- src/pages/index.astro | 266 ++++++++++++++++++++++++------------ src/scripts/ui-bindings.ts | 56 +++++++- 3 files changed, 252 insertions(+), 98 deletions(-) diff --git a/src/components/Navbar.astro b/src/components/Navbar.astro index c3fd85d..701104a 100644 --- a/src/components/Navbar.astro +++ b/src/components/Navbar.astro @@ -55,8 +55,11 @@ const { pathname } = Astro.url; left: 0; width: 100%; height: 24px; - background: #000; - border-bottom: 1px solid var(--text-color); + background: rgba(10, 10, 10, 0.8); + -webkit-backdrop-filter: blur(12px); + backdrop-filter: blur(12px); + border-bottom: 1px solid rgba(255, 255, 255, 0.15); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); display: flex; justify-content: space-between; align-items: center; @@ -81,30 +84,32 @@ const { pathname } = Astro.url; align-items: center; color: var(--text-color); text-decoration: none; - border-right: 1px solid rgba(255, 103, 0, 0.2); - transition: all 0.1s; + border-right: 1px solid rgba(255, 255, 255, 0.1); + transition: all 0.2s ease; } .nav-link:hover { - background: var(--text-color); - color: #000; + background: rgba(255, 255, 255, 0.1); + color: #fff; text-decoration: none; } .nav-link:hover .nav-index { - color: #000; + color: #fff; opacity: 1; } .status-item.active { - background: var(--text-color); - color: #000; + background: rgba(255, 255, 255, 0.15); + color: #fff; font-weight: bold; + box-shadow: inset 0 -2px 0 var(--text-color); } .status-item.brand { - background: rgba(255, 103, 0, 0.1); + background: rgba(255, 255, 255, 0.05); font-weight: 900; + letter-spacing: 1px; } .nav-index { @@ -122,7 +127,7 @@ const { pathname } = Astro.url; .status-right .status-item { border-right: none; - border-left: 1px solid rgba(255, 103, 0, 0.2); + border-left: 1px solid rgba(255, 255, 255, 0.1); } .prefix { @@ -134,6 +139,7 @@ const { pathname } = Astro.url; #system-status { color: #0f0; font-weight: bold; + text-shadow: 0 0 5px rgba(0, 255, 0, 0.5); } diff --git a/src/pages/index.astro b/src/pages/index.astro index 79e1c23..f1e791f 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -174,64 +174,80 @@ import Tooltip from "../components/Tooltip.astro";
- -
-
ACTIONS
-
- + +
+
+
ACTIONS
+
+ - -
- Q: - 0 +
+ Q: + 0 +
-
- -
+ +
- -
-
EXPORT
-
- - - +
+
+ IMPORT / EXPORT +
+
+ + + + + + +
@@ -405,6 +421,12 @@ import Tooltip from "../components/Tooltip.astro"; font-size: 1.5rem; display: none; z-index: 10; + + text-shadow: 0 0 10px rgba(0, 0, 0, 0.8); + background: rgba(0, 0, 0, 0.6); + padding: 10px 20px; + border-radius: 4px; + backdrop-filter: blur(4px); } /* FOREGROUND LAYER */ @@ -474,6 +496,7 @@ import Tooltip from "../components/Tooltip.astro"; max-width: 400px; background: rgba(0, 0, 0, 0.6); padding: 5px; + border-radius: 2px; } /* Footer / Controls */ @@ -484,25 +507,40 @@ import Tooltip from "../components/Tooltip.astro"; align-items: center; gap: 0.75rem; position: relative; + z-index: 50; /* Ensure on top */ } #tui-controls { display: flex; flex-wrap: wrap; justify-content: center; - align-items: flex-start; + align-items: stretch; /* Stretch to same height */ gap: 0; - background: rgba(0, 0, 0, 0.95); - border: 1px solid var(--text-color); - box-shadow: 0 0 30px rgba(0, 0, 0, 0.8); + + /* Glassmorphism update */ + background: rgba(10, 10, 10, 0.8); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + + border: 1px solid rgba(255, 255, 255, 0.15); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5); + max-width: 100%; + border-radius: 8px; /* Slightly rounded for premium feel */ + overflow: hidden; /* For border radius */ } .control-panel-section { - padding: 12px 16px; + padding: 16px 20px; + display: flex; + flex-direction: column; + gap: 10px; + flex-shrink: 0; + } + + .control-col-right { display: flex; flex-direction: column; - gap: 8px; } .control-panel-divider { @@ -510,32 +548,47 @@ import Tooltip from "../components/Tooltip.astro"; background: linear-gradient( to bottom, transparent 0%, - rgba(255, 103, 0, 0.3) 20%, - rgba(255, 103, 0, 0.3) 80%, + rgba(255, 255, 255, 0.1) 20%, + rgba(255, 255, 255, 0.3) 50%, + rgba(255, 255, 255, 0.1) 80%, transparent 100% ); align-self: stretch; } + .control-panel-divider-h { + height: 1px; + width: 100%; + background: linear-gradient( + to right, + transparent 0%, + rgba(255, 255, 255, 0.1) 20%, + rgba(255, 255, 255, 0.3) 50%, + rgba(255, 255, 255, 0.1) 80%, + transparent 100% + ); + } + .section-header { - font-size: 9px; - font-weight: bold; - opacity: 0.5; + font-size: 10px; + font-weight: 800; + opacity: 0.6; letter-spacing: 2px; - margin-bottom: 4px; + margin-bottom: 2px; text-transform: uppercase; + color: var(--text-color); } .sliders-grid { display: grid; grid-template-columns: repeat(2, 1fr); - gap: 6px 16px; + gap: 8px 20px; } .toggles-row { display: flex; flex-wrap: wrap; - gap: 6px; + gap: 8px; } .segments-row { @@ -547,7 +600,8 @@ import Tooltip from "../components/Tooltip.astro"; .actions-row { display: flex; align-items: center; - gap: 10px; + gap: 8px; + flex-wrap: wrap; } .queue-display { @@ -557,7 +611,7 @@ import Tooltip from "../components/Tooltip.astro"; font-size: 11px; opacity: 0.6; padding: 0 8px; - border-left: 1px solid rgba(255, 103, 0, 0.2); + border-left: 1px solid rgba(255, 255, 255, 0.2); } .queue-label { @@ -575,34 +629,34 @@ import Tooltip from "../components/Tooltip.astro"; display: flex; flex-wrap: wrap; justify-content: center; - gap: 12px; - font-size: 10px; - opacity: 0.4; + gap: 16px; + font-size: 11px; + opacity: 0.5; transition: opacity 0.2s; } .shortcuts-hint:hover { - opacity: 0.7; + opacity: 0.8; } .shortcuts-hint span { display: flex; align-items: center; - gap: 4px; + gap: 6px; } .shortcuts-hint kbd { display: inline-flex; align-items: center; justify-content: center; - min-width: 16px; - height: 16px; - padding: 0 4px; - font-size: 9px; + min-width: 18px; + height: 18px; + padding: 0 5px; + font-size: 10px; font-family: inherit; - border: 1px solid rgba(255, 103, 0, 0.4); - border-radius: 2px; - background: rgba(255, 103, 0, 0.05); + border: 1px solid rgba(255, 255, 255, 0.3); + border-radius: 4px; + background: rgba(255, 255, 255, 0.1); } /* Legacy styles kept for compatibility */ @@ -627,7 +681,7 @@ import Tooltip from "../components/Tooltip.astro"; .tui-btn:hover { opacity: 1; border-color: var(--text-color); - background: rgba(255, 103, 0, 0.1); + background: rgba(255, 255, 255, 0.1); } .tui-val { @@ -648,20 +702,45 @@ import Tooltip from "../components/Tooltip.astro"; align-items: stretch; } + .control-col-right { + flex-direction: row; + justify-content: space-between; + flex-wrap: wrap; + } + + .control-col-right > .control-panel-section { + flex: 1; + } + + /* New vertical alignment for right col on mobile */ + .control-panel-divider-h { + width: 1px; + height: auto; + align-self: stretch; + background: linear-gradient( + to bottom, + transparent 0%, + rgba(255, 255, 255, 0.2) 20%, + rgba(255, 255, 255, 0.2) 80%, + transparent 100% + ); + } + .control-panel-divider { width: 100%; height: 1px; background: linear-gradient( to right, transparent 0%, - rgba(255, 103, 0, 0.3) 20%, - rgba(255, 103, 0, 0.3) 80%, + rgba(255, 255, 255, 0.1) 20%, + rgba(255, 255, 255, 0.3) 50%, + rgba(255, 255, 255, 0.1) 80%, transparent 100% ); } .control-panel-section { - padding: 10px 14px; + padding: 12px 16px; } } @@ -670,6 +749,21 @@ import Tooltip from "../components/Tooltip.astro"; font-size: 3rem; } + .control-col-right { + flex-direction: column; + } + + .control-panel-divider-h { + width: 100%; + height: 1px; + background: linear-gradient( + to right, + transparent, + rgba(255, 255, 255, 0.2), + transparent + ); + } + .controls-footer { padding: 1rem; } @@ -691,11 +785,11 @@ import Tooltip from "../components/Tooltip.astro"; @media (max-width: 480px) { .control-panel-section { - padding: 8px 10px; + padding: 10px 12px; } .section-header { - font-size: 8px; + font-size: 9px; } } diff --git a/src/scripts/ui-bindings.ts b/src/scripts/ui-bindings.ts index cc9bee9..12fdb0b 100644 --- a/src/scripts/ui-bindings.ts +++ b/src/scripts/ui-bindings.ts @@ -67,6 +67,7 @@ export class UIBindings { this.setupKeyboard(); this.setupZoom(); this.setupResize(); + this.setupImport(); // Periodic queue update this.queueInterval = window.setInterval(() => this.updateQueueDisplay(), 1000); @@ -142,13 +143,20 @@ export class UIBindings { } // Cleanup Export Buttons - ['btn-save-png', 'btn-copy-text', 'btn-copy-html'].forEach(id => { + ['btn-save-png', 'btn-copy-text', 'btn-copy-html', 'btn-import'].forEach(id => { const el = document.getElementById(id); const handler = this.buttonHandlers.get(id); if (el && handler) { el.removeEventListener('click', handler); } }); + + // Cleanup File Input + const fileInput = document.getElementById('file-upload'); + const fileHandler = this.buttonHandlers.get('file-upload'); + if (fileInput && fileHandler) { + fileInput.removeEventListener('change', fileHandler); + } } // ============= Sliders ============= @@ -412,6 +420,52 @@ export class UIBindings { window.addEventListener('resize', this.resizeHandler); } + // ============= Import ============= + + private setupImport(): void { + const btnImport = document.getElementById('btn-import'); + const fileInput = document.getElementById('file-upload') as HTMLInputElement; + + if (btnImport && fileInput) { + // Button triggers file input + const btnHandler = (e: Event) => { + e.stopPropagation(); + fileInput.click(); + }; + this.buttonHandlers.set('btn-import', btnHandler); + btnImport.addEventListener('click', btnHandler); + + // File input change + const fileHandler = async (e: Event) => { + const files = (e.target as HTMLInputElement).files; + if (files && files.length > 0) { + const file = files[0]; + const url = URL.createObjectURL(file); + + // Reset value so same file can be selected again + fileInput.value = ''; + + try { + this.controller.showLoading("LOADING IMPORT..."); + // Use empty suggestions for user imports unless we want to auto-detect? + // For now keep existing settings or use defaults. + // Let's pass empty object to respect current user settings or controller defaults. + this.controller.setCurrentImage(url, {}); + this.updateUI(); + await this.controller.generate(); + this.controller.hideLoading(); + } catch (err) { + console.error("Import failed:", err); + this.controller.hideLoading(); + alert("Failed to load image. Please try another file."); + } + } + }; + this.buttonHandlers.set('file-upload', fileHandler); + fileInput.addEventListener('change', fileHandler); + } + } + // ============= UI Sync ============= updateUI(): void {