broke up monolithic structure

This commit is contained in:
Simon
2026-02-09 13:27:08 +00:00
parent f06a7cd3d0
commit ee1cb511df
10 changed files with 1195 additions and 1125 deletions

124
frontend/js/favorites.js Normal file
View File

@@ -0,0 +1,124 @@
window.App = window.App || {};
App.favorites = App.favorites || {};
(function() {
const { FAVORITES_KEY, FAVORITES_VISIBILITY_KEY } = App.constants;
// Favorites storage helpers.
App.favorites.getAll = function() {
try {
const raw = localStorage.getItem(FAVORITES_KEY);
const parsed = raw ? JSON.parse(raw) : [];
return Array.isArray(parsed) ? parsed : [];
} catch (err) {
return [];
}
};
App.favorites.setAll = function(items) {
localStorage.setItem(FAVORITES_KEY, JSON.stringify(items));
};
App.favorites.getKey = function(video) {
if (!video) return null;
return video.key || video.id || video.url || null;
};
App.favorites.normalize = function(video) {
const key = App.favorites.getKey(video);
if (!key) return null;
return {
key,
id: video.id || null,
url: video.url || '',
title: video.title || '',
thumb: video.thumb || '',
channel: video.channel || '',
duration: video.duration || 0
};
};
App.favorites.getSet = function() {
return new Set(App.favorites.getAll().map((item) => item.key));
};
App.favorites.isVisible = function() {
return localStorage.getItem(FAVORITES_VISIBILITY_KEY) !== 'false';
};
App.favorites.setVisible = function(isVisible) {
localStorage.setItem(FAVORITES_VISIBILITY_KEY, isVisible ? 'true' : 'false');
};
// UI helpers for rendering and syncing heart states.
App.favorites.setButtonState = function(button, isFavorite) {
button.classList.toggle('is-favorite', isFavorite);
button.textContent = isFavorite ? '♥' : '♡';
button.setAttribute('aria-pressed', isFavorite ? 'true' : 'false');
button.setAttribute('aria-label', isFavorite ? 'Remove from favorites' : 'Add to favorites');
};
App.favorites.syncButtons = function() {
const favoritesSet = App.favorites.getSet();
document.querySelectorAll('.favorite-btn[data-fav-key]').forEach((button) => {
const key = button.dataset.favKey;
if (!key) return;
App.favorites.setButtonState(button, favoritesSet.has(key));
});
};
App.favorites.toggle = function(video) {
const key = App.favorites.getKey(video);
if (!key) return;
const favorites = App.favorites.getAll();
const existingIndex = favorites.findIndex((item) => item.key === key);
if (existingIndex >= 0) {
favorites.splice(existingIndex, 1);
} else {
const entry = App.favorites.normalize(video);
if (entry) favorites.unshift(entry);
}
App.favorites.setAll(favorites);
App.favorites.renderBar();
App.favorites.syncButtons();
};
App.favorites.renderBar = function() {
const bar = document.getElementById('favorites-bar');
const list = document.getElementById('favorites-list');
const empty = document.getElementById('favorites-empty');
if (!bar || !list) return;
const favorites = App.favorites.getAll();
const visible = App.favorites.isVisible();
bar.style.display = visible ? 'block' : 'none';
list.innerHTML = "";
favorites.forEach((item) => {
const card = document.createElement('div');
card.className = 'favorite-card';
card.dataset.favKey = item.key;
card.innerHTML = `
<button class="favorite-btn is-favorite" type="button" aria-pressed="true" aria-label="Remove from favorites" data-fav-key="${item.key}">♥</button>
<img src="${item.thumb}" alt="${item.title}">
<div class="favorite-info">
<h4>${item.title}</h4>
<p>${item.channel}</p>
</div>
`;
card.onclick = () => App.player.open(item.url);
const favoriteBtn = card.querySelector('.favorite-btn');
if (favoriteBtn) {
favoriteBtn.onclick = (event) => {
event.stopPropagation();
App.favorites.toggle(item);
};
}
list.appendChild(card);
});
if (empty) {
empty.style.display = favorites.length > 0 ? 'none' : 'block';
}
};
})();