mirror of
https://github.com/danbulant/dribbblish-dynamic-theme
synced 2026-06-09 17:53:02 +00:00
add basic event functionality and a loader at startup
This commit is contained in:
parent
83b2801a36
commit
f0a562f70a
11 changed files with 805 additions and 610 deletions
|
|
@ -1,3 +1,6 @@
|
||||||
|
Added:
|
||||||
|
- A spinning loader at startup while spotify is not ready
|
||||||
|
|
||||||
Fixed:
|
Fixed:
|
||||||
- Checking for update every 10 Minutes not working
|
- Checking for update every 10 Minutes not working
|
||||||
- Background album art is cut off (#116)
|
- Background album art is cut off (#116)
|
||||||
|
|
|
||||||
68
src/js/Dribbblish.js
Normal file
68
src/js/Dribbblish.js
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
import ConfigMenu from "./ConfigMenu";
|
||||||
|
import Info from "./Info";
|
||||||
|
import Loader from "./Loader";
|
||||||
|
|
||||||
|
export default class Dribbblish {
|
||||||
|
/**
|
||||||
|
* @typedef {"ready"} Event
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @callback listener
|
||||||
|
* @param {any} [data]
|
||||||
|
* @returns {void}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @type {ConfigMenu} */
|
||||||
|
config;
|
||||||
|
|
||||||
|
/** @type {Info} */
|
||||||
|
info;
|
||||||
|
|
||||||
|
/** @type {Loader} */
|
||||||
|
loader;
|
||||||
|
|
||||||
|
/** @type {Object.<string, listener[]>} */
|
||||||
|
#listeners = {};
|
||||||
|
|
||||||
|
/** @type {Boolean} */
|
||||||
|
#ready = false;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.config = new ConfigMenu();
|
||||||
|
this.info = new Info();
|
||||||
|
this.loader = new Loader();
|
||||||
|
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
if (document.querySelector("#main") == null || Spicetify?.showNotification == undefined || !this.info.isReady()) return;
|
||||||
|
this.#ready = true;
|
||||||
|
this.emit("ready");
|
||||||
|
clearInterval(interval);
|
||||||
|
}, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Event} event
|
||||||
|
* @param {any} data
|
||||||
|
*/
|
||||||
|
emit(event, data) {
|
||||||
|
this.#listeners[event]?.forEach((listener) => listener(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Event} event
|
||||||
|
* @param {listener} listener
|
||||||
|
*/
|
||||||
|
on(event, listener) {
|
||||||
|
this.#listeners[event] = [...(this.#listeners[event] ?? []), listener];
|
||||||
|
if (event == "ready" && this.#ready) listener();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Event} event
|
||||||
|
* @param {listener} listener
|
||||||
|
*/
|
||||||
|
off(event, listener) {
|
||||||
|
this.#listeners = this.#listeners[event].filter((f) => f != listener);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -43,6 +43,10 @@ export default class Info {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isReady() {
|
||||||
|
return this.#ready;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {String} key
|
* @param {String} key
|
||||||
* @param {DribbblishInfo} info
|
* @param {DribbblishInfo} info
|
||||||
|
|
|
||||||
25
src/js/Loader.js
Normal file
25
src/js/Loader.js
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
export default class Loader {
|
||||||
|
/** @type {HTMLDivElement} */
|
||||||
|
#container;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
this.#container = document.createElement("div");
|
||||||
|
this.#container.id = "dribbblish-loader";
|
||||||
|
this.#container.innerHTML = `
|
||||||
|
<svg width="65px" height="65px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
|
||||||
|
</svg>
|
||||||
|
`;
|
||||||
|
|
||||||
|
document.body.appendChild(this.#container);
|
||||||
|
}
|
||||||
|
|
||||||
|
show(text) {
|
||||||
|
this.#container.setAttribute("text", text ?? "");
|
||||||
|
this.#container.setAttribute("active", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.#container.removeAttribute("active");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -60,3 +60,17 @@ export function htmlToNode(htmlStr) {
|
||||||
div.innerHTML = htmlStr.trim();
|
div.innerHTML = htmlStr.trim();
|
||||||
return div.firstChild;
|
return div.firstChild;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getRandomArbitrary(min, max) {
|
||||||
|
return Math.random() * (max - min) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getRandomInt(min, max) {
|
||||||
|
min = Math.ceil(min);
|
||||||
|
max = Math.floor(max);
|
||||||
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function randomFromArray(arr) {
|
||||||
|
return arr[Math.floor(Math.random() * arr.length)];
|
||||||
|
}
|
||||||
|
|
|
||||||
166
src/js/main.js
166
src/js/main.js
|
|
@ -4,9 +4,8 @@ import chroma from "chroma-js";
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
import moment from "moment";
|
import moment from "moment";
|
||||||
|
|
||||||
import { waitForElement, copyToClipboard, capitalizeFirstLetter, getClosestToNum } from "./Util";
|
import { waitForElement, copyToClipboard, capitalizeFirstLetter, getClosestToNum, randomFromArray } from "./Util";
|
||||||
import ConfigMenu from "./ConfigMenu";
|
import { default as _Dribbblish } from "./Dribbblish";
|
||||||
import Info from "./Info";
|
|
||||||
import "./Folders";
|
import "./Folders";
|
||||||
|
|
||||||
import iconArrowDown from "icon/arrow-down";
|
import iconArrowDown from "icon/arrow-down";
|
||||||
|
|
@ -14,15 +13,20 @@ import iconCode from "icon/code";
|
||||||
import iconWifiSlash from "icon/wifi-slash";
|
import iconWifiSlash from "icon/wifi-slash";
|
||||||
import iconCog from "icon/cog";
|
import iconCog from "icon/cog";
|
||||||
|
|
||||||
const Dribbblish = {
|
|
||||||
config: new ConfigMenu(),
|
|
||||||
info: new Info()
|
|
||||||
};
|
|
||||||
const colorThief = new ColorThief();
|
|
||||||
// To expose to external scripts
|
// To expose to external scripts
|
||||||
|
const Dribbblish = new _Dribbblish();
|
||||||
window.Dribbblish = Dribbblish;
|
window.Dribbblish = Dribbblish;
|
||||||
|
|
||||||
Dribbblish.config.register({
|
const colorThief = new ColorThief();
|
||||||
|
|
||||||
|
// In the future maybe have some useful info here
|
||||||
|
const loadingHints = ["Getting things ready...", "Starting up...", "Just one moment..."];
|
||||||
|
Dribbblish.loader.show(randomFromArray(loadingHints));
|
||||||
|
|
||||||
|
Dribbblish.on("ready", () => {
|
||||||
|
setTimeout(() => Dribbblish.loader.hide(), 3000);
|
||||||
|
|
||||||
|
Dribbblish.config.register({
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
key: "openSettingsInfo",
|
key: "openSettingsInfo",
|
||||||
name: "Open Settings Icon",
|
name: "Open Settings Icon",
|
||||||
|
|
@ -39,18 +43,18 @@ Dribbblish.config.register({
|
||||||
tooltip: "Open Dribbblish Settings",
|
tooltip: "Open Dribbblish Settings",
|
||||||
onClick: () => Dribbblish.config.open()
|
onClick: () => Dribbblish.config.open()
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
key: "rightBigCover",
|
key: "rightBigCover",
|
||||||
name: "Right expanded cover",
|
name: "Right expanded cover",
|
||||||
description: "Have the expanded cover Image on the right instead of on the left",
|
description: "Have the expanded cover Image on the right instead of on the left",
|
||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
onChange: (val) => $("html").toggleClass("right-expanded-cover", val)
|
onChange: (val) => $("html").toggleClass("right-expanded-cover", val)
|
||||||
});
|
});
|
||||||
|
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
area: "Sidebar",
|
area: "Sidebar",
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
key: "roundSidebarIcons",
|
key: "roundSidebarIcons",
|
||||||
|
|
@ -58,9 +62,9 @@ Dribbblish.config.register({
|
||||||
description: "If the Sidebar Icons should be round instead of square",
|
description: "If the Sidebar Icons should be round instead of square",
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
onChange: (val) => $("html").css("--sidebar-icons-border-radius", val ? "50vh" : "var(--image-radius)")
|
onChange: (val) => $("html").css("--sidebar-icons-border-radius", val ? "50vh" : "var(--image-radius)")
|
||||||
});
|
});
|
||||||
|
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
area: "Animations & Transitions",
|
area: "Animations & Transitions",
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
key: "sidebarHoverAnimation",
|
key: "sidebarHoverAnimation",
|
||||||
|
|
@ -68,9 +72,9 @@ Dribbblish.config.register({
|
||||||
description: "If the Sidebar Icons should have an animated background on hover",
|
description: "If the Sidebar Icons should have an animated background on hover",
|
||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
onChange: (val) => $("html").css("--sidebar-icons-hover-animation", val ? "1" : "0")
|
onChange: (val) => $("html").css("--sidebar-icons-hover-animation", val ? "1" : "0")
|
||||||
});
|
});
|
||||||
|
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
area: "Sidebar",
|
area: "Sidebar",
|
||||||
type: "number",
|
type: "number",
|
||||||
key: "sidebarGapLeft",
|
key: "sidebarGapLeft",
|
||||||
|
|
@ -81,9 +85,9 @@ Dribbblish.config.register({
|
||||||
min: 0
|
min: 0
|
||||||
},
|
},
|
||||||
onChange: (val) => $("html").css("--sidebar-gap-left", `${val}px`)
|
onChange: (val) => $("html").css("--sidebar-gap-left", `${val}px`)
|
||||||
});
|
});
|
||||||
|
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
area: "Sidebar",
|
area: "Sidebar",
|
||||||
type: "number",
|
type: "number",
|
||||||
key: "sidebarGapRight",
|
key: "sidebarGapRight",
|
||||||
|
|
@ -94,9 +98,9 @@ Dribbblish.config.register({
|
||||||
min: 0
|
min: 0
|
||||||
},
|
},
|
||||||
onChange: (val) => $("html").css("--sidebar-gap-right", `${val}px`)
|
onChange: (val) => $("html").css("--sidebar-gap-right", `${val}px`)
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement([".main-nowPlayingBar-container"], ([container]) => {
|
waitForElement([".main-nowPlayingBar-container"], ([container]) => {
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
area: "Playbar",
|
area: "Playbar",
|
||||||
type: "checkbox",
|
type: "checkbox",
|
||||||
|
|
@ -106,9 +110,8 @@ waitForElement([".main-nowPlayingBar-container"], ([container]) => {
|
||||||
defaultValue: true,
|
defaultValue: true,
|
||||||
onChange: (val) => $(container).toggleClass("with-shadow", val)
|
onChange: (val) => $(container).toggleClass("with-shadow", val)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement(["#main"], () => {
|
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
type: "select",
|
type: "select",
|
||||||
data: { none: "None", "none-padding": "None (With Top Padding)", solid: "Solid", transparent: "Transparent" },
|
data: { none: "None", "none-padding": "None (With Top Padding)", solid: "Solid", transparent: "Transparent" },
|
||||||
|
|
@ -152,9 +155,8 @@ waitForElement(["#main"], () => {
|
||||||
defaultValue: false,
|
defaultValue: false,
|
||||||
onChange: (val) => $("#main").attr("hide-ads", val)
|
onChange: (val) => $("#main").attr("hide-ads", val)
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
waitForElement([".main-rootlist-rootlist", ".main-rootlist-wrapper > :nth-child(2) > :first-child", "#spicetify-show-list"], ([rootlist]) => {
|
waitForElement([".main-rootlist-rootlist", ".main-rootlist-wrapper > :nth-child(2) > :first-child", "#spicetify-show-list"], ([rootlist]) => {
|
||||||
function checkSidebarPlaylistScroll() {
|
function checkSidebarPlaylistScroll() {
|
||||||
const topDist = rootlist.getBoundingClientRect().top - document.querySelector("#spicetify-show-list:not(:empty), .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;
|
const bottomDist = document.querySelector(".main-rootlist-wrapper > :nth-child(2) > :last-child").getBoundingClientRect().bottom - rootlist.getBoundingClientRect().bottom;
|
||||||
|
|
@ -183,15 +185,15 @@ waitForElement([".main-rootlist-rootlist", ".main-rootlist-wrapper > :nth-child(
|
||||||
c++;
|
c++;
|
||||||
}, 50);
|
}, 50);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement([".Root__main-view"], ([mainView]) => {
|
waitForElement([".Root__main-view"], ([mainView]) => {
|
||||||
const shadow = document.createElement("div");
|
const shadow = document.createElement("div");
|
||||||
shadow.id = "dribbblish-back-shadow";
|
shadow.id = "dribbblish-back-shadow";
|
||||||
mainView.prepend(shadow);
|
mainView.prepend(shadow);
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement([".Root__nav-bar .LayoutResizer__input, .Root__nav-bar .LayoutResizer__resize-bar input"], ([resizer]) => {
|
waitForElement([".Root__nav-bar .LayoutResizer__input, .Root__nav-bar .LayoutResizer__resize-bar input"], ([resizer]) => {
|
||||||
const observer = new MutationObserver(updateVariable);
|
const observer = new MutationObserver(updateVariable);
|
||||||
observer.observe(resizer, { attributes: true, attributeFilter: ["value"] });
|
observer.observe(resizer, { attributes: true, attributeFilter: ["value"] });
|
||||||
function updateVariable() {
|
function updateVariable() {
|
||||||
|
|
@ -201,9 +203,9 @@ waitForElement([".Root__nav-bar .LayoutResizer__input, .Root__nav-bar .LayoutRes
|
||||||
$("html").css("--sidebar-width", `${value}px`);
|
$("html").css("--sidebar-width", `${value}px`);
|
||||||
}
|
}
|
||||||
updateVariable();
|
updateVariable();
|
||||||
});
|
});
|
||||||
|
|
||||||
waitForElement([".Root__main-view .os-resize-observer-host"], ([resizeHost]) => {
|
waitForElement([".Root__main-view .os-resize-observer-host"], ([resizeHost]) => {
|
||||||
const observer = new ResizeObserver(updateVariable);
|
const observer = new ResizeObserver(updateVariable);
|
||||||
observer.observe(resizeHost);
|
observer.observe(resizeHost);
|
||||||
function updateVariable([event]) {
|
function updateVariable([event]) {
|
||||||
|
|
@ -212,9 +214,9 @@ waitForElement([".Root__main-view .os-resize-observer-host"], ([resizeHost]) =>
|
||||||
$("html").toggleClass("minimal-player", event.contentRect.width < 700);
|
$("html").toggleClass("minimal-player", event.contentRect.width < 700);
|
||||||
$("html").toggleClass("extra-minimal-player", event.contentRect.width < 550);
|
$("html").toggleClass("extra-minimal-player", event.contentRect.width < 550);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
(function Dribbblish() {
|
(function Dribbblish() {
|
||||||
const progBar = document.querySelector(".playback-bar");
|
const progBar = document.querySelector(".playback-bar");
|
||||||
const root = document.querySelector(".Root");
|
const root = document.querySelector(".Root");
|
||||||
|
|
||||||
|
|
@ -253,11 +255,11 @@ waitForElement([".Root__main-view .os-resize-observer-host"], ([resizeHost]) =>
|
||||||
root.classList.remove("is-connectBarVisible");
|
root.classList.remove("is-connectBarVisible");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
})();
|
})();
|
||||||
|
|
||||||
/* Config settings */
|
/* Config settings */
|
||||||
|
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
area: "Animations & Transitions",
|
area: "Animations & Transitions",
|
||||||
type: "slider",
|
type: "slider",
|
||||||
key: "fadeDuration",
|
key: "fadeDuration",
|
||||||
|
|
@ -271,10 +273,8 @@ Dribbblish.config.register({
|
||||||
suffix: "s"
|
suffix: "s"
|
||||||
},
|
},
|
||||||
onChange: (val) => $("html").css("--song-transition-speed", `${val}s`)
|
onChange: (val) => $("html").css("--song-transition-speed", `${val}s`)
|
||||||
});
|
});
|
||||||
|
|
||||||
// waitForElement because Spicetify is not initialized at startup
|
|
||||||
waitForElement(["#main"], () => {
|
|
||||||
Dribbblish.config.registerArea({ name: "About", order: 999 });
|
Dribbblish.config.registerArea({ name: "About", order: 999 });
|
||||||
|
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
|
|
@ -380,20 +380,19 @@ waitForElement(["#main"], () => {
|
||||||
data: "Open",
|
data: "Open",
|
||||||
onChange: () => window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme/releases", "_blank")
|
onChange: () => window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme/releases", "_blank")
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
/* js */
|
/* js */
|
||||||
async function getAlbumRelease(uri) {
|
async function getAlbumRelease(uri) {
|
||||||
const info = await Spicetify.CosmosAsync.get(`hm://album/v1/album-app/album/${uri}/desktop`);
|
const info = await Spicetify.CosmosAsync.get(`hm://album/v1/album-app/album/${uri}/desktop`);
|
||||||
return { year: info.year, month: (info.month ?? 1) - 1, day: info.day ?? 1 };
|
return { year: info.year, month: (info.month ?? 1) - 1, day: info.day ?? 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
function isLight(hex) {
|
function isLight(hex) {
|
||||||
return chroma(hex).luminance() > 0.5;
|
return chroma(hex).luminance() > 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
// From: https://stackoverflow.com/a/13763063/12126879
|
// From: https://stackoverflow.com/a/13763063/12126879
|
||||||
function getImageLightness(img) {
|
function getImageLightness(img) {
|
||||||
var colorSum = 0;
|
var colorSum = 0;
|
||||||
var canvas = document.createElement("canvas");
|
var canvas = document.createElement("canvas");
|
||||||
canvas.width = img.width;
|
canvas.width = img.width;
|
||||||
|
|
@ -417,17 +416,17 @@ function getImageLightness(img) {
|
||||||
|
|
||||||
var brightness = Math.floor(colorSum / (img.width * img.height));
|
var brightness = Math.floor(colorSum / (img.width * img.height));
|
||||||
return brightness;
|
return brightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse to hex because "--spice-sidebar" is `rgb()`
|
// parse to hex because "--spice-sidebar" is `rgb()`
|
||||||
let textColorBg = chroma($("html").css("--spice-main")).hex();
|
let textColorBg = chroma($("html").css("--spice-main")).hex();
|
||||||
|
|
||||||
function setRootColor(name, color) {
|
function setRootColor(name, color) {
|
||||||
$("html").css(`--spice-${name}`, chroma(color).hex());
|
$("html").css(`--spice-${name}`, chroma(color).hex());
|
||||||
$("html").css(`--spice-rgb-${name}`, chroma(color).rgb().join(","));
|
$("html").css(`--spice-rgb-${name}`, chroma(color).rgb().join(","));
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleDark(setDark) {
|
function toggleDark(setDark) {
|
||||||
if (setDark === undefined) setDark = isLight(textColorBg);
|
if (setDark === undefined) setDark = isLight(textColorBg);
|
||||||
|
|
||||||
$("html").css("--is_light", setDark ? 0 : 1);
|
$("html").css("--is_light", setDark ? 0 : 1);
|
||||||
|
|
@ -440,9 +439,9 @@ function toggleDark(setDark) {
|
||||||
setRootColor("notification", setDark ? "#303030" : "#DDDDDD");
|
setRootColor("notification", setDark ? "#303030" : "#DDDDDD");
|
||||||
|
|
||||||
updateColors(false);
|
updateColors(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkDarkLightMode() {
|
function checkDarkLightMode() {
|
||||||
const theme = Dribbblish.config.get("theme");
|
const theme = Dribbblish.config.get("theme");
|
||||||
if (theme == "time") {
|
if (theme == "time") {
|
||||||
const start = 60 * parseInt(Dribbblish.config.get("darkModeOnTime").split(":")[0]) + parseInt(Dribbblish.config.get("darkModeOnTime").split(":")[1]);
|
const start = 60 * parseInt(Dribbblish.config.get("darkModeOnTime").split(":")[0]) + parseInt(Dribbblish.config.get("darkModeOnTime").split(":")[1]);
|
||||||
|
|
@ -456,12 +455,12 @@ function checkDarkLightMode() {
|
||||||
else dark = start <= time && time < end;
|
else dark = start <= time && time < end;
|
||||||
toggleDark(dark);
|
toggleDark(dark);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run every Minute to check time and set dark / light mode
|
// Run every Minute to check time and set dark / light mode
|
||||||
setInterval(checkDarkLightMode, 60000);
|
setInterval(checkDarkLightMode, 60000);
|
||||||
|
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
area: "Theme",
|
area: "Theme",
|
||||||
type: "select",
|
type: "select",
|
||||||
key: "colorSelectionAlgorithm",
|
key: "colorSelectionAlgorithm",
|
||||||
|
|
@ -537,12 +536,13 @@ Dribbblish.config.register({
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
area: "Theme",
|
area: "Theme",
|
||||||
type: "select",
|
type: "select",
|
||||||
data: { dark: "Dark", light: "Light", time: "Based on Time" },
|
data: { dark: "Dark", light: "Light", time: "Based on Time" },
|
||||||
|
order: -1,
|
||||||
key: "theme",
|
key: "theme",
|
||||||
name: "Theme",
|
name: "Theme",
|
||||||
description: "Select Dark / Bright mode",
|
description: "Select Dark / Bright mode",
|
||||||
|
|
@ -584,9 +584,9 @@ Dribbblish.config.register({
|
||||||
onChange: checkDarkLightMode
|
onChange: checkDarkLightMode
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
|
|
||||||
function updateColors(checkDarkMode = true, sideColHex) {
|
function updateColors(checkDarkMode = true, sideColHex) {
|
||||||
if (sideColHex == undefined) return registerCoverListener();
|
if (sideColHex == undefined) return registerCoverListener();
|
||||||
|
|
||||||
let isLightBg = isLight(textColorBg);
|
let isLightBg = isLight(textColorBg);
|
||||||
|
|
@ -616,9 +616,9 @@ function updateColors(checkDarkMode = true, sideColHex) {
|
||||||
setRootColor("sidebar-text", isLight(sideColHex) ? "#000000" : "#FFFFFF");
|
setRootColor("sidebar-text", isLight(sideColHex) ? "#000000" : "#FFFFFF");
|
||||||
|
|
||||||
if (checkDarkMode) checkDarkLightMode([textColHex, sideColHex]);
|
if (checkDarkMode) checkDarkLightMode([textColHex, sideColHex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function songchange() {
|
async function songchange() {
|
||||||
if (!document.querySelector(".main-trackInfo-container")) return setTimeout(songchange, 300);
|
if (!document.querySelector(".main-trackInfo-container")) return setTimeout(songchange, 300);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
@ -674,11 +674,12 @@ async function songchange() {
|
||||||
|
|
||||||
$("html").css("--image-url", `url("${bgImage}")`);
|
$("html").css("--image-url", `url("${bgImage}")`);
|
||||||
registerCoverListener();
|
registerCoverListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
Spicetify.Player.addEventListener("songchange", songchange);
|
Spicetify.Player.addEventListener("songchange", songchange);
|
||||||
|
songchange();
|
||||||
|
|
||||||
async function pickCoverColor(img) {
|
async function pickCoverColor(img) {
|
||||||
if (!img.currentSrc.startsWith("spotify:")) return;
|
if (!img.currentSrc.startsWith("spotify:")) return;
|
||||||
|
|
||||||
$("html").css("--image-brightness", getImageLightness(img) / 255);
|
$("html").css("--image-brightness", getImageLightness(img) / 255);
|
||||||
|
|
@ -718,10 +719,10 @@ async function pickCoverColor(img) {
|
||||||
}
|
}
|
||||||
|
|
||||||
updateColors(false, color);
|
updateColors(false, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
var coverListener;
|
var coverListener;
|
||||||
function registerCoverListener() {
|
function registerCoverListener() {
|
||||||
const img = document.querySelector(".main-image-image.cover-art-image");
|
const img = document.querySelector(".main-image-image.cover-art-image");
|
||||||
if (!img) return setTimeout(registerCoverListener, 250); // Check if image exists
|
if (!img) return setTimeout(registerCoverListener, 250); // Check if image exists
|
||||||
if (!img.complete) return img.addEventListener("load", registerCoverListener); // Check if image is loaded
|
if (!img.complete) return img.addEventListener("load", registerCoverListener); // Check if image is loaded
|
||||||
|
|
@ -741,11 +742,11 @@ function registerCoverListener() {
|
||||||
attributes: true,
|
attributes: true,
|
||||||
attributeFilter: ["src"]
|
attributeFilter: ["src"]
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
registerCoverListener();
|
registerCoverListener();
|
||||||
|
|
||||||
// Check latest release every 10m
|
// Check latest release every 10m
|
||||||
function checkForUpdate() {
|
function checkForUpdate() {
|
||||||
fetch("https://api.github.com/repos/JulienMaille/dribbblish-dynamic-theme/releases/latest")
|
fetch("https://api.github.com/repos/JulienMaille/dribbblish-dynamic-theme/releases/latest")
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
|
|
@ -754,13 +755,13 @@ function checkForUpdate() {
|
||||||
Dribbblish.info.set("dev", isDev ? { tooltip: "Dev build", icon: iconCode } : null);
|
Dribbblish.info.set("dev", isDev ? { tooltip: "Dev build", icon: iconCode } : null);
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
setInterval(checkForUpdate, 10 * 60 * 1000);
|
setInterval(checkForUpdate, 10 * 60 * 1000);
|
||||||
checkForUpdate();
|
checkForUpdate();
|
||||||
|
|
||||||
// Show "Offline info"
|
// Show "Offline info"
|
||||||
window.addEventListener("offline", () =>
|
window.addEventListener("offline", () =>
|
||||||
Dribbblish.info.set("offline", {
|
Dribbblish.info.set("offline", {
|
||||||
tooltip: "Offline",
|
tooltip: "Offline",
|
||||||
icon: iconWifiSlash,
|
icon: iconWifiSlash,
|
||||||
|
|
@ -770,7 +771,8 @@ window.addEventListener("offline", () =>
|
||||||
bg: "#ff2323"
|
bg: "#ff2323"
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
window.addEventListener("online", () => Dribbblish.info.remove("offline"));
|
window.addEventListener("online", () => Dribbblish.info.remove("offline"));
|
||||||
|
});
|
||||||
|
|
||||||
$("html").css("--warning_message", " ");
|
$("html").css("--warning_message", " ");
|
||||||
|
|
|
||||||
|
|
@ -27,12 +27,12 @@
|
||||||
backdrop-filter: blur(3px);
|
backdrop-filter: blur(3px);
|
||||||
padding: 20px 15px;
|
padding: 20px 15px;
|
||||||
border-radius: var(--main-corner-radius);
|
border-radius: var(--main-corner-radius);
|
||||||
box-shadow: 0 0 10px 3px #0000003b;
|
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 5px;
|
gap: 5px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
@include spiceShadow();
|
||||||
|
|
||||||
.dribbblish-config-close {
|
.dribbblish-config-close {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
backdrop-filter: blur(10px);
|
backdrop-filter: blur(10px);
|
||||||
border-radius: var(--main-corner-radius);
|
border-radius: var(--main-corner-radius);
|
||||||
box-shadow: 0px 0px 8px spiceColor("subtext", 0.1, 0.1);
|
box-shadow: 0px 0px 8px spiceColor("subtext", 0.1, 0.1);
|
||||||
|
@include spiceShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-contextMenu-menuItem {
|
.main-contextMenu-menuItem {
|
||||||
|
|
|
||||||
73
src/styles/Loader.scss
Normal file
73
src/styles/Loader.scss
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
// From https://codepen.io/mrrocks/pen/EiplA
|
||||||
|
@use "sass:math";
|
||||||
|
|
||||||
|
$offset: 187;
|
||||||
|
$duration: 1.4s;
|
||||||
|
|
||||||
|
#dribbblish-loader {
|
||||||
|
z-index: 999999;
|
||||||
|
position: fixed;
|
||||||
|
inset: 0px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 1s ease-in;
|
||||||
|
|
||||||
|
&[active] {
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: all;
|
||||||
|
}
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
content: "";
|
||||||
|
position: absolute;
|
||||||
|
inset: 0px;
|
||||||
|
color: spiceColor("subtext");
|
||||||
|
background-color: spiceColor("main", 0.9, -0.1);
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
}
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: attr(text);
|
||||||
|
position: absolute;
|
||||||
|
bottom: 40%;
|
||||||
|
@include spiceFont("glue", 32px, "Bold");
|
||||||
|
}
|
||||||
|
|
||||||
|
svg {
|
||||||
|
animation: rotator $duration linear infinite;
|
||||||
|
|
||||||
|
circle {
|
||||||
|
stroke: spiceColor("sidebar");
|
||||||
|
stroke-dasharray: $offset;
|
||||||
|
stroke-dashoffset: 0;
|
||||||
|
transform-origin: center;
|
||||||
|
animation: dash $duration ease-in-out infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotator {
|
||||||
|
0% {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: rotate(270deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes dash {
|
||||||
|
0% {
|
||||||
|
stroke-dashoffset: $offset;
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
stroke-dashoffset: math.div($offset, 4);
|
||||||
|
transform: rotate(135deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
stroke-dashoffset: $offset;
|
||||||
|
transform: rotate(450deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,3 +2,7 @@
|
||||||
@function lightOffset($n, $offset) {
|
@function lightOffset($n, $offset) {
|
||||||
@return calc($n + $offset * var(--is_light));
|
@return calc($n + $offset * var(--is_light));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@mixin spiceShadow() {
|
||||||
|
box-shadow: 0px 0px 8px spiceColor("subtext", 0.1, 0.1);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
@import "NoAds";
|
@import "NoAds";
|
||||||
@import "Markdown";
|
@import "Markdown";
|
||||||
@import "Info";
|
@import "Info";
|
||||||
|
@import "Loader";
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--bar-height: 70px;
|
--bar-height: 70px;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue