mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 03:34:40 +00:00
move interface to src/ folder
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
const About: React.FC = () => {
|
||||
|
||||
return (
|
||||
<div className="flex flex-col overflow-y-scroll divide-y divide-zinc-100/50 dark:divide-zinc-700/50">
|
||||
<div>
|
||||
<h2 className="text-lg font-bold">About</h2>
|
||||
<p className="py-2">BetterSEQTA+ is a branch of BetterSEQTA which was originally developed by Nulkem. It was discontinued. So BetterSEQTA+ has come in to fill in that gap!</p>
|
||||
<p className="py-2">We are currently working on fixing bugs and adding new features. If you want to request a feature or report a bug, you can do so on
|
||||
<a className="pl-1 text-blue-500 underline hover:text-blue-600" href="https://github.com/SethBurkart123/EvenBetterSEQTA" target="_blank">Github</a>.
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<h2 className="pt-2 text-lg font-bold">Credits</h2>
|
||||
<p className="py-2">Nulkem for the original extension, OG-RandomTechChannel, Crazypersonalph, and the current maintainer SethBurkart123</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default About;
|
||||
@@ -0,0 +1,92 @@
|
||||
import Switch from '../components/Switch';
|
||||
import Slider from '../components/Slider';
|
||||
import PickerSwatch from '../components/PickerSwatch';
|
||||
|
||||
import { SettingsList } from '../types/SettingsProps';
|
||||
import { useSettingsContext } from '../SettingsContext';
|
||||
|
||||
import browser from 'webextension-polyfill'
|
||||
|
||||
const Settings: React.FC = () => {
|
||||
const { settingsState, setSettingsState } = useSettingsContext();
|
||||
|
||||
const switchChange = (key: string, isOn: boolean) => {
|
||||
setSettingsState({
|
||||
...settingsState,
|
||||
[key]: isOn,
|
||||
});
|
||||
};
|
||||
|
||||
const sliderChange = (key: string, value: number) => {
|
||||
setSettingsState({
|
||||
...settingsState,
|
||||
[key]: value,
|
||||
});
|
||||
};
|
||||
|
||||
const settings: SettingsList[] = [
|
||||
{
|
||||
title: "Transparency Effects",
|
||||
description: "Enables transparency effects on certain elements such as blur. (May impact battery life)",
|
||||
modifyElement: <Switch state={settingsState.transparencyEffects} onChange={(isOn: boolean) => switchChange('transparencyEffects', isOn)} />
|
||||
},
|
||||
{
|
||||
title: "Animated Background",
|
||||
description: "Adds an animated background to BetterSEQTA. (May impact battery life)",
|
||||
modifyElement: <Switch state={settingsState.animatedBackground} onChange={(isOn: boolean) => switchChange('animatedBackground', isOn)} />
|
||||
},
|
||||
{
|
||||
title: "Animated Background Speed",
|
||||
description: "Controls the speed of the animated background.",
|
||||
modifyElement: <Slider state={parseInt(settingsState.animatedBackgroundSpeed)} onChange={(value: number) => sliderChange('animatedBackgroundSpeed', value)} />
|
||||
},
|
||||
{
|
||||
title: "Custom Theme Colour",
|
||||
description: "Customise the overall theme colour of SEQTA Learn.",
|
||||
modifyElement: <PickerSwatch />
|
||||
},
|
||||
{
|
||||
title: "Telemetry",
|
||||
description: "Enables/disables error collecting.",
|
||||
modifyElement: <Switch state={settingsState.telemetry} onChange={(isOn: boolean) => switchChange('telemetry', isOn)} />
|
||||
},
|
||||
{
|
||||
title: "Edit Sidebar Layout",
|
||||
description: "Customise the sidebar layout.",
|
||||
modifyElement: <button onClick={() => browser.runtime.sendMessage({ type: 'currentTab', info: 'EditSidebar' })} className='px-4 py-1 text-[0.75rem] dark:bg-[#38373D] bg-[#DDDDDD] dark:text-white rounded-md'>Edit</button>
|
||||
},
|
||||
{
|
||||
title: "Notification Collector",
|
||||
description: "Uncaps the 9+ limit for notifications, showing the real number.",
|
||||
modifyElement: <Switch state={settingsState.notificationCollector} onChange={(isOn: boolean) => switchChange('notificationCollector', isOn)} />
|
||||
},
|
||||
{
|
||||
title: "Lesson Alerts",
|
||||
description: "Sends a native browser notification ~5 minutes prior to lessons.",
|
||||
modifyElement: <Switch state={settingsState.lessonAlerts} onChange={(isOn: boolean) => switchChange('lessonAlerts', isOn)} />
|
||||
},
|
||||
{
|
||||
title: "BetterSEQTA+",
|
||||
description: "Enables BetterSEQTA+ features",
|
||||
modifyElement: <Switch state={settingsState.betterSEQTAPlus} onChange={(isOn: boolean) => switchChange('betterSEQTAPlus', isOn)} />
|
||||
}
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="flex flex-col -mt-4 overflow-y-scroll divide-y divide-zinc-100 dark:divide-zinc-700">
|
||||
{settings.map((setting, index) => (
|
||||
<div className="flex items-center justify-between px-4 py-3" key={index}>
|
||||
<div className="pr-4">
|
||||
<h2 className="text-sm font-bold">{setting.title}</h2>
|
||||
<p className="text-xs">{setting.description}</p>
|
||||
</div>
|
||||
<div>
|
||||
{setting.modifyElement}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Settings;
|
||||
@@ -0,0 +1,155 @@
|
||||
import { useState } from "react";
|
||||
import Switch from "../components/Switch";
|
||||
import { useSettingsContext } from "../SettingsContext";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { CustomShortcut } from "../types/AppProps";
|
||||
|
||||
function formatUrl (inputUrl: string) {
|
||||
// Regular expression to check if the URL starts with http://, https://, or ftp://
|
||||
const protocolRegex = /^(http:\/\/|https:\/\/|ftp:\/\/)/;
|
||||
|
||||
// Check if the URL starts with one of the protocols
|
||||
if (protocolRegex.test(inputUrl)) {
|
||||
return inputUrl; // The URL is fine as is
|
||||
} else {
|
||||
return `https://${inputUrl}`; // Prepend https:// to the URL
|
||||
}
|
||||
}
|
||||
|
||||
export default function Shortcuts() {
|
||||
const { settingsState, setSettingsState } = useSettingsContext();
|
||||
|
||||
const switchChange = (shortcutName: string, isOn: boolean): void => {
|
||||
const updatedShortcuts = settingsState.shortcuts.map((shortcut) => {
|
||||
if (shortcut.name === shortcutName) {
|
||||
return { ...shortcut, enabled: isOn };
|
||||
}
|
||||
return shortcut;
|
||||
});
|
||||
|
||||
setSettingsState({ ...settingsState, shortcuts: updatedShortcuts });
|
||||
};
|
||||
|
||||
const [newTitle, setNewTitle] = useState<string>("");
|
||||
const [newURL, setNewURL] = useState<string>("");
|
||||
|
||||
const isValidTitle = (title: string): boolean => title.trim() !== "";
|
||||
|
||||
const isValidURL = (url: string): boolean => {
|
||||
const pattern = new RegExp("^(https?:\\/\\/)?[\\w.-]+[\\w.-]+$", "i");
|
||||
return pattern.test(url);
|
||||
};
|
||||
|
||||
const addNewCustomShortcut = (): void => {
|
||||
if (isValidTitle(newTitle) && isValidURL(newURL)) {
|
||||
const newShortcut: CustomShortcut = { name: newTitle.trim(), url: formatUrl(newURL).trim(), icon: newTitle[0] };
|
||||
const updatedCustomShortcuts = [...settingsState.customshortcuts, newShortcut];
|
||||
setSettingsState({ ...settingsState, customshortcuts: updatedCustomShortcuts });
|
||||
setNewTitle("");
|
||||
setNewURL("");
|
||||
|
||||
setFormVisible(false);
|
||||
} else {
|
||||
// Replace with a more user-friendly way to display errors
|
||||
console.error("Please enter a valid title and URL.");
|
||||
}
|
||||
};
|
||||
|
||||
const deleteCustomShortcut = (index: number): void => {
|
||||
const updatedCustomShortcuts = settingsState.customshortcuts.filter((_, i) => i !== index);
|
||||
setSettingsState({ ...settingsState, customshortcuts: updatedCustomShortcuts });
|
||||
};
|
||||
|
||||
const [isFormVisible, setFormVisible] = useState(false);
|
||||
|
||||
const toggleForm = () => {
|
||||
setFormVisible(!isFormVisible);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col divide-y divide-zinc-100 dark:divide-zinc-700">
|
||||
|
||||
<AnimatePresence>
|
||||
{isFormVisible ? (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, height: 0 }}
|
||||
animate={{ opacity: 1, height: "auto" }}
|
||||
exit={{ opacity: 0, height: 0 }}
|
||||
transition={{ type: "spring", damping: 20 }}
|
||||
>
|
||||
<div className="flex flex-col items-center mb-4">
|
||||
<motion.input
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.2 }}
|
||||
className="w-full p-2 rounded-md bg-zinc-100 dark:bg-zinc-700 focus:outline-none"
|
||||
type="text"
|
||||
placeholder="Shortcut Name"
|
||||
value={newTitle}
|
||||
onChange={(e) => setNewTitle(e.target.value)}
|
||||
/>
|
||||
<motion.input
|
||||
initial={{ opacity: 0, y: -10 }}
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
transition={{ delay: 0.3 }}
|
||||
className="w-full p-2 my-2 rounded-md bg-zinc-100 dark:bg-zinc-700 focus:outline-none"
|
||||
type="text"
|
||||
placeholder="URL eg. https://google.com"
|
||||
value={newURL}
|
||||
onChange={(e) => setNewURL(e.target.value)}
|
||||
/>
|
||||
<motion.button
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
transition={{ delay: 0.4 }}
|
||||
className="w-full px-4 py-2 text-white bg-blue-500 rounded-md"
|
||||
onClick={ addNewCustomShortcut }
|
||||
>
|
||||
Add
|
||||
</motion.button>
|
||||
</div>
|
||||
</motion.div>
|
||||
) : (
|
||||
<motion.button
|
||||
initial={{ backgroundColor: "rgba(29, 161, 242, 1)", height: "auto" }}
|
||||
animate={{ backgroundColor: "rgba(29, 161, 242, 1)", height: "auto" }}
|
||||
exit={{ backgroundColor: "rgba(29, 161, 242, 1)", height: "auto" }}
|
||||
transition={{ type: 'tween', ease: "easeOut" }}
|
||||
className="px-4 py-2 mb-4 text-white bg-blue-500 rounded"
|
||||
onClick={toggleForm}
|
||||
>
|
||||
Add Custom Shortcut
|
||||
</motion.button>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
{/* Shortcuts Section */}
|
||||
{settingsState.shortcuts ? (
|
||||
settingsState.shortcuts.map((shortcut, index) => shortcut.name && (
|
||||
<div className="flex items-center justify-between px-4 py-3" key={index}>
|
||||
{shortcut.name}
|
||||
<Switch state={shortcut.enabled} onChange={(isOn) => switchChange(shortcut.name, isOn)} />
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p>Loading shortcuts...</p>
|
||||
)}
|
||||
|
||||
{/* Custom Shortcuts Section */}
|
||||
{settingsState.customshortcuts ? (
|
||||
settingsState.customshortcuts.map((shortcut, index) => (
|
||||
<div className="flex items-center justify-between px-4 py-3" key={index}>
|
||||
{shortcut.name}
|
||||
<button onClick={() => deleteCustomShortcut(index)}>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" strokeWidth={1.5} stroke="currentColor" className="w-6 h-6">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" d="M6 18L18 6M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
))
|
||||
) : (
|
||||
<p>Loading custom shortcuts...</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
import { FC, useEffect, useState } from 'react';
|
||||
import BackgroundSelector from '../components/BackgroundSelector';
|
||||
import ThemeSelector from '../components/ThemeSelector';
|
||||
import { listThemes } from '../hooks/ThemeManagment';
|
||||
|
||||
const Themes: FC = () => {
|
||||
const [isEditMode, setIsEditMode] = useState<boolean>(false);
|
||||
const [selectedType, setSelectedType] = useState<'background' | 'theme'>('background');
|
||||
|
||||
useEffect(() => {
|
||||
listThemes().then(themes => {
|
||||
if (themes.selectedTheme) {
|
||||
setSelectedType('theme');
|
||||
} else {
|
||||
setSelectedType('background');
|
||||
}
|
||||
});
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<button className="absolute top-12 z-20 right-0 p-2 text-[0.8rem] text-blue-500" onClick={() => setIsEditMode(!isEditMode)}>
|
||||
{isEditMode ? 'Done' : 'Edit'}
|
||||
</button>
|
||||
<BackgroundSelector setSelectedType={setSelectedType} selectedType={selectedType} isEditMode={isEditMode} />
|
||||
<ThemeSelector setSelectedType={setSelectedType} selectedType={selectedType} isEditMode={isEditMode} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Themes;
|
||||
Reference in New Issue
Block a user