mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 11:44:40 +00:00
added multiple custom backgrounds
This commit is contained in:
@@ -6,6 +6,18 @@ import { SettingsContextProvider } from './SettingsContext.js';
|
|||||||
|
|
||||||
const root = ReactDOM.createRoot(document.getElementById('ExtensionPopup')!);
|
const root = ReactDOM.createRoot(document.getElementById('ExtensionPopup')!);
|
||||||
|
|
||||||
|
const fontURL = chrome.runtime.getURL("fonts/IconFamily.woff");
|
||||||
|
|
||||||
|
const style = document.createElement("style");
|
||||||
|
style.setAttribute("type", "text/css");
|
||||||
|
style.innerHTML = `
|
||||||
|
@font-face {
|
||||||
|
font-family: 'IconFamily';
|
||||||
|
src: url('${fontURL}') format('woff');
|
||||||
|
font-weight: normal;
|
||||||
|
font-style: normal;
|
||||||
|
}`;
|
||||||
|
document.head.appendChild(style);
|
||||||
|
|
||||||
root.render(
|
root.render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
@keyframes shake {
|
||||||
|
0% {
|
||||||
|
transform: translateX(0) rotate(0);
|
||||||
|
}
|
||||||
|
25% {
|
||||||
|
transform: translateX(-1px) rotate(-1deg);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
transform: translateX(1px) rotate(1deg);
|
||||||
|
}
|
||||||
|
75% {
|
||||||
|
transform: translateX(-1px) rotate(-1deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
transform: translateX(0) rotate(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.animate-shake {
|
||||||
|
animation: shake 1s linear infinite;
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import { useState, useEffect, ChangeEvent, FC } from 'react';
|
import { useState, useEffect, ChangeEvent, FC } from 'react';
|
||||||
|
import './Themes.css';
|
||||||
|
|
||||||
// Custom Types and Interfaces
|
// Custom Types and Interfaces
|
||||||
interface Background {
|
interface Background {
|
||||||
@@ -54,6 +55,7 @@ const readAllData = async (): Promise<Background[]> => {
|
|||||||
const Themes: FC = () => {
|
const Themes: FC = () => {
|
||||||
const [backgrounds, setBackgrounds] = useState<Background[]>([]);
|
const [backgrounds, setBackgrounds] = useState<Background[]>([]);
|
||||||
const [selectedBackground, setSelectedBackground] = useState<string | null>(localStorage.getItem('selectedBackground'));
|
const [selectedBackground, setSelectedBackground] = useState<string | null>(localStorage.getItem('selectedBackground'));
|
||||||
|
const [isEditMode, setIsEditMode] = useState<boolean>(false);
|
||||||
|
|
||||||
const handleFileChange = async (e: ChangeEvent<HTMLInputElement>): Promise<void> => {
|
const handleFileChange = async (e: ChangeEvent<HTMLInputElement>): Promise<void> => {
|
||||||
const file = e.target.files?.[0];
|
const file = e.target.files?.[0];
|
||||||
@@ -78,29 +80,67 @@ const Themes: FC = () => {
|
|||||||
localStorage.setItem('selectedBackground', fileId);
|
localStorage.setItem('selectedBackground', fileId);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const deleteBackground = async (fileId: string): Promise<void> => {
|
||||||
|
const db = await openDB();
|
||||||
|
const tx = db.transaction('backgrounds', 'readwrite');
|
||||||
|
const store = tx.objectStore('backgrounds');
|
||||||
|
store.delete(fileId);
|
||||||
|
setBackgrounds(prev => prev.filter(bg => bg.id !== fileId));
|
||||||
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
loadBackgrounds();
|
loadBackgrounds();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h2>Upload a Background</h2>
|
<button className="absolute top-0 right-0 p-2 text-lg text-blue-500" onClick={() => setIsEditMode(!isEditMode)}>
|
||||||
<input type="file" onChange={handleFileChange} />
|
{isEditMode ? 'Done' : 'Edit'}
|
||||||
|
</button>
|
||||||
<h2>Images</h2>
|
<h2 className="py-2 text-lg font-bold">Images</h2>
|
||||||
<div className="flex flex-wrap gap-4">
|
<div className="flex flex-wrap gap-4">
|
||||||
|
{/* Image uploader swatch */}
|
||||||
|
<div className="relative w-16 h-16 overflow-hidden transition rounded-xl bg-zinc-900">
|
||||||
|
<div className="flex items-center justify-center w-full h-full text-3xl font-bold text-gray-400 transition font-IconFamily hover:text-gray-500">
|
||||||
|
{/* Plus icon */}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<input type="file" accept='image/*, video/*' onChange={handleFileChange} className="absolute inset-0 w-full h-full opacity-0 cursor-pointer" />
|
||||||
|
</div>
|
||||||
{backgrounds.filter(bg => bg.type === 'image').map(bg => (
|
{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 key={bg.id}
|
||||||
<img className="object-cover w-full h-full" src={bg.url} alt="swatch" />
|
onClick={() => selectBackground(bg.id)}
|
||||||
|
className={`relative w-16 h-16 cursor-pointer rounded-xl transition ring ring-white ${isEditMode ? 'animate-shake' : ''} ${selectedBackground === bg.id ? 'ring-2' : 'ring-0'}`}>
|
||||||
|
{isEditMode && (
|
||||||
|
<div className="absolute top-0 right-0 z-10 flex w-6 h-6 p-2 text-white translate-x-1/2 -translate-y-1/2 bg-red-600 rounded-full place-items-center"
|
||||||
|
onClick={() => deleteBackground(bg.id)}>
|
||||||
|
<div className="w-4 h-0.5 bg-white"></div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<img className="object-cover w-full h-full rounded-xl" src={bg.url} alt="swatch" />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h2>Videos</h2>
|
<h2 className="py-2 text-lg font-bold">Videos</h2>
|
||||||
<div className="flex flex-wrap gap-4">
|
<div className="flex flex-wrap gap-4">
|
||||||
|
{/* Video uploader swatch */}
|
||||||
|
<div className="relative w-16 h-16 overflow-hidden transition rounded-xl bg-zinc-900">
|
||||||
|
<div className="flex items-center justify-center w-full h-full text-3xl font-bold text-gray-400 transition font-IconFamily hover:text-gray-500">
|
||||||
|
{/* Plus icon */}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<input type="file" accept='image/*, video/*' onChange={handleFileChange} className="absolute inset-0 w-full h-full opacity-0 cursor-pointer" />
|
||||||
|
</div>
|
||||||
{backgrounds.filter(bg => bg.type === 'video').map(bg => (
|
{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'}`}>
|
<div key={bg.id} onClick={() => selectBackground(bg.id)} className={`relative w-16 h-16 cursor-pointer rounded-xl transition ring ring-white ${isEditMode ? 'animate-shake' : ''} ${selectedBackground === bg.id ? 'ring-2' : 'ring-0'}`}>
|
||||||
<video muted loop autoPlay src={bg.url} className="object-cover w-full h-full" />
|
{isEditMode && (
|
||||||
|
<div className="absolute top-0 right-0 z-10 flex w-6 h-6 p-2 text-white translate-x-1/2 -translate-y-1/2 bg-red-600 rounded-full place-items-center"
|
||||||
|
onClick={() => deleteBackground(bg.id)}>
|
||||||
|
<div className="w-4 h-0.5 bg-white"></div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<video muted loop autoPlay src={bg.url} className="object-cover w-full h-full rounded-xl" />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -15,6 +15,22 @@ export default {
|
|||||||
"xl": "1.25rem",
|
"xl": "1.25rem",
|
||||||
"2xl": "1.5rem",
|
"2xl": "1.5rem",
|
||||||
"3xl": "1.875rem",
|
"3xl": "1.875rem",
|
||||||
|
"4xl": "2.25rem",
|
||||||
|
"5xl": "3rem",
|
||||||
|
"6xl": "4rem",
|
||||||
|
"7xl": "5rem",
|
||||||
|
"8xl": "6rem",
|
||||||
|
"9xl": "8rem",
|
||||||
|
"10xl": "10rem",
|
||||||
|
"11xl": "12rem",
|
||||||
|
"12xl": "14rem",
|
||||||
|
"13xl": "16rem",
|
||||||
|
"14xl": "18rem",
|
||||||
|
},
|
||||||
|
extend: {
|
||||||
|
fontFamily: {
|
||||||
|
"IconFamily": "IconFamily"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
|
|||||||
@@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
object-fit: cover;
|
object-fit: cover;
|
||||||
|
|
||||||
animation: fade 0.2s ease-in-out;
|
animation: fade 0.4s ease-in-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
@keyframes fade {
|
@keyframes fade {
|
||||||
|
|||||||
Reference in New Issue
Block a user