From 730533e88e34cdd74d903629363efa89825a7ffd Mon Sep 17 00:00:00 2001 From: 3zachm <3zachm2@gmail.com> Date: Tue, 7 Feb 2023 01:49:06 -0800 Subject: [PATCH] responsive design, url routing, image support --- components/wiki/PageBody.tsx | 11 ++++- components/wiki/RenderMarkdown.tsx | 38 +++++++++++++++-- interfaces/WikiPage.ts | 2 + pages/wiki/[...slug]/index.tsx | 68 ++++++++++++++++++++++++++++-- 4 files changed, 110 insertions(+), 9 deletions(-) diff --git a/components/wiki/PageBody.tsx b/components/wiki/PageBody.tsx index 107e08c..ade3dff 100644 --- a/components/wiki/PageBody.tsx +++ b/components/wiki/PageBody.tsx @@ -3,14 +3,21 @@ import RenderMarkdown from "./RenderMarkdown"; interface PageBodyProps { children: string; + currentLanguage: string; + path: string; } -export default function PageBody({ children }: PageBodyProps) { +export default function PageBody(props: PageBodyProps) { return ( <div className="prose prose-sm sm:prose lg:prose-lg xl:prose-xl"> <div className={mdStyles["markdown-body"]}> <div className="text-left"> - <RenderMarkdown>{children}</RenderMarkdown> + <RenderMarkdown + path={props.path} + currentLanguage={props.currentLanguage} + > + {props.children} + </RenderMarkdown> </div> </div> </div> diff --git a/components/wiki/RenderMarkdown.tsx b/components/wiki/RenderMarkdown.tsx index 54891f2..4b62cda 100644 --- a/components/wiki/RenderMarkdown.tsx +++ b/components/wiki/RenderMarkdown.tsx @@ -7,24 +7,54 @@ import remarkGfm from "remark-gfm"; interface RenderMarkdownProps { children: string; + path: string; + currentLanguage: string; } -export default function RenderMarkdown({ children }: RenderMarkdownProps) { +export default function RenderMarkdown(pageprops: RenderMarkdownProps) { return ( <ReactMarkdown remarkPlugins={[remarkGfm]} rehypePlugins={[rehypeRaw, rehypeHighlight, rehypeSlug]} components={{ a: ({ node, ...props }) => { + // if the link is internal, reformat it; if it ends with a slash, do not apply this + let href = props.href as string; + if (!href.endsWith("/") && !href.startsWith("http")) { + if (href.startsWith("/wiki/")) { + href = `/wiki/${pageprops.currentLanguage}${href.slice(5)}`; + } else { + // if single relative + href = `/wiki/${pageprops.currentLanguage}/${pageprops.path}/${href}`; + } + } return ( - <Link legacyBehavior href={props.href as string}> - <a>{props.children ? props.children[0] : props.href}</a> + <Link legacyBehavior href={href as string}> + <a>{props.children ? props.children[0] : href}</a> </Link> ); }, + img: ({ node, ...props }) => { + // if image is internal (relative), prefix it with the current page's path + let src = props.src as string; + if (!src.startsWith("http") && !src.startsWith("/")) { + src = `/img/wiki/${pageprops.path}/${src}`; + } + return ( + <div className="flex w-full flex-col items-center justify-center"> + <img + className="mb-2" + src={src} + alt={props.alt as string} + title={props.title as string} + /> + <p> {props.title as string} </p> + </div> + ); + }, }} > - {children} + {pageprops.children} </ReactMarkdown> ); } diff --git a/interfaces/WikiPage.ts b/interfaces/WikiPage.ts index f09de46..f3ecbd4 100644 --- a/interfaces/WikiPage.ts +++ b/interfaces/WikiPage.ts @@ -2,6 +2,8 @@ export default interface WikiPage { slug: string; layout?: string; content: string; + language: string; + path: string; data: { layout?: string; }; diff --git a/pages/wiki/[...slug]/index.tsx b/pages/wiki/[...slug]/index.tsx index 9e48730..8bdd9cd 100644 --- a/pages/wiki/[...slug]/index.tsx +++ b/pages/wiki/[...slug]/index.tsx @@ -20,11 +20,16 @@ interface TableOfContentsItem { function WikiLandingPage(props: WikiLandingPageProps) { const [wikiContent, setWikiContent] = useState<ReactElement>(<></>); const [indexContent, setIndexContent] = useState<TableOfContentsItem[]>([]); + const [showMobileIndex, setShowMobileIndex] = useState<boolean>(false); // needed for proper hydration due to replacing some elements useEffect(() => { - setWikiContent(<PageBody>{props.page.content}</PageBody>); - }, [props.page.content]); + setWikiContent( + <PageBody currentLanguage={props.page.language} path={props.page.path}> + {props.page.content} + </PageBody> + ); + }, [props.page.content, props.page.language, props.page.path]); useEffect(() => { const toc: TableOfContentsItem[] = []; @@ -39,7 +44,6 @@ function WikiLandingPage(props: WikiLandingPageProps) { } }); setIndexContent(toc); - console.log(toc); }, [wikiContent]); return ( @@ -71,6 +75,62 @@ function WikiLandingPage(props: WikiLandingPageProps) { </div> </div> </div> + {/* Mobile "Side"-bar */} + <div className="col-span-10 mb-6 lg:hidden"> + <div className="w-full rounded-2xl rounded-tl-2xl bg-zinc-800 bg-opacity-70 p-6 text-left text-6xl text-white"> + <div + className="flex cursor-pointer flex-row text-2xl" + onClick={() => setShowMobileIndex(!showMobileIndex)} + > + <div>Contents</div> + <m.svg + className="pointer-events-auto mt-2 ml-3 cursor-pointer lg:hidden" + origin="center" + width="20" + height="21" + viewBox="0 0 330 330" + x={0} + y={0} + animate={{ rotate: showMobileIndex ? 180 : 0 }} + > + <m.path + d="M325.607,79.393c-5.857-5.857-15.355-5.858-21.213,0.001l-139.39,139.393L25.607,79.393 c-5.857-5.857-15.355-5.858-21.213,0.001c-5.858,5.858-5.858,15.355,0,21.213l150.004,150c2.813,2.813,6.628,4.393,10.606,4.393 s7.794-1.581,10.606-4.394l149.996-150C331.465,94.749,331.465,85.251,325.607,79.393z" + fill="white" + stroke="white" + strokeWidth="15" + strokeLinecap="round" + /> + </m.svg> + </div> + <m.div + className="overflow-hidden text-left text-orange-400" + animate={{ + height: showMobileIndex ? "auto" : 0, + marginTop: showMobileIndex ? "0.5rem" : 0, + }} + > + {indexContent.map((item) => { + return ( + // increase indent based on heading level + <div + style={{ + paddingLeft: `${(parseInt(item.type[1]) - 2) * 2}rem`, + }} + className="text-xl" + key={item.id} + > + <Link href={`#${item.id}`}> + <p className="mt-2 overflow-hidden overflow-ellipsis whitespace-nowrap hover:text-white"> + {item.text} + </p> + </Link> + </div> + ); + })} + </m.div> + </div> + </div> + {/* Main content */} <div className="col-span-10 rounded-2xl bg-zinc-800 bg-opacity-70 p-6 text-center text-6xl text-white lg:col-span-8 lg:rounded-tl-none"> <m.div initial={{ opacity: 0 }} @@ -126,6 +186,8 @@ export async function getStaticProps({ params }: Params) { page: { slug: params.slug, content: pageData.content, + language: lang, + path: path, data: pageData.data, }, },