Autogenerate read all section

This commit is contained in:
Aditya Thakral 2021-06-09 04:45:25 -04:00
parent 0762d640c3
commit 99acb0f470
10 changed files with 119 additions and 118 deletions

View File

@ -3,85 +3,79 @@ import styles from "./OrganizedContent.module.css";
export interface LinkProps {
className?: string;
url: string;
children: string | ReactNode | (string | ReactNode)[];
id: string;
children: ReactNode;
}
type Link = ComponentType<LinkProps>;
interface Heading {
interface Section {
id: string;
title: string;
url: string;
content: ReactNode;
Content: ComponentType;
}
const READ_ALL_TITLE = "Read All";
export const READ_ALL_ID = "read-all";
interface Props {
headings: Heading[];
currentIndex: number;
link: Link;
children: ReactNode;
}
interface ChildProps {
headings: Heading[];
currentIndex: number;
sections: Section[];
currentId: string;
link: Link;
}
export const OrganizedContent = ({
headings,
currentIndex,
link: Link,
children,
}: Props) => {
const isReadAll = headings[currentIndex].title === "Read All";
export function OrganizedContent(props: Props) {
const sections = createSections(props.sections);
const currentIndex = sections.findIndex(({ id }) => id === props.currentId);
const readAllContent = headings
.filter((heading: { title: string }) => heading.title !== "Read All")
.map((heading) => (
<div key={heading.url}>
<h1>{heading.title}</h1>
{heading.content}
</div>
));
if (currentIndex < 0) {
throw new Error(`Section with ID ${props.currentId} was not found`);
}
const childProps: ChildProps = {
headings: headings,
currentIndex: currentIndex,
link: Link,
};
const section = sections[currentIndex];
const isReadAll = section.id === READ_ALL_ID;
return (
<div className={styles.organizedContent}>
<Nav {...childProps} />
<Nav sections={sections} currentIndex={currentIndex} link={props.link} />
<div>
{isReadAll ? (
<>{readAllContent}</>
<section.Content />
) : (
<>
<h1>{headings[currentIndex].title}</h1>
{children}
<Footer {...childProps} />
<h1>{section.title}</h1>
<section.Content />
<Footer
sections={sections}
currentIndex={currentIndex}
link={props.link}
/>
</>
)}
</div>
</div>
);
};
}
const Nav = ({ headings, currentIndex, link: Link }: ChildProps) => {
interface NavProps {
sections: Section[];
currentIndex: number;
link: Link;
}
function Nav({ sections, currentIndex, link: Link }: NavProps) {
return (
<div className={styles.nav}>
{headings.map((heading, index) => (
{sections.map((section, index) => (
<div
className={index === currentIndex ? styles.selectedHeadingArea : ""}
key={heading.url}
key={section.id}
>
<div
className={
styles.navOption +
" " +
(heading.title === "Read All" ? styles.readAll : "")
(section.title === "Read All" ? styles.readAll : "")
}
>
{index === currentIndex && (
@ -93,9 +87,9 @@ const Nav = ({ headings, currentIndex, link: Link }: ChildProps) => {
" " +
(index === currentIndex ? styles.navLinkSelected : "")
}
url={heading.url}
id={section.id}
>
{heading.title}
{section.title}
</Link>
</div>
<div className={styles.divider}></div>
@ -103,62 +97,90 @@ const Nav = ({ headings, currentIndex, link: Link }: ChildProps) => {
))}
</div>
);
};
}
const Footer = ({ headings, currentIndex, link: Link }: ChildProps) => {
const prevHeading =
currentIndex > 0 && headings[currentIndex - 1].title !== "Read All"
? headings[currentIndex - 1]
interface FooterProps {
sections: Section[];
currentIndex: number;
link: Link;
}
function Footer({ sections, currentIndex, link: Link }: FooterProps) {
const prevSection =
currentIndex > 0 && sections[currentIndex - 1].id !== READ_ALL_ID
? sections[currentIndex - 1]
: undefined;
const nextHeading =
currentIndex < headings.length - 1 &&
headings[currentIndex + 1].title !== "Read All"
? headings[currentIndex + 1]
const nextSection =
currentIndex < sections.length - 1 &&
sections[currentIndex + 1].id !== READ_ALL_ID
? sections[currentIndex + 1]
: undefined;
return (
<div className={styles.footer}>
{prevHeading && (
<Link url={prevHeading.url}>
{prevSection && (
<Link id={prevSection.id}>
<div className={styles.footerSection}>
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="9"
viewBox="0 0 14 9"
className={styles.arrow + " " + styles.prevArrow}
>
<path d="M6.24407 8.12713C6.64284 8.58759 7.35716 8.58759 7.75593 8.12713L13.3613 1.65465C13.9221 1.00701 13.4621 0 12.6053 0H1.39467C0.537918 0 0.0778675 1.00701 0.638743 1.65465L6.24407 8.12713Z" />
</svg>
<Arrow direction="left" />
<div>
<div className={styles.prevNext}>Previous</div>
<div className={styles.arrowHeading}>{prevHeading.title}</div>
<div className={styles.arrowHeading}>{prevSection.title}</div>
</div>
</div>
</Link>
)}
<div className={styles.footerDivider}></div>
{nextHeading && (
<Link url={nextHeading.url}>
{nextSection && (
<Link id={nextSection.id}>
<div className={styles.footerSection}>
<div>
<div className={styles.prevNext + " " + styles.nextText}>
Next
</div>
<div className={styles.arrowHeading}>{nextHeading.title}</div>
<div className={styles.arrowHeading}>{nextSection.title}</div>
</div>
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="9"
viewBox="0 0 14 9"
className={styles.arrow + " " + styles.nextArrow}
>
<path d="M6.24407 8.12713C6.64284 8.58759 7.35716 8.58759 7.75593 8.12713L13.3613 1.65465C13.9221 1.00701 13.4621 0 12.6053 0H1.39467C0.537918 0 0.0778675 1.00701 0.638743 1.65465L6.24407 8.12713Z" />
</svg>
<Arrow direction="right" />
</div>
</Link>
)}
</div>
);
};
}
function createSections(sections: Section[]) {
return [
{
id: READ_ALL_ID,
title: READ_ALL_TITLE,
Content() {
return (
<>
{sections.map(({ id, title, Content: SectionContent }) => (
<div key={id}>
<h1>{title}</h1>
<SectionContent />
</div>
))}
</>
);
},
},
...sections,
];
}
function Arrow({ direction }: { direction: "left" | "right" }) {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="9"
viewBox="0 0 14 9"
className={`${styles.arrow} ${
direction === "left" ? styles.prevArrow : styles.nextArrow
}`}
>
<path d="M6.24407 8.12713C6.64284 8.58759 7.35716 8.58759 7.75593 8.12713L13.3613 1.65465C13.9221 1.00701 13.4621 0 12.6053 0H1.39467C0.537918 0 0.0778675 1.00701 0.638743 1.65465L6.24407 8.12713Z" />
</svg>
);
}

View File

@ -11,9 +11,6 @@ import AltTab, {
metadata as altTabEventMetadata,
} from "../content/playground/alt-tab.event.mdx";
import ReadAll, {
metadata as readAllOrganizedContentMetadata,
} from "../content/playground/constitution/read-all.organized-content.mdx";
import Name, {
metadata as nameOrganizedContentMetadata,
} from "../content/playground/constitution/name.organized-content.mdx";
@ -56,14 +53,13 @@ const events = [
];
const constitution = [
{ content: <ReadAll />, ...readAllOrganizedContentMetadata },
{ content: <Name />, ...nameOrganizedContentMetadata },
{ content: <Purpose />, ...purposeOrganizedContentMetadata },
{ content: <Membership />, ...membershipOrganizedContentMetadata },
{ content: <Officers />, ...officersOrganizedContentMetadata },
{ content: <Duties />, ...dutiesOrganizedContentMetadata },
{ Content: Name, ...nameOrganizedContentMetadata },
{ Content: Purpose, ...purposeOrganizedContentMetadata },
{ Content: Membership, ...membershipOrganizedContentMetadata },
{ Content: Officers, ...officersOrganizedContentMetadata },
{ Content: Duties, ...dutiesOrganizedContentMetadata },
{
content: <ExecutiveCouncil />,
Content: ExecutiveCouncil,
...executiveCouncilOrganizedContentMetadata,
},
];
@ -165,28 +161,17 @@ export function TeamMemberCardDemo() {
export function OrganizedContentDemo() {
const sections = constitution;
const [index, setIndex] = useState(0);
const [id, setId] = useState(sections[0].id);
function FakeLink({ className, url, children }: LinkProps) {
function FakeLink({ className, id, children }: LinkProps) {
return (
<div
className={className}
onClick={() => {
const target = sections.findIndex((section) => section.url === url);
if (target >= 0) {
setIndex(target);
}
}}
>
<div className={className} onClick={() => setId(id)}>
{children}
</div>
);
}
return (
<OrganizedContent headings={sections} currentIndex={index} link={FakeLink}>
{sections[index].content}
</OrganizedContent>
<OrganizedContent sections={sections} currentId={id} link={FakeLink} />
);
}

View File

@ -1,6 +1,6 @@
export const metadata = {
title: "5. Duties of Officers",
url: "5"
id: "duties-of-officers"
};
The duties of the President shall be:

View File

@ -1,6 +1,6 @@
export const metadata = {
title: "6. Executive Council",
url: "6"
id: "executive-council"
};
The Executive Council shall consist of the present officers of the Club and the Faculty Advisor (as a non-voting member) and has the power to run the affairs of this club within the limits of this constitution. This includes the power to overrule or issue directions to any officer.

View File

@ -1,6 +1,6 @@
export const metadata = {
title: "3. Membership",
url: "3"
id: "membership"
};
In compliance with MathSoc regulations and in recognition of the club being primarily targeted at undergraduate students, full membership is open to all Social Members of the Mathematics Society and restricted to the same.

View File

@ -1,6 +1,6 @@
export const metadata = {
title: "1. Name",
url: "1"
id: "name"
};
The name of this organization shall be the "Computer Science Club of the University of Waterloo".

View File

@ -1,6 +1,6 @@
export const metadata = {
title: "4. Officers",
url: "4"
id: "officers"
};
The officers of the Club shall be:

View File

@ -1,6 +1,6 @@
export const metadata = {
title: "2. Purpose",
url: "2"
id: "purpose"
};
The Club is organized and will be operated exclusively for educational and scientific purposes in furtherance of:

View File

@ -1,6 +0,0 @@
export const metadata = {
title: "Read All",
url: "0"
};
You can leave readall blank, it is auto generated.

2
next-env.d.ts vendored
View File

@ -54,7 +54,7 @@ declare module "*.organized-content.mdx" {
interface OrganizedContentMetadata {
title: string;
url: string;
id: string;
}
const ReactComponent: ComponentType;