mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 03:34:40 +00:00
format: run prettify
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import ColorPicker from "react-best-gradient-color-picker"
|
||||
import { useEffect, useRef, useState } from "react"
|
||||
import { settingsState } from "@/seqta/utils/listeners/SettingsState.ts"
|
||||
import ColorPicker from "react-best-gradient-color-picker";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { settingsState } from "@/seqta/utils/listeners/SettingsState.ts";
|
||||
|
||||
const defaultPresets = [
|
||||
"linear-gradient(30deg, rgba(229,209,218,1) 0%, RGBA(235,169,202,1) 46%, rgba(214,155,162,1) 100%)",
|
||||
@@ -22,12 +22,12 @@ const defaultPresets = [
|
||||
"rgba(30, 64, 175, 0.89)",
|
||||
"rgba(134, 25, 143, 1)",
|
||||
"rgba(14, 165, 233, 0.9)",
|
||||
]
|
||||
];
|
||||
|
||||
interface PickerProps {
|
||||
customOnChange?: (color: string) => void
|
||||
customState?: string
|
||||
savePresets?: boolean
|
||||
customOnChange?: (color: string) => void;
|
||||
customState?: string;
|
||||
savePresets?: boolean;
|
||||
}
|
||||
|
||||
export default function Picker({
|
||||
@@ -35,37 +35,49 @@ export default function Picker({
|
||||
customState,
|
||||
savePresets = true,
|
||||
}: PickerProps) {
|
||||
const [customThemeColor, setCustomThemeColor] = useState<string | null>()
|
||||
const [presets, setPresets] = useState<string[]>()
|
||||
const [customThemeColor, setCustomThemeColor] = useState<string | null>();
|
||||
const [presets, setPresets] = useState<string[]>();
|
||||
|
||||
const latestValuesRef = useRef({ customThemeColor, customOnChange, savePresets, presets });
|
||||
const latestValuesRef = useRef({
|
||||
customThemeColor,
|
||||
customOnChange,
|
||||
savePresets,
|
||||
presets,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (customState !== undefined && customState !== null) {
|
||||
setCustomThemeColor(customState)
|
||||
setCustomThemeColor(customState);
|
||||
} else {
|
||||
setCustomThemeColor(settingsState.selectedColor ?? null)
|
||||
setCustomThemeColor(settingsState.selectedColor ?? null);
|
||||
}
|
||||
|
||||
if (presets === undefined) {
|
||||
const savedPresets = localStorage.getItem("colorPickerPresets")
|
||||
setPresets(savedPresets ? JSON.parse(savedPresets) : defaultPresets)
|
||||
const savedPresets = localStorage.getItem("colorPickerPresets");
|
||||
setPresets(savedPresets ? JSON.parse(savedPresets) : defaultPresets);
|
||||
}
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
latestValuesRef.current = { customThemeColor, customOnChange, savePresets, presets };
|
||||
latestValuesRef.current = {
|
||||
customThemeColor,
|
||||
customOnChange,
|
||||
savePresets,
|
||||
presets,
|
||||
};
|
||||
}, [customThemeColor, customOnChange, savePresets, presets]);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
const { customThemeColor, customOnChange, savePresets, presets } = latestValuesRef.current;
|
||||
if (!(customThemeColor && !customOnChange && savePresets && presets)) return;
|
||||
|
||||
const { customThemeColor, customOnChange, savePresets, presets } =
|
||||
latestValuesRef.current;
|
||||
if (!(customThemeColor && !customOnChange && savePresets && presets))
|
||||
return;
|
||||
|
||||
// Only proceed if presets are different (avoid unnecessary updates)
|
||||
const existingIndex = presets.indexOf(customThemeColor);
|
||||
let updatedPresets;
|
||||
|
||||
|
||||
if (existingIndex === 0) {
|
||||
// No need to update if the selected color is already the first element
|
||||
return;
|
||||
@@ -78,16 +90,19 @@ export default function Picker({
|
||||
} else {
|
||||
updatedPresets = [customThemeColor, ...presets].slice(0, 18);
|
||||
}
|
||||
|
||||
localStorage.setItem("colorPickerPresets", JSON.stringify(updatedPresets));
|
||||
}
|
||||
}, [])
|
||||
|
||||
localStorage.setItem(
|
||||
"colorPickerPresets",
|
||||
JSON.stringify(updatedPresets),
|
||||
);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
if (customThemeColor && !customOnChange) {
|
||||
settingsState.selectedColor = customThemeColor
|
||||
settingsState.selectedColor = customThemeColor;
|
||||
}
|
||||
}, [customThemeColor, customOnChange])
|
||||
}, [customThemeColor, customOnChange]);
|
||||
|
||||
return (
|
||||
<ColorPicker
|
||||
@@ -97,12 +112,12 @@ export default function Picker({
|
||||
value={customThemeColor ?? ""}
|
||||
onChange={(color: string) => {
|
||||
if (customOnChange) {
|
||||
customOnChange(color)
|
||||
setCustomThemeColor(color)
|
||||
customOnChange(color);
|
||||
setCustomThemeColor(color);
|
||||
} else {
|
||||
setCustomThemeColor(color)
|
||||
setCustomThemeColor(color);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.dark .switch[data-ison="true"],
|
||||
.switch[data-ison="true"] {
|
||||
background-color: #30D259;
|
||||
}
|
||||
background-color: #30d259;
|
||||
}
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
.tab-width {
|
||||
width: var(--tab-width);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { type DBSchema, type IDBPDatabase, openDB } from 'idb';
|
||||
import { type DBSchema, type IDBPDatabase, openDB } from "idb";
|
||||
|
||||
interface BackgroundDB extends DBSchema {
|
||||
backgrounds: {
|
||||
@@ -16,38 +16,46 @@ let db: IDBPDatabase<BackgroundDB> | null = null;
|
||||
export async function openDatabase(): Promise<IDBPDatabase<BackgroundDB>> {
|
||||
if (db) return db;
|
||||
|
||||
db = await openDB<BackgroundDB>('BackgroundDB', 1, {
|
||||
db = await openDB<BackgroundDB>("BackgroundDB", 1, {
|
||||
upgrade(db: IDBPDatabase<BackgroundDB>) {
|
||||
db.createObjectStore('backgrounds', { keyPath: 'id' });
|
||||
db.createObjectStore("backgrounds", { keyPath: "id" });
|
||||
},
|
||||
});
|
||||
|
||||
return db;
|
||||
}
|
||||
|
||||
export async function readAllData(): Promise<Array<{ id: string; type: string; blob: Blob }>> {
|
||||
export async function readAllData(): Promise<
|
||||
Array<{ id: string; type: string; blob: Blob }>
|
||||
> {
|
||||
const db = await openDatabase();
|
||||
return db.getAll('backgrounds');
|
||||
return db.getAll("backgrounds");
|
||||
}
|
||||
|
||||
export async function writeData(id: string, type: string, blob: Blob): Promise<void> {
|
||||
export async function writeData(
|
||||
id: string,
|
||||
type: string,
|
||||
blob: Blob,
|
||||
): Promise<void> {
|
||||
const db = await openDatabase();
|
||||
await db.put('backgrounds', { id, type, blob });
|
||||
await db.put("backgrounds", { id, type, blob });
|
||||
}
|
||||
|
||||
export async function deleteData(id: string): Promise<void> {
|
||||
const db = await openDatabase();
|
||||
await db.delete('backgrounds', id);
|
||||
await db.delete("backgrounds", id);
|
||||
}
|
||||
|
||||
export async function clearAllData(): Promise<void> {
|
||||
const db = await openDatabase();
|
||||
await db.clear('backgrounds');
|
||||
await db.clear("backgrounds");
|
||||
}
|
||||
|
||||
export async function getDataById(id: string): Promise<{ id: string; type: string; blob: Blob } | undefined> {
|
||||
export async function getDataById(
|
||||
id: string,
|
||||
): Promise<{ id: string; type: string; blob: Blob } | undefined> {
|
||||
const db = await openDatabase();
|
||||
return db.get('backgrounds', id);
|
||||
return db.get("backgrounds", id);
|
||||
}
|
||||
|
||||
export function closeDatabase(): void {
|
||||
@@ -59,17 +67,19 @@ export function closeDatabase(): void {
|
||||
|
||||
// Helper function to check if IndexedDB is supported
|
||||
export function isIndexedDBSupported(): boolean {
|
||||
return 'indexedDB' in window;
|
||||
return "indexedDB" in window;
|
||||
}
|
||||
|
||||
// Helper function to check if there's enough storage space
|
||||
export async function hasEnoughStorageSpace(requiredSpace: number): Promise<boolean> {
|
||||
if ('storage' in navigator && 'estimate' in navigator.storage) {
|
||||
export async function hasEnoughStorageSpace(
|
||||
requiredSpace: number,
|
||||
): Promise<boolean> {
|
||||
if ("storage" in navigator && "estimate" in navigator.storage) {
|
||||
const { quota, usage } = await navigator.storage.estimate();
|
||||
if (quota !== undefined && usage !== undefined) {
|
||||
return (quota - usage) > requiredSpace;
|
||||
return quota - usage > requiredSpace;
|
||||
}
|
||||
}
|
||||
// If we can't determine, assume there's enough space
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ class BackgroundUpdates {
|
||||
}
|
||||
|
||||
public triggerUpdate(): void {
|
||||
this.listeners.forEach(callback => callback());
|
||||
this.listeners.forEach((callback) => callback());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
type SettingsPopupCallback = () => void;
|
||||
|
||||
/**
|
||||
/**
|
||||
* This is a singleton that triggers an update when the settings popup is closed.
|
||||
* This is used to close the colour picker.
|
||||
* Usage:
|
||||
* settingsPopup.addListener(() => {
|
||||
* console.log('Settings popup closed');
|
||||
* });
|
||||
*/
|
||||
*/
|
||||
class SettingsPopup {
|
||||
private static instance: SettingsPopup;
|
||||
private listeners: Set<SettingsPopupCallback> = new Set();
|
||||
@@ -30,7 +30,7 @@ class SettingsPopup {
|
||||
}
|
||||
|
||||
public triggerClose(): void {
|
||||
this.listeners.forEach(callback => callback());
|
||||
this.listeners.forEach((callback) => callback());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ class ThemeUpdates {
|
||||
}
|
||||
|
||||
public triggerUpdate(): void {
|
||||
this.listeners.forEach(callback => callback());
|
||||
this.listeners.forEach((callback) => callback());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
export let selectedBackground = $state<string | null>(null);
|
||||
export let selectedBackground = $state<string | null>(null);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
@import './components/ColourPicker.css';
|
||||
@import "./components/ColourPicker.css";
|
||||
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@@ -47,4 +47,4 @@ input {
|
||||
|
||||
.editorHeight {
|
||||
height: calc(100vh - 58px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<title>BetterSEQTA+ Settings</title>
|
||||
</head>
|
||||
<body class="h-[600px]">
|
||||
<div id="app" style="height: 100%;"></div>
|
||||
<div id="app" style="height: 100%"></div>
|
||||
<script type="module" src="./index.ts"></script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
+15
-15
@@ -1,29 +1,29 @@
|
||||
import "./index.css"
|
||||
import Settings from "./pages/settings.svelte"
|
||||
import IconFamily from '@/resources/fonts/IconFamily.woff'
|
||||
import browser from "webextension-polyfill"
|
||||
import renderSvelte from "./main"
|
||||
import "./index.css";
|
||||
import Settings from "./pages/settings.svelte";
|
||||
import IconFamily from "@/resources/fonts/IconFamily.woff";
|
||||
import browser from "webextension-polyfill";
|
||||
import renderSvelte from "./main";
|
||||
|
||||
function InjectCustomIcons() {
|
||||
console.info('[BetterSEQTA+] Injecting Icons')
|
||||
console.info("[BetterSEQTA+] Injecting Icons");
|
||||
|
||||
const style = document.createElement('style')
|
||||
style.setAttribute('type', 'text/css')
|
||||
const style = document.createElement("style");
|
||||
style.setAttribute("type", "text/css");
|
||||
style.innerHTML = `
|
||||
@font-face {
|
||||
font-family: 'IconFamily';
|
||||
src: url('${browser.runtime.getURL(IconFamily)}') format('woff');
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}`
|
||||
document.head.appendChild(style)
|
||||
}`;
|
||||
document.head.appendChild(style);
|
||||
}
|
||||
|
||||
const mountPoint = document.getElementById('app')
|
||||
const mountPoint = document.getElementById("app");
|
||||
if (!mountPoint) {
|
||||
console.error('Mount point #app not found')
|
||||
throw new Error('Mount point #app not found')
|
||||
console.error("Mount point #app not found");
|
||||
throw new Error("Mount point #app not found");
|
||||
}
|
||||
|
||||
InjectCustomIcons()
|
||||
renderSvelte(Settings, mountPoint, { standalone: true })
|
||||
InjectCustomIcons();
|
||||
renderSvelte(Settings, mountPoint, { standalone: true });
|
||||
|
||||
Vendored
+2
-2
@@ -1,6 +1,6 @@
|
||||
import './index.css';
|
||||
import "./index.css";
|
||||
|
||||
declare module "*.png";
|
||||
declare module "*.svg";
|
||||
declare module "*.jpeg";
|
||||
declare module "*.jpg";
|
||||
declare module "*.jpg";
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { mount } from "svelte"
|
||||
import type { SvelteComponent } from "svelte"
|
||||
import style from './index.css?inline'
|
||||
import { mount } from "svelte";
|
||||
import type { SvelteComponent } from "svelte";
|
||||
import style from "./index.css?inline";
|
||||
|
||||
export default function renderSvelte(
|
||||
Component: SvelteComponent | any,
|
||||
@@ -13,11 +13,11 @@ export default function renderSvelte(
|
||||
standalone: false,
|
||||
...props,
|
||||
},
|
||||
})
|
||||
});
|
||||
|
||||
const styleElement = document.createElement('style')
|
||||
styleElement.textContent = style
|
||||
mountPoint.appendChild(styleElement)
|
||||
const styleElement = document.createElement("style");
|
||||
styleElement.textContent = style;
|
||||
mountPoint.appendChild(styleElement);
|
||||
|
||||
return app
|
||||
return app;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,6 @@ export interface SettingsList {
|
||||
title: string;
|
||||
id: number;
|
||||
description: string;
|
||||
Component: any; /* TODO: Give this a type */
|
||||
Component: any /* TODO: Give this a type */;
|
||||
props?: any;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ export type Theme = {
|
||||
coverImage: string;
|
||||
marqueeImage: string;
|
||||
id: string;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
import type { Subscriber, Unsubscriber } from "svelte/store";
|
||||
|
||||
export class Standalone {
|
||||
private static instance: Standalone;
|
||||
private _standalone = $state(false);
|
||||
private subscribers = new Set<Subscriber<boolean>>();
|
||||
private static instance: Standalone;
|
||||
private _standalone = $state(false);
|
||||
private subscribers = new Set<Subscriber<boolean>>();
|
||||
|
||||
private constructor() {}
|
||||
private constructor() {}
|
||||
|
||||
public static getInstance(): Standalone {
|
||||
if (!Standalone.instance) {
|
||||
Standalone.instance = new Standalone();
|
||||
}
|
||||
return Standalone.instance;
|
||||
}
|
||||
public static getInstance(): Standalone {
|
||||
if (!Standalone.instance) {
|
||||
Standalone.instance = new Standalone();
|
||||
}
|
||||
return Standalone.instance;
|
||||
}
|
||||
|
||||
public setStandalone(value: boolean) {
|
||||
this._standalone = value;
|
||||
this.subscribers.forEach(subscriber => subscriber(value));
|
||||
}
|
||||
public setStandalone(value: boolean) {
|
||||
this._standalone = value;
|
||||
this.subscribers.forEach((subscriber) => subscriber(value));
|
||||
}
|
||||
|
||||
public get standalone() {
|
||||
return this._standalone;
|
||||
}
|
||||
public get standalone() {
|
||||
return this._standalone;
|
||||
}
|
||||
|
||||
public subscribe(run: Subscriber<boolean>): Unsubscriber {
|
||||
this.subscribers.add(run);
|
||||
run(this._standalone);
|
||||
public subscribe(run: Subscriber<boolean>): Unsubscriber {
|
||||
this.subscribers.add(run);
|
||||
run(this._standalone);
|
||||
|
||||
return () => {
|
||||
this.subscribers.delete(run);
|
||||
};
|
||||
}
|
||||
return () => {
|
||||
this.subscribers.delete(run);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const standalone = Standalone.getInstance();
|
||||
export const standalone = Standalone.getInstance();
|
||||
|
||||
@@ -1,23 +1,31 @@
|
||||
import type { LoadedCustomTheme } from '@/types/CustomThemes';
|
||||
import type { LoadedCustomTheme } from "@/types/CustomThemes";
|
||||
|
||||
export function generateImageId(): string {
|
||||
return Math.random().toString(36).substr(2, 9);
|
||||
}
|
||||
|
||||
export function handleImageUpload(event: Event, theme: LoadedCustomTheme): Promise<LoadedCustomTheme> | LoadedCustomTheme {
|
||||
export function handleImageUpload(
|
||||
event: Event,
|
||||
theme: LoadedCustomTheme,
|
||||
): Promise<LoadedCustomTheme> | LoadedCustomTheme {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const file = input.files?.[0];
|
||||
input.value = '';
|
||||
input.value = "";
|
||||
if (file) {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = async () => {
|
||||
const imageBlob = await fetch(reader.result as string).then(res => res.blob());
|
||||
const imageBlob = await fetch(reader.result as string).then((res) =>
|
||||
res.blob(),
|
||||
);
|
||||
const imageId = generateImageId();
|
||||
const variableName = `custom-image-${theme.CustomImages.length}`;
|
||||
resolve({
|
||||
...theme,
|
||||
CustomImages: [...theme.CustomImages, { id: imageId, blob: imageBlob, variableName, url: null }],
|
||||
CustomImages: [
|
||||
...theme.CustomImages,
|
||||
{ id: imageId, blob: imageBlob, variableName, url: null },
|
||||
],
|
||||
});
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
@@ -26,35 +34,47 @@ export function handleImageUpload(event: Event, theme: LoadedCustomTheme): Promi
|
||||
return theme;
|
||||
}
|
||||
|
||||
export function handleRemoveImage(imageId: string, theme: LoadedCustomTheme): LoadedCustomTheme {
|
||||
export function handleRemoveImage(
|
||||
imageId: string,
|
||||
theme: LoadedCustomTheme,
|
||||
): LoadedCustomTheme {
|
||||
return {
|
||||
...theme,
|
||||
CustomImages: theme.CustomImages.filter((image) => image.id !== imageId),
|
||||
} as LoadedCustomTheme;
|
||||
}
|
||||
|
||||
export function handleImageVariableChange(imageId: string, variableName: string, theme: LoadedCustomTheme): LoadedCustomTheme {
|
||||
export function handleImageVariableChange(
|
||||
imageId: string,
|
||||
variableName: string,
|
||||
theme: LoadedCustomTheme,
|
||||
): LoadedCustomTheme {
|
||||
return {
|
||||
...theme,
|
||||
CustomImages: theme.CustomImages.map((image) =>
|
||||
image.id === imageId ? { ...image, variableName } : image
|
||||
image.id === imageId ? { ...image, variableName } : image,
|
||||
),
|
||||
} as LoadedCustomTheme;
|
||||
}
|
||||
|
||||
export function handleCoverImageUpload(event: Event, theme: LoadedCustomTheme): Promise<LoadedCustomTheme> {
|
||||
export function handleCoverImageUpload(
|
||||
event: Event,
|
||||
theme: LoadedCustomTheme,
|
||||
): Promise<LoadedCustomTheme> {
|
||||
const input = event.target as HTMLInputElement;
|
||||
const file = input.files?.[0];
|
||||
input.value = '';
|
||||
input.value = "";
|
||||
if (file) {
|
||||
return new Promise((resolve) => {
|
||||
const reader = new FileReader();
|
||||
reader.onload = async () => {
|
||||
const imageBlob = await fetch(reader.result as string).then(res => res.blob());
|
||||
const imageBlob = await fetch(reader.result as string).then((res) =>
|
||||
res.blob(),
|
||||
);
|
||||
resolve({ ...theme, coverImage: imageBlob });
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
});
|
||||
}
|
||||
return Promise.resolve(theme);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user