fix: sticky header opaque + banner visible + missing button styles
Three things from screenshot feedback against 4.6.20: 1) VODs visible through/above the sticky profile header. Root cause was a stack: the 0.10/0.04 alpha gradient over var(--bg-card) pushed the resulting background just barely under "opaque" in some renderers AND .content has padding-top: 25px which let VODs scroll through the area above the sticky element when top: 0 was used. Fix: drop the gradient (banner-bg + ::before pseudo handle the visual interest now), use straight var(--bg-card), set top: -25px to negate .contents padding so the header pins flush with the visible top edge, bump z-index to 100, add isolation:isolate to force a new stacking context so VODs cannot escape upward through the header. 2) Banner not visible. Was being suppressed by a 0.78-0.92 alpha dimming gradient applied via background-image alongside the banner URL — readable for text but visually killed the banner. Moved the gradient into a ::before pseudo at z-index 1 with gentler 0.55-0.78 alpha, dropped banner-bg blur from 18px to 10px, took opacity from 0.55 back up to 1.0. Banner now actually shows behind the content the way twitch.tv does. 3) Stray un-styled buttons. Scan turned up a handful of action buttons rolling their own inline styles (.vodBulkAddBtn / MarkBtn / UnmarkBtn / ClearBtn, .vodFilterClearBtn, .btnStreamerBulkRemove, .clipDialogConfirmBtn) plus a missing .queue-detail-btn rule that was leaving every "View chat", "View events", "Open file", "Show in folder" button defaulting to the browsers gray fallback. Added three reusable classes (.btn-pill default/primary/success/danger, .btn-icon, plus the missing .queue-detail-btn) and swapped the inline styles for the classes. Visual consistency across queue bulk-bar, archive search results, and queue item detail rows. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bd54ba9cfb
commit
30776c02b9
@ -131,7 +131,7 @@
|
|||||||
|
|
||||||
<!-- Button -->
|
<!-- Button -->
|
||||||
<div style="text-align: center;">
|
<div style="text-align: center;">
|
||||||
<button class="btn-primary" id="clipDialogConfirmBtn" style="background: #00c853; padding: 12px 30px; border: none; border-radius: 4px; color: white; font-weight: 600; cursor: pointer;" onclick="confirmClipDialog()">Zur Queue hinzufugen</button>
|
<button class="btn-pill success" id="clipDialogConfirmBtn" style="padding: 12px 30px;" onclick="confirmClipDialog()">Zur Queue hinzufugen</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -241,7 +241,7 @@
|
|||||||
|
|
||||||
<div class="section-title" id="streamerSectionTitle" style="display:flex; align-items:center; gap:6px; justify-content:space-between;">
|
<div class="section-title" id="streamerSectionTitle" style="display:flex; align-items:center; gap:6px; justify-content:space-between;">
|
||||||
<span id="streamerSectionTitleText">Streamer</span>
|
<span id="streamerSectionTitleText">Streamer</span>
|
||||||
<button id="btnStreamerBulkRemove" type="button" onclick="bulkRemoveStreamers()" title="Bulk remove" style="display:none; background:transparent; border:1px solid var(--border-soft); border-radius:4px; padding:2px 8px; color:var(--text-secondary); font-size:11px; cursor:pointer;">x</button>
|
<button id="btnStreamerBulkRemove" class="btn-icon" type="button" onclick="bulkRemoveStreamers()" title="Bulk remove" style="display:none;">x</button>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" id="streamerListFilter" placeholder="Filter..." oninput="onStreamerListFilterChange()" style="display:none; width:calc(100% - 16px); margin:0 8px 8px; background:var(--bg-card); border:1px solid var(--border-soft); border-radius:4px; padding:4px 8px; color:var(--text); font-size:12px;">
|
<input type="text" id="streamerListFilter" placeholder="Filter..." oninput="onStreamerListFilterChange()" style="display:none; width:calc(100% - 16px); margin:0 8px 8px; background:var(--bg-card); border:1px solid var(--border-soft); border-radius:4px; padding:4px 8px; color:var(--text); font-size:12px;">
|
||||||
<div class="streamers" id="streamerList"></div>
|
<div class="streamers" id="streamerList"></div>
|
||||||
@ -283,7 +283,7 @@
|
|||||||
<div id="streamerProfileHeader" class="streamer-profile-header" style="display:none;"></div>
|
<div id="streamerProfileHeader" class="streamer-profile-header" style="display:none;"></div>
|
||||||
<div class="vod-filter-row" style="display:flex; align-items:center; gap:8px; margin-bottom:12px; flex-wrap:wrap;">
|
<div class="vod-filter-row" style="display:flex; align-items:center; gap:8px; margin-bottom:12px; flex-wrap:wrap;">
|
||||||
<input type="text" id="vodFilterInput" placeholder="Filter VODs..." oninput="onVodFilterInput()" style="flex:1; min-width:180px; background: var(--bg-card); border:1px solid var(--border-soft); border-radius:6px; padding:8px 12px; color: var(--text); font-size:13px;">
|
<input type="text" id="vodFilterInput" placeholder="Filter VODs..." oninput="onVodFilterInput()" style="flex:1; min-width:180px; background: var(--bg-card); border:1px solid var(--border-soft); border-radius:6px; padding:8px 12px; color: var(--text); font-size:13px;">
|
||||||
<button id="vodFilterClearBtn" onclick="clearVodFilter()" title="Clear filter" style="display:none; background:transparent; border:1px solid var(--border-soft); border-radius:6px; padding:8px 12px; color: var(--text-secondary); cursor:pointer;">x</button>
|
<button id="vodFilterClearBtn" class="btn-icon" onclick="clearVodFilter()" title="Clear filter" style="display:none;">x</button>
|
||||||
<label id="vodSortLabel" for="vodSortSelect" style="color: var(--text-secondary); font-size:12px; margin-left:8px;">Sort:</label>
|
<label id="vodSortLabel" for="vodSortSelect" style="color: var(--text-secondary); font-size:12px; margin-left:8px;">Sort:</label>
|
||||||
<select id="vodSortSelect" onchange="onVodSortChange()" style="background: var(--bg-card); border:1px solid var(--border-soft); border-radius:6px; padding:7px 10px; color: var(--text); font-size:13px;">
|
<select id="vodSortSelect" onchange="onVodSortChange()" style="background: var(--bg-card); border:1px solid var(--border-soft); border-radius:6px; padding:7px 10px; color: var(--text); font-size:13px;">
|
||||||
<option value="date_desc">Newest first</option>
|
<option value="date_desc">Newest first</option>
|
||||||
@ -301,10 +301,10 @@
|
|||||||
<div id="vodBulkBar" class="vod-bulk-bar" style="display:none; align-items:center; gap:10px; padding:8px 12px; background: rgba(145, 70, 255, 0.12); border:1px solid rgba(145, 70, 255, 0.4); border-radius:6px; margin-bottom:12px; flex-wrap:wrap;">
|
<div id="vodBulkBar" class="vod-bulk-bar" style="display:none; align-items:center; gap:10px; padding:8px 12px; background: rgba(145, 70, 255, 0.12); border:1px solid rgba(145, 70, 255, 0.4); border-radius:6px; margin-bottom:12px; flex-wrap:wrap;">
|
||||||
<span id="vodBulkCount" style="color: var(--text); font-size:13px; font-weight:600;">0 selected</span>
|
<span id="vodBulkCount" style="color: var(--text); font-size:13px; font-weight:600;">0 selected</span>
|
||||||
<span style="flex:1;"></span>
|
<span style="flex:1;"></span>
|
||||||
<button id="vodBulkAddBtn" type="button" onclick="bulkAddSelectedVodsToQueue()" style="background:var(--accent); border:none; border-radius:6px; padding:6px 14px; color:#fff; font-size:13px; font-weight:600; cursor:pointer;">+ Queue</button>
|
<button id="vodBulkAddBtn" class="btn-pill primary" type="button" onclick="bulkAddSelectedVodsToQueue()">+ Queue</button>
|
||||||
<button id="vodBulkMarkBtn" type="button" onclick="bulkMarkSelectedDownloaded(true)" style="background:transparent; border:1px solid var(--border-soft); border-radius:6px; padding:6px 12px; color:var(--text-secondary); font-size:13px; cursor:pointer;">Mark as downloaded</button>
|
<button id="vodBulkMarkBtn" class="btn-pill" type="button" onclick="bulkMarkSelectedDownloaded(true)">Mark as downloaded</button>
|
||||||
<button id="vodBulkUnmarkBtn" type="button" onclick="bulkMarkSelectedDownloaded(false)" style="background:transparent; border:1px solid var(--border-soft); border-radius:6px; padding:6px 12px; color:var(--text-secondary); font-size:13px; cursor:pointer;">Unmark</button>
|
<button id="vodBulkUnmarkBtn" class="btn-pill" type="button" onclick="bulkMarkSelectedDownloaded(false)">Unmark</button>
|
||||||
<button id="vodBulkClearBtn" type="button" onclick="clearVodSelection()" style="background:transparent; border:1px solid var(--border-soft); border-radius:6px; padding:6px 12px; color:var(--text-secondary); font-size:13px; cursor:pointer;">Clear</button>
|
<button id="vodBulkClearBtn" class="btn-pill" type="button" onclick="clearVodSelection()">Clear</button>
|
||||||
</div>
|
</div>
|
||||||
<div class="vod-grid" id="vodGrid">
|
<div class="vod-grid" id="vodGrid">
|
||||||
<div class="empty-state">
|
<div class="empty-state">
|
||||||
|
|||||||
@ -111,8 +111,10 @@ function renderStreamerProfileCard(p: StreamerProfile): void {
|
|||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
// Banner-as-background — set inline so the URL stays per-streamer.
|
// Banner-as-background — set inline so the URL stays per-streamer.
|
||||||
|
// The darkening gradient is handled by the .streamer-profile-header::before
|
||||||
|
// pseudo so the banner itself stays bright and unfiltered here.
|
||||||
const bannerStyle = p.bannerUrl
|
const bannerStyle = p.bannerUrl
|
||||||
? `background-image: linear-gradient(135deg, rgba(14,14,16,0.78) 0%, rgba(14,14,16,0.92) 100%), url("${p.bannerUrl.replace(/"/g, '%22')}");`
|
? `background-image: url("${p.bannerUrl.replace(/"/g, '%22')}");`
|
||||||
: '';
|
: '';
|
||||||
|
|
||||||
// Live preview block — only when currently live. Big card with
|
// Live preview block — only when currently live. Big card with
|
||||||
|
|||||||
163
src/styles.css
163
src/styles.css
@ -978,6 +978,139 @@ body {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================
|
||||||
|
COMPACT / UTILITY BUTTONS
|
||||||
|
============================================
|
||||||
|
.btn-pill — small action buttons used in toolbars + bulk-bars.
|
||||||
|
Comes in default (transparent), primary (purple), success (green).
|
||||||
|
Replaces the inline-style blocks the renderer was rolling for each
|
||||||
|
bulk action button. */
|
||||||
|
.btn-pill {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 6px;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
border: 1px solid var(--border-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 6px 12px;
|
||||||
|
font-size: 13px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s, color 0.15s, border-color 0.15s, transform 0.15s;
|
||||||
|
line-height: 1.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-pill:hover:not(:disabled) {
|
||||||
|
background: rgba(255, 255, 255, 0.06);
|
||||||
|
color: var(--text);
|
||||||
|
border-color: rgba(255, 255, 255, 0.18);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-pill:active:not(:disabled) {
|
||||||
|
transform: translateY(1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-pill:disabled {
|
||||||
|
opacity: 0.45;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-pill.primary {
|
||||||
|
background: var(--accent);
|
||||||
|
color: #fff;
|
||||||
|
border-color: var(--accent);
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-pill.primary:hover:not(:disabled) {
|
||||||
|
background: var(--accent-hover);
|
||||||
|
border-color: var(--accent-hover);
|
||||||
|
color: #fff;
|
||||||
|
box-shadow: 0 4px 14px rgba(145, 70, 255, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-pill.success {
|
||||||
|
background: #00c853;
|
||||||
|
color: #fff;
|
||||||
|
border-color: #00c853;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-pill.success:hover:not(:disabled) {
|
||||||
|
background: #00e676;
|
||||||
|
border-color: #00e676;
|
||||||
|
box-shadow: 0 4px 14px rgba(0, 200, 83, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-pill.danger {
|
||||||
|
background: transparent;
|
||||||
|
color: #ff6b6b;
|
||||||
|
border-color: rgba(255, 107, 107, 0.4);
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-pill.danger:hover:not(:disabled) {
|
||||||
|
background: rgba(255, 107, 107, 0.12);
|
||||||
|
border-color: rgba(255, 107, 107, 0.7);
|
||||||
|
color: #ff8a8a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .btn-icon — square X-close button for filter clears, inline removals.
|
||||||
|
1.6em wide, transparent base, hover only colours the X. */
|
||||||
|
.btn-icon {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: transparent;
|
||||||
|
border: 1px solid var(--border-soft);
|
||||||
|
border-radius: 6px;
|
||||||
|
padding: 6px 10px;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: background 0.15s, color 0.15s, border-color 0.15s;
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon:hover:not(:disabled) {
|
||||||
|
background: rgba(255, 70, 70, 0.10);
|
||||||
|
border-color: rgba(255, 70, 70, 0.45);
|
||||||
|
color: #ff6b6b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* .queue-detail-btn — tiny chip-style action button used in queue item
|
||||||
|
detail rows AND in the archive search results list. Was previously
|
||||||
|
rendering with browser defaults (gray flat button). */
|
||||||
|
.queue-detail-btn {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: rgba(145, 70, 255, 0.10);
|
||||||
|
color: var(--text);
|
||||||
|
border: 1px solid rgba(145, 70, 255, 0.30);
|
||||||
|
border-radius: 5px;
|
||||||
|
padding: 4px 10px;
|
||||||
|
margin-right: 6px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: 500;
|
||||||
|
cursor: pointer;
|
||||||
|
transition: background 0.15s, border-color 0.15s, color 0.15s, transform 0.12s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.queue-detail-btn:hover {
|
||||||
|
background: rgba(145, 70, 255, 0.22);
|
||||||
|
border-color: rgba(145, 70, 255, 0.6);
|
||||||
|
color: #fff;
|
||||||
|
transform: translateY(-1px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.queue-detail-btn:active {
|
||||||
|
transform: translateY(0);
|
||||||
|
}
|
||||||
|
|
||||||
/* Clips */
|
/* Clips */
|
||||||
.clip-input {
|
.clip-input {
|
||||||
max-width: 600px;
|
max-width: 600px;
|
||||||
@ -1949,23 +2082,35 @@ body.theme-light .modal {
|
|||||||
for instant familiarity, but trimmed for the desktop-app context. */
|
for instant familiarity, but trimmed for the desktop-app context. */
|
||||||
.streamer-profile-header {
|
.streamer-profile-header {
|
||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: -25px; /* negate the .content top padding so the header pins flush with the visible top edge */
|
||||||
z-index: 20;
|
z-index: 100;
|
||||||
display: block;
|
display: block;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
margin-top: -2px;
|
||||||
margin-bottom: 14px;
|
margin-bottom: 14px;
|
||||||
background: linear-gradient(135deg, rgba(145, 70, 255, 0.10) 0%, rgba(0, 200, 83, 0.04) 100%), var(--bg-card);
|
background: var(--bg-card);
|
||||||
border: 1px solid var(--border-soft);
|
border: 1px solid var(--border-soft);
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
animation: profile-fade-in 0.32s ease-out;
|
animation: profile-fade-in 0.32s ease-out;
|
||||||
backdrop-filter: blur(6px);
|
isolation: isolate; /* new stacking context so VODs below cannot leak above */
|
||||||
-webkit-backdrop-filter: blur(6px);
|
box-shadow: 0 6px 22px rgba(0, 0, 0, 0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dimming gradient sits ABOVE the banner-bg but BELOW the content row.
|
||||||
|
Gives the banner room to breathe while keeping name + bio readable. */
|
||||||
|
.streamer-profile-header::before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
inset: 0;
|
||||||
|
background: linear-gradient(135deg, rgba(15, 15, 18, 0.55) 0%, rgba(15, 15, 18, 0.78) 100%);
|
||||||
|
z-index: 1;
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
.streamer-profile-row {
|
.streamer-profile-row {
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 1;
|
z-index: 2;
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 18px;
|
gap: 18px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@ -1977,11 +2122,11 @@ body.theme-light .modal {
|
|||||||
inset: 0;
|
inset: 0;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
background-position: center;
|
background-position: center;
|
||||||
filter: blur(18px) saturate(1.2);
|
filter: blur(10px) saturate(1.35);
|
||||||
opacity: 0.55;
|
opacity: 1;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
z-index: 0;
|
z-index: 0;
|
||||||
transform: scale(1.1); /* avoid the blur edge bleed */
|
transform: scale(1.12); /* hide the blur edge bleed inside the rounded corner clip */
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes profile-fade-in {
|
@keyframes profile-fade-in {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user