mirror of
https://github.com/danbulant/dribbblish-dynamic-theme
synced 2026-05-25 04:52:10 +00:00
Add Info class to show buttons / text next to the user icon (fixes #108)
This commit is contained in:
parent
ec84ad0c79
commit
0c318e1f21
10 changed files with 150 additions and 65 deletions
|
|
@ -9,4 +9,5 @@ Fixed:
|
|||
|
||||
Improved:
|
||||
- Settings that have been changed from default will now show a line next to them. Inspired by the [Visual Studio Code settings UI](https://d33wubrfki0l68.cloudfront.net/d1f1ea4def506997ced23d3d912154794e530e1c/063d2/assets/img/blog/2020-09-17-vscode-settings/settings-ui.png)
|
||||
- Checkbox / Switch input styles are now more in line with other input styles
|
||||
- Checkbox / Switch input styles are now more in line with other input styles
|
||||
- Available updates are noe shown as clickable button next to your user icon instead of having to open the user menu
|
||||
|
|
@ -2,7 +2,7 @@ import $ from "jquery";
|
|||
import MarkdownIt from "markdown-it";
|
||||
import MarkdownItAttrs from "markdown-it-attrs";
|
||||
|
||||
import svgUndo from "../svg/undo.svg";
|
||||
import svgUndo from "svg/undo";
|
||||
|
||||
export default class ConfigMenu {
|
||||
/**
|
||||
|
|
|
|||
63
src/js/Info.js
Normal file
63
src/js/Info.js
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
import $ from "jquery";
|
||||
import MarkdownIt from "markdown-it";
|
||||
import MarkdownItAttrs from "markdown-it-attrs";
|
||||
|
||||
import { waitForElement } from "./Util";
|
||||
|
||||
export default class Info {
|
||||
/**
|
||||
* @typedef {Object} DribbblishInfo
|
||||
* @property {String} [text]
|
||||
* @property {String} [tooltip]
|
||||
* @property {String} [icon]
|
||||
* @property {onClick} [onClick]
|
||||
*/
|
||||
|
||||
/**
|
||||
* @callback onClick
|
||||
* @returns {void}
|
||||
*/
|
||||
|
||||
/** @type {HTMLDivElement} */
|
||||
#container;
|
||||
|
||||
constructor() {
|
||||
this.md = MarkdownIt({
|
||||
html: true,
|
||||
breaks: true,
|
||||
linkify: true,
|
||||
typographer: true
|
||||
});
|
||||
this.md.use(MarkdownItAttrs);
|
||||
|
||||
waitForElement([".main-topBar-container", ".main-userWidget-box"], ([topBarContainer, userWidget]) => {
|
||||
this.#container = document.createElement("div");
|
||||
this.#container.id = "dribbblish-info-container";
|
||||
topBarContainer.insertBefore(this.#container, userWidget);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String} key
|
||||
* @param {DribbblishInfo} info
|
||||
*/
|
||||
set(key, info) {
|
||||
this.remove(key);
|
||||
if (info.text == null && info.icon == null) throw new Error("invalid info");
|
||||
|
||||
const elem = document.createElement("div");
|
||||
elem.classList.add("dribbblish-info-item");
|
||||
elem.addEventListener("click", info.onClick);
|
||||
elem.setAttribute("key", key);
|
||||
if (info.text == null) elem.setAttribute("icon-only", "");
|
||||
if (info.tooltip != null) elem.setAttribute("title", info.tooltip);
|
||||
if (info.onClick != null) elem.setAttribute("clickable", "");
|
||||
elem.innerHTML = `${this.md.render(info.text ?? "")}${info.icon ?? ""}`;
|
||||
|
||||
this.#container.appendChild(elem);
|
||||
}
|
||||
|
||||
remove(key) {
|
||||
$(this.#container).find(`[key="${key}"]`).remove();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,21 @@
|
|||
export function waitForElement(els, func, timeout = 100) {
|
||||
/**
|
||||
* @callback waitForElCb
|
||||
* @param {HTMLElement[]} queries
|
||||
*/
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {String[]} els
|
||||
* @param {waitForElCb} cb
|
||||
* @param {Number} [tries=100]
|
||||
* @param {Number} [interval=300]
|
||||
*/
|
||||
export function waitForElement(els, cb, tries = 100, interval = 300) {
|
||||
const queries = els.map((el) => document.querySelector(el));
|
||||
if (queries.every((a) => a)) {
|
||||
func(queries);
|
||||
} else if (timeout > 0) {
|
||||
setTimeout(waitForElement, 300, els, func, --timeout);
|
||||
cb(queries);
|
||||
} else if (tries > 0) {
|
||||
setTimeout(waitForElement, interval, els, cb, --tries);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -5,13 +5,15 @@ import moment from "moment";
|
|||
|
||||
import { waitForElement, copyToClipboard, capitalizeFirstLetter } from "./Util";
|
||||
import ConfigMenu from "./ConfigMenu";
|
||||
import Info from "./Info";
|
||||
|
||||
class _DribbblishShared {
|
||||
constructor() {
|
||||
this.config = new ConfigMenu();
|
||||
}
|
||||
}
|
||||
const DribbblishShared = new _DribbblishShared();
|
||||
import svgArrowDown from "svg/arrow-down";
|
||||
import svgCode from "svg/code";
|
||||
|
||||
const DribbblishShared = {
|
||||
config: new ConfigMenu(),
|
||||
info: new Info()
|
||||
};
|
||||
|
||||
DribbblishShared.config.register({
|
||||
type: "checkbox",
|
||||
|
|
@ -741,39 +743,16 @@ function registerCoverListener() {
|
|||
registerCoverListener();
|
||||
|
||||
// Check latest release every 10m
|
||||
waitForElement([".main-userWidget-box"], ([userWidget]) => {
|
||||
waitForElement([".main-topBar-container"], ([topBarContainer]) => {
|
||||
function checkForUpdate() {
|
||||
fetch("https://api.github.com/repos/JulienMaille/dribbblish-dynamic-theme/releases/latest")
|
||||
.then((response) => {
|
||||
return response.json();
|
||||
})
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
let upd;
|
||||
if (!document.getElementById("dribbblish-update")) {
|
||||
upd = document.createElement("div");
|
||||
upd.id = "dribbblish-update";
|
||||
//upd.setAttribute("title", `Changes: ${data.name}`);
|
||||
userWidget.append(upd);
|
||||
} else {
|
||||
upd = document.getElementById("dribbblish-update");
|
||||
}
|
||||
|
||||
upd.style.display = "block";
|
||||
userWidget.classList.add("update-avail");
|
||||
if (process.env.DRIBBBLISH_VERSION == "Dev") {
|
||||
upd.innerText = "Dev version!";
|
||||
} else if (data.tag_name > process.env.DRIBBBLISH_VERSION) {
|
||||
upd.innerText = `Theme UPD v${data.tag_name} avail.`;
|
||||
new Spicetify.Menu.Item("Update Dribbblish", false, () => window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme/releases/latest", "_blank")).register();
|
||||
} else {
|
||||
userWidget.classList.remove("update-avail");
|
||||
upd.style.display = "none";
|
||||
}
|
||||
const isDev = process.env.DRIBBBLISH_VERSION == "Dev";
|
||||
DribbblishShared.info.set("upd", 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);
|
||||
DribbblishShared.info.set("dev", isDev ? { tooltip: "Dev build", icon: svgCode } : null);
|
||||
})
|
||||
.catch((err) => {
|
||||
// Do something for an error here
|
||||
console.error(err);
|
||||
});
|
||||
.catch(console.error);
|
||||
}
|
||||
|
||||
setInterval(checkForUpdate(), 10 * 60 * 1000);
|
||||
|
|
|
|||
38
src/styles/Info.scss
Normal file
38
src/styles/Info.scss
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
#dribbblish-info-container {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
margin-right: 8px;
|
||||
height: 100%;
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
|
||||
& > div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
gap: 8px;
|
||||
height: 100%;
|
||||
padding: 0px 10px;
|
||||
color: spiceColor("sidebar-text");
|
||||
background-color: spiceColor("button");
|
||||
border-radius: var(--sidebar-icons-border-radius);
|
||||
line-height: 13px;
|
||||
@include spiceFont("glue", 14px);
|
||||
|
||||
&[clickable] {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&[icon-only] {
|
||||
padding: 0px;
|
||||
aspect-ratio: 1/1;
|
||||
}
|
||||
|
||||
& svg {
|
||||
width: 1em;
|
||||
height: 1em;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
@import "ContextMenu.scss";
|
||||
@import "NoAds";
|
||||
@import "Markdown";
|
||||
@import "Info";
|
||||
|
||||
:root {
|
||||
--bar-height: 70px;
|
||||
|
|
@ -273,17 +274,8 @@ span.artist-artistVerifiedBadge-badge svg > path:last-of-type {
|
|||
|
||||
.main-userWidget-box {
|
||||
background-color: transparent !important;
|
||||
}
|
||||
|
||||
.main-userWidget-box.update-avail {
|
||||
padding-right: 10px;
|
||||
background-color: spiceColor("subtext", 0.1) !important;
|
||||
|
||||
&:hover,
|
||||
&:active,
|
||||
&[data-context-menu-open="true"] {
|
||||
background-color: spiceColor("subtext", 0.15) !important;
|
||||
}
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
.main-avatar-avatar.main-avatar-withBadge:after {
|
||||
|
|
@ -769,18 +761,6 @@ li.GlueDropTarget {
|
|||
pointer-events: none;
|
||||
}
|
||||
|
||||
#dribbblish-update {
|
||||
color: spiceColor("button-active");
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
font-size: 12px;
|
||||
font-weight: 400;
|
||||
letter-spacing: normal;
|
||||
line-height: 16px;
|
||||
text-transform: none;
|
||||
}
|
||||
|
||||
/** Rearrange player bar */
|
||||
.main-nowPlayingBar-left {
|
||||
order: 1;
|
||||
|
|
@ -1254,3 +1234,9 @@ canvas[width="250"][height="250"] {
|
|||
.main-trackInfo-container > div > div:after {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// workaround to re-center track-info
|
||||
#main:not([player-controls="spotify"]) .main-trackInfo-container > div > div > div {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
|
|
|||
3
src/svg/arrow-down.svg
Normal file
3
src/svg/arrow-down.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="16" height="16">
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 383 B |
3
src/svg/code.svg
Normal file
3
src/svg/code.svg
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="16" height="16">
|
||||
<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>
|
||||
|
After Width: | Height: | Size: 675 B |
|
|
@ -1,3 +1,3 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="16" height="16">
|
||||
<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: 656 B After Width: | Height: | Size: 679 B |
Loading…
Reference in a new issue