Update UI elements for consistency
This commit is contained in:
+64
-10
@@ -264,6 +264,44 @@ h4 {
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
/* Search wrapper for clear button */
|
||||
.search-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.search-wrapper .search-input {
|
||||
padding-right: 30px;
|
||||
/* Room for clear button */
|
||||
}
|
||||
|
||||
.search-clear {
|
||||
position: absolute;
|
||||
right: 6px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
background: none;
|
||||
border: none;
|
||||
color: var(--color-text-muted);
|
||||
font-size: 1.2rem;
|
||||
line-height: 1;
|
||||
cursor: pointer;
|
||||
padding: 4px;
|
||||
opacity: 0;
|
||||
transition: opacity var(--transition-fast), color var(--transition-fast);
|
||||
}
|
||||
|
||||
.search-wrapper:hover .search-clear,
|
||||
.search-input:focus~.search-clear {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.search-clear:hover {
|
||||
opacity: 1;
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
.sidebar-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -622,6 +660,12 @@ video::cue {
|
||||
gap: var(--space-md);
|
||||
}
|
||||
|
||||
.guide-controls {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--space-md);
|
||||
}
|
||||
|
||||
.guide-date {
|
||||
font-weight: 600;
|
||||
}
|
||||
@@ -1214,8 +1258,8 @@ kbd {
|
||||
}
|
||||
|
||||
.epg-program.current {
|
||||
background: var(--color-primary-bg);
|
||||
border-left: 3px solid var(--color-primary);
|
||||
background: var(--color-accent-dim);
|
||||
border-left: 3px solid var(--color-accent);
|
||||
}
|
||||
|
||||
.epg-program-time {
|
||||
@@ -1550,10 +1594,7 @@ kbd {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.movies-controls .source-select,
|
||||
.movies-controls .search-input {
|
||||
min-width: 200px;
|
||||
}
|
||||
|
||||
|
||||
/* Favorites Button */
|
||||
/* Favorites Button Base */
|
||||
@@ -1760,11 +1801,19 @@ kbd {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.series-controls .source-select,
|
||||
.series-controls .search-input {
|
||||
/* Unified Control Sizing */
|
||||
.guide-controls .source-select,
|
||||
.movies-controls .source-select,
|
||||
.series-controls .source-select {
|
||||
min-width: 150px;
|
||||
}
|
||||
|
||||
.guide-controls .search-wrapper,
|
||||
.movies-controls .search-wrapper,
|
||||
.series-controls .search-wrapper {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
.series-content {
|
||||
flex: 1;
|
||||
overflow: hidden;
|
||||
@@ -2023,8 +2072,13 @@ kbd {
|
||||
|
||||
/* Animation Utilities */
|
||||
@keyframes spin {
|
||||
from { transform: rotate(0deg); }
|
||||
to { transform: rotate(360deg); }
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.spin {
|
||||
|
||||
+16
-5
@@ -76,7 +76,10 @@
|
||||
<!-- Channel Sidebar -->
|
||||
<aside class="channel-sidebar">
|
||||
<div class="sidebar-header">
|
||||
<input type="text" id="channel-search" placeholder="Search channels..." class="search-input">
|
||||
<div class="search-wrapper">
|
||||
<input type="text" id="channel-search" placeholder="Search channels..." class="search-input">
|
||||
<button type="button" class="search-clear" title="Clear search">×</button>
|
||||
</div>
|
||||
<div class="sidebar-controls">
|
||||
<select id="source-select" class="source-select">
|
||||
<option value="">All Sources</option>
|
||||
@@ -129,11 +132,13 @@
|
||||
<div class="guide-header">
|
||||
<h2>TV Guide</h2>
|
||||
<div class="guide-controls">
|
||||
<input type="text" id="epg-search" placeholder="Search channels..." class="search-input"
|
||||
style="min-width: 200px;">
|
||||
<select id="epg-group-select" class="source-select">
|
||||
<option value="">All Groups</option>
|
||||
</select>
|
||||
<div class="search-wrapper">
|
||||
<input type="text" id="epg-search" placeholder="Search channels..." class="search-input">
|
||||
<button type="button" class="search-clear" title="Clear search">×</button>
|
||||
</div>
|
||||
<button id="guide-prev" class="btn btn-ghost">← Earlier</button>
|
||||
<span id="guide-date" class="guide-date">Today</span>
|
||||
<button id="guide-next" class="btn btn-ghost">Later →</button>
|
||||
@@ -158,7 +163,10 @@
|
||||
<select id="movies-category-select" class="source-select">
|
||||
<option value="">All Categories</option>
|
||||
</select>
|
||||
<input type="text" id="movies-search" placeholder="Search movies..." class="search-input">
|
||||
<div class="search-wrapper">
|
||||
<input type="text" id="movies-search" placeholder="Search movies..." class="search-input">
|
||||
<button type="button" class="search-clear" title="Clear search">×</button>
|
||||
</div>
|
||||
<button id="movies-favorites-btn" class="btn btn-icon btn-ghost" title="Show Favorites Only">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
|
||||
<path
|
||||
@@ -185,7 +193,10 @@
|
||||
<select id="series-category-select" class="source-select">
|
||||
<option value="">All Categories</option>
|
||||
</select>
|
||||
<input type="text" id="series-search" placeholder="Search series..." class="search-input">
|
||||
<div class="search-wrapper">
|
||||
<input type="text" id="series-search" placeholder="Search series..." class="search-input">
|
||||
<button type="button" class="search-clear" title="Clear search">×</button>
|
||||
</div>
|
||||
<button id="series-favorites-btn" class="btn btn-icon btn-ghost" title="Show Favorites Only">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="icon">
|
||||
<path
|
||||
|
||||
@@ -37,6 +37,19 @@ class App {
|
||||
this.channelList.toggleAllGroups();
|
||||
});
|
||||
|
||||
// Search clear buttons (global handler for all)
|
||||
document.querySelectorAll('.search-clear').forEach(btn => {
|
||||
btn.addEventListener('click', () => {
|
||||
const wrapper = btn.closest('.search-wrapper');
|
||||
const input = wrapper?.querySelector('.search-input');
|
||||
if (input) {
|
||||
input.value = '';
|
||||
input.dispatchEvent(new Event('input', { bubbles: true }));
|
||||
input.focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Initialize home page
|
||||
await this.pages.home.init();
|
||||
this.navigateTo('home');
|
||||
|
||||
@@ -292,7 +292,7 @@ class MoviesPage {
|
||||
<span class="play-icon">${Icons.play}</span>
|
||||
</div>
|
||||
<button class="favorite-btn ${isFav ? 'active' : ''}" title="${isFav ? 'Remove from Favorites' : 'Add to Favorites'}">
|
||||
<span class="fav-icon">${Icons.favorite}</span>
|
||||
<span class="fav-icon">${isFav ? Icons.favorite : Icons.favoriteOutline}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="movie-info">
|
||||
@@ -367,6 +367,7 @@ class MoviesPage {
|
||||
async toggleFavorite(movie, btn) {
|
||||
const favKey = `${movie.sourceId}:${movie.stream_id}`;
|
||||
const isFav = this.favoriteIds.has(favKey);
|
||||
const iconSpan = btn.querySelector('.fav-icon');
|
||||
|
||||
try {
|
||||
// Optimistic update
|
||||
@@ -374,11 +375,13 @@ class MoviesPage {
|
||||
this.favoriteIds.delete(favKey);
|
||||
btn.classList.remove('active');
|
||||
btn.title = 'Add to Favorites';
|
||||
if (iconSpan) iconSpan.innerHTML = Icons.favoriteOutline;
|
||||
await API.favorites.remove(movie.sourceId, movie.stream_id, 'movie');
|
||||
} else {
|
||||
this.favoriteIds.add(favKey);
|
||||
btn.classList.add('active');
|
||||
btn.title = 'Remove from Favorites';
|
||||
if (iconSpan) iconSpan.innerHTML = Icons.favorite;
|
||||
await API.favorites.add(movie.sourceId, movie.stream_id, 'movie');
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -387,9 +390,11 @@ class MoviesPage {
|
||||
if (isFav) {
|
||||
this.favoriteIds.add(favKey);
|
||||
btn.classList.add('active');
|
||||
if (iconSpan) iconSpan.innerHTML = Icons.favorite;
|
||||
} else {
|
||||
this.favoriteIds.delete(favKey);
|
||||
btn.classList.remove('active');
|
||||
if (iconSpan) iconSpan.innerHTML = Icons.favoriteOutline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +302,7 @@ class SeriesPage {
|
||||
<span class="play-icon">${Icons.play}</span>
|
||||
</div>
|
||||
<button class="favorite-btn ${isFav ? 'active' : ''}" title="${isFav ? 'Remove from Favorites' : 'Add to Favorites'}">
|
||||
<span class="fav-icon">${Icons.favorite}</span>
|
||||
<span class="fav-icon">${isFav ? Icons.favorite : Icons.favoriteOutline}</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="series-card-info">
|
||||
@@ -450,6 +450,7 @@ class SeriesPage {
|
||||
async toggleFavorite(series, btn) {
|
||||
const favKey = `${series.sourceId}:${series.series_id}`;
|
||||
const isFav = this.favoriteIds.has(favKey);
|
||||
const iconSpan = btn.querySelector('.fav-icon');
|
||||
|
||||
try {
|
||||
// Optimistic update
|
||||
@@ -457,11 +458,13 @@ class SeriesPage {
|
||||
this.favoriteIds.delete(favKey);
|
||||
btn.classList.remove('active');
|
||||
btn.title = 'Add to Favorites';
|
||||
if (iconSpan) iconSpan.innerHTML = Icons.favoriteOutline;
|
||||
await API.favorites.remove(series.sourceId, series.series_id, 'series');
|
||||
} else {
|
||||
this.favoriteIds.add(favKey);
|
||||
btn.classList.add('active');
|
||||
btn.title = 'Remove from Favorites';
|
||||
if (iconSpan) iconSpan.innerHTML = Icons.favorite;
|
||||
await API.favorites.add(series.sourceId, series.series_id, 'series');
|
||||
}
|
||||
} catch (err) {
|
||||
@@ -470,9 +473,11 @@ class SeriesPage {
|
||||
if (isFav) {
|
||||
this.favoriteIds.add(favKey);
|
||||
btn.classList.add('active');
|
||||
if (iconSpan) iconSpan.innerHTML = Icons.favorite;
|
||||
} else {
|
||||
this.favoriteIds.delete(favKey);
|
||||
btn.classList.remove('active');
|
||||
if (iconSpan) iconSpan.innerHTML = Icons.favoriteOutline;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user