From 003ddc0ab3629353dd47e9c416d9f035efb65d71 Mon Sep 17 00:00:00 2001 From: Eduard Prigoana Date: Mon, 9 Feb 2026 00:01:40 +0000 Subject: [PATCH] add more fonts functionality --- index.html | 117 +++++++++++++++------ js/settings.js | 149 +++++++++++++++++++++++++++ js/storage.js | 252 ++++++++++++++++++++++++++++++++++++++++++++++ js/ui.js | 44 +++++--- package-lock.json | 15 --- styles.css | 147 +++++++++++++++++++++++++-- 6 files changed, 657 insertions(+), 67 deletions(-) diff --git a/index.html b/index.html index 43005d4..b843574 100644 --- a/index.html +++ b/index.html @@ -1096,6 +1096,20 @@

+ + @@ -2101,25 +2115,70 @@ -
+
Font - Choose the application font -
- +
+
+ + +
+ +
+ + + + + + +
diff --git a/js/settings.js b/js/settings.js index 8f37ad2..53a3270 100644 --- a/js/settings.js +++ b/js/settings.js @@ -22,6 +22,7 @@ import { libreFmSettings, homePageSettings, sidebarSectionSettings, + fontSettings, } from './storage.js'; import { audioContextManager, EQ_PRESETS } from './audio-context.js'; import { db } from './db.js'; @@ -1280,10 +1281,158 @@ export function initializeSettings(scrobbler, player, api, ui) { }); } + // Font Settings + initializeFontSettings(); + // Settings Search functionality setupSettingsSearch(); } +function initializeFontSettings() { + const fontTypeSelect = document.getElementById('font-type-select'); + const fontPresetSection = document.getElementById('font-preset-section'); + const fontGoogleSection = document.getElementById('font-google-section'); + const fontUrlSection = document.getElementById('font-url-section'); + const fontUploadSection = document.getElementById('font-upload-section'); + const fontPresetSelect = document.getElementById('font-preset-select'); + const fontGoogleInput = document.getElementById('font-google-input'); + const fontGoogleApply = document.getElementById('font-google-apply'); + const fontUrlInput = document.getElementById('font-url-input'); + const fontUrlName = document.getElementById('font-url-name'); + const fontUrlApply = document.getElementById('font-url-apply'); + const fontUploadInput = document.getElementById('font-upload-input'); + const uploadedFontsList = document.getElementById('uploaded-fonts-list'); + + if (!fontTypeSelect) return; + + // Load current font config + const config = fontSettings.getConfig(); + + // Show correct section based on type + function showFontSection(type) { + fontPresetSection.style.display = type === 'preset' ? 'block' : 'none'; + fontGoogleSection.style.display = type === 'google' ? 'flex' : 'none'; + fontUrlSection.style.display = type === 'url' ? 'flex' : 'none'; + fontUploadSection.style.display = type === 'upload' ? 'block' : 'none'; + } + + // Initialize UI state + fontTypeSelect.value = config.type; + showFontSection(config.type); + + if (config.type === 'preset') { + fontPresetSelect.value = config.family; + } else if (config.type === 'google') { + fontGoogleInput.value = config.family || ''; + } else if (config.type === 'url') { + fontUrlInput.value = config.url || ''; + fontUrlName.value = config.family || ''; + } + + // Type selector change + fontTypeSelect.addEventListener('change', (e) => { + showFontSection(e.target.value); + }); + + // Preset font change + fontPresetSelect.addEventListener('change', (e) => { + const value = e.target.value; + if (value === 'System UI') { + fontSettings.loadPresetFont( + "system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue'", + 'sans-serif' + ); + } else if (value === 'monospace') { + fontSettings.loadPresetFont('monospace', 'monospace'); + } else { + fontSettings.loadPresetFont(value, 'sans-serif'); + } + }); + + // Google Fonts apply + fontGoogleApply.addEventListener('click', () => { + const input = fontGoogleInput.value.trim(); + if (!input) return; + + let fontName = input; + + // Check if it's a Google Fonts URL + if (input.includes('fonts.google.com')) { + const parsed = fontSettings.parseGoogleFontsUrl(input); + if (parsed) { + fontName = parsed; + } + } + + fontSettings.loadGoogleFont(fontName); + }); + + // URL font apply + fontUrlApply.addEventListener('click', () => { + const url = fontUrlInput.value.trim(); + const name = fontUrlName.value.trim(); + if (!url) return; + + fontSettings.loadFontFromUrl(url, name || 'CustomFont'); + }); + + // File upload + fontUploadInput.addEventListener('change', async (e) => { + const file = e.target.files[0]; + if (!file) return; + + try { + const font = await fontSettings.saveUploadedFont(file); + await fontSettings.loadUploadedFont(font.id); + renderUploadedFontsList(); + fontUploadInput.value = ''; + } catch (err) { + console.error('Failed to upload font:', err); + alert('Failed to upload font'); + } + }); + + // Render uploaded fonts list + function renderUploadedFontsList() { + const fonts = fontSettings.getUploadedFontList(); + uploadedFontsList.innerHTML = ''; + + fonts.forEach((font) => { + const item = document.createElement('div'); + item.className = 'uploaded-font-item'; + item.innerHTML = ` + ${font.name} +
+ + +
+ `; + uploadedFontsList.appendChild(item); + }); + + // Add event listeners for buttons + uploadedFontsList.querySelectorAll('.btn-icon').forEach((btn) => { + btn.addEventListener('click', async (e) => { + const fontId = e.target.dataset.id; + const action = e.target.dataset.action; + + if (action === 'use') { + await fontSettings.loadUploadedFont(fontId); + fontTypeSelect.value = 'upload'; + showFontSection('upload'); + } else if (action === 'delete') { + if (confirm('Delete this font?')) { + fontSettings.deleteUploadedFont(fontId); + renderUploadedFontsList(); + } + } + }); + }); + } + + renderUploadedFontsList(); +} + function setupSettingsSearch() { const searchInput = document.getElementById('settings-search-input'); if (!searchInput) return; diff --git a/js/storage.js b/js/storage.js index 6c85fd8..f76cbbc 100644 --- a/js/storage.js +++ b/js/storage.js @@ -1159,3 +1159,255 @@ if (typeof window !== 'undefined' && window.matchMedia) { } }); } + +export const fontSettings = { + STORAGE_KEY: 'monochrome-font-config-v2', + CUSTOM_FONTS_KEY: 'monochrome-custom-fonts', + FONT_LINK_ID: 'monochrome-dynamic-font', + FONT_FACE_ID: 'monochrome-dynamic-fontface', + + getDefaultConfig() { + return { + type: 'preset', + family: 'Inter', + fallback: 'sans-serif', + weights: [400, 500, 600, 700, 800], + }; + }, + + getConfig() { + try { + const stored = localStorage.getItem(this.STORAGE_KEY); + if (stored) { + return JSON.parse(stored); + } + } catch { + // ignore + } + return this.getDefaultConfig(); + }, + + setConfig(config) { + localStorage.setItem(this.STORAGE_KEY, JSON.stringify(config)); + }, + + parseGoogleFontsUrl(url) { + try { + if (url.includes('fonts.google.com/specimen/')) { + const match = url.match(/specimen\/([^/?]+)/); + if (match) { + return decodeURIComponent(match[1]).replace(/\+/g, ' '); + } + } + if (url.includes('fonts.googleapis.com/css')) { + const match = url.match(/family=([^&:]+)/); + if (match) { + return decodeURIComponent(match[1]).replace(/\+/g, ' ').split(':')[0]; + } + } + } catch { + // ignore + } + return null; + }, + + async loadGoogleFont(familyName) { + const encodedFamily = familyName.replace(/\s+/g, '+'); + const url = `https://fonts.googleapis.com/css2?family=${encodedFamily}:wght@100;200;300;400;500;600;700;800;900&display=swap`; + + let link = document.getElementById(this.FONT_LINK_ID); + if (!link) { + link = document.createElement('link'); + link.id = this.FONT_LINK_ID; + link.rel = 'stylesheet'; + document.head.appendChild(link); + } + + link.href = url; + + this.setConfig({ + type: 'google', + family: familyName, + fallback: 'sans-serif', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + }); + + document.documentElement.style.setProperty('--font-family', `'${familyName}', sans-serif`); + }, + + async loadFontFromUrl(url, familyName) { + const weights = [100, 200, 300, 400, 500, 600, 700, 800, 900]; + const fontFaceId = this.FONT_FACE_ID; + + let style = document.getElementById(fontFaceId); + if (!style) { + style = document.createElement('style'); + style.id = fontFaceId; + document.head.appendChild(style); + } + + const format = this.getFontFormat(url); + const fontFamily = familyName || 'CustomFont'; + + style.textContent = ` + @font-face { + font-family: '${fontFamily}'; + src: url('${url}') format('${format}'); + font-weight: 100 900; + font-style: normal; + font-display: swap; + } + `; + + this.setConfig({ + type: 'url', + family: fontFamily, + url: url, + fallback: 'sans-serif', + weights: weights, + }); + + document.documentElement.style.setProperty('--font-family', `'${fontFamily}', sans-serif`); + }, + + getFontFormat(url) { + const ext = url.split('.').pop().toLowerCase(); + const formats = { + woff2: 'woff2', + woff: 'woff', + ttf: 'truetype', + otf: 'opentype', + }; + return formats[ext] || 'woff2'; + }, + + async saveUploadedFont(file) { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = (e) => { + const base64 = e.target.result; + const fontId = 'uploaded-' + Date.now(); + const customFonts = this.getCustomFonts(); + + customFonts[fontId] = { + name: file.name.replace(/\.[^/.]+$/, ''), + base64: base64, + format: this.getFontFormat(file.name), + size: file.size, + uploadedAt: Date.now(), + }; + + localStorage.setItem(this.CUSTOM_FONTS_KEY, JSON.stringify(customFonts)); + resolve({ id: fontId, ...customFonts[fontId] }); + }; + reader.onerror = reject; + reader.readAsDataURL(file); + }); + }, + + getCustomFonts() { + try { + const stored = localStorage.getItem(this.CUSTOM_FONTS_KEY); + return stored ? JSON.parse(stored) : {}; + } catch { + return {}; + } + }, + + async loadUploadedFont(fontId) { + const customFonts = this.getCustomFonts(); + const font = customFonts[fontId]; + + if (!font) { + throw new Error('Font not found'); + } + + const fontFamily = font.name || 'UploadedFont'; + const fontFaceId = this.FONT_FACE_ID; + + let style = document.getElementById(fontFaceId); + if (!style) { + style = document.createElement('style'); + style.id = fontFaceId; + document.head.appendChild(style); + } + + style.textContent = ` + @font-face { + font-family: '${fontFamily}'; + src: url('${font.base64}') format('${font.format}'); + font-weight: 100 900; + font-style: normal; + font-display: swap; + } + `; + + this.setConfig({ + type: 'uploaded', + family: fontFamily, + fontId: fontId, + fallback: 'sans-serif', + weights: [100, 200, 300, 400, 500, 600, 700, 800, 900], + }); + + document.documentElement.style.setProperty('--font-family', `'${fontFamily}', sans-serif`); + }, + + deleteUploadedFont(fontId) { + const customFonts = this.getCustomFonts(); + delete customFonts[fontId]; + localStorage.setItem(this.CUSTOM_FONTS_KEY, JSON.stringify(customFonts)); + }, + + loadPresetFont(family, fallback = 'sans-serif') { + let link = document.getElementById(this.FONT_LINK_ID); + if (link) { + link.remove(); + } + + let style = document.getElementById(this.FONT_FACE_ID); + if (style) { + style.remove(); + } + + this.setConfig({ + type: 'preset', + family: family, + fallback: fallback, + weights: [400, 500, 600, 700, 800], + }); + + const fontValue = family === 'monospace' ? 'monospace' : `'${family}', ${fallback}`; + document.documentElement.style.setProperty('--font-family', fontValue); + }, + + applyFont() { + const config = this.getConfig(); + + switch (config.type) { + case 'google': + this.loadGoogleFont(config.family); + break; + case 'url': + this.loadFontFromUrl(config.url, config.family); + break; + case 'uploaded': + this.loadUploadedFont(config.fontId); + break; + case 'preset': + default: + this.loadPresetFont(config.family, config.fallback); + break; + } + }, + + getUploadedFontList() { + const fonts = this.getCustomFonts(); + return Object.entries(fonts).map(([id, font]) => ({ + id, + name: font.name, + size: font.size, + uploadedAt: font.uploadedAt, + })); + }, +}; diff --git a/js/ui.js b/js/ui.js index ef5722b..b4a5426 100644 --- a/js/ui.js +++ b/js/ui.js @@ -42,8 +42,9 @@ import { createProjectCardHTML, createTrackFromSong, } from './tracker.js'; -const savedFont = localStorage.getItem('monochrome-font'); -if (savedFont) document.documentElement.style.setProperty('--font-family', savedFont); +import { fontSettings } from './storage.js'; + +fontSettings.applyFont(); function sortTracks(tracks, sortType) { if (sortType === 'custom') return [...tracks]; @@ -1382,12 +1383,34 @@ export class UIRenderer { const welcomeEl = document.getElementById('home-welcome'); const contentEl = document.getElementById('home-content'); + const editorsPicksSectionEmpty = document.getElementById('home-editors-picks-section-empty'); + const editorsPicksSection = document.getElementById('home-editors-picks-section'); const history = await db.getHistory(); const favorites = await db.getFavorites('track'); const playlists = await db.getPlaylists(true); - if (history.length === 0 && favorites.length === 0 && playlists.length === 0) { + const hasActivity = history.length > 0 || favorites.length > 0 || playlists.length > 0; + + // Handle Editor's Picks visibility based on settings + if (!homePageSettings.shouldShowEditorsPicks()) { + if (editorsPicksSectionEmpty) editorsPicksSectionEmpty.style.display = 'none'; + if (editorsPicksSection) editorsPicksSection.style.display = 'none'; + } else { + // Show empty-state section at top when no activity, hide the bottom one + if (editorsPicksSectionEmpty) editorsPicksSectionEmpty.style.display = hasActivity ? 'none' : ''; + // Show bottom section when has activity, render it + if (editorsPicksSection) editorsPicksSection.style.display = hasActivity ? '' : 'none'; + } + + // Render editor's picks in the visible container + if (hasActivity) { + this.renderHomeEditorsPicks(false, 'home-editors-picks'); + } else { + this.renderHomeEditorsPicks(false, 'home-editors-picks-empty'); + } + + if (!hasActivity) { if (welcomeEl) welcomeEl.style.display = 'block'; if (contentEl) contentEl.style.display = 'none'; return; @@ -1414,7 +1437,6 @@ export class UIRenderer { this.renderHomeSongs(); this.renderHomeAlbums(); - this.renderHomeEditorsPicks(); this.renderHomeArtists(); this.renderHomeRecent(); } @@ -1540,16 +1562,8 @@ export class UIRenderer { }); } - async renderHomeEditorsPicks(forceRefresh = false) { - const picksContainer = document.getElementById('home-editors-picks'); - const section = document.getElementById('home-editors-picks-section'); - - if (!homePageSettings.shouldShowEditorsPicks()) { - if (section) section.style.display = 'none'; - return; - } - - if (section) section.style.display = ''; + async renderHomeEditorsPicks(forceRefresh = false, containerId = 'home-editors-picks') { + const picksContainer = document.getElementById(containerId); if (picksContainer) { if (forceRefresh) picksContainer.innerHTML = this.createSkeletonCards(6); @@ -1598,7 +1612,7 @@ export class UIRenderer { if (cardsHTML.length > 0) { picksContainer.innerHTML = cardsHTML.join(''); - itemsToStore.forEach((item, index) => { + itemsToStore.forEach((item, _index) => { const type = item.type; const id = item.data.id; const el = picksContainer.querySelector(`[data-${type}-id="${id}"]`); diff --git a/package-lock.json b/package-lock.json index da7d589..2c81c15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,7 +74,6 @@ "integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/code-frame": "^7.27.1", "@babel/generator": "^7.28.5", @@ -1604,7 +1603,6 @@ "integrity": "sha512-FA5LmZVF1VziNc0bIdCSA1IoSVnDCqE8HJIZZv2/W8YmoAM50+tnUgJR/gQZwEeIMleuIOnRnHA/UaZRNeV4iQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@keyv/serialize": "^1.1.1" } @@ -1646,7 +1644,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" }, @@ -1690,7 +1687,6 @@ } ], "license": "MIT", - "peer": true, "engines": { "node": ">=18" } @@ -3142,7 +3138,6 @@ "resolved": "https://registry.npmjs.org/@svta/cml-xml/-/cml-xml-1.0.1.tgz", "integrity": "sha512-11LkJa5kDEcsRMWkVI1ABH3KLCxGoiSVe4kQ293ItVj8ncTTQ7htmCGiJDjS+Cmy35UgF3e/vc0ysJIiWRTx2g==", "license": "Apache-2.0", - "peer": true, "engines": { "node": ">=20" }, @@ -3191,7 +3186,6 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", - "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -3215,7 +3209,6 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -3503,7 +3496,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", @@ -4288,7 +4280,6 @@ "integrity": "sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", @@ -6645,7 +6636,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", @@ -6729,7 +6719,6 @@ "integrity": "sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -7679,7 +7668,6 @@ } ], "license": "MIT", - "peer": true, "dependencies": { "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-syntax-patches-for-csstree": "^1.0.19", @@ -8094,7 +8082,6 @@ "integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==", "dev": true, "license": "BSD-2-Clause", - "peer": true, "dependencies": { "@jridgewell/source-map": "^0.3.3", "acorn": "^8.15.0", @@ -8419,7 +8406,6 @@ "integrity": "sha512-dZwN5L1VlUBewiP6H9s2+B3e3Jg96D0vzN+Ry73sOefebhYr9f94wwkMNN/9ouoU8pV1BqA1d1zGk8928cx0rg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "esbuild": "^0.27.0", "fdir": "^6.5.0", @@ -8807,7 +8793,6 @@ "integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==", "dev": true, "license": "MIT", - "peer": true, "bin": { "rollup": "dist/bin/rollup" }, diff --git a/styles.css b/styles.css index 72a988c..5d51d83 100644 --- a/styles.css +++ b/styles.css @@ -268,6 +268,7 @@ margin: 0; padding: 0; -webkit-tap-highlight-color: transparent; + font-family: var(--font-family, 'Inter', sans-serif) !important; } html { @@ -280,7 +281,7 @@ html { body { background-color: var(--background); color: var(--foreground); - font-family: var(--font-family, 'Inter', sans-serif); + font-family: var(--font-family, 'Inter', sans-serif) !important; overflow: hidden; transition: background-color 0.3s ease, @@ -318,7 +319,7 @@ kbd { border-radius: 4px; padding: 0.25rem 0.5rem; font-size: 0.85rem; - font-family: 'Courier New', monospace; + font-family: inherit; box-shadow: 0 2px 4px rgb(0, 0, 0, 0.1); } @@ -1774,7 +1775,6 @@ input[type='search']::-webkit-search-cancel-button { border-radius: var(--radius); color: var(--foreground); font-size: 0.9rem; - font-family: 'Courier New', monospace; } .template-input:focus { @@ -1782,6 +1782,142 @@ input[type='search']::-webkit-search-cancel-button { border-color: var(--ring); } +.font-settings-container { + flex-direction: column; + align-items: flex-start; + gap: 1rem; +} + +.font-settings-container .info { + width: 100%; +} + +.font-input-group { + display: flex; + flex-direction: column; + gap: 0.75rem; + width: 100%; + max-width: 500px; +} + +.font-type-select { + width: 100%; + padding: 0.5rem; + background-color: var(--input); + color: var(--foreground); + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.9rem; +} + +.font-section { + display: flex; + flex-direction: column; + gap: 0.5rem; +} + +.font-section select { + width: 100%; + padding: 0.5rem; + background-color: var(--input); + color: var(--foreground); + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.9rem; +} + +.font-input { + width: 100%; + padding: 0.5rem; + background-color: var(--input); + color: var(--foreground); + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.9rem; +} + +.font-name-input { + margin-top: 0.25rem; +} + +.font-file-input { + padding: 0.5rem; + background-color: var(--input); + color: var(--foreground); + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.9rem; + cursor: pointer; +} + +.font-file-input::file-selector-button { + background-color: var(--secondary); + color: var(--secondary-foreground); + border: none; + border-radius: var(--radius-sm); + padding: 0.4rem 0.8rem; + margin-right: 0.75rem; + cursor: pointer; + font-size: 0.85rem; + transition: background-color var(--transition-fast); +} + +.font-file-input::file-selector-button:hover { + background-color: var(--secondary-hover); +} + +.uploaded-fonts-list { + display: flex; + flex-direction: column; + gap: 0.5rem; + margin-top: 0.5rem; +} + +.uploaded-font-item { + display: flex; + align-items: center; + justify-content: space-between; + padding: 0.5rem 0.75rem; + background-color: var(--card); + border: 1px solid var(--border); + border-radius: var(--radius); + font-size: 0.9rem; +} + +.uploaded-font-item .font-name { + flex: 1; + color: var(--foreground); +} + +.uploaded-font-item .font-actions { + display: flex; + gap: 0.5rem; +} + +.uploaded-font-item .btn-icon { + padding: 0.25rem 0.5rem; + background-color: var(--secondary); + color: var(--secondary-foreground); + border: none; + border-radius: var(--radius-sm); + font-size: 0.75rem; + cursor: pointer; + transition: background-color var(--transition-fast); +} + +.uploaded-font-item .btn-icon:hover { + background-color: var(--secondary-hover); +} + +.uploaded-font-item .btn-delete { + background-color: var(--destructive); + color: var(--destructive-foreground); +} + +.uploaded-font-item .btn-delete:hover { + background-color: var(--destructive-hover); +} + .toggle-switch { position: relative; display: inline-block; @@ -3041,7 +3177,6 @@ input:checked + .slider::before { .about-tech p { color: var(--muted-foreground); - font-family: 'Courier New', monospace; font-size: 0.9rem; } @@ -3205,7 +3340,6 @@ input:checked + .slider::before { background-color: var(--secondary); padding: 0.2rem 0.4rem; border-radius: 4px; - font-family: 'Courier New', monospace; font-size: 0.85em; } @@ -3376,7 +3510,6 @@ input:checked + .slider::before { } .lyrics-timing-display { - font-family: monospace; font-size: 0.875rem; font-weight: 600; color: var(--foreground); @@ -4002,7 +4135,6 @@ img[src=''] { padding: 0.75rem 1.25rem; border-bottom: 1px solid var(--border); color: var(--foreground); - font-family: Inter, sans-serif; font-size: 0.95rem; font-weight: 400; line-height: 1.4; @@ -4926,7 +5058,6 @@ body:has(#fullscreen-cover-overlay:not([style*='display: none'])) .now-playing-b font-size: 0.8rem; color: var(--muted-foreground); margin-bottom: 0.5rem; - font-family: monospace; } .annotation-text {