let videos = [];
let currentCategory = 'All';
let searchInput, searchBtn, searchResults, searchResultsContent, videoGrid, shortsGrid, categoryBtns, subscriptionsList;
async function init() {
searchInput = document.querySelector('.search-input');
searchBtn = document.querySelector('.search-btn');
searchResults = document.querySelector('.search-results');
searchResultsContent = document.querySelector('.search-results-content');
videoGrid = document.querySelector('.video-grid');
shortsGrid = document.querySelector('.shorts-grid');
categoryBtns = document.querySelectorAll('.category-btn');
subscriptionsList = document.querySelector('.subscriptions-list');
await loadVideos();
if (videoGrid && shortsGrid) {
renderVideos();
}
if (subscriptionsList) {
renderSubscriptions();
}
bindEvents();
}
async function loadVideos() {
try {
const response = await fetch('src/video.json');
const data = await response.json();
videos = data.videos;
} catch (error) {
console.error('Failed to load videos:', error);
}
}
function renderVideos() {
const filteredVideos = filterVideosByCategory(currentCategory);
const videosOnly = filteredVideos.filter(video => video.type === 'video');
const shortsOnly = filteredVideos.filter(video => video.type === 'short');
videoGrid.innerHTML = '';
shortsGrid.innerHTML = '';
// Render long videos
videosOnly.forEach(video => {
const videoCard = createVideoCard(video);
videoGrid.appendChild(videoCard);
});
// Render shorts videos
shortsOnly.forEach(video => {
const shortsCard = createShortsCard(video);
shortsGrid.appendChild(shortsCard);
});
}
function filterVideosByCategory(category) {
if (category === 'All') {
return videos;
}
const categoryMap = {
'Music': ['music'],
'Game': ['game'],
'Technology': ['tech'],
'Art': ['art'],
'Recently': videos.filter(v => v.uploadDate.includes('days ago')),
'Watched': []
};
if (categoryMap[category]) {
if (Array.isArray(categoryMap[category]) && categoryMap[category].length > 0 && typeof categoryMap[category][0] === 'string') {
return videos.filter(v => categoryMap[category].includes(v.category));
} else if (Array.isArray(categoryMap[category])) {
return categoryMap[category];
}
}
return videos;
}
function createVideoCard(video) {
const card = document.createElement('div');
card.className = 'video-card';
card.innerHTML = `
${video.duration}
`;
const menuToggle = card.querySelector('.menu-toggle');
const menuDropdown = card.querySelector('.menu-dropdown');
menuToggle.addEventListener('click', (e) => {
e.stopPropagation();
menuDropdown.classList.toggle('show');
});
document.addEventListener('click', () => { // Close the menu when clicking outside
menuDropdown.classList.remove('show');
});
// Add click event to the card
card.addEventListener('click', () => {
window.location.href = `video.html?id=${video.id}`;
});
return card;
}
function createShortsCard(video) {
const card = document.createElement('div');
card.className = 'shorts-card';
card.innerHTML = `
${video.title}
${video.views}
${video.uploadDate}
`;
// Add click event to the card
card.addEventListener('click', () => {
window.location.href = `short.html?id=${video.id}`;
});
return card;
}
function renderSubscriptions() { // Render the subscriptions list
const subscriptions = [
{ name: '花譜 -KAF-', avatar: 'img/avatar/kaf.png' },
{ name: 'ryo (supercell)', avatar: 'img/avatar/ryo.jpg' },
{ name: 'ヰ世界情緒', avatar: 'img/avatar/isekaijoucho.jpg' },
{ name: 'MyGo!!!!!', avatar: 'img/avatar/mygo.png' },
{ name: 'ZUTOMAYO', avatar: 'img/avatar/ztmy.jpg' },
{ name: 'Aqu3ra', avatar: 'img/avatar/aqu3ra.png' },
{ name: '『超かぐや姫 ! 』公式', avatar: 'img/avatar/cpk.png' },
{ name: '礼衣 / Rei', avatar: 'img/avatar/rei.jpg' },
{ name: 'tayori', avatar: 'img/avatar/tayori.jpg' }
];
subscriptionsList.innerHTML = '';
subscriptions.forEach(sub => {
const item = document.createElement('div');
item.className = 'subscription-item';
item.innerHTML = `
${sub.name}
`;
subscriptionsList.appendChild(item);
});
}
function performSearch(query) { // Perform the search and render the results
if (!query.trim()) {
searchResults.style.display = 'none';
return;
}
const results = videos.filter(video =>
video.title.toLowerCase().includes(query.toLowerCase()) ||
video.channel.toLowerCase().includes(query.toLowerCase())
);
renderSearchResults(results, query);
}
// Render the search results
function renderSearchResults(results, query) {
searchResultsContent.innerHTML = '';
if (results.length === 0) {
searchResultsContent.innerHTML = 'No videos found related to your search.
';
searchResults.style.display = 'block';
return;
}
results.forEach(video => {
const item = document.createElement('div');
item.className = 'search-result-item';
// Highlight the search keywords in the title and channel name
const highlightedTitle = video.title.replace(new RegExp(`(${query})`, 'gi'), '$1');
const highlightedChannel = video.channel.replace(new RegExp(`(${query})`, 'gi'), '$1');
item.innerHTML = `
${highlightedTitle}
${highlightedChannel}
${video.views} views · ${video.uploadDate}
`;
// Add click event to the search result item
item.addEventListener('click', () => {
window.location.href = `video.html?id=${video.id}`;
});
searchResultsContent.appendChild(item);
});
searchResults.style.display = 'block';
}
// Bind events to the DOM elements
function bindEvents() { // Bind events to the DOM elements
// Menu button event - toggle sidebar
const menuBtn = document.querySelector('.menu-btn');
const sidebar = document.querySelector('.sidebar');
if (menuBtn && sidebar) {
menuBtn.addEventListener('click', () => {
sidebar.classList.toggle('collapsed');
});
}
// Search event
if (searchInput) {
searchInput.addEventListener('input', (e) => {
performSearch(e.target.value);
});
}
if (searchBtn) {
searchBtn.addEventListener('click', () => {
performSearch(searchInput ? searchInput.value : '');
});
}
// Close the search results when clicking outside
if (searchResults) {
document.addEventListener('click', (e) => {
if (!e.target.closest('.search-container') && !e.target.closest('.search-results')) {
searchResults.style.display = 'none';
}
});
}
// Category buttons event
if (categoryBtns.length > 0) {
categoryBtns.forEach(btn => {
btn.addEventListener('click', () => {
// Remove all active states
categoryBtns.forEach(b => b.classList.remove('active'));
// Add current active state
btn.classList.add('active');
// Update current category
currentCategory = btn.textContent;
// Re-render videos and shorts
if (videoGrid && shortsGrid) {
renderVideos();
}
});
});
}
// Sidebar navigation buttons event
const navBtns = document.querySelectorAll('.nav-btn');
if (navBtns.length > 0) {
navBtns.forEach(btn => {
btn.addEventListener('click', () => {
// Remove all active states
navBtns.forEach(b => b.classList.remove('active'));
// Add current active state
btn.classList.add('active');
});
});
}
// Subscription section expand/collapse event
const subscriptionTitle = document.querySelector('.nav-section-title');
if (subscriptionTitle) {
subscriptionTitle.addEventListener('click', () => {
const subscriptionsList = document.querySelector('.subscriptions-list');
const chevron = subscriptionTitle.querySelector('i');
if (subscriptionsList && chevron) {
subscriptionsList.classList.toggle('collapsed');
if (subscriptionsList.classList.contains('collapsed')) {
chevron.style.transform = 'rotate(-90deg)';
} else {
chevron.style.transform = 'rotate(0deg)';
}
}
});
}
}
// Page load event: initialize the application
window.addEventListener('DOMContentLoaded', init);