Skip to content

Commit

Permalink
Merge pull request #56 from celestiaorg/hotfix/glossary-section-scrol…
Browse files Browse the repository at this point in the history
…l-links

Fix scroll links broken due traling slash changes
  • Loading branch information
alex-beckett authored Jan 19, 2025
2 parents acfeff0 + 8f7da9a commit 1dfc8a7
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 147 deletions.
24 changes: 12 additions & 12 deletions next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ const nextConfig = {
pageExtensions: ["js", "jsx", "ts", "tsx"],
output: "export",
distDir: "dist",
images: { unoptimized: true }, // comment out if using vercel or other service with backend support
images: { unoptimized: true },
trailingSlash: true,
async redirects() {
return redirects;
Expand All @@ -12,48 +12,48 @@ const nextConfig = {

const redirects = [
{
source: "/learn/first-principles/modular-blockchains-and-first-principles",
destination: "/learn/beginners/modular-blockchains-and-first-principles",
source: "/learn/first-principles/modular-blockchains-and-first-principles/",
destination: "/learn/beginners/modular-blockchains-and-first-principles/",
permanent: true,
},
{
source: "/learn/values-of-modular-blockchains/modular-blockchains-are-user-first",
destination: "/learn/beginners/modular-blockchains-are-user-first",
source: "/learn/values-of-modular-blockchains/modular-blockchains-are-user-first/",
destination: "/learn/beginners/modular-blockchains-are-user-first/",
permanent: true,
},
{
source: "/learn/basics-of-modular-blockchains/modular-and-monolithic-blockchains/",
destination: "/learn/intermediates/modular-and-monolithic-blockchains",
destination: "/learn/intermediates/modular-and-monolithic-blockchains/",
permanent: true,
},
{
source: "/learn/basics-of-modular-blockchains/benefits-of-modular-blockchains/",
destination: "/learn/intermediates/benefits-of-modular-blockchains",
destination: "/learn/intermediates/benefits-of-modular-blockchains/",
permanent: true,
},
{
source: "/learn/modular-architectures/the-modular-stack/",
destination: "/learn/intermediates/the-modular-stack",
destination: "/learn/intermediates/the-modular-stack/",
permanent: true,
},
{
source: "/learn/modular-software/the-differences-of-modular-software/",
destination: "/learn/intermediates/the-differences-of-modular-software",
destination: "/learn/intermediates/the-differences-of-modular-software/",
permanent: true,
},
{
source: "/learn/sovereign-rollups/an-introduction/",
destination: "/learn/intermediates/sovereign-rollups-an-introduction",
destination: "/learn/intermediates/sovereign-rollups-an-introduction/",
permanent: true,
},
{
source: "/learn/sovereign-rollups/misconceptions/",
destination: "/learn/intermediates/sovereign-rollups-misconceptions",
destination: "/learn/intermediates/sovereign-rollups-misconceptions/",
permanent: true,
},
{
source: "/learn/modular-settlement-layers/settlement-in-the-modular-stack/",
destination: "/learn/intermediates/settlement-in-the-modular-stack",
destination: "/learn/intermediates/settlement-in-the-modular-stack/",
permanent: true,
},
];
Expand Down
62 changes: 27 additions & 35 deletions src/app/learn/beginners/layout.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,32 @@ import TertiaryHero from "@/components/Heroes/TertiaryHero";
import TabNavigation from "@/components/TabNavigation/TabNavigation";

export default function BeginnersLayout({ children }) {
const routeTabNavigation = {
"Modular blockchains for beginners":
"/learn/beginners/modular-blockchains-for-beginners",
"The modular stack": "/learn/beginners/the-modular-stack",
"Values of modular blockchains":
"/learn/beginners/modular-blockchains-are-user-first",
"First Principles":
"/learn/beginners/modular-blockchains-and-first-principles",
};
const routeTabNavigation = {
"Modular blockchains for beginners": "/learn/beginners/modular-blockchains-for-beginners",
"The modular stack": "/learn/beginners/the-modular-stack",
"Values of modular blockchains": "/learn/beginners/modular-blockchains-are-user-first",
"First Principles": "/learn/beginners/modular-blockchains-and-first-principles",
};

return (
<>
<TertiaryHero
title={"Modular blockchains for beginners"}
blurbTitle={
"Modular blockchains are changing the way we think of and build decentralized applications."
}
blurbCopy={
<>
That’s pretty much what everyone says about their new blockchain
tech. So, why care about modular blockchains? Why is this time
different?
<br />
<br />
We could write a whole book about all the fantastic things that
modular blockchains can do. But most people don’t have time to read
a whole book, so we wrote this short article instead to give you the
big picture.
</>
}
/>
<TabNavigation navigation={routeTabNavigation} />
<div className="relative">{children}</div>
<div id={"learn-bottom"} />
</>
);
return (
<>
<TertiaryHero
title={"Modular blockchains for beginners"}
blurbTitle={"Modular blockchains are changing the way we think of and build decentralized applications."}
blurbCopy={
<>
That’s pretty much what everyone says about their new blockchain tech. So, why care about modular blockchains? Why is this
time different?
<br />
<br />
We could write a whole book about all the fantastic things that modular blockchains can do. But most people don’t have time to
read a whole book, so we wrote this short article instead to give you the big picture.
</>
}
/>
<TabNavigation navigation={routeTabNavigation} />
<div className='relative'>{children}</div>
<div id={"learn-bottom"} />
</>
);
}
116 changes: 16 additions & 100 deletions src/components/Accordion/GlossaryAccordion.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,16 @@
import React, { useState, useEffect } from "react";
import { useRouter } from "next/navigation";
import Container from "@/components/Container/Container";
import Accordion from "@/components/Accordion/Accordion";
import { Display, Body, Heading } from "@/macros/Copy";
import HeadingWithSuperscript from "@/micros/HeadingWithSuperscript/HeadingWithSuperscript";
import { Col, Row } from "@/macros/Grids";
import Icon from "@/macros/Icons/Icon";
import SearchInput from "@/macros/Forms/SearchInput";
import Link from "next/link";
import PrimaryButton from "@/macros/Buttons/PrimaryButton";
import FacebookSVG from "@/macros/SVGs/FacebookSVG";
import XTwitterSVG from "@/macros/SVGs/XTwitterSVG";
import EmailAltSVG from "@/macros/SVGs/EmailAltSVG";
import CopySVG from "@/macros/SVGs/CopySVG";
import { usePathname } from "next/navigation";

const GlossaryAccordion = ({ glossaryData }) => {
const GlossaryDirectory = ({ glossaryData }) => {
const router = useRouter();
const pathname = usePathname();
const [searchTerm, setSearchTerm] = useState("");
Expand All @@ -39,70 +34,36 @@ const GlossaryAccordion = ({ glossaryData }) => {

const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");

// Group glossary data by the first letter of each term's title
const groupedData = alphabet.reduce((acc, letter) => {
const groupedTerms = alphabet.reduce((acc, letter) => {
const terms = filteredData.filter((term) => term.title[0].toUpperCase() === letter);
if (terms.length > 0) {
acc[letter] = terms;
}
return acc;
}, {});

// Initialize accordion state with unique IDs and open/close status
const [accordionState, setAccordionState] = useState(
glossaryData.reduce((acc, term) => {
acc[term.slug] = { ...term, isOpen: false };
return acc;
}, {})
);

const toggleAccordion = (id) => {
setAccordionState((prevState) => ({
...prevState,
[id]: {
...prevState[id],
isOpen: !prevState[id].isOpen,
},
}));

const isOpen = !accordionState[id].isOpen;
if (isOpen) {
router.push(`/glossary/${id}`, {
scroll: false,
shallow: true,
});
} else {
router.push(`/glossary`, { scroll: false, shallow: true });
}
};
const clearSearch = () => {
setSearchTerm("");
router.push(`/glossary`, {
router.push(`/glossary/`, {
scroll: false,
shallow: true,
});
};

// Initial load effect to open and scroll to the term from URL if present
// Simplified scroll to term effect
useEffect(() => {
const term = pathname.split("/").pop();
if (term && accordionState[term]) {
// Open the specified accordion
setAccordionState((prevState) => ({
...prevState,
[term]: { ...prevState[term], isOpen: true },
}));

// Scroll to the accordion element smoothly
const term = pathname.split("/").filter(Boolean).pop();
if (term) {
setTimeout(() => {
const element = document.getElementById(`accordion-${term}`);
const scrollIntoView = element?.getBoundingClientRect().top < 0 || element?.getBoundingClientRect().top > window.innerHeight;
if (element) {
const scrollIntoView = element.getBoundingClientRect().top < 0 || element.getBoundingClientRect().top > window.innerHeight;

// if element is not in view, scroll to it
if (scrollIntoView) {
element.scrollIntoView({ behavior: "smooth", block: "center" });
if (scrollIntoView) {
element.scrollIntoView({ behavior: "smooth", block: "center" });
}
}
}, 100); // Delay to ensure DOM is fully ready
}, 100);
}
}, [pathname]);

Expand All @@ -120,7 +81,7 @@ const GlossaryAccordion = ({ glossaryData }) => {
<Col width={searchFocus ? 50 : 70} className={"transition-all"}>
<div className='flex w-auto gap-2 mx-auto overflow-x-scroll no-scrollbar'>
{alphabet.map((letter) => {
const isDisabled = !groupedData[letter];
const isDisabled = !groupedTerms[letter];
return (
<Link
key={letter}
Expand Down Expand Up @@ -151,7 +112,7 @@ const GlossaryAccordion = ({ glossaryData }) => {
</Col>
</Row>
<Container size='lg'>
{Object.keys(groupedData).map((letter) => (
{Object.keys(groupedTerms).map((letter) => (
<Row key={letter} id={letter} className={"py-10 lg:py-20 lg:flex lg:gap-12"}>
<Col width={20} className='lg:py-6'>
<HeadingWithSuperscript>
Expand All @@ -163,7 +124,7 @@ const GlossaryAccordion = ({ glossaryData }) => {
</HeadingWithSuperscript>
</Col>
<Col width={80}>
{groupedData[letter].map((term) => (
{groupedTerms[letter].map((term) => (
<div key={term.slug} id={`accordion-${term.slug}`} className='border-b border-black-subtle last:border-b-0'>
<div className='py-6'>
<Heading tag={"h3"} size={"sm"} className={"text-left mb-4"}>
Expand Down Expand Up @@ -199,49 +160,4 @@ const GlossaryAccordion = ({ glossaryData }) => {
);
};

const ShareIcons = ({ slug }) => {
const socialLinks = [
{
url: `https://twitter.com/intent/tweet?url=https://celestia.org/glossary/${slug}`,
Icon: <XTwitterSVG className='w-5' />,
IconHover: <XTwitterSVG dark className='w-6' />,
text: "Share on Twitter/X",
},
{
url: `mailto:?subject=Check out Celestia&body=Check out Celestia: https://celestia.org/glossary/${slug}`,
Icon: <EmailAltSVG className='w-6' />,
IconHover: <EmailAltSVG dark className='w-7 h-7' />,
text: "Share via Email",
},
{
url: `https://www.facebook.com/sharer/sharer.php?u=https://celestia.org/glossary/${slug}`,
Icon: <FacebookSVG className='w-6' />,
IconHover: <FacebookSVG dark className='w-7 h-7' />,
text: "Share on Facebook",
},
{
onClick: () => {
navigator.clipboard.writeText(`https://celestia.org/glossary/${slug}`);
},
Icon: <CopySVG className='w-7 h-7' />,
IconHover: <CopySVG dark className='w-8 h-8' />,
text: "Copy link",
},
];

return (
<div className='flex'>
{socialLinks.map((link, index) => {
const Tag = link.url ? "a" : "button";

return (
<Tag key={index} href={link.url} onClick={link.onClick} target='_blank' rel='noreferrer' className='group'>
<Icon Icon={link.Icon} hover dark={false} border={false} HoverIcon={link.IconHover} size={40} transparentBg={false} />
</Tag>
);
})}
</div>
);
};

export default GlossaryAccordion;
export default GlossaryDirectory;

0 comments on commit 1dfc8a7

Please sign in to comment.