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 = `
+
+
+
+
+
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
+
+
+
+
+
+
+
+
+
+
+
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
-
-
-
-
-
-
-
-