feat: add .css theme file upload and a unstyled theme selector

This commit is contained in:
Rick van Lieshout 2023-05-08 22:31:22 +02:00
parent 757f8511c0
commit 77a853e980
4 changed files with 154 additions and 25 deletions

View File

@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- moved from Javascript to Typescript for all files - moved from Javascript to Typescript for all files
- use `npm run watch` to watch for changes & recompile typescript and sass files - use `npm run watch` to watch for changes & recompile typescript and sass files
- Added support for theming the application
## 5.1.0 ## 5.1.0
### New features ### New features

View File

@ -1,5 +1,6 @@
import remote from "@electron/remote"; import remote from "@electron/remote";
import { ipcRenderer, shell } from "electron"; import { ipcRenderer, shell } from "electron";
import fs from "fs";
import { globalEvents } from "../../constants/globalEvents"; import { globalEvents } from "../../constants/globalEvents";
import { settings } from "../../constants/settings"; import { settings } from "../../constants/settings";
import { settingsStore } from "./../../scripts/settings"; import { settingsStore } from "./../../scripts/settings";
@ -24,6 +25,36 @@ let adBlock: HTMLInputElement,
trayIcon: HTMLInputElement, trayIcon: HTMLInputElement,
updateFrequency: HTMLInputElement; updateFrequency: HTMLInputElement;
function getThemeFiles() {
const selectElement = document.getElementById("themesList") as HTMLSelectElement;
const fileNames = fs.readdirSync(process.resourcesPath).filter((file) => file.endsWith(".css"));
const options = fileNames.map((name) => {
return new Option(name, name);
});
// empty old options
const oldOptions = document.querySelectorAll("#themesList option");
oldOptions.forEach((o) => o.remove());
[new Option("Tidal - Default", "none")].concat(options).forEach((option) => {
selectElement.add(option, null);
});
}
function handleFileUploads() {
const fileMessage = document.getElementById("file-message");
fileMessage.innerText = "or drag and drop files here";
document.getElementById("theme-files").addEventListener("change", function (e: any) {
Array.from(e.target.files).forEach((file: File) => {
const destination = `${process.resourcesPath}/${file.name}`;
fs.copyFileSync(file.path, destination, null);
});
fileMessage.innerText = `${e.target.files.length} files successfully uploaded`;
getThemeFiles();
});
}
/** /**
* Sync the UI forms with the current settings * Sync the UI forms with the current settings
*/ */
@ -79,6 +110,9 @@ window.addEventListener("DOMContentLoaded", () => {
return document.getElementById(id) as HTMLInputElement; return document.getElementById(id) as HTMLInputElement;
} }
getThemeFiles();
handleFileUploads();
document.getElementById("close").addEventListener("click", hide); document.getElementById("close").addEventListener("click", hide);
document.getElementById("restart").addEventListener("click", restart); document.getElementById("restart").addEventListener("click", restart);
document.querySelectorAll(".external-link").forEach((elem) => document.querySelectorAll(".external-link").forEach((elem) =>

View File

@ -35,6 +35,9 @@
<input type="radio" name="tab" id="advanced" /> <input type="radio" name="tab" id="advanced" />
<label for="advanced">Advanced</label> <label for="advanced">Advanced</label>
<input type="radio" name="tab" id="theming" />
<label for="theming">Theming</label>
<input type="radio" name="tab" id="about" /> <input type="radio" name="tab" id="about" />
<label for="about">About</label> <label for="about">About</label>
@ -226,6 +229,49 @@
<input id="updateFrequency" type="number" class="text-input" name="updateFrequency" /> <input id="updateFrequency" type="number" class="text-input" name="updateFrequency" />
</div> </div>
</div> </div>
<div class="group">
<p class="group__title">Flags</p>
<div class="group__option">
<div class="group__description">
<h4>Disable hardware built-in media keys</h4>
<p>
Also prevents certain desktop environments from recognizing the chrome MPRIS
client separately from the custom MPRIS client.
</p>
</div>
<label class="switch">
<input id="disableHardwareMediaKeys" type="checkbox" />
<span class="switch__slider"></span>
</label>
</div>
<div class="group__option">
<div class="group__description">
<h4>Enable GPU rasterization</h4>
<p>Move a part of the rendering to the GPU for increased performance.</p>
</div>
<label class="switch">
<input id="gpuRasterization" type="checkbox" />
<span class="switch__slider"></span>
</label>
</div>
<div class="group__option">
<div class="group__description">
<h4>Disable Background Throttling</h4>
<p>
Makes app more responsive while in the background, at the cost of performance.
</p>
</div>
<label class="switch">
<input id="disableBackgroundThrottle" type="checkbox" />
<span class="switch__slider"></span>
</label>
</div>
</div>
</section>
<section id="theming-section" class="tabs__section">
<div class="group">
<p class="group__title">Theming</p>
<div class="group__option"> <div class="group__option">
<div class="group__description"> <div class="group__description">
<h4>Custom CSS</h4> <h4>Custom CSS</h4>
@ -238,41 +284,34 @@
<textarea id="customCSS" class="textarea" cols="40" rows="8" spellcheck="false"></textarea> <textarea id="customCSS" class="textarea" cols="40" rows="8" spellcheck="false"></textarea>
<div class="group"> <div class="group">
<p class="group__title">Flags</p> <p class="group__title">Theme files</p>
<div class="group__option"> <div class="group__option">
<div class="group__description"> <div class="group__description">
<h4>Disable hardware built-in media keys</h4> <h4>Current theme</h4>
<p> <p>
Also prevents certain desktop environments from recognizing the chrome MPRIS Select a theme below or "Tidal - Default" to return to the original Tidal look.
client separately from the custom MPRIS client.
</p> </p>
<select id="themesList" name="themesList">
</select>
</div> </div>
<label class="switch">
<input id="disableHardwareMediaKeys" type="checkbox" />
<span class="switch__slider"></span>
</label>
</div> </div>
<div class="group__option"> <div class="group__option">
<div class="group__description"> <div class="group__description">
<h4>Enable GPU rasterization</h4> <h4>Upload new themes</h4>
<p>Move a part of the rendering to the GPU for increased performance.</p>
</div>
<label class="switch">
<input id="gpuRasterization" type="checkbox" />
<span class="switch__slider"></span>
</label>
</div>
<div class="group__option">
<div class="group__description">
<h4>Disable Background Throttling</h4>
<p> <p>
Makes app more responsive while in the background, at the cost of performance. Click the button and select the css files to import. They will be added to the theme list
automatically.
</p> </p>
<div class="file-drop-area">
<div>
<span class="file-btn">Choose files</span>
<span id="file-message" class="file-msg">or drag and drop files here</span>
<input id="theme-files" class="file-input" type="file" accept=".css" multiple>
</div>
</div>
</div> </div>
<label class="switch">
<input id="disableBackgroundThrottle" type="checkbox" />
<span class="switch__slider"></span>
</label>
</div> </div>
</div> </div>
</section> </section>

View File

@ -156,7 +156,7 @@ html {
display: none; display: none;
} }
@for $i from 1 to 6 { @for $i from 1 to 7 {
.settings > input:nth-child(#{$i * 2 - 1}):checked ~ & > .tabs__section:nth-child(#{$i}) { .settings > input:nth-child(#{$i * 2 - 1}):checked ~ & > .tabs__section:nth-child(#{$i}) {
display: block; display: block;
} }
@ -361,3 +361,57 @@ html {
} }
} }
} }
// file upload
.file-drop-area {
position: relative;
display: flex;
align-items: center;
width: 100%;
max-width: 100%;
padding: 25px 0 25px 0px;
border: 1px dashed $tidal-grey;
border-radius: 3px;
transition: 0.2s;
&.is-active {
background-color: $black;
}
div {
padding-left: 25px;
}
}
.file-btn {
flex-shrink: 0;
background-color: $black;
border: 1px solid $tidal-grey;
border-radius: 3px;
padding: 8px 15px;
margin-right: 10px;
font-size: 12px;
text-transform: uppercase;
}
.file-msg {
font-size: small;
font-weight: 300;
line-height: 1.4;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.file-input {
position: absolute;
left: 0;
top: 0;
height: 100%;
width: 100%;
cursor: pointer;
opacity: 0;
&:focus {
outline: none;
}
}