Use theme-aware SVGs for download and offline actions

This commit is contained in:
Jonathan Sykes
2026-10-09 14:28:23 +08:00
parent 66bbda51c7
commit 2001e77cee
13 changed files with 122 additions and 62 deletions

View File

@@ -1241,7 +1241,7 @@ async function adoptSharedPlaylistByCode(code, { fromName = '' } = {}) {
Add “<strong>${escapeHtml(shared.name)}</strong>” (${count} video${count === 1 ? '' : 's'}) to your playlists?
This playlist is added alongside your existing playlists and nothing is replaced.
</p>`;
showModal(fromName ? '🎵 Playlist sent to you' : '⬇ Add shared playlist', body, [
showModal(fromName ? '🎵 Playlist sent to you' : 'Add shared playlist', body, [
{ label: fromName ? 'No thanks' : 'Cancel', onClick: () => { closeModal(); resolve(false); } },
{ label: 'Add playlist', primary: true, onClick: () => { closeModal(); resolve(true); } },
]);
@@ -1361,7 +1361,7 @@ async function adoptProfileFromUrl() {
Loading it replaces the playlists, history and settings on this device,
and future changes here sync to that profile.
</p>`;
showModal('⬇ Open shared profile', body, [
showModal('Open shared profile', body, [
{ label: 'Cancel', onClick: () => { closeModal(); resolve(false); } },
{ label: 'Load profile', primary: true, onClick: () => { closeModal(); resolve(true); } },
]);
@@ -1567,7 +1567,7 @@ function loadProfileFlow() {
changes here sync back to that profile.
</p>
<input id="profileNameInput" type="text" placeholder="profile name" autocomplete="off" />`;
showModal('⬇ Load online profile', body, [
showModal('Load online profile', body, [
{ label: 'Cancel', onClick: closeModal },
{ label: 'Load', primary: true, onClick: async () => {
const name = ($('profileNameInput').value || '').trim();
@@ -2209,7 +2209,7 @@ async function openVideoEditor(source) {
{
label: 'Save edited copy', primary: true, onClick: () => {
if (!VideoEdit.hasEdits(cuts, duration)) {
showErr('Add at least one cut, or use ⬇ Save for the full video.');
showErr('Add at least one cut, or use Save for the full video.');
return;
}
const keep = VideoEdit.invertCuts(cuts, duration);
@@ -3559,7 +3559,7 @@ const Notes = (() => {
<div class="notes-empty-actions">
<button class="np-btn" type="button" data-act="web">🌐 Find lyrics online</button>
<button class="np-btn" type="button" data-act="paste">✎ Add lyrics</button>
${isUploadId(st.videoId) ? '' : '<button class="np-btn" type="button" data-act="captions">⤓ Import YouTube captions</button>'}
${isUploadId(st.videoId) ? '' : `<button class="np-btn" type="button" data-act="captions">${MediaIcons.svg('download')} Import YouTube captions</button>`}
</div>
<div class="notes-empty-hint">Lyrics and chapters are shared with everyone who plays this song.</div>
</div>`;
@@ -3801,7 +3801,7 @@ const Notes = (() => {
${note ? `<p class="lyr-editor-note">${escapeHtml(note)}</p>` : ''}
<textarea class="lyr-editor-text" spellcheck="false" placeholder="Paste or type the lyrics…"></textarea>
<div class="lyr-editor-tools">
<button type="button" class="np-btn" data-act="captions">⤓ Import YouTube captions</button>
<button type="button" class="np-btn" data-act="captions">${MediaIcons.svg('download')} Import YouTube captions</button>
<button type="button" class="np-btn" data-act="break">↵ Line break (same time)</button>
<button type="button" class="np-btn" data-act="stamp">⏱ Stamp current time on this line</button>
</div>`;
@@ -4181,7 +4181,7 @@ const Notes = (() => {
const refresh = () => { ta.value = build(inc.checked); };
inc.addEventListener('change', refresh);
refresh();
showModal('⤓ Export chapters', body, [
showModal('Export chapters', body, [
{ label: 'Download .txt', onClick: () => {
const blob = new Blob([`${title}\nhttps://youtu.be/${st.videoId}\n\n${ta.value}\n`], { type: 'text/plain' });
const a = document.createElement('a');
@@ -6920,7 +6920,7 @@ function openImportYouTubeModal() {
</p>
`;
showModal('⬇ Import from YouTube', successBody, [
showModal('Import from YouTube', successBody, [
{ label: 'Cancel', onClick: closeModal },
{
label: 'Create playlist',
@@ -6959,7 +6959,7 @@ function openImportYouTubeModal() {
}
}
showModal('⬇ Import from YouTube', body, [
showModal('Import from YouTube', body, [
{ label: 'Cancel', onClick: closeModal },
{ label: 'Import', primary: true, onClick: handleImport },
]);
@@ -6991,7 +6991,7 @@ function openCardMenu(video) {
const isCustom = !!video.custom;
const exportBtn = document.createElement('button');
exportBtn.textContent = '🖼 Save to gallery';
exportBtn.innerHTML = MediaIcons.svg('download') + ' Save to gallery';
exportBtn.title = 'Put the video file in your gallery, Files app or Downloads folder';
exportBtn.onclick = () => { closeModal(); exportToDevice(video); };
body.appendChild(exportBtn);
@@ -7005,7 +7005,7 @@ function openCardMenu(video) {
saveBtn.className = 'danger';
saveBtn.onclick = () => { closeModal(); deleteCustomVideo(video.id); };
} else {
saveBtn.textContent = isSaved ? '✓ Saved offline — remove' : '⬇ Save for offline';
saveBtn.innerHTML = MediaIcons.svg(isSaved ? 'offline' : 'download') + (isSaved ? ' Saved offline — remove' : ' Save for offline');
saveBtn.onclick = async () => {
closeModal();
if (cachedIds.has(video.id)) {
@@ -7232,17 +7232,17 @@ function updatePlaylistOfflineButton(btn, pl) {
let label;
btn.classList.remove('done', 'busy');
if (stats.total > 0 && stats.cached === stats.total) {
if (iconOnly) { setListIcon(btn, 'offlineDone'); btn.classList.add('done'); } else btn.textContent = '✓ Available offline';
if (iconOnly) { setListIcon(btn, 'offlineDone'); btn.classList.add('done'); } else btn.innerHTML = MediaIcons.svg('offline') + ' Available offline';
btn.disabled = true;
btn.classList.add('disabled');
label = 'All videos in this playlist are available offline';
} else if (isDownloading) {
if (iconOnly) { btn.innerHTML = `<span class="lib-progress">${stats.cached}/${stats.total}</span>`; btn.classList.add('busy'); } else btn.textContent = `Saving ${stats.cached}/${stats.total}…`;
if (iconOnly) { btn.innerHTML = MediaIcons.svg('progress') + `<span class="lib-progress">${stats.cached}/${stats.total}</span>`; btn.classList.add('busy'); } else btn.innerHTML = MediaIcons.svg('progress') + ` Saving ${stats.cached}/${stats.total}…`;
btn.disabled = true;
btn.classList.add('disabled');
label = `${stats.cached} of ${stats.total} videos saved offline`;
} else {
if (iconOnly) setListIcon(btn, 'offline'); else btn.textContent = '⬇ Make available offline';
if (iconOnly) setListIcon(btn, 'offline'); else btn.innerHTML = MediaIcons.svg('download') + ' Make available offline';
btn.disabled = stats.total === 0;
btn.classList.toggle('disabled', stats.total === 0);
label = stats.total === 0 ? 'Playlist is empty' : 'Make available offline';
@@ -7259,7 +7259,7 @@ async function makePlaylistOffline(pl) {
const btn = $('plOfflineBtn');
if (btn) {
const stats = playlistOfflineStats(pl);
btn.innerHTML = `<span class="lib-progress">${stats.cached}/${stats.total}</span>`;
btn.innerHTML = MediaIcons.svg('progress') + `<span class="lib-progress">${stats.cached}/${stats.total}</span>`;
btn.classList.add('busy');
btn.disabled = true;
btn.classList.add('disabled');