mirror of
https://github.com/danbulant/dribbblish-dynamic-theme
synced 2026-06-22 00:02:41 +00:00
Compare commits
No commits in common. "main" and "4.1.1" have entirely different histories.
40 changed files with 350 additions and 9846 deletions
3
.babelrc
3
.babelrc
|
|
@ -1,3 +0,0 @@
|
||||||
{
|
|
||||||
"presets": ["@babel/env"]
|
|
||||||
}
|
|
||||||
1
.github/workflows/post-release.yaml
vendored
1
.github/workflows/post-release.yaml
vendored
|
|
@ -12,7 +12,6 @@ jobs:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
repository: ${{ github.event.repository.full_name }}
|
|
||||||
ref: ${{ github.event.repository.default_branch }}
|
ref: ${{ github.event.repository.default_branch }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
|
|
||||||
3
.github/workflows/prettier.yml
vendored
3
.github/workflows/prettier.yml
vendored
|
|
@ -14,12 +14,11 @@ jobs:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
repository: ${{ github.event.repository.full_name }}
|
|
||||||
ref: ${{ github.head_ref }}
|
ref: ${{ github.head_ref }}
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Prettify code
|
- name: Prettify code
|
||||||
uses: creyD/prettier_action@v4.1.1
|
uses: creyD/prettier_action@v4.0
|
||||||
with:
|
with:
|
||||||
prettier_options: --write **/*.{js,css}
|
prettier_options: --write **/*.{js,css}
|
||||||
same_commit: True
|
same_commit: True
|
||||||
|
|
|
||||||
2
.github/workflows/release.yaml
vendored
2
.github/workflows/release.yaml
vendored
|
|
@ -28,7 +28,7 @@ jobs:
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: "15"
|
node-version: "14"
|
||||||
|
|
||||||
- name: Build Webpack
|
- name: Build Webpack
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
21
.github/workflows/stale.yml
vendored
21
.github/workflows/stale.yml
vendored
|
|
@ -1,21 +0,0 @@
|
||||||
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,7 +10,6 @@ jobs:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
repository: ${{ github.event.repository.full_name }}
|
|
||||||
ref: ${{ github.head_ref }}
|
ref: ${{ github.head_ref }}
|
||||||
|
|
||||||
- name: Get commit SHA
|
- name: Get commit SHA
|
||||||
|
|
@ -19,7 +18,7 @@ jobs:
|
||||||
- name: Setup Node.js
|
- name: Setup Node.js
|
||||||
uses: actions/setup-node@v2
|
uses: actions/setup-node@v2
|
||||||
with:
|
with:
|
||||||
node-version: "15"
|
node-version: "14"
|
||||||
|
|
||||||
- name: Test-Build Webpack
|
- name: Test-Build Webpack
|
||||||
run: |
|
run: |
|
||||||
|
|
|
||||||
12
CHANGELOG.md
12
CHANGELOG.md
|
|
@ -1,13 +1,5 @@
|
||||||
Added:
|
|
||||||
- Ability to hide premium features in addition to ads
|
|
||||||
- Ability to show current artist's genres
|
|
||||||
|
|
||||||
Fixed:
|
Fixed:
|
||||||
- Custom search input not being focussed after clicking
|
- Weird pill-shaped background on Playlist pages title (#137)
|
||||||
- When changing songs, the color shifts to blue for a second (#179)
|
|
||||||
|
|
||||||
Improved:
|
Improved:
|
||||||
- Add `embedWidgetGenerator` modals to custom modal styles. (Things like the [spicetify-marketplace](https://github.com/CharlieS1103/spicetify-marketplace) options)
|
- Changed default `sidebar` color to be darker, so you won't get flashed green on startup
|
||||||
- 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";
|
Write-Part "APPLYING";
|
||||||
$backupVer = $configFile -match "^version"
|
$backupVer = $configFile -match "^version"
|
||||||
if ($backupVer.Length -gt 0) {
|
$version = ConvertFrom-StringData $backupVer[0]
|
||||||
|
if ($version.version.Length -gt 0) {
|
||||||
spicetify apply
|
spicetify apply
|
||||||
} else {
|
} else {
|
||||||
spicetify backup apply
|
spicetify backup apply
|
||||||
}
|
}
|
||||||
Write-Done
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Write-Part "`nYour Powershell version is less than "; Write-Emphasized "$PSMinVersion";
|
Write-Part "`nYour Powershell version is less than "; Write-Emphasized "$PSMinVersion";
|
||||||
|
|
|
||||||
10
manifest.json
Normal file
10
manifest.json
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
{
|
||||||
|
"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"]
|
||||||
|
}
|
||||||
|
|
@ -1,22 +0,0 @@
|
||||||
[
|
|
||||||
{
|
|
||||||
"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
9109
package-lock.json
generated
File diff suppressed because it is too large
Load diff
13
package.json
13
package.json
|
|
@ -1,14 +1,11 @@
|
||||||
{
|
{
|
||||||
"name": "dribbblish-dynamic-theme",
|
"name": "dribbblish-dynamic-theme",
|
||||||
"version": "4.1.1",
|
"version": "4.1.0",
|
||||||
"homepage": "https://github.com/JulienMaille/dribbblish-dynamic-theme",
|
"homepage": "https://github.com/JulienMaille/dribbblish-dynamic-theme",
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/JulienMaille/dribbblish-dynamic-theme/issues"
|
"url": "https://github.com/JulienMaille/dribbblish-dynamic-theme/issues"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.17.0",
|
|
||||||
"@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",
|
||||||
|
|
@ -17,17 +14,15 @@
|
||||||
"webpack-cli": "^4.9.0"
|
"webpack-cli": "^4.9.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "webpack"
|
"build": "webpack --mode=development"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chroma-js": "^2.1.2",
|
"chroma-js": "^2.1.2",
|
||||||
"colorthief": "^2.3.2",
|
"colorthief": "^2.3.2",
|
||||||
"jquery": "^3.6.0",
|
"jquery": "^3.6.0",
|
||||||
"lodash.debounce": "^4.0.8",
|
"markdown-it": "^12.2.0",
|
||||||
"lodash.defaultsdeep": "^4.6.1",
|
|
||||||
"markdown-it": "^12.3.2",
|
|
||||||
"markdown-it-attrs": "^4.1.0",
|
"markdown-it-attrs": "^4.1.0",
|
||||||
"moment": "^2.29.2",
|
"moment": "^2.29.1",
|
||||||
"node-vibrant": "^3.1.6",
|
"node-vibrant": "^3.1.6",
|
||||||
"svgson": "^5.2.1"
|
"svgson": "^5.2.1"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,10 @@
|
||||||
Get-Process -Name Spotify -ErrorAction SilentlyContinue | Stop-Process -Force
|
$sp = "$env:APPDATA\Spotify\Spotify.exe"
|
||||||
Get-Process -Name SpotifyWebHelper -ErrorAction SilentlyContinue | Stop-Process -Force
|
|
||||||
|
|
||||||
$sp = spicetify config spotify_path
|
|
||||||
$sp += "\Spotify.exe"
|
|
||||||
Copy-Item $sp ($sp + ".backup")
|
Copy-Item $sp ($sp + ".backup")
|
||||||
|
|
||||||
$bytes = [System.IO.File]::ReadAllBytes($sp);
|
$bytes = [System.IO.File]::ReadAllBytes($sp);
|
||||||
$toRemove = [System.Text.Encoding]::UTF8.GetBytes("force-dark-mode");
|
$toRemove = [System.Text.Encoding]::UTF8.GetBytes("force-dark-mode");
|
||||||
|
|
||||||
$sw = [System.Diagnostics.Stopwatch]::StartNew()
|
|
||||||
for ($i = 0; $i -lt $bytes.Length; $i++) {
|
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
|
$found = $true
|
||||||
for ($j = 0; $j -lt $toRemove.Length; $j++) {
|
for ($j = 0; $j -lt $toRemove.Length; $j++) {
|
||||||
if ($bytes[$i + $j] -ne $toRemove[$j]) {
|
if ($bytes[$i + $j] -ne $toRemove[$j]) {
|
||||||
|
|
@ -32,8 +22,3 @@ 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"
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,131 +0,0 @@
|
||||||
<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>
|
|
||||||
|
Before Width: | Height: | Size: 3.8 KiB |
|
|
@ -1,42 +0,0 @@
|
||||||
<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>
|
|
||||||
|
Before Width: | Height: | Size: 1.3 KiB |
|
|
@ -1,6 +1,6 @@
|
||||||
import $ from "jquery";
|
import $ from "jquery";
|
||||||
|
|
||||||
import { renderMD, defaults } from "./Util";
|
import { renderMD } from "./Util";
|
||||||
import { icons } from "./Icons";
|
import { icons } from "./Icons";
|
||||||
|
|
||||||
export default class ConfigMenu {
|
export default class ConfigMenu {
|
||||||
|
|
@ -125,7 +125,7 @@ export default class ConfigMenu {
|
||||||
parent: null
|
parent: null
|
||||||
};
|
};
|
||||||
// Set Defaults
|
// Set Defaults
|
||||||
options = defaults(options, defaultOptions);
|
options = { ...defaultOptions, ...options };
|
||||||
if (typeof options.area == "string") options.area = { name: options.area, order: 0 };
|
if (typeof options.area == "string") options.area = { name: options.area, order: 0 };
|
||||||
options.description = options.description
|
options.description = options.description
|
||||||
.split("\n")
|
.split("\n")
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import ConfigMenu from "./ConfigMenu";
|
import ConfigMenu from "./ConfigMenu";
|
||||||
import Info from "./Info";
|
import Info from "./Info";
|
||||||
import Loader from "./Loader";
|
import Loader from "./Loader";
|
||||||
import Overlay from "./Overlay";
|
import { icons } from "./Icons";
|
||||||
import Icon, { icons } from "./Icons";
|
|
||||||
|
|
||||||
export default class Dribbblish {
|
export default class Dribbblish {
|
||||||
/**
|
/**
|
||||||
|
|
@ -24,10 +23,7 @@ export default class Dribbblish {
|
||||||
/** @type {Loader} */
|
/** @type {Loader} */
|
||||||
loader;
|
loader;
|
||||||
|
|
||||||
/** @type {Overlay} */
|
/** @type {Icons} */
|
||||||
overlay;
|
|
||||||
|
|
||||||
/** @type {Icon} */
|
|
||||||
icons;
|
icons;
|
||||||
|
|
||||||
/** @type {Object.<string, listener[]>} */
|
/** @type {Object.<string, listener[]>} */
|
||||||
|
|
@ -40,12 +36,9 @@ export default class Dribbblish {
|
||||||
this.config = new ConfigMenu();
|
this.config = new ConfigMenu();
|
||||||
this.info = new Info();
|
this.info = new Info();
|
||||||
this.loader = new Loader();
|
this.loader = new Loader();
|
||||||
this.overlay = new Overlay();
|
|
||||||
this.icons = icons;
|
this.icons = icons;
|
||||||
|
|
||||||
let tries = 0;
|
|
||||||
const interval = setInterval(() => {
|
const interval = setInterval(() => {
|
||||||
if (++tries > 50) throw new Error("ready timeout");
|
|
||||||
if (document.querySelector("#main") == null || Spicetify?.showNotification == undefined || !this.info.isReady()) return;
|
if (document.querySelector("#main") == null || Spicetify?.showNotification == undefined || !this.info.isReady()) return;
|
||||||
this.#ready = true;
|
this.#ready = true;
|
||||||
this.emit("ready");
|
this.emit("ready");
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,3 @@
|
||||||
import { defaults } from "./Util";
|
|
||||||
import { parseSync as parseSVG, stringify as stringifySVG } from "svgson";
|
import { parseSync as parseSVG, stringify as stringifySVG } from "svgson";
|
||||||
|
|
||||||
export default class Icons {
|
export default class Icons {
|
||||||
|
|
@ -7,7 +6,6 @@ export default class Icons {
|
||||||
/**
|
/**
|
||||||
* @typedef {Object} IconOptions
|
* @typedef {Object} IconOptions
|
||||||
* @property {IconStyle} [style="round"]
|
* @property {IconStyle} [style="round"]
|
||||||
* @property {String} [className=""]
|
|
||||||
* @property {Number} [size=16]
|
* @property {Number} [size=16]
|
||||||
* @property {Number} [scale=1]
|
* @property {Number} [scale=1]
|
||||||
* @property {String} [fill="currentColor"]
|
* @property {String} [fill="currentColor"]
|
||||||
|
|
@ -17,8 +15,8 @@ export default class Icons {
|
||||||
/** @type {Object.<String, Object.<IconStyle, String>>} */
|
/** @type {Object.<String, Object.<IconStyle, String>>} */
|
||||||
#icons;
|
#icons;
|
||||||
|
|
||||||
constructor(icons) {
|
constructor() {
|
||||||
this.#icons = icons ?? process.env.DRIBBBLISH_ICONS;
|
this.#icons = process.env.DRIBBBLISH_ICONS;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -68,42 +66,32 @@ export default class Icons {
|
||||||
/** @type {IconOptions} */
|
/** @type {IconOptions} */
|
||||||
const defaultOptions = {
|
const defaultOptions = {
|
||||||
style: this.#getDefaultStyle(name),
|
style: this.#getDefaultStyle(name),
|
||||||
className: "",
|
|
||||||
size: 16,
|
size: 16,
|
||||||
scale: 1,
|
scale: 1,
|
||||||
fill: "currentColor",
|
fill: "currentColor",
|
||||||
base64: false
|
base64: false
|
||||||
};
|
};
|
||||||
options = defaults(options, defaultOptions);
|
options = { ...defaultOptions, ...options };
|
||||||
|
|
||||||
const svg = parseSVG(this.getRawSVG(name, options.style));
|
const svg = parseSVG(this.getRawSVG(name, options.style));
|
||||||
|
|
||||||
// Add general / required attributes
|
|
||||||
svg.attributes["icon-type"] = "dribbblish";
|
svg.attributes["icon-type"] = "dribbblish";
|
||||||
svg.attributes["icon-name"] = name;
|
|
||||||
svg.attributes["icon-style"] = options.style;
|
svg.attributes["icon-style"] = options.style;
|
||||||
svg.attributes.fill = options.fill;
|
svg.attributes.fill = options.fill;
|
||||||
svg.attributes.width = options.size;
|
svg.attributes.width = options.size;
|
||||||
svg.attributes.height = options.size;
|
svg.attributes.height = options.size;
|
||||||
|
|
||||||
// Add className
|
// Create CSSStyleDeclaration by creating an element since there is no constructor for it
|
||||||
if (options.className != "") svg.attributes.class = options.className;
|
const styles = document.createElement("a").style;
|
||||||
|
|
||||||
// Add Styles
|
|
||||||
const styles = {};
|
|
||||||
if (options.scale != 1) {
|
if (options.scale != 1) {
|
||||||
styles["transform"] = `scale(${options.scale})`;
|
styles.transform = `scale(${options.scale})`;
|
||||||
styles["transform-origin"] = "center";
|
styles.transformOrigin = "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 (styleStr != "") child.attributes.style = styleStr;
|
if (styles.cssText != "") child.attributes.style = styles.cssText;
|
||||||
return child;
|
return child;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add title
|
|
||||||
if (options.title != null) {
|
if (options.title != null) {
|
||||||
svg.children.push({
|
svg.children.push({
|
||||||
name: "title",
|
name: "title",
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,28 @@
|
||||||
import Overlay from "./Overlay";
|
|
||||||
|
|
||||||
export default class Loader {
|
export default class Loader {
|
||||||
/** @type {Overlay} */
|
/** @type {HTMLDivElement} */
|
||||||
#overlay;
|
#container;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
this.#overlay = new Overlay();
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
show(text) {
|
show(text) {
|
||||||
this.#overlay.show({ icon: "loading", text });
|
this.#container.querySelector("span").innerText = text ?? "";
|
||||||
|
this.#container.setAttribute("active", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
hide() {
|
hide() {
|
||||||
this.#overlay.hide();
|
this.#container.removeAttribute("active");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,68 +0,0 @@
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
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,7 +1,5 @@
|
||||||
import MarkdownIt from "markdown-it";
|
import MarkdownIt from "markdown-it";
|
||||||
import MarkdownItAttrs from "markdown-it-attrs";
|
import MarkdownItAttrs from "markdown-it-attrs";
|
||||||
import defaultsDeep from "lodash.defaultsdeep";
|
|
||||||
import { default as _debounce } from "lodash.debounce";
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @callback waitForElCb
|
* @callback waitForElCb
|
||||||
|
|
@ -71,25 +69,22 @@ export function getRandomInt(min, max) {
|
||||||
return Math.floor(Math.random() * (max - min + 1)) + min;
|
return Math.floor(Math.random() * (max - min + 1)) + min;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @template T
|
|
||||||
* @param {T[]} arr
|
|
||||||
* @returns {T}
|
|
||||||
*/
|
|
||||||
export function randomFromArray(arr) {
|
export function randomFromArray(arr) {
|
||||||
return arr[Math.floor(Math.random() * arr.length)];
|
return arr[Math.floor(Math.random() * arr.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @type {_debounce} */
|
export function debounce(func, wait, immediate) {
|
||||||
export function debounce(fn, wait, opts) {
|
var timeout;
|
||||||
return _debounce(fn, wait, opts);
|
return function () {
|
||||||
}
|
var context = this,
|
||||||
|
args = arguments;
|
||||||
/**
|
var later = function () {
|
||||||
* @param {Object} options
|
timeout = null;
|
||||||
* @param {...Object} defaults
|
if (!immediate) func.apply(context, args);
|
||||||
* @returns {Object}
|
};
|
||||||
*/
|
var callNow = immediate && !timeout;
|
||||||
export function defaults(options, ...defaults) {
|
clearTimeout(timeout);
|
||||||
return defaultsDeep(options, ...defaults);
|
timeout = setTimeout(later, wait);
|
||||||
|
if (callNow) func.apply(context, args);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
151
src/js/main.js
151
src/js/main.js
|
|
@ -12,7 +12,6 @@ $("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();
|
||||||
|
|
@ -48,8 +47,8 @@ Dribbblish.on("ready", () => {
|
||||||
? {
|
? {
|
||||||
icon: "settings",
|
icon: "settings",
|
||||||
color: {
|
color: {
|
||||||
fg: spiceColor("subtext"),
|
fg: "var(--spice-subtext)",
|
||||||
bg: spiceColor("subtext", 0.1, 0.05)
|
bg: "rgba(var(--spice-rgb-subtext), calc(0.1 + var(--is_light) * 0.05))"
|
||||||
},
|
},
|
||||||
order: 999,
|
order: 999,
|
||||||
tooltip: "Open Dribbblish Settings",
|
tooltip: "Open Dribbblish Settings",
|
||||||
|
|
@ -77,7 +76,7 @@ Dribbblish.on("ready", () => {
|
||||||
input.setAttribute("spellcheck", "false");
|
input.setAttribute("spellcheck", "false");
|
||||||
input.addEventListener("click", (e) => {
|
input.addEventListener("click", (e) => {
|
||||||
if (!Spicetify.Platform.History.location.pathname.startsWith("/search")) Spicetify.Platform.History.push(`/search/${input.value}`);
|
if (!Spicetify.Platform.History.location.pathname.startsWith("/search")) Spicetify.Platform.History.push(`/search/${input.value}`);
|
||||||
waitForElement([`.main-topBar-topbarContent form[role="search"]`], ([defaultSearch]) => {
|
waitForElement([`[data-testid="search-input"]`], ([defaultSearch]) => {
|
||||||
input.focus();
|
input.focus();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
@ -216,29 +215,14 @@ Dribbblish.on("ready", () => {
|
||||||
onChange: (val) => $("#main").attr("playbar-album-info", val)
|
onChange: (val) => $("#main").attr("playbar-album-info", val)
|
||||||
});
|
});
|
||||||
|
|
||||||
Dribbblish.config.register({
|
|
||||||
area: "Playbar",
|
|
||||||
type: "checkbox",
|
|
||||||
key: "showGenreInfoInPlaybar",
|
|
||||||
name: "Show Genre Info in Playbar",
|
|
||||||
description: "Show artist's genres in the Playbar",
|
|
||||||
defaultValue: false,
|
|
||||||
onChange: (val) => $("#main").attr("playbar-genre-info", val)
|
|
||||||
});
|
|
||||||
|
|
||||||
Dribbblish.config.register({
|
Dribbblish.config.register({
|
||||||
order: 999,
|
order: 999,
|
||||||
type: "select",
|
type: "checkbox",
|
||||||
data: { none: "Hide Nothing", ads: "Hide Ads", premium: "Hide Premium Features", both: "Hide Both" },
|
key: "hideAds",
|
||||||
key: "hideAdsOrPremium",
|
name: "Hide Ads",
|
||||||
name: "Hide Ads / Premium Features",
|
description: `Hide ads / premium features (see: [SpotifyNoPremium](https://github.com/Daksh777/SpotifyNoPremium))`,
|
||||||
description: `Hide ads / premium features like Fullscreen and Download Buttons (see: [SpotifyNoPremium](https://github.com/Daksh777/SpotifyNoPremium))`,
|
defaultValue: false,
|
||||||
defaultValue: "none",
|
onChange: (val) => $("#main").attr("hide-ads", val)
|
||||||
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]) => {
|
waitForElement([".main-rootlist-rootlist", ".main-rootlist-wrapper > :nth-child(2) > :first-child", "#spicetify-show-list"], ([rootlist]) => {
|
||||||
|
|
@ -379,11 +363,11 @@ Dribbblish.on("ready", () => {
|
||||||
key: "aboutDribbblishInfo",
|
key: "aboutDribbblishInfo",
|
||||||
name: "Info",
|
name: "Info",
|
||||||
description: `
|
description: `
|
||||||
OS: \`${capitalizeFirstLetter(Spicetify.Platform.PlatformData.os_name)} v${Spicetify.Platform.PlatformData.os_version}\`
|
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}\`
|
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"}\`
|
Spicetify: \`${Spicetify.version != null ? `v${Spicetify.version}` : "< v2.7.3"}\`
|
||||||
Dribbblish: \`v${process.env.DRIBBBLISH_VERSION}-${process.env.COMMIT_HASH}\`
|
Dribbblish: \`v${process.env.DRIBBBLISH_VERSION}-${process.env.COMMIT_HASH}\`
|
||||||
`,
|
`,
|
||||||
data: "Copy",
|
data: "Copy",
|
||||||
onChange: function () {
|
onChange: function () {
|
||||||
copyToClipboard(this.description.replace(/\`/g, ""));
|
copyToClipboard(this.description.replace(/\`/g, ""));
|
||||||
|
|
@ -400,29 +384,30 @@ Dribbblish.on("ready", () => {
|
||||||
data: "Create Report",
|
data: "Create Report",
|
||||||
onChange: () => {
|
onChange: () => {
|
||||||
const reportBody = `
|
const reportBody = `
|
||||||
${process.env.BUG_REPORT}
|
${process.env.BUG_REPORT}
|
||||||
|
|
||||||
<!-- Leave the lines below as they are -->
|
<!-- Leave the lines below as they are -->
|
||||||
---
|
---
|
||||||
|
|
||||||
<details>
|
### Info for Contributors:
|
||||||
<summary>Info for Contributors</summary>
|
|
||||||
|
|
||||||
**Versions**
|
**Versions**
|
||||||
${Dribbblish.config.getOptions("aboutDribbblishInfo").description.split("\n").join("\n ")}
|
${Dribbblish.config.getOptions("aboutDribbblishInfo").description}
|
||||||
|
|
||||||
**Extensions**
|
**Extensions**
|
||||||
${$(`script[src^="extensions/"]`)
|
${$(`script[src^="extensions/"]`)
|
||||||
.toArray()
|
.toArray()
|
||||||
.map((e) => `- ${e.src.split("/").slice(-1)[0]}`)
|
.map((e) => `- ${e.src.split("/").slice(-1)[0]}`)
|
||||||
.join("\n ")}
|
.join("\n")}
|
||||||
|
|
||||||
**Settings**
|
**Settings**
|
||||||
\`\`\`json
|
\`\`\`json
|
||||||
${JSON.stringify(Dribbblish.config.export(), null, 4).split("\n").join("\n ")}
|
${JSON.stringify(Dribbblish.config.export(), null, 4)}
|
||||||
\`\`\`
|
\`\`\`
|
||||||
</details>
|
`
|
||||||
`.replace(/^ {12}/gm, "");
|
.split("\n")
|
||||||
|
.map((line) => line.replace(/^ {16}/, ""))
|
||||||
|
.join("\n");
|
||||||
|
|
||||||
const reportURL = new URL("https://github.com/JulienMaille/dribbblish-dynamic-theme/issues/new");
|
const reportURL = new URL("https://github.com/JulienMaille/dribbblish-dynamic-theme/issues/new");
|
||||||
reportURL.searchParams.set("labels", "bug");
|
reportURL.searchParams.set("labels", "bug");
|
||||||
|
|
@ -460,13 +445,8 @@ Dribbblish.on("ready", () => {
|
||||||
|
|
||||||
/* js */
|
/* js */
|
||||||
async function getAlbumRelease(uri) {
|
async function getAlbumRelease(uri) {
|
||||||
const info = await Spicetify.CosmosAsync.get(`https://api.spotify.com/v1/albums/${uri}`);
|
const info = await Spicetify.CosmosAsync.get(`hm://album/v1/album-app/album/${uri}/desktop`);
|
||||||
return { year: info.release_date };
|
return { year: info.year, month: (info.month ?? 1) - 1, day: info.day ?? 1 };
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
function isLight(hex) {
|
||||||
|
|
@ -565,10 +545,11 @@ Dribbblish.on("ready", () => {
|
||||||
Algorithm of selecting colors from the albumart
|
Algorithm of selecting colors from the albumart
|
||||||
- **Colorthief [(see)](https://lokeshdhakar.com/projects/color-thief/):** Gets more fitting colors
|
- **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)*
|
- **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
|
- **Static:** Select a static color to be used
|
||||||
{.muted}
|
{.muted}
|
||||||
`,
|
`,
|
||||||
data: { colorthief: "Colorthief", vibrant: "Vibrant", static: "Static" },
|
data: { spotify: "Spotify", colorthief: "Colorthief", vibrant: "Vibrant", static: "Static" },
|
||||||
defaultValue: "colorthief",
|
defaultValue: "colorthief",
|
||||||
onChange: () => updateColors(),
|
onChange: () => updateColors(),
|
||||||
showChildren: (val) => {
|
showChildren: (val) => {
|
||||||
|
|
@ -752,19 +733,8 @@ Dribbblish.on("ready", () => {
|
||||||
}
|
}
|
||||||
const albumInfoSpan = document.getElementById("main-trackInfo-year");
|
const albumInfoSpan = document.getElementById("main-trackInfo-year");
|
||||||
|
|
||||||
if (!document.getElementById("main-trackInfo-genre")) {
|
let album_uri = Spicetify.Player.data.track.metadata.album_uri;
|
||||||
const el = document.createElement("div");
|
let bgImage = Spicetify.Player.data.track.metadata.image_url;
|
||||||
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) {
|
if (bgImage === undefined) {
|
||||||
bgImage = "/images/tracklist-row-song-fallback.svg";
|
bgImage = "/images/tracklist-row-song-fallback.svg";
|
||||||
}
|
}
|
||||||
|
|
@ -775,37 +745,22 @@ Dribbblish.on("ready", () => {
|
||||||
const albumLinkElem = /* html */ `
|
const albumLinkElem = /* html */ `
|
||||||
<span>
|
<span>
|
||||||
<span draggable="true">
|
<span draggable="true">
|
||||||
<a draggable="false" dir="auto" href="${album_uri}">${track.metadata.album_title}</a>
|
<a draggable="false" dir="auto" href="${album_uri}">${Spicetify.Player.data.track.metadata.album_title}</a>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
`;
|
`;
|
||||||
const albumDateElem = /* html */ `<span> • <span title="${albumDate.format("L")}">${albumDate.format(moment().diff(albumDate, "months") <= 6 ? "MMM YYYY" : "YYYY")}</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}`;
|
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
|
// podcast
|
||||||
bgImage = bgImage.replace("spotify:image:", "https://i.scdn.co/image/");
|
bgImage = bgImage.replace("spotify:image:", "https://i.scdn.co/image/");
|
||||||
albumInfoSpan.innerHTML = track.metadata.album_title;
|
albumInfoSpan.innerHTML = Spicetify.Player.data.track.metadata.album_title;
|
||||||
genreInfoSpan.innerHTML = "";
|
} else if (Spicetify.Player.data.track.metadata.is_local == "true") {
|
||||||
} else if (track.metadata.is_local == "true") {
|
|
||||||
// local file
|
// local file
|
||||||
albumInfoSpan.innerHTML = track.metadata.album_title;
|
albumInfoSpan.innerHTML = Spicetify.Player.data.track.metadata.album_title;
|
||||||
genreInfoSpan.innerHTML = "";
|
} else if (Spicetify.Player.data.track.provider == "ad") {
|
||||||
} else if (track.provider == "ad") {
|
|
||||||
// ad
|
// ad
|
||||||
albumInfoSpan.innerHTML = "Advertisement";
|
albumInfoSpan.innerHTML = "Advertisement";
|
||||||
genreInfoSpan.innerHTML = "";
|
|
||||||
return;
|
return;
|
||||||
} else {
|
} else {
|
||||||
// When clicking a song from the homepage, songChange is fired with half empty metadata
|
// When clicking a song from the homepage, songChange is fired with half empty metadata
|
||||||
|
|
@ -825,13 +780,19 @@ Dribbblish.on("ready", () => {
|
||||||
|
|
||||||
$("html").css("--image-brightness", getImageLightness(img) / 255);
|
$("html").css("--image-brightness", getImageLightness(img) / 255);
|
||||||
|
|
||||||
|
let color = "#509bf5";
|
||||||
if (img.complete) {
|
if (img.complete) {
|
||||||
let color = "#1ed760";
|
|
||||||
const colorSelectionAlgorithm = Dribbblish.config.get("colorSelectionAlgorithm");
|
const colorSelectionAlgorithm = Dribbblish.config.get("colorSelectionAlgorithm");
|
||||||
const colorSelectionMode = Dribbblish.config.get("colorSelectionMode");
|
const colorSelectionMode = Dribbblish.config.get("colorSelectionMode");
|
||||||
let palette = {};
|
let palette = {};
|
||||||
|
|
||||||
if (colorSelectionAlgorithm == "colorthief") {
|
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") {
|
||||||
palette = Object.fromEntries([colorThief.getColor(img), ...colorThief.getPalette(img, 24, 5)].map((c) => chroma(c)).map((c) => [c.luminance(), c]));
|
palette = Object.fromEntries([colorThief.getColor(img), ...colorThief.getPalette(img, 24, 5)].map((c) => chroma(c)).map((c) => [c.luminance(), c]));
|
||||||
} else if (colorSelectionAlgorithm == "vibrant") {
|
} else if (colorSelectionAlgorithm == "vibrant") {
|
||||||
const swatches = await new Promise((resolve, reject) => new Vibrant(img, 5).getPalette().then(resolve).catch(reject));
|
const swatches = await new Promise((resolve, reject) => new Vibrant(img, 5).getPalette().then(resolve).catch(reject));
|
||||||
|
|
@ -857,9 +818,9 @@ Dribbblish.on("ready", () => {
|
||||||
const wantedLuminance = $("html").css("--is_light") == "1" ? Dribbblish.config.get("lightModeLuminance") : Dribbblish.config.get("darkModeLuminance");
|
const wantedLuminance = $("html").css("--is_light") == "1" ? Dribbblish.config.get("lightModeLuminance") : Dribbblish.config.get("darkModeLuminance");
|
||||||
color = palette[getClosestToNum(Object.keys(palette), wantedLuminance)].hex();
|
color = palette[getClosestToNum(Object.keys(palette), wantedLuminance)].hex();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateColors(false, color);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateColors(false, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
var coverListener;
|
var coverListener;
|
||||||
|
|
@ -891,7 +852,7 @@ Dribbblish.on("ready", () => {
|
||||||
fetch("https://api.github.com/repos/JulienMaille/dribbblish-dynamic-theme/releases/latest")
|
fetch("https://api.github.com/repos/JulienMaille/dribbblish-dynamic-theme/releases/latest")
|
||||||
.then((response) => response.json())
|
.then((response) => response.json())
|
||||||
.then((data) => {
|
.then((data) => {
|
||||||
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);
|
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);
|
||||||
})
|
})
|
||||||
.catch(console.error);
|
.catch(console.error);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -44,3 +44,16 @@ $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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,13 +23,16 @@
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
width: clamp(500px, 50%, 650px);
|
width: clamp(500px, 50%, 650px);
|
||||||
|
background-color: spiceColor("main", 0.95);
|
||||||
|
backdrop-filter: blur(3px);
|
||||||
padding: 20px 15px;
|
padding: 20px 15px;
|
||||||
|
border-radius: var(--main-corner-radius);
|
||||||
display: flex;
|
display: flex;
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@include spiceGlass();
|
@include spiceShadow();
|
||||||
|
|
||||||
> h2 {
|
> h2 {
|
||||||
font-size: 32px;
|
font-size: 32px;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,13 @@
|
||||||
.connect-device-list-container {
|
.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;
|
padding: 8px;
|
||||||
@include spiceGlass(lightOffset(0.8, -0.1));
|
background-color: spiceColor("main", 0.75, -0.1) !important;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border-radius: var(--main-corner-radius);
|
||||||
|
@include spiceShadow();
|
||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
display: none;
|
display: none;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
.main-contextMenu-menu {
|
.main-contextMenu-menu {
|
||||||
position: relative;
|
$border-color: spiceColor("subtext", 0.1, 0.1);
|
||||||
overflow: visible;
|
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
|
border: 1px solid $border-color;
|
||||||
border-radius: var(--main-corner-radius);
|
border-radius: var(--main-corner-radius);
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
|
||||||
|
|
@ -10,7 +11,10 @@
|
||||||
content: "";
|
content: "";
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset: 0px;
|
inset: 0px;
|
||||||
@include spiceGlass(lightOffset(0.8, -0.1));
|
background-color: spiceColor("main", 0.75, -0.1) !important;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border-radius: var(--main-corner-radius);
|
||||||
|
@include spiceShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-contextMenu-menuItem {
|
.main-contextMenu-menuItem {
|
||||||
|
|
@ -28,7 +32,7 @@
|
||||||
&::after {
|
&::after {
|
||||||
left: 8px;
|
left: 8px;
|
||||||
right: 8px;
|
right: 8px;
|
||||||
border-color: spiceColor("subtext", 0.1, 0.1);
|
border-color: $border-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +0,0 @@
|
||||||
.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 @@
|
||||||
.main-button {
|
button.main-button {
|
||||||
&-primary {
|
&-primary {
|
||||||
$color: spiceColor("subtext");
|
$color: spiceColor("subtext");
|
||||||
color: $color;
|
color: $color;
|
||||||
|
|
|
||||||
75
src/styles/Loader.scss
Normal file
75
src/styles/Loader.scss
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
// 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 +0,0 @@
|
||||||
// TODO: improve default lyrics styles when the classes are mapped `see: https://github.com/JulienMaille/dribbblish-dynamic-theme/issues/144`
|
|
||||||
|
|
@ -5,12 +5,15 @@
|
||||||
.GenericModal {
|
.GenericModal {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
background-color: spiceColor("main", 0.95);
|
||||||
|
backdrop-filter: blur(3px);
|
||||||
padding: 24px 16px;
|
padding: 24px 16px;
|
||||||
|
border-radius: var(--main-corner-radius);
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@include spiceGlass();
|
@include spiceShadow();
|
||||||
|
|
||||||
// Popups (`Spicetify.PopupModal.display()`)
|
// Popups (`Spicetify.PopupModal.display()`)
|
||||||
generic-modal & {
|
generic-modal & {
|
||||||
|
|
@ -27,40 +30,34 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.main- {
|
.main-trackCreditsModal-container {
|
||||||
&trackCreditsModal,
|
display: flex;
|
||||||
&embedWidgetGenerator {
|
gap: 16px;
|
||||||
&-container {
|
background-color: transparent;
|
||||||
display: flex;
|
width: 100%;
|
||||||
gap: 16px;
|
|
||||||
background-color: transparent;
|
.main-trackCreditsModal-header {
|
||||||
|
display: flex;
|
||||||
|
gap: 16px;
|
||||||
|
padding: 0px;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
text-align: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
box-shadow: none;
|
@include spiceFont("glue", 2em, "Bold");
|
||||||
}
|
}
|
||||||
|
|
||||||
&-header {
|
button {
|
||||||
display: flex;
|
position: absolute;
|
||||||
gap: 16px;
|
top: 16px;
|
||||||
padding: 0px;
|
right: 16px;
|
||||||
width: 100%;
|
|
||||||
border: none;
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
text-align: center;
|
|
||||||
width: 100%;
|
|
||||||
@include spiceFont("glue", 2em, "Bold");
|
|
||||||
}
|
|
||||||
|
|
||||||
button {
|
|
||||||
position: absolute;
|
|
||||||
top: 16px;
|
|
||||||
right: 16px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&-mainSection {
|
.main-trackCreditsModal-mainSection {
|
||||||
padding: 0px 26px;
|
padding: 0px 26px;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,17 @@
|
||||||
// Hide ads
|
#main[hide-ads="true"] {
|
||||||
#main[hide-ads~="ads"] {
|
/* Remove upgrade button*/
|
||||||
// Remove ad placeholder in main screen
|
|
||||||
.main-leaderboardComponent-container {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide premium features
|
|
||||||
#main[hide-ads~="premium"] {
|
|
||||||
// Remove upgrade button
|
|
||||||
.main-topBar-UpgradeButton {
|
.main-topBar-UpgradeButton {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove upgrade to premium button in user menu
|
/* Remove upgrade to premium button in user menu */
|
||||||
// prettier-ignore
|
.main-contextMenu-menuItemButton[href="https://www.spotify.com/premium/"]
|
||||||
.main-contextMenu-menuItemButton[href="https://www.spotify.com/premium/"] {
|
{
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide fullscreen button
|
/* Remove ad placeholder in main screen */
|
||||||
.volume-bar + .control-button {
|
.main-leaderboardComponent-container {
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide download buttons
|
|
||||||
.main-actionBar-ActionBarRow button[role="switch"] {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,42 +0,0 @@
|
||||||
#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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
50
src/styles/Popup.scss
Normal file
50
src/styles/Popup.scss
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
.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,14 +3,11 @@
|
||||||
@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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@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,12 +7,10 @@
|
||||||
@import "NoAds";
|
@import "NoAds";
|
||||||
@import "Markdown";
|
@import "Markdown";
|
||||||
@import "Info";
|
@import "Info";
|
||||||
|
@import "Loader";
|
||||||
@import "Modals";
|
@import "Modals";
|
||||||
@import "ConnectDeviceList";
|
@import "ConnectDeviceList";
|
||||||
@import "Lyrics";
|
|
||||||
@import "Icons";
|
@import "Icons";
|
||||||
@import "Overlay";
|
|
||||||
@import "CustomAppTabBar";
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--bar-height: 70px;
|
--bar-height: 70px;
|
||||||
|
|
@ -22,7 +20,7 @@
|
||||||
--scrollbar-vertical-size: 8px;
|
--scrollbar-vertical-size: 8px;
|
||||||
--cover-border-radius: 8px;
|
--cover-border-radius: 8px;
|
||||||
--playbar-movement-anim-speed: 0.5s;
|
--playbar-movement-anim-speed: 0.5s;
|
||||||
--image-radius: 4px;
|
--image-radius: 10px;
|
||||||
--sidebar-icons-border-radius: 50vh; // 50vh = round / pill
|
--sidebar-icons-border-radius: 50vh; // 50vh = round / pill
|
||||||
--song-transition-speed: 3s;
|
--song-transition-speed: 3s;
|
||||||
--is_dark: calc(1 - var(--is_light));
|
--is_dark: calc(1 - var(--is_light));
|
||||||
|
|
@ -135,27 +133,13 @@
|
||||||
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 {
|
|
||||||
background-color: var(--spice-main);
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-trackList-active {
|
|
||||||
background-color: spiceColor("selected-row", 0.25) !important;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-trackList-trackListRow:hover {
|
.main-trackList-trackListRow:hover {
|
||||||
background-color: spiceColor("selected-row", 0.15) !important;
|
background-color: spiceColor("selected-row", 0.2) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.main-trackList-trackListRow:focus-within,
|
.main-trackList-trackListRow:focus-within,
|
||||||
|
|
@ -170,11 +154,6 @@ span.artist-artistVerifiedBadge-badge svg > path:last-of-type {
|
||||||
fill: spiceColor("text");
|
fill: spiceColor("text");
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Playlist text color */
|
|
||||||
.main-entityHeader-subtitle.main-entityHeader-gra {
|
|
||||||
color: spiceColor("subtext");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Full window artist background */
|
/* Full window artist background */
|
||||||
.main-entityHeader-background.main-entityHeader-gradient {
|
.main-entityHeader-background.main-entityHeader-gradient {
|
||||||
opacity: 0.3;
|
opacity: 0.3;
|
||||||
|
|
@ -576,7 +555,6 @@ html.sidebar-hide-text .GlueDropTarget span {
|
||||||
|
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
--progress-bar-height: 2px;
|
--progress-bar-height: 2px;
|
||||||
--is-active-fg-color: #{spiceColor("button-active")};
|
|
||||||
--fg-color: #{spiceColor("button")};
|
--fg-color: #{spiceColor("button")};
|
||||||
--bg-color: #{spiceColor("text", 0.2)};
|
--bg-color: #{spiceColor("text", 0.2)};
|
||||||
}
|
}
|
||||||
|
|
@ -616,8 +594,13 @@ html.sidebar-hide-text .GlueDropTarget span {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
|
border: 1px solid spiceColor("subtext", 0.1, 0.1);
|
||||||
|
border-radius: var(--main-corner-radius);
|
||||||
color: spiceColor("subtext");
|
color: spiceColor("subtext");
|
||||||
@include spiceGlass();
|
background-color: spiceColor("main", 0.75, -0.1) !important;
|
||||||
|
backdrop-filter: blur(10px);
|
||||||
|
border-radius: var(--main-corner-radius);
|
||||||
|
@include spiceShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
.minimal-player .player-controls__buttons {
|
.minimal-player .player-controls__buttons {
|
||||||
|
|
@ -672,13 +655,9 @@ html.sidebar-hide-text .GlueDropTarget span {
|
||||||
}
|
}
|
||||||
|
|
||||||
#main-trackInfo-year {
|
#main-trackInfo-year {
|
||||||
#main[playbar-album-info="false"] & {
|
display: block;
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#main-trackInfo-genre {
|
#main[playbar-album-info="false"] & {
|
||||||
#main[playbar-genre-info="false"] & {
|
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -821,10 +800,6 @@ li.GlueDropTarget {
|
||||||
gap: 8px;
|
gap: 8px;
|
||||||
max-width: unset;
|
max-width: unset;
|
||||||
padding: 16px 32px !important;
|
padding: 16px 32px !important;
|
||||||
|
|
||||||
& > * {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Custom elements */
|
/** Custom elements */
|
||||||
|
|
@ -1293,14 +1268,13 @@ html.right-expanded-cover.buddyfeed-visible .main-coverSlotExpanded-container {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fix main-view-containers having a scrollbar when top-bar is `solid` or `transparent`
|
// Fix lyrics-plus having a scrollbar when top-bar is `solid` or `transparent`
|
||||||
|
.lyrics-lyricsContainer-LyricsContainer {
|
||||||
|
height: 100% !important;
|
||||||
|
}
|
||||||
.main-view-container__scroll-node-child {
|
.main-view-container__scroll-node-child {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
|
|
||||||
& > * {
|
|
||||||
height: 100% !important;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hide default Spotify "Offline" notice
|
// Hide default Spotify "Offline" notice
|
||||||
|
|
@ -1308,14 +1282,6 @@ html.right-expanded-cover.buddyfeed-visible .main-coverSlotExpanded-container {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Notifications
|
|
||||||
.main-notificationBubbleContainer-NotificationBubbleContainer {
|
|
||||||
.main-notificationBubble-NotificationBubble {
|
|
||||||
color: spiceColor("subtext");
|
|
||||||
@include spiceGlass();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ! WORKAROUNDS / TEMP FIXES
|
// ! WORKAROUNDS / TEMP FIXES
|
||||||
// Spotify UI breaks after advertisements #63
|
// Spotify UI breaks after advertisements #63
|
||||||
canvas[width="250"][height="250"] {
|
canvas[width="250"][height="250"] {
|
||||||
|
|
@ -1333,20 +1299,3 @@ canvas[width="250"][height="250"] {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
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 "SpicetifyDefault" extensions dribbblish-dynamic.js-
|
spicetify config current_theme " " extensions dribbblish-dynamic.js-
|
||||||
|
|
||||||
$spicePath = spicetify -c | Split-Path
|
$spicePath = spicetify -c | Split-Path
|
||||||
$configFile = Get-Content "$spicePath\config-xpui.ini"
|
$configFile = Get-Content "$spicePath\config-xpui.ini"
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ set -e
|
||||||
|
|
||||||
echo "UN-INSTALLING"
|
echo "UN-INSTALLING"
|
||||||
cd "$(dirname "$(spicetify -c)")"
|
cd "$(dirname "$(spicetify -c)")"
|
||||||
spicetify config current_theme "SpicetifyDefault" extensions dribbblish-dynamic.js-
|
spicetify config current_theme " " extensions dribbblish-dynamic.js-
|
||||||
|
|
||||||
echo "UN-PATCHING"
|
echo "UN-PATCHING"
|
||||||
if cat config-xpui.ini | grep -o '\[Patch\]'; then
|
if cat config-xpui.ini | grep -o '\[Patch\]'; then
|
||||||
|
|
|
||||||
|
|
@ -1,17 +1,14 @@
|
||||||
import webpack from "webpack";
|
const webpack = require("webpack");
|
||||||
import sass from "sass";
|
const sass = require("sass");
|
||||||
import { CleanWebpackPlugin } from "clean-webpack-plugin";
|
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||||
import path from "path";
|
const path = require("path");
|
||||||
import fs from "fs";
|
const fs = require("fs");
|
||||||
|
|
||||||
import Icons from "./src/js/Icons";
|
const icons = {};
|
||||||
import { lightOffset, spiceColor } from "./src/js/SassUtil";
|
|
||||||
|
|
||||||
const _icons = {};
|
|
||||||
function addIcon(name, style, path) {
|
function addIcon(name, style, path) {
|
||||||
name = name.replace(/_/g, "-");
|
name = name.replace(/_/g, "-");
|
||||||
if (!_icons.hasOwnProperty(name)) _icons[name] = {};
|
if (!icons.hasOwnProperty(name)) icons[name] = {};
|
||||||
_icons[name][style] = fs.readFileSync(path, { encoding: "utf8" });
|
icons[name][style] = fs.readFileSync(path, { encoding: "utf8" });
|
||||||
}
|
}
|
||||||
// Add Material Icons
|
// Add Material Icons
|
||||||
let iconDir = path.resolve(__dirname, "node_modules/@material-icons/svg/svg");
|
let iconDir = path.resolve(__dirname, "node_modules/@material-icons/svg/svg");
|
||||||
|
|
@ -26,11 +23,8 @@ for (const icon of fs.readdirSync(iconDir)) {
|
||||||
addIcon(icon.replace(/\..*?$/, ""), "custom", path.resolve(iconDir, icon));
|
addIcon(icon.replace(/\..*?$/, ""), "custom", path.resolve(iconDir, icon));
|
||||||
}
|
}
|
||||||
|
|
||||||
const icons = new Icons(_icons);
|
|
||||||
|
|
||||||
/** @type {import('webpack').Configuration} */
|
/** @type {import('webpack').Configuration} */
|
||||||
const config = {
|
module.exports = {
|
||||||
mode: "development",
|
|
||||||
entry: [path.resolve(__dirname, "src/js/main.js"), path.resolve(__dirname, "src/styles/main.scss"), path.resolve(__dirname, "src/styles/Colors.scss")],
|
entry: [path.resolve(__dirname, "src/js/main.js"), path.resolve(__dirname, "src/styles/main.scss"), path.resolve(__dirname, "src/styles/Colors.scss")],
|
||||||
output: {
|
output: {
|
||||||
path: path.resolve(__dirname, "dist"),
|
path: path.resolve(__dirname, "dist"),
|
||||||
|
|
@ -56,20 +50,9 @@ const config = {
|
||||||
sourceMap: true,
|
sourceMap: true,
|
||||||
sassOptions: {
|
sassOptions: {
|
||||||
functions: {
|
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) => {
|
"font64($font)": (font) => {
|
||||||
const file = path.resolve(__dirname, "src/fonts", font.getValue());
|
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" })}"`);
|
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 }));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -96,7 +79,7 @@ const config = {
|
||||||
.replace(/^---(.*?\r?\n)+---(.*?\r?\n)*?(?=\S)/, "") // Replace GitHub header
|
.replace(/^---(.*?\r?\n)+---(.*?\r?\n)*?(?=\S)/, "") // Replace GitHub header
|
||||||
.replace(/\*\*Desktop Setup\*\*\r?\n(- .*?\r?\n)+\r?\n/, "") // Replace **Desktop Setup** block
|
.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.DRIBBBLISH_VERSION": JSON.stringify(process.env.DRIBBBLISH_VERSION ?? "Dev"),
|
||||||
"process.env.COMMIT_HASH": JSON.stringify(process.env.COMMIT_HASH ?? "local")
|
"process.env.COMMIT_HASH": JSON.stringify(process.env.COMMIT_HASH ?? "local")
|
||||||
}),
|
}),
|
||||||
|
|
@ -106,5 +89,3 @@ const config = {
|
||||||
})
|
})
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
export default config;
|
|
||||||
Loading…
Reference in a new issue