mirror of
https://github.com/4gray/iptvnator.git
synced 2026-10-15 21:56:18 -08:00
refactor(ui): remove dead portal code and share detail styles (#946)
This commit is contained in:
1 parent
0ec9b29993
commit
5e5a89a300
21 files changed
+633
-2189
No files matched your search
@@ -1,562 +1,3 @@
|
||||
// ============================================================================
|
||||
// Netflix-style Detail View - Cinematic Streaming Design
|
||||
// ============================================================================
|
||||
@use '../../../../styles/detail-view' as detail-view;
|
||||
|
||||
@use '../../../../styles/detail-view-actions' as detail-actions;
|
||||
|
||||
:host {
|
||||
--poster-width: 220px;
|
||||
--poster-shadow: 0 8px 40px rgba(0, 0, 0, 0.15);
|
||||
--content-max-width: 1400px;
|
||||
|
||||
// Light theme colors (default - no .dark-theme class on body)
|
||||
--hero-gradient-start: rgba(255, 250, 245, 0);
|
||||
--hero-gradient-mid: rgba(255, 250, 245, 0.75);
|
||||
--hero-gradient-end: rgba(255, 250, 245, 1);
|
||||
--surface-bg: #fffaf5;
|
||||
--text-primary: #1a1a1a;
|
||||
--text-secondary: rgba(26, 26, 26, 0.75);
|
||||
--text-muted: rgba(26, 26, 26, 0.5);
|
||||
--accent-color: #b81d24;
|
||||
--tag-bg: rgba(0, 0, 0, 0.06);
|
||||
--tag-border: rgba(0, 0, 0, 0.12);
|
||||
--play-idle-bg: linear-gradient(
|
||||
135deg,
|
||||
#fffaf2 0%,
|
||||
#ffffff 52%,
|
||||
#f7ecdf 100%
|
||||
);
|
||||
--play-idle-fg: #161310;
|
||||
--play-idle-border: rgba(88, 48, 18, 0.12);
|
||||
--play-idle-shadow: 0 18px 38px rgba(91, 56, 24, 0.14);
|
||||
--play-launching-bg: linear-gradient(
|
||||
135deg,
|
||||
#ffd36f 0%,
|
||||
#ffb14c 46%,
|
||||
#f57d35 100%
|
||||
);
|
||||
--play-launching-fg: #241103;
|
||||
--play-launching-border: rgba(142, 66, 0, 0.2);
|
||||
--play-launching-shadow: 0 22px 44px rgba(244, 136, 55, 0.32);
|
||||
--play-stop-bg: linear-gradient(
|
||||
135deg,
|
||||
#ffd1c8 0%,
|
||||
#ff9f8d 42%,
|
||||
#ef5e64 100%
|
||||
);
|
||||
--play-stop-fg: #321012;
|
||||
--play-stop-border: rgba(162, 38, 45, 0.18);
|
||||
--play-stop-shadow: 0 22px 46px rgba(214, 74, 86, 0.26);
|
||||
--play-icon-shell-bg: rgba(255, 255, 255, 0.32);
|
||||
--play-icon-shell-border: rgba(255, 255, 255, 0.3);
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
background: var(--surface-bg);
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
// Dark theme overrides - cinematic dark mode
|
||||
:host-context(.dark-theme) {
|
||||
--hero-gradient-start: rgba(20, 20, 20, 0);
|
||||
--hero-gradient-mid: rgba(20, 20, 20, 0.7);
|
||||
--hero-gradient-end: rgba(20, 20, 20, 1);
|
||||
--surface-bg: #141414;
|
||||
--text-primary: #fff;
|
||||
--text-secondary: rgba(255, 255, 255, 0.7);
|
||||
--text-muted: rgba(255, 255, 255, 0.5);
|
||||
--accent-color: #e50914;
|
||||
--tag-bg: rgba(255, 255, 255, 0.1);
|
||||
--tag-border: rgba(255, 255, 255, 0.2);
|
||||
--poster-shadow: 0 8px 40px rgba(0, 0, 0, 0.5);
|
||||
--play-idle-bg: linear-gradient(
|
||||
135deg,
|
||||
#fff5e6 0%,
|
||||
#f6efe5 58%,
|
||||
#e7dac9 100%
|
||||
);
|
||||
--play-idle-fg: #15110d;
|
||||
--play-idle-border: rgba(255, 255, 255, 0.18);
|
||||
--play-idle-shadow: 0 20px 42px rgba(0, 0, 0, 0.36);
|
||||
--play-launching-bg: linear-gradient(
|
||||
135deg,
|
||||
#ffdd79 0%,
|
||||
#ffb347 42%,
|
||||
#ef6a3a 100%
|
||||
);
|
||||
--play-launching-fg: #1f1105;
|
||||
--play-launching-border: rgba(255, 223, 136, 0.26);
|
||||
--play-launching-shadow: 0 24px 50px rgba(255, 153, 71, 0.3);
|
||||
--play-stop-bg: linear-gradient(
|
||||
135deg,
|
||||
#ffd7cf 0%,
|
||||
#ff9b8b 40%,
|
||||
#eb5961 100%
|
||||
);
|
||||
--play-stop-fg: #2d1012;
|
||||
--play-stop-border: rgba(255, 205, 205, 0.24);
|
||||
--play-stop-shadow: 0 24px 50px rgba(235, 89, 97, 0.24);
|
||||
--play-icon-shell-bg: rgba(255, 255, 255, 0.28);
|
||||
--play-icon-shell-border: rgba(255, 255, 255, 0.24);
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Details Section - Content Elements
|
||||
// ============================================================================
|
||||
|
||||
.details {
|
||||
// Styles for projected content elements
|
||||
|
||||
&__tag {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 4px 12px;
|
||||
font-size: 0.8125rem;
|
||||
font-weight: 500;
|
||||
background: var(--tag-bg);
|
||||
border: 1px solid var(--tag-border);
|
||||
border-radius: 4px;
|
||||
backdrop-filter: blur(8px);
|
||||
|
||||
&--rating {
|
||||
color: #ffd700;
|
||||
border-color: rgba(255, 215, 0, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
&__meta-item {
|
||||
font-size: 0.875rem;
|
||||
|
||||
.label {
|
||||
color: var(--text-muted);
|
||||
font-weight: 400;
|
||||
margin-bottom: 2px;
|
||||
text-decoration: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.value {
|
||||
color: var(--text-primary);
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Action Buttons - Play, Favorite
|
||||
// ============================================================================
|
||||
|
||||
.play-btn {
|
||||
--play-btn-bg: var(--play-idle-bg);
|
||||
--play-btn-fg: var(--play-idle-fg);
|
||||
--play-btn-border: var(--play-idle-border);
|
||||
--play-btn-shadow: var(--play-idle-shadow);
|
||||
|
||||
position: relative;
|
||||
isolation: isolate;
|
||||
overflow: hidden;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 10px 24px 10px 18px;
|
||||
min-height: 64px;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0;
|
||||
background: var(--play-btn-bg);
|
||||
background-size: 140% 140%;
|
||||
background-position: 0% 50%;
|
||||
color: var(--play-btn-fg);
|
||||
border: 1px solid var(--play-btn-border);
|
||||
border-radius: 16px;
|
||||
box-shadow: var(--play-btn-shadow);
|
||||
cursor: pointer;
|
||||
transition:
|
||||
transform 220ms cubic-bezier(0.22, 1, 0.36, 1),
|
||||
background-position 280ms ease,
|
||||
box-shadow 260ms ease,
|
||||
border-color 220ms ease,
|
||||
color 220ms ease,
|
||||
filter 220ms ease;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: 1px;
|
||||
border-radius: inherit;
|
||||
background:
|
||||
linear-gradient(115deg, rgba(255, 255, 255, 0.34), transparent 36%),
|
||||
linear-gradient(180deg, rgba(255, 255, 255, 0.18), transparent 62%);
|
||||
opacity: 0.7;
|
||||
transition: opacity 220ms ease;
|
||||
z-index: -1;
|
||||
}
|
||||
|
||||
&:hover:not(:disabled) {
|
||||
transform: translateY(-2px);
|
||||
background-position: 100% 50%;
|
||||
box-shadow:
|
||||
var(--play-btn-shadow),
|
||||
0 10px 20px rgba(255, 255, 255, 0.16) inset;
|
||||
}
|
||||
|
||||
&:hover:not(:disabled)::before {
|
||||
opacity: 0.95;
|
||||
}
|
||||
|
||||
&:active:not(:disabled) {
|
||||
transform: translateY(0);
|
||||
box-shadow: var(--play-btn-shadow);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
cursor: progress;
|
||||
opacity: 1;
|
||||
filter: saturate(1.05);
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
font-size: 24px;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
transition:
|
||||
transform 220ms cubic-bezier(0.22, 1, 0.36, 1),
|
||||
color 220ms ease,
|
||||
filter 220ms ease;
|
||||
}
|
||||
|
||||
&:hover:not(:disabled) .play-btn__icon {
|
||||
transform: scale(1.08);
|
||||
}
|
||||
|
||||
&__icon-shell {
|
||||
flex: 0 0 auto;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
width: 34px;
|
||||
height: 34px;
|
||||
border-radius: 999px;
|
||||
background: var(--play-icon-shell-bg);
|
||||
border: 1px solid var(--play-icon-shell-border);
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.38),
|
||||
0 6px 14px rgba(0, 0, 0, 0.08);
|
||||
backdrop-filter: blur(10px);
|
||||
transition:
|
||||
transform 220ms ease,
|
||||
background-color 220ms ease,
|
||||
border-color 220ms ease,
|
||||
box-shadow 220ms ease;
|
||||
}
|
||||
|
||||
@include detail-actions.play-button-copy(var(--play-btn-fg));
|
||||
|
||||
&--state-launching,
|
||||
&--state-stop {
|
||||
color: var(--play-btn-fg);
|
||||
}
|
||||
|
||||
&--state-launching {
|
||||
--play-btn-bg: var(--play-launching-bg);
|
||||
--play-btn-fg: var(--play-launching-fg);
|
||||
--play-btn-border: var(--play-launching-border);
|
||||
--play-btn-shadow: var(--play-launching-shadow);
|
||||
animation: playButtonPulse 1.8s ease-in-out infinite;
|
||||
|
||||
.play-btn__icon-shell {
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.42),
|
||||
0 10px 22px rgba(184, 89, 26, 0.2);
|
||||
}
|
||||
|
||||
.play-btn__icon {
|
||||
animation: playIconLaunch 1.15s cubic-bezier(0.55, 0, 0.45, 1)
|
||||
infinite;
|
||||
}
|
||||
}
|
||||
|
||||
&--state-stop {
|
||||
--play-btn-bg: var(--play-stop-bg);
|
||||
--play-btn-fg: var(--play-stop-fg);
|
||||
--play-btn-border: var(--play-stop-border);
|
||||
--play-btn-shadow: var(--play-stop-shadow);
|
||||
|
||||
.play-btn__icon-shell {
|
||||
box-shadow:
|
||||
inset 0 1px 0 rgba(255, 255, 255, 0.4),
|
||||
0 12px 24px rgba(145, 38, 53, 0.18);
|
||||
}
|
||||
|
||||
.play-btn__icon {
|
||||
animation: playIconStop 1.2s ease-in-out infinite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes playButtonPulse {
|
||||
0%,
|
||||
100% {
|
||||
box-shadow: var(--play-btn-shadow);
|
||||
}
|
||||
|
||||
50% {
|
||||
box-shadow:
|
||||
var(--play-btn-shadow),
|
||||
0 0 0 6px rgba(255, 190, 92, 0.14);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes playIconLaunch {
|
||||
0%,
|
||||
100% {
|
||||
transform: rotate(0deg) scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: rotate(18deg) scale(1.1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes playIconStop {
|
||||
0%,
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
50% {
|
||||
transform: scale(1.08);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.play-btn,
|
||||
.play-btn::before,
|
||||
.play-btn mat-icon,
|
||||
.play-btn__icon-shell {
|
||||
animation: none !important;
|
||||
transition-duration: 1ms !important;
|
||||
}
|
||||
}
|
||||
|
||||
.favorite-btn,
|
||||
.download-btn {
|
||||
@include detail-actions.secondary-action-button;
|
||||
}
|
||||
|
||||
.favorite-btn {
|
||||
@include detail-actions.favorite-button-state;
|
||||
}
|
||||
|
||||
.download-btn {
|
||||
@include detail-actions.download-button-state;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Content Sections - Below the hero fold
|
||||
// ============================================================================
|
||||
|
||||
.content-section {
|
||||
padding: 20px 0;
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
|
||||
&__title {
|
||||
font-size: 1.375rem;
|
||||
font-weight: 600;
|
||||
margin: 0 0 20px 0;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Seasons & Episodes - Inside details section
|
||||
// ============================================================================
|
||||
|
||||
.seasons {
|
||||
margin-top: 24px;
|
||||
width: 100%;
|
||||
|
||||
.season-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px 0;
|
||||
cursor: pointer;
|
||||
transition: opacity 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
opacity: 0.8;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin: 0;
|
||||
font-size: 1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.expand-icon {
|
||||
font-size: 0.75rem;
|
||||
color: var(--text-muted);
|
||||
}
|
||||
}
|
||||
|
||||
.episodes {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
padding: 8px 0 16px;
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
font-weight: 500;
|
||||
}
|
||||
}
|
||||
|
||||
.episodes-loading,
|
||||
.seasons-loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 20px 0;
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
|
||||
.no-episodes {
|
||||
color: var(--text-muted);
|
||||
font-style: italic;
|
||||
padding: 8px 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Seasons loading when inside details
|
||||
.details .seasons-loading {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 20px 0;
|
||||
color: var(--text-secondary);
|
||||
margin-top: 24px;
|
||||
}
|
||||
|
||||
// Season container when inside details section
|
||||
.details app-season-container {
|
||||
display: block;
|
||||
width: 100%;
|
||||
margin-top: 24px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// YouTube Trailer Section - Inside details
|
||||
// ============================================================================
|
||||
|
||||
.youtube-trailer {
|
||||
margin-top: 24px;
|
||||
width: 100%;
|
||||
|
||||
h3 {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
margin: 0 0 12px 0;
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.trailer-wrapper {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
max-width: 560px;
|
||||
aspect-ratio: 16 / 9;
|
||||
border-radius: 8px;
|
||||
overflow: hidden;
|
||||
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
|
||||
|
||||
iframe {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Legacy container support (for gradual migration)
|
||||
// ============================================================================
|
||||
|
||||
.container {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
.image {
|
||||
display: none; // Hidden - now using .poster in hero
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Mobile Responsive - Option A: Keep poster grid layout
|
||||
// ============================================================================
|
||||
|
||||
@media (max-width: 800px) {
|
||||
:host {
|
||||
--poster-width: 120px;
|
||||
}
|
||||
|
||||
.action-buttons {
|
||||
width: 100%;
|
||||
// This class is in ContentHeroComponent now, but these rules apply to children?
|
||||
// No, .play-btn is a child of the PROJECTED content.
|
||||
// So we should target the buttons directly for mobile
|
||||
}
|
||||
|
||||
@include detail-actions.mobile-action-buttons;
|
||||
|
||||
.youtube-trailer {
|
||||
margin-top: 16px;
|
||||
|
||||
.trailer-wrapper {
|
||||
max-width: 100%;
|
||||
border-radius: 4px;
|
||||
}
|
||||
}
|
||||
|
||||
.seasons {
|
||||
padding: 16px 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Animations
|
||||
// ============================================================================
|
||||
|
||||
.youtube-trailer {
|
||||
animation: fadeInUp 0.5s ease-out 0.4s both;
|
||||
}
|
||||
|
||||
@keyframes fadeInUp {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(20px);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Utility - keep .label for backwards compatibility
|
||||
// ============================================================================
|
||||
|
||||
.label {
|
||||
font-weight: 400;
|
||||
font-size: 0.8125rem;
|
||||
color: var(--text-muted);
|
||||
text-decoration: none;
|
||||
padding: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
@include detail-view.base();
|
||||
Reference in new issue
Block a user