mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 03:34:40 +00:00
added support for multiple image and video backgrounds to be uploaded at once
This commit is contained in:
@@ -1,4 +1,12 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import { useState, useEffect, ChangeEvent, FC } from 'react';
|
||||||
|
|
||||||
|
// Custom Types and Interfaces
|
||||||
|
interface Background {
|
||||||
|
id: string;
|
||||||
|
type: string;
|
||||||
|
blob: Blob;
|
||||||
|
url?: string;
|
||||||
|
}
|
||||||
|
|
||||||
// IndexedDB utility functions
|
// IndexedDB utility functions
|
||||||
const openDB = () => {
|
const openDB = () => {
|
||||||
@@ -15,12 +23,12 @@ const openDB = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const writeData = async (type: string, blob: Blob) => {
|
const writeData = async (fileId: string, type: string, blob: Blob) => {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
openDB().then(async db => {
|
openDB().then(async db => {
|
||||||
const tx = db.transaction('backgrounds', 'readwrite');
|
const tx = db.transaction('backgrounds', 'readwrite');
|
||||||
const store = tx.objectStore('backgrounds');
|
const store = tx.objectStore('backgrounds');
|
||||||
const request = store.put({ id: 'customBackground', type, blob });
|
const request = store.put({ id: fileId, type, blob });
|
||||||
|
|
||||||
await new Promise((res, rej) => {
|
await new Promise((res, rej) => {
|
||||||
tx.oncomplete = () => res(request.result);
|
tx.oncomplete = () => res(request.result);
|
||||||
@@ -31,11 +39,11 @@ const writeData = async (type: string, blob: Blob) => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const readData = async () => {
|
const readAllData = async (): Promise<Background[]> => {
|
||||||
const db = await openDB();
|
const db = await openDB();
|
||||||
const tx = db.transaction('backgrounds', 'readonly');
|
const tx = db.transaction('backgrounds', 'readonly');
|
||||||
const store = tx.objectStore('backgrounds');
|
const store = tx.objectStore('backgrounds');
|
||||||
const request = store.get('customBackground');
|
const request = store.getAll();
|
||||||
|
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
request.onsuccess = () => resolve(request.result);
|
request.onsuccess = () => resolve(request.result);
|
||||||
@@ -43,65 +51,69 @@ const readData = async () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const Themes: React.FC = () => {
|
const Themes: FC = () => {
|
||||||
const [imageSrc, setImageSrc] = useState<string | null>(null);
|
const [backgrounds, setBackgrounds] = useState<Background[]>([]);
|
||||||
const [videoSrc, setVideoSrc] = useState<string | null>(null);
|
const [selectedBackground, setSelectedBackground] = useState<string | null>(localStorage.getItem('selectedBackground'));
|
||||||
|
|
||||||
const handleFileChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
|
const handleFileChange = async (e: ChangeEvent<HTMLInputElement>): Promise<void> => {
|
||||||
const file = e.target.files?.[0];
|
const file = e.target.files?.[0];
|
||||||
if (!file) return;
|
if (!file) return;
|
||||||
|
|
||||||
|
const fileId = `${Date.now()}-${file.name}`;
|
||||||
const fileType = file.type.split('/')[0];
|
const fileType = file.type.split('/')[0];
|
||||||
const blob = new Blob([file], { type: file.type });
|
const blob = new Blob([file], { type: file.type });
|
||||||
|
|
||||||
// Save blob to IndexedDB
|
await writeData(fileId, fileType, blob);
|
||||||
await writeData(fileType, blob);
|
setBackgrounds(prev => [...prev, { id: fileId, type: fileType, blob, url: URL.createObjectURL(blob) }]);
|
||||||
|
};
|
||||||
|
|
||||||
// For displaying purpose
|
const loadBackgrounds = async (): Promise<void> => {
|
||||||
const url = URL.createObjectURL(blob);
|
const data = await readAllData();
|
||||||
if (fileType === 'image') {
|
const dataWithUrls = data.map(bg => ({ ...bg, url: URL.createObjectURL(bg.blob) }));
|
||||||
setVideoSrc(null);
|
setBackgrounds(dataWithUrls);
|
||||||
setImageSrc(url);
|
};
|
||||||
} else if (fileType === 'video') {
|
|
||||||
setImageSrc(null);
|
const selectBackground = (fileId: string): void => {
|
||||||
setVideoSrc(url);
|
setSelectedBackground(fileId);
|
||||||
}
|
localStorage.setItem('selectedBackground', fileId);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
(async () => {
|
loadBackgrounds();
|
||||||
const data = await readData();
|
|
||||||
const url = URL.createObjectURL(data.blob);
|
|
||||||
if (data?.type === 'image') {
|
|
||||||
setImageSrc(url);
|
|
||||||
} else if (data?.type === 'video') {
|
|
||||||
setVideoSrc(url);
|
|
||||||
}
|
|
||||||
})();
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col overflow-y-scroll divide-y divide-zinc-100/50 dark:divide-zinc-700/50">
|
<div>
|
||||||
<div>
|
<h2>Upload a Background</h2>
|
||||||
<h2 className="text-lg font-bold">Custom Background</h2>
|
<input type="file" onChange={handleFileChange} />
|
||||||
</div>
|
|
||||||
|
|
||||||
<input type="file" onChange={handleFileChange} />
|
<h2>Images</h2>
|
||||||
{imageSrc && <img src={imageSrc} alt="Uploaded content" />}
|
<div className="flex flex-wrap gap-4">
|
||||||
{videoSrc && <video src={videoSrc} autoPlay loop muted />}
|
{backgrounds.filter(bg => bg.type === 'image').map(bg => (
|
||||||
|
<div key={bg.id} onClick={() => selectBackground(bg.id)} className={`w-16 h-16 rounded-lg overflow-hidden transition ring ring-white ${selectedBackground === bg.id ? 'ring-4' : 'ring-0'}`}>
|
||||||
<div>
|
<img className="object-cover w-full h-full" src={bg.url} alt="swatch" />
|
||||||
<h2 className="text-lg font-bold">Themes</h2>
|
</div>
|
||||||
</div>
|
))}
|
||||||
<div className="grid grid-cols-2 gap-2 py-4">
|
|
||||||
<button className="flex flex-col items-center justify-center w-full h-32 rounded-md bg-zinc-100 dark:bg-zinc-700">
|
|
||||||
<h2 className="text-lg font-bold">Light</h2>
|
|
||||||
</button>
|
|
||||||
<button className="flex flex-col items-center justify-center w-full h-32 rounded-md bg-zinc-800 dark:bg-zinc-600">
|
|
||||||
<h2 className="text-lg font-bold">Dark</h2>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<h2>Videos</h2>
|
||||||
|
<div className="flex flex-wrap gap-4">
|
||||||
|
{backgrounds.filter(bg => bg.type === 'video').map(bg => (
|
||||||
|
<div key={bg.id} onClick={() => selectBackground(bg.id)} className={`w-16 h-16 rounded-lg overflow-hidden transition ring ring-white ${selectedBackground === bg.id ? 'ring-4' : 'ring-0'}`}>
|
||||||
|
<video muted loop autoPlay src={bg.url} className="object-cover w-full h-full" />
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{ /* Preview section */ }
|
||||||
|
<div className="hidden">
|
||||||
|
{backgrounds.filter(bg => bg.id === selectedBackground).map(bg => (
|
||||||
|
bg.type === 'image' ?
|
||||||
|
<img key={bg.id} src={URL.createObjectURL(bg.blob)} alt="Selected Background" /> :
|
||||||
|
<video key={bg.id} src={URL.createObjectURL(bg.blob)} autoPlay loop muted />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,27 @@
|
|||||||
body {
|
body {
|
||||||
margin: 0 !important;
|
margin: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
video, img {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
object-fit: cover;
|
||||||
|
|
||||||
|
animation: fade 0.2s ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fade {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|||||||
@@ -13,12 +13,18 @@ const openDB = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Read data from IndexedDB
|
// Modified Read Data from IndexedDB
|
||||||
const readData = async () => {
|
const readData = async () => {
|
||||||
|
const selectedBackground = localStorage.getItem("selectedBackground");
|
||||||
|
if (!selectedBackground) {
|
||||||
|
console.log("No selected background in local storage.");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const db = await openDB();
|
const db = await openDB();
|
||||||
const tx = db.transaction("backgrounds", "readonly");
|
const tx = db.transaction("backgrounds", "readonly");
|
||||||
const store = tx.objectStore("backgrounds");
|
const store = tx.objectStore("backgrounds");
|
||||||
const request = store.get("customBackground");
|
const request = store.get(selectedBackground);
|
||||||
|
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
request.onsuccess = () => resolve(request.result);
|
request.onsuccess = () => resolve(request.result);
|
||||||
@@ -26,8 +32,8 @@ const readData = async () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Main function to run on page load
|
// Function to update the background
|
||||||
const main = async () => {
|
const updateBackground = async () => {
|
||||||
try {
|
try {
|
||||||
const data = await readData();
|
const data = await readData();
|
||||||
if (!data) {
|
if (!data) {
|
||||||
@@ -37,6 +43,7 @@ const main = async () => {
|
|||||||
|
|
||||||
const url = URL.createObjectURL(data.blob);
|
const url = URL.createObjectURL(data.blob);
|
||||||
const container = document.getElementById("media-container");
|
const container = document.getElementById("media-container");
|
||||||
|
container.innerHTML = ""; // Clear previous background
|
||||||
|
|
||||||
if (data.type === "image") {
|
if (data.type === "image") {
|
||||||
const imgElement = document.createElement("img");
|
const imgElement = document.createElement("img");
|
||||||
@@ -56,5 +63,17 @@ const main = async () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Main function to run on page load
|
||||||
|
const main = async () => {
|
||||||
|
await updateBackground(); // Initial background update
|
||||||
|
|
||||||
|
// Listen for changes to local storage
|
||||||
|
window.addEventListener("storage", async (event) => {
|
||||||
|
if (event.key === "selectedBackground") {
|
||||||
|
await updateBackground(); // Update background if 'selectedBackground' changes
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Run the main function when the document is ready
|
// Run the main function when the document is ready
|
||||||
document.addEventListener("DOMContentLoaded", main);
|
document.addEventListener("DOMContentLoaded", main);
|
||||||
|
|||||||
@@ -12,73 +12,4 @@ export async function appendBackgroundToUI() {
|
|||||||
background.setAttribute("excludeDarkCheck", "true");
|
background.setAttribute("excludeDarkCheck", "true");
|
||||||
background.src = chrome.runtime.getURL("backgrounds/background.html");
|
background.src = chrome.runtime.getURL("backgrounds/background.html");
|
||||||
parent.appendChild(background);
|
parent.appendChild(background);
|
||||||
|
|
||||||
/* const response = await new Promise((resolve, reject) => {
|
|
||||||
console.log("Sending message to background script...");
|
|
||||||
chrome.runtime.sendMessage({ type: "IndexedDB", action: "read", fileName: "customBackground" }, (response) => {
|
|
||||||
if (chrome.runtime.lastError) {
|
|
||||||
console.error("Error from background script:", chrome.runtime.lastError);
|
|
||||||
return reject(chrome.runtime.lastError);
|
|
||||||
}
|
|
||||||
console.log("Received response from background script:", response);
|
|
||||||
resolve(response);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
let data = response.data; // response.data is the image Data URL
|
|
||||||
|
|
||||||
// Extract the pure base64 string from the Data URL
|
|
||||||
const base64Marker = ";base64,";
|
|
||||||
const base64Index = data.indexOf(base64Marker) + base64Marker.length;
|
|
||||||
const base64 = data.substring(base64Index);
|
|
||||||
|
|
||||||
let type = response.type; // response.type is the image type [ video | image ]
|
|
||||||
|
|
||||||
if (base64) {
|
|
||||||
console.log("Data exists, proceeding...");
|
|
||||||
|
|
||||||
const mount = document.getElementById("container");
|
|
||||||
|
|
||||||
// Convert base64 to ArrayBuffer
|
|
||||||
console.log("Converting base64 to ArrayBuffer...");
|
|
||||||
const byteCharacters = atob(base64);
|
|
||||||
const byteNumbers = Array.from(byteCharacters).map(char => char.charCodeAt(0));
|
|
||||||
const byteArray = new Uint8Array(byteNumbers);
|
|
||||||
|
|
||||||
// Create blob
|
|
||||||
console.log("Creating blob...");
|
|
||||||
const blob = new Blob([byteArray], { type: type === "video" ? "video/mp4" : "image/jpeg" });
|
|
||||||
|
|
||||||
// Create blob URL
|
|
||||||
console.log("Creating blob URL...");
|
|
||||||
const blobUrl = URL.createObjectURL(blob);
|
|
||||||
|
|
||||||
let backgroundElement;
|
|
||||||
|
|
||||||
if (type === "video") {
|
|
||||||
console.log("Appending video element...");
|
|
||||||
backgroundElement = document.createElement("video");
|
|
||||||
backgroundElement.src = blobUrl;
|
|
||||||
backgroundElement.autoplay = true;
|
|
||||||
backgroundElement.loop = true;
|
|
||||||
backgroundElement.muted = true;
|
|
||||||
|
|
||||||
// Revoke blob URL to free memory
|
|
||||||
backgroundElement.addEventListener("ended", () => {
|
|
||||||
console.log("Video ended, revoking blob URL...");
|
|
||||||
URL.revokeObjectURL(blobUrl);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
console.log("Appending image element...");
|
|
||||||
backgroundElement = document.createElement("img");
|
|
||||||
backgroundElement.src = blobUrl;
|
|
||||||
backgroundElement.alt = "Custom Background";
|
|
||||||
backgroundElement.classList.add("imageBackground");
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log("Appending background element to the DOM...");
|
|
||||||
mount.appendChild(backgroundElement);
|
|
||||||
} else {
|
|
||||||
console.warn("No data received. Background not appended.");
|
|
||||||
} */
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user