diff --git a/main.js b/main.js
index 272a9c5..1dced18 100644
--- a/main.js
+++ b/main.js
@@ -204,6 +204,22 @@ app.whenReady().then(async () => {
ipcMain.handle("features", () => {
return configFeatures;
});
+
+ ipcMain.handle("set-feature", (event, { key, value }) => {
+ try {
+ // update mémoire
+ configFeatures[key] = value;
+
+ // écriture directe sur le JSON
+ fs.writeFileSync(configFolderPath, JSON.stringify(configFeatures, null, 2), "utf-8");
+
+ logger.info(`Feature updated: ${key} = ${value}`);
+ return true;
+ } catch (err) {
+ logger.error(`set-feature failed (${key}): ${err.message}`);
+ return false;
+ }
+ });
configFeatures.discordRPC ? startRPC() : "";
diff --git a/preload.js b/preload.js
index aacdf74..e9ca875 100644
--- a/preload.js
+++ b/preload.js
@@ -5,6 +5,7 @@ contextBridge.exposeInMainWorld("electronAPI", {
selectDownloadFolder: () => ipcRenderer.invoke("select-download-folder"),
setProgress: (percent) => ipcRenderer.send("set-progress", percent),
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)
});
diff --git a/public/assets/icon/settings.png b/public/assets/icon/settings.png
deleted file mode 100644
index 848e6b1..0000000
Binary files a/public/assets/icon/settings.png and /dev/null differ
diff --git a/public/assets/icon/settings.svg b/public/assets/icon/settings.svg
new file mode 100644
index 0000000..39ab649
--- /dev/null
+++ b/public/assets/icon/settings.svg
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/public/index.html b/public/index.html
index f4bfa4f..7050fe2 100644
--- a/public/index.html
+++ b/public/index.html
@@ -23,7 +23,6 @@
-
@@ -31,18 +30,167 @@
-
-
-
-
-
-
+
-
-
Settings Panel
-
+
+
+
+
+
+
+
SETTINGS
+
Changes are saved automatically.
Somes changes could need a restart
+
+
+
+
+
Basic Settings
+
+
+
+
+ Thème
+
+
+
+
Choose the theme of the application
+
+
+
+
+
+
+
+ Discord RPC
+ Enable/disable Discord Rich Presence for your app.
+
+
+
+
+
+
+ Download Playlist automatically?
+ If enabled, playlists will download without confirmation.
+
+
+
+
+
+
+
+
+ Custom Top bar
+ Use this if the topbar is missing or you prefer a custom one.
+
+
+
+
+
+
+ Auto Fetch Info
+ Automatically fetch information for new downloads.
+
+
+
+
+
+
+
+ Advanced Settings
+
+
+
+
+ Auto Update
+ Enable automatic app updates.
+
+
+
+
+
+
+
+
+ Add Metadata
+ Include metadata in downloaded files.
+
+
+
+
+
+
+ Add Thumbnail
+ Include thumbnails in downloaded files.
+
+
+
+
+
+ Custom Codec
+
+ Choose your preferred video codec.
+
+
+
+
+
+
+
+ Developer Settings
+
+
+
+
+
+
+
+
+ Verbose Logs
+ Show verbose logs for debugging purposes.
+
+
+
+
+
+
+
+
@@ -106,6 +254,9 @@
+
+
Because Why Not ?
+
diff --git a/public/script/settingsPanel.js b/public/script/settingsPanel.js
index 6868501..ae8f2f9 100644
--- a/public/script/settingsPanel.js
+++ b/public/script/settingsPanel.js
@@ -1,7 +1,50 @@
-const settingsButton = document.getElementById("settings-button")
-const settingsPanel = document.getElementById("settings-panel")
+const settingsPanel = document.getElementById("settings-panel");
+const settingsModal = document.querySelector(".settings-modal");
-function openPanel(){
- settingsPanel.style.display = "block";
- console.log("Click")
-}
\ No newline at end of file
+const settingsButton = document.getElementById("settings-button");
+
+let isOpen = false;
+
+settingsButton.addEventListener("click", () => {
+ const isOpen = settingsPanel.style.display === "block";
+ settingsPanel.style.display = isOpen ? "none" : "block";
+});
+
+function closePanel() {
+ isOpen = false;
+ settingsPanel.style.display = "none";
+}
+
+// charge les features
+async function loadSettings() {
+ const features = await window.electronAPI.getFeatures();
+
+ document.querySelectorAll(".settings-section input, .settings-section select").forEach(el => {
+ const key = el.dataset.key;
+ if (features[key] !== undefined) {
+ if (el.type === "checkbox") el.checked = features[key];
+ else if (el.tagName === "SELECT") el.value = features[key];
+ }
+
+ el.addEventListener("change", () => {
+ let value = el.type === "checkbox" ? el.checked : el.value;
+ window.electronAPI.setFeature(key, value);
+ });
+ });
+}
+
+// ouvrir le JSON
+document.getElementById("open-json-btn").addEventListener("click", () => {
+ window.topbarAPI.openConfig(); // ton IPC existant
+});
+
+
+/* clic sur l'overlay = fermer */
+settingsPanel.addEventListener("click", closePanel);
+
+/* clic dans la modal = stop propagation */
+settingsModal.addEventListener("click", (e) => {
+ e.stopPropagation();
+});
+
+loadSettings();
diff --git a/public/styles/layout/settingsPanel.css b/public/styles/layout/settingsPanel.css
index 59a234e..0fa7b3d 100644
--- a/public/styles/layout/settingsPanel.css
+++ b/public/styles/layout/settingsPanel.css
@@ -1,33 +1,234 @@
-.settings-button{
- display:flex;
- background-color: rgba(219, 219, 219, 0.89);
- border-radius: 12px;
- padding: 5px;
- transition: all ease-in-out 0.2s;
- position: absolute;
+/* SETTINGS BUTTON */
+.settings-button {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: fixed;
+ top: 60px;
+ right: 20px;
+ opacity: 0.8;
+ background-color: var(--settings-button-bg-color);
+ border-radius: 14px;
+ padding: 8px;
+ border: none;
+ box-shadow: 0 6px 16px rgba(0,0,0,0.25);
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
+}
+
+.settings-button svg {
+ width: 40px;
+ height: 40px;
+ stroke: var(--settings-button-text-color);
+}
+
+.settings-button:hover {
+ transform: scale(1.1);
+ cursor: pointer;
+ box-shadow: 0 10px 24px rgba(0,0,0,0.35);
+}
+
+.settings-button:active {
+ transform: scale(0.95);
+}
+
+
+/* SETTINGS PANEL */
+.settings-panel {
+ position: fixed;
top: 60px;
right: 40px;
- border: none;
+ width: 40vw;
+ max-width: 320px;
+ max-height: 80vh;
+ background-color: var(--settings-bg-primary-color);
+ border-radius: 12px;
+ padding: 20px;
+ box-shadow: 0 8px 24px rgba(0,0,0,0.4);
+ display: none;
+ overflow-y: auto;
+ z-index: 9999;
+ animation: slideIn 0.2s ease-out;
+ color: var(--settings-text-color);
}
-.settings-button img{
- width: 50px;
- height: 50px;
+.settings-panel::-webkit-scrollbar {
+ width: 0px;
+ background: transparent;
}
-.settings-button:hover{
- transform: scale(1.2);
+.settings-modal {
+ width: 100%;
+ min-height: auto;
+ max-height: none;
+ padding: 0;
+ background: none;
+ box-shadow: none;
+ border-radius: none;
+
+}
+
+/* TITLE */
+.settings-title {
+ margin-bottom: 20px;
+}
+
+.settings-title h2 {
+ margin: 0;
+ font-size: 24px;
+}
+
+.settings-title p {
+ font-size: 14px;
+ color: #ccc;
+ margin-top: 4px;
+}
+
+/* SECTION */
+.settings-section {
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 20px;
+ padding: 10px 15px;
+ background: var(--settings-bg-secondary-color);
+ border-radius: 12px;
+ gap: 6px;
+}
+
+.settings-section h3 {
+ margin: 0 0 10px 0;
+ font-size: 18px;
+}
+
+/* SETTING ITEM */
+.setting-item {
+ display: flex;
+ align-items: flex-start;
+ gap: 12px;
+ margin-bottom: 8px;
+ margin-top: 8px;
+}
+
+.setting-item input[type="checkbox"] {
+ margin: 0;
+ flex-shrink: 0;
+ width: 20px;
+ height: 20px;
+}
+
+.setting-info {
+ display: flex;
+ flex-direction: column;
+}
+
+.setting-title {
+ font-size: 14px;
+ font-weight: 500;
+}
+
+.setting-info small {
+ font-size: 12px;
+ color: var(--settings-subtitle-color);
+ margin-top: 2px;
+ font-style: italic;
+}
+
+#theme .settings-title{
+ display: flex;
+}
+
+.setting-item select {
+ width: 70%;
+ background: #fff;
+ border: 1px solid #242424;
+ border-radius: 6px;
+ padding: 4px 8px;
+ color: #000;
+ cursor: pointer;
+ font-weight: 600;
+ transition: background 0.3s ease, color 0.3s ease;
+}
+
+.setting-item select:hover,
+.setting-item select:focus {
+ background: #474747;
+ color: #fff;
+ outline: none;
+}
+
+/* SELECT */
+.settings-section select {
+ margin-left: 10px;
+}
+
+/* DETAILS / DROPDOWN */
+details {
+ margin-bottom: 20px;
+ padding: 10px 15px;
+ background: #2a2a2a;
+ border-radius: 12px;
+}
+
+details[open] {
+ box-shadow: 0 4px 15px rgba(0,0,0,0.3);
+}
+
+details summary {
cursor: pointer;
}
-.settings-button:active{
- transform: scale(0.9);
+/* FOOTER */
+.settings-footer {
+ margin-top: 20px;
+ display: flex;
+ flex-direction: column;
+ gap: 10px;
}
-.settings-panel{
- position: absolute;
+#open-json-btn {
+ padding: 6px 12px;
+ border-radius: 8px;
+ border: none;
+ cursor: pointer;
+ font-weight: 600;
+ background-color: var(--form-button-bg-color);
+ color: #fff;
+}
+
+#experimental-args {
width: 100%;
- height: 100%;
- background-color: red;
- z-index: 9999999;
+ min-height: 80px;
+ background-color: #1e1e1e;
+ border-radius: 8px;
+ padding: 8px;
+ color: #fff;
+ border: 1px solid #333;
+ resize: vertical;
+}
+
+/* CLOSE BTN */
+.close-btn {
+ position: absolute;
+ top: 20px;
+ right: 20px;
+ background: none;
+ border: none;
+ color: white;
+ font-size: 24px;
+ cursor: pointer;
+ opacity: 0.6;
+}
+
+.close-btn:hover {
+ opacity: 1;
+}
+
+/* ANIMATION */
+@keyframes popIn {
+ from { transform: scale(0.95); opacity: 0; }
+ to { transform: scale(1); opacity: 1; }
+}
+
+@keyframes slideIn {
+ from { transform: translateX(20px); opacity: 0; }
+ to { transform: translateX(0); opacity: 1; }
}
\ No newline at end of file
diff --git a/public/styles/variables.css b/public/styles/variables.css
index cfbb85d..29362d3 100644
--- a/public/styles/variables.css
+++ b/public/styles/variables.css
@@ -33,4 +33,14 @@
--video-info-list-strong-color: #000000;
--video-info-link-color: #007bff;
--video-info-link-hover-color: #0056b3;
+
+ /* Settings */
+ --settings-button-bg-color: var(--form-bg-color);
+ --settings-button-text-color: var(--default-text-color);
+
+ --settings-bg-primary-color: var(--form-bg-color);
+ --settings-bg-secondary-color: var(--form-bg-color);
+ --settings-text-color: var(--default-text-color);
+ --settings-subtitle-color: #aaa;
+
}