Proyecto App Linux
This commit is contained in:
@@ -0,0 +1,120 @@
|
||||
// Shared content grid and card styles
|
||||
//
|
||||
// Usage (after adding libs/ui/styles to stylePreprocessorOptions.includePaths):
|
||||
// @use 'content-grid' as grid;
|
||||
// @include grid.content-grid;
|
||||
// @include grid.content-card;
|
||||
|
||||
@mixin content-grid($min-width: 140px, $gap: 20px) {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax($min-width, 1fr));
|
||||
gap: $gap;
|
||||
}
|
||||
|
||||
@mixin content-card {
|
||||
cursor: pointer;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
transition: transform 0.2s ease, box-shadow 0.2s ease;
|
||||
|
||||
&:hover {
|
||||
transform: translateY(-3px);
|
||||
box-shadow: 0 6px 16px rgba(0, 0, 0, 0.12);
|
||||
}
|
||||
}
|
||||
|
||||
@mixin thumbnail-wrapper {
|
||||
position: relative;
|
||||
border-radius: 10px;
|
||||
overflow: hidden;
|
||||
|
||||
.poster {
|
||||
width: 100%;
|
||||
aspect-ratio: 2/3;
|
||||
object-fit: cover;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.poster-placeholder {
|
||||
width: 100%;
|
||||
aspect-ratio: 2/3;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(128, 128, 128, 0.1);
|
||||
|
||||
mat-icon {
|
||||
font-size: 36px;
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
opacity: 0.25;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@mixin type-badge {
|
||||
position: absolute;
|
||||
top: 6px;
|
||||
left: 6px;
|
||||
padding: 3px 6px;
|
||||
border-radius: 4px;
|
||||
font-size: 9px;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 0.5px;
|
||||
background: rgba(0, 0, 0, 0.85);
|
||||
color: #fff;
|
||||
|
||||
&.live {
|
||||
color: #ef5350;
|
||||
}
|
||||
&.movie {
|
||||
color: #42a5f5;
|
||||
}
|
||||
&.series {
|
||||
color: #66bb6a;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin remove-button {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
right: 4px;
|
||||
z-index: 1;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
width: 28px;
|
||||
height: 28px;
|
||||
padding: 0;
|
||||
|
||||
&:hover {
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
mat-icon {
|
||||
color: white;
|
||||
font-size: 18px;
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin card-info {
|
||||
padding: 8px 10px;
|
||||
|
||||
h3 {
|
||||
margin: 0;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 500;
|
||||
line-height: 1.3;
|
||||
display: -webkit-box;
|
||||
-webkit-line-clamp: 2;
|
||||
-webkit-box-orient: vertical;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.date-info {
|
||||
margin: 4px 0 0;
|
||||
font-size: 0.7rem;
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// ─── IPTVnator UI styles library ─────────────────────────────────────────────
|
||||
// Add libs/ui/styles to stylePreprocessorOptions.includePaths in project.json
|
||||
// to import these without relative paths:
|
||||
//
|
||||
// @use 'portal-layout' as portal;
|
||||
// @use 'content-grid' as grid;
|
||||
// @use 'portal-sidebar';
|
||||
|
||||
@forward 'portal-layout';
|
||||
@forward 'content-grid';
|
||||
@forward 'portal-sidebar';
|
||||
@@ -0,0 +1,60 @@
|
||||
@mixin standard-panel-header(
|
||||
$sticky: false,
|
||||
$padding: 0 20px,
|
||||
$gap: 12px,
|
||||
$min-height: 52px,
|
||||
$z-index: 2,
|
||||
$border-color: var(--app-widget-header-border, rgba(255, 255, 255, 0.05))
|
||||
) {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
gap: $gap;
|
||||
padding: $padding;
|
||||
min-height: $min-height;
|
||||
flex-shrink: 0;
|
||||
background: var(--app-widget-header-bg, var(--mat-sys-surface-container-high));
|
||||
border-bottom: 1px solid $border-color;
|
||||
|
||||
@if $sticky {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: $z-index;
|
||||
}
|
||||
}
|
||||
|
||||
@mixin standard-panel-meta($gap: 10px) {
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: $gap;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
@mixin standard-panel-title($font-size: 0.95rem) {
|
||||
margin: 0;
|
||||
font-size: $font-size;
|
||||
font-weight: 600;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
color: var(--app-heading-color, var(--mat-sys-on-surface));
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
@mixin standard-panel-subtitle(
|
||||
$font-size: 0.78rem,
|
||||
$font-weight: 500,
|
||||
$padding: 2px 8px,
|
||||
$color: var(--app-body-color, var(--mat-sys-on-surface-variant)),
|
||||
$background: var(--mat-sys-surface-container)
|
||||
) {
|
||||
white-space: nowrap;
|
||||
font-size: $font-size;
|
||||
font-weight: $font-weight;
|
||||
color: $color;
|
||||
background: $background;
|
||||
padding: $padding;
|
||||
border-radius: 999px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// ─── Shared mixin for live-stream portal layouts ──────────────────────────────
|
||||
// Used by: xtream live-stream-layout, stalker live-stream-layout,
|
||||
// portal-collection-live-shell
|
||||
//
|
||||
// Include this mixin in a component's SCSS to get the shared flex host+sidebar
|
||||
// skeleton, then add only the component-specific rules underneath.
|
||||
//
|
||||
// Usage (after adding libs/ui/styles to stylePreprocessorOptions.includePaths):
|
||||
// @use 'portal-layout' as portal;
|
||||
// @include portal.live-layout;
|
||||
|
||||
@mixin live-layout {
|
||||
:host {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: hidden;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
// ─── Sidebar ─────────────────────────────────────────────────────────────
|
||||
.sidebar {
|
||||
// Width controlled by the resizable directive at runtime
|
||||
width: 400px;
|
||||
min-width: 250px;
|
||||
max-width: 600px;
|
||||
border-right: 1px solid var(--app-separator);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
container-type: inline-size;
|
||||
|
||||
app-category-view {
|
||||
flex: 1;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
margin-right: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Main content column ─────────────────────────────────────────────────
|
||||
.content-container {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow: hidden;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.video-player {
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
|
||||
> app-web-player-view {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.epg {
|
||||
flex: 1 1 0;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.epg-content {
|
||||
height: 100%;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
> app-epg-view {
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
}
|
||||
|
||||
// ─── Fix artplayer sizing when nested inside .video-player ───────────────
|
||||
::ng-deep {
|
||||
.video-player
|
||||
> app-web-player-view
|
||||
> app-art-player
|
||||
> .artplayer-container {
|
||||
height: 100% !important;
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
// ─── Shared sidebar + sidebar-header styles ───────────────────────────────────
|
||||
// Plain CSS rules (not a mixin) used for M3U/legacy sidebar layouts.
|
||||
//
|
||||
// Usage (after adding libs/ui/styles to stylePreprocessorOptions.includePaths):
|
||||
// @use 'portal-sidebar'; (no alias needed — no exported members to call)
|
||||
|
||||
.sidebar {
|
||||
// Width is controlled by the resizable directive
|
||||
// Default fallback if directive not applied
|
||||
width: 400px;
|
||||
min-width: 250px;
|
||||
max-width: 600px;
|
||||
border-right: 1px solid var(--app-separator);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-shrink: 0; // Prevent sidebar from shrinking
|
||||
|
||||
.sidebar-header {
|
||||
padding: 8px 12px;
|
||||
background: var(--app-widget-header-bg, var(--mat-sys-surface-container-high));
|
||||
border-bottom: 1px solid var(--app-separator);
|
||||
app-region: drag;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
flex-shrink: 0;
|
||||
|
||||
h2 {
|
||||
margin: 0;
|
||||
font-size: 0.94rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--mat-sys-on-surface);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
button {
|
||||
app-region: no-drag;
|
||||
}
|
||||
|
||||
.switcher {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.manage-categories-btn {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.category-heading {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 8px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.category-title {
|
||||
margin: 0;
|
||||
font-size: 0.94rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--mat-sys-on-surface);
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.category-count {
|
||||
flex-shrink: 0;
|
||||
font-size: 0.72rem;
|
||||
font-weight: 500;
|
||||
color: var(--mat-sys-on-surface-variant);
|
||||
background: var(--mat-sys-surface-container);
|
||||
padding: 2px 8px;
|
||||
border-radius: 999px;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user