diff --git a/index.html b/index.html index b843574..66729bf 100644 --- a/index.html +++ b/index.html @@ -2095,9 +2095,9 @@
System
-
Light
-
Dark
Black
+
White
+
Dark
Ocean
Purple
Forest
@@ -2132,7 +2132,8 @@
+ + +
Full-screen Visualizer diff --git a/js/settings.js b/js/settings.js index 53a3270..2d8d8dc 100644 --- a/js/settings.js +++ b/js/settings.js @@ -5,6 +5,7 @@ import { nowPlayingSettings, lyricsSettings, backgroundSettings, + dynamicColorSettings, cardSettings, waveformSettings, replayGainSettings, @@ -779,6 +780,19 @@ export function initializeSettings(scrobbler, player, api, ui) { }); } + // Dynamic Color Toggle + const dynamicColorToggle = document.getElementById('dynamic-color-toggle'); + if (dynamicColorToggle) { + dynamicColorToggle.checked = dynamicColorSettings.isEnabled(); + dynamicColorToggle.addEventListener('change', (e) => { + dynamicColorSettings.setEnabled(e.target.checked); + if (!e.target.checked) { + // Reset colors immediately when disabled + window.dispatchEvent(new CustomEvent('reset-dynamic-color')); + } + }); + } + // Waveform Toggle const waveformToggle = document.getElementById('waveform-toggle'); if (waveformToggle) { diff --git a/js/storage.js b/js/storage.js index f76cbbc..f545a4b 100644 --- a/js/storage.js +++ b/js/storage.js @@ -237,7 +237,7 @@ export const themeManager = { if (theme === 'system') { const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; - document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'light'); + document.documentElement.setAttribute('data-theme', isDark ? 'dark' : 'white'); } else { document.documentElement.setAttribute('data-theme', theme); } @@ -371,6 +371,23 @@ export const backgroundSettings = { }, }; +export const dynamicColorSettings = { + STORAGE_KEY: 'dynamic-color-enabled', + + isEnabled() { + try { + // Default to true if not set + return localStorage.getItem(this.STORAGE_KEY) !== 'false'; + } catch { + return true; + } + }, + + setEnabled(enabled) { + localStorage.setItem(this.STORAGE_KEY, enabled ? 'true' : 'false'); + }, +}; + export const cardSettings = { COMPACT_ARTIST_KEY: 'card-compact-artist', COMPACT_ALBUM_KEY: 'card-compact-album', @@ -1155,7 +1172,7 @@ export const sidebarSectionSettings = { if (typeof window !== 'undefined' && window.matchMedia) { window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', (e) => { if (themeManager.getTheme() === 'system') { - document.documentElement.setAttribute('data-theme', e.matches ? 'dark' : 'light'); + document.documentElement.setAttribute('data-theme', e.matches ? 'dark' : 'white'); } }); } @@ -1168,10 +1185,10 @@ export const fontSettings = { getDefaultConfig() { return { - type: 'preset', - family: 'Inter', - fallback: 'sans-serif', - weights: [400, 500, 600, 700, 800], + type: 'google', + family: 'IBM Plex Mono', + fallback: 'monospace', + weights: [100, 200, 300, 400, 500, 600, 700], }; }, diff --git a/js/ui.js b/js/ui.js index b4a5426..0903a57 100644 --- a/js/ui.js +++ b/js/ui.js @@ -23,9 +23,11 @@ import { openLyricsPanel } from './lyrics.js'; import { recentActivityManager, backgroundSettings, + dynamicColorSettings, cardSettings, visualizerSettings, homePageSettings, + fontSettings, } from './storage.js'; import { db } from './db.js'; import { getVibrantColorFromImage } from './vibrant-color.js'; @@ -42,7 +44,6 @@ import { createProjectCardHTML, createTrackFromSong, } from './tracker.js'; -import { fontSettings } from './storage.js'; fontSettings.applyFont(); @@ -85,6 +86,11 @@ export class UIRenderer { this.searchAbortController = null; this.vibrantColorCache = new Map(); this.visualizer = null; + + // Listen for dynamic color reset events + window.addEventListener('reset-dynamic-color', () => { + this.resetVibrantColor(); + }); } // Helper for Heart Icon @@ -96,7 +102,13 @@ export class UIRenderer { } async extractAndApplyColor(url) { - if (!backgroundSettings.isEnabled() || !url) { + if (!url) { + this.resetVibrantColor(); + return; + } + + // Check if dynamic coloring is enabled + if (!dynamicColorSettings.isEnabled()) { this.resetVibrantColor(); return; } @@ -695,7 +707,7 @@ export class UIRenderer { const root = document.documentElement; const theme = root.getAttribute('data-theme'); - const isLightMode = theme === 'light'; + const isLightMode = theme === 'white'; let hex = color.replace('#', ''); // Handle shorthand hex diff --git a/js/visualizers/lcd.js b/js/visualizers/lcd.js index 6382288..475904c 100644 --- a/js/visualizers/lcd.js +++ b/js/visualizers/lcd.js @@ -190,7 +190,7 @@ export class LCDPreset { const { kick, primaryColor, mode } = params; this.primaryColor = primaryColor; - const isDark = document.documentElement.getAttribute('data-theme') !== 'light'; + const isDark = document.documentElement.getAttribute('data-theme') !== 'white'; // --- Background --- ctx.clearRect(0, 0, width, height); diff --git a/js/visualizers/particles.js b/js/visualizers/particles.js index be2d535..527a817 100644 --- a/js/visualizers/particles.js +++ b/js/visualizers/particles.js @@ -18,7 +18,7 @@ export class ParticlesPreset { const { width, height } = canvas; const { kick, intensity, primaryColor, mode } = params; const sensitivity = params.sensitivity || 1.0; - const isDark = document.documentElement.getAttribute('data-theme') !== 'light'; + const isDark = document.documentElement.getAttribute('data-theme') !== 'white'; // Clear background ctx.clearRect(0, 0, width, height); diff --git a/js/visualizers/unknown_pleasures_webgl.js b/js/visualizers/unknown_pleasures_webgl.js index 491c993..a43e85a 100644 --- a/js/visualizers/unknown_pleasures_webgl.js +++ b/js/visualizers/unknown_pleasures_webgl.js @@ -457,7 +457,7 @@ export class UnknownPleasuresWebGL { draw(ctx, canvas, analyser, dataArray, params) { const gl = ctx; const { width, height } = canvas; - const isDark = document.documentElement.getAttribute('data-theme') !== 'light'; + const isDark = document.documentElement.getAttribute('data-theme') !== 'white'; // Set CSS blend mode based on mode and theme // Solid: normal (opaque background) diff --git a/styles.css b/styles.css index 5d51d83..711283e 100644 --- a/styles.css +++ b/styles.css @@ -43,23 +43,23 @@ :root[data-theme='monochrome'] { color-scheme: dark; - --background: #000; - --foreground: #fafafa; - --card: #111; - --card-foreground: #fafafa; - --primary: #fafafa; - --primary-foreground: #111; - --secondary: #27272a; - --secondary-foreground: #fafafa; - --muted: #27272a; - --muted-foreground: #a1a1aa; - --border: #27272a; - --input: #27272a; - --ring: #fafafa; - --highlight: #fff; - --highlight-rgb: 255, 255, 255; + --background: #0a0a0a; + --foreground: #f5f5f5; + --card: #141414; + --card-foreground: #f5f5f5; + --primary: #f5f5f5; + --primary-foreground: #0a0a0a; + --secondary: #1f1f1f; + --secondary-foreground: #e0e0e0; + --muted: #1f1f1f; + --muted-foreground: #a0a0a0; + --border: #2a2a2a; + --input: #1f1f1f; + --ring: #f5f5f5; + --highlight: #f5f5f5; + --highlight-rgb: 245, 245, 245; --active-highlight: var(--highlight); - --explicit-badge: #fafafa; + --explicit-badge: #f5f5f5; } :root[data-theme='dark'] { @@ -231,33 +231,33 @@ --muted-foreground: #6c6f85; --border: #ccd0da; --input: #bcc0cc; - --ring: #1e66f5; + --ring: #fdfdfd; --highlight: #1e66f5; --highlight-rgb: #7287fd; --active-highlight: #7287fd; --explicit-badge: #df8e1d; } -:root[data-theme='light'] { +:root[data-theme='white'] { color-scheme: light; - --background: #fff; - --foreground: #000; - --card: #f4f4f5; - --card-foreground: #000; - --primary: #2563eb; - --primary-foreground: #fff; - --secondary: #e4e4e7; - --secondary-foreground: #000; - --muted: #e4e4e7; - --muted-foreground: #62626a; - --border: #e4e4e7; - --input: #e4e4e7; - --ring: #2563eb; - --highlight: #2563eb; - --highlight-rgb: 37, 99, 235; + --background: #f5f5f5; + --foreground: #1a1a1a; + --card: #e8e8e8; + --card-foreground: #1a1a1a; + --primary: #1a1a1a; + --primary-foreground: #f5f5f5; + --secondary: #ddd; + --secondary-foreground: #2a2a2a; + --muted: #e0e0e0; + --muted-foreground: #555; + --border: #ccc; + --input: #e0e0e0; + --ring: #1a1a1a; + --highlight: #1a1a1a; + --highlight-rgb: 26, 26, 26; --active-highlight: var(--highlight); - --explicit-badge: #f58a8a; + --explicit-badge: #1a1a1a; --cover-filter: blur(50px) brightness(1.6) opacity(0.35); } @@ -268,7 +268,7 @@ margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; - font-family: var(--font-family, 'Inter', sans-serif) !important; + font-family: var(--font-family, 'IBM Plex Mono', monospace) !important; } html { @@ -281,7 +281,7 @@ html { body { background-color: var(--background); color: var(--foreground); - font-family: var(--font-family, 'Inter', sans-serif) !important; + font-family: var(--font-family, 'IBM Plex Mono', monospace) !important; overflow: hidden; transition: background-color 0.3s ease, @@ -391,7 +391,7 @@ kbd { } /* Light mode adjustments */ -:root[data-theme='light'] #page-background { +:root[data-theme='white'] #page-background { mask-image: linear-gradient(to bottom, rgb(0, 0, 0, 1) 0%, rgb(0, 0, 0, 0) 100%); } @@ -423,7 +423,7 @@ kbd { animation: slide-up var(--transition-slow) var(--ease-out-back); } -:root[data-theme='light'] .now-playing-bar { +:root[data-theme='white'] .now-playing-bar { background-color: color-mix(in srgb, var(--card) 80%, transparent); border-color: rgb(0, 0, 0, 0.1); }