make sass functions available in js & color playlist visualizer

This commit is contained in:
Send_Nukez 2022-01-23 11:03:40 +01:00
parent 36fe1f5a2f
commit 316e7581cf
12 changed files with 3982 additions and 143 deletions

3
.babelrc Normal file
View file

@ -0,0 +1,3 @@
{
"presets": ["@babel/env"]
}

View file

@ -7,4 +7,5 @@ Fixed:
Improved: Improved:
- Add `embedWidgetGenerator` modals to custom modal styles. (Things like the [spicetify-marketplace](https://github.com/CharlieS1103/spicetify-marketplace) options) - Add `embedWidgetGenerator` modals to custom modal styles. (Things like the [spicetify-marketplace](https://github.com/CharlieS1103/spicetify-marketplace) options)
- Changed custom app tab styles to fit in with the theme - Changed custom app tab styles to fit in with the theme
- Changed notification styles to fit in with other elements of the theme - Changed notification styles to fit in with other elements of the theme
- The visualizer icon when playing a song from a playlist is now colored

3723
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -6,6 +6,8 @@
"url": "https://github.com/JulienMaille/dribbblish-dynamic-theme/issues" "url": "https://github.com/JulienMaille/dribbblish-dynamic-theme/issues"
}, },
"devDependencies": { "devDependencies": {
"@babel/preset-env": "^7.16.5",
"@babel/register": "^7.16.5",
"@material-icons/svg": "^1.0.22", "@material-icons/svg": "^1.0.22",
"clean-webpack-plugin": "^4.0.0", "clean-webpack-plugin": "^4.0.0",
"sass": "^1.43.5", "sass": "^1.43.5",
@ -14,7 +16,7 @@
"webpack-cli": "^4.9.0" "webpack-cli": "^4.9.0"
}, },
"scripts": { "scripts": {
"build": "webpack --mode=development" "build": "webpack"
}, },
"dependencies": { "dependencies": {
"chroma-js": "^2.1.2", "chroma-js": "^2.1.2",

131
src/icons/equaliser.svg Normal file
View file

@ -0,0 +1,131 @@
<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 22 24'>
<defs>
<style>
@keyframes play {
0% {
transform: scaleY(1);
}
3.3% {
transform: scaleY(0.9583);
}
6.6% {
transform: scaleY(0.9166);
}
9.9% {
transform: scaleY(0.8333);
}
13.3% {
transform: scaleY(0.7083);
}
16.6% {
transform: scaleY(0.5416);
}
19.9% {
transform: scaleY(0.4166);
}
23.3% {
transform: scaleY(0.25);
}
26.6% {
transform: scaleY(0.1666);
}
29.9% {
transform: scaleY(0.125);
}
33.3% {
transform: scaleY(0.125);
}
36.6% {
transform: scaleY(0.1666);
}
39.9% {
transform: scaleY(0.1666);
}
43.3% {
transform: scaleY(0.2083);
}
46.6% {
transform: scaleY(0.2916);
}
49.9% {
transform: scaleY(0.375);
}
53.3% {
transform: scaleY(0.5);
}
56.6% {
transform: scaleY(0.5833);
}
59.9% {
transform: scaleY(0.625);
}
63.3% {
transform: scaleY(0.6666);
}
66.6% {
transform: scaleY(0.6666);
}
69.9% {
transform: scaleY(0.6666);
}
73.3% {
transform: scaleY(0.6666);
}
76.6% {
transform: scaleY(0.7083);
}
79.9% {
transform: scaleY(0.75);
}
83.3% {
transform: scaleY(0.8333);
}
86.6% {
transform: scaleY(0.875);
}
89.9% {
transform: scaleY(0.9166);
}
93.3% {
transform: scaleY(0.9583);
}
96.6% {
transform: scaleY(1);
}
}
svg[icon-type="dribbblish"][icon-name="equaliser"] > rect[i="0"] {
transform-origin: bottom;
animation: play 0.9s -0.51s infinite;
}
svg[icon-type="dribbblish"][icon-name="equaliser"] > rect[i="1"] {
transform-origin: bottom;
animation: play 0.9s infinite;
}
svg[icon-type="dribbblish"][icon-name="equaliser"] > rect[i="2"] {
transform-origin: bottom;
animation: play 0.9s -0.15s infinite;
}
svg[icon-type="dribbblish"][icon-name="equaliser"] > rect[i="3"] {
transform-origin: bottom;
animation: play 0.9s -0.75s infinite;
}
</style>
</defs>
<rect fill="currentColor" i="0" class='cls-1' width='4' height='24'/>
<rect fill="currentColor" i="1" class='cls-1' x='6' width='4' height='24'/>
<rect fill="currentColor" i="2" class='cls-1' x='12' width='4' height='24'/>
<rect fill="currentColor" i="3" class='cls-1' x='18' width='4' height='24'/>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -17,8 +17,8 @@ export default class Icons {
/** @type {Object.<String, Object.<IconStyle, String>>} */ /** @type {Object.<String, Object.<IconStyle, String>>} */
#icons; #icons;
constructor() { constructor(icons) {
this.#icons = process.env.DRIBBBLISH_ICONS; this.#icons = icons ?? process.env.DRIBBBLISH_ICONS;
} }
/** /**
@ -90,14 +90,16 @@ export default class Icons {
if (options.className != "") svg.attributes.class = options.className; if (options.className != "") svg.attributes.class = options.className;
// Add Styles // Add Styles
// Create CSSStyleDeclaration by creating an element since there is no constructor for it const styles = {};
const styles = document.createElement("a").style;
if (options.scale != 1) { if (options.scale != 1) {
styles.transform = `scale(${options.scale})`; styles["transform"] = `scale(${options.scale})`;
styles.transformOrigin = "center"; styles["transform-origin"] = "center";
} }
const styleStr = Object.entries(styles)
.map(([prop, val]) => `${prop}: ${val};`)
.join(" ");
svg.children = svg.children.map((child) => { svg.children = svg.children.map((child) => {
if (styles.cssText != "") child.attributes.style = styles.cssText; if (styleStr != "") child.attributes.style = styleStr;
return child; return child;
}); });

13
src/js/SassUtil.js Normal file
View file

@ -0,0 +1,13 @@
export function lightOffset(n, offset) {
return `calc(${n} + ${offset} * var(--is_light))`;
}
export function spiceColor(key, alpha = 1, _lightOffset = 0) {
if (alpha == 1) {
return `var(--spice-${key})`;
} else if (_lightOffset == 0) {
return `rgba(var(--spice-rgb-${key}), ${alpha})`;
} else {
return `rgba(var(--spice-rgb-${key}), ${lightOffset(alpha, _lightOffset)})`;
}
}

View file

@ -12,6 +12,7 @@ $("html").attr("dribbblish-js-installed", "");
import { waitForElement, copyToClipboard, capitalizeFirstLetter, getClosestToNum, randomFromArray, debounce } from "./Util"; import { waitForElement, copyToClipboard, capitalizeFirstLetter, getClosestToNum, randomFromArray, debounce } from "./Util";
import { default as _Dribbblish } from "./Dribbblish"; import { default as _Dribbblish } from "./Dribbblish";
import "./Folders"; import "./Folders";
import { spiceColor } from "./SassUtil";
// To expose to external scripts // To expose to external scripts
const Dribbblish = new _Dribbblish(); const Dribbblish = new _Dribbblish();
@ -47,8 +48,8 @@ Dribbblish.on("ready", () => {
? { ? {
icon: "settings", icon: "settings",
color: { color: {
fg: "var(--spice-subtext)", fg: spiceColor("subtext"),
bg: "rgba(var(--spice-rgb-subtext), calc(0.1 + var(--is_light) * 0.05))" bg: spiceColor("subtext", 0.1, 0.05)
}, },
order: 999, order: 999,
tooltip: "Open Dribbblish Settings", tooltip: "Open Dribbblish Settings",

View file

@ -44,16 +44,3 @@ $props-to-transition: ("sidebar", "main", "text", "button");
transition: all var(--song-transition-speed) linear; transition: all var(--song-transition-speed) linear;
transition-property: $props; transition-property: $props;
} }
// $key: the key of the color, e.g. "main"
// $alpha: tha alpha in rgba()
// $light-offset: added when in light mode
@function spiceColor($key, $alpha: 1, $light-offset: 0) {
@if $alpha == 1 {
@return var(--spice-#{$key});
} @else if $light-offset == 0 {
@return rgba(var(--spice-rgb-#{$key}), $alpha);
} @else {
@return rgba(var(--spice-rgb-#{$key}), lightOffset($alpha, $light-offset));
}
}

View file

@ -3,11 +3,6 @@
@return #{"invert("}$v#{")"}; @return #{"invert("}$v#{")"};
} }
// returns $n and adds $offset when the theme is light
@function lightOffset($n, $offset) {
@return calc($n + $offset * var(--is_light));
}
@mixin spiceShadow() { @mixin spiceShadow() {
box-shadow: 0px 0px 8px spiceColor("subtext", 0.1, 0.1); box-shadow: 0px 0px 8px spiceColor("subtext", 0.1, 0.1);
} }

View file

@ -135,9 +135,15 @@
box-shadow: 0 4px 20px #21212130; box-shadow: 0 4px 20px #21212130;
} }
.main-trackList-rowMarker {
color: spiceColor("text");
}
.main-trackList-playingIcon { .main-trackList-playingIcon {
-webkit-mask-image: url(icon64("equaliser", '{"size": 14}'));
background-color: currentColor;
content-visibility: hidden;
image-rendering: pixelated; image-rendering: pixelated;
filter: grayscale(1);
} }
.main-trackList-trackListRowGrid { .main-trackList-trackListRowGrid {

View file

@ -1,91 +1,110 @@
const webpack = require("webpack"); import webpack from "webpack";
const sass = require("sass"); import sass from "sass";
const { CleanWebpackPlugin } = require("clean-webpack-plugin"); import { CleanWebpackPlugin } from "clean-webpack-plugin";
const path = require("path"); import path from "path";
const fs = require("fs"); import fs from "fs";
const icons = {}; import Icons from "./src/js/Icons";
function addIcon(name, style, path) { import { lightOffset, spiceColor } from "./src/js/SassUtil";
name = name.replace(/_/g, "-");
if (!icons.hasOwnProperty(name)) icons[name] = {}; const _icons = {};
icons[name][style] = fs.readFileSync(path, { encoding: "utf8" }); function addIcon(name, style, path) {
} name = name.replace(/_/g, "-");
// Add Material Icons if (!_icons.hasOwnProperty(name)) _icons[name] = {};
let iconDir = path.resolve(__dirname, "node_modules/@material-icons/svg/svg"); _icons[name][style] = fs.readFileSync(path, { encoding: "utf8" });
for (const dir of fs.readdirSync(iconDir)) { }
for (const file of fs.readdirSync(path.resolve(iconDir, dir))) { // Add Material Icons
addIcon(dir, `material:${file.replace(/\..*?$/, "")}`, path.resolve(iconDir, dir, file)); let iconDir = path.resolve(__dirname, "node_modules/@material-icons/svg/svg");
} for (const dir of fs.readdirSync(iconDir)) {
} for (const file of fs.readdirSync(path.resolve(iconDir, dir))) {
// Add Custom Icons addIcon(dir, `material:${file.replace(/\..*?$/, "")}`, path.resolve(iconDir, dir, file));
iconDir = path.resolve(__dirname, "src/icons"); }
for (const icon of fs.readdirSync(iconDir)) { }
addIcon(icon.replace(/\..*?$/, ""), "custom", path.resolve(iconDir, icon)); // Add Custom Icons
} iconDir = path.resolve(__dirname, "src/icons");
for (const icon of fs.readdirSync(iconDir)) {
/** @type {import('webpack').Configuration} */ addIcon(icon.replace(/\..*?$/, ""), "custom", path.resolve(iconDir, icon));
module.exports = { }
entry: [path.resolve(__dirname, "src/js/main.js"), path.resolve(__dirname, "src/styles/main.scss"), path.resolve(__dirname, "src/styles/Colors.scss")],
output: { const icons = new Icons(_icons);
path: path.resolve(__dirname, "dist"),
filename: "dribbblish-dynamic.js" /** @type {import('webpack').Configuration} */
}, const config = {
module: { mode: "development",
rules: [ entry: [path.resolve(__dirname, "src/js/main.js"), path.resolve(__dirname, "src/styles/main.scss"), path.resolve(__dirname, "src/styles/Colors.scss")],
{ output: {
include: path.resolve(__dirname, "src/js/main.js"), path: path.resolve(__dirname, "dist"),
use: [] filename: "dribbblish-dynamic.js"
}, },
{ module: {
include: path.resolve(__dirname, "src/styles/main.scss"), rules: [
type: "asset/resource", {
generator: { include: path.resolve(__dirname, "src/js/main.js"),
filename: "user.css" use: []
}, },
use: [ {
{ include: path.resolve(__dirname, "src/styles/main.scss"),
loader: "sass-loader", type: "asset/resource",
options: { generator: {
implementation: sass, filename: "user.css"
sourceMap: true, },
sassOptions: { use: [
functions: { {
"font64($font)": (font) => { loader: "sass-loader",
const file = path.resolve(__dirname, "src/fonts", font.getValue()); options: {
return new sass.types.String(`"data:font/truetype;charset=utf-8;base64,${fs.readFileSync(file, { encoding: "base64" })}"`); implementation: sass,
} sourceMap: true,
} sassOptions: {
} functions: {
} "lightOffset($n, $offset)": (n, offset) => {
} return new sass.types.String(lightOffset(n.getValue(), offset.getValue()));
] },
}, "spiceColor($key, $alpha: 1, $light-offset: 0)": (key, alpha, _lightOffset) => {
{ return new sass.types.String(spiceColor(key.getValue(), alpha.getValue(), _lightOffset.getValue()));
include: path.resolve(__dirname, "src/styles/Colors.scss"), },
type: "asset/resource", "font64($font)": (font) => {
generator: { const file = path.resolve(__dirname, "src/fonts", font.getValue());
filename: "color.ini" return new sass.types.String(`"data:font/truetype;charset=utf-8;base64,${fs.readFileSync(file, { encoding: "base64" })}"`);
}, },
use: [path.resolve(__dirname, "src/loaders/color-loader.js")] 'icon64($name, $options: "{}")': (name, options) => {
} name = name.getValue();
] options = JSON.parse(options.getValue());
}, return new sass.types.String(icons.get(name, { ...options, base64: true }));
devtool: "inline-source-map", }
plugins: [ }
new webpack.DefinePlugin({ }
"process.env.BUG_REPORT": JSON.stringify( }
fs }
.readFileSync(path.resolve(__dirname, ".github/ISSUE_TEMPLATE/bug_report.md"), { encoding: "utf8" }) ]
.replace(/^---(.*?\r?\n)+---(.*?\r?\n)*?(?=\S)/, "") // Replace GitHub header },
.replace(/\*\*Desktop Setup\*\*\r?\n(- .*?\r?\n)+\r?\n/, "") // Replace **Desktop Setup** block {
), include: path.resolve(__dirname, "src/styles/Colors.scss"),
"process.env.DRIBBBLISH_ICONS": JSON.stringify(icons), type: "asset/resource",
"process.env.DRIBBBLISH_VERSION": JSON.stringify(process.env.DRIBBBLISH_VERSION ?? "Dev"), generator: {
"process.env.COMMIT_HASH": JSON.stringify(process.env.COMMIT_HASH ?? "local") filename: "color.ini"
}), },
new CleanWebpackPlugin({ use: [path.resolve(__dirname, "src/loaders/color-loader.js")]
protectWebpackAssets: false, }
cleanAfterEveryBuildPatterns: ["*.LICENSE.txt"] ]
}) },
] devtool: "inline-source-map",
}; plugins: [
new webpack.DefinePlugin({
"process.env.BUG_REPORT": JSON.stringify(
fs
.readFileSync(path.resolve(__dirname, ".github/ISSUE_TEMPLATE/bug_report.md"), { encoding: "utf8" })
.replace(/^---(.*?\r?\n)+---(.*?\r?\n)*?(?=\S)/, "") // Replace GitHub header
.replace(/\*\*Desktop Setup\*\*\r?\n(- .*?\r?\n)+\r?\n/, "") // Replace **Desktop Setup** block
),
"process.env.DRIBBBLISH_ICONS": JSON.stringify(_icons),
"process.env.DRIBBBLISH_VERSION": JSON.stringify(process.env.DRIBBBLISH_VERSION ?? "Dev"),
"process.env.COMMIT_HASH": JSON.stringify(process.env.COMMIT_HASH ?? "local")
}),
new CleanWebpackPlugin({
protectWebpackAssets: false,
cleanAfterEveryBuildPatterns: ["*.LICENSE.txt"]
})
]
};
export default config;