diff --git a/.gitignore b/.gitignore index 3c5cf2c..825f0c2 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,8 @@ /ressources/ffprobe.exe /ressources/deno.exe +/theme/** + config/config.dev.json logs/*.json diff --git a/app/ipcHandlers.js b/app/ipcHandlers.js index 556f1c3..6efa381 100644 --- a/app/ipcHandlers.js +++ b/app/ipcHandlers.js @@ -1,7 +1,9 @@ const { ipcMain, dialog, shell } = require("electron"); const fs = require("fs"); +const path = require("path"); const { logger, logDir } = require("../server/logger"); -const { configFeatures, featuresPath } = require("../config"); +const { configFeatures, featuresPath } = require("../config"); +const { getThemes } = require("./themeManager"); const config = require("../config"); const { validateDownloadPath, getDefaultDownloadPath } = require("./pathValidator"); @@ -15,6 +17,7 @@ const FEATURE_WHITELIST = new Set([ "verboseLogs", "autoDownloadPlaylist", "customCodec", + "theme" ]); const configFolderPath = featuresPath; @@ -72,6 +75,8 @@ function registerIpcHandlers(getMainWindow) { ); ipcMain.on("open-config", () => shell.openPath(configFolderPath)); + ipcMain.handle("get-themes", () => getThemes()); + // Modification des features ipcMain.handle("set-feature", (event, { key, value }) => { try { diff --git a/app/themeManager.js b/app/themeManager.js new file mode 100644 index 0000000..4d2b4c6 --- /dev/null +++ b/app/themeManager.js @@ -0,0 +1,190 @@ +const fs = require("fs"); +const path = require("path"); +const { logger } = require("../server/logger"); +const JSZip = require("jszip"); + +const MAX_IMAGE_SIZE = 10 * 1024 * 1024; +const ALLOWED_IMAGE_EXTENSIONS = [".jpg", ".jpeg", ".png", ".webp", ".gif", ".avif"]; +const ALLOWED_IMAGE_NAMES = ["cover", "background"]; + +const REQUIRED_KEYS = [ + ["meta", "name"], + ["meta", "author"], + ["meta", "version"], + ["meta", "formatVersion"], + ["style", "colors", "background"], + ["style", "colors", "text", "default"], + ["style", "form", "button", "background"], + ["style", "progressBar", "fill"], +]; + +function getNestedValue(obj, keys) { + return keys.reduce((acc, key) => acc?.[key], obj); +} + +function validateThemeJson(json) { + for (const keyPath of REQUIRED_KEYS) { + if (getNestedValue(json, keyPath) === undefined) { + return { valid: false, reason: `Missing key: ${keyPath.join(".")}` }; + } + } + return { valid: true }; +} + +let cachedThemes = null; +let themeFolderPath = null; + +function setThemeFolderPath(folderPath) { + themeFolderPath = folderPath; +} + +async function loadThemesFromFolder() { + const themes = []; + + if (!fs.existsSync(themeFolderPath)) { + logger.warn(`Theme folder not found: ${themeFolderPath}`); + return themes; + } + + const files = fs.readdirSync(themeFolderPath); + + for (const file of files) { + const filePath = path.join(themeFolderPath, file); + const themeId = path.basename(file, path.extname(file)); + + // ZIP + if (file.endsWith(".zip")) { + const theme = await loadThemeFromZip(filePath, themeId); + if (theme) themes.push(theme); + continue; + } + + // Dossier décompressé + if (fs.statSync(filePath).isDirectory()) { + const theme = await loadThemeFromFolder(filePath, themeId); + if (theme) themes.push(theme); + continue; + } + } + + return themes; +} + +async function loadThemeFromZip(zipPath, themeId) { + try { + const zipBuffer = fs.readFileSync(zipPath); + const zip = await JSZip.loadAsync(zipBuffer); + + const jsonFile = Object.keys(zip.files).find(f => f.endsWith(".theme.json")); + if (!jsonFile) { + logger.warn(`Theme ${themeId}: no .theme.json found, skipping`); + return null; + } + + const jsonContent = await zip.files[jsonFile].async("string"); + let themeJson; + try { themeJson = JSON.parse(jsonContent); } + catch { logger.warn(`Theme ${themeId}: invalid JSON, skipping`); return null; } + + const validation = validateThemeJson(themeJson); + if (!validation.valid) { + logger.warn(`Theme ${themeId}: ${validation.reason}, skipping`); + return null; + } + + let imageData = null; + const imageFile = Object.keys(zip.files).find(f => { + const ext = path.extname(f).toLowerCase(); + const name = path.basename(f, ext).toLowerCase(); + return ALLOWED_IMAGE_NAMES.includes(name) && ALLOWED_IMAGE_EXTENSIONS.includes(ext); + }); + + if (imageFile) { + const imageBuffer = await zip.files[imageFile].async("nodebuffer"); + if (imageBuffer.length > MAX_IMAGE_SIZE) { + logger.warn(`Theme ${themeId}: image too large, ignoring image`); + } else { + const ext = path.extname(imageFile).toLowerCase().replace(".", ""); + const mime = ext === "jpg" || ext === "jpeg" ? "jpeg" : ext; + imageData = `data:image/${mime};base64,${imageBuffer.toString("base64")}`; + } + } + + logger.info(`Theme loaded (zip): ${themeId}`); + return buildThemeObject(themeId, themeJson, imageData); + + } catch (err) { + logger.warn(`Theme ${themeId}: failed to load zip — ${err.message}`); + return null; + } +} + +async function loadThemeFromFolder(folderPath, themeId) { + try { + const jsonFile = fs.readdirSync(folderPath).find(f => f.endsWith(".theme.json")); + if (!jsonFile) { + logger.warn(`Theme ${themeId}: no .theme.json found, skipping`); + return null; + } + + const jsonContent = fs.readFileSync(path.join(folderPath, jsonFile), "utf-8"); + let themeJson; + try { themeJson = JSON.parse(jsonContent); } + catch { logger.warn(`Theme ${themeId}: invalid JSON, skipping`); return null; } + + const validation = validateThemeJson(themeJson); + if (!validation.valid) { + logger.warn(`Theme ${themeId}: ${validation.reason}, skipping`); + return null; + } + + let imageData = null; + const imageFile = fs.readdirSync(folderPath).find(f => { + const ext = path.extname(f).toLowerCase(); + const name = path.basename(f, ext).toLowerCase(); + return ALLOWED_IMAGE_NAMES.includes(name) && ALLOWED_IMAGE_EXTENSIONS.includes(ext); + }); + + if (imageFile) { + const imageBuffer = fs.readFileSync(path.join(folderPath, imageFile)); + if (imageBuffer.length > MAX_IMAGE_SIZE) { + logger.warn(`Theme ${themeId}: image too large, ignoring image`); + } else { + const ext = path.extname(imageFile).toLowerCase().replace(".", ""); + const mime = ext === "jpg" || ext === "jpeg" ? "jpeg" : ext; + imageData = `data:image/${mime};base64,${imageBuffer.toString("base64")}`; + } + } + + logger.info(`Theme loaded (folder): ${themeId}`); + return buildThemeObject(themeId, themeJson, imageData); + + } catch (err) { + logger.warn(`Theme ${themeId}: failed to load folder — ${err.message}`); + return null; + } +} + +function buildThemeObject(themeId, themeJson, imageData) { + return { + id: themeId, + name: themeJson.meta.name || themeId, + author: themeJson.meta.author || "Unknown", + version: themeJson.meta.version, + subtitle: themeJson.meta.subtitle || "", + style: themeJson.style, + image: imageData, + }; +} + +async function initThemes(folderPath) { + setThemeFolderPath(folderPath); + cachedThemes = await loadThemesFromFolder(); + logger.info(`${cachedThemes.length} theme(s) loaded`); +} + +function getThemes() { + return cachedThemes ?? []; +} + +module.exports = { initThemes, getThemes }; \ No newline at end of file diff --git a/config/config.default.json b/config/config.default.json index d73ef86..328a2b4 100644 --- a/config/config.default.json +++ b/config/config.default.json @@ -11,5 +11,6 @@ "logSystem": true, "outputTitleCheck": true, "downloadSystem": true, - "notifySystem": true + "notifySystem": true, + "theme": "dark" } \ No newline at end of file diff --git a/main.js b/main.js index 6041f89..9be3e35 100644 --- a/main.js +++ b/main.js @@ -9,6 +9,7 @@ process.on("unhandledRejection", (reason) => { }); const { app } = require("electron"); +const path = require("path"); const { logger, logSessionStart, logSessionEnd } = require("./server/logger"); const { AutoUpdater } = require("./app/autoUpdater"); @@ -16,6 +17,7 @@ const { startRPC, stopRPC } = require("./app/discordRPC"); const { configFeatures } = require("./config"); const config = require("./config"); +const { initThemes } = require("./app/themeManager"); const { checkNativeDependencies } = require("./app/dependencyCheck"); const { updateYtDlp } = require("./app/ytDlpUpdater"); @@ -48,6 +50,12 @@ app.whenReady().then(async () => { registerIpcHandlers(getMainWindow); + const themeFolderPath = config.localMode + ? path.join(__dirname, "theme") + : path.join(process.resourcesPath, "theme"); + + await initThemes(themeFolderPath); + await createMainWindow(); if (configFeatures.discordRPC) startRPC(); diff --git a/package-lock.json b/package-lock.json index f2d2963..ed318fd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "freedom-loader", - "version": "1.4.7", + "version": "1.5.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "freedom-loader", - "version": "1.4.7", + "version": "1.5.0", "dependencies": { "chalk": "^4.1.2", "debug": "^4.4.1", @@ -14,6 +14,7 @@ "electron-updater": "^6.6.2", "express": "^5.1.0", "express-rate-limit": "^8.2.1", + "jszip": "^3.10.1", "webidl-conversions": "^8.0.0", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" @@ -1925,9 +1926,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true, - "license": "MIT", - "optional": true + "license": "MIT" }, "node_modules/crc": { "version": "3.8.0", @@ -3515,6 +3514,12 @@ ], "license": "BSD-3-Clause" }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "license": "MIT" + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3612,6 +3617,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "license": "MIT" + }, "node_modules/isbinaryfile": { "version": "5.0.7", "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-5.0.7.tgz", @@ -3736,6 +3747,48 @@ "graceful-fs": "^4.1.6" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "license": "MIT" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -3758,6 +3811,15 @@ "integrity": "sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==", "license": "MIT" }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lodash": { "version": "4.18.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", @@ -4447,6 +4509,12 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "license": "(MIT AND Zlib)" + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -4607,6 +4675,12 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "license": "MIT" + }, "node_modules/progress": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", @@ -5039,6 +5113,12 @@ "url": "https://opencollective.com/express" } }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "license": "MIT" + }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", diff --git a/package.json b/package.json index a9e324a..fd4cb2b 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "electron-updater": "^6.6.2", "express": "^5.1.0", "express-rate-limit": "^8.2.1", + "jszip": "^3.10.1", "webidl-conversions": "^8.0.0", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0" @@ -45,6 +46,10 @@ }, "asar": true, "extraResources": [ + { + "from": "theme", + "to": "theme" + }, { "from": "build/confirm-icon.png", "to": "confirm-icon.png" diff --git a/preload.js b/preload.js index e9ca875..9692594 100644 --- a/preload.js +++ b/preload.js @@ -7,7 +7,8 @@ contextBridge.exposeInMainWorld("electronAPI", { getFeatures: () => ipcRenderer.invoke("features"), setFeature: (key, value) => ipcRenderer.invoke("set-feature", { key, value }), getVersion: () => ipcRenderer.invoke("version"), - getValidatedDownloadPath: (path) => ipcRenderer.invoke("validate-download-path", path) + getValidatedDownloadPath: (path) => ipcRenderer.invoke("validate-download-path", path), + getThemes: () => ipcRenderer.invoke("get-themes"), }); // Contrôles de fenêtre et outils custom pour la topbar diff --git a/public/assets/images/Chirac.png b/public/assets/images/Chirac.png deleted file mode 100644 index f40b8e7..0000000 Binary files a/public/assets/images/Chirac.png and /dev/null differ diff --git a/public/assets/images/Drift.jpg b/public/assets/images/Drift.jpg deleted file mode 100644 index 9fe9e29..0000000 Binary files a/public/assets/images/Drift.jpg and /dev/null differ diff --git a/public/assets/images/NF.jpg b/public/assets/images/NF.jpg deleted file mode 100644 index f8d4f55..0000000 Binary files a/public/assets/images/NF.jpg and /dev/null differ diff --git a/public/assets/images/Songbird.webp b/public/assets/images/Songbird.webp deleted file mode 100644 index e43a4b8..0000000 Binary files a/public/assets/images/Songbird.webp and /dev/null differ diff --git a/public/assets/images/Spicy.png b/public/assets/images/Spicy.png deleted file mode 100644 index c190be6..0000000 Binary files a/public/assets/images/Spicy.png and /dev/null differ diff --git a/public/script/customthemes.js b/public/script/customthemes.js index 7e5262c..ffd5209 100644 --- a/public/script/customthemes.js +++ b/public/script/customthemes.js @@ -1,62 +1,111 @@ -const themes = { - dark: { label: "Sombre", subtitle: "Darkness is my ally" }, - light: { label: "Clair", subtitle: "Qui aime ce thème ?" }, - neon: { label: "Purple", subtitle: "How was your day ?"}, - nf: { label: "NF", subtitle: "You call it music, i call it my Therapist" }, - songbird: { label: "Songbird", subtitle: "From Her to Eternity" }, - drift: { label: "Drift", subtitle: "Si la route t'appelle, contre appel" }, - fanatic: { label: "Fanatic", subtitle: "Always Fnatic !" }, - chirac: { label: "Chirac", subtitle: "J'aime les pommes" }, - spicy: { label: "Spicy", subtitle: "The Spiciest One" }, -}; - const themeSelect = document.getElementById("themeSelect"); +let loadedThemes = []; -function populateThemeSelect() { - for (const [themeKey, themeInfo] of Object.entries(themes)) { +function applyTheme(theme) { + const root = document.documentElement; + const style = theme.style; + + // Background + if (theme.image) { + document.body.style.backgroundImage = `url('${theme.image}')`; + document.body.style.backgroundSize = style.background?.size || "cover"; + document.body.style.backgroundPosition = style.background?.position || "center"; + document.body.style.backgroundAttachment = style.background?.attachment || "fixed"; + } else { + document.body.style.backgroundImage = ""; + } + + // Colors + root.style.setProperty("--background-color", style.colors?.background || ""); + root.style.setProperty("--default-text-color", style.colors?.text?.default || ""); + root.style.setProperty("--subtitle-color", style.colors?.text?.subtitle || ""); + root.style.setProperty("--audio-only-label-color", style.colors?.text?.audioOnly || ""); + + // Form + root.style.setProperty("--form-bg-color", style.form?.background || ""); + root.style.setProperty("--form-input-bg-color", style.form?.input?.background || ""); + root.style.setProperty("--form-input-border-color", style.form?.input?.border || ""); + root.style.setProperty("--form-input-border-focus-color", style.form?.input?.borderFocus || ""); + root.style.setProperty("--form-input-text-color", style.form?.input?.text || ""); + root.style.setProperty("--form-input-placeholder-color", style.form?.input?.placeholder || ""); + root.style.setProperty("--form-button-bg-color", style.form?.button?.background || ""); + root.style.setProperty("--form-button-text-color", style.form?.button?.text || ""); + root.style.setProperty("--form-button-bg-hover-color", style.form?.button?.hover || ""); + root.style.setProperty("--paste-button-icon-color", style.form?.pasteButtonIcon || ""); + + // Checkbox + root.style.setProperty("--checkbox-unchecked-bg-color", style.checkbox?.background?.unchecked || ""); + root.style.setProperty("--checkbox-checked-bg-color", style.checkbox?.background?.checked || ""); + root.style.setProperty("--checkbox-checkmark-border-color", style.checkbox?.checkmarkBorder || ""); + root.style.setProperty("--checkbox-pulse-color", style.checkbox?.pulse || ""); + + // Download + root.style.setProperty("--download-status-color", style.download?.status || ""); + + // Progress bar + root.style.setProperty("--progress-bar-bg-color", style.progressBar?.background || ""); + root.style.setProperty("--progress-bar-fill-color", style.progressBar?.fill || ""); + + // Video info + root.style.setProperty("--video-info-bg-color", style.videoInfo?.background || ""); + root.style.setProperty("--video-info-text-color", style.videoInfo?.text || ""); + root.style.setProperty("--video-info-heading-color", style.videoInfo?.heading || ""); + root.style.setProperty("--video-info-list-color", style.videoInfo?.list || ""); + root.style.setProperty("--video-info-list-strong-color", style.videoInfo?.strong || ""); + root.style.setProperty("--video-info-link-color", style.videoInfo?.link || ""); + root.style.setProperty("--video-info-link-hover-color", style.videoInfo?.linkHover || ""); + + // Playlist + root.style.setProperty("--playlist-background-color", style.playlist?.background || ""); + + // Settings + root.style.setProperty("--settings-button-bg-color", style.settings?.button?.background || ""); + root.style.setProperty("--settings-button-text-color", style.settings?.button?.text || ""); + root.style.setProperty("--settings-modal-bg-color", style.settings?.background?.modal || ""); + root.style.setProperty("--settings-section-bg-color", style.settings?.background?.section || ""); + root.style.setProperty("--settings-text-color", style.settings?.text || ""); + root.style.setProperty("--settings-subtitle-color", style.settings?.subtitle || ""); + + // Subtitle + const subtitleEl = document.getElementById("subtitle"); + if (subtitleEl) subtitleEl.textContent = theme.subtitle || theme.name; +} + +function saveTheme(themeId) { + window.electronAPI.setFeature("theme", themeId); +} + +function populateThemeSelect(themes) { + themeSelect.innerHTML = ""; + for (const theme of themes) { const option = document.createElement("option"); - option.value = themeKey; - option.textContent = themeInfo.label; + option.value = theme.id; + option.textContent = theme.name; themeSelect.appendChild(option); } } -function applyTheme(themeKey) { - document.body.classList.remove(...Object.keys(themes)); - document.body.classList.add(themeKey); +async function initThemes() { + loadedThemes = await window.electronAPI.getThemes(); - const subtitleElement = document.getElementById("subtitle"); - if (subtitleElement && themes[themeKey]) { - subtitleElement.textContent = themes[themeKey].subtitle; - } + if (!loadedThemes.length) return; + populateThemeSelect(loadedThemes); + + const features = await window.electronAPI.getFeatures(); + const savedId = features.theme; + const theme = loadedThemes.find(t => t.id === savedId) || loadedThemes[0]; + + themeSelect.value = theme.id; + applyTheme(theme); } -function saveTheme(themeKey) { - localStorage.setItem("selectedTheme", themeKey); -} - -function loadTheme() { - const savedTheme = localStorage.getItem("selectedTheme"); - - if (savedTheme && themes[savedTheme]) { - applyTheme(savedTheme); - themeSelect.value = savedTheme; - } else { - applyTheme("dark"); - themeSelect.value = "dark"; - } -} - -// When the user changes the theme from the select -themeSelect.addEventListener("change", (event) => { - const selectedTheme = event.target.value; - if (themes[selectedTheme]) { - applyTheme(selectedTheme); - saveTheme(selectedTheme); +themeSelect.addEventListener("change", (e) => { + const theme = loadedThemes.find(t => t.id === e.target.value); + if (theme) { + applyTheme(theme); + saveTheme(theme.id); } }); -// Initialisation -populateThemeSelect(); -loadTheme(); \ No newline at end of file +initThemes(); \ No newline at end of file diff --git a/public/styles/styles.css b/public/styles/styles.css index fad369e..9b9bc1c 100644 --- a/public/styles/styles.css +++ b/public/styles/styles.css @@ -12,9 +12,6 @@ @import url("components/editpathbutton.css"); @import url("components/progressBar.css"); -/* Themes */ -@import url("theme/themeimport.css"); - @import url('https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap'); #app { diff --git a/public/styles/theme/chirac-theme.css b/public/styles/theme/chirac-theme.css deleted file mode 100644 index babeebd..0000000 --- a/public/styles/theme/chirac-theme.css +++ /dev/null @@ -1,108 +0,0 @@ -body.chirac { - - background-image: url('../../assets/images/Chirac.png'); - background-repeat: no-repeat; - background-size: cover; - background-attachment: fixed; - - - --background-color: rgba(255, 255, 255, 0.85); - --default-text-color: #002395; - --subtitle-color: #EF4135; - --audio-only-label-color: #002395; - - /* Formulaire */ - --form-bg-color: rgba(255, 255, 255, 0.9); - --form-input-bg-color: #f5f5f5; - --form-input-border-color: #002395; - --form-input-border-focus-color: #EF4135; - --form-input-text-color: #002395; - --form-input-placeholder-color: #999999; - --form-button-bg-color: #002395; - --form-button-text-color: #ffffff; - --form-button-bg-hover-color: #EF4135; - --paste-button-icon-color: #ffffff; - - /* Checkbox */ - --checkbox-unchecked-bg-color: #cccccc; - --checkbox-checked-bg-color: #002395; - --checkbox-checkmark-border-color: #ffffff; - --checkbox-pulse-color: rgba(0, 35, 149, 0.5); - - /* Download status */ - --download-status-color: #002395; - - /* Progress bar */ - --progress-bar-bg-color: #d0d0d0; - --progress-bar-fill-color: #EF4135; - - /* Video Info Box */ - --video-info-bg-color: rgba(255, 255, 255, 0.9); - --video-info-text-color: #000000; - --video-info-heading-color: #EF4135; - --video-info-list-color: #444444; - --video-info-list-strong-color: #000000; - --video-info-link-color: #002395; - --video-info-link-hover-color: #EF4135; - - /* Playlist Color */ - --playlist-background-color: #d1d1d1ca; - - /* Settings */ - --settings-button-bg-color: #00196a; - --settings-button-text-color: #dcdcdc; - - --settings-modal-bg-color: #0b0528; - --settings-section-bg-color: #1c1055; - - --settings-text-color: #cecece; - --settings-subtitle-color: #adadad; -} - - -/* - -Je serai le président de tous les Français -Tous les Français -Tous les Français -Tous les Français -Tous les Français -Tous les Français -Tous les Français -Tous les Français -Tous les Français -Tous les Français -Mes chers compatriotes -Je serai le président de tous les Français, de tous les Français -Je mesure la difficulté de la tâche qui nous attend -Tous les Français -Tous les Français -Je veux un État, je veux les Français -Je veux un État, je veux -Je veux un État-tat-tat-tat vigoureux -Un État-tat-tat-tat impartial -Un État-tat-tat-tat vigoureux -Un État-tat-tat-tat exigeant -Un État-tat-tat-tat -Je serai le président de tous les Français -Tous les Français -Tous les Français -Tous les Français -Un État qui n'isole pas, tous, pas, pas -Tous, pas, tous, pas, pas -Tous, pas, tous, pas, pas (les Français) -Tous, tous, pas, tous, tous, pas, pas -Tous, tous, pas, tous, tous, pas, pas -Tous, tous, tous, pas, tous, pas, pas (les Français) -Tous, pas, tous, tous, pas, pas -Tous, tous, tous, pas, tous, tous, pas, pas -Tous, tous, pas, tous, tous, pas, pas -Tous, tous, tous-tous, tous-tous, pas, pas -Tous, tous-tous, tous-tous, pas, pas -Un État-tat-tat-tat vigoureux -Un État-tat-tat-tat impartial -Un État-tat-tat-tat exigeant -Un État-tat-tat-tat -Je serai le président de tous les Français - -*/ \ No newline at end of file diff --git a/public/styles/theme/dark-theme.css b/public/styles/theme/dark-theme.css deleted file mode 100644 index a727ac0..0000000 --- a/public/styles/theme/dark-theme.css +++ /dev/null @@ -1,54 +0,0 @@ -body.dark { - /* Couleurs générales */ - --background-color: #121212; /* noir/gris très foncé */ - --default-text-color: #e0e0e0; /* texte clair */ - --subtitle-color: #2196f3; /* bleu accent */ - --audio-only-label-color: #f5f5f5; /* texte checkbox */ - - /* Formulaire */ - --form-bg-color: #1e1e1e; /* fond formulaire */ - --form-input-bg-color: #2a2a2a; /* fond inputs */ - --form-input-border-color: #444444; /* bordure */ - --form-input-border-focus-color: #2196f3; /* focus bleu */ - --form-input-text-color: #f5f5f5; /* texte clair */ - --form-input-placeholder-color: #888888; /* placeholder gris */ - --form-button-bg-color: #2196f3; /* bouton bleu */ - --form-button-text-color: #ffffff; /* texte bouton */ - --form-button-bg-hover-color: #1976d2; /* hover bleu plus foncé */ - --paste-button-icon-color: #ffffff; - - /* Checkbox */ - --checkbox-unchecked-bg-color: #555555; /* gris moyen */ - --checkbox-checked-bg-color: #2196f3; /* bleu accent */ - --checkbox-checkmark-border-color: #ffffff; /* blanc */ - --checkbox-pulse-color: rgba(33, 150, 243, 0.5); - - /* Download status */ - --download-status-color: #2196f3; - - /* Progress bar */ - --progress-bar-bg-color: #444444; - --progress-bar-fill-color: #2196f3; - - /* Video Info Box */ - --video-info-bg-color: #1a1a1a; - --video-info-text-color: #e0e0e0; - --video-info-heading-color: #2196f3; - --video-info-list-color: #cccccc; - --video-info-list-strong-color: #ffffff; - --video-info-link-color: #2196f3; - --video-info-link-hover-color: #1976d2; - - /* Playlist Color */ - --playlist-background-color: #303030; - - /* Settings */ - --settings-button-bg-color: #1e1e1e; - --settings-button-text-color: var(--default-text-color); - - --settings-modal-bg-color: #1e1e1e; - --settings-section-bg-color: #2a2a2a; - --settings-text-color: var(--default-text-color); - --settings-subtitle-color: #aaa; - -} diff --git a/public/styles/theme/drift-theme.css b/public/styles/theme/drift-theme.css deleted file mode 100644 index eb640ab..0000000 --- a/public/styles/theme/drift-theme.css +++ /dev/null @@ -1,66 +0,0 @@ -body.drift { - - background-image: url('../../assets/images/Drift.jpg'); - background-size: cover; - background-position: center; - background-attachment: fixed; - - /* Palette principale */ - --background-color: #0f1218; - --default-text-color: #3d4b61; - --subtitle-color: #1a1a1a; - --audio-only-label-color: #c0d4ff; - - /* Formulaire */ - --form-bg-color: #1e222a; - --form-input-bg-color: #13171d; - --form-input-border-color: #3b4b6d; - --form-input-border-focus-color: #6ea8ff; - --form-input-text-color: #f0f4ff; - --form-input-placeholder-color: #7a8fae; - --form-button-bg-color: #2a2979; - --form-button-text-color: #ffffff; - --form-button-bg-hover-color: #353393; - --paste-button-icon-color: #ffffff; - - /* Checkbox */ - --checkbox-unchecked-bg-color: #2a2e38; - --checkbox-checked-bg-color: #2a2979; - --checkbox-checkmark-border-color: #ffffff; - --checkbox-pulse-color: rgba(76,108,255,0.3); - - /* Download status */ - --download-status-color: #ff8e8e; - - /* Progress bar */ - --progress-bar-bg-color: #3b4b6d; - --progress-bar-fill-color: #ff8e8e; - - /* Video Info Box */ - --video-info-bg-color: #1e222ad0; - --video-info-text-color: #e8e8f0; - --video-info-heading-color: #9ab6ff; - --video-info-list-color: #c0d4ff; - --video-info-list-strong-color: #ffffff; - --video-info-link-color: #4c6cff; - --video-info-link-hover-color: #6c8dff; - - /* Playlist Color */ - --playlist-background-color: #424b5cc2; - - /* Settings */ - --settings-button-bg-color: #1e222ace; - --settings-button-text-color: #b3b3b4; - - --settings-modal-bg-color: #1e222a; - --settings-section-bg-color: #272d38; - - --settings-text-color: #bababa; - --settings-subtitle-color: #cacaca; -} - - - -body.drift .download-path{ - color: #ededed; -} diff --git a/public/styles/theme/fanatic-theme.css b/public/styles/theme/fanatic-theme.css deleted file mode 100644 index a6d0d72..0000000 --- a/public/styles/theme/fanatic-theme.css +++ /dev/null @@ -1,54 +0,0 @@ -body.fanatic{ - /* Couleurs générales */ - --background-color: #121212; - --default-text-color: #eee; - --subtitle-color: #FF5900; - --audio-only-label-color: #ffffff; - - /* Formulaire */ - --form-bg-color: #1e1e1e; - --form-input-bg-color: #2b2b2b; - --form-input-border-color: #333333; - --form-input-border-focus-color: #FF5900; - --form-input-text-color: #eeeeee; - --form-input-placeholder-color: #666666; - --form-button-bg-color: #FF5900; - --form-button-text-color: #121212; - --form-button-bg-hover-color: #e65500; - --paste-button-icon-color: #f1f1f1; - - /* Checkbox */ - --checkbox-unchecked-bg-color: #555555; - --checkbox-checked-bg-color: #ff6600; - --checkbox-checkmark-border-color: #eee; - --checkbox-pulse-color: rgba(255, 102, 0, 0.5); - - /* Download status */ - --download-status-color: #FF5900; - - /* Progress bar */ - --progress-bar-bg-color: #444444; - --progress-bar-fill-color: #FF5900; - - /* Video Info Box */ - --video-info-bg-color: #222222; - --video-info-text-color: #eee; - --video-info-heading-color: #FF5900; - --video-info-list-color: #ccc; - --video-info-list-strong-color: #fff; - --video-info-link-color: #FF5900; - --video-info-link-hover-color: #e65500; - - /* Playlist Color */ - --playlist-background-color: #2b2b2b; - - /* Settings */ - --settings-button-bg-color: #1e1e1e; - --settings-button-text-color: #dcdcdc; - - --settings-modal-bg-color: #1e1e1e; - --settings-section-bg-color: #2d2d2d; - - --settings-text-color: #cecece; - --settings-subtitle-color: #adadad; -} diff --git a/public/styles/theme/light-theme.css b/public/styles/theme/light-theme.css deleted file mode 100644 index aff1015..0000000 --- a/public/styles/theme/light-theme.css +++ /dev/null @@ -1,53 +0,0 @@ -body.light { - /* Couleurs générales */ - --background-color: #dadada; - --default-text-color: #222222; - --subtitle-color: #007bff; - --audio-only-label-color: #000000; - - /* Formulaire */ - --form-bg-color: #ffffff; - --form-input-bg-color: #fafafa; - --form-input-border-color: #cccccc; - --form-input-border-focus-color: #007bff; - --form-input-text-color: #333333; - --form-input-placeholder-color: #888888; - --form-button-bg-color: #007bff; - --form-button-text-color: #ffffff; - --form-button-bg-hover-color: #0056b3; - --paste-button-icon-color: #ffffff; - - /* Checkbox */ - --checkbox-unchecked-bg-color: #cccccc; - --checkbox-checked-bg-color: #007bff; - --checkbox-checkmark-border-color: #ffffff; - --checkbox-pulse-color: rgba(0, 123, 255, 0.4); - - /* Download status */ - --download-status-color: #007bff; - - /* Progress bar */ - --progress-bar-bg-color: #e0e0e0; - --progress-bar-fill-color: #007bff; - - /* Video Info Box */ - --video-info-bg-color: #ffffff; - --video-info-text-color: #222222; - --video-info-heading-color: #007bff; - --video-info-list-color: #444444; - --video-info-list-strong-color: #000000; - --video-info-link-color: #007bff; - --video-info-link-hover-color: #0056b3; - - /* Playlist Color */ - --playlist-background-color: #c5c5c5b2; - - /* Settings */ - --settings-button-bg-color: #e4e4e4; - --settings-button-text-color: var(--default-text-color); - - --settings-modal-bg-color: #cbcbcb; - --settings-section-bg-color: #b8b8b8; - --settings-text-color: var(--default-text-color); - --settings-subtitle-color: #656565; -} diff --git a/public/styles/theme/neon-theme.css b/public/styles/theme/neon-theme.css deleted file mode 100644 index 3097cd6..0000000 --- a/public/styles/theme/neon-theme.css +++ /dev/null @@ -1,64 +0,0 @@ -body.neon { - - background: (url("../../assets/images/drift.jpg")); - background-image: linear-gradient(135deg, #0f0c29, #302b63, #24243e); /* dégradé sombre violet/bleu */ - background-size: cover; - background-position: center; - background-attachment: fixed; - - /* Couleurs générales */ - --background-color: #1b1b2f; - --default-text-color: #e0e0ff; - --subtitle-color: #a3a3ff; - --audio-only-label-color: #c0c0ff; - - /* Formulaire */ - --form-bg-color: #2c2c4a; - --form-input-bg-color: #1f1f3a; - --form-input-border-color: #5858f0; - --form-input-border-focus-color: #a3a3ff; - --form-input-text-color: #ffffff; - --form-input-placeholder-color: #8888ff; - --form-button-bg-color: #5858f0; - --form-button-text-color: #ffffff; - --form-button-bg-hover-color: #7a7aff; - --paste-button-icon-color: #ffffff; - - /* Checkbox */ - --checkbox-unchecked-bg-color: #302b63; - --checkbox-checked-bg-color: #5858f0; - --checkbox-checkmark-border-color: #ffffff; - --checkbox-pulse-color: rgba(88,88,240,0.3); - - /* Download status */ - --download-status-color: #a3a3ff; - - /* Progress bar */ - --progress-bar-bg-color: #302b63; - --progress-bar-fill-color: #a3a3ff; - - /* Video Info Box */ - --video-info-bg-color: #2c2c4a; - --video-info-text-color: #e0e0ff; - --video-info-heading-color: #a3a3ff; - --video-info-list-color: #c0c0ff; - --video-info-list-strong-color: #ffffff; - --video-info-link-color: #5858f0; - --video-info-link-hover-color: #7a7aff; - - /* Playlist Color */ - --playlist-background-color: #3e3e64; - - /* Settings */ - --settings-button-bg-color: #202038; - --settings-button-text-color: var(--default-text-color); - - --settings-modal-bg-color: #242454; - --settings-section-bg-color: #2f2f6f; - --settings-text-color: var(--default-text-color); - --settings-subtitle-color: #d2d2d2; -} - -body.neon .download-path { - color: var(--default-text-color); -} diff --git a/public/styles/theme/nf-theme.css b/public/styles/theme/nf-theme.css deleted file mode 100644 index e61eec2..0000000 --- a/public/styles/theme/nf-theme.css +++ /dev/null @@ -1,63 +0,0 @@ -body.nf { - - background-image: url('../../assets/images/NF.jpg'); - background-size: cover; - background-position: 70% center; - background-attachment: fixed; - - /* Couleurs générales */ - --background-color: #1a1a1a; - --default-text-color: #e6dfd5; - --subtitle-color: #f5f0e6; - --audio-only-label-color: #d8cfc2; - - /* Formulaire */ - --form-bg-color: #2a2a2a; - --form-input-bg-color: #222222; - --form-input-border-color: #4a4036; - --form-input-border-focus-color: #cbb89d; - --form-input-text-color: #f0e8dd; - --form-input-placeholder-color: #9a8f80; - --form-button-bg-color: #cbb89d; - --form-button-text-color: #1a1a1a; - --form-button-bg-hover-color: #b7a588; - --paste-button-icon-color: #1a1a1a; - - /* Checkbox */ - --checkbox-unchecked-bg-color: #4a4036; - --checkbox-checked-bg-color: #cbb89d; - --checkbox-checkmark-border-color: #1a1a1a; - --checkbox-pulse-color: rgba(203,184,157,0.3); - - /* Download status */ - --download-status-color: #cbb89d; - - /* Progress bar */ - --progress-bar-bg-color: #4a4036; - --progress-bar-fill-color: #cbb89d; - - /* Video Info Box */ - --video-info-bg-color: #2a2a2a; - --video-info-text-color: #e6dfd5; - --video-info-heading-color: #f5f0e6; - --video-info-list-color: #d8cfc2; - --video-info-list-strong-color: #ffffff; - --video-info-link-color: #cbb89d; - --video-info-link-hover-color: #b7a588; - - /* Playlist Color */ - --playlist-background-color: #4f4f4f; - - /* Settings */ - --settings-button-bg-color: #2a2a2a; - --settings-button-text-color: var(--default-text-color); - - --settings-modal-bg-color: #2a2a2a; - --settings-section-bg-color: #313131; - --settings-text-color: var(--default-text-color); - --settings-subtitle-color: #7a7979; -} - -body.nf .download-path { - color: var(--default-text-color); -} diff --git a/public/styles/theme/songbird-theme.css b/public/styles/theme/songbird-theme.css deleted file mode 100644 index 1280393..0000000 --- a/public/styles/theme/songbird-theme.css +++ /dev/null @@ -1,63 +0,0 @@ -body.songbird { - - background-image: url('../../assets/images/Songbird.webp'); - background-size: cover; - background-position: center center; - background-attachment: fixed; - - /* Couleurs générales */ - --background-color: #0a0a0a; /* noir profond */ - --default-text-color: #ff2a2a; /* rouge néon */ - --subtitle-color: #f2f2f2; /* rouge sombre */ - --audio-only-label-color: #ff4d4d; /* rouge un peu plus clair */ - - /* Formulaire */ - --form-bg-color: rgba(20,0,0,0.85); /* noir semi-transparent avec rouge */ - --form-input-bg-color: #1a0a0a; - --form-input-border-color: #ff2a2a; - --form-input-border-focus-color: #b30000; - --form-input-text-color: #ffffff; - --form-input-placeholder-color: #950404; - --form-button-bg-color: #b30000; - --form-button-text-color: #ffffff; - --form-button-bg-hover-color: #ff2a2a; - --paste-button-icon-color: #ffffff; - - /* Checkbox */ - --checkbox-unchecked-bg-color: #630000; - --checkbox-checked-bg-color: #ff2a2a; - --checkbox-checkmark-border-color: #ffffff; - --checkbox-pulse-color: rgba(255,42,42,0.3); - - /* Download status */ - --download-status-color: #ff2a2a; - - /* Progress bar */ - --progress-bar-bg-color: #630000; - --progress-bar-fill-color: #ff2a2a; - - /* Video Info Box */ - --video-info-bg-color: rgba(30,0,0,0.9); - --video-info-text-color: #ff4d4d; - --video-info-heading-color: #ff2a2a; - --video-info-list-color: #b30000; - --video-info-list-strong-color: #ffffff; - --video-info-link-color: #ff2a2a; - --video-info-link-hover-color: #b30000; - - /* Playlist Color */ - --playlist-background-color: #3f0000; - - /* Settings */ - --settings-button-bg-color: rgba(29, 0, 0, 0.784); - --settings-button-text-color: var(--default-text-color); - - --settings-modal-bg-color: #121212; - --settings-section-bg-color: #1a1a1a; - --settings-text-color: var(--default-text-color); - --settings-subtitle-color: #7a7979; -} - -body.cyberpunk .download-path { - color: var(--default-text-color); -} diff --git a/public/styles/theme/spicy-theme.css b/public/styles/theme/spicy-theme.css deleted file mode 100644 index d1f5a00..0000000 --- a/public/styles/theme/spicy-theme.css +++ /dev/null @@ -1,64 +0,0 @@ -body.spicy { - /* Couleurs générales */ - --background-color: #121212; /* fond noir profond */ - --default-text-color: #ffffff; /* texte clair */ - --subtitle-color: #f87918; /* accent rouge piment */ - --audio-only-label-color: #ffffff; /* texte checkbox inline */ - - /* Formulaire */ - --form-bg-color: #1a1a1a; /* fond formulaire gris très foncé */ - --form-input-bg-color: #2b2b2b; /* fond inputs gris foncé */ - --form-input-border-color: #444444; /* bordure gris */ - --form-input-border-focus-color: #ff1a1a; /* focus rouge piment */ - --form-input-text-color: #eeeeee; /* texte inputs */ - --form-input-placeholder-color: #888888; /* placeholder gris moyen */ - --form-button-bg-color: #ff1a1a; /* bouton rouge vif */ - --form-button-text-color: #ffffff; /* texte bouton blanc */ - --form-button-bg-hover-color: #cc0000; /* hover rouge foncé */ - --paste-button-icon-color: #ffffff; - - /* Checkbox */ - --checkbox-unchecked-bg-color: #555555; /* gris moyen */ - --checkbox-checked-bg-color: #ff1a1a; /* rouge piment */ - --checkbox-checkmark-border-color: #f5f5f5; /* blanc cassé */ - --checkbox-pulse-color: rgba(255, 26, 26, 0.5); /* pulse rouge translucide */ - - /* Download status */ - --download-status-color: #ffffff; /* rouge vif */ - - /* Progress bar */ - --progress-bar-bg-color: #444444; - --progress-bar-fill-color: #ff1a1a; - - /* Video Info Box */ - --video-info-bg-color: #1a1a1a; /* fond infos gris foncé */ - --video-info-text-color: #f5f5f5; /* texte clair */ - --video-info-heading-color: #ff1a1a; /* titres rouges */ - --video-info-list-color: #cccccc; /* texte liste gris clair */ - --video-info-list-strong-color: #ffffff; /* texte important blanc */ - --video-info-link-color: #ff1a1a; /* liens rouges */ - --video-info-link-hover-color: #cc0000; /* liens hover rouge foncé */ - - /* Playlist Color */ - --playlist-background-color: #353232; - - /* Settings */ - --settings-button-bg-color: #1a1a1a; - --settings-button-text-color: #dcdcdc; - - --settings-modal-bg-color: #1a1a1a; - --settings-section-bg-color: #292929; - - --settings-text-color: #cecece; - --settings-subtitle-color: #adadad; - -} - -/* Optionnel: background piments */ -body.spicy { - background-image: url('../../assets/images/Spicy.png'); - background-size:cover; - background-position: center; - background-attachment: fixed; - background-repeat: no-repeat; -} \ No newline at end of file diff --git a/public/styles/theme/themeimport.css b/public/styles/theme/themeimport.css deleted file mode 100644 index 7de5d07..0000000 --- a/public/styles/theme/themeimport.css +++ /dev/null @@ -1,9 +0,0 @@ -@import url("chirac-theme.css"); -@import url("dark-theme.css"); -@import url("fanatic-theme.css"); -@import url("light-theme.css"); -@import url("nf-theme.css"); -@import url("drift-theme.css"); -@import url("neon-theme.css"); -@import url("songbird-theme.css"); -@import url("spicy-theme.css") \ No newline at end of file diff --git a/public/styles/variables.css b/public/styles/variables.css index 3107bef..a47550e 100644 --- a/public/styles/variables.css +++ b/public/styles/variables.css @@ -39,6 +39,9 @@ --video-info-link-color: #007bff; --video-info-link-hover-color: #0056b3; + /* Playlist */ + --playlist-background-color: #4f4f4f; + /* Settings */ --settings-button-bg-color: var(--form-bg-color); --settings-button-text-color: var(--default-text-color);