From 9ded9817ee7ff6633eab009de6f31e57f3944a24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Sj=C3=B6stedt?= Date: Thu, 7 Oct 2021 20:02:49 +0100 Subject: [PATCH 01/13] Add color fading - Add color fading, by using a JS interval that changes the color every 10ms. - Add option in Dribbblish settings to change the fading duration. - Fixed a few types in the Dribbblish settings. Thanks for making such an awesome extension! --- dribbblish-dynamic.js | 83 ++++++++++++++++++++++++++++++++++--------- dribbblish.js | 19 ++++++++-- user.css | 2 +- 3 files changed, 84 insertions(+), 20 deletions(-) diff --git a/dribbblish-dynamic.js b/dribbblish-dynamic.js index 4c5713c..9796f06 100644 --- a/dribbblish-dynamic.js +++ b/dribbblish-dynamic.js @@ -170,7 +170,7 @@ function toggleDark(setDark) { setRootColor('subtext', setDark ? "#EAEAEA" : "#3D3D3D") setRootColor('notification', setDark ? "#303030" : "#DDDDDD") - updateColors(textColor, sidebarColor) + updateColors(textColor, sidebarColor, false) } /* Init with current system light/dark mode */ @@ -198,20 +198,70 @@ DribbblishShared.config.register({ } }); -function updateColors(textColHex, sideColHex) { - let isLightBg = isLight(textColorBg) - if (isLightBg) textColHex = LightenDarkenColor(textColHex, -15) // vibrant color is always too bright for white bg mode +var currentColor; +var currentSideColor; +var colorFadeInterval = false; - let darkColHex = LightenDarkenColor(textColHex, isLightBg ? 12 : -20) - let darkerColHex = LightenDarkenColor(textColHex, isLightBg ? 30 : -40) - let buttonBgColHex = setLightness(textColHex, isLightBg ? 0.90 : 0.14) - setRootColor('text', textColHex) - setRootColor('button', darkerColHex) - setRootColor('button-active', darkColHex) - setRootColor('selected-row', darkerColHex) - setRootColor('tab-active', buttonBgColHex) - setRootColor('button-disabled', buttonBgColHex) - setRootColor('sidebar', sideColHex) +function updateColors(textColHex, sideColHex, animate=false) { + let update = (textColHex, sideColHex) => { + currentColor = textColHex; + currentSideColor = sideColHex; + + let isLightBg = isLight(textColorBg) + if (isLightBg) textColHex = LightenDarkenColor(textColHex, -15) // vibrant color is always too bright for white bg mode + + let darkColHex = LightenDarkenColor(textColHex, isLightBg ? 12 : -20) + let darkerColHex = LightenDarkenColor(textColHex, isLightBg ? 30 : -40) + let buttonBgColHex = setLightness(textColHex, isLightBg ? 0.90 : 0.14) + setRootColor('text', textColHex) + setRootColor('button', darkerColHex) + setRootColor('button-active', darkColHex) + setRootColor('selected-row', darkerColHex) + setRootColor('tab-active', buttonBgColHex) + setRootColor('button-disabled', buttonBgColHex) + setRootColor('sidebar', sideColHex) + }; + + clearInterval(colorFadeInterval); // clear any interval that might be running + + if(!animate) { + update(textColHex, sideColHex); + return; + } + + let clamp = (num,min,max) => Math.min(Math.max(num, min), max); + let lerp = (a,b,u) => (1-u) * a + u * b; + let toMS = s => parseFloat(s) * (/\ds$/.test(s) ? 1000 : 1); + + let interval = 10; // 10 ms between each call + var duration = toMS(getComputedStyle(document.documentElement).getPropertyValue("--song-transition-speed")); + if(duration < 1) duration = 1; + let startC1 = hexToRgb(currentColor); + let startC2 = hexToRgb(currentSideColor); + + let endC1 = hexToRgb(textColHex); + let endC2 = hexToRgb(sideColHex); + + var start; + + colorFadeInterval = setInterval(function(){ + if(!start) { start = performance.now() } + let elapsed = performance.now()-start; + let ratio = clamp(elapsed/duration, 0, 1) + + let currentC1 = []; + let currentC2 = []; + for(var i = 0; i < 3; i++){ + currentC1[i] = lerp(startC1[i], endC1[i], ratio); + currentC2[i] = lerp(startC2[i], endC2[i], ratio); + } + + update(rgbToHex(currentC1), rgbToHex(currentC2)); + + console.log(elapsed+">"+duration+"->"+(elapsed>duration)) + if (elapsed>duration){ clearInterval(colorFadeInterval) } + + }, interval); } let nearArtistSpanText = "" @@ -294,7 +344,7 @@ function pickCoverColor(img) { sidebarColor = swatches[lightCols[col]].getHex() break } - updateColors(textColor, sidebarColor) + updateColors(textColor, sidebarColor, true) } function hookCoverChange(pick) { @@ -363,6 +413,7 @@ document.styleSheets[0].addRule('.Root__top-container::before', backface-visibility: hidden; will-change: transform; opacity: calc(0.07 + 0.03 * var(--is_light, 0)); - z-index: +3;`) + z-index: +3; + transition: background-image var(--song-transition-speed) linear;`) document.documentElement.style.setProperty('--warning_message', ' '); diff --git a/dribbblish.js b/dribbblish.js index 9c57af4..d498dee 100644 --- a/dribbblish.js +++ b/dribbblish.js @@ -131,7 +131,7 @@ 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.", + description: "Have the expanded cover Image on the right instead of on the left", defaultValue: true, onChange: (val) => { if (val) { @@ -146,7 +146,7 @@ DribbblishShared.config.register({ type: "checkbox", key: "roundSidebarIcons", name: "Round Sidebar Icons", - description: "If the Sidebar Iconns should be round instead of square", + description: "If the Sidebar Icons should be round instead of square", defaultValue: false, onChange: (val) => { if (val) { @@ -157,13 +157,26 @@ DribbblishShared.config.register({ } }); +DribbblishShared.config.register({ + type: "select", + options: ["No fade", "0.25s", "0.5s", "1s", "5s"], + key: "fadeDuration", + name: "Color Fade Duration", + description: "Select the duration of the color fading transition", + defaultValue: 0, + onChange: (val) => { + let values = ["0s", "0.25s", "0.5s", "1s", "5s"]; + document.documentElement.style.setProperty("--song-transition-speed", values[val]); + } +}); + waitForElement(["#main"], () => { DribbblishShared.config.register({ type: "select", options: ["None", "None (With Top Padding)", "Solid", "Transparent"], key: "winTopBar", name: "Windows Top Bar", - description: "Have differennt top Bars (Ore none at all)", + description: "Have different top Bars (or none at all)", defaultValue: 0, onChange: (val) => { switch (val) { diff --git a/user.css b/user.css index 368c0ce..b667a0a 100644 --- a/user.css +++ b/user.css @@ -8,6 +8,7 @@ --playbar-movement-anim-speed: 0.5s; --image-radius: 10px; --sidebar-icons-border-radius: 50%; + --song-transition-speed: 3s; } @font-face { @@ -1068,4 +1069,3 @@ html.right-expanded-cover.buddyfeed-visible .main-coverSlotExpanded-container { .main-actionBar-ActionBarRow button:not(.main-playButton-primary) { color: var(--spice-subtext); -} \ No newline at end of file From 1e128d7d831f22f1715fceb2a9ab8535bca69a60 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Sj=C3=B6stedt?= Date: Thu, 7 Oct 2021 20:04:17 +0100 Subject: [PATCH 02/13] Add missing } at end of user.css --- user.css | 1 + 1 file changed, 1 insertion(+) diff --git a/user.css b/user.css index b667a0a..7eda485 100644 --- a/user.css +++ b/user.css @@ -1069,3 +1069,4 @@ html.right-expanded-cover.buddyfeed-visible .main-coverSlotExpanded-container { .main-actionBar-ActionBarRow button:not(.main-playButton-primary) { color: var(--spice-subtext); +} From 5dbd1afbd73e7d558713753034db835078f0cd97 Mon Sep 17 00:00:00 2001 From: Send_Nukez Date: Fri, 8 Oct 2021 06:05:38 +0200 Subject: [PATCH 03/13] update config to support areas / categories, number, text and slider inputs --- dribbblish-dynamic.js | 56 ++++++----- dribbblish.js | 212 ++++++++++++++++++++++++++++++------------ user.css | 96 ++++++++++++++++++- 3 files changed, 272 insertions(+), 92 deletions(-) diff --git a/dribbblish-dynamic.js b/dribbblish-dynamic.js index 4c5713c..2571c34 100644 --- a/dribbblish-dynamic.js +++ b/dribbblish-dynamic.js @@ -178,7 +178,7 @@ let systemDark = parseInt(getComputedStyle(document.documentElement).getProperty DribbblishShared.config.register({ type: "select", - options: ["System", "Dark", "Light"], + data: ["System", "Dark", "Light"], key: "theme", name: "Theme", description: "Select Dark / Bright mode", @@ -325,19 +325,13 @@ hookCoverChange(false); }).then(data => { if (data.tag_name > current) { upd = document.createElement("div") + upd.innerText = `Theme UPD v${data.tag_name} avail.` upd.classList.add("ellipsis-one-line", "main-type-finale") - document.querySelector(".main-userWidget-box").append(upd) - upd.append(`Theme UPD v${data.tag_name} avail.`) upd.setAttribute("title", `Changes: ${data.name}`) - DribbblishShared.config.register({ - 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"); - } - }); + upd.style.setProperty("color", "var(--spice-main)"); + document.querySelector(".main-userWidget-box").append(upd) + document.querySelector(".main-userWidget-box").classList.add("update-avail") + new Spicetify.Menu.Item("Update Dribbblish", false, () => window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme#install", "_blank")).register(); } }).catch(err => { // Do something for an error here @@ -346,23 +340,25 @@ hookCoverChange(false); })() /* translucid background cover */ -document.styleSheets[0].addRule('.Root__top-container::before', -` content: ''; - background-image: var(--image_url); - background-repeat: no-repeat; - background-size: cover; - background-position: center center; - position: fixed; - display: block; - top: 0; - left: 0; - right: 0; - bottom: 0; - filter: blur(15px); - pointer-events: none; - backface-visibility: hidden; - will-change: transform; - opacity: calc(0.07 + 0.03 * var(--is_light, 0)); - z-index: +3;`) +document.styleSheets[0].insertRule(` + .Root__top-container::before { + content: ''; + background-image: var(--image_url); + background-repeat: no-repeat; + background-size: cover; + background-position: center center; + position: fixed; + display: block; + top: 0; + left: 0; + right: 0; + bottom: 0; + filter: blur(15px); + pointer-events: none; + backface-visibility: hidden; + will-change: transform; + opacity: calc(0.07 + 0.03 * var(--is_light, 0)); + z-index: +3; + }`) document.documentElement.style.setProperty('--warning_message', ' '); diff --git a/dribbblish.js b/dribbblish.js index 9c57af4..392b513 100644 --- a/dribbblish.js +++ b/dribbblish.js @@ -1,6 +1,20 @@ // Hide popover message // document.getElementById("popover-container").style.height = 0; class ConfigMenu { + /** + * @typedef {Object} DribbblishConfigOptions + * @property {"checkbox" | "select" | "button" | "slider" | "number" | "text"} type + * @property {String?} area + * @property {any?} data + * @property {String?} key + * @property {String?} name + * @property {String?} description + * @property {any?} defaultValue + * @property {Boolean?} insertOnTop + * @property {Function?} onAppended + * @property {Function?} onChange + */ + constructor() { this.config = {}; this.configButton = new Spicetify.Menu.Item("Dribbblish config", false, () => DribbblishShared.config.open()); @@ -14,6 +28,7 @@ class ConfigMenu {

Dribbblish Settings

+
`; @@ -31,79 +46,164 @@ class ConfigMenu { document.getElementById("dribbblish-config").removeAttribute("active"); } - /** @private */ - addInputHTML({ type, key, name, description, input, insertOnTop }) { + /** + * @private + * @param {DribbblishConfigOptions} options + */ + addInputHTML(options) { + let parent; + if (options.area != null) { + if (!document.querySelector(`.dribbblish-config-area[name="${options.area}"]`)) { + const areaElem = document.createElement("div"); + areaElem.classList.add("dribbblish-config-area"); + areaElem.setAttribute("name", options.area); + areaElem.innerHTML = `

${options.area}

`; + document.querySelector(".dribbblish-config-items").appendChild(areaElem); + } + parent = document.querySelector(`.dribbblish-config-area[name="${options.area}"]`); + } else { + parent = document.querySelector(".dribbblish-config-items"); + } + const elem = document.createElement("div"); elem.classList.add("dribbblish-config-item"); - elem.setAttribute("key", `dribbblish:config:${key}`); - elem.setAttribute("type", type); + elem.setAttribute("key", `dribbblish:config:${options.key}`); + elem.setAttribute("type", options.type); elem.innerHTML = /* html */ ` -

${name}

- +

${options.name}

+ `; - if (insertOnTop && document.querySelector(".dribbblish-config-item")) { - console.log("before"); - document.querySelector(".dribbblish-config-container").insertBefore(elem, document.querySelector(".dribbblish-config-item:first-of-type")); + + if (options.insertOnTop && parent.children.length > 0) { + parent.insertBefore(elem, parent.children[0]); } else { - document.querySelector(".dribbblish-config-container").appendChild(elem); + parent.appendChild(elem); } } - register({ type, options, key, name, description, defaultValue, insertOnTop, onChange }) { - if (!key) key = cyrb53Hash(name); + /** + * @param {DribbblishConfigOptions} options + */ + register(options) { + options = { + ...{ + area: "Main Settings", + data: {}, + key: cyrb53Hash(options.name ?? ""), + name: "", + description: "", + insertOnTop: false, + onAppended: () => {}, + onChange: () => {} + }, + ...options + }; var fireChange = true; - if (type == "checkbox") { + if (options.type == "checkbox") { const input = /* html */ ` - + `; - this.addInputHTML({ type, key, name, description, input, insertOnTop }); + this.addInputHTML({ ...options, input }); - document.getElementById(`dribbblish-config-input-${key}`).addEventListener("change", (e) => { - this.set(key, e.target.checked); - onChange(this.get(key)); + document.getElementById(`dribbblish-config-input-${options.key}`).addEventListener("change", (e) => { + this.set(options.key, e.target.checked); + options.onChange(this.get(options.key)); }); - } else if (type == "select") { + } else if (options.type == "select") { const input = /* html */ ` - - - + `; - this.addInputHTML({ type, key, name, description, input, insertOnTop }); + this.addInputHTML({ ...options, input }); - document.getElementById(`dribbblish-config-input-${key}`).addEventListener("change", (e) => { - this.set(key, e.target.value); - onChange(this.get(key)); + document.getElementById(`dribbblish-config-input-${options.key}`).addEventListener("change", (e) => { + this.set(options.key, e.target.value); + options.onChange(this.get(options.key)); }); - } else if (type == "button") { + } else if (options.type == "button") { const input = /* html */ ` - - - + `; - this.addInputHTML({ type, key, name, description, input, insertOnTop }); + this.addInputHTML({ ...options, input }); - document.getElementById(`dribbblish-config-input-${key}`).addEventListener("click", (e) => { - onChange(true); + document.getElementById(`dribbblish-config-input-${options.key}`).addEventListener("click", (e) => { + options.onChange(true); }); fireChange = false; + } else if (options.type == "number") { + if (options.defaultValue == null) options.defaultValue = 0; + + const input = /* html */ ` + + `; + this.addInputHTML({ ...options, input }); + + // Prevent inputting +, - and e. Why is it even possible in the first place? + document.getElementById(`dribbblish-config-input-${options.key}`).addEventListener("keypress", (e) => { + if (["+", "-", "e"].includes(e.key)) e.preventDefault(); + }); + + document.getElementById(`dribbblish-config-input-${options.key}`).addEventListener("input", (e) => { + if (options.data.min != null && e.target.value < options.data.min) e.target.value = options.data.min; + if (options.data.max != null && e.target.value > options.data.max) e.target.value = options.data.max; + + this.set(options.key, e.target.value); + options.onChange(this.get(options.key)); + }); + } else if (options.type == "text") { + if (options.defaultValue == null) options.defaultValue = ""; + + const input = /* html */ ` + + `; + this.addInputHTML({ ...options, input }); + + document.getElementById(`dribbblish-config-input-${options.key}`).addEventListener("input", (e) => { + // TODO: maybe add an validation function via `data.validate` + this.set(options.key, e.target.value); + options.onChange(this.get(options.key)); + }); + } else if (options.type == "slider") { + if (options.defaultValue == null) options.defaultValue = 0; + + const input = /* html */ ` + + `; + this.addInputHTML({ ...options, input }); + + document.getElementById(`dribbblish-config-input-${options.key}`).addEventListener("input", (e) => { + document.getElementById(`dribbblish-config-input-${options.key}`).setAttribute("tooltip", `${e.target.value}${options.data?.suffix ?? ""}`); + document.getElementById(`dribbblish-config-input-${options.key}`).setAttribute("value", e.target.value); + this.set(options.key, e.target.value); + options.onChange(e.target.value); + }); } else { - throw new Error(`Config Type "${type}" invalid`); + throw new Error(`Config Type "${options.type}" invalid`); } - if (fireChange) onChange(this.get(key, defaultValue)); + options.onAppended(); + if (fireChange) options.onChange(this.get(options.key, options.defaultValue)); } get(key, defaultValue) { @@ -111,7 +211,8 @@ class ConfigMenu { if (val == null) return defaultValue; if (val == "true" || val == "false") return val == "true"; // Boolean - if (!isNaN(val) && !isNaN(parseInt(val))) return parseInt(val); // Number + if (!isNaN(val) && /\d+\.\d+/.test(val) && !isNaN(parseFloat(val))) return parseFloat(val); // Float + if (!isNaN(val) && /\d+/.test(val) && !isNaN(parseInt(val))) return parseInt(val); // Int return val; // String } @@ -131,7 +232,7 @@ 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.", + description: "Have the expanded cover Image on the right instead of on the left.", defaultValue: true, onChange: (val) => { if (val) { @@ -160,7 +261,7 @@ DribbblishShared.config.register({ waitForElement(["#main"], () => { DribbblishShared.config.register({ type: "select", - options: ["None", "None (With Top Padding)", "Solid", "Transparent"], + data: ["None", "None (With Top Padding)", "Solid", "Transparent"], key: "winTopBar", name: "Windows Top Bar", description: "Have differennt top Bars (Ore none at all)", @@ -206,10 +307,7 @@ function cyrb53Hash(str, seed = 0) { return 4294967296 * (2097151 & h2) + (h1 >>> 0); } -waitForElement([ - `.main-rootlist-rootlistPlaylistsScrollNode ul[tabindex="0"]`, - `.main-rootlist-rootlistPlaylistsScrollNode ul[tabindex="0"] li` -], ([root, firstItem]) => { +waitForElement([`.main-rootlist-rootlistPlaylistsScrollNode ul[tabindex="0"]`, `.main-rootlist-rootlistPlaylistsScrollNode ul[tabindex="0"] li`], ([root, firstItem]) => { const listElem = firstItem.parentElement; root.classList.add("dribs-playlist-list"); @@ -219,7 +317,7 @@ waitForElement([ let link = item.querySelector("a"); if (!link) continue; - let [_, app, uid ] = link.pathname.split("/"); + let [_, app, uid] = link.pathname.split("/"); let uri; if (app === "playlist") { uri = Spicetify.URI.playlistV2URI(uid); @@ -231,14 +329,11 @@ waitForElement([ img.classList.add("playlist-picture"); link.prepend(img); } - img.src = base64 || "/images/tracklist-row-song-fallback.svg"; + img.src = base64 || "/images/tracklist-row-song-fallback.svg"; continue; } - Spicetify.CosmosAsync.get( - `sp://core-playlist/v1/playlist/${uri.toURI()}/metadata`, - { policy: { picture: true } } - ).then(res => { + Spicetify.CosmosAsync.get(`sp://core-playlist/v1/playlist/${uri.toURI()}/metadata`, { policy: { picture: true } }).then((res) => { const meta = res.metadata; let img = link.querySelector("img"); if (!img) { @@ -254,13 +349,12 @@ waitForElement([ DribbblishShared.loadPlaylistImage = loadPlaylistImage; loadPlaylistImage(); - new MutationObserver(loadPlaylistImage) - .observe(listElem, {childList: true}); + new MutationObserver(loadPlaylistImage).observe(listElem, { childList: true }); }); -waitForElement([".main-rootlist-rootlist", ".main-rootlist-wrapper > :nth-child(2) > :first-child"], ([rootlist]) => { +waitForElement([".main-rootlist-rootlist", ".main-rootlist-wrapper > :nth-child(2) > :first-child", "#spicetify-show-list"], ([rootlist]) => { function checkSidebarPlaylistScroll() { - const topDist = rootlist.getBoundingClientRect().top - document.querySelector(".main-rootlist-wrapper > :nth-child(2) > :first-child").getBoundingClientRect().top; + const topDist = rootlist.getBoundingClientRect().top - document.querySelector("#spicetify-show-list:not(:empty), .main-rootlist-wrapper > :nth-child(2) > :first-child").getBoundingClientRect().top; const bottomDist = document.querySelector(".main-rootlist-wrapper > :nth-child(2) > :last-child").getBoundingClientRect().bottom - rootlist.getBoundingClientRect().bottom; rootlist.classList.remove("no-top-shadow", "no-bottom-shadow"); diff --git a/user.css b/user.css index 368c0ce..fb06482 100644 --- a/user.css +++ b/user.css @@ -91,12 +91,81 @@ body { input { background-color: unset !important; - border-bottom: solid 1px var(--spice-text) !important; border-radius: 0 !important; padding: 6px 10px 6px 48px; color: var(--spice-text) !important; } +input[type=range] { + -webkit-appearance: none; + background: transparent; + padding: 0px; +} + +input[type=range]::-webkit-slider-thumb { + -webkit-appearance: none; + width: 16px; + height: 16px; + margin-top: -4px; + border-radius: 50%; + background-color: var(--spice-text); +} + +input[type=range]::-webkit-slider-thumb:hover, +input[type=range]::-webkit-slider-thumb:active { + filter: brightness(80%); +} + +input[type=range]::after { + z-index: 9999; + content: attr(tooltip); + position: absolute; + min-width: 50px; + top: -10px; + left: 50%; + transform: translateX(calc(-50%)); + padding: 0 5px; + border-radius: 4px; + text-align: center; + color: var(--spice-sidebar-text); + background-color: var(--spice-button); + transition: opacity 0.25s ease; + opacity: 0; +} + +input[type=range]:hover::after, +input[type=range]:active::after { + opacity: 1; +} + +input[type=range]:focus { + outline: none; +} + +input[type=range]::-webkit-slider-runnable-track { + width: 100%; + height: 8px; + background-color: rgba(var(--spice-rgb-text), .2); + border-radius: 50vw; +} + +input[type=number], +input[type=text] { + height: 32px; + border: none; + border-radius: 4px !important; + padding: 0px 10px; + background-color: rgba(var(--spice-rgb-selected-row), .4) !important; + color: var(--spice-subtext) !important; +} + +input[type=number]:hover, +input[type=number]:active, +input[type=text]:hover, +input[type=text]:active { + background-color: rgba(var(--spice-rgb-selected-row), .6) !important; +} + .x-searchInput-searchInputSearchIcon, .x-searchInput-searchInputClearButton { color: var(--spice-text) !important; @@ -717,10 +786,11 @@ li.GlueDropTarget { z-index: 1; position: relative; max-width: 80%; - background-color: rgba(var(--spice-rgb-main), 0.85); + background-color: rgba(var(--spice-rgb-main), 0.9); backdrop-filter: blur(3px); padding: 20px 15px; border-radius: var(--main-corner-radius); + box-shadow: 0 0 10px 3px #0000003b; display: flex; gap: 5px; flex-direction: column; @@ -728,10 +798,21 @@ li.GlueDropTarget { justify-content: center; } +#dribbblish-config .dribbblish-config-items { + max-height: 60vh; + overflow-y: auto; + padding: 0px 50px; +} + +.dribbblish-config-area > h2 { + text-align: center; +} + #dribbblish-config .dribbblish-config-item { position: relative; width: 100%; - padding: 0px 50px; + padding: 5px 0px; + height: min-content; display: grid; grid-template-columns: 1fr auto; grid-template-rows: 1fr 1fr; @@ -743,10 +824,19 @@ li.GlueDropTarget { #dribbblish-config .dribbblish-config-item > .x-settings-title { grid-area: header; + margin: 0px; + height: min-content; + position: relative; + bottom: 0px; +} + +#dribbblish-config .dribbblish-config-item > .x-settings-title.no-desc { + bottom: -10px; } #dribbblish-config .dribbblish-config-item > .main-type-mesto { grid-area: description; + height: min-content; } #dribbblish-config .dribbblish-config-item > .x-settings-secondColumn { From 30b66d37a66410e2ed22a5cfba79008fbb4de559 Mon Sep 17 00:00:00 2001 From: Send_Nukez Date: Fri, 8 Oct 2021 06:09:31 +0200 Subject: [PATCH 04/13] fix user icon update available looking weird --- user.css | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/user.css b/user.css index fb06482..b3b9eaf 100644 --- a/user.css +++ b/user.css @@ -340,21 +340,31 @@ span.artist-artistVerifiedBadge-badge svg > path:last-of-type { .view-homeShortcutsGrid-shortcut { overflow: hidden; + background-color: rgba(var(--spice-rgb-selected-row), 0.4); +} + +.view-homeShortcutsGrid-shortcut:hover { + background-color: rgba(var(--spice-rgb-selected-row), 0.6); } .cover-art, -.main-userWidget-box, +.main-userWidget-box.upd-avail, .view-homeShortcutsGrid-shortcut, :not(.view-homeShortcutsGrid-imageWrapper) > .main-image-image:not(.main-avatar-image) { border-radius: var(--image-radius) !important; } .main-avatar-image, +.main-userWidget-box:not(.upd-avail), .main-avatar-userIcon, .view-homeShortcutsGrid-shortcutLink { border-radius: var(--sidebar-icons-border-radius) !important; } +.main-userWidget-box { + background-color: transparent; +} + .main-avatar-avatar.main-avatar-withBadge:after { box-shadow: 0 0 0 2px var(--spice-sidebar); background-color: var(--spice-notification); From 96486d419caa045561a01caff261ccfcbd0d2567 Mon Sep 17 00:00:00 2001 From: Send_Nukez Date: Fri, 8 Oct 2021 06:10:27 +0200 Subject: [PATCH 05/13] fix connect bar and make add friends button more visible --- user.css | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/user.css b/user.css index b3b9eaf..c6bfbf8 100644 --- a/user.css +++ b/user.css @@ -384,11 +384,16 @@ span.artist-artistVerifiedBadge-badge svg > path:last-of-type { min-width: 518px; } +.main-buddyFeed-findFriendsButton { + color: var(--spice-sidebar-text); +} + .main-connectBar-connectBar { border-radius: 0 0 var(--main-corner-radius) var(--main-corner-radius); border: 2px solid var(--spice-main); border-top: 0; - color: var(--spice-sidebar-text); + background-color: var(--spice-button) !important; + color: var(--spice-text) !important; } .Root__nav-bar { From d3cf6c2853f4db9fa36a603fd152002c29eef34d Mon Sep 17 00:00:00 2001 From: Send_Nukez Date: Fri, 8 Oct 2021 06:11:11 +0200 Subject: [PATCH 06/13] improve toggle input styles --- user.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/user.css b/user.css index c6bfbf8..8969ff5 100644 --- a/user.css +++ b/user.css @@ -530,6 +530,14 @@ html.sidebar-hide-text .GlueDropTarget span { display: none; } +.x-toggle-indicatorWrapper { + background-color: var(--spice-shadow); +} + +input:hover:not([disabled]):not(:active)~.x-toggle-indicatorWrapper { + background-color: var(--spice-button-active); +} + /** */ .main-topBar-historyButtons .main-topBar-button { background-color: unset; From a4100b2eb7dd3f3c1837bafd37bc33b99a625309 Mon Sep 17 00:00:00 2001 From: Send_Nukez Date: Fri, 8 Oct 2021 06:15:07 +0200 Subject: [PATCH 07/13] fix some sidebar alignment issues --- user.css | 65 ++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 52 insertions(+), 13 deletions(-) diff --git a/user.css b/user.css index 8969ff5..2f43388 100644 --- a/user.css +++ b/user.css @@ -708,15 +708,20 @@ html.sidebar-hide-text .main-rootlist-rootlistItem { height: 2px; } -.main-navBar-navBarLink { - height: 56px; +.main-rootlist-rootlistPlaylistsScrollNode { + padding: 0px; } -.main-navBar-navBarLink .icon, .main-collectionLinkButton-icon, -.main-createPlaylistButton-icon, -.main-collectionLinkButton-icon { - margin-right: 24px; +.main-createPlaylistButton-icon { + margin: 0px; +} + +.main-navBar-navBarLink, +.main-collectionLinkButton-collectionLinkButton, +.main-createPlaylistButton-button { + gap: 24px; + height: 56px; } li.GlueDropTarget { @@ -941,6 +946,16 @@ li.GlueDropTarget { opacity: 1; } +.main-collectionLinkButton-collectionLinkText, +.main-createPlaylistButton-text, +.main-navBar-navBarLink > span { + font-size: 14px; + font-weight: 400; + letter-spacing: normal; + line-height: 20px; + text-transform: none; +} + .main-likedSongsButton-likedSongsIcon, .main-yourEpisodesButton-yourEpisodesIcon, .main-createPlaylistButton-createPlaylistIcon { @@ -1016,22 +1031,35 @@ span.main-userWidget-displayName, padding: 0px 8px; } -.main-navBar-navBar, -.main-rootlist-wrapper > div:nth-child(2), -.main-navBar-entryPoints { +.main-navBar-navBar .main-rootlist-wrapper > div:nth-child(2), +.main-navBar-entryPoints, +#spicetify-show-list, +.main-rootlist-rootlistContent .os-content { display: flex; flex-direction: column; gap: 5px; } +#spicetify-show-list:empty { + display: none; +} + .main-rootlist-wrapper > div:nth-child(2) > li img, .main-navBar-navBarLink > .icon { z-index: 100; } +.main-collectionLinkButton-collectionLinkButton, +.main-createPlaylistButton-button { + position: relative; +} + .main-navBar-navBarItem:hover::before, .main-rootlist-rootlistItem:hover::before, -.main-rootlist-rootlistItemLinkActive::before { +.main-rootlist-rootlistItemLinkActive::before, +.main-collectionLinkButton-collectionLinkButton:hover::before, +.main-collectionLinkButton-selected::before, +.main-createPlaylistButton-button:hover::before { content: ""; position: absolute; inset: 0px; @@ -1040,7 +1068,8 @@ span.main-userWidget-displayName, pointer-events: none; } -.main-navBar-navBarLinkActive { +.main-navBar-navBarLinkActive, +.main-collectionLinkButton-selected { border-radius: var(--image-radius); background-color: rgba(var(--spice-rgb-main), 0.4); } @@ -1059,7 +1088,7 @@ div.GlueDropTarget.personal-library >* { } div.GlueDropTarget.personal-library >*.active { - background: var(--spice-button); + background: transparent; } /** Big cover, small cover */ @@ -1128,9 +1157,19 @@ html.right-expanded-cover.buddyfeed-visible .main-coverSlotExpanded-container { border-radius: 5px; } +.main-buttons-button { + color: var(--spice-main); +} + .main-dropDown-dropDown, .x-sortBox-sortDropdown { - background-color: rgba(var(--spice-rgb-selected-row), .1) !important; + background-color: rgba(var(--spice-rgb-selected-row), .4) !important; + color: var(--spice-subtext); +} + +.main-dropDown-dropDown:hover, +.x-sortBox-sortDropdown:hover { + background-color: rgba(var(--spice-rgb-selected-row), .6) !important; } .connect-device-list-item:focus, From e161628aeac19a1e32ad10073d992a13312fee22 Mon Sep 17 00:00:00 2001 From: Send_Nukez Date: Fri, 8 Oct 2021 06:38:29 +0200 Subject: [PATCH 08/13] fix update button oopsie and set version correctly --- dribbblish-dynamic.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dribbblish-dynamic.js b/dribbblish-dynamic.js index 2571c34..78d86f9 100644 --- a/dribbblish-dynamic.js +++ b/dribbblish-dynamic.js @@ -1,4 +1,4 @@ -let current = '2.3' +let current = '2.4.1' /* css is injected so this works with untouched user.css from Dribbblish */ /* dark theme */ @@ -328,7 +328,7 @@ hookCoverChange(false); upd.innerText = `Theme UPD v${data.tag_name} avail.` upd.classList.add("ellipsis-one-line", "main-type-finale") upd.setAttribute("title", `Changes: ${data.name}`) - upd.style.setProperty("color", "var(--spice-main)"); + upd.style.setProperty("color", "var(--spice-button-active)"); document.querySelector(".main-userWidget-box").append(upd) document.querySelector(".main-userWidget-box").classList.add("update-avail") new Spicetify.Menu.Item("Update Dribbblish", false, () => window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme#install", "_blank")).register(); From d08995ec5cf6b9a05c8789e1c854cfd07773f142 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 8 Oct 2021 13:32:16 +0200 Subject: [PATCH 09/13] update readme to better show how to update the theme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6023831..5b233cb 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Right click at folder and choose images for your playlist folder. Every image fo ### Left/Right expanded cover In profile menu, toggle option "Right expanded cover" to change expaned current track cover image to left or right side, whereever you prefer. -## Install +## Install / Update Make sure you are using spicetify >= v2.6.0 and Spotify >= v1.1.67. Run these commands: From a28f106433542692bcd595c4c1574adc94724a42 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 8 Oct 2021 13:33:07 +0200 Subject: [PATCH 10/13] update the update link --- dribbblish-dynamic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dribbblish-dynamic.js b/dribbblish-dynamic.js index 78d86f9..ccfc4ec 100644 --- a/dribbblish-dynamic.js +++ b/dribbblish-dynamic.js @@ -331,7 +331,7 @@ hookCoverChange(false); upd.style.setProperty("color", "var(--spice-button-active)"); document.querySelector(".main-userWidget-box").append(upd) document.querySelector(".main-userWidget-box").classList.add("update-avail") - new Spicetify.Menu.Item("Update Dribbblish", false, () => window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme#install", "_blank")).register(); + new Spicetify.Menu.Item("Update Dribbblish", false, () => window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme/blob/main/README.md#install--update", "_blank")).register(); } }).catch(err => { // Do something for an error here From 81e49efbc56679ccbd64fa5ad7934e796f98a463 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oscar=20Sj=C3=B6stedt?= Date: Fri, 8 Oct 2021 13:25:51 +0100 Subject: [PATCH 11/13] Update to 2.4 - Changed config element to a slider, that is now declared in dribbblish-dynamic.js. - Removed log statement. - Added background-image transition. --- dribbblish-dynamic.js | 21 ++++++++++++++++++++- dribbblish.js | 17 ----------------- 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/dribbblish-dynamic.js b/dribbblish-dynamic.js index 94e98f1..1e7e706 100644 --- a/dribbblish-dynamic.js +++ b/dribbblish-dynamic.js @@ -71,6 +71,25 @@ document.styleSheets[0].insertRule(` color: var(--spice-sidebar-text) !important; }`) +/* Config settings */ + +DribbblishShared.config.register({ + type: "slider", + data: { + "min": 0, + "max": 10, + "step": 0.1, + "suffix": "s" + }, + key: "fadeDuration", + name: "Color Fade Duration", + description: "Select the duration of the color fading transition", + defaultValue: 0.5, + onChange: (val) => { + document.documentElement.style.setProperty("--song-transition-speed", val+"s"); + } +}); + /* js */ function getAlbumInfo(uri) { return Spicetify.CosmosAsync.get(`hm://album/v1/album-app/album/${uri}/desktop`) @@ -258,7 +277,6 @@ function updateColors(textColHex, sideColHex, animate=false) { update(rgbToHex(currentC1), rgbToHex(currentC2)); - console.log(elapsed+">"+duration+"->"+(elapsed>duration)) if (elapsed>duration){ clearInterval(colorFadeInterval) } }, interval); @@ -409,6 +427,7 @@ document.styleSheets[0].insertRule(` will-change: transform; opacity: calc(0.07 + 0.03 * var(--is_light, 0)); z-index: +3; + transition: background-image var(--song-transition-speed) linear; }`) document.documentElement.style.setProperty('--warning_message', ' '); diff --git a/dribbblish.js b/dribbblish.js index 2491356..631d465 100644 --- a/dribbblish.js +++ b/dribbblish.js @@ -258,23 +258,6 @@ DribbblishShared.config.register({ } }); -DribbblishShared.config.register({ - type: "slider", - data: { - "min": 0, - "max": 10, - "step": 0.1, - "suffix": "s" - }, - key: "fadeDuration", - name: "Color Fade Duration", - description: "Select the duration of the color fading transition", - defaultValue: 0.5, - onChange: (val) => { - document.documentElement.style.setProperty("--song-transition-speed", val+"s"); - } -}); - waitForElement(["#main"], () => { DribbblishShared.config.register({ type: "select", From 6c925807b5e0e1df57a7390bb32614016a42de41 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 8 Oct 2021 14:42:09 +0200 Subject: [PATCH 12/13] 2.4.2 --- dribbblish-dynamic.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dribbblish-dynamic.js b/dribbblish-dynamic.js index 1e7e706..303fa9f 100644 --- a/dribbblish-dynamic.js +++ b/dribbblish-dynamic.js @@ -1,4 +1,4 @@ -let current = '2.4.1' +let current = '2.4.2' /* css is injected so this works with untouched user.css from Dribbblish */ /* dark theme */ From cf2327d2717a272e6a747921fba695a6dcb0a7e4 Mon Sep 17 00:00:00 2001 From: Send_Nukez Date: Fri, 8 Oct 2021 14:55:46 +0200 Subject: [PATCH 13/13] fix for playlist names being invisible (#58) --- dribbblish-dynamic.js | 2 +- user.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dribbblish-dynamic.js b/dribbblish-dynamic.js index 303fa9f..17fad56 100644 --- a/dribbblish-dynamic.js +++ b/dribbblish-dynamic.js @@ -1,4 +1,4 @@ -let current = '2.4.2' +let current = '2.4.3' /* css is injected so this works with untouched user.css from Dribbblish */ /* dark theme */ diff --git a/user.css b/user.css index 2d9d95c..6625a15 100644 --- a/user.css +++ b/user.css @@ -1158,7 +1158,7 @@ html.right-expanded-cover.buddyfeed-visible .main-coverSlotExpanded-container { border-radius: 5px; } -.main-buttons-button { +.main-buttons-button:not(.main-entityHeader-titleButton) { color: var(--spice-main); }