Autogenerate read all section
This commit is contained in:
parent
0762d640c3
commit
99acb0f470
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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} />
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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".
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
export const metadata = {
|
||||
title: "4. Officers",
|
||||
url: "4"
|
||||
id: "officers"
|
||||
};
|
||||
|
||||
The officers of the Club shall be:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -1,6 +0,0 @@
|
|||
export const metadata = {
|
||||
title: "Read All",
|
||||
url: "0"
|
||||
};
|
||||
|
||||
You can leave readall blank, it is auto generated.
|
|
@ -54,7 +54,7 @@ declare module "*.organized-content.mdx" {
|
|||
|
||||
interface OrganizedContentMetadata {
|
||||
title: string;
|
||||
url: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
const ReactComponent: ComponentType;
|
||||
|
|
Loading…
Reference in New Issue