Polish: card hover lift, fade-in posters, skeleton loading, snap rows, glowing progress, stronger detail backdrop, lyrics glow
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
c49693bac6
commit
2de5e343b2
3 files changed
+31
-3
No files matched your search
@@ -759,3 +759,31 @@ body.nav-mini .ngrp span { display: none; }
|
||||
.vunw { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: 14px; } .vunw input { width: 18px; height: 18px; }
|
||||
.vmark { position: absolute; right: 16px; bottom: 96px; z-index: 6; background: rgba(0, 0, 0, .7); color: #fff; border: 1px solid rgba(255, 255, 255, .5); }
|
||||
.vdeckc .vcard.wide { width: 250px; }
|
||||
|
||||
/* Movies & TV polish */
|
||||
.vimg { box-shadow: 0 2px 8px rgba(0, 0, 0, .18); transition: transform .18s ease, box-shadow .18s ease; }
|
||||
.vimg img { animation: vfade .35s ease both; }
|
||||
@keyframes vfade { from { opacity: 0; } to { opacity: 1; } }
|
||||
@media (hover: hover) {
|
||||
.vcard:hover .vimg, .vcard:focus-visible .vimg { transform: translateY(-3px) scale(1.025); box-shadow: 0 10px 24px rgba(0, 0, 0, .32); }
|
||||
.vcard.wide .vimg::after, .vcard .vimg::after { content: ''; position: absolute; inset: 0; background: linear-gradient(transparent 55%, rgba(0, 0, 0, .45)); opacity: 0; transition: opacity .18s; pointer-events: none; }
|
||||
.vcard:hover .vimg::after { opacity: 1; }
|
||||
.vx { opacity: 0; transition: opacity .15s; } .vdeckc:hover .vx, .vx:focus-visible { opacity: .95; }
|
||||
}
|
||||
.vrow { scroll-snap-type: x proximity; padding: 4px 2px 10px; margin: 0 -2px; }
|
||||
.vrow > * { scroll-snap-align: start; }
|
||||
.vcard b { font-weight: 650; letter-spacing: -.005em; }
|
||||
.vprog { height: 5px; border-radius: 0 3px 3px 0; overflow: hidden; } .vprog b { border-radius: 0 3px 3px 0; box-shadow: 0 0 6px var(--accent); }
|
||||
#view h2 { letter-spacing: -.01em; }
|
||||
.vclear { vertical-align: middle; font-size: 13px; }
|
||||
.vfilt select { border-radius: 10px; border: 1px solid var(--line); background: var(--panel); padding: 0 10px; color: var(--text); }
|
||||
.vsk { aspect-ratio: 2/3; border-radius: 10px; background: linear-gradient(100deg, var(--panel2) 30%, var(--panel) 50%, var(--panel2) 70%); background-size: 300% 100%; animation: vshim 1.3s linear infinite; }
|
||||
@keyframes vshim { from { background-position: 100% 0; } to { background-position: 0 0; } }
|
||||
.vhero .vbg { opacity: .3; height: 300px; filter: saturate(1.2); }
|
||||
.vpost { box-shadow: 0 10px 30px rgba(0, 0, 0, .35); border-radius: 12px; }
|
||||
.vsum { font-size: 15.5px; }
|
||||
.vmark { border-radius: 10px; backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px); animation: vfade .25s ease both; font-weight: 650; }
|
||||
/* Lyrics polish */
|
||||
.ll { text-shadow: 0 1px 12px color-mix(in srgb, var(--bg) 70%, transparent); }
|
||||
.ll.on { text-shadow: 0 0 28px color-mix(in srgb, var(--accent) 35%, transparent); }
|
||||
.lyrart { box-shadow: 0 4px 14px rgba(0, 0, 0, .3); }
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
// App-shell cache only; Seafile/API traffic always goes to the network.
|
||||
const CACHE = 'hub-v17';
|
||||
const CACHE = 'hub-v18';
|
||||
const SHARE = 'hub-share'; // files shared into the app from other apps, held until the person picks a folder
|
||||
const SHELL = ['/icon.svg', '/manifest.webmanifest', '/icons/icon-192.png', '/icons/apple-touch-icon.png'];
|
||||
|
||||
|
||||
+2
-2
@@ -95,12 +95,12 @@ async function videoHome(st, libKey) {
|
||||
const load = async () => {
|
||||
const my = gen, mc = await px.get(`/library/sections/${cur.key}/all?type=${type}&sort=${vdEnc($('#vsort').value)}${$('#vunwc').checked ? '&unwatched=1' : ''}${genre ? '&genre=' + vdEnc(genre) : ''}&X-Plex-Container-Start=${start}&X-Plex-Container-Size=${size}`);
|
||||
if (!$('#vgrid') || my !== gen) return; total = mc.totalSize || mc.size || 0; const items = mc.Metadata || []; start += items.length; all = all.concat(items);
|
||||
$('#vgrid').insertAdjacentHTML('beforeend', items.map(m => vdCard(m)).join('')); if (start === items.length) $('#vgrid .empty')?.remove();
|
||||
$('#vgrid').insertAdjacentHTML('beforeend', items.map(m => vdCard(m)).join('')); if (start === items.length) $('#vgrid .vsk') && $('#vgrid').querySelectorAll('.vsk').forEach(x => x.remove());
|
||||
$('#vmore').innerHTML = start < total ? `<div class="bar" style="justify-content:center"><button class="btn ghost" id="vmb">Show more (${total - start} left)</button></div>` : '';
|
||||
if ($('#vmb')) $('#vmb').onclick = () => load().catch(e => toast(e.message));
|
||||
if (!all.length) $('#vgrid').innerHTML = '<p class="empty">Nothing matches.</p>';
|
||||
};
|
||||
const reload = () => { gen++; start = 0; total = 0; all = []; $('#vgrid').innerHTML = '<p class="empty">Loading…</p>'; $('#vmore').innerHTML = ''; $('#vgrid').innerHTML = ''; load().catch(e => { if ($('#vgrid')) $('#vgrid').innerHTML = `<p class="err">${esc(e.message)}</p>`; }); };
|
||||
const reload = () => { gen++; start = 0; total = 0; all = []; $('#vmore').innerHTML = ''; $('#vgrid').innerHTML = '<i class="vsk"></i>'.repeat(12); load().catch(e => { if ($('#vgrid')) $('#vgrid').innerHTML = `<p class="err">${esc(e.message)}</p>`; }); };
|
||||
$('#vsort').onchange = () => { store.set('video_sort', $('#vsort').value); reload(); }; $('#vunwc').onchange = () => { store.set('video_unw', $('#vunwc').checked ? '1' : '0'); reload(); }; $('#vgen').onchange = () => { genre = $('#vgen').value; reload(); };
|
||||
reload();
|
||||
// press and hold (or right-click) a card: quick actions
|
||||
|
||||
Reference in new issue
Block a user