From 5e0b3d5dba5d0a30a3cf3d5c489cc2f2895607b1 Mon Sep 17 00:00:00 2001 From: phamhungd Date: Fri, 28 Nov 2025 16:04:26 +0700 Subject: [PATCH] update setting --- .DS_Store | Bin 10244 -> 10244 bytes app.py | 7 ++- gallery_favorites.json | 4 +- static/script.js | 101 +++++++++++++++++++++++++++++++++++++++++ static/style.css | 43 ++++++++++++++++-- templates/index.html | 83 ++++++++++++++++++++++++++++++++- 6 files changed, 230 insertions(+), 8 deletions(-) diff --git a/.DS_Store b/.DS_Store index 384f77c574e6c1e61d8062b4cebadd2cd298422b..19d8a8d06c6ca2fe197fefa29e0c6a8a24b9b032 100644 GIT binary patch delta 107 zcmZn(XbIThE5Q6}_teP&0urnbVt?hFo17~k4Q2HT$S`db*t}ZcCnt;ef%h*buaJ^w z+I4pFNhu`|^;SxrS^U_C$^6m>nPxqo{6|`1@+)Z`W`;RuCjXSyU`jqZSy@J%alvM9 HnVsAK)9EcS delta 107 zcmZn(XbIThE5Q7s_w3{V0SVUAfmf~^ot!Hm4Q2HT$S|!{*t}ZcCnt;8 { const apiKeyToggleBtn = document.getElementById('toggle-api-key-visibility'); const apiKeyEyeIcon = apiKeyToggleBtn?.querySelector('.icon-eye'); const apiKeyEyeOffIcon = apiKeyToggleBtn?.querySelector('.icon-eye-off'); + const bodyFontSelect = document.getElementById('body-font'); const placeholderState = document.getElementById('placeholder-state'); const loadingState = document.getElementById('loading-state'); @@ -150,6 +151,10 @@ document.addEventListener('DOMContentLoaded', () => { toggleResolutionVisibility(); } currentTheme = settings.theme || DEFAULT_THEME; + applyBodyFont(settings.bodyFont || DEFAULT_BODY_FONT); + if (bodyFontSelect && settings.bodyFont) { + bodyFontSelect.value = settings.bodyFont; + } return settings; } } catch (e) { @@ -173,6 +178,7 @@ document.addEventListener('DOMContentLoaded', () => { model: apiModelSelect ? apiModelSelect.value : 'gemini-3-pro-image-preview', referenceImages, theme: currentTheme || DEFAULT_THEME, + bodyFont: bodyFontSelect ? bodyFontSelect.value : DEFAULT_BODY_FONT, }; try { localStorage.setItem(SETTINGS_STORAGE_KEY, JSON.stringify(settings)); @@ -216,6 +222,7 @@ document.addEventListener('DOMContentLoaded', () => { ]; const DEFAULT_THEME = 'theme-sdvn'; + const DEFAULT_BODY_FONT = 'Be Vietnam Pro'; const themeOptionsData = [ { id: 'theme-sdvn', name: 'SDVN', gradient: 'linear-gradient(to bottom, #5858e6, #151523)' }, @@ -306,6 +313,65 @@ document.addEventListener('DOMContentLoaded', () => { noteHighlight.scrollLeft = promptNoteInput.scrollLeft; } + function triggerInputUpdate(targetInput) { + if (!targetInput) return; + targetInput.dispatchEvent(new Event('input', { bubbles: true })); + } + + function getFieldInput(target) { + if (target === 'note') return promptNoteInput; + return promptInput; + } + + async function copyToClipboard(text) { + if (!navigator.clipboard?.writeText) { + const temp = document.createElement('textarea'); + temp.value = text; + document.body.appendChild(temp); + temp.select(); + document.execCommand('copy'); + temp.remove(); + return; + } + await navigator.clipboard.writeText(text); + } + + async function pasteIntoInput(targetInput) { + if (!targetInput) return; + if (!navigator.clipboard?.readText) { + alert('Clipboard paste không được hỗ trợ trong trình duyệt này.'); + return; + } + const text = await navigator.clipboard.readText(); + if (!text && text !== '') return; + const start = targetInput.selectionStart ?? targetInput.value.length; + const end = targetInput.selectionEnd ?? start; + targetInput.value = targetInput.value.slice(0, start) + text + targetInput.value.slice(end); + const cursor = start + text.length; + requestAnimationFrame(() => { + targetInput.setSelectionRange(cursor, cursor); + targetInput.focus(); + }); + triggerInputUpdate(targetInput); + } + + async function handleFieldAction(action, target) { + const targetInput = getFieldInput(target); + if (!targetInput) return; + if (action === 'copy') { + await copyToClipboard(targetInput.value); + return; + } + if (action === 'paste') { + await pasteIntoInput(targetInput); + return; + } + if (action === 'clear') { + targetInput.value = ''; + triggerInputUpdate(targetInput); + } + } + function updateThemeSelectionUi() { if (!themeOptionsContainer) return; themeOptionsContainer.querySelectorAll('.theme-option').forEach(btn => { @@ -334,6 +400,19 @@ document.addEventListener('DOMContentLoaded', () => { } } + function applyBodyFont(fontName) { + const fontMap = { + 'Be Vietnam Pro': "'Be Vietnam Pro', sans-serif", + 'Playwrite AU SA': "'Playwrite AU SA', cursive", + 'JetBrains Mono': "'JetBrains Mono', monospace", + }; + const cssFont = fontMap[fontName] || fontMap[DEFAULT_BODY_FONT]; + document.body.style.fontFamily = cssFont; + if (bodyFontSelect && fontName) { + bodyFontSelect.value = fontName; + } + } + function renderThemeOptions(initialTheme) { if (!themeOptionsContainer) return; themeOptionsContainer.innerHTML = ''; @@ -430,6 +509,7 @@ document.addEventListener('DOMContentLoaded', () => { applyThemeClass(currentTheme || DEFAULT_THEME); slotManager.initialize(savedSettings.referenceImages || []); refreshPromptHighlight(); + applyBodyFont(savedSettings.bodyFont || DEFAULT_BODY_FONT); apiKeyInput.addEventListener('input', persistSettings); let isApiKeyVisible = false; @@ -472,8 +552,28 @@ document.addEventListener('DOMContentLoaded', () => { }); aspectRatioInput.addEventListener('change', persistSettings); resolutionInput.addEventListener('change', persistSettings); + if (bodyFontSelect) { + bodyFontSelect.addEventListener('change', () => { + applyBodyFont(bodyFontSelect.value); + persistSettings(); + }); + } window.addEventListener('beforeunload', persistSettings); + document.querySelectorAll('.field-action-btn').forEach(btn => { + btn.addEventListener('click', async () => { + const action = btn.dataset.action; + const target = btn.closest('.field-action-buttons')?.dataset.target; + if (!action || !target) return; + try { + await handleFieldAction(action, target); + } catch (err) { + console.warn('Field action failed', err); + alert('Không thể thực hiện thao tác clipboard. Vui lòng thử lại.'); + } + }); + }); + const queueCounter = document.getElementById('queue-counter'); const queueCountText = document.getElementById('queue-count-text'); @@ -1770,6 +1870,7 @@ document.addEventListener('DOMContentLoaded', () => { } else { promptNoteInput.value = ''; } + refreshNoteHighlight(); if (metadata.aspect_ratio) aspectRatioInput.value = metadata.aspect_ratio; if (metadata.resolution) resolutionInput.value = metadata.resolution; diff --git a/static/style.css b/static/style.css index 119aa25..e07e2ef 100644 --- a/static/style.css +++ b/static/style.css @@ -438,7 +438,7 @@ body.theme-amin { --bd-bg: linear-gradient(to right, #4A00E0, #8E2DE2); } .prompt-highlight { position: absolute; inset: 0; - padding: 0.75rem; + padding: 0.75rem 0.75rem 2.25rem 0.75rem; overflow: auto; pointer-events: none; white-space: pre-wrap; @@ -472,7 +472,7 @@ body.theme-amin { --bd-bg: linear-gradient(to right, #4A00E0, #8E2DE2); } background: transparent; color: transparent; caret-color: var(--accent-color); - padding: 0.75rem; + padding: 0.75rem 0.75rem 2.25rem 0.75rem; font-family: inherit; font-size: 0.875rem; line-height: 1.4; @@ -493,7 +493,7 @@ body.theme-amin { --bd-bg: linear-gradient(to right, #4A00E0, #8E2DE2); } .note-highlight { position: absolute; inset: 0; - padding: 0.75rem; + padding: 0.75rem 0.75rem 2.25rem 0.75rem; overflow: auto; pointer-events: none; white-space: pre-wrap; @@ -526,7 +526,7 @@ body.theme-amin { --bd-bg: linear-gradient(to right, #4A00E0, #8E2DE2); } background: transparent; color: transparent; caret-color: var(--accent-color); - padding: 0.75rem; + padding: 0.75rem 0.75rem 2.25rem 0.75rem; font-family: inherit; font-size: 0.875rem; line-height: 1.4; @@ -536,6 +536,41 @@ body.theme-amin { --bd-bg: linear-gradient(to right, #4A00E0, #8E2DE2); } height: 100%; } +.field-action-buttons { + position: absolute; + right: 0.35rem; + bottom: 0.35rem; + display: inline-flex; + gap: 0.25rem; + padding: 0.1rem; + border-radius: 0.5rem; + z-index: 3; + background: transparent; +} + +.field-action-btn { + border: none; + background: transparent; + color: var(--text-secondary); + width: 24px; + height: 24px; + border-radius: 8px; + display: inline-flex; + align-items: center; + justify-content: center; + cursor: pointer; + transition: background 0.15s, color 0.15s; +} + +.field-action-btn:hover { + background: rgba(255, 255, 255, 0.06); + color: var(--accent-color); +} + +.field-action-btn:active { + transform: translateY(1px); +} + .theme-option-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(110px, 1fr)); diff --git a/templates/index.html b/templates/index.html index 94f714c..b999d3e 100644 --- a/templates/index.html +++ b/templates/index.html @@ -10,7 +10,7 @@ @@ -43,6 +43,41 @@
+
+ + + +