mirror of
https://github.com/danbulant/dribbblish-dynamic-theme
synced 2026-06-21 15:52:12 +00:00
Compare commits
63 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77182042dd | ||
|
|
7492c86124 | ||
|
|
55693078f6 | ||
|
|
2c8dea7f5d | ||
|
|
6d23932d0b | ||
|
|
d7e355bf46 | ||
|
|
c9ec3971ad | ||
|
|
bb7017960b | ||
|
|
1064087b48 | ||
|
|
3edfc3fa6b | ||
|
|
239033ad5e | ||
|
|
145cfe9b53 | ||
|
|
2e55b23b44 | ||
|
|
8c5a45c64a | ||
|
|
8d9cdf3df5 | ||
|
|
9f5a988eca | ||
|
|
167e253a86 | ||
|
|
ba5846bc41 | ||
|
|
d687a13cb7 | ||
|
|
33134709ed | ||
|
|
13e1f64054 | ||
|
|
827c9f3ba0 | ||
|
|
f13a3c1ff9 | ||
|
|
14da00bf74 | ||
|
|
23fe7deb15 | ||
|
|
a146134b1d | ||
|
|
4c134a94a0 | ||
|
|
14902a060f | ||
|
|
c45c5faad0 | ||
|
|
162616c2cb | ||
|
|
301a972a53 | ||
|
|
290df59e02 | ||
|
|
3e2cde1e53 | ||
|
|
eb9a7b1939 | ||
|
|
7d3341b7a7 | ||
|
|
d78ae80ef1 | ||
|
|
316e7581cf | ||
|
|
36fe1f5a2f | ||
|
|
273a5b3e7e | ||
|
|
f9c30d230a | ||
|
|
bc200bfef6 | ||
|
|
13186767e8 | ||
|
|
d69c825555 | ||
|
|
56b109cc01 | ||
|
|
decfe17aa2 | ||
|
|
b55a82bf99 | ||
|
|
c052260a8b | ||
|
|
ee98ffd134 | ||
|
|
305d70fb6d | ||
|
|
e50b8b4bb3 | ||
|
|
ca0d24fd11 | ||
|
|
fa29a12d00 | ||
|
|
0ecd8d6166 | ||
|
|
c5fec9cbd1 | ||
|
|
11eae40857 | ||
|
|
604ddfbf97 | ||
|
|
1b45d68568 | ||
|
|
2bfa6e55db | ||
|
|
48c475ee9a | ||
|
|
8517327ee6 | ||
|
|
e2e6214159 | ||
|
|
7ac95c23a9 | ||
|
|
048d007430 |
40 changed files with 9852 additions and 356 deletions
3
.babelrc
Normal file
3
.babelrc
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"presets": ["@babel/env"]
|
||||
}
|
||||
1
.github/workflows/post-release.yaml
vendored
1
.github/workflows/post-release.yaml
vendored
|
|
@ -12,6 +12,7 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: ${{ github.event.repository.full_name }}
|
||||
ref: ${{ github.event.repository.default_branch }}
|
||||
fetch-depth: 0
|
||||
|
||||
|
|
|
|||
3
.github/workflows/prettier.yml
vendored
3
.github/workflows/prettier.yml
vendored
|
|
@ -14,11 +14,12 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: ${{ github.event.repository.full_name }}
|
||||
ref: ${{ github.head_ref }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Prettify code
|
||||
uses: creyD/prettier_action@v4.0
|
||||
uses: creyD/prettier_action@v4.1.1
|
||||
with:
|
||||
prettier_options: --write **/*.{js,css}
|
||||
same_commit: True
|
||||
|
|
|
|||
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
|
|
@ -28,7 +28,7 @@ jobs:
|
|||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "14"
|
||||
node-version: "15"
|
||||
|
||||
- name: Build Webpack
|
||||
run: |
|
||||
|
|
|
|||
21
.github/workflows/stale.yml
vendored
Normal file
21
.github/workflows/stale.yml
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
name: 'Close stale issues and PRs'
|
||||
on:
|
||||
schedule:
|
||||
- cron: '30 1 * * *'
|
||||
|
||||
jobs:
|
||||
stale:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/stale@v4
|
||||
with:
|
||||
stale-issue-message: 'This issue is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 7 days.'
|
||||
stale-pr-message: 'This PR is stale because it has been open 60 days with no activity. Remove stale label or comment or this will be closed in 15 days.'
|
||||
close-issue-message: 'This issue was closed because it has been stalled for 7 days with no activity.'
|
||||
close-pr-message: 'This PR was closed because it has been stalled for 15 days with no activity.'
|
||||
days-before-issue-stale: 60
|
||||
days-before-pr-stale: 60
|
||||
days-before-issue-close: 7
|
||||
days-before-pr-close: 15
|
||||
operations-per-run: 100
|
||||
ascending: true
|
||||
3
.github/workflows/webpack-test.yml
vendored
3
.github/workflows/webpack-test.yml
vendored
|
|
@ -10,6 +10,7 @@ jobs:
|
|||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
repository: ${{ github.event.repository.full_name }}
|
||||
ref: ${{ github.head_ref }}
|
||||
|
||||
- name: Get commit SHA
|
||||
|
|
@ -18,7 +19,7 @@ jobs:
|
|||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: "14"
|
||||
node-version: "15"
|
||||
|
||||
- name: Test-Build Webpack
|
||||
run: |
|
||||
|
|
|
|||
12
CHANGELOG.md
12
CHANGELOG.md
|
|
@ -1,5 +1,13 @@
|
|||
Added:
|
||||
- Ability to hide premium features in addition to ads
|
||||
- Ability to show current artist's genres
|
||||
|
||||
Fixed:
|
||||
- Weird pill-shaped background on Playlist pages title (#137)
|
||||
- Custom search input not being focussed after clicking
|
||||
- When changing songs, the color shifts to blue for a second (#179)
|
||||
|
||||
Improved:
|
||||
- Changed default `sidebar` color to be darker, so you won't get flashed green on startup
|
||||
- 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 notification styles to fit in with other elements of the theme
|
||||
- The visualizer icon when playing a song from a playlist is now colored
|
||||
|
|
@ -117,12 +117,12 @@ xpui.js_repl_8008=,`${1}58,
|
|||
|
||||
Write-Part "APPLYING";
|
||||
$backupVer = $configFile -match "^version"
|
||||
$version = ConvertFrom-StringData $backupVer[0]
|
||||
if ($version.version.Length -gt 0) {
|
||||
if ($backupVer.Length -gt 0) {
|
||||
spicetify apply
|
||||
} else {
|
||||
spicetify backup apply
|
||||
}
|
||||
Write-Done
|
||||
}
|
||||
else {
|
||||
Write-Part "`nYour Powershell version is less than "; Write-Emphasized "$PSMinVersion";
|
||||
|
|
|
|||
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"name": "Dribbblish Dynamic (Beta)",
|
||||
"description": "A mod of Dribbblish theme for Spicetify with support for light/dark modes and album art based colors. (Beta Release)",
|
||||
"branch": "release-beta",
|
||||
"preview": "https://raw.githubusercontent.com/JulienMaille/dribbblish-dynamic-theme/main/showcase-images/preview.gif",
|
||||
"readme": "https://raw.githubusercontent.com/JulienMaille/dribbblish-dynamic-theme/main/README.md",
|
||||
"usercss": "user.css",
|
||||
"schemes": "color.ini",
|
||||
"include": ["https://raw.githubusercontent.com/JulienMaille/dribbblish-dynamic-theme/release-beta/dribbblish-dynamic.js"]
|
||||
}
|
||||
22
manifest.json.rem
Normal file
22
manifest.json.rem
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
[
|
||||
{
|
||||
"name": "Dribbblish Dynamic",
|
||||
"description": "A mod of Dribbblish theme for Spicetify with support for light/dark modes and album art based colors. (Beta Release)",
|
||||
"branch": "release-stable",
|
||||
"preview": "https://raw.githubusercontent.com/JulienMaille/dribbblish-dynamic-theme/main/showcase-images/preview.gif",
|
||||
"readme": "https://raw.githubusercontent.com/JulienMaille/dribbblish-dynamic-theme/main/README.md",
|
||||
"usercss": "user.css",
|
||||
"schemes": "color.ini",
|
||||
"include": ["https://raw.githubusercontent.com/JulienMaille/dribbblish-dynamic-theme/release-stable/dribbblish-dynamic.js"]
|
||||
},
|
||||
{
|
||||
"name": "Dribbblish Dynamic (Beta)",
|
||||
"description": "A mod of Dribbblish theme for Spicetify with support for light/dark modes and album art based colors. (Beta Release)",
|
||||
"branch": "release-beta",
|
||||
"preview": "https://raw.githubusercontent.com/JulienMaille/dribbblish-dynamic-theme/main/showcase-images/preview.gif",
|
||||
"readme": "https://raw.githubusercontent.com/JulienMaille/dribbblish-dynamic-theme/main/README.md",
|
||||
"usercss": "user.css",
|
||||
"schemes": "color.ini",
|
||||
"include": ["https://raw.githubusercontent.com/JulienMaille/dribbblish-dynamic-theme/release-beta/dribbblish-dynamic.js"]
|
||||
}
|
||||
]
|
||||
9109
package-lock.json
generated
Normal file
9109
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
15
package.json
15
package.json
|
|
@ -1,11 +1,14 @@
|
|||
{
|
||||
"name": "dribbblish-dynamic-theme",
|
||||
"version": "4.1.0",
|
||||
"version": "4.1.1",
|
||||
"homepage": "https://github.com/JulienMaille/dribbblish-dynamic-theme",
|
||||
"bugs": {
|
||||
"url": "https://github.com/JulienMaille/dribbblish-dynamic-theme/issues"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.0",
|
||||
"@babel/preset-env": "^7.16.5",
|
||||
"@babel/register": "^7.16.5",
|
||||
"@material-icons/svg": "^1.0.22",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"sass": "^1.43.5",
|
||||
|
|
@ -14,16 +17,18 @@
|
|||
"webpack-cli": "^4.9.0"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --mode=development"
|
||||
"build": "webpack"
|
||||
},
|
||||
"dependencies": {
|
||||
"chroma-js": "^2.1.2",
|
||||
"colorthief": "^2.3.2",
|
||||
"jquery": "^3.6.0",
|
||||
"markdown-it": "^12.2.0",
|
||||
"lodash.debounce": "^4.0.8",
|
||||
"lodash.defaultsdeep": "^4.6.1",
|
||||
"markdown-it": "^12.3.2",
|
||||
"markdown-it-attrs": "^4.1.0",
|
||||
"moment": "^2.29.1",
|
||||
"moment": "^2.29.2",
|
||||
"node-vibrant": "^3.1.6",
|
||||
"svgson": "^5.2.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,20 @@
|
|||
$sp = "$env:APPDATA\Spotify\Spotify.exe"
|
||||
Get-Process -Name Spotify -ErrorAction SilentlyContinue | Stop-Process -Force
|
||||
Get-Process -Name SpotifyWebHelper -ErrorAction SilentlyContinue | Stop-Process -Force
|
||||
|
||||
$sp = spicetify config spotify_path
|
||||
$sp += "\Spotify.exe"
|
||||
Copy-Item $sp ($sp + ".backup")
|
||||
|
||||
$bytes = [System.IO.File]::ReadAllBytes($sp);
|
||||
$toRemove = [System.Text.Encoding]::UTF8.GetBytes("force-dark-mode");
|
||||
|
||||
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
||||
for ($i = 0; $i -lt $bytes.Length; $i++) {
|
||||
if ($sw.Elapsed.TotalMilliseconds -ge 1000) {
|
||||
Write-Progress -Activity "Enabling dark mode in Spotify.exe" -status "Patching binary file $i" -percentComplete ($i / $bytes.Length*100);
|
||||
$sw.Reset();
|
||||
$sw.Start();
|
||||
}
|
||||
$found = $true
|
||||
for ($j = 0; $j -lt $toRemove.Length; $j++) {
|
||||
if ($bytes[$i + $j] -ne $toRemove[$j]) {
|
||||
|
|
@ -21,4 +31,9 @@ for ($i = 0; $i -lt $bytes.Length; $i++) {
|
|||
}
|
||||
}
|
||||
|
||||
[System.IO.File]::WriteAllBytes($sp, $bytes);
|
||||
[System.IO.File]::WriteAllBytes($sp, $bytes);
|
||||
if ( $found ) {
|
||||
Write-Host "The patch is complete." -ForegroundColor "Green"
|
||||
} else {
|
||||
Write-Host "Failed to patch the file." -ForegroundColor "Red"
|
||||
}
|
||||
|
|
|
|||
131
src/icons/equaliser.svg
Normal file
131
src/icons/equaliser.svg
Normal 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 |
42
src/icons/loading.svg
Normal file
42
src/icons/loading.svg
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
<svg viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<style>
|
||||
/* From https://codepen.io/mrrocks/pen/EiplA */
|
||||
@keyframes loader-rotator {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes loader-dash {
|
||||
0% {
|
||||
stroke-dashoffset: 187;
|
||||
}
|
||||
50% {
|
||||
stroke-dashoffset: 46.75;
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: 187;
|
||||
transform: rotate(450deg);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
svg[icon-type="dribbblish"][icon-name="loading"] {
|
||||
animation: loader-rotator 1.4s linear infinite;
|
||||
}
|
||||
|
||||
svg[icon-type="dribbblish"][icon-name="loading"] circle {
|
||||
stroke-dasharray: 187;
|
||||
stroke-dashoffset: 0;
|
||||
transform-origin: center;
|
||||
animation: loader-dash 1.4s ease-in-out infinite;
|
||||
}
|
||||
</style>
|
||||
</defs>
|
||||
<circle fill="none" stroke="currentColor" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.3 KiB |
|
|
@ -1,6 +1,6 @@
|
|||
import $ from "jquery";
|
||||
|
||||
import { renderMD } from "./Util";
|
||||
import { renderMD, defaults } from "./Util";
|
||||
import { icons } from "./Icons";
|
||||
|
||||
export default class ConfigMenu {
|
||||
|
|
@ -125,7 +125,7 @@ export default class ConfigMenu {
|
|||
parent: null
|
||||
};
|
||||
// Set Defaults
|
||||
options = { ...defaultOptions, ...options };
|
||||
options = defaults(options, defaultOptions);
|
||||
if (typeof options.area == "string") options.area = { name: options.area, order: 0 };
|
||||
options.description = options.description
|
||||
.split("\n")
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
import ConfigMenu from "./ConfigMenu";
|
||||
import Info from "./Info";
|
||||
import Loader from "./Loader";
|
||||
import { icons } from "./Icons";
|
||||
import Overlay from "./Overlay";
|
||||
import Icon, { icons } from "./Icons";
|
||||
|
||||
export default class Dribbblish {
|
||||
/**
|
||||
|
|
@ -23,7 +24,10 @@ export default class Dribbblish {
|
|||
/** @type {Loader} */
|
||||
loader;
|
||||
|
||||
/** @type {Icons} */
|
||||
/** @type {Overlay} */
|
||||
overlay;
|
||||
|
||||
/** @type {Icon} */
|
||||
icons;
|
||||
|
||||
/** @type {Object.<string, listener[]>} */
|
||||
|
|
@ -36,9 +40,12 @@ export default class Dribbblish {
|
|||
this.config = new ConfigMenu();
|
||||
this.info = new Info();
|
||||
this.loader = new Loader();
|
||||
this.overlay = new Overlay();
|
||||
this.icons = icons;
|
||||
|
||||
let tries = 0;
|
||||
const interval = setInterval(() => {
|
||||
if (++tries > 50) throw new Error("ready timeout");
|
||||
if (document.querySelector("#main") == null || Spicetify?.showNotification == undefined || !this.info.isReady()) return;
|
||||
this.#ready = true;
|
||||
this.emit("ready");
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { defaults } from "./Util";
|
||||
import { parseSync as parseSVG, stringify as stringifySVG } from "svgson";
|
||||
|
||||
export default class Icons {
|
||||
|
|
@ -6,6 +7,7 @@ export default class Icons {
|
|||
/**
|
||||
* @typedef {Object} IconOptions
|
||||
* @property {IconStyle} [style="round"]
|
||||
* @property {String} [className=""]
|
||||
* @property {Number} [size=16]
|
||||
* @property {Number} [scale=1]
|
||||
* @property {String} [fill="currentColor"]
|
||||
|
|
@ -15,8 +17,8 @@ export default class Icons {
|
|||
/** @type {Object.<String, Object.<IconStyle, String>>} */
|
||||
#icons;
|
||||
|
||||
constructor() {
|
||||
this.#icons = process.env.DRIBBBLISH_ICONS;
|
||||
constructor(icons) {
|
||||
this.#icons = icons ?? process.env.DRIBBBLISH_ICONS;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -66,32 +68,42 @@ export default class Icons {
|
|||
/** @type {IconOptions} */
|
||||
const defaultOptions = {
|
||||
style: this.#getDefaultStyle(name),
|
||||
className: "",
|
||||
size: 16,
|
||||
scale: 1,
|
||||
fill: "currentColor",
|
||||
base64: false
|
||||
};
|
||||
options = { ...defaultOptions, ...options };
|
||||
options = defaults(options, defaultOptions);
|
||||
|
||||
const svg = parseSVG(this.getRawSVG(name, options.style));
|
||||
|
||||
// Add general / required attributes
|
||||
svg.attributes["icon-type"] = "dribbblish";
|
||||
svg.attributes["icon-name"] = name;
|
||||
svg.attributes["icon-style"] = options.style;
|
||||
svg.attributes.fill = options.fill;
|
||||
svg.attributes.width = options.size;
|
||||
svg.attributes.height = options.size;
|
||||
|
||||
// Create CSSStyleDeclaration by creating an element since there is no constructor for it
|
||||
const styles = document.createElement("a").style;
|
||||
// Add className
|
||||
if (options.className != "") svg.attributes.class = options.className;
|
||||
|
||||
// Add Styles
|
||||
const styles = {};
|
||||
if (options.scale != 1) {
|
||||
styles.transform = `scale(${options.scale})`;
|
||||
styles.transformOrigin = "center";
|
||||
styles["transform"] = `scale(${options.scale})`;
|
||||
styles["transform-origin"] = "center";
|
||||
}
|
||||
const styleStr = Object.entries(styles)
|
||||
.map(([prop, val]) => `${prop}: ${val};`)
|
||||
.join(" ");
|
||||
svg.children = svg.children.map((child) => {
|
||||
if (styles.cssText != "") child.attributes.style = styles.cssText;
|
||||
if (styleStr != "") child.attributes.style = styleStr;
|
||||
return child;
|
||||
});
|
||||
|
||||
// Add title
|
||||
if (options.title != null) {
|
||||
svg.children.push({
|
||||
name: "title",
|
||||
|
|
|
|||
|
|
@ -1,28 +1,18 @@
|
|||
import Overlay from "./Overlay";
|
||||
|
||||
export default class Loader {
|
||||
/** @type {HTMLDivElement} */
|
||||
#container;
|
||||
/** @type {Overlay} */
|
||||
#overlay;
|
||||
|
||||
constructor() {
|
||||
this.#container = document.createElement("div");
|
||||
this.#container.id = "dribbblish-loader";
|
||||
this.#container.innerHTML = /* html */ `
|
||||
<div>
|
||||
<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>
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
document.body.appendChild(this.#container);
|
||||
this.#overlay = new Overlay();
|
||||
}
|
||||
|
||||
show(text) {
|
||||
this.#container.querySelector("span").innerText = text ?? "";
|
||||
this.#container.setAttribute("active", "");
|
||||
this.#overlay.show({ icon: "loading", text });
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.#container.removeAttribute("active");
|
||||
this.#overlay.hide();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
68
src/js/Overlay.js
Normal file
68
src/js/Overlay.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
import { defaults } from "./Util";
|
||||
import { icons } from "./Icons";
|
||||
|
||||
export default class Overlay {
|
||||
/**
|
||||
* @typedef {Object} DribbblishOverlayOptions
|
||||
* @property {String} icon
|
||||
* @property {String} text
|
||||
* @property {DribbblishOverlayColor} color
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} DribbblishOverlayColor
|
||||
* @property {String} [icon]
|
||||
* @property {String} [text]
|
||||
*/
|
||||
|
||||
/** @type {HTMLDivElement} */
|
||||
#container;
|
||||
|
||||
/** @type {HTMLElement} */
|
||||
#iconElem;
|
||||
|
||||
/** @type {HTMLSpanElement} */
|
||||
#textElem;
|
||||
|
||||
constructor() {
|
||||
this.#container = document.createElement("div");
|
||||
this.#container.id = "dribbblish-overlay";
|
||||
this.#container.innerHTML = /* html */ `
|
||||
<div>
|
||||
<i></i>
|
||||
<span>Loading...</span>
|
||||
</div>
|
||||
`;
|
||||
|
||||
this.#iconElem = this.#container.querySelector("i");
|
||||
this.#textElem = this.#container.querySelector("span");
|
||||
|
||||
document.body.appendChild(this.#container);
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {DribbblishOverlayOptions} options
|
||||
*/
|
||||
show(options) {
|
||||
const defaultOptions = {
|
||||
icon: "",
|
||||
text: "",
|
||||
color: {
|
||||
icon: "var(--spice-text)",
|
||||
text: "var(--spice-subtext)"
|
||||
}
|
||||
};
|
||||
options = defaults(options, defaultOptions);
|
||||
if (options.icon != "" && !options.icon.startsWith("<svg")) options.icon = icons.get(options.icon, { size: 64 });
|
||||
this.#iconElem.innerHTML = options.icon;
|
||||
this.#iconElem.style.setProperty("--color", options.color.icon);
|
||||
this.#textElem.innerHTML = options.text;
|
||||
this.#textElem.style.setProperty("--color", options.color.text);
|
||||
this.#container.setAttribute("active", "");
|
||||
}
|
||||
|
||||
hide() {
|
||||
this.#container.removeAttribute("active");
|
||||
}
|
||||
}
|
||||
13
src/js/SassUtil.js
Normal file
13
src/js/SassUtil.js
Normal 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)})`;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,7 @@
|
|||
import MarkdownIt from "markdown-it";
|
||||
import MarkdownItAttrs from "markdown-it-attrs";
|
||||
import defaultsDeep from "lodash.defaultsdeep";
|
||||
import { default as _debounce } from "lodash.debounce";
|
||||
|
||||
/**
|
||||
* @callback waitForElCb
|
||||
|
|
@ -69,22 +71,25 @@ export function getRandomInt(min, max) {
|
|||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {T[]} arr
|
||||
* @returns {T}
|
||||
*/
|
||||
export function randomFromArray(arr) {
|
||||
return arr[Math.floor(Math.random() * arr.length)];
|
||||
}
|
||||
|
||||
export function debounce(func, wait, immediate) {
|
||||
var timeout;
|
||||
return function () {
|
||||
var context = this,
|
||||
args = arguments;
|
||||
var later = function () {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
};
|
||||
var callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
if (callNow) func.apply(context, args);
|
||||
};
|
||||
/** @type {_debounce} */
|
||||
export function debounce(fn, wait, opts) {
|
||||
return _debounce(fn, wait, opts);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} options
|
||||
* @param {...Object} defaults
|
||||
* @returns {Object}
|
||||
*/
|
||||
export function defaults(options, ...defaults) {
|
||||
return defaultsDeep(options, ...defaults);
|
||||
}
|
||||
|
|
|
|||
151
src/js/main.js
151
src/js/main.js
|
|
@ -12,6 +12,7 @@ $("html").attr("dribbblish-js-installed", "");
|
|||
import { waitForElement, copyToClipboard, capitalizeFirstLetter, getClosestToNum, randomFromArray, debounce } from "./Util";
|
||||
import { default as _Dribbblish } from "./Dribbblish";
|
||||
import "./Folders";
|
||||
import { spiceColor } from "./SassUtil";
|
||||
|
||||
// To expose to external scripts
|
||||
const Dribbblish = new _Dribbblish();
|
||||
|
|
@ -47,8 +48,8 @@ Dribbblish.on("ready", () => {
|
|||
? {
|
||||
icon: "settings",
|
||||
color: {
|
||||
fg: "var(--spice-subtext)",
|
||||
bg: "rgba(var(--spice-rgb-subtext), calc(0.1 + var(--is_light) * 0.05))"
|
||||
fg: spiceColor("subtext"),
|
||||
bg: spiceColor("subtext", 0.1, 0.05)
|
||||
},
|
||||
order: 999,
|
||||
tooltip: "Open Dribbblish Settings",
|
||||
|
|
@ -76,7 +77,7 @@ Dribbblish.on("ready", () => {
|
|||
input.setAttribute("spellcheck", "false");
|
||||
input.addEventListener("click", (e) => {
|
||||
if (!Spicetify.Platform.History.location.pathname.startsWith("/search")) Spicetify.Platform.History.push(`/search/${input.value}`);
|
||||
waitForElement([`[data-testid="search-input"]`], ([defaultSearch]) => {
|
||||
waitForElement([`.main-topBar-topbarContent form[role="search"]`], ([defaultSearch]) => {
|
||||
input.focus();
|
||||
});
|
||||
});
|
||||
|
|
@ -216,13 +217,28 @@ Dribbblish.on("ready", () => {
|
|||
});
|
||||
|
||||
Dribbblish.config.register({
|
||||
order: 999,
|
||||
area: "Playbar",
|
||||
type: "checkbox",
|
||||
key: "hideAds",
|
||||
name: "Hide Ads",
|
||||
description: `Hide ads / premium features (see: [SpotifyNoPremium](https://github.com/Daksh777/SpotifyNoPremium))`,
|
||||
key: "showGenreInfoInPlaybar",
|
||||
name: "Show Genre Info in Playbar",
|
||||
description: "Show artist's genres in the Playbar",
|
||||
defaultValue: false,
|
||||
onChange: (val) => $("#main").attr("hide-ads", val)
|
||||
onChange: (val) => $("#main").attr("playbar-genre-info", val)
|
||||
});
|
||||
|
||||
Dribbblish.config.register({
|
||||
order: 999,
|
||||
type: "select",
|
||||
data: { none: "Hide Nothing", ads: "Hide Ads", premium: "Hide Premium Features", both: "Hide Both" },
|
||||
key: "hideAdsOrPremium",
|
||||
name: "Hide Ads / Premium Features",
|
||||
description: `Hide ads / premium features like Fullscreen and Download Buttons (see: [SpotifyNoPremium](https://github.com/Daksh777/SpotifyNoPremium))`,
|
||||
defaultValue: "none",
|
||||
onChange: (val) => {
|
||||
if (val == "none") return $("#main").attr("hide-ads", null);
|
||||
if (val == "both") return $("#main").attr("hide-ads", "ads premium");
|
||||
$("#main").attr("hide-ads", val);
|
||||
}
|
||||
});
|
||||
|
||||
waitForElement([".main-rootlist-rootlist", ".main-rootlist-wrapper > :nth-child(2) > :first-child", "#spicetify-show-list"], ([rootlist]) => {
|
||||
|
|
@ -363,11 +379,11 @@ Dribbblish.on("ready", () => {
|
|||
key: "aboutDribbblishInfo",
|
||||
name: "Info",
|
||||
description: `
|
||||
OS: \`${capitalizeFirstLetter(Spicetify.Platform.PlatformData.os_name)} v${Spicetify.Platform.PlatformData.os_version}\`
|
||||
Spotify: \`v${Spicetify.Platform.PlatformData.event_sender_context_information?.client_version_string ?? Spicetify.Platform.PlatformData.client_version_triple}\`
|
||||
Spicetify: \`${Spicetify.version != null ? `v${Spicetify.version}` : "< v2.7.3"}\`
|
||||
Dribbblish: \`v${process.env.DRIBBBLISH_VERSION}-${process.env.COMMIT_HASH}\`
|
||||
`,
|
||||
OS: \`${capitalizeFirstLetter(Spicetify.Platform.PlatformData.os_name)} v${Spicetify.Platform.PlatformData.os_version}\`
|
||||
Spotify: \`v${Spicetify.Platform.PlatformData.event_sender_context_information?.client_version_string ?? Spicetify.Platform.PlatformData.client_version_triple}\`
|
||||
Spicetify: \`${Spicetify.version != null ? `v${Spicetify.version}` : "< v2.7.3"}\`
|
||||
Dribbblish: \`v${process.env.DRIBBBLISH_VERSION}-${process.env.COMMIT_HASH}\`
|
||||
`,
|
||||
data: "Copy",
|
||||
onChange: function () {
|
||||
copyToClipboard(this.description.replace(/\`/g, ""));
|
||||
|
|
@ -384,30 +400,29 @@ Dribbblish.on("ready", () => {
|
|||
data: "Create Report",
|
||||
onChange: () => {
|
||||
const reportBody = `
|
||||
${process.env.BUG_REPORT}
|
||||
${process.env.BUG_REPORT}
|
||||
|
||||
<!-- Leave the lines below as they are -->
|
||||
---
|
||||
<!-- Leave the lines below as they are -->
|
||||
---
|
||||
|
||||
### Info for Contributors:
|
||||
|
||||
**Versions**
|
||||
${Dribbblish.config.getOptions("aboutDribbblishInfo").description}
|
||||
<details>
|
||||
<summary>Info for Contributors</summary>
|
||||
|
||||
**Extensions**
|
||||
${$(`script[src^="extensions/"]`)
|
||||
.toArray()
|
||||
.map((e) => `- ${e.src.split("/").slice(-1)[0]}`)
|
||||
.join("\n")}
|
||||
**Versions**
|
||||
${Dribbblish.config.getOptions("aboutDribbblishInfo").description.split("\n").join("\n ")}
|
||||
|
||||
**Settings**
|
||||
\`\`\`json
|
||||
${JSON.stringify(Dribbblish.config.export(), null, 4)}
|
||||
\`\`\`
|
||||
`
|
||||
.split("\n")
|
||||
.map((line) => line.replace(/^ {16}/, ""))
|
||||
.join("\n");
|
||||
**Extensions**
|
||||
${$(`script[src^="extensions/"]`)
|
||||
.toArray()
|
||||
.map((e) => `- ${e.src.split("/").slice(-1)[0]}`)
|
||||
.join("\n ")}
|
||||
|
||||
**Settings**
|
||||
\`\`\`json
|
||||
${JSON.stringify(Dribbblish.config.export(), null, 4).split("\n").join("\n ")}
|
||||
\`\`\`
|
||||
</details>
|
||||
`.replace(/^ {12}/gm, "");
|
||||
|
||||
const reportURL = new URL("https://github.com/JulienMaille/dribbblish-dynamic-theme/issues/new");
|
||||
reportURL.searchParams.set("labels", "bug");
|
||||
|
|
@ -445,8 +460,13 @@ Dribbblish.on("ready", () => {
|
|||
|
||||
/* js */
|
||||
async function getAlbumRelease(uri) {
|
||||
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 };
|
||||
const info = await Spicetify.CosmosAsync.get(`https://api.spotify.com/v1/albums/${uri}`);
|
||||
return { year: info.release_date };
|
||||
}
|
||||
|
||||
async function getGenres(uri) {
|
||||
const res = await Spicetify.CosmosAsync.get(`https://api.spotify.com/v1/artists/${uri}`);
|
||||
return res.genres.slice(0, 3);
|
||||
}
|
||||
|
||||
function isLight(hex) {
|
||||
|
|
@ -545,11 +565,10 @@ Dribbblish.on("ready", () => {
|
|||
Algorithm of selecting colors from the albumart
|
||||
- **Colorthief [(see)](https://lokeshdhakar.com/projects/color-thief/):** Gets more fitting colors
|
||||
- **Vibrant [(see)](https://jariz.github.io/vibrant.js/):** Gets more vibrant colors *(was the default up to v3.1.1)*
|
||||
- **Spotify:** Basically Vibrant but internal and without support of local files
|
||||
- **Static:** Select a static color to be used
|
||||
{.muted}
|
||||
`,
|
||||
data: { spotify: "Spotify", colorthief: "Colorthief", vibrant: "Vibrant", static: "Static" },
|
||||
data: { colorthief: "Colorthief", vibrant: "Vibrant", static: "Static" },
|
||||
defaultValue: "colorthief",
|
||||
onChange: () => updateColors(),
|
||||
showChildren: (val) => {
|
||||
|
|
@ -733,8 +752,19 @@ Dribbblish.on("ready", () => {
|
|||
}
|
||||
const albumInfoSpan = document.getElementById("main-trackInfo-year");
|
||||
|
||||
let album_uri = Spicetify.Player.data.track.metadata.album_uri;
|
||||
let bgImage = Spicetify.Player.data.track.metadata.image_url;
|
||||
if (!document.getElementById("main-trackInfo-genre")) {
|
||||
const el = document.createElement("div");
|
||||
el.classList.add("main-trackInfo-release", "standalone-ellipsis-one-line", "main-type-finale");
|
||||
el.setAttribute("as", "div");
|
||||
el.id = "main-trackInfo-genre";
|
||||
document.querySelector(".main-trackInfo-container").append(el);
|
||||
}
|
||||
const genreInfoSpan = document.getElementById("main-trackInfo-genre");
|
||||
|
||||
let track = Spicetify.Player.data.track;
|
||||
let album_uri = track.metadata.album_uri;
|
||||
let artist_uri = track.metadata.artist_uri;
|
||||
let bgImage = track.metadata.image_url;
|
||||
if (bgImage === undefined) {
|
||||
bgImage = "/images/tracklist-row-song-fallback.svg";
|
||||
}
|
||||
|
|
@ -745,22 +775,37 @@ Dribbblish.on("ready", () => {
|
|||
const albumLinkElem = /* html */ `
|
||||
<span>
|
||||
<span draggable="true">
|
||||
<a draggable="false" dir="auto" href="${album_uri}">${Spicetify.Player.data.track.metadata.album_title}</a>
|
||||
<a draggable="false" dir="auto" href="${album_uri}">${track.metadata.album_title}</a>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
const albumDateElem = /* html */ `<span> • <span title="${albumDate.format("L")}">${albumDate.format(moment().diff(albumDate, "months") <= 6 ? "MMM YYYY" : "YYYY")}</span></span>`;
|
||||
albumInfoSpan.innerHTML = `${albumLinkElem}${albumDateElem}`;
|
||||
} else if (Spicetify.Player.data.track.uri.includes("spotify:episode")) {
|
||||
|
||||
let genres = "";
|
||||
if (!album_uri.includes("spotify:episode")) {
|
||||
genres = await getGenres(artist_uri.replace("spotify:artist:", ""));
|
||||
}
|
||||
genreInfoSpan.innerHTML = /* html */ `
|
||||
<span>
|
||||
<span draggable="true">
|
||||
<span draggable="false" dir="auto">${genres.join(", ")}</span>
|
||||
</span>
|
||||
</span>
|
||||
`;
|
||||
} else if (track.uri.includes("spotify:episode")) {
|
||||
// podcast
|
||||
bgImage = bgImage.replace("spotify:image:", "https://i.scdn.co/image/");
|
||||
albumInfoSpan.innerHTML = Spicetify.Player.data.track.metadata.album_title;
|
||||
} else if (Spicetify.Player.data.track.metadata.is_local == "true") {
|
||||
albumInfoSpan.innerHTML = track.metadata.album_title;
|
||||
genreInfoSpan.innerHTML = "";
|
||||
} else if (track.metadata.is_local == "true") {
|
||||
// local file
|
||||
albumInfoSpan.innerHTML = Spicetify.Player.data.track.metadata.album_title;
|
||||
} else if (Spicetify.Player.data.track.provider == "ad") {
|
||||
albumInfoSpan.innerHTML = track.metadata.album_title;
|
||||
genreInfoSpan.innerHTML = "";
|
||||
} else if (track.provider == "ad") {
|
||||
// ad
|
||||
albumInfoSpan.innerHTML = "Advertisement";
|
||||
genreInfoSpan.innerHTML = "";
|
||||
return;
|
||||
} else {
|
||||
// When clicking a song from the homepage, songChange is fired with half empty metadata
|
||||
|
|
@ -780,19 +825,13 @@ Dribbblish.on("ready", () => {
|
|||
|
||||
$("html").css("--image-brightness", getImageLightness(img) / 255);
|
||||
|
||||
let color = "#509bf5";
|
||||
if (img.complete) {
|
||||
let color = "#1ed760";
|
||||
const colorSelectionAlgorithm = Dribbblish.config.get("colorSelectionAlgorithm");
|
||||
const colorSelectionMode = Dribbblish.config.get("colorSelectionMode");
|
||||
let palette = {};
|
||||
|
||||
if (colorSelectionAlgorithm == "spotify") {
|
||||
const swatches = await Spicetify.colorExtractor(Spicetify.Player.data.track.uri);
|
||||
for (const col of ["VIBRANT", "VIBRANT_NON_ALARMING", "PROMINENT", "DARK_VIBRANT", "LIGHT_VIBRANT", "DESATURATED"]) {
|
||||
const c = chroma(swatches[col]);
|
||||
palette[c.luminance()] = c;
|
||||
}
|
||||
} else if (colorSelectionAlgorithm == "colorthief") {
|
||||
if (colorSelectionAlgorithm == "colorthief") {
|
||||
palette = Object.fromEntries([colorThief.getColor(img), ...colorThief.getPalette(img, 24, 5)].map((c) => chroma(c)).map((c) => [c.luminance(), c]));
|
||||
} else if (colorSelectionAlgorithm == "vibrant") {
|
||||
const swatches = await new Promise((resolve, reject) => new Vibrant(img, 5).getPalette().then(resolve).catch(reject));
|
||||
|
|
@ -818,9 +857,9 @@ Dribbblish.on("ready", () => {
|
|||
const wantedLuminance = $("html").css("--is_light") == "1" ? Dribbblish.config.get("lightModeLuminance") : Dribbblish.config.get("darkModeLuminance");
|
||||
color = palette[getClosestToNum(Object.keys(palette), wantedLuminance)].hex();
|
||||
}
|
||||
}
|
||||
|
||||
updateColors(false, color);
|
||||
updateColors(false, color);
|
||||
}
|
||||
}
|
||||
|
||||
var coverListener;
|
||||
|
|
@ -852,7 +891,7 @@ Dribbblish.on("ready", () => {
|
|||
fetch("https://api.github.com/repos/JulienMaille/dribbblish-dynamic-theme/releases/latest")
|
||||
.then((response) => response.json())
|
||||
.then((data) => {
|
||||
Dribbblish.info.set("dribbblish-update", data.tag_name > process.env.DRIBBBLISH_VERSION ? { text: `v${data.tag_name}`, tooltip: "Nev Dribbblish version available", icon: "palette", onClick: () => window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme/releases/latest", "_blank") } : null);
|
||||
Dribbblish.info.set("dribbblish-update", data.tag_name > process.env.DRIBBBLISH_VERSION ? { text: `v${data.tag_name}`, tooltip: "New Dribbblish version available", icon: "palette", onClick: () => window.open("https://github.com/JulienMaille/dribbblish-dynamic-theme/releases/latest", "_blank") } : null);
|
||||
})
|
||||
.catch(console.error);
|
||||
|
||||
|
|
|
|||
|
|
@ -44,16 +44,3 @@ $props-to-transition: ("sidebar", "main", "text", "button");
|
|||
transition: all var(--song-transition-speed) linear;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,16 +23,13 @@
|
|||
z-index: 1;
|
||||
position: relative;
|
||||
width: clamp(500px, 50%, 650px);
|
||||
background-color: spiceColor("main", 0.95);
|
||||
backdrop-filter: blur(3px);
|
||||
padding: 20px 15px;
|
||||
border-radius: var(--main-corner-radius);
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@include spiceShadow();
|
||||
@include spiceGlass();
|
||||
|
||||
> h2 {
|
||||
font-size: 32px;
|
||||
|
|
|
|||
|
|
@ -1,13 +1,6 @@
|
|||
.connect-device-list-container {
|
||||
$border-color: spiceColor("subtext", 0.1, 0.1);
|
||||
|
||||
border: 1px solid $border-color;
|
||||
border-radius: var(--main-corner-radius);
|
||||
padding: 8px;
|
||||
background-color: spiceColor("main", 0.75, -0.1) !important;
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: var(--main-corner-radius);
|
||||
@include spiceShadow();
|
||||
@include spiceGlass(lightOffset(0.8, -0.1));
|
||||
|
||||
&::before {
|
||||
display: none;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
.main-contextMenu-menu {
|
||||
$border-color: spiceColor("subtext", 0.1, 0.1);
|
||||
|
||||
position: relative;
|
||||
overflow: visible;
|
||||
background-color: transparent !important;
|
||||
border: 1px solid $border-color;
|
||||
border-radius: var(--main-corner-radius);
|
||||
padding: 8px;
|
||||
|
||||
|
|
@ -11,10 +10,7 @@
|
|||
content: "";
|
||||
position: absolute;
|
||||
inset: 0px;
|
||||
background-color: spiceColor("main", 0.75, -0.1) !important;
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: var(--main-corner-radius);
|
||||
@include spiceShadow();
|
||||
@include spiceGlass(lightOffset(0.8, -0.1));
|
||||
}
|
||||
|
||||
.main-contextMenu-menuItem {
|
||||
|
|
@ -32,7 +28,7 @@
|
|||
&::after {
|
||||
left: 8px;
|
||||
right: 8px;
|
||||
border-color: $border-color;
|
||||
border-color: spiceColor("subtext", 0.1, 0.1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
32
src/styles/CustomAppTabBar.scss
Normal file
32
src/styles/CustomAppTabBar.scss
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
.main-topBar-topbarContent {
|
||||
height: 100%;
|
||||
|
||||
& > nav[class*="-tabBar"][class*="-tabBar-nav"] {
|
||||
height: 100%;
|
||||
|
||||
& > ul {
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
height: 100%;
|
||||
|
||||
li[class*="-tabBar-headerItem"] {
|
||||
height: 100%;
|
||||
|
||||
& > a {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin: 0px;
|
||||
height: 100%;
|
||||
padding: 0px 8px;
|
||||
border-radius: var(--sidebar-icons-border-radius);
|
||||
|
||||
& > span {
|
||||
line-height: 13px;
|
||||
@include spiceFont("glue", 14px, "Medium");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
button.main-button {
|
||||
.main-button {
|
||||
&-primary {
|
||||
$color: spiceColor("subtext");
|
||||
color: $color;
|
||||
|
|
|
|||
|
|
@ -1,75 +0,0 @@
|
|||
// 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;
|
||||
color: spiceColor("subtext");
|
||||
@include spiceFont("glue", 32px, "Bold");
|
||||
|
||||
&[active] {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
&::before {
|
||||
z-index: -1;
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0px;
|
||||
background-color: spiceColor("main", 0.9, -0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
& > div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
|
||||
svg {
|
||||
animation: rotator $duration linear infinite;
|
||||
|
||||
circle {
|
||||
stroke: spiceColor("text");
|
||||
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);
|
||||
}
|
||||
}
|
||||
1
src/styles/Lyrics.scss
Normal file
1
src/styles/Lyrics.scss
Normal file
|
|
@ -0,0 +1 @@
|
|||
// TODO: improve default lyrics styles when the classes are mapped `see: https://github.com/JulienMaille/dribbblish-dynamic-theme/issues/144`
|
||||
|
|
@ -5,15 +5,12 @@
|
|||
.GenericModal {
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
background-color: spiceColor("main", 0.95);
|
||||
backdrop-filter: blur(3px);
|
||||
padding: 24px 16px;
|
||||
border-radius: var(--main-corner-radius);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@include spiceShadow();
|
||||
@include spiceGlass();
|
||||
|
||||
// Popups (`Spicetify.PopupModal.display()`)
|
||||
generic-modal & {
|
||||
|
|
@ -30,34 +27,40 @@
|
|||
}
|
||||
}
|
||||
|
||||
.main-trackCreditsModal-container {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
background-color: transparent;
|
||||
width: 100%;
|
||||
|
||||
.main-trackCreditsModal-header {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
.main- {
|
||||
&trackCreditsModal,
|
||||
&embedWidgetGenerator {
|
||||
&-container {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
background-color: transparent;
|
||||
width: 100%;
|
||||
@include spiceFont("glue", 2em, "Bold");
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
button {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
}
|
||||
&-header {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
|
||||
.main-trackCreditsModal-mainSection {
|
||||
padding: 0px 26px;
|
||||
h1 {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
@include spiceFont("glue", 2em, "Bold");
|
||||
}
|
||||
|
||||
button {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
&-mainSection {
|
||||
padding: 0px 26px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,17 +1,31 @@
|
|||
#main[hide-ads="true"] {
|
||||
/* Remove upgrade button*/
|
||||
.main-topBar-UpgradeButton {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Remove upgrade to premium button in user menu */
|
||||
.main-contextMenu-menuItemButton[href="https://www.spotify.com/premium/"]
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
|
||||
/* Remove ad placeholder in main screen */
|
||||
// Hide ads
|
||||
#main[hide-ads~="ads"] {
|
||||
// Remove ad placeholder in main screen
|
||||
.main-leaderboardComponent-container {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide premium features
|
||||
#main[hide-ads~="premium"] {
|
||||
// Remove upgrade button
|
||||
.main-topBar-UpgradeButton {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Remove upgrade to premium button in user menu
|
||||
// prettier-ignore
|
||||
.main-contextMenu-menuItemButton[href="https://www.spotify.com/premium/"] {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Hide fullscreen button
|
||||
.volume-bar + .control-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
// Hide download buttons
|
||||
.main-actionBar-ActionBarRow button[role="switch"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
42
src/styles/Overlay.scss
Normal file
42
src/styles/Overlay.scss
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#dribbblish-overlay {
|
||||
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;
|
||||
color: spiceColor("subtext");
|
||||
@include spiceFont("glue", 32px, "Bold");
|
||||
|
||||
&[active] {
|
||||
opacity: 1;
|
||||
pointer-events: all;
|
||||
}
|
||||
|
||||
&::before {
|
||||
z-index: -1;
|
||||
content: "";
|
||||
position: absolute;
|
||||
inset: 0px;
|
||||
background-color: spiceColor("main", 0.9, -0.1);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
& > div {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 16px;
|
||||
align-items: center;
|
||||
|
||||
& > * {
|
||||
color: var(--color);
|
||||
|
||||
&:empty {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
.GenericModal__overlay {
|
||||
backdrop-filter: blur(3px) brightness(60%);
|
||||
background-color: transparent;
|
||||
|
||||
.GenericModal {
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
width: clamp(500px, 50%, 650px);
|
||||
background-color: spiceColor("main", 0.95);
|
||||
backdrop-filter: blur(3px);
|
||||
padding: 24px 16px;
|
||||
border-radius: var(--main-corner-radius);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@include spiceShadow();
|
||||
|
||||
.main-trackCreditsModal-container {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
background-color: transparent;
|
||||
width: 100%;
|
||||
|
||||
.main-trackCreditsModal-header {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
padding: 0px;
|
||||
width: 100%;
|
||||
border: none;
|
||||
|
||||
h1 {
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
@include spiceFont("glue", 2em, "Bold");
|
||||
}
|
||||
|
||||
button {
|
||||
position: absolute;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.main-trackCreditsModal-mainSection {
|
||||
padding: 0px 26px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -3,11 +3,14 @@
|
|||
@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() {
|
||||
box-shadow: 0px 0px 8px spiceColor("subtext", 0.1, 0.1);
|
||||
}
|
||||
|
||||
@mixin spiceGlass($opacity: 0.95) {
|
||||
background-color: spiceColor("main", $opacity);
|
||||
backdrop-filter: blur(10px);
|
||||
border: 1px solid spiceColor("subtext", 0.1, 0.1);
|
||||
border-radius: var(--main-corner-radius);
|
||||
@include spiceShadow();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,10 +7,12 @@
|
|||
@import "NoAds";
|
||||
@import "Markdown";
|
||||
@import "Info";
|
||||
@import "Loader";
|
||||
@import "Modals";
|
||||
@import "ConnectDeviceList";
|
||||
@import "Lyrics";
|
||||
@import "Icons";
|
||||
@import "Overlay";
|
||||
@import "CustomAppTabBar";
|
||||
|
||||
:root {
|
||||
--bar-height: 70px;
|
||||
|
|
@ -20,7 +22,7 @@
|
|||
--scrollbar-vertical-size: 8px;
|
||||
--cover-border-radius: 8px;
|
||||
--playbar-movement-anim-speed: 0.5s;
|
||||
--image-radius: 10px;
|
||||
--image-radius: 4px;
|
||||
--sidebar-icons-border-radius: 50vh; // 50vh = round / pill
|
||||
--song-transition-speed: 3s;
|
||||
--is_dark: calc(1 - var(--is_light));
|
||||
|
|
@ -133,13 +135,27 @@
|
|||
box-shadow: 0 4px 20px #21212130;
|
||||
}
|
||||
|
||||
.main-trackList-rowMarker {
|
||||
color: spiceColor("text");
|
||||
}
|
||||
|
||||
.main-trackList-playingIcon {
|
||||
-webkit-mask-image: url(icon64("equaliser", '{"size": 14}'));
|
||||
background-color: currentColor;
|
||||
content-visibility: hidden;
|
||||
image-rendering: pixelated;
|
||||
filter: grayscale(1);
|
||||
}
|
||||
|
||||
.main-trackList-trackListRowGrid {
|
||||
background-color: var(--spice-main);
|
||||
}
|
||||
|
||||
.main-trackList-active {
|
||||
background-color: spiceColor("selected-row", 0.25) !important;
|
||||
}
|
||||
|
||||
.main-trackList-trackListRow:hover {
|
||||
background-color: spiceColor("selected-row", 0.2) !important;
|
||||
background-color: spiceColor("selected-row", 0.15) !important;
|
||||
}
|
||||
|
||||
.main-trackList-trackListRow:focus-within,
|
||||
|
|
@ -154,6 +170,11 @@ span.artist-artistVerifiedBadge-badge svg > path:last-of-type {
|
|||
fill: spiceColor("text");
|
||||
}
|
||||
|
||||
/* Playlist text color */
|
||||
.main-entityHeader-subtitle.main-entityHeader-gra {
|
||||
color: spiceColor("subtext");
|
||||
}
|
||||
|
||||
/* Full window artist background */
|
||||
.main-entityHeader-background.main-entityHeader-gradient {
|
||||
opacity: 0.3;
|
||||
|
|
@ -555,6 +576,7 @@ html.sidebar-hide-text .GlueDropTarget span {
|
|||
|
||||
.progress-bar {
|
||||
--progress-bar-height: 2px;
|
||||
--is-active-fg-color: #{spiceColor("button-active")};
|
||||
--fg-color: #{spiceColor("button")};
|
||||
--bg-color: #{spiceColor("text", 0.2)};
|
||||
}
|
||||
|
|
@ -594,13 +616,8 @@ html.sidebar-hide-text .GlueDropTarget span {
|
|||
text-align: center;
|
||||
white-space: nowrap;
|
||||
pointer-events: none;
|
||||
border: 1px solid spiceColor("subtext", 0.1, 0.1);
|
||||
border-radius: var(--main-corner-radius);
|
||||
color: spiceColor("subtext");
|
||||
background-color: spiceColor("main", 0.75, -0.1) !important;
|
||||
backdrop-filter: blur(10px);
|
||||
border-radius: var(--main-corner-radius);
|
||||
@include spiceShadow();
|
||||
@include spiceGlass();
|
||||
}
|
||||
|
||||
.minimal-player .player-controls__buttons {
|
||||
|
|
@ -655,13 +672,17 @@ html.sidebar-hide-text .GlueDropTarget span {
|
|||
}
|
||||
|
||||
#main-trackInfo-year {
|
||||
display: block;
|
||||
|
||||
#main[playbar-album-info="false"] & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
#main-trackInfo-genre {
|
||||
#main[playbar-genre-info="false"] & {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.main-topBar-topbarContent .main-playButton-PlayButton {
|
||||
--size: 35px !important;
|
||||
}
|
||||
|
|
@ -800,6 +821,10 @@ li.GlueDropTarget {
|
|||
gap: 8px;
|
||||
max-width: unset;
|
||||
padding: 16px 32px !important;
|
||||
|
||||
& > * {
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
/** Custom elements */
|
||||
|
|
@ -1268,13 +1293,14 @@ html.right-expanded-cover.buddyfeed-visible .main-coverSlotExpanded-container {
|
|||
}
|
||||
}
|
||||
|
||||
// Fix lyrics-plus having a scrollbar when top-bar is `solid` or `transparent`
|
||||
.lyrics-lyricsContainer-LyricsContainer {
|
||||
height: 100% !important;
|
||||
}
|
||||
// Fix main-view-containers having a scrollbar when top-bar is `solid` or `transparent`
|
||||
.main-view-container__scroll-node-child {
|
||||
height: 100%;
|
||||
padding-bottom: 0px;
|
||||
|
||||
& > * {
|
||||
height: 100% !important;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide default Spotify "Offline" notice
|
||||
|
|
@ -1282,6 +1308,14 @@ html.right-expanded-cover.buddyfeed-visible .main-coverSlotExpanded-container {
|
|||
display: none;
|
||||
}
|
||||
|
||||
// Notifications
|
||||
.main-notificationBubbleContainer-NotificationBubbleContainer {
|
||||
.main-notificationBubble-NotificationBubble {
|
||||
color: spiceColor("subtext");
|
||||
@include spiceGlass();
|
||||
}
|
||||
}
|
||||
|
||||
// ! WORKAROUNDS / TEMP FIXES
|
||||
// Spotify UI breaks after advertisements #63
|
||||
canvas[width="250"][height="250"] {
|
||||
|
|
@ -1299,3 +1333,20 @@ canvas[width="250"][height="250"] {
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
// fix albumn name font size (#171)
|
||||
.main-trackInfo-release {
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
// fix play buttons color going green (#174)
|
||||
.encore-bright-accent-set {
|
||||
--background-highlight: var(--spice-button) !important;
|
||||
--background-press: var(--spice-button-active) !important;
|
||||
color: var(--spice-sidebar-text);
|
||||
}
|
||||
|
||||
// hide the triangle under the connect button
|
||||
.control-button--active::after {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
spicetify config current_theme " " extensions dribbblish-dynamic.js-
|
||||
spicetify config current_theme "SpicetifyDefault" extensions dribbblish-dynamic.js-
|
||||
|
||||
$spicePath = spicetify -c | Split-Path
|
||||
$configFile = Get-Content "$spicePath\config-xpui.ini"
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ set -e
|
|||
|
||||
echo "UN-INSTALLING"
|
||||
cd "$(dirname "$(spicetify -c)")"
|
||||
spicetify config current_theme " " extensions dribbblish-dynamic.js-
|
||||
spicetify config current_theme "SpicetifyDefault" extensions dribbblish-dynamic.js-
|
||||
|
||||
echo "UN-PATCHING"
|
||||
if cat config-xpui.ini | grep -o '\[Patch\]'; then
|
||||
|
|
|
|||
|
|
@ -1,14 +1,17 @@
|
|||
const webpack = require("webpack");
|
||||
const sass = require("sass");
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
import webpack from "webpack";
|
||||
import sass from "sass";
|
||||
import { CleanWebpackPlugin } from "clean-webpack-plugin";
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
|
||||
const icons = {};
|
||||
import Icons from "./src/js/Icons";
|
||||
import { lightOffset, spiceColor } from "./src/js/SassUtil";
|
||||
|
||||
const _icons = {};
|
||||
function addIcon(name, style, path) {
|
||||
name = name.replace(/_/g, "-");
|
||||
if (!icons.hasOwnProperty(name)) icons[name] = {};
|
||||
icons[name][style] = fs.readFileSync(path, { encoding: "utf8" });
|
||||
if (!_icons.hasOwnProperty(name)) _icons[name] = {};
|
||||
_icons[name][style] = fs.readFileSync(path, { encoding: "utf8" });
|
||||
}
|
||||
// Add Material Icons
|
||||
let iconDir = path.resolve(__dirname, "node_modules/@material-icons/svg/svg");
|
||||
|
|
@ -23,8 +26,11 @@ for (const icon of fs.readdirSync(iconDir)) {
|
|||
addIcon(icon.replace(/\..*?$/, ""), "custom", path.resolve(iconDir, icon));
|
||||
}
|
||||
|
||||
const icons = new Icons(_icons);
|
||||
|
||||
/** @type {import('webpack').Configuration} */
|
||||
module.exports = {
|
||||
const config = {
|
||||
mode: "development",
|
||||
entry: [path.resolve(__dirname, "src/js/main.js"), path.resolve(__dirname, "src/styles/main.scss"), path.resolve(__dirname, "src/styles/Colors.scss")],
|
||||
output: {
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
|
|
@ -50,9 +56,20 @@ module.exports = {
|
|||
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()));
|
||||
},
|
||||
"font64($font)": (font) => {
|
||||
const file = path.resolve(__dirname, "src/fonts", font.getValue());
|
||||
return new sass.types.String(`"data:font/truetype;charset=utf-8;base64,${fs.readFileSync(file, { encoding: "base64" })}"`);
|
||||
},
|
||||
'icon64($name, $options: "{}")': (name, options) => {
|
||||
name = name.getValue();
|
||||
options = JSON.parse(options.getValue());
|
||||
return new sass.types.String(icons.get(name, { ...options, base64: true }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -79,7 +96,7 @@ module.exports = {
|
|||
.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_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")
|
||||
}),
|
||||
|
|
@ -89,3 +106,5 @@ module.exports = {
|
|||
})
|
||||
]
|
||||
};
|
||||
|
||||
export default config;
|
||||
Loading…
Reference in a new issue