Merge branch 'main' of github.com:monochrome-music/monochrome
This commit is contained in:
commit
704074d275
18 changed files with 1472 additions and 656 deletions
1
.github/workflows/copilot-setup-steps.yml
vendored
1
.github/workflows/copilot-setup-steps.yml
vendored
|
|
@ -20,7 +20,6 @@ jobs:
|
|||
# Copilot will be given its own token for its operations.
|
||||
permissions:
|
||||
contents: read
|
||||
workflows: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
|
|
|
|||
1
.github/workflows/editors-picks.yml
vendored
1
.github/workflows/editors-picks.yml
vendored
|
|
@ -104,6 +104,7 @@ jobs:
|
|||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
git pull --rebase origin main
|
||||
git add public/editors-picks.json public/editors-picks-old/
|
||||
git diff --staged --quiet && echo "No changes to commit." && exit 0
|
||||
git commit -m "chore: update editors picks"
|
||||
|
|
|
|||
43
.github/workflows/lighthouse.yml
vendored
Normal file
43
.github/workflows/lighthouse.yml
vendored
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
name: Lighthouse
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
lighthouse:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Build
|
||||
run: npm run build
|
||||
|
||||
- name: Preview build
|
||||
run: npm run preview &
|
||||
continue-on-error: true
|
||||
|
||||
- name: Wait for preview server
|
||||
run: sleep 10
|
||||
|
||||
- name: Run Lighthouse
|
||||
run: |
|
||||
npx lhci autorun --config=.lhci.yml || true
|
||||
|
||||
- name: Upload results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: lighthouse-results
|
||||
path: .lighthouseci/
|
||||
|
|
@ -21,4 +21,7 @@ album:250986538
|
|||
album:509761344
|
||||
album:15621057
|
||||
album:103897783
|
||||
album:151728406
|
||||
album:151728406
|
||||
album:199412873
|
||||
album:3280432
|
||||
album:37927851
|
||||
|
|
@ -19,4 +19,3 @@ new_func = """def download_and_process_cover(cover_uuid):
|
|||
content = re.sub(r"def download_and_process_cover\(cover_uuid\):[\s\S]*?(?=def process_cover)", new_func + "\n\n", content)
|
||||
|
||||
with open("gen-editors-picks.py", "w") as f: f.write(content)
|
||||
|
||||
|
|
|
|||
|
|
@ -9,32 +9,58 @@ import hashlib
|
|||
import time
|
||||
import os
|
||||
import tempfile
|
||||
import base64
|
||||
|
||||
INPUT_FILE = "editors-picks-input.txt"
|
||||
COUNTRY = "US"
|
||||
|
||||
# Tidal internal token replace when expired
|
||||
TIDAL_TOKEN = "eyJraWQiOiJ2OU1GbFhqWSIsImFsZyI6IkVTMjU2In0.eyJ0eXBlIjoibzJfYWNjZXNzIiwic2NvcGUiOiIiLCJnVmVyIjowLCJzVmVyIjowLCJjaWQiOjEzNTU3LCJhdCI6IklOVEVSTkFMIiwiZXhwIjoxNzc1MzY0MTQwLCJpc3MiOiJodHRwczovL2F1dGgudGlkYWwuY29tL3YxIn0.6ui6itHVQ-OXPF0F9mbf5KcKz1fKYJNsa1vBAj60upXpcN-DQG8JPKBlqJN6RuBEH8yhwYj2wh4YJ-TOOuO8DA"
|
||||
TIDAL_CLIENT_ID = "txNoH4kkV41MfH25"
|
||||
TIDAL_CLIENT_SECRET = "dQjy0MinCEvxi1O4UmxvxWnDjt4cgHBPw8ll6nYBk98="
|
||||
|
||||
TIDAL_HEADERS = {
|
||||
"accept": "*/*",
|
||||
"authorization": f"Bearer {TIDAL_TOKEN}",
|
||||
}
|
||||
|
||||
# PodcastIndex credentials
|
||||
PODCAST_API_KEY = "YU5HMSDYBQQVYDF6QN4P"
|
||||
PODCAST_API_SECRET = "8hCvpjSL7T$S7^5ftnf5MhqQwYUYVjM^fmUL3Ld$"
|
||||
PODCASTINDEX_BASE = "https://api.podcastindex.org/api/1.0"
|
||||
_tidal_token = None
|
||||
|
||||
|
||||
# ── Tidal helpers ─────────────────────────────────────────────────────────────
|
||||
def get_tidal_token():
|
||||
global _tidal_token
|
||||
if _tidal_token:
|
||||
return _tidal_token
|
||||
|
||||
credentials = base64.b64encode(f"{TIDAL_CLIENT_ID}:{TIDAL_CLIENT_SECRET}".encode()).decode()
|
||||
params = urllib.parse.urlencode({
|
||||
"client_id": TIDAL_CLIENT_ID,
|
||||
"client_secret": TIDAL_CLIENT_SECRET,
|
||||
"grant_type": "client_credentials",
|
||||
})
|
||||
req = urllib.request.Request(
|
||||
"https://auth.tidal.com/v1/oauth2/token",
|
||||
data=params.encode(),
|
||||
headers={
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Authorization": f"Basic {credentials}",
|
||||
},
|
||||
method="POST"
|
||||
)
|
||||
try:
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
data = json.loads(resp.read().decode())
|
||||
_tidal_token = data["access_token"]
|
||||
return _tidal_token
|
||||
except Exception as e:
|
||||
print(f"Error getting Tidal token: {e}", file=sys.stderr)
|
||||
return None
|
||||
|
||||
|
||||
def tidal_get(path, params=None):
|
||||
if params is None:
|
||||
params = {}
|
||||
params.setdefault("countryCode", COUNTRY)
|
||||
|
||||
token = get_tidal_token()
|
||||
if not token:
|
||||
return None
|
||||
|
||||
url = f"https://api.tidal.com/v1/{path}?{urllib.parse.urlencode(params)}"
|
||||
req = urllib.request.Request(url, headers=TIDAL_HEADERS)
|
||||
req = urllib.request.Request(url, headers={"Authorization": f"Bearer {token}"})
|
||||
try:
|
||||
with urllib.request.urlopen(req) as resp:
|
||||
return json.loads(resp.read().decode())
|
||||
|
|
|
|||
19
index.html
19
index.html
|
|
@ -205,13 +205,21 @@
|
|||
z-index: 0;
|
||||
"
|
||||
></div>
|
||||
<button id="fullscreen-dismiss-handle" type="button" aria-label="Dismiss fullscreen"></button>
|
||||
<button
|
||||
id="toggle-fullscreen-lyrics-mobile-btn"
|
||||
class="fullscreen-mobile-lyrics-toggle"
|
||||
title="Hide Lyrics"
|
||||
>
|
||||
<use svg="!lucide/mic-vocal.svg" size="18" />
|
||||
</button>
|
||||
<button id="toggle-ui-btn" class="fullscreen-ui-toggle" title="Toggle UI">
|
||||
<use svg="!lucide/eye-off.svg" size="24" />
|
||||
</button>
|
||||
<button id="toggle-fullscreen-lyrics-btn" class="fullscreen-lyrics-toggle" title="Toggle Lyrics">
|
||||
<use svg="!lucide/mic-vocal.svg" size="24" />
|
||||
</button>
|
||||
<div class="fullscreen-top-actions">
|
||||
<button id="toggle-fullscreen-lyrics-btn" class="fullscreen-lyrics-toggle" title="Hide Lyrics">
|
||||
<use svg="!lucide/mic-vocal.svg" size="20" />
|
||||
</button>
|
||||
<button id="fs-visualizer-btn" class="fs-visualizer-btn" title="Disable Visualizer">
|
||||
<use svg="!lucide/audio-lines.svg" size="20" />
|
||||
</button>
|
||||
|
|
@ -257,6 +265,11 @@
|
|||
</div>
|
||||
|
||||
<div class="fullscreen-controls">
|
||||
<div
|
||||
id="fullscreen-mobile-quality"
|
||||
class="fullscreen-mobile-quality"
|
||||
aria-hidden="true"
|
||||
></div>
|
||||
<div class="fullscreen-progress-container">
|
||||
<span id="fs-current-time">0:00</span>
|
||||
<div id="fs-progress-bar" class="progress-bar">
|
||||
|
|
|
|||
|
|
@ -1013,12 +1013,16 @@ function applyFullscreenLyricsShadowTweaks(amLyrics, container) {
|
|||
}
|
||||
|
||||
.lyrics-line {
|
||||
transform-origin: left center;
|
||||
transition:
|
||||
opacity 0.42s ease,
|
||||
transform 0.55s cubic-bezier(0.22, 1, 0.36, 1) var(--lyrics-line-delay, 0ms),
|
||||
filter 0.48s cubic-bezier(0.22, 1, 0.36, 1) !important;
|
||||
}
|
||||
|
||||
.lyrics-line:not(.active):not(.pre-active) {
|
||||
opacity: 0.44;
|
||||
}
|
||||
.lyrics-line-container {
|
||||
transition:
|
||||
transform 0.72s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
|
|
@ -1033,6 +1037,10 @@ function applyFullscreenLyricsShadowTweaks(amLyrics, container) {
|
|||
background-color 0.22s ease,
|
||||
color 0.22s ease !important;
|
||||
}
|
||||
|
||||
.lyrics-line.active .lyrics-line-container {
|
||||
transform: scale(1.015);
|
||||
}
|
||||
`;
|
||||
|
||||
return true;
|
||||
|
|
|
|||
293
js/ui.js
293
js/ui.js
|
|
@ -93,6 +93,7 @@ const setFullscreenUIToggleIcon = (button, visualizerOnlyMode) => {
|
|||
button.innerHTML = visualizerOnlyMode ? SVG_EYE(24) : SVG_EYE_OFF(24);
|
||||
};
|
||||
|
||||
const isMobileFullscreenViewport = () => window.matchMedia('(max-width: 768px)').matches;
|
||||
function sortTracks(tracks, sortType) {
|
||||
if (sortType === 'custom') return [...tracks];
|
||||
const sorted = [...tracks];
|
||||
|
|
@ -155,6 +156,10 @@ export class UIRenderer {
|
|||
this.renderLock = false;
|
||||
this.lastRecommendedTracks = [];
|
||||
this.currentArtistId = null;
|
||||
this.fullscreenLyricsVisible = true;
|
||||
this.fullscreenPlaybackStateCleanup = null;
|
||||
this.fullscreenDismissHandleCleanup = null;
|
||||
this.fullscreenLyricsToggleCleanup = null;
|
||||
|
||||
// Listen for dynamic color reset events
|
||||
window.addEventListener('reset-dynamic-color', () => {
|
||||
|
|
@ -545,7 +550,7 @@ export class UIRenderer {
|
|||
type = 'album'
|
||||
) {
|
||||
let size = '320';
|
||||
if (this.currentPage === 'search' || className === 'track-item-cover') {
|
||||
if (className === 'track-item-cover') {
|
||||
size = '80';
|
||||
} else if (type === 'artist') {
|
||||
size = '160';
|
||||
|
|
@ -1095,9 +1100,13 @@ export class UIRenderer {
|
|||
let r = parseInt(hex.substr(0, 2), 16);
|
||||
let g = parseInt(hex.substr(2, 2), 16);
|
||||
let b = parseInt(hex.substr(4, 2), 16);
|
||||
let fullscreenR = r;
|
||||
let fullscreenG = g;
|
||||
let fullscreenB = b;
|
||||
|
||||
// Calculate perceived brightness
|
||||
let brightness = (r * 299 + g * 587 + b * 114) / 1000;
|
||||
let fullscreenBrightness = brightness;
|
||||
|
||||
if (isLightMode) {
|
||||
// In light mode, the background is white.
|
||||
|
|
@ -1124,6 +1133,23 @@ export class UIRenderer {
|
|||
}
|
||||
|
||||
const adjustedColor = `#${r.toString(16).padStart(2, '0')}${g.toString(16).padStart(2, '0')}${b.toString(16).padStart(2, '0')}`;
|
||||
while (fullscreenBrightness < 105) {
|
||||
fullscreenR = Math.min(255, Math.max(fullscreenR + 1, Math.floor(fullscreenR * 1.08)));
|
||||
fullscreenG = Math.min(255, Math.max(fullscreenG + 1, Math.floor(fullscreenG * 1.08)));
|
||||
fullscreenB = Math.min(255, Math.max(fullscreenB + 1, Math.floor(fullscreenB * 1.08)));
|
||||
fullscreenBrightness = (fullscreenR * 299 + fullscreenG * 587 + fullscreenB * 114) / 1000;
|
||||
if (fullscreenR >= 255 && fullscreenG >= 255 && fullscreenB >= 255) break;
|
||||
}
|
||||
while (fullscreenBrightness > 185) {
|
||||
fullscreenR = Math.floor(fullscreenR * 0.92);
|
||||
fullscreenG = Math.floor(fullscreenG * 0.92);
|
||||
fullscreenB = Math.floor(fullscreenB * 0.92);
|
||||
fullscreenBrightness = (fullscreenR * 299 + fullscreenG * 587 + fullscreenB * 114) / 1000;
|
||||
}
|
||||
|
||||
const fullscreenAdjustedColor = `#${fullscreenR.toString(16).padStart(2, '0')}${fullscreenG
|
||||
.toString(16)
|
||||
.padStart(2, '0')}${fullscreenB.toString(16).padStart(2, '0')}`;
|
||||
|
||||
// Calculate contrast text color for buttons (text on top of the vibrant color)
|
||||
const foreground = brightness > 128 ? '#000000' : '#ffffff';
|
||||
|
|
@ -1135,6 +1161,8 @@ export class UIRenderer {
|
|||
root.style.setProperty('--highlight-rgb', `${r}, ${g}, ${b}`);
|
||||
root.style.setProperty('--active-highlight', adjustedColor);
|
||||
root.style.setProperty('--ring', adjustedColor);
|
||||
root.style.setProperty('--fs-accent', fullscreenAdjustedColor);
|
||||
root.style.setProperty('--fs-accent-rgb', `${fullscreenR}, ${fullscreenG}, ${fullscreenB}`);
|
||||
|
||||
// Calculate a safe hover color
|
||||
let hoverColor;
|
||||
|
|
@ -1157,6 +1185,8 @@ export class UIRenderer {
|
|||
root.style.removeProperty('--highlight-rgb');
|
||||
root.style.removeProperty('--active-highlight');
|
||||
root.style.removeProperty('--ring');
|
||||
root.style.removeProperty('--fs-accent');
|
||||
root.style.removeProperty('--fs-accent-rgb');
|
||||
root.style.removeProperty('--track-hover-bg');
|
||||
}
|
||||
|
||||
|
|
@ -1270,12 +1300,10 @@ export class UIRenderer {
|
|||
currentImage.src = coverUrl;
|
||||
}
|
||||
}
|
||||
overlay.style.setProperty('--bg-image', `url('${this.api.getCoverUrl(track.album?.cover, '1280')}')`);
|
||||
await this.extractAndApplyColor(this.api.getCoverUrl(track.album?.cover, '80'));
|
||||
}
|
||||
|
||||
const qualityBadge = this.getFullscreenQualityBadgeHTML(track);
|
||||
title.innerHTML = `${escapeHtml(track.title)} ${qualityBadge}`;
|
||||
this.updateFullscreenQualityBadgePlacement(track, overlay);
|
||||
artist.textContent = getTrackArtists(track);
|
||||
|
||||
if (nextTrack) {
|
||||
|
|
@ -1288,7 +1316,7 @@ export class UIRenderer {
|
|||
|
||||
async showFullscreenCover(track, nextTrack, lyricsManager, activeElement) {
|
||||
if (!track) return;
|
||||
this.fullscreenVisualizerSuppressed = true;
|
||||
this.fullscreenVisualizerSuppressed = isMobileFullscreenViewport();
|
||||
if (window.location.hash !== '#fullscreen') {
|
||||
window.history.pushState({ fullscreen: true }, '', '#fullscreen');
|
||||
}
|
||||
|
|
@ -1312,12 +1340,14 @@ export class UIRenderer {
|
|||
lyricsManager && activeElement && lyricsPane && lyricsContent && track.type !== 'video'
|
||||
);
|
||||
if (canRenderLyrics) {
|
||||
lyricsToggleBtn.style.display = 'none';
|
||||
this.fullscreenLyricsVisible = true;
|
||||
if (lyricsToggleBtn) lyricsToggleBtn.style.removeProperty('display');
|
||||
overlay.classList.remove('lyrics-unavailable');
|
||||
clearFullscreenLyricsSync(lyricsContent);
|
||||
await renderLyricsInFullscreen(track, activeElement, lyricsManager, lyricsContent);
|
||||
} else {
|
||||
lyricsToggleBtn.style.display = 'none';
|
||||
this.fullscreenLyricsVisible = false;
|
||||
if (lyricsToggleBtn) lyricsToggleBtn.style.display = 'none';
|
||||
overlay.classList.add('lyrics-unavailable');
|
||||
if (lyricsContent) {
|
||||
clearFullscreenLyricsSync(lyricsContent);
|
||||
|
|
@ -1325,6 +1355,7 @@ export class UIRenderer {
|
|||
'<div class="fullscreen-lyrics-empty">Lyrics are not available for this track.</div>';
|
||||
}
|
||||
}
|
||||
this.updateFullscreenLyricsVisibility(overlay);
|
||||
|
||||
const playerBar = document.querySelector('.now-playing-bar');
|
||||
if (playerBar) playerBar.style.display = 'none';
|
||||
|
|
@ -1355,9 +1386,85 @@ export class UIRenderer {
|
|||
this.setupUIToggleButton(overlay);
|
||||
this.setupControlsAutoHide(overlay);
|
||||
this.setupFullscreenSidePanelSync(overlay);
|
||||
this.setupFullscreenDismissHandle(overlay);
|
||||
this.setupFullscreenLyricsToggle(overlay);
|
||||
await this.refreshFullscreenVisualizerState(activeElement);
|
||||
}
|
||||
|
||||
updateFullscreenLyricsVisibility(overlay = document.getElementById('fullscreen-cover-overlay')) {
|
||||
if (!overlay) return;
|
||||
|
||||
const lyricsToggleButtons = [
|
||||
document.getElementById('toggle-fullscreen-lyrics-btn'),
|
||||
document.getElementById('toggle-fullscreen-lyrics-mobile-btn'),
|
||||
].filter(Boolean);
|
||||
const lyricsUnavailable = overlay.classList.contains('lyrics-unavailable');
|
||||
const shouldShowLyrics = this.fullscreenLyricsVisible && !lyricsUnavailable;
|
||||
|
||||
overlay.classList.toggle('lyrics-hidden', !shouldShowLyrics);
|
||||
this.updateFullscreenQualityBadgePlacement(this.player?.currentTrack, overlay);
|
||||
|
||||
lyricsToggleButtons.forEach((lyricsToggleBtn) => {
|
||||
lyricsToggleBtn.classList.toggle('active', shouldShowLyrics);
|
||||
lyricsToggleBtn.title = shouldShowLyrics ? 'Hide Lyrics' : 'Show Lyrics';
|
||||
lyricsToggleBtn.setAttribute('aria-pressed', shouldShowLyrics ? 'true' : 'false');
|
||||
if (lyricsUnavailable) {
|
||||
lyricsToggleBtn.style.display = 'none';
|
||||
} else {
|
||||
lyricsToggleBtn.style.removeProperty('display');
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
updateFullscreenQualityBadgePlacement(track, overlay = document.getElementById('fullscreen-cover-overlay')) {
|
||||
if (!track || !overlay) return;
|
||||
|
||||
const title = document.getElementById('fullscreen-track-title');
|
||||
const mobileQuality = document.getElementById('fullscreen-mobile-quality');
|
||||
if (!title) return;
|
||||
|
||||
const qualityBadge = this.getFullscreenQualityBadgeHTML(track);
|
||||
const useMobileBadgeOnly =
|
||||
window.matchMedia('(max-width: 768px)').matches && overlay.classList.contains('lyrics-hidden');
|
||||
|
||||
title.innerHTML = useMobileBadgeOnly ? escapeHtml(track.title) : `${escapeHtml(track.title)} ${qualityBadge}`;
|
||||
if (mobileQuality) {
|
||||
mobileQuality.innerHTML = useMobileBadgeOnly ? qualityBadge : '';
|
||||
}
|
||||
}
|
||||
|
||||
async dismissFullscreenCover({ animate = true } = {}) {
|
||||
const overlay = document.getElementById('fullscreen-cover-overlay');
|
||||
if (!overlay || overlay.style.display === 'none') return;
|
||||
|
||||
if (animate) {
|
||||
await new Promise((resolve) => {
|
||||
const finish = () => {
|
||||
overlay.removeEventListener('transitionend', handleTransitionEnd);
|
||||
overlay.classList.remove('fullscreen-dragging', 'fullscreen-dismissing');
|
||||
overlay.style.removeProperty('--fullscreen-drag-offset');
|
||||
overlay.style.removeProperty('--fullscreen-drag-progress');
|
||||
resolve();
|
||||
};
|
||||
|
||||
const handleTransitionEnd = (event) => {
|
||||
if (event.target !== overlay.querySelector('.fullscreen-cover-content')) return;
|
||||
finish();
|
||||
};
|
||||
|
||||
overlay.addEventListener('transitionend', handleTransitionEnd);
|
||||
overlay.classList.add('fullscreen-dismissing');
|
||||
window.setTimeout(finish, 280);
|
||||
});
|
||||
}
|
||||
|
||||
this.closeFullscreenCover();
|
||||
|
||||
if (window.location.hash === '#fullscreen') {
|
||||
window.history.back();
|
||||
}
|
||||
}
|
||||
|
||||
closeFullscreenCover() {
|
||||
const overlay = document.getElementById('fullscreen-cover-overlay');
|
||||
const coverImage = document.getElementById('fullscreen-cover-image');
|
||||
|
|
@ -1370,7 +1477,16 @@ export class UIRenderer {
|
|||
lyricsContent.innerHTML = '<div class="fullscreen-lyrics-empty">Lyrics appear here.</div>';
|
||||
}
|
||||
overlay.style.display = 'none';
|
||||
overlay.classList.remove('visualizer-active', 'ui-hidden', 'fullscreen-cover-no-round', 'fullscreen-paused');
|
||||
overlay.classList.remove(
|
||||
'visualizer-active',
|
||||
'ui-hidden',
|
||||
'fullscreen-cover-no-round',
|
||||
'fullscreen-paused',
|
||||
'fullscreen-dragging',
|
||||
'fullscreen-dismissing'
|
||||
);
|
||||
overlay.style.removeProperty('--fullscreen-drag-offset');
|
||||
overlay.style.removeProperty('--fullscreen-drag-progress');
|
||||
|
||||
const playerBar = document.querySelector('.now-playing-bar');
|
||||
if (playerBar) playerBar.style.removeProperty('display');
|
||||
|
|
@ -1434,6 +1550,16 @@ export class UIRenderer {
|
|||
this.fullscreenSidePanelSyncCleanup();
|
||||
this.fullscreenSidePanelSyncCleanup = null;
|
||||
}
|
||||
|
||||
if (this.fullscreenDismissHandleCleanup) {
|
||||
this.fullscreenDismissHandleCleanup();
|
||||
this.fullscreenDismissHandleCleanup = null;
|
||||
}
|
||||
|
||||
if (this.fullscreenLyricsToggleCleanup) {
|
||||
this.fullscreenLyricsToggleCleanup();
|
||||
this.fullscreenLyricsToggleCleanup = null;
|
||||
}
|
||||
}
|
||||
|
||||
async startFullscreenVisualizer(activeElement, overlay) {
|
||||
|
|
@ -1448,6 +1574,7 @@ export class UIRenderer {
|
|||
}
|
||||
|
||||
if (this.visualizer) {
|
||||
this.visualizer.applyPresetOverride('kawarp');
|
||||
await this.visualizer.start();
|
||||
overlay.classList.add('visualizer-active');
|
||||
}
|
||||
|
|
@ -1493,7 +1620,7 @@ export class UIRenderer {
|
|||
const visualizerBtn = document.getElementById('fs-visualizer-btn');
|
||||
const toggleBtn = document.getElementById('toggle-ui-btn');
|
||||
const isVideoTrack = this.player?.currentTrack?.type === 'video';
|
||||
const enabled = visualizerSettings.isEnabled() && !isVideoTrack && !this.fullscreenVisualizerSuppressed;
|
||||
const enabled = !isVideoTrack && !this.fullscreenVisualizerSuppressed && !isMobileFullscreenViewport();
|
||||
|
||||
if (!overlay) return;
|
||||
|
||||
|
|
@ -1578,7 +1705,6 @@ export class UIRenderer {
|
|||
}
|
||||
|
||||
this.fullscreenVisualizerSuppressed = false;
|
||||
visualizerSettings.setEnabled(true);
|
||||
await this.refreshFullscreenVisualizerState(this.player?.activeElement);
|
||||
|
||||
if (!overlay.classList.contains('visualizer-active')) {
|
||||
|
|
@ -1659,6 +1785,138 @@ export class UIRenderer {
|
|||
};
|
||||
}
|
||||
|
||||
setupFullscreenDismissHandle(overlay) {
|
||||
if (this.fullscreenDismissHandleCleanup) {
|
||||
this.fullscreenDismissHandleCleanup();
|
||||
this.fullscreenDismissHandleCleanup = null;
|
||||
}
|
||||
|
||||
const handle = document.getElementById('fullscreen-dismiss-handle');
|
||||
if (!handle) return;
|
||||
|
||||
let activePointerId = null;
|
||||
let startY = 0;
|
||||
let startX = 0;
|
||||
let lastY = 0;
|
||||
let lastTimestamp = 0;
|
||||
let velocityY = 0;
|
||||
let hasDragged = false;
|
||||
|
||||
const resetDragState = () => {
|
||||
activePointerId = null;
|
||||
hasDragged = false;
|
||||
overlay.classList.remove('fullscreen-dragging');
|
||||
overlay.style.removeProperty('--fullscreen-drag-offset');
|
||||
overlay.style.removeProperty('--fullscreen-drag-progress');
|
||||
};
|
||||
|
||||
const onPointerDown = (event) => {
|
||||
if (!isMobileFullscreenViewport()) return;
|
||||
|
||||
activePointerId = event.pointerId;
|
||||
startY = event.clientY;
|
||||
startX = event.clientX;
|
||||
lastY = event.clientY;
|
||||
lastTimestamp = event.timeStamp;
|
||||
velocityY = 0;
|
||||
hasDragged = false;
|
||||
overlay.classList.add('fullscreen-dragging');
|
||||
handle.setPointerCapture(event.pointerId);
|
||||
};
|
||||
|
||||
const onPointerMove = (event) => {
|
||||
if (event.pointerId !== activePointerId) return;
|
||||
|
||||
const deltaY = Math.max(0, event.clientY - startY);
|
||||
const deltaX = Math.abs(event.clientX - startX);
|
||||
|
||||
if (!hasDragged && deltaX > deltaY) {
|
||||
resetDragState();
|
||||
return;
|
||||
}
|
||||
|
||||
hasDragged = true;
|
||||
event.preventDefault();
|
||||
|
||||
const elapsed = Math.max(1, event.timeStamp - lastTimestamp);
|
||||
velocityY = (event.clientY - lastY) / elapsed;
|
||||
lastY = event.clientY;
|
||||
lastTimestamp = event.timeStamp;
|
||||
|
||||
const progress = Math.min(deltaY / Math.max(window.innerHeight * 0.32, 1), 1);
|
||||
overlay.style.setProperty('--fullscreen-drag-offset', `${deltaY}px`);
|
||||
overlay.style.setProperty('--fullscreen-drag-progress', progress.toFixed(3));
|
||||
};
|
||||
|
||||
const onPointerEnd = async (event) => {
|
||||
if (event.pointerId !== activePointerId) return;
|
||||
|
||||
const deltaY = Math.max(0, event.clientY - startY);
|
||||
const shouldDismiss = hasDragged && (deltaY > 96 || velocityY > 0.55);
|
||||
|
||||
if (handle.hasPointerCapture(event.pointerId)) {
|
||||
handle.releasePointerCapture(event.pointerId);
|
||||
}
|
||||
|
||||
if (shouldDismiss) {
|
||||
await this.dismissFullscreenCover();
|
||||
return;
|
||||
}
|
||||
|
||||
resetDragState();
|
||||
};
|
||||
|
||||
const onClick = async (event) => {
|
||||
if (!isMobileFullscreenViewport() || hasDragged) return;
|
||||
event.preventDefault();
|
||||
await this.dismissFullscreenCover();
|
||||
};
|
||||
|
||||
handle.addEventListener('pointerdown', onPointerDown);
|
||||
handle.addEventListener('pointermove', onPointerMove);
|
||||
handle.addEventListener('pointerup', onPointerEnd);
|
||||
handle.addEventListener('pointercancel', onPointerEnd);
|
||||
handle.addEventListener('click', onClick);
|
||||
|
||||
this.fullscreenDismissHandleCleanup = () => {
|
||||
handle.removeEventListener('pointerdown', onPointerDown);
|
||||
handle.removeEventListener('pointermove', onPointerMove);
|
||||
handle.removeEventListener('pointerup', onPointerEnd);
|
||||
handle.removeEventListener('pointercancel', onPointerEnd);
|
||||
handle.removeEventListener('click', onClick);
|
||||
overlay.classList.remove('fullscreen-dragging');
|
||||
overlay.style.removeProperty('--fullscreen-drag-offset');
|
||||
overlay.style.removeProperty('--fullscreen-drag-progress');
|
||||
};
|
||||
}
|
||||
|
||||
setupFullscreenLyricsToggle(overlay) {
|
||||
if (this.fullscreenLyricsToggleCleanup) {
|
||||
this.fullscreenLyricsToggleCleanup();
|
||||
this.fullscreenLyricsToggleCleanup = null;
|
||||
}
|
||||
|
||||
const toggleButtons = [
|
||||
document.getElementById('toggle-fullscreen-lyrics-btn'),
|
||||
document.getElementById('toggle-fullscreen-lyrics-mobile-btn'),
|
||||
].filter(Boolean);
|
||||
if (toggleButtons.length === 0) return;
|
||||
|
||||
const handleToggle = (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
if (overlay.classList.contains('lyrics-unavailable')) return;
|
||||
this.fullscreenLyricsVisible = !this.fullscreenLyricsVisible;
|
||||
this.updateFullscreenLyricsVisibility(overlay);
|
||||
};
|
||||
|
||||
toggleButtons.forEach((toggleBtn) => toggleBtn.addEventListener('click', handleToggle));
|
||||
this.updateFullscreenLyricsVisibility(overlay);
|
||||
|
||||
this.fullscreenLyricsToggleCleanup = () => {
|
||||
toggleButtons.forEach((toggleBtn) => toggleBtn.removeEventListener('click', handleToggle));
|
||||
};
|
||||
}
|
||||
setupFullscreenControls() {
|
||||
const playBtn = document.getElementById('fs-play-pause-btn');
|
||||
const prevBtn = document.getElementById('fs-prev-btn');
|
||||
|
|
@ -1728,16 +1986,7 @@ export class UIRenderer {
|
|||
|
||||
if (visualizerBtn) {
|
||||
visualizerBtn.onclick = async () => {
|
||||
if (this.fullscreenVisualizerSuppressed) {
|
||||
this.fullscreenVisualizerSuppressed = false;
|
||||
visualizerSettings.setEnabled(true);
|
||||
} else if (visualizerSettings.isEnabled()) {
|
||||
visualizerSettings.setEnabled(false);
|
||||
this.fullscreenVisualizerSuppressed = false;
|
||||
} else {
|
||||
this.fullscreenVisualizerSuppressed = false;
|
||||
visualizerSettings.setEnabled(true);
|
||||
}
|
||||
this.fullscreenVisualizerSuppressed = !this.fullscreenVisualizerSuppressed;
|
||||
await this.refreshFullscreenVisualizerState(this.player.activeElement);
|
||||
};
|
||||
}
|
||||
|
|
@ -3605,6 +3854,10 @@ export class UIRenderer {
|
|||
const data = await response.json();
|
||||
|
||||
rateCriticsEl.innerHTML = `<a href="${data.url}" target="_blank" style="color: var(--muted-foreground);">Critic Score: <span style="text-decoration: underline;">${data.critic.score}</span>, Based on ${data.critic.count} reviews</a>`;
|
||||
|
||||
if (data.critic.score == 'NR') {
|
||||
rateCriticsEl.innerHTML = `<a style="color: var(--muted-foreground);">Critic Score Not Available Yet</a>`;
|
||||
}
|
||||
rateUsersEl.innerHTML = `<a href="${data.url}" target="_blank" style="color: var(--muted-foreground);">User Score: <span style="text-decoration: underline;">${data.user.score}</span>, Based on ${data.user.count} reviews</a>`;
|
||||
} catch (e) {
|
||||
rateCriticsEl.innerHTML = `<a style="color: var(--muted-foreground);">Unable to Fetch Critic Score</a>`;
|
||||
|
|
|
|||
|
|
@ -337,4 +337,16 @@ export class Visualizer {
|
|||
});
|
||||
}
|
||||
}
|
||||
|
||||
applyPresetOverride(key) {
|
||||
if (!this.presets?.[key] || this.activePresetKey === key) return;
|
||||
|
||||
if (this.activePreset?.destroy) {
|
||||
this.activePreset.destroy();
|
||||
}
|
||||
|
||||
this._currentContextType = undefined;
|
||||
this.ctx = null;
|
||||
this.activePresetKey = key;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
27
lhci.yml
Normal file
27
lhci.yml
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
target: static
|
||||
assert:
|
||||
assertions:
|
||||
# Performance
|
||||
- first-contentful-paint:warn < 3000
|
||||
- interactive:warn < 7000
|
||||
- lcp-lazy-loaded:off
|
||||
- speed-index:warn < 5000
|
||||
|
||||
# Accessibility (warn if below 85)
|
||||
- accessibility:warn < 85
|
||||
|
||||
# Best Practices
|
||||
- best-practices:warn < 85
|
||||
|
||||
# SEO
|
||||
- seo:warn < 85
|
||||
|
||||
upload:
|
||||
target: temporary-public-storage
|
||||
|
||||
collect:
|
||||
numberOfRuns: 3
|
||||
settings:
|
||||
preset: desktop
|
||||
# Headless Chrome for CI
|
||||
chromeFlags: '--no-sandbox --disable-gpu'
|
||||
|
|
@ -17,7 +17,9 @@
|
|||
"lint:css": "stylelint \"**/*.css\"",
|
||||
"lint:html": "htmlhint \"**/*.html\" --ignore=\"dist/**,legacy/**,node_modules/**\"",
|
||||
"lint": "bun run lint:js && bun run lint:css && bun run lint:html",
|
||||
"format": "prettier --write ."
|
||||
"format": "prettier --write .",
|
||||
"lhci": "lhci",
|
||||
"lhci:autorun": "npm run build && lhci autorun"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
|
@ -33,6 +35,7 @@
|
|||
"devDependencies": {
|
||||
"@capacitor/assets": "^3.0.5",
|
||||
"@capacitor/cli": "^8.2.0",
|
||||
"@lhci/cli": "^0.14.0",
|
||||
"@testing-library/dom": "^10.4.1",
|
||||
"@types/node": "^25.3.5",
|
||||
"@vitest/browser-playwright": "^4.1.2",
|
||||
|
|
@ -47,6 +50,7 @@
|
|||
"stylelint": "^17.6.0",
|
||||
"stylelint-config-standard": "^39.0.1",
|
||||
"stylelint-config-standard-scss": "^16.0.0",
|
||||
"terser": "^5.46.1",
|
||||
"typescript": "^5.9.3",
|
||||
"vite": "^7.3.1",
|
||||
"vite-bundle-visualizer": "^1.2.1",
|
||||
|
|
|
|||
|
|
@ -1,274 +1 @@
|
|||
[
|
||||
{
|
||||
"type": "album",
|
||||
"id": 324660713,
|
||||
"title": "JOECHILLWORLD",
|
||||
"artist": {
|
||||
"id": 40978758,
|
||||
"name": "Devon Hendryx"
|
||||
},
|
||||
"releaseDate": "2010-07-10",
|
||||
"cover": "25d45544-3e82-4184-b8c2-2c2c6f0f152a",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS", "HIRES_LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 15427733,
|
||||
"title": "Mysterious Phonk: The Chronicles of SpaceGhostPurrp",
|
||||
"artist": {
|
||||
"id": 4611745,
|
||||
"name": "Spaceghostpurrp"
|
||||
},
|
||||
"releaseDate": "2012-06-12",
|
||||
"cover": "c78b7543-1cd8-4921-9155-e81d421353a0",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 464178301,
|
||||
"title": "Never Forget",
|
||||
"artist": {
|
||||
"id": 5516508,
|
||||
"name": "Chris Travis"
|
||||
},
|
||||
"releaseDate": "2014-05-14",
|
||||
"cover": "4ab11f0d-0768-4cce-8de5-1894134d5994",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 75115890,
|
||||
"title": "Blood Shore Season 2",
|
||||
"artist": {
|
||||
"id": 6332342,
|
||||
"name": "Xavier Wulf"
|
||||
},
|
||||
"releaseDate": "2014-10-30",
|
||||
"cover": "517303e5-d541-4704-b552-026427e05fcb",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 410197513,
|
||||
"title": "THE PEAK",
|
||||
"artist": {
|
||||
"id": 33481052,
|
||||
"name": "smokedope2016"
|
||||
},
|
||||
"releaseDate": "2025-01-17",
|
||||
"cover": "ea18084d-36ec-4cea-98a7-fe4684246986",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 418729278,
|
||||
"title": "I LAY DOWN MY LIFE FOR YOU: DIRECTOR'S CUT",
|
||||
"artist": {
|
||||
"id": 7958797,
|
||||
"name": "JPEGMAFIA"
|
||||
},
|
||||
"releaseDate": "2025-02-03",
|
||||
"cover": "9c84302b-2584-4c0a-9db7-e648542f459f",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS", "HIRES_LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 504004321,
|
||||
"title": "Half Blood (BloodLuxe)",
|
||||
"artist": {
|
||||
"id": 50799233,
|
||||
"name": "slayr"
|
||||
},
|
||||
"releaseDate": "2025-11-05",
|
||||
"cover": "2767cc63-7e92-4a48-aa4b-806a3ea7ec1c",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS", "HIRES_LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 510893864,
|
||||
"title": "BULLY",
|
||||
"artist": {
|
||||
"id": 25022,
|
||||
"name": "Kanye West"
|
||||
},
|
||||
"releaseDate": "2026-03-28",
|
||||
"cover": "cf2f2c9c-ff67-44f6-83aa-a7622f8c6b64",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS", "HIRES_LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 325723583,
|
||||
"title": "Replica",
|
||||
"artist": {
|
||||
"id": 3715530,
|
||||
"name": "Oneohtrix Point Never"
|
||||
},
|
||||
"releaseDate": "2011-11-05",
|
||||
"cover": "95ceeae9-cac7-42dc-ae37-7c93c223f809",
|
||||
"explicit": false,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 336178142,
|
||||
"title": "Pirate This Album",
|
||||
"artist": {
|
||||
"id": 8622751,
|
||||
"name": "Shamana"
|
||||
},
|
||||
"releaseDate": "2023-12-25",
|
||||
"cover": "a8a647be-0331-4779-9a6e-31645a9abdab",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS", "HIRES_LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 106369871,
|
||||
"title": "Organic Thoughts from the Synthetic Mind",
|
||||
"artist": {
|
||||
"id": 6436013,
|
||||
"name": "Shinjuku Mad"
|
||||
},
|
||||
"releaseDate": "2009-07-01",
|
||||
"cover": "3acc888e-35da-40a8-a4b7-7ffd00576cc9",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 423471869,
|
||||
"title": "pain",
|
||||
"artist": {
|
||||
"id": 44257324,
|
||||
"name": "bleood"
|
||||
},
|
||||
"releaseDate": "2025-03-11",
|
||||
"cover": "711b23ba-c473-44e6-a2f0-010fefa9c5b8",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 250986538,
|
||||
"title": "Revolutionary, Vol. 1 (Bonus Edition)",
|
||||
"artist": {
|
||||
"id": 3604583,
|
||||
"name": "Immortal Technique"
|
||||
},
|
||||
"releaseDate": "2001-09-14",
|
||||
"cover": "e510dd6d-dcdf-4272-9c68-f4580f2fbd14",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 509761344,
|
||||
"title": "EMOTIONS",
|
||||
"artist": {
|
||||
"id": 49124576,
|
||||
"name": "Nine Vicious"
|
||||
},
|
||||
"releaseDate": "2026-04-03",
|
||||
"cover": "f29b18d3-b19f-45b1-968a-0ad360647130",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 15621057,
|
||||
"title": "Triple F Life: Friends, Fans & Family (Deluxe Version)",
|
||||
"artist": {
|
||||
"id": 3654061,
|
||||
"name": "Waka Flocka Flame"
|
||||
},
|
||||
"releaseDate": "2012-06-12",
|
||||
"cover": "3199b7de-5e3d-486c-acf1-870ff4c60572",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 103897783,
|
||||
"title": "Freewave 3",
|
||||
"artist": {
|
||||
"id": 7923685,
|
||||
"name": "Lucki"
|
||||
},
|
||||
"releaseDate": "2019-02-15",
|
||||
"cover": "1d481a33-8b20-4ee3-b04b-5ac6e0fc5e78",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 151728406,
|
||||
"title": "Niagara",
|
||||
"artist": {
|
||||
"id": 7607680,
|
||||
"name": "redveil"
|
||||
},
|
||||
"releaseDate": "2020-08-25",
|
||||
"cover": "14690142-7fc8-4557-8a61-0721b7884822",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
}
|
||||
]
|
||||
[]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,19 @@
|
|||
[
|
||||
{
|
||||
"file": "2026-4-5.json",
|
||||
"label": "Spring 2026",
|
||||
"date": "2026-04-05"
|
||||
},
|
||||
{
|
||||
"file": "2026-4-5.json",
|
||||
"label": "Spring 2026",
|
||||
"date": "2026-04-05"
|
||||
},
|
||||
{
|
||||
"file": "2026-4-5.json",
|
||||
"label": "Spring 2026",
|
||||
"date": "2026-04-05"
|
||||
},
|
||||
{
|
||||
"file": "2026-4-5.json",
|
||||
"label": "Spring 2026",
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
"name": "Devon Hendryx"
|
||||
},
|
||||
"releaseDate": "2010-07-10",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/25d45544-3e82-4184-b8c2-2c2c6f0f152a.webp",
|
||||
"cover": "25d45544-3e82-4184-b8c2-2c2c6f0f152a",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -24,7 +24,7 @@
|
|||
"name": "Spaceghostpurrp"
|
||||
},
|
||||
"releaseDate": "2012-06-12",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/c78b7543-1cd8-4921-9155-e81d421353a0.webp",
|
||||
"cover": "c78b7543-1cd8-4921-9155-e81d421353a0",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -40,7 +40,7 @@
|
|||
"name": "Chris Travis"
|
||||
},
|
||||
"releaseDate": "2014-05-14",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/4ab11f0d-0768-4cce-8de5-1894134d5994.webp",
|
||||
"cover": "4ab11f0d-0768-4cce-8de5-1894134d5994",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -56,7 +56,7 @@
|
|||
"name": "Xavier Wulf"
|
||||
},
|
||||
"releaseDate": "2014-10-30",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/517303e5-d541-4704-b552-026427e05fcb.webp",
|
||||
"cover": "517303e5-d541-4704-b552-026427e05fcb",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -72,7 +72,7 @@
|
|||
"name": "smokedope2016"
|
||||
},
|
||||
"releaseDate": "2025-01-17",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/ea18084d-36ec-4cea-98a7-fe4684246986.webp",
|
||||
"cover": "ea18084d-36ec-4cea-98a7-fe4684246986",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -88,7 +88,7 @@
|
|||
"name": "JPEGMAFIA"
|
||||
},
|
||||
"releaseDate": "2025-02-03",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/9c84302b-2584-4c0a-9db7-e648542f459f.webp",
|
||||
"cover": "9c84302b-2584-4c0a-9db7-e648542f459f",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -104,7 +104,7 @@
|
|||
"name": "slayr"
|
||||
},
|
||||
"releaseDate": "2025-11-05",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/2767cc63-7e92-4a48-aa4b-806a3ea7ec1c.webp",
|
||||
"cover": "2767cc63-7e92-4a48-aa4b-806a3ea7ec1c",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -120,7 +120,7 @@
|
|||
"name": "Kanye West"
|
||||
},
|
||||
"releaseDate": "2026-03-28",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/cf2f2c9c-ff67-44f6-83aa-a7622f8c6b64.webp",
|
||||
"cover": "cf2f2c9c-ff67-44f6-83aa-a7622f8c6b64",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -136,7 +136,7 @@
|
|||
"name": "Oneohtrix Point Never"
|
||||
},
|
||||
"releaseDate": "2011-11-05",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/95ceeae9-cac7-42dc-ae37-7c93c223f809.webp",
|
||||
"cover": "95ceeae9-cac7-42dc-ae37-7c93c223f809",
|
||||
"explicit": false,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -152,7 +152,7 @@
|
|||
"name": "Shamana"
|
||||
},
|
||||
"releaseDate": "2023-12-25",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/a8a647be-0331-4779-9a6e-31645a9abdab.webp",
|
||||
"cover": "a8a647be-0331-4779-9a6e-31645a9abdab",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -168,7 +168,7 @@
|
|||
"name": "Shinjuku Mad"
|
||||
},
|
||||
"releaseDate": "2009-07-01",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/3acc888e-35da-40a8-a4b7-7ffd00576cc9.webp",
|
||||
"cover": "3acc888e-35da-40a8-a4b7-7ffd00576cc9",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -184,7 +184,7 @@
|
|||
"name": "bleood"
|
||||
},
|
||||
"releaseDate": "2025-03-11",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/711b23ba-c473-44e6-a2f0-010fefa9c5b8.webp",
|
||||
"cover": "711b23ba-c473-44e6-a2f0-010fefa9c5b8",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -200,7 +200,7 @@
|
|||
"name": "Immortal Technique"
|
||||
},
|
||||
"releaseDate": "2001-09-14",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/e510dd6d-dcdf-4272-9c68-f4580f2fbd14.webp",
|
||||
"cover": "e510dd6d-dcdf-4272-9c68-f4580f2fbd14",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -216,7 +216,7 @@
|
|||
"name": "Nine Vicious"
|
||||
},
|
||||
"releaseDate": "2026-04-03",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/f29b18d3-b19f-45b1-968a-0ad360647130.webp",
|
||||
"cover": "f29b18d3-b19f-45b1-968a-0ad360647130",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -232,7 +232,7 @@
|
|||
"name": "Waka Flocka Flame"
|
||||
},
|
||||
"releaseDate": "2012-06-12",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/3199b7de-5e3d-486c-acf1-870ff4c60572.webp",
|
||||
"cover": "3199b7de-5e3d-486c-acf1-870ff4c60572",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -248,7 +248,7 @@
|
|||
"name": "Lucki"
|
||||
},
|
||||
"releaseDate": "2019-02-15",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/1d481a33-8b20-4ee3-b04b-5ac6e0fc5e78.webp",
|
||||
"cover": "1d481a33-8b20-4ee3-b04b-5ac6e0fc5e78",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
|
|
@ -264,11 +264,59 @@
|
|||
"name": "redveil"
|
||||
},
|
||||
"releaseDate": "2020-08-25",
|
||||
"cover": "https://monochrome.tf/editors-picks-images/14690142-7fc8-4557-8a61-0721b7884822.webp",
|
||||
"cover": "14690142-7fc8-4557-8a61-0721b7884822",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 199412873,
|
||||
"title": "Tha Carter III",
|
||||
"artist": {
|
||||
"id": 27518,
|
||||
"name": "Lil Wayne"
|
||||
},
|
||||
"releaseDate": "2008-06-10",
|
||||
"cover": "797a90ea-3860-4d02-ac85-39b34ca8ee25",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOW",
|
||||
"mediaMetadata": {
|
||||
"tags": ["DOLBY_ATMOS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 3280432,
|
||||
"title": "We Are Young Money",
|
||||
"artist": {
|
||||
"id": 3654487,
|
||||
"name": "Young Money"
|
||||
},
|
||||
"releaseDate": "2009-12-21",
|
||||
"cover": "5b1456e5-1bba-415b-8276-8bc9cd211687",
|
||||
"explicit": true,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "album",
|
||||
"id": 37927851,
|
||||
"title": "The DeAndre Way (Deluxe)",
|
||||
"artist": {
|
||||
"id": 3820209,
|
||||
"name": "Soulja Boy"
|
||||
},
|
||||
"releaseDate": "2010-11-30",
|
||||
"cover": "6ca0217d-4f74-47d2-b449-30144d91e41f",
|
||||
"explicit": false,
|
||||
"audioQuality": "LOSSLESS",
|
||||
"mediaMetadata": {
|
||||
"tags": ["LOSSLESS"]
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
|||
758
styles.css
758
styles.css
|
|
@ -3575,7 +3575,7 @@ input:checked + .slider::before {
|
|||
}
|
||||
|
||||
.player-controls .progress-container span {
|
||||
min-width: 45px;
|
||||
min-width: 40px;
|
||||
font-variant-numeric: tabular-nums;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
|
@ -3920,29 +3920,25 @@ input:checked + .slider::before {
|
|||
justify-content: center;
|
||||
animation: fade-in 0.3s ease;
|
||||
overflow: hidden;
|
||||
background-color: var(--background);
|
||||
|
||||
/* Use a CSS variable for the image so we can set it in JS */
|
||||
--bg-image: none;
|
||||
background-color: rgb(11 13 17);
|
||||
|
||||
/* Reserve space above taskbar / system UI so volume controls stay visible (fixes #322) */
|
||||
padding-bottom: max(env(safe-area-inset-bottom), 1.5rem);
|
||||
|
||||
--fullscreen-drag-progress: 0;
|
||||
--fs-accent-rgb: var(--highlight-rgb);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
inset: -20px;
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
filter: var(--cover-filter);
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(circle at 50% 50%, rgb(255 255 255 / 0.035), transparent 58%),
|
||||
linear-gradient(180deg, rgb(6 8 12 / 0.12), rgb(6 8 12 / 0.34));
|
||||
z-index: -1;
|
||||
background-image: var(--bg-image);
|
||||
transition:
|
||||
background-image var(--transition),
|
||||
filter 0.65s ease,
|
||||
opacity 0.65s ease;
|
||||
transition: opacity 0.65s ease;
|
||||
opacity: calc(1 - (var(--fullscreen-drag-progress, 0) * 0.32));
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay::after {
|
||||
|
|
@ -3950,10 +3946,10 @@ input:checked + .slider::before {
|
|||
position: absolute;
|
||||
inset: 0;
|
||||
background:
|
||||
radial-gradient(circle at 20% 22%, rgb(var(--highlight-rgb) / 0.28), transparent 36%),
|
||||
radial-gradient(circle at 20% 22%, rgb(var(--fs-accent-rgb) / 0.28), transparent 36%),
|
||||
radial-gradient(circle at 82% 18%, rgb(255 255 255 / 0.09), transparent 28%),
|
||||
linear-gradient(135deg, rgb(10 13 18 / 0.48), rgb(10 13 18 / 0.2) 38%, rgb(var(--highlight-rgb) / 0.12) 100%);
|
||||
opacity: 0.36;
|
||||
linear-gradient(135deg, rgb(10 13 18 / 0.48), rgb(10 13 18 / 0.2) 38%, rgb(var(--fs-accent-rgb) / 0.12) 100%);
|
||||
opacity: calc(0.36 - (var(--fullscreen-drag-progress, 0) * 0.26));
|
||||
pointer-events: none;
|
||||
z-index: 0;
|
||||
transition:
|
||||
|
|
@ -3968,9 +3964,9 @@ input:checked + .slider::before {
|
|||
height: 100%;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
filter: blur(14px) saturate(0.84) brightness(0.8);
|
||||
transform: scale(1.04);
|
||||
opacity: 0.82;
|
||||
filter: blur(8px) saturate(0.9) brightness(0.8);
|
||||
transform: scale(1.03);
|
||||
opacity: 0.8;
|
||||
transition:
|
||||
opacity 0.65s ease,
|
||||
filter 0.65s ease,
|
||||
|
|
@ -3991,9 +3987,57 @@ input:checked + .slider::before {
|
|||
justify-content: center;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
padding: 1rem;
|
||||
overflow: hidden;
|
||||
transform: translateY(var(--fullscreen-drag-offset, 0));
|
||||
opacity: calc(1 - (var(--fullscreen-drag-progress, 0) * 0.16));
|
||||
transition:
|
||||
transform 0.26s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
opacity 0.22s ease;
|
||||
will-change: transform, opacity;
|
||||
}
|
||||
|
||||
#fullscreen-dismiss-handle {
|
||||
position: absolute;
|
||||
top: calc(0.75rem + env(safe-area-inset-top));
|
||||
left: 50%;
|
||||
width: 3.25rem;
|
||||
height: 1rem;
|
||||
border: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: transparent;
|
||||
transform: translateX(-50%);
|
||||
z-index: 14;
|
||||
display: none;
|
||||
cursor: grab;
|
||||
touch-action: none;
|
||||
}
|
||||
|
||||
#fullscreen-dismiss-handle::before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
width: 3rem;
|
||||
height: 0.3rem;
|
||||
border-radius: 999px;
|
||||
transform: translate(-50%, -50%);
|
||||
background: rgb(255 255 255 / 0.28);
|
||||
box-shadow: 0 2px 12px rgb(0 0 0 / 0.25);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.fullscreen-dragging .fullscreen-cover-content {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.fullscreen-dismissing .fullscreen-cover-content {
|
||||
transform: translateY(calc(100% + 3rem));
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
/* UI Toggle Button for Visualizer Mode - Rightmost position */
|
||||
|
|
@ -4071,6 +4115,38 @@ input:checked + .slider::before {
|
|||
background: var(--primary);
|
||||
}
|
||||
|
||||
#toggle-fullscreen-lyrics-mobile-btn {
|
||||
display: none;
|
||||
position: absolute;
|
||||
top: calc(0.85rem + env(safe-area-inset-top));
|
||||
right: calc(0.9rem + env(safe-area-inset-right));
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
border: none;
|
||||
border-radius: 999px;
|
||||
padding: 0;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgb(9 12 18 / 0.32);
|
||||
color: rgb(255 255 255 / 0.76);
|
||||
backdrop-filter: blur(10px);
|
||||
z-index: 14;
|
||||
transition:
|
||||
background-color 0.2s ease,
|
||||
color 0.2s ease,
|
||||
opacity 0.2s ease,
|
||||
transform 0.2s ease;
|
||||
}
|
||||
|
||||
#toggle-fullscreen-lyrics-mobile-btn.active {
|
||||
background: rgb(255 255 255 / 0.12);
|
||||
color: rgb(255 255 255 / 0.96);
|
||||
}
|
||||
|
||||
#toggle-fullscreen-lyrics-mobile-btn:hover {
|
||||
transform: scale(1.04);
|
||||
}
|
||||
|
||||
/* Close Button - Leftmost position */
|
||||
#close-fullscreen-cover-btn {
|
||||
position: absolute;
|
||||
|
|
@ -7817,148 +7893,6 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
transform: scale(0.97);
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
16-Band Graphic Equalizer (Legacy EQ)
|
||||
======================================== */
|
||||
.graphic-eq-section {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.graphic-eq-preset-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.graphic-eq-preset-label {
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
color: var(--foreground);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.graphic-eq-preset-select {
|
||||
flex: 1;
|
||||
padding: 8px 12px;
|
||||
background: var(--input);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
color: var(--foreground);
|
||||
font-size: 0.85rem;
|
||||
}
|
||||
|
||||
.graphic-eq-bands {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-end;
|
||||
gap: 2px;
|
||||
padding: var(--spacing-md) var(--spacing-sm);
|
||||
background: rgb(0, 0, 0, 0.15);
|
||||
border-radius: var(--radius);
|
||||
min-height: 240px;
|
||||
}
|
||||
|
||||
.graphic-eq-band {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 6px;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.graphic-eq-band-value {
|
||||
font-size: 0.65rem;
|
||||
color: var(--foreground);
|
||||
font-variant-numeric: tabular-nums;
|
||||
white-space: nowrap;
|
||||
min-height: 14px;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.graphic-eq-band-slider-wrap {
|
||||
position: relative;
|
||||
height: 160px;
|
||||
width: 28px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.graphic-eq-band-slider-wrap input[type='range'] {
|
||||
writing-mode: vertical-lr;
|
||||
direction: rtl;
|
||||
width: 28px;
|
||||
height: 100%;
|
||||
accent-color: var(--foreground);
|
||||
cursor: pointer;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.graphic-eq-band-label {
|
||||
font-size: 0.6rem;
|
||||
color: var(--muted-foreground);
|
||||
white-space: nowrap;
|
||||
text-align: center;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
.graphic-eq-bottom-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-md);
|
||||
}
|
||||
|
||||
.graphic-eq-preamp {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.graphic-eq-preamp-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
color: var(--muted-foreground);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.graphic-eq-preamp-slider {
|
||||
flex: 1;
|
||||
height: 4px;
|
||||
accent-color: var(--highlight);
|
||||
}
|
||||
|
||||
.graphic-eq-preamp-value {
|
||||
font-size: 0.75rem;
|
||||
color: var(--muted-foreground);
|
||||
min-width: 45px;
|
||||
text-align: right;
|
||||
font-variant-numeric: tabular-nums;
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.graphic-eq-bands {
|
||||
min-height: 180px;
|
||||
}
|
||||
|
||||
.graphic-eq-band-slider-wrap {
|
||||
height: 130px;
|
||||
width: 22px;
|
||||
}
|
||||
|
||||
.graphic-eq-band-label {
|
||||
font-size: 0.5rem;
|
||||
}
|
||||
|
||||
.graphic-eq-band-value {
|
||||
font-size: 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
/* ========================================
|
||||
Precision AutoEQ - Redesigned Equalizer
|
||||
======================================== */
|
||||
|
|
@ -8579,19 +8513,6 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: var(--spacing-md);
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
transition: background var(--transition-fast);
|
||||
}
|
||||
|
||||
.autoeq-database-header:hover {
|
||||
background: rgb(var(--highlight-rgb), 0.08);
|
||||
}
|
||||
|
||||
.autoeq-database-header-right {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.autoeq-database-title {
|
||||
|
|
@ -9311,69 +9232,6 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
flex: 1;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
/* Mobile parametric EQ band layout */
|
||||
.autoeq-band-control {
|
||||
padding: 0.5rem;
|
||||
}
|
||||
|
||||
.autoeq-band-header {
|
||||
flex-wrap: wrap;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.autoeq-band-number {
|
||||
min-width: 1.2rem;
|
||||
}
|
||||
|
||||
.autoeq-band-param {
|
||||
min-width: 0;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.autoeq-band-sliders {
|
||||
flex-direction: column;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
|
||||
.autoeq-band-slider {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
.autoeq-band-slider::-webkit-slider-thumb {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.autoeq-band-slider::-moz-range-thumb {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
.autoeq-filters-actions {
|
||||
flex-wrap: wrap;
|
||||
gap: 0.3rem;
|
||||
}
|
||||
|
||||
.autoeq-filters-actions button {
|
||||
font-size: 0.7rem;
|
||||
padding: 0.3rem 0.5rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
/* Rearrange band header into 2 rows on small screens */
|
||||
.autoeq-band-header {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto 1fr 1fr 1fr;
|
||||
gap: 0.25rem 0.4rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.autoeq-band-param {
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
|
||||
/* Track List Search */
|
||||
|
|
@ -10229,35 +10087,12 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
}
|
||||
|
||||
.about-contributors div {
|
||||
flex: 1 1 calc(25% - 10px);
|
||||
min-width: 150px;
|
||||
max-width: calc(50% - 10px);
|
||||
width: calc(20% - 8px);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 14px;
|
||||
padding: 20px;
|
||||
padding: 30px;
|
||||
text-align: center;
|
||||
overflow: hidden;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.about-contributors div {
|
||||
flex: 1 1 calc(50% - 10px);
|
||||
max-width: 100%;
|
||||
padding: 15px;
|
||||
}
|
||||
}
|
||||
|
||||
.about-contributors a {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
.about-contributors img {
|
||||
|
|
@ -10281,24 +10116,34 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
display: flex;
|
||||
align-items: stretch;
|
||||
justify-content: center;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-main-view {
|
||||
width: min(1240px, 100%);
|
||||
--fs-media-column-size: minmax(340px, 430px);
|
||||
--fs-lyrics-column-size: minmax(520px, 760px);
|
||||
|
||||
width: min(1480px, 100%);
|
||||
height: 100%;
|
||||
flex: 1;
|
||||
display: grid;
|
||||
grid-template-columns: minmax(360px, 430px) minmax(420px, 1fr);
|
||||
gap: clamp(1.5rem, 3vw, 3rem);
|
||||
grid-template-columns: var(--fs-media-column-size) var(--fs-lyrics-column-size);
|
||||
gap: clamp(2rem, 4vw, 4.5rem);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: clamp(4rem, 7vh, 5rem) clamp(2rem, 4vw, 3rem) clamp(3rem, 6vh, 4rem) clamp(4rem, 7vw, 6.25rem);
|
||||
padding: clamp(4rem, 7vh, 5rem) clamp(3rem, 6vw, 5rem) clamp(3rem, 6vh, 4rem);
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
min-height: 0;
|
||||
overflow: hidden;
|
||||
transition:
|
||||
grid-template-columns 0.34s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
width 0.34s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
gap 0.34s cubic-bezier(0.22, 1, 0.36, 1);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-media-column,
|
||||
|
|
@ -10312,7 +10157,11 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
flex-direction: column;
|
||||
gap: 0.95rem;
|
||||
justify-self: center;
|
||||
transform: translateX(clamp(0.75rem, 1.2vw, 1.4rem));
|
||||
transform: none;
|
||||
transition:
|
||||
width 0.34s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
transform 0.34s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
opacity 0.24s ease;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-artwork-card {
|
||||
|
|
@ -10365,7 +10214,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
|
||||
#fullscreen-cover-overlay #toggle-fullscreen-lyrics-btn,
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-toggle {
|
||||
display: none !important;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-actions {
|
||||
|
|
@ -10443,9 +10292,10 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-top-actions #fs-visualizer-btn {
|
||||
order: 2;
|
||||
order: 3;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-top-actions #toggle-fullscreen-lyrics-btn,
|
||||
#fullscreen-cover-overlay .fullscreen-top-actions #fs-visualizer-btn,
|
||||
#fullscreen-cover-overlay .fullscreen-top-actions #close-fullscreen-cover-btn {
|
||||
position: static;
|
||||
|
|
@ -10457,6 +10307,15 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
opacity: 1;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-top-actions #toggle-fullscreen-lyrics-btn {
|
||||
order: 2;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-top-actions #toggle-fullscreen-lyrics-btn.active {
|
||||
color: rgb(255 255 255 / 0.96);
|
||||
background: rgb(255 255 255 / 0.12);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-top-actions #close-fullscreen-cover-btn {
|
||||
order: 1;
|
||||
}
|
||||
|
|
@ -10477,7 +10336,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
|
||||
#fullscreen-cover-overlay #toggle-ui-btn {
|
||||
top: 1.25rem;
|
||||
left: calc(80px + 2.3rem + env(safe-area-inset-left));
|
||||
left: calc(9.9rem + env(safe-area-inset-left));
|
||||
right: auto;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
|
@ -10522,7 +10381,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-buttons button.active {
|
||||
color: rgb(var(--highlight-rgb) / 0.98);
|
||||
color: rgb(var(--fs-accent-rgb) / 0.98);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-buttons #fs-play-pause-btn {
|
||||
|
|
@ -10563,7 +10422,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
}
|
||||
|
||||
#fullscreen-cover-overlay .fs-visualizer-btn.active {
|
||||
color: rgb(var(--highlight-rgb) / 0.96);
|
||||
color: rgb(var(--fs-accent-rgb) / 0.96);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fs-volume-btn {
|
||||
|
|
@ -10609,7 +10468,7 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
|
||||
#fullscreen-cover-overlay .fullscreen-progress-container .progress-bar:hover .progress-fill,
|
||||
#fullscreen-cover-overlay .fs-volume-bar:hover .fs-volume-fill {
|
||||
background: rgb(var(--highlight-rgb) / 0.94);
|
||||
background: rgb(var(--fs-accent-rgb) / 0.94);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-progress-container .progress-bar:hover .progress-fill::after,
|
||||
|
|
@ -10626,6 +10485,13 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
align-items: stretch;
|
||||
justify-content: flex-start;
|
||||
overflow: hidden;
|
||||
min-width: 0;
|
||||
opacity: 1;
|
||||
transform: translateX(0);
|
||||
transition:
|
||||
opacity 0.24s ease,
|
||||
transform 0.34s cubic-bezier(0.22, 1, 0.36, 1),
|
||||
visibility 0s linear 0s;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-shell,
|
||||
|
|
@ -10641,14 +10507,14 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
#fullscreen-cover-overlay .fullscreen-lyrics-shell {
|
||||
width: min(860px, 100%);
|
||||
min-height: 0;
|
||||
margin-left: clamp(4rem, 8vw, 8rem);
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-content {
|
||||
min-height: 0;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
padding-left: clamp(2.5rem, 4vw, 4rem);
|
||||
padding-left: clamp(0.5rem, 1.6vw, 1.5rem);
|
||||
mask-image: none;
|
||||
overflow: visible;
|
||||
scrollbar-width: none;
|
||||
|
|
@ -10696,6 +10562,35 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
opacity: 0.55;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-main-view {
|
||||
--fs-media-column-size: minmax(420px, 760px);
|
||||
--fs-lyrics-column-size: minmax(0, 0fr);
|
||||
|
||||
width: min(760px, 100%);
|
||||
gap: 0;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-media-column {
|
||||
justify-self: center;
|
||||
width: min(520px, 100%);
|
||||
transform: translateX(clamp(2rem, 4vw, 3.5rem));
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-lyrics-pane {
|
||||
opacity: 0;
|
||||
transform: translateX(2rem);
|
||||
visibility: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
#fullscreen-cover-overlay .fullscreen-main-view,
|
||||
#fullscreen-cover-overlay .fullscreen-media-column,
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-pane {
|
||||
transition: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.queue-panel-active .fullscreen-main-view {
|
||||
grid-template-columns: 1fr;
|
||||
width: min(760px, 100%);
|
||||
|
|
@ -10712,101 +10607,330 @@ body:has(#side-panel.active) #close-fullscreen-cover-btn {
|
|||
|
||||
@media (max-width: 980px) {
|
||||
#fullscreen-cover-overlay .fullscreen-main-view {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-rows: auto minmax(0, 1fr) auto;
|
||||
width: min(760px, 100%);
|
||||
gap: 1rem;
|
||||
align-items: start;
|
||||
padding: calc(4.5rem + env(safe-area-inset-top)) clamp(1rem, 4vw, 1.5rem)
|
||||
gap: 1.25rem;
|
||||
align-items: stretch;
|
||||
padding: calc(5rem + env(safe-area-inset-top)) clamp(1rem, 4vw, 1.75rem)
|
||||
calc(1.5rem + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-media-column {
|
||||
justify-self: center;
|
||||
transform: none;
|
||||
width: min(100%, 620px);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-pane {
|
||||
display: none;
|
||||
display: flex;
|
||||
width: min(100%, 620px);
|
||||
justify-self: center;
|
||||
min-height: min(48vh, 440px);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-shell {
|
||||
width: 100%;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-content {
|
||||
padding-left: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
#fullscreen-cover-overlay {
|
||||
--fs-mobile-top-btn-size: 44px;
|
||||
--fs-mobile-top-btn-size: 42px;
|
||||
--fs-mobile-top-btn-gap: 0.6rem;
|
||||
--fs-mobile-top-btn-left: calc(1rem + env(safe-area-inset-left));
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-cover-content {
|
||||
padding: 0.75rem 0.75rem calc(0.75rem + env(safe-area-inset-bottom));
|
||||
padding: 0 calc(0.9rem + env(safe-area-inset-right)) calc(0.9rem + env(safe-area-inset-bottom))
|
||||
calc(0.9rem + env(safe-area-inset-left));
|
||||
}
|
||||
|
||||
#fullscreen-dismiss-handle {
|
||||
display: block;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-top-actions {
|
||||
top: calc(0.75rem + env(safe-area-inset-top));
|
||||
left: var(--fs-mobile-top-btn-left);
|
||||
gap: var(--fs-mobile-top-btn-gap);
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-top-actions button,
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-toggle,
|
||||
#fullscreen-cover-overlay #toggle-ui-btn {
|
||||
width: var(--fs-mobile-top-btn-size);
|
||||
height: var(--fs-mobile-top-btn-size);
|
||||
background: rgb(9 12 18 / 0.5);
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay #toggle-ui-btn {
|
||||
top: calc(0.75rem + env(safe-area-inset-top));
|
||||
left: calc(
|
||||
var(--fs-mobile-top-btn-left) + (var(--fs-mobile-top-btn-size) * 2) + (var(--fs-mobile-top-btn-gap) * 2)
|
||||
);
|
||||
#toggle-fullscreen-lyrics-mobile-btn {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-main-view {
|
||||
width: 100%;
|
||||
gap: 0.85rem;
|
||||
padding: calc(7.25rem + env(safe-area-inset-top)) 0.75rem calc(1.5rem + env(safe-area-inset-bottom));
|
||||
height: 100%;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
min-height: 0;
|
||||
box-sizing: border-box;
|
||||
grid-template-columns: minmax(78px, 92px) minmax(0, 1fr);
|
||||
grid-template-rows: auto minmax(0, 1fr) auto;
|
||||
grid-template-areas:
|
||||
'art info'
|
||||
'lyrics lyrics'
|
||||
'controls controls';
|
||||
gap: 1rem 0.9rem;
|
||||
padding: calc(4.45rem + env(safe-area-inset-top)) 0 calc(0.8rem + env(safe-area-inset-bottom));
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-track-info,
|
||||
#fullscreen-cover-overlay .fullscreen-controls,
|
||||
#fullscreen-cover-overlay .fullscreen-media-column {
|
||||
width: min(100%, 460px);
|
||||
display: contents;
|
||||
width: auto;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-artwork-card {
|
||||
grid-area: art;
|
||||
width: 100%;
|
||||
max-width: 92px;
|
||||
box-sizing: border-box;
|
||||
border-radius: 12px;
|
||||
align-self: start;
|
||||
margin-left: 0.95rem;
|
||||
box-shadow: 0 20px 48px rgb(0 0 0 / 0.34);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay #fullscreen-cover-image {
|
||||
border-radius: 12px;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-track-info {
|
||||
grid-area: info;
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
align-self: center;
|
||||
display: grid;
|
||||
gap: 0.3rem;
|
||||
padding-top: 0.2rem;
|
||||
padding-left: 0.95rem;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-track-text {
|
||||
display: grid;
|
||||
gap: 0.14rem;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay #fullscreen-track-title {
|
||||
font-size: clamp(1.1rem, 4.7vw, 1.34rem);
|
||||
line-height: 1.04;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay #fullscreen-track-artist {
|
||||
margin-top: 0;
|
||||
font-size: 0.92rem;
|
||||
color: rgb(255 255 255 / 0.7);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-actions {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay #fullscreen-next-track {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-pane {
|
||||
grid-area: lyrics;
|
||||
width: 100%;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.45rem;
|
||||
max-width: 100%;
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
justify-self: stretch;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-actions .btn-icon {
|
||||
background: rgb(255 255 255 / 0.06);
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-shell {
|
||||
min-height: 0;
|
||||
position: relative;
|
||||
background: transparent !important;
|
||||
box-shadow: none !important;
|
||||
border-radius: 0;
|
||||
overflow: visible;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-progress-container {
|
||||
gap: 0.65rem;
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-content {
|
||||
height: 100%;
|
||||
padding: 0 0 0.2rem;
|
||||
overflow: hidden;
|
||||
mask-image: linear-gradient(180deg, transparent 0%, black 10%, black 88%, transparent 100%);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-buttons {
|
||||
gap: 0.2rem;
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-content am-lyrics {
|
||||
--lyrics-scroll-padding-top: 18%;
|
||||
--lyplus-font-size-base: clamp(1.75rem, 7vw, 2.35rem);
|
||||
--lyplus-padding-line: 6px;
|
||||
--lyplus-text-color: rgb(246, 244, 239, 0.16);
|
||||
--lyplus-blur-amount: 0.16em;
|
||||
--lyplus-blur-amount-near: 0.08em;
|
||||
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-buttons button {
|
||||
width: 38px;
|
||||
height: 38px;
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-empty,
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-content .lyrics-loading,
|
||||
#fullscreen-cover-overlay .fullscreen-lyrics-content .lyrics-error {
|
||||
padding: 2.5rem 1.2rem 0;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-buttons #fs-play-pause-btn {
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
#fullscreen-cover-overlay .fullscreen-controls {
|
||||
grid-area: controls;
|
||||
width: 100%;
|
||||
max-width: none;
|
||||
min-width: 0;
|
||||
box-sizing: border-box;
|
||||
margin-top: 0;
|
||||
padding: 0.15rem 0 0;
|
||||
gap: 0.9rem;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-mobile-quality {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-volume-container {
|
||||
width: min(220px, calc(100% - 2.75rem));
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-progress-container {
|
||||
gap: 0.55rem;
|
||||
font-size: 0.72rem;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-buttons {
|
||||
gap: 0.1rem;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-buttons button {
|
||||
width: 42px;
|
||||
height: 42px;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-buttons #fs-play-pause-btn {
|
||||
width: 62px;
|
||||
height: 62px;
|
||||
box-shadow: 0 14px 28px rgb(0 0 0 / 0.3);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-main-view {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
grid-template-rows: minmax(0, 1fr) auto minmax(0, 1fr) auto;
|
||||
align-items: center;
|
||||
justify-items: center;
|
||||
gap: 0;
|
||||
padding: calc(4.45rem + env(safe-area-inset-top)) clamp(1rem, 4vw, 1.4rem)
|
||||
calc(0.8rem + env(safe-area-inset-bottom));
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
max-width: 100%;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-lyrics-pane {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-media-column {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
grid-row: 2;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
align-self: center;
|
||||
width: min(100%, 320px);
|
||||
max-width: min(88vw, 320px);
|
||||
min-height: 0;
|
||||
min-width: 0;
|
||||
margin: 0 auto;
|
||||
transform: none;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-artwork-card {
|
||||
max-width: min(88vw, 320px);
|
||||
width: min(100%, 320px);
|
||||
margin: 0 auto;
|
||||
align-self: center;
|
||||
justify-self: center;
|
||||
border-radius: 14px;
|
||||
box-shadow: 0 24px 56px rgb(0 0 0 / 0.28);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden #fullscreen-cover-image {
|
||||
border-radius: 14px;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-track-info {
|
||||
align-self: center;
|
||||
width: min(100%, 320px);
|
||||
padding: 0;
|
||||
gap: 0.3rem;
|
||||
margin-top: 0.9rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-track-text {
|
||||
gap: 0.2rem;
|
||||
justify-items: center;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden #fullscreen-track-title {
|
||||
font-size: clamp(1.15rem, 5vw, 1.5rem);
|
||||
line-height: 1.05;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden #fullscreen-track-artist {
|
||||
font-size: 0.95rem;
|
||||
color: rgb(255 255 255 / 0.66);
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-controls {
|
||||
grid-row: 4;
|
||||
width: min(100%, 320px);
|
||||
max-width: min(88vw, 320px);
|
||||
justify-self: center;
|
||||
align-self: end;
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden #fullscreen-track-title .quality-badge,
|
||||
#fullscreen-cover-overlay.lyrics-hidden #fullscreen-track-title .shaka-quality-badge {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-mobile-quality {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 1.25rem;
|
||||
margin: 0 auto -0.1rem;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-mobile-quality .quality-badge,
|
||||
#fullscreen-cover-overlay.lyrics-hidden .fullscreen-mobile-quality .shaka-quality-badge {
|
||||
display: inline-flex !important;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fullscreen-volume-container {
|
||||
width: min(280px, calc(100% - 3rem));
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fs-volume-btn {
|
||||
left: -2.25rem;
|
||||
left: -2.5rem;
|
||||
}
|
||||
|
||||
#fullscreen-cover-overlay .fs-volume-bar {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import path from 'path';
|
|||
import uploadPlugin from './vite-plugin-upload.js';
|
||||
import blobAssetPlugin from './vite-plugin-blob.js';
|
||||
import svgUse from './vite-plugin-svg-use.js';
|
||||
// import purgecss from 'vite-plugin-purgecss';
|
||||
import purgecss from 'vite-plugin-purgecss';
|
||||
import { execSync } from 'child_process';
|
||||
import { playwright } from '@vitest/browser-playwright';
|
||||
|
|
@ -67,13 +68,34 @@ export default defineConfig((_options) => {
|
|||
outDir: 'dist',
|
||||
emptyOutDir: true,
|
||||
sourcemap: true,
|
||||
minify: 'terser',
|
||||
terserOptions: {
|
||||
compress: {
|
||||
drop_console: true,
|
||||
drop_debugger: true,
|
||||
},
|
||||
},
|
||||
rollupOptions: {
|
||||
treeshake: true,
|
||||
},
|
||||
},
|
||||
plugins: [
|
||||
purgecss({
|
||||
variables: true,
|
||||
variables: false, // DO NOT REMOVE UNUSED VARIABLES (breaks web components like am-lyrics)
|
||||
safelist: {
|
||||
standard: [
|
||||
/^am-lyrics/,
|
||||
/^lyplus-/,
|
||||
'sidepanel',
|
||||
'side-panel',
|
||||
'active',
|
||||
'show',
|
||||
/^data-/,
|
||||
/^modal-/,
|
||||
],
|
||||
deep: [/^am-lyrics/],
|
||||
greedy: [/^lyplus-/, /sidepanel/, /side-panel/],
|
||||
},
|
||||
}),
|
||||
authGatePlugin(),
|
||||
uploadPlugin(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue