UNPKG

@arraypress/waveform-player

Version:

Lightweight, customizable audio player with waveform visualization

196 lines (173 loc) 5.75 kB
/** * @module themes * @description Color presets and default options for WaveformPlayer */ /** * Detect appropriate color scheme * Priority: 1) Explicit classes, 2) Website background, 3) System preference, 4) Default * @returns {string} 'dark' or 'light' */ export function detectColorScheme() { const root = document.documentElement; const body = document.body; // 1. Check for explicit theme class names and data attributes FIRST // Check for dark theme indicators if (root.classList.contains('dark') || root.classList.contains('dark-mode') || root.classList.contains('theme-dark') || root.getAttribute('data-theme') === 'dark' || root.getAttribute('data-color-scheme') === 'dark' || body.classList.contains('dark') || body.classList.contains('dark-mode') || body.getAttribute('data-theme') === 'dark') { return 'dark'; } // Check for light theme indicators if (root.classList.contains('light') || root.classList.contains('light-mode') || root.classList.contains('theme-light') || root.getAttribute('data-theme') === 'light' || root.getAttribute('data-color-scheme') === 'light' || body.classList.contains('light') || body.classList.contains('light-mode') || body.getAttribute('data-theme') === 'light') { return 'light'; } // 2. Try to detect website's theme from background color try { const bodyBg = getComputedStyle(document.body).backgroundColor; // Parse RGB values const rgb = bodyBg.match(/\d+/g); if (rgb && rgb.length >= 3) { const [r, g, b] = rgb.map(Number); // Calculate perceived brightness using luminance formula (0-255) const brightness = (r * 299 + g * 587 + b * 114) / 1000; // Clear determination: bright background = light theme if (brightness > 128) { return 'light'; } else if (brightness < 128) { return 'dark'; } } } catch (e) { // If background detection fails, continue to next method } // 3. Check system preference if (window.matchMedia) { if (window.matchMedia('(prefers-color-scheme: dark)').matches) { return 'dark'; } if (window.matchMedia('(prefers-color-scheme: light)').matches) { return 'light'; } } // 4. Default fallback (most audio players are dark) return 'dark'; } /** * Color presets - simple dark/light defaults that can be overridden */ export const COLOR_PRESETS = { dark: { waveformColor: 'rgba(255, 255, 255, 0.3)', progressColor: 'rgba(255, 255, 255, 0.9)', buttonColor: 'rgba(255, 255, 255, 0.9)', buttonHoverColor: 'rgba(255, 255, 255, 1)', textColor: '#ffffff', textSecondaryColor: 'rgba(255, 255, 255, 0.6)', backgroundColor: 'rgba(255, 255, 255, 0.03)', borderColor: 'rgba(255, 255, 255, 0.1)' }, light: { waveformColor: 'rgba(0, 0, 0, 0.2)', progressColor: 'rgba(0, 0, 0, 0.8)', buttonColor: 'rgba(0, 0, 0, 0.8)', buttonHoverColor: 'rgba(0, 0, 0, 0.9)', textColor: '#333333', textSecondaryColor: 'rgba(0, 0, 0, 0.6)', backgroundColor: 'rgba(0, 0, 0, 0.02)', borderColor: 'rgba(0, 0, 0, 0.1)' } }; /** * Get color preset by name, with auto-detection fallback * @param {string|null} presetName - Preset name ('dark', 'light') or null for auto-detect * @returns {Object} Color preset object */ export function getColorPreset(presetName) { // If explicitly set to a valid preset, use it if (presetName && COLOR_PRESETS[presetName]) { return COLOR_PRESETS[presetName]; } // Auto-detect if not specified or invalid const detected = detectColorScheme(); return COLOR_PRESETS[detected]; } /** * Default player options */ export const DEFAULT_OPTIONS = { // Core settings url: '', height: 60, samples: 200, preload: 'metadata', // Playback playbackRate: 1, showPlaybackSpeed: false, playbackRates: [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2], // Layout Options buttonAlign: 'auto', // Default waveform style waveformStyle: 'mirror', barWidth: 2, barSpacing: 0, // Color preset: null = auto-detect, 'dark' = force dark, 'light' = force light colorPreset: null, // Individual color overrides (null means use preset) waveformColor: null, progressColor: null, buttonColor: null, buttonHoverColor: null, textColor: null, textSecondaryColor: null, backgroundColor: null, borderColor: null, // Features autoplay: false, showTime: true, showHoverTime: false, showBPM: false, singlePlay: true, playOnSeek: true, enableMediaSession: true, // Markers markers: [], showMarkers: true, // Content title: null, subtitle: null, artwork: null, album: '', // Icons (SVG) playIcon: '<svg viewBox="0 0 24 24" width="16" height="16"><path d="M8 5v14l11-7z"/></svg>', pauseIcon: '<svg viewBox="0 0 24 24" width="16" height="16"><path d="M6 4h4v16H6zM14 4h4v16h-4z"/></svg>', // Callbacks onLoad: null, onPlay: null, onPause: null, onEnd: null, onError: null, onTimeUpdate: null }; /** * Style defaults */ export const STYLE_DEFAULTS = { bars: {barWidth: 3, barSpacing: 1}, mirror: {barWidth: 2, barSpacing: 0}, line: {barWidth: 2, barSpacing: 0}, blocks: {barWidth: 4, barSpacing: 2}, dots: {barWidth: 3, barSpacing: 3}, seekbar: {barWidth: 1, barSpacing: 0} };