feat: add selected images panel and clear-all button

- New "已选" tab shows all selected images in a grid; each card has
  an X button (top-right) to remove that image from the selection
- "清除全部" button in header clears all selections at once
- illustCache persists illust thumbnails across modal opens so the
  panel can display images selected in previous sessions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
wrt122311
2026-04-24 12:28:54 +08:00
co-authored by Claude Sonnet 4.6
parent 96bcf56cea
commit b26e9473f2
2 changed files with 117 additions and 0 deletions
+32
View File
@@ -168,6 +168,38 @@
text-overflow: ellipsis;
}
#pixiv-clear-all-btn {
padding: 4px 10px;
background: transparent;
border: 1px solid #45475a;
color: #7f849c;
border-radius: 4px;
cursor: pointer;
font-size: 12px;
}
#pixiv-clear-all-btn:hover { color: #f38ba8; border-color: #f38ba8; }
.pixiv-card-remove-btn {
position: absolute;
top: 4px;
right: 4px;
background: rgba(243, 139, 168, 0.85);
color: #1e1e2e;
border: none;
border-radius: 50%;
width: 20px;
height: 20px;
display: flex;
align-items: center;
justify-content: center;
font-size: 11px;
font-weight: bold;
cursor: pointer;
line-height: 1;
padding: 0;
}
.pixiv-card-remove-btn:hover { background: #f38ba8; }
.pixiv-seq-badge {
position: absolute;
top: 4px;
+85
View File
@@ -11,6 +11,9 @@ const state = {
artistNextUrl: null,
};
// Persists across modal opens so the "已选" panel can show thumbnails
const illustCache = new Map();
// ── CSS injection ─────────────────────────────────────────────────────────────
function injectCSS() {
@@ -34,6 +37,9 @@ function escapeHtml(str) {
function updateSelectedCount() {
const el = document.getElementById("pixiv-selected-count");
if (el) el.textContent = `已选 ${state.selectedIds.length} 张`;
const tabEl = document.getElementById("pixiv-selected-tab");
if (tabEl) tabEl.textContent = state.selectedIds.length > 0
? `已选 (${state.selectedIds.length})` : "已选";
}
// ── Modal DOM ─────────────────────────────────────────────────────────────────
@@ -46,6 +52,7 @@ function buildModal() {
<div id="pixiv-modal-header">
<h2>📷 Pixiv Browser</h2>
<span id="pixiv-selected-count">已选 0 张</span>
<button id="pixiv-clear-all-btn" title="清除全部选择">清除全部</button>
<button id="pixiv-close-btn" title="关闭">✕</button>
</div>
<div id="pixiv-tabs">
@@ -53,6 +60,7 @@ function buildModal() {
<button class="pixiv-tab" data-tab="ranking">排行榜</button>
<button class="pixiv-tab" data-tab="bookmarks">收藏</button>
<button class="pixiv-tab" data-tab="artists">画师</button>
<button class="pixiv-tab" data-tab="selected" id="pixiv-selected-tab">已选</button>
</div>
<div id="pixiv-content"></div>
<div id="pixiv-modal-footer">
@@ -99,6 +107,19 @@ async function openModal(node, idsWidget) {
closeModal();
});
document.getElementById("pixiv-clear-all-btn").addEventListener("click", () => {
state.selectedIds.length = 0;
updateSelectedCount();
if (state.activeTab === "selected") {
renderSelectedPane(contentEl);
} else {
document.querySelectorAll(".pixiv-card.selected").forEach(card => {
card.classList.remove("selected");
card.querySelector(".pixiv-seq-badge")?.remove();
});
}
});
// Tab buttons
document.querySelectorAll(".pixiv-tab").forEach(btn => {
btn.addEventListener("click", () => switchTab(btn.dataset.tab, contentEl));
@@ -289,6 +310,10 @@ async function openMainBrowser(contentEl) {
renderArtistPane(contentEl);
return;
}
if (state.activeTab === "selected") {
renderSelectedPane(contentEl);
return;
}
contentEl.innerHTML = `
<div id="pixiv-grid-pane">
<div class="pixiv-grid" id="pixiv-image-grid"></div>
@@ -347,6 +372,7 @@ function appendIllusts(illusts, gridEl) {
}
function createCard(illust) {
illustCache.set(String(illust.id), illust);
const card = document.createElement("div");
card.className = "pixiv-card";
card.dataset.id = String(illust.id);
@@ -399,6 +425,65 @@ function setupInfiniteScroll(tab) {
}, { rootMargin: "200px" }).observe(sentinel);
}
// ── Selected pane ─────────────────────────────────────────────────────────────
function renderSelectedPane(contentEl) {
contentEl.innerHTML = `
<div id="pixiv-grid-pane">
<div class="pixiv-grid" id="pixiv-selected-grid"></div>
</div>
`;
const grid = document.getElementById("pixiv-selected-grid");
if (state.selectedIds.length === 0) {
grid.innerHTML = `<div style="color:#7f849c;padding:40px;text-align:center;grid-column:1/-1">尚未选择任何图片</div>`;
return;
}
for (const id of [...state.selectedIds]) {
const illust = illustCache.get(id);
const card = document.createElement("div");
card.className = "pixiv-card selected";
card.dataset.id = id;
if (illust) {
const thumb = `/pixiv/image_proxy?url=${encodeURIComponent(illust.image_urls.medium)}`;
card.innerHTML = `
<img src="${thumb}" alt="${escapeHtml(illust.title)}" loading="lazy" />
<div class="pixiv-card-title">${escapeHtml(illust.title)}</div>
<div class="pixiv-seq-badge">${state.selectedIds.indexOf(id) + 1}</div>
<button class="pixiv-card-remove-btn" title="取消选择">✕</button>
`;
} else {
card.innerHTML = `
<div style="width:100%;aspect-ratio:1;background:#313244;display:flex;align-items:center;justify-content:center;color:#7f849c;font-size:12px">${id}</div>
<div class="pixiv-card-title">ID: ${escapeHtml(id)}</div>
<button class="pixiv-card-remove-btn" title="取消选择">✕</button>
`;
}
card.querySelector(".pixiv-card-remove-btn").addEventListener("click", () => {
const idx = state.selectedIds.indexOf(id);
if (idx !== -1) {
state.selectedIds.splice(idx, 1);
card.remove();
updateSelectedCount();
if (state.selectedIds.length === 0) {
grid.innerHTML = `<div style="color:#7f849c;padding:40px;text-align:center;grid-column:1/-1">尚未选择任何图片</div>`;
} else {
// Update remaining badge numbers
grid.querySelectorAll(".pixiv-card").forEach(c => {
const badge = c.querySelector(".pixiv-seq-badge");
if (badge) badge.textContent = state.selectedIds.indexOf(c.dataset.id) + 1;
});
}
}
});
grid.appendChild(card);
}
}
// ── Artist tab ────────────────────────────────────────────────────────────────
async function renderArtistPane(contentEl) {