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