mirror of
https://github.com/danbulant/dribbblish-dynamic-theme
synced 2026-06-09 09:42:26 +00:00
Updated config Interface
This commit is contained in:
parent
db1ad17ffa
commit
507d283d00
3 changed files with 279 additions and 120 deletions
|
|
@ -176,17 +176,25 @@ function toggleDark(setDark) {
|
||||||
/* Init with current system light/dark mode */
|
/* Init with current system light/dark mode */
|
||||||
let systemDark = parseInt(getComputedStyle(document.documentElement).getPropertyValue("--system_is_dark")) == 1;
|
let systemDark = parseInt(getComputedStyle(document.documentElement).getPropertyValue("--system_is_dark")) == 1;
|
||||||
|
|
||||||
DribbblishShared.config.registerSelect("Theme", "theme", ["System", "Dark", "Light"], 0, (val) => {
|
DribbblishShared.config.register({
|
||||||
switch (val) {
|
type: "select",
|
||||||
case 0:
|
options: ["System", "Dark", "Light"],
|
||||||
toggleDark(systemDark);
|
key: "theme",
|
||||||
break;
|
name: "Theme",
|
||||||
case 1:
|
description: "Select Dark / Bright mode",
|
||||||
toggleDark(true);
|
defaultValue: 0,
|
||||||
break;
|
onChange: (val) => {
|
||||||
case 2:
|
switch (val) {
|
||||||
toggleDark(false);
|
case 0:
|
||||||
break;
|
toggleDark(systemDark);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
toggleDark(true);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
toggleDark(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -321,11 +329,15 @@ hookCoverChange(false);
|
||||||
document.querySelector(".main-userWidget-box").append(upd)
|
document.querySelector(".main-userWidget-box").append(upd)
|
||||||
upd.append(`Theme UPD v${data.tag_name} avail.`)
|
upd.append(`Theme UPD v${data.tag_name} avail.`)
|
||||||
upd.setAttribute("title", `Changes: ${data.name}`)
|
upd.setAttribute("title", `Changes: ${data.name}`)
|
||||||
DribbblishShared.configButton.addItem(
|
DribbblishShared.config.register({
|
||||||
new Spicetify.Menu.Item("Update", false, (self) => {
|
insertOnTop: true,
|
||||||
|
type: "button",
|
||||||
|
name: "Update",
|
||||||
|
description: "Open the GitHub Page with Installation instructions / Commands.",
|
||||||
|
onChange: () => {
|
||||||
window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme#install", "_blank");
|
window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme#install", "_blank");
|
||||||
})
|
}
|
||||||
);
|
});
|
||||||
}
|
}
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
// Do something for an error here
|
// Do something for an error here
|
||||||
|
|
|
||||||
286
dribbblish.js
286
dribbblish.js
|
|
@ -1,133 +1,213 @@
|
||||||
// Hide popover message
|
// Hide popover message
|
||||||
// document.getElementById("popover-container").style.height = 0;
|
// document.getElementById("popover-container").style.height = 0;
|
||||||
const DribbblishShared = {
|
class ConfigMenu {
|
||||||
configButton: new Spicetify.Menu.SubMenu("Dribbblish", []),
|
constructor() {
|
||||||
config: {
|
this.config = {};
|
||||||
register: (name, key, defaultValue, update) => {
|
this.configButton = new Spicetify.Menu.Item("Dribbblish config", false, () => DribbblishShared.config.open());
|
||||||
const menuItem = new Spicetify.Menu.Item(name, defaultValue, (self) => {
|
this.configButton.register();
|
||||||
self.setState(!self.isEnabled);
|
|
||||||
DribbblishShared.config.toggle(key);
|
|
||||||
});
|
|
||||||
DribbblishShared.configButton.addItem(menuItem);
|
|
||||||
|
|
||||||
if (localStorage.getItem(`dribbblish:config:${key}`) == null) localStorage.setItem(`dribbblish:config:${key}`, defaultValue);
|
const container = document.createElement("div");
|
||||||
|
container.id = "dribbblish-config";
|
||||||
|
container.innerHTML = /* html */ `
|
||||||
|
<div class="dribbblish-config-container">
|
||||||
|
<button aria-label="Close" class="dribbblish-config-close main-trackCreditsModal-closeBtn">
|
||||||
|
<svg width="18" height="18" viewBox="0 0 32 32" xmlns="http://www.w3.org/2000/svg"><path d="M31.098 29.794L16.955 15.65 31.097 1.51 29.683.093 15.54 14.237 1.4.094-.016 1.508 14.126 15.65-.016 29.795l1.414 1.414L15.54 17.065l14.144 14.143" fill="currentColor" fill-rule="evenodd"></path></svg>
|
||||||
|
</button>
|
||||||
|
<h1>Dribbblish Settings</h1>
|
||||||
|
</div>
|
||||||
|
<div class="dribbblish-config-backdrop"></div>
|
||||||
|
`;
|
||||||
|
|
||||||
DribbblishShared.configData[key] = {
|
document.body.appendChild(container);
|
||||||
menuItem,
|
document.querySelector(".dribbblish-config-close").addEventListener("click", () => DribbblishShared.config.close());
|
||||||
update
|
document.querySelector(".dribbblish-config-backdrop").addEventListener("click", () => DribbblishShared.config.close());
|
||||||
};
|
}
|
||||||
|
|
||||||
DribbblishShared.config.update(key);
|
open() {
|
||||||
},
|
document.getElementById("dribbblish-config").setAttribute("active", "");
|
||||||
registerSelect: (name, key, choices, defaultChoice, update) => {
|
}
|
||||||
const menuItem = new Spicetify.Menu.SubMenu(name, []);
|
|
||||||
const menuItems = choices.map((choice, i) => {
|
|
||||||
const subItem = new Spicetify.Menu.Item(choice, i == defaultChoice, (self) => {
|
|
||||||
self.setState(!self.isEnabled);
|
|
||||||
DribbblishShared.config.set(key, i);
|
|
||||||
});
|
|
||||||
menuItem.addItem(subItem);
|
|
||||||
return subItem;
|
|
||||||
});
|
|
||||||
DribbblishShared.configButton.addItem(menuItem);
|
|
||||||
menuItem.register();
|
|
||||||
|
|
||||||
if (localStorage.getItem(`dribbblish:config:${key}`) == null) localStorage.setItem(`dribbblish:config:${key}`, defaultChoice);
|
close() {
|
||||||
|
document.getElementById("dribbblish-config").removeAttribute("active");
|
||||||
|
}
|
||||||
|
|
||||||
DribbblishShared.configData[key] = {
|
/** @private */
|
||||||
subItems: menuItems,
|
addInputHTML({ type, key, name, description, input, insertOnTop }) {
|
||||||
menuItem,
|
const elem = document.createElement("div");
|
||||||
update
|
elem.classList.add("dribbblish-config-item");
|
||||||
};
|
elem.setAttribute("key", `dribbblish:config:${key}`);
|
||||||
|
elem.setAttribute("type", type);
|
||||||
DribbblishShared.config.update(key);
|
elem.innerHTML = /* html */ `
|
||||||
},
|
<h2 class="x-settings-title main-type-cello" as="h2">${name}</h2>
|
||||||
get: (key) => {
|
<label class="main-type-mesto" as="label" for="dribbblish-config-input-${key}" style="color: var(--spice-subtext);">${description}</label>
|
||||||
const val = localStorage.getItem(`dribbblish:config:${key}`);
|
<label class="x-toggle-wrapper x-settings-secondColumn">
|
||||||
if (val == "true" || val == "false") return val == "true";
|
${input}
|
||||||
if (!isNaN(val) && !isNaN(parseInt(val))) return parseInt(val);
|
</label>
|
||||||
},
|
`;
|
||||||
set: (key, val) => {
|
if (insertOnTop && document.querySelector(".dribbblish-config-item")) {
|
||||||
if (DribbblishShared.configData[key].hasOwnProperty("subItems")) {
|
console.log("before");
|
||||||
DribbblishShared.configData[key].subItems.forEach((item, i) => {
|
document.querySelector(".dribbblish-config-container").insertBefore(elem, document.querySelector(".dribbblish-config-item:first-of-type"));
|
||||||
item.setState(val == i);
|
} else {
|
||||||
});
|
document.querySelector(".dribbblish-config-container").appendChild(elem);
|
||||||
} else {
|
|
||||||
DribbblishShared.configData[key].menuItem.setState(val);
|
|
||||||
}
|
|
||||||
localStorage.setItem(`dribbblish:config:${key}`, val);
|
|
||||||
DribbblishShared.config.update(key);
|
|
||||||
},
|
|
||||||
toggle: (key) => {
|
|
||||||
DribbblishShared.config.set(key, !DribbblishShared.config.get(key));
|
|
||||||
|
|
||||||
if (DribbblishShared.configData[key].hasOwnProperty("subItems")) {
|
|
||||||
// Can't toggle lists
|
|
||||||
} else {
|
|
||||||
DribbblishShared.configData[key].menuItem.setState(DribbblishShared.config.get(key));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
update: (key) => {
|
|
||||||
const val = DribbblishShared.config.get(key);
|
|
||||||
if (DribbblishShared.configData[key].hasOwnProperty("subItems")) {
|
|
||||||
DribbblishShared.configData[key].subItems.forEach((item, i) => {
|
|
||||||
item.setState(val == i);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
DribbblishShared.configData[key].menuItem.setState(val);
|
|
||||||
}
|
|
||||||
DribbblishShared.configData[key].update(val);
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
configData: {}
|
|
||||||
};
|
|
||||||
DribbblishShared.configButton.register();
|
|
||||||
|
|
||||||
// Initialize Config
|
register({ type, options, key, name, description, defaultValue, insertOnTop, onChange }) {
|
||||||
DribbblishShared.config.register("Right expanded cover", "rightBigCover", true, (value) => {
|
if (!key) key = cyrb53Hash(name);
|
||||||
if (value) {
|
var fireChange = true;
|
||||||
document.documentElement.classList.add("right-expanded-cover");
|
|
||||||
} else {
|
if (type == "checkbox") {
|
||||||
document.documentElement.classList.remove("right-expanded-cover");
|
const input = /* html */ `
|
||||||
|
<input id="dribbblish-config-input-${key}" class="x-toggle-input" type="checkbox"${this.get(key, defaultValue) ? " checked" : ""}>
|
||||||
|
<span class="x-toggle-indicatorWrapper">
|
||||||
|
<span class="x-toggle-indicator"></span>
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
this.addInputHTML({ type, key, name, description, input, insertOnTop });
|
||||||
|
|
||||||
|
document.getElementById(`dribbblish-config-input-${key}`).addEventListener("change", (e) => {
|
||||||
|
this.set(key, e.target.checked);
|
||||||
|
onChange(this.get(key));
|
||||||
|
});
|
||||||
|
} else if (type == "select") {
|
||||||
|
const input = /* html */ `
|
||||||
|
<span class="x-settings-secondColumn">
|
||||||
|
<select class="main-dropDown-dropDown" id="dribbblish-config-input-${key}">
|
||||||
|
${options.map((option, i) => `<option value="${i}"${this.get(key, defaultValue) == i ? " selected" : ""}>${option}</option>`).join("")}
|
||||||
|
</select>
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
this.addInputHTML({ type, key, name, description, input, insertOnTop });
|
||||||
|
|
||||||
|
document.getElementById(`dribbblish-config-input-${key}`).addEventListener("change", (e) => {
|
||||||
|
this.set(key, e.target.value);
|
||||||
|
onChange(this.get(key));
|
||||||
|
});
|
||||||
|
} else if (type == "button") {
|
||||||
|
const input = /* html */ `
|
||||||
|
<span class="x-settings-secondColumn">
|
||||||
|
<button class="main-buttons-button main-button-primary" type="button" id="dribbblish-config-input-${key}">
|
||||||
|
<div class="x-settings-buttonContainer">
|
||||||
|
<span>${name}</span>
|
||||||
|
</div>
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
`;
|
||||||
|
this.addInputHTML({ type, key, name, description, input, insertOnTop });
|
||||||
|
|
||||||
|
document.getElementById(`dribbblish-config-input-${key}`).addEventListener("click", (e) => {
|
||||||
|
onChange(true);
|
||||||
|
});
|
||||||
|
fireChange = false;
|
||||||
|
} else {
|
||||||
|
throw new Error(`Config Type "${type}" invalid`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fireChange) onChange(this.get(key, defaultValue));
|
||||||
|
}
|
||||||
|
|
||||||
|
get(key, defaultValue) {
|
||||||
|
const val = localStorage.getItem(`dribbblish:config:${key}`);
|
||||||
|
if (val == null) return defaultValue;
|
||||||
|
|
||||||
|
if (val == "true" || val == "false") return val == "true"; // Boolean
|
||||||
|
if (!isNaN(val) && !isNaN(parseInt(val))) return parseInt(val); // Number
|
||||||
|
return val; // String
|
||||||
|
}
|
||||||
|
|
||||||
|
set(key, val) {
|
||||||
|
localStorage.setItem(`dribbblish:config:${key}`, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class _DribbblishShared {
|
||||||
|
constructor() {
|
||||||
|
this.config = new ConfigMenu();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const DribbblishShared = new _DribbblishShared();
|
||||||
|
|
||||||
|
DribbblishShared.config.register({
|
||||||
|
type: "checkbox",
|
||||||
|
key: "rightBigCover",
|
||||||
|
name: "Right expanded cover",
|
||||||
|
description: "Have the expanded cover Image on the right instead of onn the left.",
|
||||||
|
defaultValue: true,
|
||||||
|
onChange: (val) => {
|
||||||
|
if (val) {
|
||||||
|
document.documentElement.classList.add("right-expanded-cover");
|
||||||
|
} else {
|
||||||
|
document.documentElement.classList.remove("right-expanded-cover");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
DribbblishShared.config.register("Round Sidebar Icons", "roundSidebarIcons", false, (value) => {
|
DribbblishShared.config.register({
|
||||||
if (value) {
|
type: "checkbox",
|
||||||
document.documentElement.style.setProperty("--sidebar-icons-border-radius", "50%");
|
key: "roundSidebarIcons",
|
||||||
} else {
|
name: "Round Sidebar Icons",
|
||||||
document.documentElement.style.setProperty("--sidebar-icons-border-radius", "var(--image-radius)");
|
description: "If the Sidebar Iconns should be round instead of square",
|
||||||
|
defaultValue: false,
|
||||||
|
onChange: (val) => {
|
||||||
|
if (val) {
|
||||||
|
document.documentElement.style.setProperty("--sidebar-icons-border-radius", "50%");
|
||||||
|
} else {
|
||||||
|
document.documentElement.style.setProperty("--sidebar-icons-border-radius", "var(--image-radius)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
DribbblishShared.config.open();
|
||||||
|
|
||||||
waitForElement(["#main"], () => {
|
waitForElement(["#main"], () => {
|
||||||
DribbblishShared.config.registerSelect("Windows Top Bar", "winTopBar", ["None", "None (With Top Padding)", "Solid", "Transparent"], 0, (value) => {
|
DribbblishShared.config.register({
|
||||||
switch (value) {
|
type: "select",
|
||||||
case 0:
|
options: ["None", "None (With Top Padding)", "Solid", "Transparent"],
|
||||||
document.getElementById("main").setAttribute("top-bar", "none");
|
key: "winTopBar",
|
||||||
break;
|
name: "Windows Top Bar",
|
||||||
case 1:
|
description: "Have differennt top Bars (Ore none at all)",
|
||||||
document.getElementById("main").setAttribute("top-bar", "none-padding");
|
defaultValue: 0,
|
||||||
break;
|
onChange: (val) => {
|
||||||
case 2:
|
switch (val) {
|
||||||
document.getElementById("main").setAttribute("top-bar", "solid");
|
case 0:
|
||||||
break;
|
document.getElementById("main").setAttribute("top-bar", "none");
|
||||||
case 3:
|
break;
|
||||||
document.getElementById("main").setAttribute("top-bar", "transparent");
|
case 1:
|
||||||
break;
|
document.getElementById("main").setAttribute("top-bar", "none-padding");
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
document.getElementById("main").setAttribute("top-bar", "solid");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
document.getElementById("main").setAttribute("top-bar", "transparent");
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function waitForElement(els, func, timeout = 100) {
|
function waitForElement(els, func, timeout = 100) {
|
||||||
const queries = els.map(el => document.querySelector(el));
|
const queries = els.map((el) => document.querySelector(el));
|
||||||
if (queries.every(a => a)) {
|
if (queries.every((a) => a)) {
|
||||||
func(queries);
|
func(queries);
|
||||||
} else if (timeout > 0) {
|
} else if (timeout > 0) {
|
||||||
setTimeout(waitForElement, 300, els, func, --timeout);
|
setTimeout(waitForElement, 300, els, func, --timeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cyrb53Hash(str, seed = 0) {
|
||||||
|
let h1 = 0xdeadbeef ^ seed,
|
||||||
|
h2 = 0x41c6ce57 ^ seed;
|
||||||
|
for (let i = 0, ch; i < str.length; i++) {
|
||||||
|
ch = str.charCodeAt(i);
|
||||||
|
h1 = Math.imul(h1 ^ ch, 2654435761);
|
||||||
|
h2 = Math.imul(h2 ^ ch, 1597334677);
|
||||||
|
}
|
||||||
|
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^ Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
||||||
|
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^ Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
||||||
|
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
||||||
|
}
|
||||||
|
|
||||||
waitForElement([
|
waitForElement([
|
||||||
`.main-rootlist-rootlistPlaylistsScrollNode ul[tabindex="0"]`,
|
`.main-rootlist-rootlistPlaylistsScrollNode ul[tabindex="0"]`,
|
||||||
`.main-rootlist-rootlistPlaylistsScrollNode ul[tabindex="0"] li`
|
`.main-rootlist-rootlistPlaylistsScrollNode ul[tabindex="0"] li`
|
||||||
|
|
|
||||||
71
user.css
71
user.css
|
|
@ -274,14 +274,14 @@ span.artist-artistVerifiedBadge-badge svg > path:last-of-type {
|
||||||
}
|
}
|
||||||
|
|
||||||
.cover-art,
|
.cover-art,
|
||||||
|
.main-userWidget-box,
|
||||||
.view-homeShortcutsGrid-shortcut,
|
.view-homeShortcutsGrid-shortcut,
|
||||||
:not(.view-homeShortcutsGrid-imageWrapper) > .main-image-image:not(.main-avatar-image) {
|
:not(.view-homeShortcutsGrid-imageWrapper) > .main-image-image:not(.main-avatar-image) {
|
||||||
border-radius: var(--image-radius) !important;
|
border-radius: var(--image-radius) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-userWidget-box,
|
|
||||||
.main-avatar-userIcon,
|
|
||||||
.main-avatar-image,
|
.main-avatar-image,
|
||||||
|
.main-avatar-userIcon,
|
||||||
.view-homeShortcutsGrid-shortcutLink {
|
.view-homeShortcutsGrid-shortcutLink {
|
||||||
border-radius: var(--sidebar-icons-border-radius) !important;
|
border-radius: var(--sidebar-icons-border-radius) !important;
|
||||||
}
|
}
|
||||||
|
|
@ -699,6 +699,73 @@ li.GlueDropTarget {
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#dribbblish-config {
|
||||||
|
display: none;
|
||||||
|
z-index: 99999;
|
||||||
|
position: absolute;
|
||||||
|
inset: 0px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
color: var(--spice-text);
|
||||||
|
}
|
||||||
|
|
||||||
|
#dribbblish-config[active] {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dribbblish-config .dribbblish-config-container {
|
||||||
|
z-index: 1;
|
||||||
|
position: relative;
|
||||||
|
max-width: 80%;
|
||||||
|
background-color: rgba(var(--spice-rgb-main), 0.85);
|
||||||
|
backdrop-filter: blur(3px);
|
||||||
|
padding: 20px 15px;
|
||||||
|
border-radius: var(--main-corner-radius);
|
||||||
|
display: flex;
|
||||||
|
gap: 5px;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dribbblish-config .dribbblish-config-item {
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0px 50px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr auto;
|
||||||
|
grid-template-rows: 1fr 1fr;
|
||||||
|
gap: 0px 10px;
|
||||||
|
grid-template-areas:
|
||||||
|
"header input"
|
||||||
|
"description input";
|
||||||
|
}
|
||||||
|
|
||||||
|
#dribbblish-config .dribbblish-config-item > .x-settings-title {
|
||||||
|
grid-area: header;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dribbblish-config .dribbblish-config-item > .main-type-mesto {
|
||||||
|
grid-area: description;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dribbblish-config .dribbblish-config-item > .x-settings-secondColumn {
|
||||||
|
grid-area: input;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dribbblish-config .dribbblish-config-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 15px;
|
||||||
|
right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#dribbblish-config .dribbblish-config-backdrop {
|
||||||
|
position: absolute;
|
||||||
|
content: "";
|
||||||
|
inset: 0px;
|
||||||
|
backdrop-filter: blur(3px) brightness(60%);
|
||||||
|
}
|
||||||
|
|
||||||
/** Rearrange player bar */
|
/** Rearrange player bar */
|
||||||
.main-nowPlayingBar-left {
|
.main-nowPlayingBar-left {
|
||||||
order: 1;
|
order: 1;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue