mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 11:44:40 +00:00
add custom cover images to themes.
This commit is contained in:
@@ -54,16 +54,13 @@ export const ThemeCover: React.FC<ThemeCoverProps> = ({
|
|||||||
}
|
}
|
||||||
|
|
||||||
<div className="relative top-0 z-10 flex justify-center w-full h-full overflow-hidden transition dark:text-white rounded-xl group place-items-center bg-zinc-100 dark:bg-zinc-900">
|
<div className="relative top-0 z-10 flex justify-center w-full h-full overflow-hidden transition dark:text-white rounded-xl group place-items-center bg-zinc-100 dark:bg-zinc-900">
|
||||||
{/* Render theme cover image or placeholder */}
|
{theme.coverImage &&
|
||||||
{/* {theme.CustomImages.length > 0 ? (
|
|
||||||
<img
|
<img
|
||||||
src={URL.createObjectURL(theme.CustomImages[0].blob)}
|
src={theme.coverImage as string}
|
||||||
alt={theme.name}
|
alt={theme.name}
|
||||||
className="absolute inset-0 z-0 object-cover"
|
className="absolute inset-0 z-0 object-cover"
|
||||||
/>
|
/>
|
||||||
) : (
|
}
|
||||||
<div className="absolute inset-0 z-0 bg-gray-300 rounded-lg"></div>
|
|
||||||
)} */}
|
|
||||||
<div className="z-10">{theme.name}</div>
|
<div className="z-10">{theme.name}</div>
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -30,8 +30,19 @@ export const listThemes = async (): Promise<ThemeList> => {
|
|||||||
browser.runtime.sendMessage({
|
browser.runtime.sendMessage({
|
||||||
type: 'currentTab',
|
type: 'currentTab',
|
||||||
info: 'ListThemes'
|
info: 'ListThemes'
|
||||||
}).then((response) => {
|
}).then(async (response) => {
|
||||||
if (response) {
|
if (response) {
|
||||||
|
// convert the response themes coverImage to a bloburl
|
||||||
|
response.themes = await Promise.all(
|
||||||
|
response.themes.map(async (theme: Omit<CustomTheme, 'CustomImages'>) => {
|
||||||
|
if (theme.coverImage) {
|
||||||
|
const blob = await fetch(theme.coverImage as string).then((res) => res.blob());
|
||||||
|
theme.coverImage = URL.createObjectURL(blob);
|
||||||
|
}
|
||||||
|
return theme;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
resolve(response);
|
resolve(response);
|
||||||
} else {
|
} else {
|
||||||
reject(new Error('Failed to get response'));
|
reject(new Error('Failed to get response'));
|
||||||
@@ -81,15 +92,22 @@ export const sendThemeUpdate = (updatedTheme: CustomTheme, saveTheme?: boolean,
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
Promise.all(imageDataPromises).then((imageData) => {
|
Promise.all(imageDataPromises).then(async (imageData) => {
|
||||||
// Send the updated theme with image data to the content script for live preview or saving
|
const themeData = {
|
||||||
|
...updatedTheme,
|
||||||
|
CustomImages: imageData,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (saveTheme) {
|
||||||
|
themeData.coverImage = await blobToBase64(updatedTheme.coverImage as Blob);
|
||||||
|
} else {
|
||||||
|
themeData.coverImage = null;
|
||||||
|
}
|
||||||
|
|
||||||
browser.runtime.sendMessage({
|
browser.runtime.sendMessage({
|
||||||
type: 'currentTab',
|
type: 'currentTab',
|
||||||
info: 'UpdateThemePreview',
|
info: 'UpdateThemePreview',
|
||||||
body: {
|
body: themeData,
|
||||||
...updatedTheme,
|
|
||||||
CustomImages: imageData,
|
|
||||||
},
|
|
||||||
save: saveTheme,
|
save: saveTheme,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -55,9 +55,27 @@ function ThemeCreator() {
|
|||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const coverImageBase64 = theme.coverImage;
|
||||||
|
let coverImageBlob = null;
|
||||||
|
|
||||||
|
if (coverImageBase64) {
|
||||||
|
const base64Index = coverImageBase64.indexOf(',') + 1;
|
||||||
|
const imageBase64 = coverImageBase64.substring(base64Index);
|
||||||
|
|
||||||
|
// Convert base64 to blob
|
||||||
|
const byteCharacters = atob(imageBase64);
|
||||||
|
const byteNumbers = new Uint8Array(byteCharacters.length);
|
||||||
|
for (let i = 0; i < byteCharacters.length; i++) {
|
||||||
|
byteNumbers[i] = byteCharacters.charCodeAt(i);
|
||||||
|
}
|
||||||
|
const byteArray = new Uint8Array(byteNumbers);
|
||||||
|
coverImageBlob = new Blob([byteArray], { type: 'image/png' });
|
||||||
|
}
|
||||||
|
|
||||||
setTheme({
|
setTheme({
|
||||||
...theme,
|
...theme,
|
||||||
CustomImages,
|
CustomImages,
|
||||||
|
coverImage: coverImageBlob
|
||||||
});
|
});
|
||||||
|
|
||||||
sendThemeUpdate({
|
sendThemeUpdate({
|
||||||
@@ -189,7 +207,7 @@ function ThemeCreator() {
|
|||||||
theme.coverImage && (
|
theme.coverImage && (
|
||||||
<>
|
<>
|
||||||
<div className="absolute z-20 w-full h-full transition-opacity opacity-0 pointer-events-none group-hover:opacity-100 bg-black/20"></div>
|
<div className="absolute z-20 w-full h-full transition-opacity opacity-0 pointer-events-none group-hover:opacity-100 bg-black/20"></div>
|
||||||
<img src={URL.createObjectURL(theme.coverImage)} alt='Cover Image' className="absolute z-0 object-cover w-full h-full rounded" />
|
<img src={URL.createObjectURL(theme.coverImage as Blob)} alt='Cover Image' className="absolute z-0 object-cover w-full h-full rounded" />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ export type CustomTheme = {
|
|||||||
allowBackgrounds: boolean;
|
allowBackgrounds: boolean;
|
||||||
CustomCSS: string;
|
CustomCSS: string;
|
||||||
CustomImages: CustomImage[];
|
CustomImages: CustomImage[];
|
||||||
coverImage: Blob | null;
|
coverImage: Blob | string | null;
|
||||||
isEditable: boolean;
|
isEditable: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import browser from 'webextension-polyfill';
|
import browser from 'webextension-polyfill';
|
||||||
import localforage from 'localforage';
|
import localforage from 'localforage';
|
||||||
import { CustomTheme, ThemeList } from '../../../interface/types/CustomThemes';
|
import { CustomTheme, ThemeList } from '../../../interface/types/CustomThemes';
|
||||||
|
import { blobToBase64 } from '../../utils/blobToBase64';
|
||||||
|
|
||||||
|
|
||||||
export const getAvailableThemes = async (): Promise<ThemeList | {}> => {
|
export const getAvailableThemes = async (): Promise<ThemeList | {}> => {
|
||||||
@@ -11,8 +12,12 @@ export const getAvailableThemes = async (): Promise<ThemeList | {}> => {
|
|||||||
const themes = await Promise.all(
|
const themes = await Promise.all(
|
||||||
themeIds.map(async (id) => {
|
themeIds.map(async (id) => {
|
||||||
const theme = await localforage.getItem(id) as CustomTheme;
|
const theme = await localforage.getItem(id) as CustomTheme;
|
||||||
|
console.log('CoverImage: ', theme.coverImage)
|
||||||
const { CustomImages, ...themeWithoutImages } = theme;
|
const { CustomImages, ...themeWithoutImages } = theme;
|
||||||
return themeWithoutImages;
|
return {
|
||||||
|
...themeWithoutImages,
|
||||||
|
coverImage: theme.coverImage ? await blobToBase64(theme.coverImage as Blob) : '',
|
||||||
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ export const getTheme = async (themeId: string): Promise<CustomThemeBase64 | nul
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...theme,
|
...theme,
|
||||||
|
coverImage: theme.coverImage ? await blobToBase64(theme.coverImage as Blob) : null,
|
||||||
CustomImages,
|
CustomImages,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ export const saveTheme = async (theme: CustomThemeBase64) => {
|
|||||||
try {
|
try {
|
||||||
const updatedTheme: CustomTheme = {
|
const updatedTheme: CustomTheme = {
|
||||||
...theme,
|
...theme,
|
||||||
|
coverImage: theme.coverImage ? await fetch(theme.coverImage).then((res) => res.blob()) : null,
|
||||||
CustomImages: await Promise.all(
|
CustomImages: await Promise.all(
|
||||||
theme.CustomImages.map(async (image) => ({
|
theme.CustomImages.map(async (image) => ({
|
||||||
id: image.id,
|
id: image.id,
|
||||||
|
|||||||
Reference in New Issue
Block a user