1
0

Enhance popup and HUD functionality: add clear archive and whitelist buttons, improve styling and layout

This commit is contained in:
Chipperfluff 2026-01-20 06:21:42 +01:00
parent 49bbce95ea
commit 88abb559d1
3 changed files with 118 additions and 35 deletions

View File

@ -69,13 +69,13 @@ function injectStyleOnce() {
width: 520px;
height: 520px;
overflow: auto;
padding: 10px;
border-radius: 10px;
border: 1px solid #b04a00;
background: #fff6e8;
color: #2b2014;
padding: 0;
border-radius: 12px;
border: 1px solid #9b3b0c;
background: radial-gradient(circle at 20% 10%, #2b2b2b, #151515 60%);
color: #f5efe6;
font-size: 12px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
box-shadow: 0 10px 28px rgba(0, 0, 0, 0.35);
z-index: 2147483647;
}
#${HUD_PANEL_ID}[data-${DATA_PREFIX}-hidden="true"] {
@ -83,17 +83,24 @@ function injectStyleOnce() {
}
.${DATA_PREFIX}-hud-title {
font-weight: 700;
margin: 0 0 8px;
margin: 0;
padding: 12px 14px;
text-transform: uppercase;
font-size: 11px;
letter-spacing: 0.4px;
font-size: 12px;
letter-spacing: 0.6px;
background: linear-gradient(90deg, #e35b14, #c9490e);
border-bottom: 2px solid #b2410e;
color: #fff8ee;
}
.${DATA_PREFIX}-hud-body {
padding: 10px 12px 14px;
}
.${DATA_PREFIX}-channel {
margin: 6px 0;
margin: 8px 0;
padding: 6px 8px;
border-radius: 8px;
background: #fffaf0;
border: 1px solid #e2d7be;
border-radius: 10px;
background: rgba(15, 15, 15, 0.55);
border: 1px solid #2a2a2a;
}
.${DATA_PREFIX}-channel-header {
display: flex;
@ -102,6 +109,10 @@ function injectStyleOnce() {
gap: 8px;
cursor: pointer;
font-weight: 700;
color: #ffd8b0;
text-transform: uppercase;
letter-spacing: 0.5px;
font-size: 11px;
}
.${DATA_PREFIX}-channel-header::before {
content: "▸";
@ -115,7 +126,7 @@ function injectStyleOnce() {
.${DATA_PREFIX}-video-list {
margin: 6px 0 0;
padding-left: 18px;
border-left: 2px solid #f0d8b4;
border-left: 2px solid #3a2c22;
}
.${DATA_PREFIX}-hud-item {
display: grid;
@ -125,21 +136,35 @@ function injectStyleOnce() {
margin: 6px 0;
padding: 6px;
border-radius: 8px;
background: #fffaf0;
border: 1px solid #e2d7be;
background: #232323;
border: 1px solid #3a2c22;
}
.${DATA_PREFIX}-hud-thumb {
width: 64px;
height: 36px;
object-fit: cover;
border-radius: 4px;
background: #eee2cc;
background: #2a2a2a;
}
.${DATA_PREFIX}-hud-link {
color: #5a2b00;
color: #ffb26a;
text-decoration: none;
font-weight: 700;
}
.${DATA_PREFIX}-hud-actions {
display: flex;
justify-content: flex-end;
margin-bottom: 8px;
}
.${DATA_PREFIX}-hud-clear {
padding: 6px 10px;
border: 1px solid #4a3a2a;
border-radius: 8px;
background: transparent;
color: #f5efe6;
font-size: 11px;
cursor: pointer;
}
.${DATA_PREFIX}-hud-link:hover {
text-decoration: underline;
}
@ -244,11 +269,26 @@ function process(root = document) {
if (!video) return;
const titleEl = video.querySelector("#video-title");
const title = titleEl?.textContent?.trim() ?? "(no title)";
const url = titleEl?.href ?? "";
const thumbImg = video.querySelector("ytd-thumbnail img");
const linkEl =
video.querySelector('a[href^="/watch"]') ||
video.querySelector("#video-title-link") ||
video.querySelector("#video-title");
const title =
linkEl?.getAttribute("title") ||
linkEl?.textContent?.trim() ||
"(no title)";
const rawUrl = linkEl?.getAttribute("href") || "";
const url = rawUrl.startsWith("http")
? rawUrl
: rawUrl
? new URL(rawUrl, location.origin).toString()
: "";
const thumbImg =
video.querySelector("ytd-thumbnail img") ||
video.querySelector("yt-img-shadow img") ||
video.querySelector("img#img");
const thumb =
thumbImg?.currentSrc ||
thumbImg?.getAttribute("src") ||
thumbImg?.getAttribute("data-thumb") ||
thumbImg?.getAttribute("data-src") ||
@ -278,6 +318,13 @@ function process(root = document) {
thumb
});
hudDirty = true;
} else {
// Fill missing metadata as it becomes available.
if (!existing.title && title) existing.title = title;
if (!existing.url && url) existing.url = url;
if (!existing.thumb && thumb) existing.thumb = thumb;
if (!existing.channelLabel && channel) existing.channelLabel = channel;
if (!existing.channelUrl && channelUrl) existing.channelUrl = channelUrl;
}
}
@ -548,6 +595,19 @@ function renderHudPanel(panel) {
title.textContent = "Hidden member-only videos";
panel.appendChild(title);
const body = document.createElement("div");
body.className = `${DATA_PREFIX}-hud-body`;
panel.appendChild(body);
const actions = document.createElement("div");
actions.className = `${DATA_PREFIX}-hud-actions`;
const clearBtn = document.createElement("button");
clearBtn.className = `${DATA_PREFIX}-hud-clear`;
clearBtn.textContent = "Clear archive";
clearBtn.addEventListener("click", () => clearArchive());
actions.appendChild(clearBtn);
body.appendChild(actions);
const groups = new Map();
for (const meta of sharedIndex.values()) {
if (!meta.hidden) continue;
@ -563,7 +623,7 @@ function renderHudPanel(panel) {
if (groups.size === 0) {
const empty = document.createElement("div");
empty.textContent = "No hidden member-only videos.";
panel.appendChild(empty);
body.appendChild(empty);
return;
}
@ -604,11 +664,16 @@ function renderHudPanel(panel) {
list.appendChild(item);
});
panel.appendChild(details);
body.appendChild(details);
details.appendChild(list);
}
}
function clearArchive() {
sharedIndex.clear();
chrome.storage.local.set({ [STORAGE_KEY]: [] }, () => updateHudDot());
}
/* ---------------- initial + observer ---------------- */
process();

View File

@ -33,13 +33,16 @@
<div id="addError" class="hint"></div>
</details>
<details class="section">
<summary>Archive settings</summary>
<div class="row">
<input id="maxInput" type="number" placeholder="Max archived (-1 = unlimited)" />
<button id="saveMaxBtn">Save max</button>
</div>
</details>
<details class="section">
<summary>Archive settings</summary>
<div class="row">
<input id="maxInput" type="number" placeholder="Max archived (-1 = unlimited)" />
<button id="saveMaxBtn">Save max</button>
</div>
<div class="row">
<button id="clearArchiveBtn" class="ghost">Clear archive</button>
</div>
</details>
<!-- Settings -->
<details class="section">
@ -61,10 +64,13 @@
</p>
<!-- Whitelist list -->
<details class="section" open>
<summary>Whitelisted creators</summary>
<ul id="channelList"></ul>
</details>
<details class="section" open>
<summary>Whitelisted creators</summary>
<ul id="channelList"></ul>
<div class="row">
<button id="clearWhitelistBtn" class="ghost">Clear whitelist</button>
</div>
</details>
<div class="section explain">
<div class="explain-title">For non-technical users</div>

View File

@ -5,6 +5,8 @@ const addBtn = document.getElementById("addBtn");
const maxInput = document.getElementById("maxInput");
const saveMaxBtn = document.getElementById("saveMaxBtn");
const addError = document.getElementById("addError");
const clearArchiveBtn = document.getElementById("clearArchiveBtn");
const clearWhitelistBtn = document.getElementById("clearWhitelistBtn");
const list = document.getElementById("channelList");
const debugToggle = document.getElementById("debugToggle");
const resetBtn = document.getElementById("resetBtn");
@ -110,9 +112,19 @@ function saveMaxArchive() {
chrome.storage.local.set({ maxArchive: value }, loadChannels);
}
function clearArchive() {
chrome.storage.local.set({ memberOnlyHidden: [] }, loadChannels);
}
function clearWhitelist() {
chrome.storage.local.set({ whitelist: [] }, loadChannels);
}
// Wire UI events.
addBtn.onclick = addChannel;
saveMaxBtn.onclick = saveMaxArchive;
clearArchiveBtn.onclick = clearArchive;
clearWhitelistBtn.onclick = clearWhitelist;
debugToggle.onchange = e => setDebug(e.target.checked);
resetBtn.onclick = resetDefaults;
loadChannels();