Layered progressive polish on the warm classic + brass theme: - Card entrance animation on first mount (virtualizer-aware) - Cursor-tracking brass spotlight border on cards - Thumbnail skeleton shimmer until the poster paints - Hover video preview after a short dwell (only when formats resolved) - View Transition + blurred-poster ambient backdrop on player open - Favorite heart pop + expanding ring on add - ⌘K command palette (search, theme, density, reels, source/channel) - Scroll-progress bar + back-to-top FAB - Grid density toggle (comfortable/compact) - Reels HUD: serif title, brass scrubber, muted-state pulse All new motion respects prefers-reduced-motion; no JS/HTML structure changes to the core grid/feed. New glue lives in frontend/js/enhance.js. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
53 lines
1.7 KiB
JavaScript
53 lines
1.7 KiB
JavaScript
window.App = window.App || {};
|
|
|
|
(function() {
|
|
// App bootstrap: initialize storage, render UI, and load the first page.
|
|
async function initApp() {
|
|
await App.storage.ensureDefaults();
|
|
App.ui.applyTheme();
|
|
App.ui.applyPreferredQuality();
|
|
App.ui.applyFeedEndBehavior();
|
|
App.ui.applyDensity();
|
|
App.ui.renderMenu();
|
|
App.favorites.renderBar();
|
|
App.ui.bindGlobalHandlers();
|
|
|
|
App.videos.observeSentinel();
|
|
|
|
const loadMoreBtn = document.getElementById('load-more-btn');
|
|
if (loadMoreBtn) {
|
|
loadMoreBtn.onclick = () => {
|
|
App.videos.loadVideos();
|
|
};
|
|
}
|
|
|
|
const errorToastClose = document.getElementById('error-toast-close');
|
|
if (errorToastClose) {
|
|
errorToastClose.onclick = () => {
|
|
const toast = document.getElementById('error-toast');
|
|
if (toast) toast.classList.remove('show');
|
|
};
|
|
}
|
|
|
|
window.addEventListener('resize', () => {
|
|
App.videos.ensureViewportFilled();
|
|
});
|
|
|
|
await App.videos.loadVideos();
|
|
App.favorites.syncButtons();
|
|
|
|
// The UI above is rendered entirely from the last known status cached in
|
|
// localStorage, so startup never blocks on (or breaks because of) a slow
|
|
// or failing status endpoint. Now fetch fresh status in the background and
|
|
// reconcile the UI with whatever comes back.
|
|
App.storage.refreshServerStatusInBackground();
|
|
|
|
// Watch for frontend deploys and seamlessly reload/hot-swap changed assets.
|
|
if (App.version && App.version.start) {
|
|
App.version.start();
|
|
}
|
|
}
|
|
|
|
initApp();
|
|
})();
|