mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 03:34:40 +00:00
feat(ThemePreview): update to follow blob format
This commit is contained in:
@@ -38,6 +38,7 @@ import documentLoadCSS from '@/css/documentload.scss?inline'
|
|||||||
import renderSvelte from '@/svelte-interface/main'
|
import renderSvelte from '@/svelte-interface/main'
|
||||||
import Settings from '@/svelte-interface/pages/settings.svelte'
|
import Settings from '@/svelte-interface/pages/settings.svelte'
|
||||||
import { settingsPopup } from './svelte-interface/hooks/SettingsPopup'
|
import { settingsPopup } from './svelte-interface/hooks/SettingsPopup'
|
||||||
|
import { OpenThemeCreator } from './seqta/ui/ThemeCreator'
|
||||||
|
|
||||||
let SettingsClicked = false
|
let SettingsClicked = false
|
||||||
export let MenuOptionsOpen = false
|
export let MenuOptionsOpen = false
|
||||||
@@ -461,6 +462,8 @@ export async function finishLoad() {
|
|||||||
console.error("Error during loading cleanup:", err);
|
console.error("Error during loading cleanup:", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenThemeCreator()
|
||||||
|
|
||||||
if (settingsState.justupdated && !document.getElementById('whatsnewbk')) {
|
if (settingsState.justupdated && !document.getElementById('whatsnewbk')) {
|
||||||
OpenWhatsNewPopup();
|
OpenWhatsNewPopup();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import renderSvelte from "@/svelte-interface/main"
|
import renderSvelte from "@/svelte-interface/main"
|
||||||
import themeCreator from "@/svelte-interface/pages/themeCreator.svelte"
|
import themeCreator from "@/svelte-interface/pages/themeCreator.svelte"
|
||||||
import { unmount } from "svelte"
|
import { unmount } from "svelte"
|
||||||
|
import { ClearThemePreview } from "./themes/UpdateThemePreview"
|
||||||
|
|
||||||
let themeCreatorSvelteApp: any = null
|
let themeCreatorSvelteApp: any = null
|
||||||
|
|
||||||
@@ -30,7 +31,11 @@ export function OpenThemeCreator(themeID: string = "") {
|
|||||||
const closeButton = document.createElement("button")
|
const closeButton = document.createElement("button")
|
||||||
closeButton.classList.add("themeCloseButton")
|
closeButton.classList.add("themeCloseButton")
|
||||||
closeButton.textContent = "×"
|
closeButton.textContent = "×"
|
||||||
closeButton.addEventListener("click", CloseThemeCreator)
|
closeButton.addEventListener("click", () => {
|
||||||
|
CloseThemeCreator()
|
||||||
|
ClearThemePreview()
|
||||||
|
})
|
||||||
|
|
||||||
document.body.appendChild(closeButton)
|
document.body.appendChild(closeButton)
|
||||||
|
|
||||||
const resizeBar = document.createElement("div")
|
const resizeBar = document.createElement("div")
|
||||||
|
|||||||
@@ -1,17 +1,5 @@
|
|||||||
import { base64toblobURL } from '@/seqta/utils/imageConversions';
|
|
||||||
|
|
||||||
export const imageData: Record<string, { url: string; variableName: string }> = {};
|
export const imageData: Record<string, { url: string; variableName: string }> = {};
|
||||||
|
|
||||||
export const UpdateImageData = (image: { id: string; base64: string }) => {
|
|
||||||
const { id, base64 } = image;
|
|
||||||
|
|
||||||
if (imageData[id]) {
|
|
||||||
imageData[id].url = base64toblobURL(base64);
|
|
||||||
const { variableName } = imageData[id];
|
|
||||||
document.documentElement.style.setProperty('--' + variableName, `url(${imageData[id].url})`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export function applyCustomCSS(customCSS: string) {
|
export function applyCustomCSS(customCSS: string) {
|
||||||
let styleElement = document.getElementById('custom-theme');
|
let styleElement = document.getElementById('custom-theme');
|
||||||
if (!styleElement) {
|
if (!styleElement) {
|
||||||
|
|||||||
@@ -1,65 +1,75 @@
|
|||||||
import type { CustomThemeBase64 } from '@/types/CustomThemes';
|
import type { LoadedCustomTheme } from '@/types/CustomThemes';
|
||||||
import { applyCustomCSS, imageData, removeImageFromDocument, UpdateImageData } from './Themes';
|
import { applyCustomCSS, removeImageFromDocument } from './Themes';
|
||||||
import { settingsState } from '@/seqta/utils/listeners/SettingsState';
|
import { settingsState } from '@/seqta/utils/listeners/SettingsState';
|
||||||
|
|
||||||
|
let previousImageVariableNames: string[] = [];
|
||||||
|
let originalColor: string | null = null;
|
||||||
|
let originalTheme: boolean | null = null;
|
||||||
|
|
||||||
export const UpdateThemePreview = async (updatedTheme: CustomThemeBase64 /* Omit<CustomTheme, 'CustomImages'> & { CustomImages: Omit<CustomImage, 'blob'>[] } */) => {
|
export const UpdateThemePreview = async (updatedTheme: LoadedCustomTheme) => {
|
||||||
const { CustomCSS, CustomImages, defaultColour } = updatedTheme;
|
const { CustomCSS, CustomImages, defaultColour, forceDark } = updatedTheme;
|
||||||
|
|
||||||
if (updatedTheme.forceDark != undefined) {
|
// Update dark mode setting
|
||||||
if (updatedTheme.forceDark) {
|
if (forceDark !== undefined) {
|
||||||
settingsState.DarkMode = true;
|
// Store the original theme if it hasn't been stored yet
|
||||||
} else {
|
if (originalTheme === null) {
|
||||||
settingsState.DarkMode = false;
|
originalTheme = settingsState.DarkMode;
|
||||||
}
|
}
|
||||||
|
settingsState.DarkMode = forceDark;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update image data
|
// Get the new image variable names
|
||||||
const currentImageIds = Object.keys(imageData);
|
const newImageVariableNames = CustomImages.map(image => image.variableName);
|
||||||
const updatedImageIds = CustomImages.map((image) => image.id);
|
|
||||||
|
|
||||||
// Remove unused images from imageData and document
|
// Remove images that are no longer present
|
||||||
currentImageIds.forEach((imageId) => {
|
previousImageVariableNames.forEach(variableName => {
|
||||||
if (!updatedImageIds.includes(imageId)) {
|
if (!newImageVariableNames.includes(variableName)) {
|
||||||
const { variableName } = imageData[imageId];
|
|
||||||
removeImageFromDocument(variableName);
|
removeImageFromDocument(variableName);
|
||||||
delete imageData[imageId];
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update or add new images to imageData
|
// Update or add new images
|
||||||
CustomImages.forEach((image) => {
|
CustomImages.forEach((image: any) => {
|
||||||
const existingImage = imageData[image.id];
|
document.documentElement.style.setProperty(`--${image.variableName}`, `url(${image.url})`);
|
||||||
|
|
||||||
if (existingImage && existingImage.variableName !== image.variableName) {
|
|
||||||
// Remove the previous variableName from the document
|
|
||||||
removeImageFromDocument(existingImage.variableName);
|
|
||||||
|
|
||||||
// Update the variableName in imageData
|
|
||||||
imageData[image.id].variableName = image.variableName;
|
|
||||||
|
|
||||||
// Update the variableName in the document
|
|
||||||
document.documentElement.style.setProperty('--' + image.variableName, `url(${existingImage.url})`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (image.url) {
|
|
||||||
UpdateImageData({
|
|
||||||
id: image.id,
|
|
||||||
base64: image.url
|
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
imageData[image.id] = {
|
// Update the previousImageVariableNames for the next run
|
||||||
url: imageData[image.id]?.url || '',
|
previousImageVariableNames = newImageVariableNames;
|
||||||
variableName: image.variableName,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Apply custom CSS
|
// Apply custom CSS
|
||||||
applyCustomCSS(CustomCSS);
|
applyCustomCSS(CustomCSS);
|
||||||
|
|
||||||
// Apply default color
|
// Apply default color
|
||||||
if (defaultColour !== '') {
|
if (defaultColour) {
|
||||||
settingsState.selectedColor = defaultColour
|
// Store the original color if it hasn't been stored yet
|
||||||
|
if (originalColor === null) {
|
||||||
|
originalColor = settingsState.selectedColor;
|
||||||
|
}
|
||||||
|
settingsState.selectedColor = defaultColour;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const ClearThemePreview = () => {
|
||||||
|
previousImageVariableNames.forEach(variableName => {
|
||||||
|
removeImageFromDocument(variableName);
|
||||||
|
});
|
||||||
|
|
||||||
|
previousImageVariableNames = [];
|
||||||
|
|
||||||
|
let styleElement = document.getElementById('custom-theme');
|
||||||
|
if (styleElement) {
|
||||||
|
styleElement.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the color to the original value
|
||||||
|
if (originalColor !== null) {
|
||||||
|
settingsState.selectedColor = originalColor;
|
||||||
|
originalColor = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset the theme (dark/light mode) to the original value
|
||||||
|
if (originalTheme !== null) {
|
||||||
|
settingsState.DarkMode = originalTheme;
|
||||||
|
originalTheme = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,27 +1,18 @@
|
|||||||
import localforage from 'localforage';
|
import localforage from 'localforage';
|
||||||
import type { CustomTheme, CustomThemeBase64 } from '@/types/CustomThemes';
|
import type { LoadedCustomTheme } from '@/types/CustomThemes';
|
||||||
import { disableTheme } from './disableTheme';
|
import { disableTheme } from './disableTheme';
|
||||||
|
|
||||||
|
|
||||||
export const saveTheme = async (theme: CustomThemeBase64) => {
|
export const saveTheme = async (theme: LoadedCustomTheme) => {
|
||||||
try {
|
try {
|
||||||
const updatedTheme: CustomTheme = {
|
|
||||||
...theme,
|
|
||||||
coverImage: theme.coverImage ? await fetch(theme.coverImage).then((res) => res.blob()) : null,
|
|
||||||
CustomImages: await Promise.all(
|
|
||||||
theme.CustomImages.map(async (image) => ({
|
|
||||||
id: image.id,
|
|
||||||
blob: await fetch(image.url).then((res) => res.blob()),
|
|
||||||
variableName: image.variableName,
|
|
||||||
}))
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
disableTheme();
|
disableTheme();
|
||||||
|
|
||||||
console.debug('Theme to save:', updatedTheme);
|
console.debug('Theme to save:', theme);
|
||||||
|
|
||||||
await localforage.setItem(updatedTheme.id, updatedTheme);
|
/* remove blob urls from theme */
|
||||||
|
const updatedTheme = { ...theme, CustomImages: theme.CustomImages.map((image) => ({ ...image, blob: null })) }
|
||||||
|
|
||||||
|
await localforage.setItem(theme.id, updatedTheme);
|
||||||
await localforage.getItem('customThemes').then((themes: unknown) => {
|
await localforage.getItem('customThemes').then((themes: unknown) => {
|
||||||
const themeList = themes as string[] | null;
|
const themeList = themes as string[] | null;
|
||||||
if (themeList) {
|
if (themeList) {
|
||||||
|
|||||||
@@ -22,6 +22,9 @@
|
|||||||
handleImageVariableChange,
|
handleImageVariableChange,
|
||||||
handleCoverImageUpload
|
handleCoverImageUpload
|
||||||
} from '../utils/themeImageHandlers';
|
} from '../utils/themeImageHandlers';
|
||||||
|
import { ClearThemePreview, UpdateThemePreview } from '@/seqta/ui/themes/UpdateThemePreview'
|
||||||
|
import { saveTheme } from '@/seqta/ui/themes/saveTheme'
|
||||||
|
import { CloseThemeCreator } from '@/seqta/ui/ThemeCreator'
|
||||||
|
|
||||||
const { themeID } = $props<{ themeID: string }>()
|
const { themeID } = $props<{ themeID: string }>()
|
||||||
let theme = $state<LoadedCustomTheme>({
|
let theme = $state<LoadedCustomTheme>({
|
||||||
@@ -83,8 +86,16 @@
|
|||||||
theme = await handleCoverImageUpload(event, theme);
|
theme = await handleCoverImageUpload(event, theme);
|
||||||
}
|
}
|
||||||
|
|
||||||
$effect(() => {
|
function submitTheme() {
|
||||||
|
console.log('saving theme', theme)
|
||||||
|
|
||||||
|
ClearThemePreview();
|
||||||
|
saveTheme(theme);
|
||||||
|
CloseThemeCreator();
|
||||||
|
}
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
UpdateThemePreview(theme);
|
||||||
});
|
});
|
||||||
|
|
||||||
type SettingType = 'switch' | 'button' | 'slider' | 'colourPicker' | 'select' | 'codeEditor' | 'imageUpload' | 'conditional' | 'lightDarkToggle';
|
type SettingType = 'switch' | 'button' | 'slider' | 'colourPicker' | 'select' | 'codeEditor' | 'imageUpload' | 'conditional' | 'lightDarkToggle';
|
||||||
@@ -314,9 +325,7 @@
|
|||||||
{/each}
|
{/each}
|
||||||
|
|
||||||
<button
|
<button
|
||||||
onclick={() => {
|
onclick={submitTheme}
|
||||||
console.log(theme)
|
|
||||||
}}
|
|
||||||
class="w-full px-4 py-2 mt-3 text-[13px] dark:text-white transition rounded-xl bg-zinc-200 dark:bg-zinc-700/50">
|
class="w-full px-4 py-2 mt-3 text-[13px] dark:text-white transition rounded-xl bg-zinc-200 dark:bg-zinc-700/50">
|
||||||
Save Theme
|
Save Theme
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -16,12 +16,12 @@ export type CustomTheme = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export type LoadedCustomTheme = CustomTheme & {
|
export type LoadedCustomTheme = CustomTheme & {
|
||||||
CustomImages: Array<{
|
CustomImages: {
|
||||||
id: string;
|
id: string;
|
||||||
blob: Blob;
|
blob: Blob;
|
||||||
variableName: string;
|
variableName: string;
|
||||||
url: string | null;
|
url: string | null;
|
||||||
}>;
|
}[];
|
||||||
coverImageUrl?: string;
|
coverImageUrl?: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -35,17 +35,6 @@ export type CustomImage = {
|
|||||||
variableName: string;
|
variableName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CustomImageBase64 = {
|
|
||||||
id: string;
|
|
||||||
url: string;
|
|
||||||
variableName: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type CustomThemeBase64 = Omit<CustomTheme, 'CustomImages'> & {
|
|
||||||
CustomImages: CustomImageBase64[];
|
|
||||||
coverImage: string | null;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ThemeList = {
|
export type ThemeList = {
|
||||||
themes: CustomTheme[];
|
themes: CustomTheme[];
|
||||||
selectedTheme: string;
|
selectedTheme: string;
|
||||||
|
|||||||
Reference in New Issue
Block a user