Compare commits
2 Commits
bd54ba9cfb
...
fa8c2b2658
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa8c2b2658 | ||
|
|
30776c02b9 |
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "twitch-vod-manager",
|
||||
"version": "4.6.20",
|
||||
"version": "4.6.21",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "twitch-vod-manager",
|
||||
"version": "4.6.20",
|
||||
"version": "4.6.21",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"axios": "^1.6.0",
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "twitch-vod-manager",
|
||||
"version": "4.6.20",
|
||||
"version": "4.6.21",
|
||||
"description": "Twitch VOD Manager - Download Twitch VODs easily",
|
||||
"main": "dist/main.js",
|
||||
"author": "xRangerDE",
|
||||
|
||||
@ -131,7 +131,7 @@
|
||||
|
||||
<!-- Button -->
|
||||
<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>
|
||||
@ -241,7 +241,7 @@
|
||||
|
||||
<div class="section-title" id="streamerSectionTitle" style="display:flex; align-items:center; gap:6px; justify-content:space-between;">
|
||||
<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>
|
||||
<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>
|
||||
@ -283,7 +283,7 @@
|
||||
<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;">
|
||||
<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>
|
||||
<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>
|
||||
@ -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;">
|
||||
<span id="vodBulkCount" style="color: var(--text); font-size:13px; font-weight:600;">0 selected</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="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="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="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="vodBulkAddBtn" class="btn-pill primary" type="button" onclick="bulkAddSelectedVodsToQueue()">+ Queue</button>
|
||||
<button id="vodBulkMarkBtn" class="btn-pill" type="button" onclick="bulkMarkSelectedDownloaded(true)">Mark as downloaded</button>
|
||||
<button id="vodBulkUnmarkBtn" class="btn-pill" type="button" onclick="bulkMarkSelectedDownloaded(false)">Unmark</button>
|
||||
<button id="vodBulkClearBtn" class="btn-pill" type="button" onclick="clearVodSelection()">Clear</button>
|
||||
</div>
|
||||
<div class="vod-grid" id="vodGrid">
|
||||
<div class="empty-state">
|
||||
|
||||
@ -111,8 +111,10 @@ function renderStreamerProfileCard(p: StreamerProfile): void {
|
||||
</div>`;
|
||||
|
||||
// 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
|
||||
? `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
|
||||
|
||||
163
src/styles.css
163
src/styles.css
@ -978,6 +978,139 @@ body {
|
||||
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 */
|
||||
.clip-input {
|
||||
max-width: 600px;
|
||||
@ -1949,23 +2082,35 @@ body.theme-light .modal {
|
||||
for instant familiarity, but trimmed for the desktop-app context. */
|
||||
.streamer-profile-header {
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 20;
|
||||
top: -25px; /* negate the .content top padding so the header pins flush with the visible top edge */
|
||||
z-index: 100;
|
||||
display: block;
|
||||
padding: 0;
|
||||
margin-top: -2px;
|
||||
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-radius: 12px;
|
||||
overflow: hidden;
|
||||
animation: profile-fade-in 0.32s ease-out;
|
||||
backdrop-filter: blur(6px);
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
isolation: isolate; /* new stacking context so VODs below cannot leak above */
|
||||
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 {
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
z-index: 2;
|
||||
display: flex;
|
||||
gap: 18px;
|
||||
align-items: center;
|
||||
@ -1977,11 +2122,11 @@ body.theme-light .modal {
|
||||
inset: 0;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
filter: blur(18px) saturate(1.2);
|
||||
opacity: 0.55;
|
||||
filter: blur(10px) saturate(1.35);
|
||||
opacity: 1;
|
||||
pointer-events: none;
|
||||
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 {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user