Implement Playlist Creation in Video Library

PLAYLIST CREATION FEATURES:
-  Multi-selection system with visual checkboxes and green highlighting
-  Select mode toggle ( Select /  Exit Select) for batch operations
-  Dynamic playlist creation button with selection counter
-  Professional creation modal with video preview and removal options
-  Two creation modes: Create Playlist & Create & Switch to Playlist

VIDEO LIBRARY ENHANCEMENTS:
- Added playlist management controls to library header
- Implemented multi-selection state tracking with Set-based storage
- Enhanced video cards/items with selection checkboxes and styling
- Smart playlist naming with auto-increment (My Playlist 1, 2, etc.)
- Duplicate name handling with user confirmation for overwrites

UI/UX IMPROVEMENTS:
- Professional playlist creation modal with responsive design
- Visual selection indicators (green borders, checkboxes)
- Real-time button text updates based on selection count
- Individual video removal in creation dialog
- Consistent styling with existing cinema theme

TECHNICAL IMPLEMENTATION:
- Extended VideoLibrary class with playlist creation methods
- Integration with existing localStorage playlist system
- Cross-feature compatibility with save/load functionality
- Error handling and user feedback notifications
- Keyboard support (Enter to create) and accessibility features

WORKFLOW BENEFITS:
- Bulk playlist creation from selected videos
- Empty playlist creation for manual building
- Immediate playlist switching after creation
- Seamless integration with existing playlist management
- Enhanced user experience for playlist organization

The video library now provides complete playlist creation capabilities,
allowing users to efficiently organize their video collections into custom playlists.
This commit is contained in:
dilgenfritz 2025-10-31 15:41:27 -05:00
parent a34aa9c86b
commit b360e4d68d
4 changed files with 830 additions and 3 deletions

View File

@ -151,6 +151,10 @@
<button id="grid-view-btn" class="view-btn active" title="Grid View"></button>
<button id="list-view-btn" class="view-btn" title="List View"></button>
</div>
<div class="playlist-management">
<button id="create-playlist-btn" class="btn btn-mini" title="Create New Playlist">📝 New Playlist</button>
<button id="select-mode-btn" class="btn btn-mini" title="Select Multiple Videos">☑️ Select</button>
</div>
<div class="sort-controls">
<select id="sort-select" class="sort-dropdown">
<option value="name">Sort by Name</option>

Binary file not shown.

View File

@ -13,6 +13,8 @@ class VideoLibrary {
this.sortDirection = 'asc';
this.searchQuery = '';
this.selectedVideo = null;
this.selectedVideos = new Set(); // For multi-selection
this.isSelectMode = false; // Track if we're in multi-select mode
this.initializeElements();
this.attachEventListeners();
@ -31,6 +33,10 @@ class VideoLibrary {
this.searchInput = document.getElementById('library-search');
this.refreshBtn = document.getElementById('refresh-library');
// Playlist controls
this.createPlaylistBtn = document.getElementById('create-playlist-btn');
this.selectModeBtn = document.getElementById('select-mode-btn');
// Content container
this.libraryContent = document.getElementById('library-content');
}
@ -47,6 +53,10 @@ class VideoLibrary {
// Search
this.searchInput.addEventListener('input', (e) => this.setSearchQuery(e.target.value));
this.refreshBtn.addEventListener('click', () => this.refreshLibrary());
// Playlist controls
this.createPlaylistBtn.addEventListener('click', () => this.createNewPlaylist());
this.selectModeBtn.addEventListener('click', () => this.toggleSelectMode());
}
async loadVideoLibrary() {
@ -282,13 +292,16 @@ class VideoLibrary {
createVideoElement(video) {
const duration = this.formatDuration(video.duration);
const fileSize = this.formatFileSize(video.size);
const isSelected = this.selectedVideos.has(video.path);
const selectionClass = isSelected ? 'multi-selected' : '';
// Generate or get thumbnail
const thumbnailSrc = this.getThumbnailSrc(video);
if (this.currentView === 'grid') {
return `
<div class="video-card" data-video-path="${video.path}">
<div class="video-card ${selectionClass}" data-video-path="${video.path}">
${this.isSelectMode ? `<div class="video-selection-checkbox ${isSelected ? 'checked' : ''}">✓</div>` : ''}
<div class="video-thumbnail" data-video-path="${video.path}">
${thumbnailSrc ?
`<img src="${thumbnailSrc}" alt="${video.name}" onload="this.style.opacity=1" style="opacity:0; transition: opacity 0.3s;">` :
@ -311,7 +324,8 @@ class VideoLibrary {
`;
} else {
return `
<div class="video-list-item" data-video-path="${video.path}">
<div class="video-list-item ${selectionClass}" data-video-path="${video.path}">
${this.isSelectMode ? `<div class="video-selection-checkbox ${isSelected ? 'checked' : ''}">✓</div>` : ''}
<div class="list-thumbnail" data-video-path="${video.path}">
${thumbnailSrc ?
`<img src="${thumbnailSrc}" alt="${video.name}" class="list-thumbnail" onload="this.style.opacity=1" style="opacity:0; transition: opacity 0.3s;">` :
@ -341,7 +355,22 @@ class VideoLibrary {
if (e.target.closest('.video-actions')) return; // Don't trigger on action buttons
const videoPath = element.dataset.videoPath;
this.selectVideo(videoPath);
if (this.isSelectMode) {
this.toggleVideoSelection(videoPath);
} else {
this.selectVideo(videoPath);
}
});
});
// Selection checkbox click events
const checkboxes = this.libraryContent.querySelectorAll('.video-selection-checkbox');
checkboxes.forEach(checkbox => {
checkbox.addEventListener('click', (e) => {
e.stopPropagation();
const videoPath = checkbox.closest('[data-video-path]').dataset.videoPath;
this.toggleVideoSelection(videoPath);
});
});
@ -830,4 +859,298 @@ class VideoLibrary {
}
}
}
// ===== PLAYLIST CREATION METHODS =====
toggleSelectMode() {
this.isSelectMode = !this.isSelectMode;
// Update button appearance
this.selectModeBtn.classList.toggle('active', this.isSelectMode);
this.selectModeBtn.textContent = this.isSelectMode ? '✓ Exit Select' : '☑️ Select';
// Clear selections when exiting select mode
if (!this.isSelectMode) {
this.selectedVideos.clear();
}
// Re-render library to show/hide checkboxes
this.displayLibrary();
// Show create playlist button if videos are selected
this.updatePlaylistControls();
}
toggleVideoSelection(videoPath) {
if (this.selectedVideos.has(videoPath)) {
this.selectedVideos.delete(videoPath);
} else {
this.selectedVideos.add(videoPath);
}
// Update visual selection
const videoElement = this.libraryContent.querySelector(`[data-video-path="${videoPath}"]`);
if (videoElement) {
videoElement.classList.toggle('multi-selected', this.selectedVideos.has(videoPath));
const checkbox = videoElement.querySelector('.video-selection-checkbox');
if (checkbox) {
checkbox.classList.toggle('checked', this.selectedVideos.has(videoPath));
}
}
this.updatePlaylistControls();
}
updatePlaylistControls() {
// Update create playlist button text based on selection
if (this.selectedVideos.size > 0) {
this.createPlaylistBtn.textContent = `📝 Create Playlist (${this.selectedVideos.size})`;
this.createPlaylistBtn.classList.add('has-selection');
} else {
this.createPlaylistBtn.textContent = '📝 New Playlist';
this.createPlaylistBtn.classList.remove('has-selection');
}
}
createNewPlaylist() {
if (this.selectedVideos.size > 0) {
// Create playlist with selected videos
this.createPlaylistFromSelection();
} else {
// Create empty playlist
this.showCreatePlaylistDialog();
}
}
createPlaylistFromSelection() {
const selectedVideoObjects = Array.from(this.selectedVideos).map(path =>
this.videos.find(video => video.path === path)
).filter(Boolean);
this.showCreatePlaylistDialog(selectedVideoObjects);
}
showCreatePlaylistDialog(preselectedVideos = []) {
// Create modal dialog for playlist creation
const modal = document.createElement('div');
modal.className = 'playlist-modal';
modal.innerHTML = `
<div class="playlist-modal-content create-playlist-modal">
<div class="playlist-modal-header">
<h3>Create New Playlist</h3>
<button class="playlist-modal-close"></button>
</div>
<div class="playlist-modal-body">
<div class="create-playlist-form">
<label for="new-playlist-name">Playlist Name:</label>
<input type="text" id="new-playlist-name" placeholder="Enter playlist name..." value="My Playlist ${this.getExistingPlaylistCount() + 1}">
${preselectedVideos.length > 0 ? `
<div class="preselected-videos">
<h4>Selected Videos (${preselectedVideos.length}):</h4>
<div class="video-list">
${preselectedVideos.map(video => `
<div class="playlist-creation-video-item">
<span class="video-name">${video.name}</span>
<button class="btn-remove-from-creation" data-path="${video.path}"></button>
</div>
`).join('')}
</div>
</div>
` : `
<div class="empty-playlist-note">
<p>Creating an empty playlist. You can add videos later using the button.</p>
</div>
`}
<div class="playlist-creation-actions">
<button class="btn-create-playlist">Create Playlist</button>
<button class="btn-create-and-switch">Create & Switch to Playlist</button>
</div>
</div>
</div>
</div>
`;
// Add modal styles
modal.style.cssText = `
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.8);
display: flex;
align-items: center;
justify-content: center;
z-index: 10002;
backdrop-filter: blur(5px);
`;
document.body.appendChild(modal);
// Focus on input and select text
const input = modal.querySelector('#new-playlist-name');
setTimeout(() => {
input.focus();
input.select();
}, 100);
// Setup event handlers
this.setupCreatePlaylistModalEvents(modal, preselectedVideos);
}
setupCreatePlaylistModalEvents(modal, preselectedVideos) {
const input = modal.querySelector('#new-playlist-name');
const createBtn = modal.querySelector('.btn-create-playlist');
const createSwitchBtn = modal.querySelector('.btn-create-and-switch');
const closeBtn = modal.querySelector('.playlist-modal-close');
let currentVideos = [...preselectedVideos];
// Close modal handlers
const closeModal = () => {
document.body.removeChild(modal);
};
closeBtn.addEventListener('click', closeModal);
modal.addEventListener('click', (e) => {
if (e.target === modal) closeModal();
});
// Remove video from creation list
const removeButtons = modal.querySelectorAll('.btn-remove-from-creation');
removeButtons.forEach(button => {
button.addEventListener('click', () => {
const path = button.dataset.path;
currentVideos = currentVideos.filter(video => video.path !== path);
button.closest('.playlist-creation-video-item').remove();
// Update header count
const videoCountSpan = modal.querySelector('.preselected-videos h4');
if (videoCountSpan) {
videoCountSpan.textContent = `Selected Videos (${currentVideos.length}):`;
}
});
});
// Create playlist handlers
const createPlaylist = async (switchToPlaylist = false) => {
const name = input.value.trim();
if (!name) {
input.focus();
return;
}
try {
const playlistData = {
name: name,
created: new Date().toISOString(),
videos: currentVideos.map(video => ({
name: video.name,
path: video.path,
duration: video.duration,
size: video.size,
type: video.type
})),
count: currentVideos.length
};
// Save to localStorage
const savedPlaylists = this.getSavedPlaylists();
// Check for duplicate names
const existingIndex = savedPlaylists.findIndex(p => p.name === name);
if (existingIndex >= 0) {
if (!confirm(`A playlist named "${name}" already exists. Replace it?`)) {
return;
}
savedPlaylists[existingIndex] = playlistData;
} else {
savedPlaylists.push(playlistData);
}
localStorage.setItem('pornCinema_savedPlaylists', JSON.stringify(savedPlaylists));
this.showLibraryNotification(`Created playlist: ${name} (${currentVideos.length} videos)`);
// Switch to playlist if requested
if (switchToPlaylist && this.pornCinema) {
this.pornCinema.loadSavedPlaylist(playlistData);
this.showLibraryNotification(`Switched to playlist: ${name}`);
}
// Clear selection
this.selectedVideos.clear();
this.isSelectMode = false;
this.selectModeBtn.classList.remove('active');
this.selectModeBtn.textContent = '☑️ Select';
this.updatePlaylistControls();
this.displayLibrary();
console.log('📝 ✅ Playlist created:', name);
closeModal();
} catch (error) {
console.error('📝 ❌ Error creating playlist:', error);
this.showLibraryNotification('Error creating playlist');
}
};
createBtn.addEventListener('click', () => createPlaylist(false));
createSwitchBtn.addEventListener('click', () => createPlaylist(true));
// Enter key to create
input.addEventListener('keydown', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
createPlaylist(false);
}
});
}
getSavedPlaylists() {
try {
const saved = localStorage.getItem('pornCinema_savedPlaylists');
return saved ? JSON.parse(saved) : [];
} catch (error) {
console.error('📝 ❌ Error getting saved playlists:', error);
return [];
}
}
getExistingPlaylistCount() {
return this.getSavedPlaylists().length;
}
showLibraryNotification(message) {
// Create a simple notification system
const notification = document.createElement('div');
notification.className = 'library-notification';
notification.textContent = message;
notification.style.cssText = `
position: fixed;
top: 80px;
right: 20px;
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 10px 15px;
border-radius: 5px;
z-index: 10001;
font-size: 14px;
backdrop-filter: blur(5px);
border: 1px solid rgba(255, 255, 255, 0.1);
animation: slideInRight 0.3s ease-out, slideOutRight 0.3s ease-in 2.7s;
`;
document.body.appendChild(notification);
// Remove after 3 seconds
setTimeout(() => {
if (notification.parentNode) {
notification.parentNode.removeChild(notification);
}
}, 3000);
}
}

View File

@ -377,6 +377,439 @@ body.cinema-mode {
}
}
/* ===== PLAYLIST MODAL STYLES ===== */
.playlist-modal-content {
background: linear-gradient(135deg, #2a2a3a, #1e1e2e);
border-radius: 12px;
max-width: 500px;
width: 90vw;
max-height: 80vh;
overflow: hidden;
border: 1px solid #404050;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.5);
}
.playlist-modal-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 20px;
border-bottom: 1px solid #404050;
background: rgba(0, 0, 0, 0.2);
}
.playlist-modal-header h3 {
margin: 0;
color: #ff6b9d;
font-size: 1.2rem;
font-weight: 600;
}
.playlist-modal-close {
background: rgba(255, 255, 255, 0.1);
border: 1px solid rgba(255, 255, 255, 0.2);
color: #ffffff;
border-radius: 50%;
width: 32px;
height: 32px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 1rem;
transition: all 0.2s ease;
}
.playlist-modal-close:hover {
background: rgba(220, 53, 69, 0.3);
border-color: rgba(220, 53, 69, 0.5);
}
.playlist-modal-body {
padding: 20px;
max-height: 60vh;
overflow-y: auto;
}
/* Save playlist form styles */
.save-playlist-form {
display: flex;
flex-direction: column;
gap: 16px;
}
.save-playlist-form label {
color: #ffffff;
font-weight: 500;
margin-bottom: 8px;
}
.save-playlist-form input {
background: rgba(0, 0, 0, 0.3);
border: 1px solid #404050;
border-radius: 6px;
color: #ffffff;
padding: 12px;
font-size: 1rem;
transition: border-color 0.2s ease;
}
.save-playlist-form input:focus {
outline: none;
border-color: #ff6b9d;
box-shadow: 0 0 0 2px rgba(255, 107, 157, 0.2);
}
.save-playlist-form input::placeholder {
color: #666;
}
.playlist-info {
color: #999;
font-size: 0.9rem;
text-align: center;
padding: 8px;
background: rgba(255, 255, 255, 0.05);
border-radius: 4px;
}
.save-actions {
display: flex;
gap: 12px;
justify-content: center;
}
.btn-save-playlist,
.btn-save-and-export {
padding: 10px 20px;
border-radius: 6px;
border: 1px solid;
cursor: pointer;
font-size: 0.9rem;
font-weight: 500;
transition: all 0.2s ease;
min-width: 120px;
}
.btn-save-playlist {
background: rgba(139, 99, 214, 0.15);
border-color: rgba(139, 99, 214, 0.3);
color: #e0e0e0;
}
.btn-save-playlist:hover {
background: rgba(139, 99, 214, 0.25);
border-color: rgba(139, 99, 214, 0.5);
}
.btn-save-and-export {
background: rgba(40, 167, 69, 0.15);
border-color: rgba(40, 167, 69, 0.3);
color: #e0e0e0;
}
.btn-save-and-export:hover {
background: rgba(40, 167, 69, 0.25);
border-color: rgba(40, 167, 69, 0.5);
}
.saved-playlists {
display: flex;
flex-direction: column;
gap: 12px;
margin-bottom: 20px;
}
.saved-playlist-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 16px;
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
border: 1px solid rgba(255, 255, 255, 0.1);
transition: all 0.3s ease;
}
.saved-playlist-item:hover {
background: rgba(255, 255, 255, 0.1);
border-color: rgba(255, 255, 255, 0.2);
}
.saved-playlist-info {
flex: 1;
min-width: 0;
}
.saved-playlist-name {
font-weight: 600;
color: #ffffff;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.saved-playlist-meta {
color: #999;
font-size: 0.85rem;
}
.saved-playlist-actions {
display: flex;
gap: 6px;
}
.btn-load-playlist,
.btn-export-playlist,
.btn-delete-playlist {
padding: 6px 10px;
border-radius: 4px;
border: 1px solid;
cursor: pointer;
font-size: 0.8rem;
transition: all 0.2s ease;
min-width: 60px;
}
.btn-load-playlist {
background: rgba(139, 99, 214, 0.15);
border-color: rgba(139, 99, 214, 0.3);
color: #e0e0e0;
}
.btn-load-playlist:hover {
background: rgba(139, 99, 214, 0.25);
border-color: rgba(139, 99, 214, 0.5);
}
.btn-export-playlist {
background: rgba(40, 167, 69, 0.15);
border-color: rgba(40, 167, 69, 0.3);
color: #e0e0e0;
}
.btn-export-playlist:hover {
background: rgba(40, 167, 69, 0.25);
border-color: rgba(40, 167, 69, 0.5);
}
.btn-delete-playlist {
background: rgba(220, 53, 69, 0.15);
border-color: rgba(220, 53, 69, 0.3);
color: #e0e0e0;
}
.btn-delete-playlist:hover {
background: rgba(220, 53, 69, 0.25);
border-color: rgba(220, 53, 69, 0.5);
}
.playlist-modal-separator {
display: flex;
align-items: center;
text-align: center;
margin: 20px 0;
color: #666;
font-size: 0.9rem;
}
.playlist-modal-separator::before,
.playlist-modal-separator::after {
content: '';
flex: 1;
height: 1px;
background: #404050;
}
.playlist-modal-separator span {
padding: 0 15px;
}
.file-upload-area {
text-align: center;
}
.btn-upload-playlist {
background: rgba(40, 167, 69, 0.15);
border: 1px solid rgba(40, 167, 69, 0.3);
color: #e0e0e0;
padding: 10px 20px;
border-radius: 6px;
cursor: pointer;
font-size: 0.9rem;
transition: all 0.2s ease;
}
.btn-upload-playlist:hover {
background: rgba(40, 167, 69, 0.25);
border-color: rgba(40, 167, 69, 0.5);
}
/* Responsive modal styles */
@media (max-width: 768px) {
.playlist-modal-content {
width: 95vw;
max-height: 90vh;
}
.saved-playlist-item {
flex-direction: column;
align-items: stretch;
gap: 12px;
}
.saved-playlist-actions {
justify-content: space-between;
}
.save-actions {
flex-direction: column;
}
}
/* ===== PLAYLIST CREATION MODAL ===== */
.create-playlist-modal {
max-width: 600px;
}
.create-playlist-form {
display: flex;
flex-direction: column;
gap: 20px;
}
.create-playlist-form label {
color: #ffffff;
font-weight: 500;
margin-bottom: 8px;
}
.create-playlist-form input {
background: rgba(0, 0, 0, 0.3);
border: 1px solid #404050;
border-radius: 6px;
color: #ffffff;
padding: 12px;
font-size: 1rem;
transition: border-color 0.2s ease;
}
.create-playlist-form input:focus {
outline: none;
border-color: #ff6b9d;
box-shadow: 0 0 0 2px rgba(255, 107, 157, 0.2);
}
.preselected-videos {
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
padding: 16px;
}
.preselected-videos h4 {
margin: 0 0 12px 0;
color: #28a745;
font-size: 1rem;
}
.video-list {
max-height: 200px;
overflow-y: auto;
display: flex;
flex-direction: column;
gap: 8px;
}
.playlist-creation-video-item {
display: flex;
align-items: center;
justify-content: space-between;
padding: 8px 12px;
background: rgba(255, 255, 255, 0.05);
border-radius: 6px;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.playlist-creation-video-item .video-name {
flex: 1;
color: #ffffff;
font-size: 0.9rem;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.btn-remove-from-creation {
background: rgba(220, 53, 69, 0.15);
border: 1px solid rgba(220, 53, 69, 0.3);
color: #e0e0e0;
border-radius: 50%;
width: 24px;
height: 24px;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
font-size: 12px;
transition: all 0.2s ease;
}
.btn-remove-from-creation:hover {
background: rgba(220, 53, 69, 0.25);
border-color: rgba(220, 53, 69, 0.5);
}
.empty-playlist-note {
background: rgba(255, 255, 255, 0.05);
border-radius: 8px;
padding: 16px;
text-align: center;
color: #999;
font-size: 0.9rem;
line-height: 1.4;
}
.playlist-creation-actions {
display: flex;
gap: 12px;
justify-content: center;
}
.btn-create-playlist,
.btn-create-and-switch {
padding: 12px 24px;
border-radius: 6px;
border: 1px solid;
cursor: pointer;
font-size: 0.9rem;
font-weight: 500;
transition: all 0.2s ease;
min-width: 140px;
}
.btn-create-playlist {
background: rgba(139, 99, 214, 0.15);
border-color: rgba(139, 99, 214, 0.3);
color: #e0e0e0;
}
.btn-create-playlist:hover {
background: rgba(139, 99, 214, 0.25);
border-color: rgba(139, 99, 214, 0.5);
}
.btn-create-and-switch {
background: rgba(40, 167, 69, 0.15);
border-color: rgba(40, 167, 69, 0.3);
color: #e0e0e0;
}
.btn-create-and-switch:hover {
background: rgba(40, 167, 69, 0.25);
border-color: rgba(40, 167, 69, 0.5);
}
/* Search panel */
.search-content {
flex: 1;
@ -776,6 +1209,23 @@ body.cinema-mode {
gap: 8px;
}
.playlist-management {
display: flex;
gap: 6px;
}
.playlist-management .btn-mini.has-selection {
background: rgba(40, 167, 69, 0.2);
border-color: rgba(40, 167, 69, 0.4);
color: #fff;
}
.playlist-management .btn-mini.active {
background: rgba(255, 107, 157, 0.2);
border-color: rgba(255, 107, 157, 0.4);
color: #fff;
}
.view-toggle {
display: flex;
border: 1px solid #444;
@ -873,6 +1323,7 @@ body.cinema-mode {
cursor: pointer;
transition: all 0.3s ease;
border: 2px solid transparent;
position: relative;
}
.video-card:hover {
@ -886,6 +1337,42 @@ body.cinema-mode {
background: rgba(255, 107, 157, 0.1);
}
.video-card.multi-selected {
border-color: #28a745;
background: rgba(40, 167, 69, 0.15);
}
.video-selection-checkbox {
position: absolute;
top: 8px;
left: 8px;
width: 24px;
height: 24px;
background: rgba(0, 0, 0, 0.7);
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
color: transparent;
font-size: 14px;
font-weight: bold;
cursor: pointer;
transition: all 0.3s ease;
z-index: 10;
}
.video-selection-checkbox.checked {
background: #28a745;
border-color: #28a745;
color: white;
}
.video-selection-checkbox:hover {
border-color: rgba(255, 255, 255, 0.6);
background: rgba(0, 0, 0, 0.8);
}
.video-thumbnail {
width: 100%;
height: 120px;
@ -969,6 +1456,7 @@ body.cinema-mode {
cursor: pointer;
transition: all 0.3s ease;
border: 1px solid transparent;
position: relative;
}
.video-list-item:hover {
@ -980,6 +1468,18 @@ body.cinema-mode {
background: rgba(255, 107, 157, 0.1);
}
.video-list-item.multi-selected {
border-color: #28a745;
background: rgba(40, 167, 69, 0.15);
}
.video-list-item .video-selection-checkbox {
position: relative;
top: auto;
left: auto;
margin-right: 12px;
}
.list-thumbnail {
width: 80px;
height: 50px;