Add Info class to show buttons / text next to the user icon (fixes #108)

This commit is contained in:
Send_Nukez 2021-11-12 17:57:19 +01:00 committed by GitHub Action
parent ec84ad0c79
commit 0c318e1f21
10 changed files with 150 additions and 65 deletions

View file

@ -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

View file

@ -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
View 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();
}
}

View file

@ -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);
}
}

View file

@ -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
View 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;
}
}
}

View file

@ -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
View 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
View 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

View file

@ -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