diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index cb53943..99cceb0 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,3 @@ -ignoredBuiltDependencies: - - '@swc/core' - - esbuild +allowBuilds: + '@swc/core': true + esbuild: true diff --git a/public/background/background.js b/public/background/background.js index 8da9602..c16f9e4 100644 --- a/public/background/background.js +++ b/public/background/background.js @@ -12,7 +12,7 @@ chrome.runtime.onInstalled.addListener((details) => { chrome.storage.sync.set({ enabled: true, autoHide: true, - hideDelay: 5000, + hideDelay: 5, }); } else if (details.reason === "update") { console.log("SuperBook extension updated"); @@ -22,8 +22,8 @@ chrome.runtime.onInstalled.addListener((details) => { // Handle extension icon click chrome.action.onClicked.addListener((tab) => { // Toggle extension on/off for current tab - chrome.storage.sync.get(["enabled"], (result) => { - const newState = !result.enabled; + chrome.storage.sync.get(["enabled"], (result) => { + const newState = !(result && result.enabled); chrome.storage.sync.set({ enabled: newState }); // Update icon to reflect state @@ -79,9 +79,9 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { if (message.action === "getSettings") { chrome.storage.sync.get(["enabled", "autoHide", "hideDelay"], (result) => { sendResponse({ - enabled: result.enabled !== false, // Default to true - autoHide: result.autoHide !== false, // Default to true - hideDelay: result.hideDelay || 5000, // Default to 5 seconds + enabled: result ? result.enabled !== false : true, + autoHide: result ? result.autoHide !== false : true, + hideDelay: result && result.hideDelay ? result.hideDelay : 5, }); }); return true; // Keep message channel open for async response @@ -90,5 +90,5 @@ chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { // Initialize icon state on startup chrome.storage.sync.get(["enabled"], (result) => { - updateIcon(result.enabled !== false); + updateIcon(result ? result.enabled !== false : true); }); diff --git a/public/content/content.js b/public/content/content.js index 8c45b07..35db767 100644 --- a/public/content/content.js +++ b/public/content/content.js @@ -8,6 +8,9 @@ let tooltipEl = null; let hideHoverTimeout = null; let isInteracting = false; let enabled = true; +let autoHide = true; +let hideDelay = 5; +let hideTooltipTimeout = null; let lastSelectionRect = null; let isInitialized = false; @@ -34,8 +37,10 @@ function initializeSuperBook() { try { chrome.runtime.sendMessage({ action: "getSettings" }, (res) => { - if (res && typeof res.enabled !== "undefined") { - enabled = !!res.enabled; + if (res) { + if (typeof res.enabled !== "undefined") enabled = !!res.enabled; + if (typeof res.autoHide !== "undefined") autoHide = !!res.autoHide; + if (typeof res.hideDelay !== "undefined") hideDelay = res.hideDelay; } }); } catch (_) {} @@ -49,6 +54,23 @@ function initializeSuperBook() { removeTooltip(); } } + if (message && message.action === "showSettings") { + showSettingsPanel(); + } + }); + } catch (_) {} + + try { + chrome.storage.onChanged.addListener((changes, area) => { + if (area === "sync") { + if (changes.enabled) enabled = !!changes.enabled.newValue; + if (changes.autoHide) autoHide = !!changes.autoHide.newValue; + if (changes.hideDelay) hideDelay = changes.hideDelay.newValue; + if (!enabled) { + hideHoverButton(); + removeTooltip(); + } + } }); } catch (_) {} } @@ -163,6 +185,16 @@ function createHoverButton() { return btn; } +//Auto hide function +function startAutoHide() { + clearTimeout(hideTooltipTimeout); + if (autoHide && hideDelay > 0) { + hideTooltipTimeout = setTimeout(function() { + removeTooltip(); + }, hideDelay * 1000); + } +} + function showHoverButton(position, word) { if (!hoverButtonEl) { hoverButtonEl = createHoverButton(); @@ -187,6 +219,7 @@ function hideHoverButton() { } function removeTooltip() { + clearTimeout(hideTooltipTimeout); if (tooltipEl && tooltipEl.parentNode) { tooltipEl.parentNode.removeChild(tooltipEl); } @@ -282,6 +315,7 @@ async function showTooltip(word, position) { content.innerHTML = parts.join(""); tooltipEl.classList.add("show"); + startAutoHide(); } catch (err) { clearTimeout(timeout); console.error(err); @@ -324,6 +358,7 @@ async function showTooltip(word, position) { } tooltipEl.classList.add("show"); + startAutoHide(); } }; @@ -343,6 +378,257 @@ async function showTooltip(word, position) { document.addEventListener("click", onDocClick, true); } +// Settings overlay panel +let settingsPanelEl = null; + +function createSettingsPanel() { + if (settingsPanelEl) { + settingsPanelEl.style.display = 'block'; + return settingsPanelEl; + } + + const panel = document.createElement('div'); + panel.className = 'superbook-settings-overlay'; + panel.innerHTML = ` +
+
+ SuperBook Settings + +
+
+
+

General

+
+
+ + Turn SuperBook on or off +
+ +
+
+
+

Tooltip

+
+
+ + Automatically hide after a few seconds +
+ +
+
+
+ + How long before the tooltip hides +
+ +
+
+ +
+
+ `; + + panel.querySelector('.superbook-settings-close').addEventListener('click', hideSettingsPanel); + panel.addEventListener('click', (e) => { + if (e.target === panel) hideSettingsPanel(); + }); + panel.querySelector('#sb-settings-save').addEventListener('click', saveSettingsPanel); + + document.documentElement.appendChild(panel); + settingsPanelEl = panel; + + // Inject styles + if (!document.getElementById('superbook-settings-styles')) { + const style = document.createElement('style'); + style.id = 'superbook-settings-styles'; + style.textContent = ` + .superbook-settings-overlay { + position: fixed; + top: 0; + right: 0; + width: 300px; + height: 400px; + z-index: 2147483647; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; + } + .superbook-settings-panel { + background: #1a1a1a; + border: 1px solid #333; + border-radius: 0 0 0 12px; + box-shadow: -4px 4px 24px rgba(0,0,0,0.5); + height: 100%; + display: flex; + flex-direction: column; + overflow: hidden; + } + .superbook-settings-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px 16px; + border-bottom: 1px solid #2a2a2a; + } + .superbook-settings-title { + font-size: 14px; + font-weight: 600; + color: #fff; + } + .superbook-settings-close { + background: none; + border: none; + color: #6b7280; + font-size: 20px; + cursor: pointer; + padding: 0 4px; + line-height: 1; + } + .superbook-settings-close:hover { color: #fff; } + .superbook-settings-body { + flex: 1; + padding: 16px; + overflow-y: auto; + } + .superbook-settings-section { margin-bottom: 16px; } + .superbook-settings-section h3 { + font-size: 11px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.05em; + color: #9ca3af; + margin: 0 0 12px 0; + } + .superbook-settings-row { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px 0; + border-bottom: 1px solid #2a2a2a; + gap: 12px; + } + .superbook-settings-row:last-child { border-bottom: none; padding-bottom: 0; } + .superbook-settings-row:first-child { padding-top: 0; } + .superbook-settings-row label { + font-size: 13px; + font-weight: 500; + color: #e5e5e5; + display: block; + } + .superbook-settings-desc { + font-size: 11px; + color: #6b7280; + display: block; + margin-top: 2px; + } + .superbook-settings-row input[type="number"] { + width: 60px; + padding: 4px 8px; + background: #2a2a2a; + color: #fff; + border: 1px solid #3a3a3a; + border-radius: 6px; + font-size: 13px; + text-align: center; + outline: none; + flex-shrink: 0; + } + .superbook-settings-row input[type="number"]:focus { border-color: #4ade80; } + .superbook-toggle { + position: relative; + width: 36px; + height: 20px; + flex-shrink: 0; + } + .superbook-toggle input { opacity: 0; width: 0; height: 0; } + .superbook-toggle-slider { + position: absolute; + cursor: pointer; + inset: 0; + background: #374151; + border-radius: 20px; + transition: 0.2s; + } + .superbook-toggle-slider::before { + content: ""; + position: absolute; + width: 14px; + height: 14px; + left: 3px; + bottom: 3px; + background: #fff; + border-radius: 50%; + transition: 0.2s; + } + .superbook-toggle input:checked + .superbook-toggle-slider { background: #4ade80; } + .superbook-toggle input:checked + .superbook-toggle-slider::before { transform: translateX(16px); } + #sb-settings-save { + width: 100%; + background: #4ade80; + color: #000; + border: none; + padding: 8px; + border-radius: 8px; + font-size: 13px; + font-weight: 600; + cursor: pointer; + transition: 0.2s; + margin-top: 8px; + } + #sb-settings-save:hover { background: #22c55e; } + `; + document.head.appendChild(style); + } + + return panel; +} + +function loadSettingsPanel() { + try { + chrome.storage.sync.get(['enabled', 'autoHide', 'hideDelay'], (res) => { + const enabled = res && res.enabled !== false; + const autoHide = res && res.autoHide !== false; + const hideDelay = res && res.hideDelay ? res.hideDelay : 5; + const enabledEl = document.getElementById('sb-settings-enabled'); + const autoHideEl = document.getElementById('sb-settings-autohide'); + const delayEl = document.getElementById('sb-settings-delay'); + if (enabledEl) enabledEl.checked = enabled; + if (autoHideEl) autoHideEl.checked = autoHide; + if (delayEl) delayEl.value = hideDelay; + }); + } catch (_) {} +} + +function saveSettingsPanel() { + const enabled = document.getElementById('sb-settings-enabled')?.checked ?? true; + const autoHide = document.getElementById('sb-settings-autohide')?.checked ?? true; + const hideDelay = parseInt(document.getElementById('sb-settings-delay')?.value || '5', 10); + try { + chrome.storage.sync.set({ enabled, autoHide, hideDelay }, () => { + const btn = document.getElementById('sb-settings-save'); + if (btn) { + const orig = btn.textContent; + btn.textContent = 'Saved!'; + setTimeout(() => { btn.textContent = orig; }, 1500); + } + }); + } catch (_) {} +} + +function showSettingsPanel() { + const panel = createSettingsPanel(); + panel.style.display = 'block'; + loadSettingsPanel(); +} + +function hideSettingsPanel() { + if (settingsPanelEl) settingsPanelEl.style.display = 'none'; +} + function escapeHtml(str) { return String(str) .replace(/&/g, "&") diff --git a/public/manifest.json b/public/manifest.json index 0f27290..c7da4c9 100644 --- a/public/manifest.json +++ b/public/manifest.json @@ -20,6 +20,10 @@ "48": "icons/icon48.png", "128": "icons/icon128.png" }, + "options_ui": { + "page": "options.html", + "open_in_tab": false + }, "action": { "default_popup": "popup.html" }, diff --git a/public/options.html b/public/options.html new file mode 100644 index 0000000..b4d62af --- /dev/null +++ b/public/options.html @@ -0,0 +1,89 @@ + + + + + + SuperBook Settings + + + + +
+
+
+ SuperBook Settings + +
+ +
+
+ GENERAL +
+
+ Enable Extension + Turn SuperBook on or off +
+ +
+
+ +
+ TOOLTIP +
+
+ Auto-Hide Tooltip + Automatically hide the definition after a few seconds +
+ +
+
+
+ Hide Delay (seconds) + How long before the tooltip hides +
+ +
+
+ + +
+
+ +
Settings saved
+
+ + + + diff --git a/public/options.js b/public/options.js new file mode 100644 index 0000000..022b70c --- /dev/null +++ b/public/options.js @@ -0,0 +1,52 @@ +const DEFAULTS = { enabled: true, autoHide: true, hideDelay: 5 }; + +document.addEventListener("DOMContentLoaded", () => { + function loadSettings() { + chrome.storage.sync.get(DEFAULTS, (items) => { + document.getElementById("enabled").checked = items.enabled; + document.getElementById("autoHide").checked = items.autoHide; + document.getElementById("hideDelay").value = items.hideDelay; + }); + } + + function showToast() { + const toast = document.getElementById("toast"); + toast.classList.add("show"); + setTimeout(() => toast.classList.remove("show"), 2000); + } + + document.getElementById("closeBtn").addEventListener("click", () => window.close()); + + document.getElementById("saveBtn").addEventListener("click", () => { + const settings = { + enabled: document.getElementById("enabled").checked, + autoHide: document.getElementById("autoHide").checked, + hideDelay: Number(document.getElementById("hideDelay").value), + }; + + const btn = document.getElementById("saveBtn"); + const orig = btn.textContent; + btn.textContent = "Saved!"; + btn.classList.add("saved"); + + chrome.storage.sync.set(settings, () => { + showToast(); + chrome.tabs.query({}, (tabs) => { + for (const tab of tabs) { + if (tab.id) { + chrome.tabs.sendMessage(tab.id, { + action: "toggleExtension", + enabled: settings.enabled, + }).catch(() => {}); + } + } + }); + setTimeout(() => { + btn.textContent = orig; + btn.classList.remove("saved"); + }, 1500); + }); + }); + + loadSettings(); +}); diff --git a/public/popup.css b/public/popup.css index 39e5710..a2dbf1f 100644 --- a/public/popup.css +++ b/public/popup.css @@ -1,4 +1,4 @@ -* { +*, *::before, *::after { margin: 0; padding: 0; box-sizing: border-box; @@ -6,282 +6,553 @@ body { width: 380px; - height: 500px; - background: #1e1e1e; - color: #e5e5e5; - font-family: "Fira Code", "Courier New", monospace; + background: transparent; + font-family: "Segoe UI", "Roboto", system-ui, -apple-system, sans-serif; + color: #e8eaed; + overflow: hidden; + -webkit-font-smoothing: antialiased; font-size: 13px; - line-height: 1.4; +} + +/* Master sliding container */ +.popup { + background: #202124; + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 8px; + box-shadow: 0 2px 6px rgba(0, 0, 0, 0.24); + display: flex; + width: 760px; + transition: transform 0.25s ease; overflow: hidden; } -.terminal-container { - height: 100%; - border: 1px solid #444; - border-radius: 6px; - background: #1e1e1e; +.popup.show-settings { + transform: translateX(-380px); +} + +.view { + width: 380px; + flex-shrink: 0; display: flex; flex-direction: column; - position: relative; + background: transparent; } -.terminal-header { - background: #2d2d2d; - padding: 8px 12px; - border-bottom: 1px solid #444; +/* ============================= + LIST VIEW + ============================= */ +.popup-header { display: flex; align-items: center; - gap: 8px; - border-radius: 6px 6px 0 0; + justify-content: space-between; + padding: 12px 12px 8px; } -.terminal-dots { - display: flex; - gap: 6px; +.popup-title { + font-size: 13px; + font-weight: 500; + color: #e8eaed; } -.terminal-dot { - width: 12px; - height: 12px; +.icon-only-btn { + background: none; + border: none; + color: #9aa0a6; + cursor: pointer; + width: 24px; + height: 24px; border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.1s; + flex-shrink: 0; +} + +.icon-only-btn:hover { + background: rgba(255, 255, 255, 0.06); + color: #e8eaed; } -.terminal-dot.red { - background: #ff5f56; +.popup-body { + padding: 0 4px 8px; + max-height: 480px; + overflow-y: auto; +} + +.popup-body::-webkit-scrollbar { + width: 3px; +} + +.popup-body::-webkit-scrollbar-track { + background: transparent; } -.terminal-dot.yellow { - background: #ffbd2e; +.popup-body::-webkit-scrollbar-thumb { + background: rgba(255, 255, 255, 0.1); + border-radius: 4px; } -.terminal-dot.green { - background: #27ca3f; +.section { + padding: 8px 4px 0; } -.terminal-title { +.section-header { + display: flex; + align-items: center; + margin-bottom: 2px; +} + +.section-title { font-size: 12px; - color: #999; - margin-left: 8px; + font-weight: 500; + color: #9aa0a6; } -.terminal-body { - flex: 1; - padding: 16px; +.section-desc { + font-size: 12px; + color: #9aa0a6; + margin-bottom: 4px; + line-height: 1.4; + padding: 0 4px; +} + +.ext-list { display: flex; flex-direction: column; - gap: 16px; - overflow: hidden; + gap: 1px; } -.input-section { +.ext-row { display: flex; align-items: center; - gap: 8px; + justify-content: space-between; + padding: 6px 8px; + border-radius: 8px; + transition: background 0.1s; + user-select: none; + min-height: 44px; } -.prompt { - color: #4ade80; - font-weight: 500; +.clickable-row { + cursor: pointer; } -.input-container { +.ext-row:hover { + background: rgba(255, 255, 255, 0.06); +} + +.ext-info { + display: flex; + align-items: center; + gap: 12px; flex: 1; - position: relative; + min-width: 0; } -.word-input { - background: transparent; - border: none; - color: #e5e5e5; - font-family: inherit; - font-size: inherit; - width: 100%; - outline: none; - padding: 2px 0; +.ext-logo { + width: 28px; + height: 28px; + border-radius: 4px; + display: flex; + align-items: center; + justify-content: center; + flex-shrink: 0; } -.word-input::placeholder { - color: #666; +.sb-logo-container { + background: #ffffff; } -.cursor { - display: inline-block; - width: 8px; - height: 16px; - background: #e5e5e5; - animation: blink 1s infinite; - margin-left: 2px; +.vb-logo-container { + background: linear-gradient(135deg, #f4511e, #ff6d00); + color: #ffffff; } -@keyframes blink { - 0%, - 50% { - opacity: 1; - } - 51%, - 100% { - opacity: 0; - } +.ext-name { + font-size: 13px; + font-weight: 400; + color: #e8eaed; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } -.output-section { - flex: 1; - overflow-y: auto; - scrollbar-width: thin; - scrollbar-color: #444 #1e1e1e; +.ext-actions { + display: flex; + align-items: center; + gap: 2px; + flex-shrink: 0; } -.output-section::-webkit-scrollbar { - width: 6px; +.action-pin-btn, .action-menu-btn { + color: #9aa0a6; + opacity: 0.7; } -.output-section::-webkit-scrollbar-track { - background: #1e1e1e; +.action-pin-btn:hover, .action-menu-btn:hover { + opacity: 1; + color: #e8eaed; } -.output-section::-webkit-scrollbar-thumb { - background: #444; - border-radius: 3px; +.popup-footer { + border-top: 1px solid rgba(255, 255, 255, 0.06); + padding: 4px 4px; } -.output-section::-webkit-scrollbar-thumb:hover { - background: #555; +.footer-btn { + display: flex; + align-items: center; + gap: 10px; + width: 100%; + padding: 8px 8px; + background: none; + border: none; + border-radius: 8px; + color: #e8eaed; + font-size: 12px; + font-weight: 400; + font-family: inherit; + cursor: pointer; + transition: background 0.1s; + text-align: left; } -.output-line { - margin-bottom: 8px; - word-wrap: break-word; +.footer-btn:hover { + background: rgba(255, 255, 255, 0.06); } -.command-line { - color: #4ade80; +.gear-icon { + color: #9aa0a6; } -.word-title { - color: #60a5fa; - font-weight: 600; - font-size: 16px; - margin-bottom: 4px; +/* ============================= + SETTINGS VIEW (Chromium-style) + ============================= */ +.settings-view { + width: 380px; + flex-shrink: 0; + display: flex; + flex-direction: column; + background: transparent; } -.phonetic { - color: #fbbf24; - font-style: italic; - margin-bottom: 8px; +.settings-header { + display: flex; + align-items: center; + justify-content: space-between; + padding: 12px 12px 8px; + border-bottom: 1px solid rgba(255, 255, 255, 0.06); } -.part-of-speech { - color: #a855f7; +.settings-title-text { + font-size: 13px; font-weight: 500; - margin-bottom: 4px; + color: #e8eaed; } -.definition { - color: #e5e5e5; - margin-bottom: 8px; - padding-left: 16px; - border-left: 2px solid #444; +.icon-btn { + background: none; + border: none; + color: #9aa0a6; + cursor: pointer; + width: 28px; + height: 28px; + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + transition: background 0.1s; + flex-shrink: 0; } -.example { - color: #9ca3af; - font-style: italic; - margin-bottom: 8px; - padding-left: 16px; - border-left: 2px solid #374151; +.icon-btn:hover { + background: rgba(255, 255, 255, 0.06); + color: #e8eaed; } -.synonyms { - color: #10b981; - margin-bottom: 8px; +.settings-body { + padding: 12px 12px 16px; + display: flex; + flex-direction: column; + gap: 12px; } -.synonyms-list { - color: #6ee7b7; - margin-left: 8px; +/* Cards */ +.settings-card { + background: #2d2e30; + border: 1px solid rgba(255, 255, 255, 0.04); + border-radius: 8px; + padding: 14px 16px; } -.error { - color: #ef4444; +.card-label { + font-size: 11px; + font-weight: 500; + text-transform: uppercase; + letter-spacing: 0.06em; + color: #9aa0a6; + display: block; + margin-bottom: 12px; } -.loading { - color: #fbbf24; +.setting-row { display: flex; align-items: center; - gap: 8px; + justify-content: space-between; + padding: 8px 0; + border-bottom: 1px solid rgba(255, 255, 255, 0.04); + gap: 12px; +} + +.setting-row:last-child { + border-bottom: none; + padding-bottom: 0; +} + +.setting-row:first-of-type { + padding-top: 0; +} + +.setting-info { + flex: 1; + min-width: 0; +} + +.setting-name { + font-size: 13px; + font-weight: 400; + color: #e8eaed; + display: block; +} + +.setting-desc { + font-size: 12px; + color: #9aa0a6; + margin-top: 2px; + line-height: 1.3; +} + +/* Chrome-style Toggle */ +.chrome-toggle { + position: relative; + width: 32px; + height: 16px; + flex-shrink: 0; + cursor: pointer; +} + +.chrome-toggle input { + position: absolute; + opacity: 0; + width: 0; + height: 0; } -.loading-dots { - display: inline-block; +.chrome-toggle-track { + position: absolute; + inset: 0; + background: rgba(255, 255, 255, 0.1); + border-radius: 8px; + transition: background 0.2s; } -.loading-dots::after { +.chrome-toggle-track::before { content: ""; - animation: dots 1.5s infinite; -} - -@keyframes dots { - 0%, - 20% { - content: ""; - } - 40% { - content: "."; - } - 60% { - content: ".."; - } - 80%, - 100% { - content: "..."; - } -} - -.clear-btn { position: absolute; - top: 8px; - right: 12px; - background: transparent; - border: 1px solid #444; - color: #999; - padding: 4px 8px; + width: 12px; + height: 12px; + left: 2px; + bottom: 2px; + background: #dadce0; + border-radius: 50%; + transition: transform 0.2s, background 0.2s; +} + +.chrome-toggle input:checked + .chrome-toggle-track { + background: rgba(74, 222, 128, 0.3); +} + +.chrome-toggle input:checked + .chrome-toggle-track::before { + transform: translateX(16px); + background: #4ade80; +} + +/* Number Input */ +.chrome-input { + width: 52px; + padding: 4px 6px; + background: #202124; + color: #e8eaed; + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 6px; + font-size: 13px; + font-weight: 400; + text-align: center; + outline: none; + font-family: inherit; + transition: border-color 0.15s; + flex-shrink: 0; +} + +.chrome-input:focus { + border-color: #8ab4f8; +} + +/* Save Button */ +.chrome-btn { + width: 100%; + height: 36px; + padding: 0 16px; + background: #2ea043; + color: #ffffff; + border: none; + border-radius: 8px; + font-size: 13px; + font-weight: 500; font-family: inherit; - font-size: 11px; - border-radius: 3px; cursor: pointer; - transition: all 0.2s; + transition: background 0.15s; } -.clear-btn:first-of-type { - right: 70px; +.chrome-btn:hover { + background: #2b8a3d; } -.clear-btn:hover { - background: #333; - color: #e5e5e5; - border-color: #666; +.chrome-btn:active { + background: #247334; } -.help-text { - color: #666; - font-size: 11px; - text-align: center; - margin-top: 8px; +.chrome-btn.saved { + background: #1a7333; + pointer-events: none; } -.status-indicator { - position: absolute; - bottom: 8px; - right: 12px; - font-size: 10px; - color: #666; +/* Toast */ +.toast { + position: fixed; + bottom: 12px; + left: 50%; + transform: translateX(-50%) translateY(60px); + background: #2d2e30; + border: 1px solid rgba(255, 255, 255, 0.06); + border-radius: 8px; + padding: 8px 14px; + font-size: 12px; + font-weight: 400; + color: #e8eaed; + opacity: 0; + transition: opacity 0.2s, transform 0.2s ease; + pointer-events: none; + display: flex; + align-items: center; + gap: 6px; + z-index: 1000; + white-space: nowrap; } -.status-enabled { +.toast.show { + opacity: 1; + transform: translateX(-50%) translateY(0); +} + +.toast-icon { color: #4ade80; + font-size: 13px; + font-weight: 500; +} + +/* ============================= + BACKWARD COMPAT ALIASES + ============================= */ +.toggle-switch { + position: relative; + width: 32px; + height: 16px; + flex-shrink: 0; + cursor: pointer; +} + +.toggle-switch input { + position: absolute; + opacity: 0; + width: 0; + height: 0; +} + +.toggle-slider { + position: absolute; + inset: 0; + background: rgba(255, 255, 255, 0.1); + border-radius: 8px; + transition: background 0.2s; +} + +.toggle-slider::before { + content: ""; + position: absolute; + width: 12px; + height: 12px; + left: 2px; + bottom: 2px; + background: #dadce0; + border-radius: 50%; + transition: transform 0.2s, background 0.2s; +} + +.toggle-switch input:checked + .toggle-slider { + background: rgba(74, 222, 128, 0.3); +} + +.toggle-switch input:checked + .toggle-slider::before { + transform: translateX(16px); + background: #4ade80; +} + +input[type="number"] { + width: 52px; + padding: 4px 6px; + background: #202124; + color: #e8eaed; + border: 1px solid rgba(255, 255, 255, 0.1); + border-radius: 6px; + font-size: 13px; + font-weight: 400; + text-align: center; + outline: none; + font-family: inherit; + transition: border-color 0.15s; + flex-shrink: 0; +} + +input[type="number"]:focus { + border-color: #8ab4f8; +} + +.save-btn { + width: 100%; + height: 36px; + padding: 0 16px; + background: #2ea043; + color: #ffffff; + border: none; + border-radius: 8px; + font-size: 13px; + font-weight: 500; + font-family: inherit; + cursor: pointer; + transition: background 0.15s; +} + +.save-btn:hover { + background: #2b8a3d; +} + +.save-btn:active { + background: #247334; } -.status-disabled { - color: #ef4444; +.save-btn.saved { + background: #1a7333; + pointer-events: none; } diff --git a/public/popup.html b/public/popup.html index 99cdf91..9255e83 100644 --- a/public/popup.html +++ b/public/popup.html @@ -1,63 +1,173 @@ - - - - - Dictionary Terminal - - - - - - -
-
-
-
-
-
-
-
Dictionary Terminal v1.0
- - + + + + + Extensions + + + + + + +