mirror of
https://github.com/BetterSEQTA/BetterSEQTA-Plus.git
synced 2026-06-06 11:44:40 +00:00
performance improvements to shortcuts and tab container components
This commit is contained in:
@@ -54,7 +54,7 @@ const TabbedContainer: React.FC<TabbedContainerProps> = ({ tabs }) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div ref={containerRef} className="top-0 z-10 text-[0.875rem] pb-0.5 mx-4">
|
<div ref={containerRef} className="top-0 z-10 text-[0.875rem] pb-0.5 mx-4">
|
||||||
<div className="relative flex">
|
<div className="relative flex">
|
||||||
<motion.div
|
<motion.div
|
||||||
@@ -78,21 +78,21 @@ const TabbedContainer: React.FC<TabbedContainerProps> = ({ tabs }) => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-full px-4 overflow-x-clip">
|
<div className="h-full px-4 overflow-x-clip">
|
||||||
<motion.div
|
<motion.div
|
||||||
initial={false}
|
initial={false}
|
||||||
animate={{ x: `${position}%` }}
|
animate={{ x: `${position}%` }}
|
||||||
transition={springTransition}
|
transition={springTransition}
|
||||||
className='flex'
|
className='flex'
|
||||||
>
|
>
|
||||||
{tabs.map((tab, index) => (
|
{tabs.map((tab, index) => (
|
||||||
<div key={index} className={`absolute h-[100vh] overflow-y-scroll w-full pb-40 transition-opacity duration-300 ${activeTab === index ? 'opacity-100' : 'opacity-0'}`}
|
<div key={index} className={`absolute h-[100vh] overflow-y-scroll w-full pb-40 transition-opacity duration-300 ${activeTab === index ? 'opacity-100' : 'opacity-0'}`}
|
||||||
style={{left: `${index * 100}%`}}>
|
style={{left: `${index * 100}%`}}>
|
||||||
{tab.content}
|
{tab.content}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,50 +1,44 @@
|
|||||||
import { useState, memo } from "react";
|
import { useState, memo, useCallback } from "react";
|
||||||
import Switch from "../components/Switch";
|
import Switch from "../components/Switch";
|
||||||
import { useSettingsContext } from "../SettingsContext";
|
import { useSettingsContext } from "../SettingsContext";
|
||||||
import { motion, AnimatePresence } from "framer-motion";
|
import { motion, AnimatePresence } from "framer-motion";
|
||||||
import { CustomShortcut } from "../types/AppProps";
|
import { CustomShortcut } from "../types/AppProps";
|
||||||
|
|
||||||
function formatUrl (inputUrl: string) {
|
function formatUrl(inputUrl: string) {
|
||||||
// Regular expression to check if the URL starts with http://, https://, or ftp://
|
|
||||||
const protocolRegex = /^(http:\/\/|https:\/\/|ftp:\/\/)/;
|
const protocolRegex = /^(http:\/\/|https:\/\/|ftp:\/\/)/;
|
||||||
|
return protocolRegex.test(inputUrl) ? inputUrl : `https://${inputUrl}`;
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function Shortcuts() {
|
const Shortcuts = memo(() => {
|
||||||
const { settingsState, setSettingsState } = useSettingsContext();
|
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 [newTitle, setNewTitle] = useState<string>("");
|
||||||
|
const [isFormVisible, setFormVisible] = useState(false);
|
||||||
const [newURL, setNewURL] = useState<string>("");
|
const [newURL, setNewURL] = useState<string>("");
|
||||||
|
|
||||||
const isValidTitle = (title: string): boolean => title.trim() !== "";
|
|
||||||
|
|
||||||
const isValidURL = (url: string): boolean => {
|
const switchChange = useCallback((shortcutName: string, isOn: boolean) => {
|
||||||
|
setSettingsState((prevState) => {
|
||||||
|
const updatedShortcuts = prevState.shortcuts.map((shortcut) =>
|
||||||
|
shortcut.name === shortcutName ? { ...shortcut, enabled: isOn } : shortcut
|
||||||
|
);
|
||||||
|
return { ...prevState, shortcuts: updatedShortcuts };
|
||||||
|
});
|
||||||
|
}, [setSettingsState]);
|
||||||
|
|
||||||
|
const isValidTitle = useCallback((title: string) => title.trim() !== "", []);
|
||||||
|
|
||||||
|
const isValidURL = useCallback((url: string) => {
|
||||||
const pattern = new RegExp("^(https?:\\/\\/)?[\\w.-]+[\\w.-]+(/[\\w.-]*)*$", "i");
|
const pattern = new RegExp("^(https?:\\/\\/)?[\\w.-]+[\\w.-]+(/[\\w.-]*)*$", "i");
|
||||||
return pattern.test(url);
|
return pattern.test(url);
|
||||||
};
|
}, []);
|
||||||
|
|
||||||
const addNewCustomShortcut = (): void => {
|
const addNewCustomShortcut = useCallback(() => {
|
||||||
if (isValidTitle(newTitle) && isValidURL(newURL)) {
|
if (isValidTitle(newTitle) && isValidURL(newURL)) {
|
||||||
const newShortcut: CustomShortcut = { name: newTitle.trim(), url: formatUrl(newURL).trim(), icon: newTitle[0] };
|
const newShortcut: CustomShortcut = { name: newTitle.trim(), url: formatUrl(newURL).trim(), icon: newTitle[0] };
|
||||||
const updatedCustomShortcuts = [...settingsState.customshortcuts, newShortcut];
|
const updatedCustomShortcuts = [...settingsState.customshortcuts, newShortcut];
|
||||||
setSettingsState({ ...settingsState, customshortcuts: updatedCustomShortcuts });
|
setSettingsState(prevState => ({ ...prevState, updatedCustomShortcuts }));
|
||||||
|
|
||||||
setNewTitle("");
|
setNewTitle("");
|
||||||
setNewURL("");
|
setNewURL("");
|
||||||
|
|
||||||
@@ -53,18 +47,18 @@ function Shortcuts() {
|
|||||||
// Replace with a more user-friendly way to display errors
|
// Replace with a more user-friendly way to display errors
|
||||||
console.error("Please enter a valid title and URL.");
|
console.error("Please enter a valid title and URL.");
|
||||||
}
|
}
|
||||||
};
|
}, [newTitle, newURL, isValidTitle, isValidURL, setSettingsState]);
|
||||||
|
|
||||||
const deleteCustomShortcut = (index: number): void => {
|
const deleteCustomShortcut = useCallback((index: number) => {
|
||||||
const updatedCustomShortcuts = settingsState.customshortcuts.filter((_, i) => i !== index);
|
setSettingsState((prevState) => ({
|
||||||
setSettingsState({ ...settingsState, customshortcuts: updatedCustomShortcuts });
|
...prevState,
|
||||||
};
|
customshortcuts: prevState.customshortcuts.filter((_, i) => i !== index),
|
||||||
|
}));
|
||||||
|
}, [setSettingsState]);
|
||||||
|
|
||||||
const [isFormVisible, setFormVisible] = useState(false);
|
const toggleForm = useCallback(() => {
|
||||||
|
setFormVisible((isVisible) => !isVisible);
|
||||||
const toggleForm = () => {
|
}, []);
|
||||||
setFormVisible(!isFormVisible);
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col divide-y divide-zinc-100 dark:divide-zinc-700">
|
<div className="flex flex-col divide-y divide-zinc-100 dark:divide-zinc-700">
|
||||||
@@ -77,48 +71,48 @@ function Shortcuts() {
|
|||||||
transition={{ type: "spring", damping: 20 }}
|
transition={{ type: "spring", damping: 20 }}
|
||||||
>
|
>
|
||||||
{isFormVisible &&
|
{isFormVisible &&
|
||||||
<div className="flex flex-col items-center mb-4">
|
<div className="flex flex-col items-center mb-4">
|
||||||
<motion.input
|
<motion.input
|
||||||
initial={{ opacity: 0, y: -10 }}
|
initial={{ opacity: 0, y: -10 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ delay: 0.2 }}
|
transition={{ delay: 0.2 }}
|
||||||
className="w-full p-2 rounded-md bg-zinc-100 dark:bg-zinc-700 focus:outline-none"
|
className="w-full p-2 rounded-md bg-zinc-100 dark:bg-zinc-700 focus:outline-none"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="Shortcut Name"
|
placeholder="Shortcut Name"
|
||||||
value={newTitle}
|
value={newTitle}
|
||||||
onChange={(e) => setNewTitle(e.target.value)}
|
onChange={(e) => setNewTitle(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<motion.input
|
<motion.input
|
||||||
initial={{ opacity: 0, y: -10 }}
|
initial={{ opacity: 0, y: -10 }}
|
||||||
animate={{ opacity: 1, y: 0 }}
|
animate={{ opacity: 1, y: 0 }}
|
||||||
transition={{ delay: 0.3 }}
|
transition={{ delay: 0.3 }}
|
||||||
className="w-full p-2 my-2 rounded-md bg-zinc-100 dark:bg-zinc-700 focus:outline-none"
|
className="w-full p-2 my-2 rounded-md bg-zinc-100 dark:bg-zinc-700 focus:outline-none"
|
||||||
type="text"
|
type="text"
|
||||||
placeholder="URL eg. https://google.com"
|
placeholder="URL eg. https://google.com"
|
||||||
value={newURL}
|
value={newURL}
|
||||||
onChange={(e) => setNewURL(e.target.value)}
|
onChange={(e) => setNewURL(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<motion.button
|
<motion.button
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
animate={{ opacity: 1 }}
|
animate={{ opacity: 1 }}
|
||||||
transition={{ delay: 0.4 }}
|
transition={{ delay: 0.4 }}
|
||||||
className="w-full px-4 py-2 text-white bg-blue-500 rounded-md"
|
className="w-full px-4 py-2 text-white bg-blue-500 rounded-md"
|
||||||
onClick={ addNewCustomShortcut }
|
onClick={ addNewCustomShortcut }
|
||||||
>
|
>
|
||||||
Add
|
Add
|
||||||
</motion.button>
|
</motion.button>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</motion.div>
|
</motion.div>
|
||||||
{!isFormVisible && (
|
|
||||||
<button
|
|
||||||
className="w-full px-4 py-2 mb-4 text-white bg-blue-500 rounded"
|
|
||||||
onClick={toggleForm}
|
|
||||||
>
|
|
||||||
Add Custom Shortcut
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</AnimatePresence>
|
</AnimatePresence>
|
||||||
|
{!isFormVisible && (
|
||||||
|
<button
|
||||||
|
className="w-full px-4 py-2 mb-4 text-white bg-blue-500 rounded"
|
||||||
|
onClick={toggleForm}
|
||||||
|
>
|
||||||
|
Add Custom Shortcut
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Shortcuts Section */}
|
{/* Shortcuts Section */}
|
||||||
{settingsState.shortcuts ? (
|
{settingsState.shortcuts ? (
|
||||||
@@ -149,6 +143,6 @@ function Shortcuts() {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
});
|
||||||
|
|
||||||
export default memo(Shortcuts);
|
export default Shortcuts;
|
||||||
Reference in New Issue
Block a user