performance improvements to shortcuts and tab container components

This commit is contained in:
SethBurkart123
2024-03-28 07:13:22 +11:00
parent 8219ae33c3
commit 48cf79e6f1
2 changed files with 88 additions and 94 deletions
+16 -16
View File
@@ -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>
</> </>
); );
}; };
+72 -78
View File
@@ -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;