Merge branch 'codex/ui-fixes'

This commit is contained in:
Jonathan Sykes
2026-10-09 14:37:51 +08:00
23 changed files with 511 additions and 67 deletions

View File

@@ -44,7 +44,7 @@ function renderNotesView() {
// Most recently played first (history order), the rest after.
const order = new Map(data.history.map((v, i) => [v.id, i]));
groups.sort((a, b) => (order.has(a.id) ? order.get(a.id) : 1e9) - (order.has(b.id) ? order.get(b.id) : 1e9));
els.listActions.innerHTML = groups.length ? '<button class="np-btn" id="notesExportBtn" type="button">⤓ Export Markdown</button>' : '';
els.listActions.innerHTML = groups.length ? `<button class="np-btn" id="notesExportBtn" type="button">${MediaIcons.svg('download')} Export Markdown</button>` : '';
const c = els.cards;
if (!groups.length) {
c.innerHTML = `
@@ -130,8 +130,8 @@ function setListPaneHidden(hidden) {
const LIST_ICONS = {
rename: '<path d="M4 20h4L19 9l-4-4L4 16v4zM14 6l4 4"/>',
share: '<path d="M10 14a4 4 0 0 0 5.66 0l3-3a4 4 0 0 0-5.66-5.66l-1 1"/><path d="M14 10a4 4 0 0 0-5.66 0l-3 3a4 4 0 0 0 5.66 5.66l1-1"/>',
offline: '<path d="M12 4v11M7 10l5 5 5-5M5 20h14"/>',
offlineDone: '<path d="M5 12.5l4.5 4.5L19 7.5"/>',
offline: '<use href="#media-download"/>',
offlineDone: '<use href="#media-offline"/>',
pin: '<path d="M9 3h6l-1 6 4 4H6l4-4zM12 13v8"/>',
select: '<rect x="4" y="4" width="16" height="16" rx="3"/><path d="M8 12l3 3 5-6"/>',
del: '<path d="M4 7h16M9 7V4h6v3M6 7l1 13h10l1-13M10 11v6M14 11v6"/>',
@@ -416,7 +416,7 @@ async function renderP2pStrip() {
const v = { id: it.id, title: it.title || videoTitleById(it.id) || it.id, channel: it.channel || '', duration: it.duration || 0, thumbnail: `https://i.ytimg.com/vi/${it.id}/mqdefault.jpg` };
const row = document.createElement('div');
row.className = 'ps-row';
row.innerHTML = '<span class="ps-ic">📡</span><span class="ps-txt"><b></b><small></small></span><button type="button" class="ps-dl" aria-label="Save to this device">⤓</button>';
row.innerHTML = `<span class="ps-ic">📡</span><span class="ps-txt"><b></b><small></small></span><button type="button" class="ps-dl" aria-label="Save to this device">${MediaIcons.svg('download')}</button>`;
row.querySelector('b').textContent = v.title;
row.querySelector('small').textContent = `${fmtBytes(it.size)}${it.height ? ' · ' + it.height + 'p' : ''} · ${it.online ? 'Online' : 'Offline'}`;
row.querySelector('.ps-dl').onclick = () => exportToDevice(v);
@@ -517,7 +517,7 @@ async function renderP2pList() {
<div class="card-title"></div>
<div class="card-channel">${state} · ${it.holders} device${it.holders === 1 ? '' : 's'} · ${fmtBytes(it.size)}${it.height ? ' · ' + it.height + 'p' : ''}${it.stale ? ' · <i>not checked lately</i>' : ''}</div>
</div>
<button class="card-act" data-act="export" title="Save to this device" aria-label="Save to this device">⤓</button>
<button class="card-act" data-act="export" title="Save to this device" aria-label="Save to this device">${MediaIcons.svg('download')}</button>
<button class="card-act" data-act="add" title="Add to a playlist" aria-label="Add to a playlist">+</button>`;
row.querySelector('.card-title').textContent = v.title;
row.addEventListener('click', (e) => {
@@ -550,7 +550,7 @@ async function renderSaved() {
const empty = document.createElement('div');
empty.className = 'empty-state';
empty.innerHTML = `
<div class="empty-icon">💾</div>
<div class="empty-icon">${MediaIcons.svg('offline')}</div>
<h3 class="empty-title">Offline cache unavailable</h3>
<p class="empty-desc">This build doesn't support saving videos for offline playback.</p>`;
c.appendChild(empty);
@@ -566,9 +566,9 @@ async function renderSaved() {
const empty = document.createElement('div');
empty.className = 'empty-state';
empty.innerHTML = `
<div class="empty-icon">💾</div>
<div class="empty-icon">${MediaIcons.svg('offline')}</div>
<h3 class="empty-title">Nothing saved yet</h3>
<p class="empty-desc">Use <strong>⬇ Save</strong> while playing, or add videos to a playlist to keep them offline.</p>`;
<p class="empty-desc">Use <strong>${MediaIcons.svg('download')} Save</strong> while playing, or add videos to a playlist to keep them offline.</p>`;
addBrowseCta(empty, '🔍 Find videos');
c.appendChild(empty);
return;
@@ -904,7 +904,7 @@ async function renderSettings() {
<div class="set-group">
<div class="set-group-title">Playlists</div>
<div class="set-row" style="border:none;gap:8px;flex-wrap:wrap">
<button id="importYtBtn" class="btn">⬇ Import from YouTube</button>
<button id="importYtBtn" class="btn">${MediaIcons.svg('download')} Import from YouTube</button>
<button id="exportBtn" class="btn">Export playlists</button>
<button id="importBtn" class="btn">Import playlists</button>
<input id="fileInput" type="file" accept=".json" style="display:none" />
@@ -976,7 +976,7 @@ async function renderSettings() {
<button id="profileShareBtn" class="btn"${profileShareUrl() ? '' : ' style="display:none"'}>↗ Share</button>
<button id="profileUnlinkBtn" class="btn danger"${data.profile && data.profile.name ? '' : ' style="display:none"'}>Unlink</button>
<button id="profileProtectBtn" class="btn"${data.profile && data.profile.name ? '' : ' style="display:none"'}>🔒 Protect…</button>
<button id="profileExportCredBtn" class="btn" style="display:none">⤓ Credentials file</button>
<button id="profileExportCredBtn" class="btn" style="display:none">${MediaIcons.svg('download')} Credentials file</button>
<button id="profileImportCredBtn" class="btn">⤒ Import credentials</button>
<input id="profileCredFileInput" type="file" accept=".json,application/json" hidden />
</div>
@@ -1339,7 +1339,7 @@ function renderCard(v, index, list) {
<div class="thumb">
<img loading="lazy" decoding="async" src="${escapeHtml(v.thumbnail || '')}" alt="" />
${v.duration ? `<span class="dur">${fmtTime(v.duration)}</span>` : ''}
<span class="saved-badge" title="${isDownloading ? 'Downloading…' : 'Saved offline'}">${isDownloading ? '' : '⬇'}</span>
<span class="saved-badge" title="${isDownloading ? 'Downloading…' : 'Saved offline'}">${MediaIcons.svg('offline', 'badge-offline')}${MediaIcons.svg('progress', 'badge-progress')}</span>
${isDownloading ? '<div class="dl-progress"><div class="dl-bar"></div></div>' : ''}
</div>
<div class="card-info">