diff --git a/components/ImageBox/ImageBox.jsx b/components/ImageBox/ImageBox.jsx index 4c3381a..3403230 100644 --- a/components/ImageBox/ImageBox.jsx +++ b/components/ImageBox/ImageBox.jsx @@ -1,5 +1,5 @@ import Image from "next/image"; -import React from "react"; +import React, { useMemo } from "react"; import Styles from "./ImageBox.module.scss"; function ImageBox({ @@ -10,35 +10,39 @@ function ImageBox({ alt, src, style, - layout, + layout = "fill", aspectRatio, + priority = false, ...rest }) { - let dimensions = {}; - width ? (dimensions["width"] = width) : "100%"; - maxWidth ? (dimensions["maxWidth"] = maxWidth) : "100%"; - height ? (dimensions["height"] = height) : "unset"; - maxHeight ? (dimensions["maxHeight"] = maxHeight) : "unset"; + const dimensions = useMemo(() => { + const dims = {}; + if (width) dims.width = width; + if (maxWidth) dims.maxWidth = maxWidth; + if (height) dims.height = height; + if (maxHeight) dims.maxHeight = maxHeight; + return dims; + }, [width, maxWidth, height, maxHeight]); + + const containerClass = aspectRatio ? + Styles.imageRatioContainer : + Styles.imageContainer; return ( -
+
{alt
); } -export default ImageBox; +export default React.memo(ImageBox); diff --git a/components/QuestionBox/QuestionBox.jsx b/components/QuestionBox/QuestionBox.jsx index ebf9b5a..c414fbf 100644 --- a/components/QuestionBox/QuestionBox.jsx +++ b/components/QuestionBox/QuestionBox.jsx @@ -1,31 +1,44 @@ -import React, { useState } from "react"; +import React, { useState, useCallback, useMemo } from "react"; import Styles from "./QuestionBox.module.scss"; import { BiChevronRight, BiChevronDown } from "react-icons/bi"; function QuestionBox({ question }) { const [isOpen, setIsOpen] = useState(false); + + const toggleOpen = useCallback(() => { + setIsOpen(prev => !prev); + }, []); + + const sanitizedAnswer = useMemo(() => { + return question?.attributes?.answer.replace( + /)<[^<]*)*<\/script>/gi, + '' + ); + }, [question?.attributes?.answer]); + return (
-
{ - isOpen ? setIsOpen(false) : setIsOpen(true); - }} + onClick={toggleOpen} + aria-expanded={isOpen} + aria-controls={`answer-${question?.id}`} >

{question?.attributes?.question}

-
+ -
+ {isOpen && (
+ dangerouslySetInnerHTML={{ __html: sanitizedAnswer }} + /> )}
); } -export default QuestionBox; +export default React.memo(QuestionBox); diff --git a/components/metadata/Metadata.jsx b/components/metadata/Metadata.jsx index 69ed11e..ec91ac9 100644 --- a/components/metadata/Metadata.jsx +++ b/components/metadata/Metadata.jsx @@ -1,47 +1,57 @@ import Head from "next/head"; -import { useRouter } from "next/router"; -import React, { useEffect } from "react"; import Script from "next/script"; +import React from "react"; function Metadata({ title = "Lighthouse Storage - Store Data Permanently & Securely", description = "Decentralized storage powered by Filecoin. Secure, scalable, and ideal for individuals, developers, and enterprises.", url = "https://lighthouse.storage/", image = "https://gateway.lighthouse.storage/ipfs/Qmd7rR9EPKomhmoRUw2WB7FJAeSWAtC8c1nkKgGZL39LpB", + keywords = "decentralized storage, IPFS, Filecoin, permanent storage", }) { - const router = useRouter(); - return ( <> {title} + + + + + {/* Open Graph */} - {/* */} + {/* Twitter */} - + + + + - - ); } -export default Metadata; +export default React.memo(Metadata); diff --git a/containers/EcosystemGrid/EcosystemGrid.jsx b/containers/EcosystemGrid/EcosystemGrid.jsx index 5f45143..be64f69 100644 --- a/containers/EcosystemGrid/EcosystemGrid.jsx +++ b/containers/EcosystemGrid/EcosystemGrid.jsx @@ -1,10 +1,10 @@ -import React, { useState, useContext } from "react"; +import React, { useState, useContext, useMemo, useCallback } from "react"; import styles from "./EcosystemGrid.module.scss"; import { RiTwitterXLine } from "react-icons/ri"; import { FaTelegramPlane } from "react-icons/fa"; import { SlGlobe } from "react-icons/sl"; import ThemeContext from "../../utils/services/Themecontext"; -import { ImageBox } from "../../components"; +import ImageBox from "../../components/ImageBox/ImageBox"; const badgeOptions = [ "Artificial Intelligence (AI)", @@ -391,10 +391,20 @@ const ecosystemData = [ const EcosystemGrid = () => { const [activeTag, setActiveTag] = useState("Artificial Intelligence (AI)"); - const filtered = ecosystemData.filter((item) => - item.tags.includes(activeTag) + const { theme } = useContext(ThemeContext); + + const filtered = useMemo(() => + ecosystemData.filter(item => item.tags.includes(activeTag)), + [activeTag] ); - const { theme, setTheme } = useContext(ThemeContext); + + const handleTagClick = useCallback((tag) => { + setActiveTag(tag); + }, []); + + const imageStyle = useMemo(() => ({ + filter: theme === "dark" ? "brightness(100%)" : "brightness(10%)" + }), [theme]); return (
@@ -402,10 +412,9 @@ const EcosystemGrid = () => { {badgeOptions.map((tag) => ( @@ -416,39 +425,24 @@ const EcosystemGrid = () => { {filtered .filter((item) => item.image) .map((item, idx) => ( -
+
{item.name}
- {/* {item.name} */} - - + -

{item.description}

{ ); }; -export default EcosystemGrid; +export default React.memo(EcosystemGrid); diff --git a/package.json b/package.json index 7f4161e..b5d6359 100644 --- a/package.json +++ b/package.json @@ -6,26 +6,26 @@ "dev": "next dev", "build": "next build", "start": "next start", - "lint": "next lint" + "lint": "next lint", + "analyze": "ANALYZE=true next build" }, "dependencies": { "aos": "^2.3.4", "axios": "^1.1.3", - "lighthouse_ui_2.0": "file:", - "next": "12.3.1", + "next": "^12.3.1", "react": "18.2.0", "react-countup": "^6.5.0", "react-dom": "18.2.0", "react-icons": "^4.7.1", "react-markdown": "^8.0.5", "react-paginate": "^8.1.4", - "react-pagination": "^1.0.0", "react-toastify": "^9.1.1", "rfs": "^10.0.0", "sass": "^1.55.0", "swiper": "^8.4.7" }, "devDependencies": { + "@next/bundle-analyzer": "^12.3.1", "eslint": "8.25.0", "eslint-config-next": "12.3.1" } diff --git a/pages/_app.js b/pages/_app.js index 03befd5..ce806f3 100644 --- a/pages/_app.js +++ b/pages/_app.js @@ -3,8 +3,6 @@ import "../styles/globals.scss"; import "swiper/css"; import "swiper/css/navigation"; import "swiper/css/pagination"; -import AOS from "aos"; -import "aos/dist/aos.css"; import { useEffect, useState } from "react"; import { ToastContainer } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; @@ -15,36 +13,45 @@ function MyApp({ Component, pageProps }) { const [theme, setTheme] = useState(null); useEffect(() => { - AOS.init({ - disable: false, - startEvent: "DOMContentLoaded", - initClassName: "aos-init", - animatedClassName: "aos-animate", - useClassNames: false, - disableMutationObserver: false, - debounceDelay: 50, - throttleDelay: 99, + const initAOS = async () => { + if (typeof window !== 'undefined') { + const AOS = (await import('aos')).default; + await import('aos/dist/aos.css'); + + AOS.init({ + disable: false, + startEvent: "DOMContentLoaded", + initClassName: "aos-init", + animatedClassName: "aos-animate", + useClassNames: false, + disableMutationObserver: false, + debounceDelay: 50, + throttleDelay: 99, + offset: 120, + delay: 0, + duration: 400, + easing: "ease", + once: true, + mirror: false, + anchorPlacement: "top-center", + }); + } + }; - offset: 120, - delay: 0, - duration: 400, - easing: "ease", - once: true, - mirror: false, - anchorPlacement: "top-center", - }); - const themeFromLocalStorage = JSON.parse( - localStorage?.getItem("lighthouse.storage/store") || "{}" - ); - if (themeFromLocalStorage?.theme) { - setTheme(themeFromLocalStorage?.theme); - } else { - setTheme("dark"); + initAOS(); + + if (typeof window !== 'undefined') { + const themeFromLocalStorage = JSON.parse( + localStorage?.getItem("lighthouse.storage/store") || "{}" + ); + setTheme(themeFromLocalStorage?.theme || "dark"); } }, []); useEffect(() => { - themeChanger(theme); + if (theme) { + themeChanger(theme); + } }, [theme]); return ( diff --git a/utils/services/theme.js b/utils/services/theme.js index 36ee513..900781f 100644 --- a/utils/services/theme.js +++ b/utils/services/theme.js @@ -42,12 +42,24 @@ const ThemeProperties = [ ]; export const themeChanger = (theme) => { - theme && - localStorage.setItem("lighthouse.storage/store", JSON.stringify({ theme })); - ThemeProperties.forEach((property) => { - document.documentElement.style.setProperty( - `${property?.property}`, - theme === "dark" ? property?.dark : property?.light - ); - }); + if (!theme || typeof window === 'undefined') return; + + try { + requestAnimationFrame(() => { + localStorage.setItem( + "lighthouse.storage/store", + JSON.stringify({ theme }) + ); + + const style = document.documentElement.style; + ThemeProperties.forEach((property) => { + style.setProperty( + property.property, + theme === "dark" ? property.dark : property.light + ); + }); + }); + } catch (error) { + console.error('Error updating theme:', error); + } };