Switch Memos Clipper theme to emerald accent and update image handling logic in popup.js.
|
Before Width: | Height: | Size: 341 B After Width: | Height: | Size: 7.5 KiB |
|
Before Width: | Height: | Size: 99 B After Width: | Height: | Size: 454 B |
BIN
src/icons/icon32.png
Normal file
|
After Width: | Height: | Size: 1.0 KiB |
|
Before Width: | Height: | Size: 145 B After Width: | Height: | Size: 1.9 KiB |
@@ -15,12 +15,14 @@
|
||||
"default_popup": "popup.html",
|
||||
"default_icon": {
|
||||
"16": "icons/icon16.png",
|
||||
"32": "icons/logo.svg",
|
||||
"48": "icons/icon48.png",
|
||||
"128": "icons/icon128.png"
|
||||
}
|
||||
},
|
||||
"icons": {
|
||||
"16": "icons/icon16.png",
|
||||
"32": "icons/logo.svg",
|
||||
"48": "icons/icon48.png",
|
||||
"128": "icons/icon128.png"
|
||||
},
|
||||
|
||||
@@ -7,9 +7,9 @@
|
||||
--surface: #1a1a1f;
|
||||
--surface2: #22222a;
|
||||
--border: #2a2a35;
|
||||
--accent: #7c6af7;
|
||||
--accent-dim: #7c6af720;
|
||||
--accent-hover: #9585fa;
|
||||
--accent: #10b981;
|
||||
--accent-dim: #10b98120;
|
||||
--accent-hover: #059669;
|
||||
--text: #e8e8f0;
|
||||
--text-dim: #777788;
|
||||
--text-muted: #444455;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<body>
|
||||
<!-- ── Loading ── -->
|
||||
<div id="view-loading" class="view flex flex-col items-center justify-center p-8 space-y-4">
|
||||
<div class="spinner animate-spin rounded-full h-8 w-8 border-b-2 border-blue-500"></div>
|
||||
<div class="spinner animate-spin rounded-full h-8 w-8 border-b-2 border-emerald-500"></div>
|
||||
<span class="text-gray-600">Extracting content…</span>
|
||||
</div>
|
||||
|
||||
@@ -22,19 +22,20 @@
|
||||
</svg>
|
||||
</div>
|
||||
<p class="text-gray-700 mb-4 font-medium">Configure your Memos instance first.</p>
|
||||
<button id="open-settings-btn" class="bg-blue-600 hover:bg-blue-700 text-white px-4 py-2 rounded shadow transition">Open Settings</button>
|
||||
<button id="open-settings-btn" class="bg-emerald-500 hover:bg-emerald-600 text-white px-4 py-2 rounded shadow transition">Open Settings</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ── Main editor ── -->
|
||||
<div id="view-main" class="view hidden">
|
||||
<header class="flex items-center justify-between p-3 border-b border-gray-100 bg-white sticky top-0 z-10">
|
||||
<div class="logo flex items-center space-x-2 text-blue-600">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="18" height="18">
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||
<polyline points="14 2 14 8 20 8"/>
|
||||
<line x1="16" y1="13" x2="8" y2="13"/>
|
||||
<line x1="16" y1="17" x2="8" y2="17"/>
|
||||
<div class="logo flex items-center space-x-2 text-emerald-500">
|
||||
<svg viewBox="0 0 32 32" fill="none" width="18" height="18" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="32" height="32" rx="8" fill="currentColor"/>
|
||||
<path d="M11 9C11 8.44772 11.4477 8 12 8H20C20.5523 8 21 8.44772 21 9V23C21 23.5523 20.5523 24 20 24H12C11.4477 24 11 23.5523 11 23V9Z" fill="white"/>
|
||||
<path d="M14 12H18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M14 15H18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M14 18H16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<span id="page-title" class="page-title font-semibold text-gray-800 truncate max-w-[180px]">Clip to Memos</span>
|
||||
</div>
|
||||
@@ -62,7 +63,7 @@
|
||||
|
||||
<!-- edit panel -->
|
||||
<div id="tab-edit" class="tab-panel flex flex-col h-96 border-b border-gray-100">
|
||||
<textarea rows="14" id="md-editor" spellcheck="false" placeholder="Markdown content…" class="flex-1 w-full p-3 text-sm resize-none focus:outline-none focus:ring-1 focus:ring-blue-100"></textarea>
|
||||
<textarea rows="14" id="md-editor" spellcheck="false" placeholder="Markdown content…" class="flex-1 w-full p-3 text-sm resize-none focus:outline-none focus:ring-1 focus:ring-emerald-100"></textarea>
|
||||
<div id="char-counter" class="char-counter text-right px-3 py-1 text-[10px] text-gray-400">0 chars</div>
|
||||
</div>
|
||||
|
||||
@@ -91,7 +92,7 @@
|
||||
<!-- footer -->
|
||||
<footer class="flex items-center justify-between p-3 bg-gray-50">
|
||||
<div class="footer-left">
|
||||
<select id="visibility-select" class="text-xs border border-gray-200 rounded px-2 py-1 bg-white focus:outline-none focus:ring-1 focus:ring-blue-400 transition">
|
||||
<select id="visibility-select" class="text-xs border border-gray-200 rounded px-2 py-1 bg-white focus:outline-none focus:ring-1 focus:ring-emerald-400 transition">
|
||||
<option value="PRIVATE">🔒 Private</option>
|
||||
<option value="PROTECTED">🔗 Protected</option>
|
||||
<option value="PUBLIC">🌐 Public</option>
|
||||
@@ -99,7 +100,7 @@
|
||||
</div>
|
||||
<div class="footer-right flex space-x-2">
|
||||
<button id="reload-btn" class="secondary-btn p-1.5 border border-gray-200 rounded hover:bg-white transition text-gray-500" title="Re-clip page">↺</button>
|
||||
<button id="send-btn" class="send-btn bg-blue-600 hover:bg-blue-700 text-white px-4 py-1.5 rounded shadow flex items-center space-x-2 transition">
|
||||
<button id="send-btn" class="send-btn bg-emerald-500 hover:bg-emerald-600 text-white px-4 py-1.5 rounded shadow flex items-center space-x-2 transition">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" width="14" height="14">
|
||||
<line x1="22" y1="2" x2="11" y2="13"/>
|
||||
<polygon points="22 2 15 22 11 13 2 9 22 2"/>
|
||||
|
||||
17
src/popup.js
@@ -152,8 +152,8 @@ function renderImages() {
|
||||
// Sync keep flags back (dedup may have removed some)
|
||||
state.images = visible;
|
||||
|
||||
const uploadable = visible.filter((img) => !img.src.startsWith("data:")).length;
|
||||
imgCount.textContent = uploadable;
|
||||
const kept = visible.filter((img) => img.keep).length;
|
||||
imgCount.textContent = kept;
|
||||
imagesList.innerHTML = "";
|
||||
|
||||
if (!visible.length) {
|
||||
@@ -176,20 +176,16 @@ function renderImages() {
|
||||
? `inline-image-${i + 1}`
|
||||
: (img.src.split("/").pop().split("?")[0].slice(0, 28) || `image-${i + 1}`);
|
||||
label.textContent = name;
|
||||
if (isDataUri) label.title = "Embedded data URI — cannot be uploaded";
|
||||
|
||||
const remove = document.createElement("button");
|
||||
remove.className = "remove-img";
|
||||
remove.textContent = "×";
|
||||
remove.title = img.keep ? "Exclude this image" : "Include this image";
|
||||
if (isDataUri) {
|
||||
remove.style.display = "none"; // data URIs can't be uploaded anyway
|
||||
}
|
||||
remove.addEventListener("click", () => {
|
||||
img.keep = !img.keep;
|
||||
chip.classList.toggle("skipped", !img.keep);
|
||||
remove.title = img.keep ? "Exclude this image" : "Include this image";
|
||||
const kept = state.images.filter((im) => im.keep && !im.src.startsWith("data:")).length;
|
||||
const kept = state.images.filter((im) => im.keep).length;
|
||||
imgCount.textContent = kept;
|
||||
});
|
||||
|
||||
@@ -260,7 +256,7 @@ sendBtn.addEventListener("click", async () => {
|
||||
// 1. Upload images if requested
|
||||
const imageMap = new Map(); // originalUrl -> resourceName
|
||||
if (attachCheck.checked) {
|
||||
const toUpload = state.images.filter((img) => img.keep && !img.src.startsWith("data:"));
|
||||
const toUpload = state.images.filter((img) => img.keep);
|
||||
let uploaded = 0;
|
||||
for (const img of toUpload) {
|
||||
sendBtn.textContent = `Uploading image ${uploaded + 1}/${toUpload.length}…`;
|
||||
@@ -363,7 +359,10 @@ async function uploadImage(baseUrl, token, img) {
|
||||
const blob = await response.blob();
|
||||
|
||||
// Derive a filename with a valid extension
|
||||
let filename = img.src.split("/").pop().split("?")[0].split("#")[0];
|
||||
let filename = "image";
|
||||
if (!img.src.startsWith("data:")) {
|
||||
filename = img.src.split("/").pop().split("?")[0].split("#")[0] || "image";
|
||||
}
|
||||
// Strip non-filename characters
|
||||
filename = filename.replace(/[^a-zA-Z0-9._-]/g, "_").slice(0, 80);
|
||||
// If no extension, infer from MIME type
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
--bg: #0f0f11;
|
||||
--surface: #1a1a1f;
|
||||
--border: #2a2a35;
|
||||
--accent: #7c6af7;
|
||||
--accent-dim: #7c6af730;
|
||||
--accent: #10b981;
|
||||
--accent-dim: #10b98130;
|
||||
--text: #e8e8f0;
|
||||
--text-dim: #888899;
|
||||
--success: #4ade80;
|
||||
|
||||
@@ -9,13 +9,13 @@
|
||||
<body>
|
||||
<div class="page">
|
||||
<header class="p-6 border-b border-gray-100 bg-white">
|
||||
<div class="logo flex items-center space-x-3 text-2xl font-bold text-blue-600">
|
||||
<svg class="w-8 h-8" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
|
||||
<polyline points="14 2 14 8 20 8"/>
|
||||
<line x1="16" y1="13" x2="8" y2="13"/>
|
||||
<line x1="16" y1="17" x2="8" y2="17"/>
|
||||
<polyline points="10 9 9 9 8 9"/>
|
||||
<div class="logo flex items-center space-x-3 text-2xl font-bold text-emerald-500">
|
||||
<svg viewBox="0 0 32 32" fill="none" width="32" height="32" xmlns="http://www.w3.org/2000/svg">
|
||||
<rect width="32" height="32" rx="8" fill="currentColor"/>
|
||||
<path d="M11 9C11 8.44772 11.4477 8 12 8H20C20.5523 8 21 8.44772 21 9V23C21 23.5523 20.5523 24 20 24H12C11.4477 24 11 23.5523 11 23V9Z" fill="white"/>
|
||||
<path d="M14 12H18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M14 15H18" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<path d="M14 18H16" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</svg>
|
||||
<span>Memos Clipper Settings</span>
|
||||
</div>
|
||||
@@ -26,17 +26,17 @@
|
||||
<h2 class="text-xl font-semibold text-gray-800 border-b pb-2">Connection</h2>
|
||||
<label class="block space-y-2">
|
||||
<span class="text-sm font-medium text-gray-700">Memos Instance URL</span>
|
||||
<input type="url" id="memos-url" placeholder="https://memos.example.com" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-100 focus:border-blue-400 outline-none transition" />
|
||||
<input type="url" id="memos-url" placeholder="https://memos.example.com" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-emerald-100 focus:border-emerald-400 outline-none transition" />
|
||||
<small class="block text-xs text-gray-400">The base URL of your usememos instance (no trailing slash)</small>
|
||||
</label>
|
||||
<label class="block space-y-2">
|
||||
<span class="text-sm font-medium text-gray-700">API Token</span>
|
||||
<input type="password" id="api-token" placeholder="Your access token" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-100 focus:border-blue-400 outline-none transition" />
|
||||
<input type="password" id="api-token" placeholder="Your access token" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-emerald-100 focus:border-emerald-400 outline-none transition" />
|
||||
<small class="block text-xs text-gray-400">Settings → Account → Access Tokens in your Memos instance</small>
|
||||
</label>
|
||||
<div class="actions flex space-x-3 pt-2">
|
||||
<button id="test-btn" class="secondary flex-1 bg-gray-50 hover:bg-gray-100 text-gray-700 font-medium py-2 px-4 rounded-lg border border-gray-200 transition">Test Connection</button>
|
||||
<button id="save-btn" class="flex-1 bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg shadow-sm transition">Save Settings</button>
|
||||
<button id="save-btn" class="flex-1 bg-emerald-500 hover:bg-emerald-600 text-white font-medium py-2 px-4 rounded-lg shadow-sm transition">Save Settings</button>
|
||||
</div>
|
||||
<div id="status" class="status hidden p-3 rounded-lg text-sm"></div>
|
||||
</div>
|
||||
@@ -45,7 +45,7 @@
|
||||
<h2 class="text-xl font-semibold text-gray-800 border-b pb-2">Defaults</h2>
|
||||
<label class="block space-y-2">
|
||||
<span class="text-sm font-medium text-gray-700">Default visibility</span>
|
||||
<select id="visibility" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-100 focus:border-blue-400 outline-none bg-white transition">
|
||||
<select id="visibility" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-emerald-100 focus:border-emerald-400 outline-none bg-white transition">
|
||||
<option value="PRIVATE">Private</option>
|
||||
<option value="PROTECTED">Protected</option>
|
||||
<option value="PUBLIC">Public</option>
|
||||
@@ -53,23 +53,23 @@
|
||||
</label>
|
||||
<label class="block space-y-2">
|
||||
<span class="text-sm font-medium text-gray-700">Default clip mode</span>
|
||||
<select id="clip-mode" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-blue-100 focus:border-blue-400 outline-none bg-white transition">
|
||||
<select id="clip-mode" class="w-full px-4 py-2 border border-gray-200 rounded-lg focus:ring-2 focus:ring-emerald-100 focus:border-emerald-400 outline-none bg-white transition">
|
||||
<option value="page">Full page (article extraction)</option>
|
||||
<option value="selection">Selection only</option>
|
||||
</select>
|
||||
</label>
|
||||
<div class="space-y-3 pt-2">
|
||||
<label class="flex items-center space-x-3 cursor-pointer group">
|
||||
<input type="checkbox" id="include-images" checked class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500 transition" />
|
||||
<input type="checkbox" id="include-images" checked class="w-4 h-4 text-emerald-500 border-gray-300 rounded focus:ring-emerald-400 transition" />
|
||||
<span class="text-sm text-gray-700 group-hover:text-gray-900 transition">Upload page images as attachments</span>
|
||||
</label>
|
||||
<label class="flex items-center space-x-3 cursor-pointer group">
|
||||
<input type="checkbox" id="include-tags" class="w-4 h-4 text-blue-600 border-gray-300 rounded focus:ring-blue-500 transition" />
|
||||
<input type="checkbox" id="include-tags" class="w-4 h-4 text-emerald-500 border-gray-300 rounded focus:ring-emerald-400 transition" />
|
||||
<span class="text-sm text-gray-700 group-hover:text-gray-900 transition">Automatically add #clipped tag</span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="actions pt-4">
|
||||
<button id="save-defaults-btn" class="w-full bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg shadow-sm transition">Save Defaults</button>
|
||||
<button id="save-defaults-btn" class="w-full bg-emerald-500 hover:bg-emerald-600 text-white font-medium py-2 px-4 rounded-lg shadow-sm transition">Save Defaults</button>
|
||||
</div>
|
||||
<div id="defaults-status" class="status hidden p-3 rounded-lg text-sm"></div>
|
||||
</div>
|
||||
|
||||