change default folder & playlist image and refactor
|
|
@ -1,4 +1,8 @@
|
|||
Fixed:
|
||||
- Checking for update every 10 Minutes not working
|
||||
- Background album art is cut off (#116)
|
||||
- Tall context menus not scrollable (#114)
|
||||
- Tall context menus not scrollable (#114)
|
||||
- Default folder images not working
|
||||
|
||||
Improved:
|
||||
- Moved `Hide Ads` into `Main Settings`
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
"markdown-it-attrs": "^4.1.0",
|
||||
"markdown-it-bracketed-spans": "^1.0.1",
|
||||
"moment": "^2.29.1",
|
||||
"node-vibrant": "^3.1.6"
|
||||
"node-vibrant": "^3.1.6",
|
||||
"svgson": "^5.2.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="16" height="16">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512">
|
||||
<path fill="currentColor" d="M413.1 222.5l22.2 22.2c9.4 9.4 9.4 24.6 0 33.9L241 473c-9.4 9.4-24.6 9.4-33.9 0L12.7 278.6c-9.4-9.4-9.4-24.6 0-33.9l22.2-22.2c9.5-9.5 25-9.3 34.3.4L184 343.4V56c0-13.3 10.7-24 24-24h32c13.3 0 24 10.7 24 24v287.4l114.8-120.5c9.3-9.8 24.8-10 34.3-.4z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 383 B After Width: | Height: | Size: 360 B |
|
|
@ -1,3 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="16" height="16">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512">
|
||||
<path fill="currentColor" d="M278.9 511.5l-61-17.7c-6.4-1.8-10-8.5-8.2-14.9L346.2 8.7c1.8-6.4 8.5-10 14.9-8.2l61 17.7c6.4 1.8 10 8.5 8.2 14.9L293.8 503.3c-1.9 6.4-8.5 10.1-14.9 8.2zm-114-112.2l43.5-46.4c4.6-4.9 4.3-12.7-.8-17.2L117 256l90.6-79.7c5.1-4.5 5.5-12.3.8-17.2l-43.5-46.4c-4.5-4.8-12.1-5.1-17-.5L3.8 247.2c-5.1 4.7-5.1 12.8 0 17.5l144.1 135.1c4.9 4.6 12.5 4.4 17-.5zm327.2.6l144.1-135.1c5.1-4.7 5.1-12.8 0-17.5L492.1 112.1c-4.8-4.5-12.4-4.3-17 .5L431.6 159c-4.6 4.9-4.3 12.7.8 17.2L523 256l-90.6 79.7c-5.1 4.5-5.5 12.3-.8 17.2l43.5 46.4c4.5 4.9 12.1 5.1 17 .6z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 675 B After Width: | Height: | Size: 652 B |
|
|
@ -1,3 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16" height="16">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M487.4 315.7l-42.6-24.6c4.3-23.2 4.3-47 0-70.2l42.6-24.6c4.9-2.8 7.1-8.6 5.5-14-11.1-35.6-30-67.8-54.7-94.6-3.8-4.1-10-5.1-14.8-2.3L380.8 110c-17.9-15.4-38.5-27.3-60.8-35.1V25.8c0-5.6-3.9-10.5-9.4-11.7-36.7-8.2-74.3-7.8-109.2 0-5.5 1.2-9.4 6.1-9.4 11.7V75c-22.2 7.9-42.8 19.8-60.8 35.1L88.7 85.5c-4.9-2.8-11-1.9-14.8 2.3-24.7 26.7-43.6 58.9-54.7 94.6-1.7 5.4.6 11.2 5.5 14L67.3 221c-4.3 23.2-4.3 47 0 70.2l-42.6 24.6c-4.9 2.8-7.1 8.6-5.5 14 11.1 35.6 30 67.8 54.7 94.6 3.8 4.1 10 5.1 14.8 2.3l42.6-24.6c17.9 15.4 38.5 27.3 60.8 35.1v49.2c0 5.6 3.9 10.5 9.4 11.7 36.7 8.2 74.3 7.8 109.2 0 5.5-1.2 9.4-6.1 9.4-11.7v-49.2c22.2-7.9 42.8-19.8 60.8-35.1l42.6 24.6c4.9 2.8 11 1.9 14.8-2.3 24.7-26.7 43.6-58.9 54.7-94.6 1.5-5.5-.7-11.3-5.6-14.1zM256 336c-44.1 0-80-35.9-80-80s35.9-80 80-80 80 35.9 80 80-35.9 80-80 80z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 945 B After Width: | Height: | Size: 922 B |
3
src/icons/folder-open.light.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||||
<path fill="currentColor" d="M527.95 224H480v-48c0-26.51-21.49-48-48-48H272l-64-64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h385.057c28.068 0 54.135-14.733 68.599-38.84l67.453-112.464C588.24 264.812 565.285 224 527.95 224zM48 96h146.745l64 64H432c8.837 0 16 7.163 16 16v48H171.177c-28.068 0-54.135 14.733-68.599 38.84L32 380.47V112c0-8.837 7.163-16 16-16zm493.695 184.232l-67.479 112.464A47.997 47.997 0 0 1 433.057 416H44.823l82.017-136.696A48 48 0 0 1 168 256h359.975c12.437 0 20.119 13.568 13.72 24.232z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 600 B |
3
src/icons/folder-open.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512">
|
||||
<path fill="currentColor" d="M572.694 292.093L500.27 416.248A63.997 63.997 0 0 1 444.989 448H45.025c-18.523 0-30.064-20.093-20.731-36.093l72.424-124.155A64 64 0 0 1 152 256h399.964c18.523 0 30.064 20.093 20.73 36.093zM152 224h328v-48c0-26.51-21.49-48-48-48H272l-64-64H48C21.49 64 0 85.49 0 112v278.046l69.077-118.418C86.214 242.25 117.989 224 152 224z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 434 B |
3
src/icons/folder.light.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M194.74 96l54.63 54.63c6 6 14.14 9.37 22.63 9.37h192c8.84 0 16 7.16 16 16v224c0 8.84-7.16 16-16 16H48c-8.84 0-16-7.16-16-16V112c0-8.84 7.16-16 16-16h146.74M48 64C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V176c0-26.51-21.49-48-48-48H272l-54.63-54.63c-6-6-14.14-9.37-22.63-9.37H48z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 425 B |
3
src/icons/folder.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M464 128H272l-64-64H48C21.49 64 0 85.49 0 112v288c0 26.51 21.49 48 48 48h416c26.51 0 48-21.49 48-48V176c0-26.51-21.49-48-48-48z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 239 B |
3
src/icons/note.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
|
||||
<path fill="currentColor" d="M9 6.159v10.899A3.485 3.485 0 006.5 16C4.57 16 3 17.57 3 19.5S4.57 23 6.5 23s3.5-1.57 3.5-3.5V6.969L21 4.63v10.178a3.485 3.485 0 00-2.5-1.058c-1.93 0-3.5 1.57-3.5 3.5s1.57 3.5 3.5 3.5 3.5-1.57 3.5-3.5V3.395L9 6.159zM6.5 22C5.122 22 4 20.878 4 19.5S5.122 17 6.5 17 9 18.122 9 19.5 7.878 22 6.5 22zm12-2.25a2.503 2.503 0 01-2.5-2.5c0-1.379 1.122-2.5 2.5-2.5s2.5 1.121 2.5 2.5c0 1.378-1.122 2.5-2.5 2.5z"></path>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 510 B |
|
|
@ -1,3 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16" height="16">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<path fill="currentColor" d="M255.545 8c-66.269.119-126.438 26.233-170.86 68.685L48.971 40.971C33.851 25.851 8 36.559 8 57.941V192c0 13.255 10.745 24 24 24h134.059c21.382 0 32.09-25.851 16.971-40.971l-41.75-41.75c30.864-28.899 70.801-44.907 113.23-45.273 92.398-.798 170.283 73.977 169.484 169.442C423.236 348.009 349.816 424 256 424c-41.127 0-79.997-14.678-110.63-41.556-4.743-4.161-11.906-3.908-16.368.553L89.34 422.659c-4.872 4.872-4.631 12.815.482 17.433C133.798 479.813 192.074 504 256 504c136.966 0 247.999-111.033 248-247.998C504.001 119.193 392.354 7.755 255.545 8z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 679 B After Width: | Height: | Size: 656 B |
|
|
@ -1,3 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="16" height="16">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512">
|
||||
<path fill="currentColor" d="M5.09 154.87c-6.66 6.16-6.79 16.59-.35 22.97l34.24 33.96c6.14 6.09 16.02 6.23 22.4.38 6.99-6.4 14.31-12.22 21.65-18.01l-64.96-50.21c-4.3 3.71-8.79 7.04-12.98 10.91zm471.75 181.9l45.42-45.21c6.52-6.46 6.29-17.06-.57-23.17-64.94-57.74-148.91-82.66-230.34-74.98l-83.16-64.27c125.94-38.36 267.75-11.01 370.43 83.05 6.38 5.85 16.26 5.71 22.4-.38l34.24-33.96c6.44-6.39 6.3-16.82-.35-22.97C496.46 26.82 298.08-.76 133.42 71.35L45.47 3.37C38.49-2.05 28.43-.8 23.01 6.18L3.37 31.45C-2.05 38.42-.8 48.47 6.18 53.9l588.36 454.73c6.98 5.43 17.03 4.17 22.46-2.81l19.64-25.27c5.42-6.97 4.17-17.03-2.81-22.45L476.84 336.77zm-358.53-68.38c-6.86 6.1-7.08 16.7-.57 23.17l34.28 34.01c5.97 5.93 15.59 6.32 21.94.8 13.35-11.6 28.01-20.66 43.15-28.55l-68.36-52.83c-10.48 7.15-20.74 14.78-30.44 23.4zM256 416c0 35.35 28.65 64 64 64 31.91 0 58.15-23.42 62.99-53.98l-88.7-68.56C271.77 367.37 256 389.82 256 416z"></path>
|
||||
</svg>
|
||||
|
Before Width: | Height: | Size: 1,021 B After Width: | Height: | Size: 998 B |
|
|
@ -1,9 +1,8 @@
|
|||
import $ from "jquery";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import MarkdownItAttrs from "markdown-it-attrs";
|
||||
import MarkdownItBracketedSpans from "markdown-it-bracketed-spans";
|
||||
|
||||
import svgUndo from "svg/undo";
|
||||
import { renderMD } from "./Util";
|
||||
|
||||
import iconUndo from "icon/undo";
|
||||
|
||||
export default class ConfigMenu {
|
||||
/**
|
||||
|
|
@ -69,21 +68,10 @@ export default class ConfigMenu {
|
|||
/** @type {Spicetify.Menu.Item} */
|
||||
#configButton;
|
||||
|
||||
/** @type {MarkdownIt} */
|
||||
#md;
|
||||
|
||||
constructor() {
|
||||
this.#config = {};
|
||||
this.#configButton = new Spicetify.Menu.Item("Dribbblish Settings", false, () => this.open());
|
||||
this.#configButton.register();
|
||||
this.#md = MarkdownIt({
|
||||
html: true,
|
||||
breaks: true,
|
||||
linkify: true,
|
||||
typographer: true
|
||||
});
|
||||
this.#md.use(MarkdownItBracketedSpans);
|
||||
this.#md.use(MarkdownItAttrs);
|
||||
|
||||
const container = document.createElement("div");
|
||||
container.id = "dribbblish-config";
|
||||
|
|
@ -134,9 +122,9 @@ export default class ConfigMenu {
|
|||
<div class="dribbblish-config-item-header">
|
||||
<h2 class="x-settings-title main-type-cello" as="h2" empty="${options.name == null}">
|
||||
${options.name}
|
||||
${options.resetButton ? /* html */ `<button aria-label="Reset" class="dribbblish-config-item-reset main-trackCreditsModal-closeBtn">${svgUndo}</button>` : ""}
|
||||
${options.resetButton ? /* html */ `<button aria-label="Reset" class="dribbblish-config-item-reset main-trackCreditsModal-closeBtn">${iconUndo}</button>` : ""}
|
||||
</h2>
|
||||
<label class="main-type-mesto" empty="${options.description == null}" markdown>${this.#md.render(options.description)}</label>
|
||||
<label class="main-type-mesto" empty="${options.description == null}" markdown>${renderMD(options.description)}</label>
|
||||
</div>
|
||||
`
|
||||
: ""
|
||||
|
|
|
|||
116
src/js/Folders.js
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
import { waitForElement, htmlToNode } from "./Util";
|
||||
|
||||
import iconFolder from "icon/folder.light";
|
||||
import iconFolderOpen from "icon/folder-open.light";
|
||||
import iconNote from "icon/note";
|
||||
|
||||
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");
|
||||
|
||||
/** Replace Playlist name with their pictures */
|
||||
function loadPlaylistImage() {
|
||||
for (const item of listElem.children) {
|
||||
let link = item.querySelector("a");
|
||||
if (!link) continue;
|
||||
|
||||
let [_, app, uid] = link.pathname.split("/");
|
||||
let uri;
|
||||
if (app === "playlist") {
|
||||
uri = Spicetify.URI.playlistV2URI(uid);
|
||||
} else if (app === "folder") {
|
||||
const base64 = localStorage.getItem("dribbblish:folder-image:" + uid);
|
||||
if (base64 != null) {
|
||||
if (link.querySelector("svg")) link.querySelector("svg").remove();
|
||||
let img = link.querySelector("img");
|
||||
if (!img) {
|
||||
img = document.createElement("img");
|
||||
img.classList.add("playlist-picture");
|
||||
link.prepend(img);
|
||||
}
|
||||
img.src = base64;
|
||||
} else {
|
||||
if (link.querySelector("img")) link.querySelector("img").remove();
|
||||
let svg = link.querySelector("svg");
|
||||
if (!svg) {
|
||||
svg = htmlToNode(iconFolder);
|
||||
svg.classList.add("playlist-picture");
|
||||
link.prepend(svg);
|
||||
}
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
Spicetify.CosmosAsync.get(`sp://core-playlist/v1/playlist/${uri.toURI()}/metadata`, { policy: { picture: true } }).then((res) => {
|
||||
const { picture } = res.metadata;
|
||||
if (picture != null && picture.trim() != "") {
|
||||
if (link.querySelector("svg")) link.querySelector("svg").remove();
|
||||
let img = link.querySelector("img");
|
||||
if (!img) {
|
||||
img = document.createElement("img");
|
||||
img.classList.add("playlist-picture");
|
||||
link.prepend(img);
|
||||
}
|
||||
img.src = picture;
|
||||
} else {
|
||||
if (link.querySelector("img")) link.querySelector("img").remove();
|
||||
let svg = link.querySelector("svg");
|
||||
if (!svg) {
|
||||
svg = htmlToNode(iconNote);
|
||||
svg.classList.add("playlist-picture");
|
||||
link.prepend(svg);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
loadPlaylistImage();
|
||||
new MutationObserver(loadPlaylistImage).observe(listElem, { childList: true });
|
||||
|
||||
const filePickerForm = document.createElement("form");
|
||||
filePickerForm.setAttribute("aria-hidden", true);
|
||||
filePickerForm.innerHTML = '<input type="file" class="hidden-visually" />';
|
||||
document.body.appendChild(filePickerForm);
|
||||
/** @type {HTMLInputElement} */
|
||||
const filePickerInput = filePickerForm.childNodes[0];
|
||||
filePickerInput.accept = ["image/jpeg", "image/apng", "image/avif", "image/gif", "image/png", "image/svg+xml", "image/webp"].join(",");
|
||||
|
||||
filePickerInput.onchange = () => {
|
||||
if (!filePickerInput.files.length) return;
|
||||
|
||||
const file = filePickerInput.files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
const result = event.target.result;
|
||||
const id = Spicetify.URI.from(filePickerInput.uri).id;
|
||||
try {
|
||||
localStorage.setItem("dribbblish:folder-image:" + id, result);
|
||||
} catch {
|
||||
Spicetify.showNotification("File too large");
|
||||
}
|
||||
loadPlaylistImage();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
|
||||
new Spicetify.ContextMenu.Item(
|
||||
"Remove folder image",
|
||||
([uri]) => {
|
||||
const id = Spicetify.URI.from(uri).id;
|
||||
localStorage.removeItem("dribbblish:folder-image:" + id);
|
||||
loadPlaylistImage();
|
||||
},
|
||||
([uri]) => Spicetify.URI.isFolder(uri),
|
||||
"x"
|
||||
).register();
|
||||
new Spicetify.ContextMenu.Item(
|
||||
"Choose folder image",
|
||||
([uri]) => {
|
||||
filePickerInput.uri = uri;
|
||||
filePickerForm.reset();
|
||||
filePickerInput.click();
|
||||
},
|
||||
([uri]) => Spicetify.URI.isFolder(uri),
|
||||
"edit"
|
||||
).register();
|
||||
});
|
||||
|
|
@ -1,3 +1,7 @@
|
|||
import MarkdownIt from "markdown-it";
|
||||
import MarkdownItAttrs from "markdown-it-attrs";
|
||||
import MarkdownItBracketedSpans from "markdown-it-bracketed-spans";
|
||||
|
||||
/**
|
||||
* @callback waitForElCb
|
||||
* @param {HTMLElement[]} queries
|
||||
|
|
@ -37,3 +41,22 @@ export function capitalizeFirstLetter(string) {
|
|||
export function getClosestToNum(arr, num) {
|
||||
return arr.reduce((prev, curr) => (Math.abs(curr - num) < Math.abs(prev - num) ? curr : prev));
|
||||
}
|
||||
|
||||
export function renderMD(src, env) {
|
||||
const md = MarkdownIt({
|
||||
html: true,
|
||||
breaks: true,
|
||||
linkify: true,
|
||||
typographer: true
|
||||
});
|
||||
md.use(MarkdownItBracketedSpans);
|
||||
md.use(MarkdownItAttrs);
|
||||
|
||||
return md.render(src, env);
|
||||
}
|
||||
|
||||
export function htmlToNode(htmlStr) {
|
||||
var div = document.createElement("div");
|
||||
div.innerHTML = htmlStr.trim();
|
||||
return div.firstChild;
|
||||
}
|
||||
|
|
|
|||
107
src/js/main.js
|
|
@ -7,11 +7,12 @@ import moment from "moment";
|
|||
import { waitForElement, copyToClipboard, capitalizeFirstLetter, getClosestToNum } from "./Util";
|
||||
import ConfigMenu from "./ConfigMenu";
|
||||
import Info from "./Info";
|
||||
import "./Folders";
|
||||
|
||||
import svgArrowDown from "svg/arrow-down";
|
||||
import svgCode from "svg/code";
|
||||
import svgWifiSlash from "svg/wifi-slash";
|
||||
import svgCog from "svg/cog";
|
||||
import iconArrowDown from "icon/arrow-down";
|
||||
import iconCode from "icon/code";
|
||||
import iconWifiSlash from "icon/wifi-slash";
|
||||
import iconCog from "icon/cog";
|
||||
|
||||
const Dribbblish = {
|
||||
config: new ConfigMenu(),
|
||||
|
|
@ -29,7 +30,7 @@ Dribbblish.config.register({
|
|||
defaultValue: true,
|
||||
onChange: (val) =>
|
||||
Dribbblish.info[val ? "set" : "remove"]("settings", {
|
||||
icon: svgCog,
|
||||
icon: iconCog,
|
||||
color: {
|
||||
fg: "var(--spice-subtext)",
|
||||
bg: "rgba(var(--spice-rgb-subtext), calc(0.1 + var(--is_light) * 0.05))"
|
||||
|
|
@ -153,49 +154,6 @@ waitForElement(["#main"], () => {
|
|||
});
|
||||
});
|
||||
|
||||
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");
|
||||
|
||||
/** Replace Playlist name with their pictures */
|
||||
function loadPlaylistImage() {
|
||||
for (const item of listElem.children) {
|
||||
let link = item.querySelector("a");
|
||||
if (!link) continue;
|
||||
|
||||
let [_, app, uid] = link.pathname.split("/");
|
||||
let uri;
|
||||
if (app === "playlist") {
|
||||
uri = Spicetify.URI.playlistV2URI(uid);
|
||||
} else if (app === "folder") {
|
||||
const base64 = localStorage.getItem("dribbblish:folder-image:" + uid);
|
||||
let img = link.querySelector("img");
|
||||
if (!img) {
|
||||
img = document.createElement("img");
|
||||
img.classList.add("playlist-picture");
|
||||
link.prepend(img);
|
||||
}
|
||||
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) => {
|
||||
const meta = res.metadata;
|
||||
let img = link.querySelector("img");
|
||||
if (!img) {
|
||||
img = document.createElement("img");
|
||||
img.classList.add("playlist-picture");
|
||||
link.prepend(img);
|
||||
}
|
||||
img.src = meta.picture || "/images/tracklist-row-song-fallback.svg";
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
loadPlaylistImage();
|
||||
new MutationObserver(loadPlaylistImage).observe(listElem, { childList: true });
|
||||
});
|
||||
|
||||
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("#spicetify-show-list:not(:empty), .main-rootlist-wrapper > :nth-child(2) > :first-child").getBoundingClientRect().top;
|
||||
|
|
@ -295,53 +253,6 @@ waitForElement([".Root__main-view .os-resize-observer-host"], ([resizeHost]) =>
|
|||
root.classList.remove("is-connectBarVisible");
|
||||
}
|
||||
});
|
||||
|
||||
const filePickerForm = document.createElement("form");
|
||||
filePickerForm.setAttribute("aria-hidden", true);
|
||||
filePickerForm.innerHTML = '<input type="file" class="hidden-visually" />';
|
||||
document.body.appendChild(filePickerForm);
|
||||
/** @type {HTMLInputElement} */
|
||||
const filePickerInput = filePickerForm.childNodes[0];
|
||||
filePickerInput.accept = ["image/jpeg", "image/apng", "image/avif", "image/gif", "image/png", "image/svg+xml", "image/webp"].join(",");
|
||||
|
||||
filePickerInput.onchange = () => {
|
||||
if (!filePickerInput.files.length) return;
|
||||
|
||||
const file = filePickerInput.files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = (event) => {
|
||||
const result = event.target.result;
|
||||
const id = Spicetify.URI.from(filePickerInput.uri).id;
|
||||
try {
|
||||
localStorage.setItem("dribbblish:folder-image:" + id, result);
|
||||
} catch {
|
||||
Spicetify.showNotification("File too large");
|
||||
}
|
||||
loadPlaylistImage();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
|
||||
new Spicetify.ContextMenu.Item(
|
||||
"Remove folder image",
|
||||
([uri]) => {
|
||||
const id = Spicetify.URI.from(uri).id;
|
||||
localStorage.removeItem("dribbblish:folder-image:" + id);
|
||||
loadPlaylistImage();
|
||||
},
|
||||
([uri]) => Spicetify.URI.isFolder(uri),
|
||||
"x"
|
||||
).register();
|
||||
new Spicetify.ContextMenu.Item(
|
||||
"Choose folder image",
|
||||
([uri]) => {
|
||||
filePickerInput.uri = uri;
|
||||
filePickerForm.reset();
|
||||
filePickerInput.click();
|
||||
},
|
||||
([uri]) => Spicetify.URI.isFolder(uri),
|
||||
"edit"
|
||||
).register();
|
||||
})();
|
||||
|
||||
/* Config settings */
|
||||
|
|
@ -839,8 +750,8 @@ function checkForUpdate() {
|
|||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
const isDev = process.env.DRIBBBLISH_VERSION == "Dev";
|
||||
Dribbblish.info.set("update", isDev || data.tag_name > process.env.DRIBBBLISH_VERSION ? { text: `v${data.tag_name}`, tooltip: "Open Release page to download", icon: svgArrowDown, onClick: () => window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme/releases/latest", "_blank") } : null);
|
||||
Dribbblish.info.set("dev", isDev ? { tooltip: "Dev build", icon: svgCode } : null);
|
||||
Dribbblish.info.set("update", isDev || data.tag_name > process.env.DRIBBBLISH_VERSION ? { text: `v${data.tag_name}`, tooltip: "Open Release page to download", icon: iconArrowDown, onClick: () => window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme/releases/latest", "_blank") } : null);
|
||||
Dribbblish.info.set("dev", isDev ? { tooltip: "Dev build", icon: iconCode } : null);
|
||||
})
|
||||
.catch(console.error);
|
||||
}
|
||||
|
|
@ -852,7 +763,7 @@ checkForUpdate();
|
|||
window.addEventListener("offline", () =>
|
||||
Dribbblish.info.set("offline", {
|
||||
tooltip: "Offline",
|
||||
icon: svgWifiSlash,
|
||||
icon: iconWifiSlash,
|
||||
order: 998,
|
||||
color: {
|
||||
fg: "#ffffff",
|
||||
|
|
|
|||
22
src/loaders/icon-loader.js
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
const { parseSync: parseSVG, stringify: stringifySVG } = require("svgson");
|
||||
|
||||
module.exports = function (content, map, meta) {
|
||||
const query = new URLSearchParams(this.resourceQuery);
|
||||
const svg = parseSVG(content);
|
||||
|
||||
svg.attributes.type = "icon";
|
||||
svg.attributes.width = query.get("width") ?? 16;
|
||||
svg.attributes.height = query.get("height") ?? 16;
|
||||
|
||||
svg.children = svg.children.map((c) => {
|
||||
if (c.attributes.fill != null && query.has("fill")) c.attributes.fill = query.get("fill");
|
||||
return c;
|
||||
});
|
||||
|
||||
const svgStr = stringifySVG(svg);
|
||||
if (query.has("base64")) {
|
||||
return `data:image/svg+xml;base64,${Buffer.from(svgStr).toString("base64")}`;
|
||||
} else {
|
||||
return svgStr;
|
||||
}
|
||||
};
|
||||
|
|
@ -20,7 +20,7 @@ $font-weights: (
|
|||
font-family: $font;
|
||||
font-weight: $weight;
|
||||
font-style: normal;
|
||||
src: url("glue-resources/fonts/#{$font}-#{$style}.ttf") format("truetype");
|
||||
src: url("fonts/#{$font}-#{$style}.ttf") format("truetype");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
height: 100%;
|
||||
padding: 0px 8px;
|
||||
color: spiceColor("sidebar-text");
|
||||
background-color: spiceColor("button");
|
||||
background-color: spiceColor("sidebar");
|
||||
border-radius: var(--sidebar-icons-border-radius);
|
||||
line-height: 13px;
|
||||
@include spiceFont("glue", 14px, "Medium");
|
||||
|
|
|
|||
|
|
@ -638,7 +638,7 @@ html.sidebar-hide-text .GlueDropTarget span {
|
|||
padding: 0 12px;
|
||||
}
|
||||
|
||||
img.playlist-picture {
|
||||
.playlist-picture {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
flex: 0 0 32px;
|
||||
|
|
@ -646,6 +646,10 @@ img.playlist-picture {
|
|||
background-size: cover;
|
||||
background-position: center;
|
||||
border-radius: var(--sidebar-icons-border-radius);
|
||||
|
||||
&[type="icon"] {
|
||||
padding: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.main-rootlist-rootlistItem a span {
|
||||
|
|
@ -737,12 +741,9 @@ li.GlueDropTarget {
|
|||
padding-top: 32px;
|
||||
}
|
||||
|
||||
#main[top-bar="none-padding"] .spotify__container--is-desktop.spotify__os--is-windows[dir="ltr"] .Root__top-bar + .main-buddyFeed-buddyFeedRoot .main-topBar-container {
|
||||
padding-right: 167px;
|
||||
}
|
||||
|
||||
.main-topBar-container {
|
||||
max-width: unset;
|
||||
padding: 16px 32px !important;
|
||||
}
|
||||
|
||||
/** Custom elements */
|
||||
|
|
@ -969,7 +970,8 @@ span.main-userWidget-displayName,
|
|||
|
||||
.main-rootlist-wrapper > div:nth-child(2) > li img,
|
||||
.main-navBar-navBarLink > svg,
|
||||
.main-navBar-navBarLink > .icon {
|
||||
.main-navBar-navBarLink > .icon,
|
||||
.main-rootlist-rootlistItemLink > svg {
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
|
|
@ -1051,7 +1053,7 @@ div.GlueDropTarget.personal-library > *.active {
|
|||
}
|
||||
|
||||
html.right-expanded-cover .main-coverSlotExpanded-container {
|
||||
right: var(--main-gap);
|
||||
right: calc(var(--main-gap) * 2);
|
||||
left: unset;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ module.exports = {
|
|||
resolve: {
|
||||
extensions: [".js", ".svg"],
|
||||
alias: {
|
||||
svg: path.resolve(__dirname, "./src/svg")
|
||||
icon: path.resolve(__dirname, "./src/icons")
|
||||
}
|
||||
},
|
||||
module: {
|
||||
|
|
@ -49,23 +49,24 @@ module.exports = {
|
|||
},
|
||||
{
|
||||
test: /\.svg/,
|
||||
exclude: /node_modules/,
|
||||
type: "asset/source"
|
||||
type: "asset/source",
|
||||
resourceQuery: /.?/,
|
||||
use: [path.resolve(__dirname, "./src/loaders/icon-loader.js")]
|
||||
}
|
||||
]
|
||||
},
|
||||
devtool: "inline-source-map",
|
||||
plugins: [
|
||||
new CleanWebpackPlugin({
|
||||
protectWebpackAssets: false,
|
||||
cleanAfterEveryBuildPatterns: ["*.LICENSE.txt"]
|
||||
new CopyPlugin({
|
||||
patterns: [{ from: "src/assets", to: "assets" }]
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
"process.env.DRIBBBLISH_VERSION": JSON.stringify(process.env.DRIBBBLISH_VERSION || "Dev"),
|
||||
"process.env.COMMIT_HASH": JSON.stringify(process.env.COMMIT_HASH || "local")
|
||||
}),
|
||||
new CopyPlugin({
|
||||
patterns: [{ from: "src/assets", to: "assets" }]
|
||||
new CleanWebpackPlugin({
|
||||
protectWebpackAssets: false,
|
||||
cleanAfterEveryBuildPatterns: ["*.LICENSE.txt"]
|
||||
})
|
||||
]
|
||||
};
|
||||
|
|
|
|||