From ef45a8b258231447587ba19170b572010c4384c8 Mon Sep 17 00:00:00 2001 From: Daniel Dada Date: Mon, 23 Jun 2025 08:50:28 +0300 Subject: [PATCH] WIP - refactor: updated styling --- _locales/en/messages.json | 10 +- _locales/ru/messages.json | 6 +- popup/popup.css | 265 ++++++++++++++++++++++++++------------ popup/popup.html | 81 ++++++------ popup/popup.js | 78 ++++++++--- 5 files changed, 298 insertions(+), 142 deletions(-) diff --git a/_locales/en/messages.json b/_locales/en/messages.json index 309004e..be66263 100644 --- a/_locales/en/messages.json +++ b/_locales/en/messages.json @@ -30,16 +30,16 @@ "message": "Add Words" }, "select_all": { - "message": "Select All" + "message": "Select" }, "delete_selected": { - "message": "Delete Selected" + "message": "Delete" }, "disable_selected": { - "message": "Disable Selected" + "message": "Disable" }, "enable_selected": { - "message": "Enable Selected" + "message": "Enable" }, "import_list": { "message": "Import JSON" @@ -66,6 +66,6 @@ "message": "Are you sure you want to delete the selected words?" }, "deselect_all": { - "message": "Deselect All" + "message": "Deselect" } } \ No newline at end of file diff --git a/_locales/ru/messages.json b/_locales/ru/messages.json index aeab38c..7a514f5 100644 --- a/_locales/ru/messages.json +++ b/_locales/ru/messages.json @@ -33,13 +33,13 @@ "message": "Выбрать все" }, "delete_selected": { - "message": "Удалить выбранное" + "message": "Удалить" }, "disable_selected": { - "message": "Отключить выбранное" + "message": "Отключить" }, "enable_selected": { - "message": "Включить выбранное" + "message": "Включить" }, "import_list": { "message": "Импорт JSON" diff --git a/popup/popup.css b/popup/popup.css index 0a37de7..7a7f45f 100644 --- a/popup/popup.css +++ b/popup/popup.css @@ -1,61 +1,95 @@ :root { - --bg-color: #ffffff; - --text-color: #1a1a1a; - --input-bg: #f0f0f0; - --input-border: #ccc; - --button-bg: #007bff; - --button-hover: #0056b3; - --wordlist-bg: #f9f9f9; - --checkbox-accent: #007bff; -} - -.dark { - --bg-color: #171717; - --text-color: #e0e0e0; - --input-bg: #1f1f1f; + --bg-color: #0d0d0d; + --text-color: #f0f0f0; + --input-bg: #1a1a1a; --input-border: #333; - --button-bg: #2e7d32; - --button-hover: #388e3c; - --wordlist-bg: #1f1f1f; - --checkbox-accent: #4caf50; + --button-bg: #222; + --button-hover: #444; + --button-text: white; + --accent: #ffeb3b; + --accent-text: #000; + --highlight-tag: #292929; + --highlight-tag-border: #444; + --danger: #b00020; + --success: #00c853; + --shadow: 0 2px 6px rgba(0, 0, 0, 0.5); + --border-radius: 12px; + --section-bg: #111; + --switch-bg: #444; + --checkbox-accent: #ffeb3b; + --checkbox-border: #666; } body { - font-family: 'Segoe UI', sans-serif; - width: 400px; - margin: 0; - padding: 0; + font-family: 'Inter', sans-serif; background: var(--bg-color); color: var(--text-color); - transition: background 0.3s ease, color 0.3s ease; + margin: 0; + padding: 0; + width: 400px; max-height: 600px; - overflow: hidden; + overflow-y: auto; + transition: background 0.3s ease, color 0.3s ease; +} + +body.light { + --bg-color: #f5f5f5; + --text-color: #222; + --input-bg: #ffffff; + --input-border: #ccc; + --button-bg: #e0e0e0; + --button-hover: #d0d0d0; + --button-text: #222; + --accent: #ec9c23; + --accent-text: #000; + --highlight-tag: #f0f0f0; + --highlight-tag-border: #d0d0d0; + --danger: #b00020; + --success: #00c853; + --shadow: 0 2px 6px rgba(0, 0, 0, 0.1); + --section-bg: #fff; + --switch-bg: #ccc; + --checkbox-accent: #ec9c23; + --checkbox-border: #999; } .container { - padding: 12px; - height: 100%; + padding: 16px; display: flex; flex-direction: column; - gap: 8px; + gap: 12px; } h1 { - font-size: 1.5em; - margin-bottom: 16px; - color: var(--text-color); - text-align: center; + font-size: 1.3em; + display: flex; + align-items: center; + gap: 8px; + justify-content: center; + margin-bottom: 4px; } .section { - margin-bottom: 0; + background: var(--section-bg); + border: 1px solid var(--input-border); + border-radius: var(--border-radius); + padding: 14px; + box-shadow: var(--shadow); } -.word-list-section { - flex: 1; - min-height: 200px; +.section-header { display: flex; - flex-direction: column; + justify-content: space-between; + align-items: center; + margin-bottom: 10px; +} + +.section h2 { + font-size: 1em; + margin-bottom: 10px; + font-weight: 600; + display: flex; + align-items: center; gap: 8px; } @@ -63,44 +97,42 @@ input[type="text"], textarea, select { width: 100%; - box-sizing: border-box; - margin-top: 4px; - margin-bottom: 6px; - padding: 6px; + padding: 8px; border-radius: 6px; border: 1px solid var(--input-border); background-color: var(--input-bg); color: var(--text-color); - transition: background 0.3s, color 0.3s, border-color 0.3s; + font-size: 0.9em; + box-sizing: border-box; + margin-top: 4px; + margin-bottom: 6px; } textarea { - height: 60px; resize: vertical; - background-color: var(--input-bg) !important; - color: var(--text-color) !important; - border: 1px solid var(--input-border) !important; + height: 60px; } input[type="color"] { - background-color: transparent; + background: none; border: none; cursor: pointer; width: 36px; height: 36px; + margin-left: 6px; } input[type="checkbox"] { -webkit-appearance: none; appearance: none; - accent-color: var(--checkbox-accent); background-color: var(--input-bg); - border: 1px solid var(--input-border); + border: 1px solid var(--checkbox-border); border-radius: 4px; width: 16px; height: 16px; transform: scale(1.2); cursor: pointer; + position: relative; } input[type="checkbox"]:checked::after { @@ -115,54 +147,120 @@ input[type="checkbox"]:checked::after { transform: rotate(45deg); } -button { - margin: 2px; - padding: 6px 10px; - font-size: 0.85em; - border: none; - border-radius: 6px; - background-color: var(--button-bg); - color: white; +input[type="checkbox"]:checked { + background-color: var(--input-bg); +} + +input[type="checkbox"].switch { + appearance: none; + width: 40px; + height: 20px; + background: var(--switch-bg); + border-radius: 20px; + position: relative; + outline: none; cursor: pointer; - transition: background-color 0.2s ease; + transition: background 0.3s; +} + +input[type="checkbox"].switch::before { + content: ""; + position: absolute; + top: 2px; + left: 2px; + width: 16px; + height: 16px; + background: white; + border-radius: 50%; + transition: transform 0.3s; +} + +input[type="checkbox"].switch:checked { + background: var(--accent); +} + +input[type="checkbox"].switch:checked::before { + transform: translateX(20px); +} + +button { + background: var(--button-bg); + color: var(--button-text); + border: 1px solid var(--input-border); + padding: 6px 12px; + border-radius: 8px; + font-weight: 500; + cursor: pointer; + transition: background 0.2s; + display: flex; + align-items: center; + gap: 4px; + font-size: 0.9em; } button:hover { - background-color: var(--button-hover); + background: var(--button-hover); +} + +button.danger { + background: var(--danger); + color: white !important; +} + +button.danger:hover { + background: #d32f2f; +} + +.button-row { + display: flex; + gap: 8px; + flex-wrap: wrap; + margin-top: 8px; +} + +.button-row.wrap { + flex-wrap: wrap; +} + +.color-row { + display: flex; + gap: 12px; + align-items: center; + margin-bottom: 8px; } #wordList { + margin-top: 8px; position: relative; overflow-y: auto; overflow-x: hidden; flex: 1; - background: var(--wordlist-bg); - border-radius: 6px; - padding: 4px; min-height: 200px; + max-height: 300px; } -#wordList>div { +#wordList > div { + position: absolute; + width: calc(100% - 8px); + left: 4px; display: flex; align-items: center; - margin-bottom: 4px; - gap: 4px; - background: var(--wordlist-bg); + gap: 6px; padding: 4px; - border-radius: 6px; - will-change: transform; - flex-wrap: nowrap; - position: absolute; - left: 4px; - right: 4px; + box-sizing: border-box; + background: var(--highlight-tag); + border: 1px solid var(--highlight-tag-border); + border-radius: 30px; } #wordList input[type="text"] { - flex: 1; + flex-grow: 1; min-width: 0; background-color: var(--input-bg) !important; color: var(--text-color) !important; border: 1px solid var(--input-border) !important; + padding: 4px 8px; + border-radius: 4px; } #wordList input[type="color"] { @@ -177,12 +275,21 @@ button:hover { flex-shrink: 0; } -#wordList label { - flex-shrink: 0; - white-space: nowrap; - margin: 0; -} - input[type="file"] { display: none; -} \ No newline at end of file +} + +.section-header label { + display: flex; + align-items: center; + gap: 6px; + cursor: pointer; +} + +.section-header input[type="checkbox"] { + margin-right: 6px; +} + +#wordCount { + font-weight: normal; +} diff --git a/popup/popup.html b/popup/popup.html index b5a449e..c3ea87a 100644 --- a/popup/popup.html +++ b/popup/popup.html @@ -1,65 +1,74 @@ - Goose Highlighter + + - - +
-

Goose Highlighter

+

Goose Highlighter

-
+
+
+

Highlight Lists

+ +
+ + +
+ + +
+
+ +
+

List Settings

+ +
+ + +
- - - - -
- -
- - - - -
- -
+

Add Words

- +
-
-
- - - - - +
+

Word List (0)

+
+ + + + +
-
- - - +
+ + + +
- - \ No newline at end of file + diff --git a/popup/popup.js b/popup/popup.js index de76298..4b98ceb 100644 --- a/popup/popup.js +++ b/popup/popup.js @@ -60,6 +60,7 @@ function renderWords() { const list = lists[currentListIndex]; const fragment = document.createDocumentFragment(); + // For virtualized list, calculate visible items const itemHeight = 32; const containerHeight = wordList.clientHeight; const scrollTop = wordList.scrollTop; @@ -77,59 +78,91 @@ function renderWords() { container.style.height = `${itemHeight}px`; container.style.position = 'absolute'; container.style.top = `${i * itemHeight}px`; - container.style.width = '100%'; + container.style.width = 'calc(100% - 8px)'; + container.style.left = '4px'; + container.style.right = '4px'; + container.style.display = 'flex'; + container.style.alignItems = 'center'; + container.style.gap = '6px'; + container.style.padding = '0 4px'; container.style.boxSizing = 'border-box'; + container.style.background = 'var(--highlight-tag)'; + container.style.border = '1px solid var(--highlight-tag-border)'; + container.style.borderRadius = '30px'; + // Checkbox for selection const cbSelect = document.createElement("input"); cbSelect.type = "checkbox"; + cbSelect.className = "word-checkbox"; cbSelect.dataset.index = i; if (selectedCheckboxes.has(i)) { cbSelect.checked = true; } + // Text input for word const inputWord = document.createElement("input"); inputWord.type = "text"; inputWord.value = w.wordStr; inputWord.dataset.wordEdit = i; + inputWord.style.flexGrow = '1'; + inputWord.style.minWidth = '0'; + inputWord.style.padding = '4px 8px'; + inputWord.style.borderRadius = '4px'; + inputWord.style.border = '1px solid var(--input-border)'; + inputWord.style.backgroundColor = 'var(--input-bg)'; + inputWord.style.color = 'var(--text-color)'; + // Background color picker const inputBg = document.createElement("input"); inputBg.type = "color"; inputBg.value = w.background || list.background; inputBg.dataset.bgEdit = i; + inputBg.style.width = '24px'; + inputBg.style.height = '24px'; + inputBg.style.flexShrink = '0'; + // Foreground color picker const inputFg = document.createElement("input"); inputFg.type = "color"; inputFg.value = w.foreground || list.foreground; inputFg.dataset.fgEdit = i; + inputFg.style.width = '24px'; + inputFg.style.height = '24px'; + inputFg.style.flexShrink = '0'; - const labelActive = document.createElement("label"); + // Active checkbox container + const activeContainer = document.createElement("label"); + activeContainer.className = "word-active"; + activeContainer.style.display = 'flex'; + activeContainer.style.alignItems = 'center'; + activeContainer.style.gap = '4px'; + activeContainer.style.flexShrink = '0'; + + // Active checkbox const cbActive = document.createElement("input"); cbActive.type = "checkbox"; - if (w.active) cbActive.checked = true; + cbActive.checked = w.active !== false; cbActive.dataset.activeEdit = i; - labelActive.appendChild(cbActive); - labelActive.appendChild(document.createTextNode(" " + chrome.i18n.getMessage("word_active_label"))); + cbActive.className = "switch"; + + activeContainer.appendChild(cbActive); container.appendChild(cbSelect); container.appendChild(inputWord); container.appendChild(inputBg); container.appendChild(inputFg); - container.appendChild(labelActive); - - const styles = getComputedStyle(document.documentElement); - const bg = styles.getPropertyValue('--input-bg').trim(); - const fg = styles.getPropertyValue('--text-color').trim(); - const border = styles.getPropertyValue('--input-border').trim(); - - inputWord.style.backgroundColor = bg; - inputWord.style.color = fg; - inputWord.style.border = `1px solid ${border}`; + container.appendChild(activeContainer); fragment.appendChild(container); } wordList.innerHTML = ''; wordList.appendChild(fragment); + + const wordCount = document.getElementById('wordCount'); + if (wordCount) { + wordCount.textContent = list.words.length; + } } document.getElementById("selectAllBtn").onclick = () => { @@ -250,13 +283,13 @@ wordList.addEventListener("input", e => { wordList.addEventListener("change", e => { if (e.target.type === "checkbox") { - if (e.target.dataset.index != null) { // Word selection checkbox + if (e.target.dataset.index != null) { if (e.target.checked) { selectedCheckboxes.add(+e.target.dataset.index); } else { selectedCheckboxes.delete(+e.target.dataset.index); } - } else if (e.target.dataset.activeEdit != null) { // Active checkbox + } else if (e.target.dataset.activeEdit != null) { lists[currentListIndex].words[e.target.dataset.activeEdit].active = e.target.checked; debouncedSave(); } @@ -317,17 +350,24 @@ const toggle = document.getElementById('themeToggle'); const body = document.body; const savedTheme = localStorage.getItem('theme'); -if (savedTheme === 'dark') { +if (savedTheme === 'light') { + body.classList.remove('dark'); + body.classList.add('light'); + toggle.checked = false; +} else { body.classList.add('dark'); + body.classList.remove('light'); toggle.checked = true; } toggle.addEventListener('change', () => { if (toggle.checked) { body.classList.add('dark'); + body.classList.remove('light'); localStorage.setItem('theme', 'dark'); } else { body.classList.remove('dark'); + body.classList.add('light'); localStorage.setItem('theme', 'light'); } }); @@ -337,4 +377,4 @@ document.getElementById("deselectAllBtn").onclick = () => { renderWords(); }; -load(); \ No newline at end of file +load();