responsive design, url routing, image support
This commit is contained in:
parent
2ef5765ae2
commit
730533e88e
4 changed files with 110 additions and 9 deletions
|
@ -3,14 +3,21 @@ import RenderMarkdown from "./RenderMarkdown";
|
||||||
|
|
||||||
interface PageBodyProps {
|
interface PageBodyProps {
|
||||||
children: string;
|
children: string;
|
||||||
|
currentLanguage: string;
|
||||||
|
path: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function PageBody({ children }: PageBodyProps) {
|
export default function PageBody(props: PageBodyProps) {
|
||||||
return (
|
return (
|
||||||
<div className="prose prose-sm sm:prose lg:prose-lg xl:prose-xl">
|
<div className="prose prose-sm sm:prose lg:prose-lg xl:prose-xl">
|
||||||
<div className={mdStyles["markdown-body"]}>
|
<div className={mdStyles["markdown-body"]}>
|
||||||
<div className="text-left">
|
<div className="text-left">
|
||||||
<RenderMarkdown>{children}</RenderMarkdown>
|
<RenderMarkdown
|
||||||
|
path={props.path}
|
||||||
|
currentLanguage={props.currentLanguage}
|
||||||
|
>
|
||||||
|
{props.children}
|
||||||
|
</RenderMarkdown>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -7,24 +7,54 @@ import remarkGfm from "remark-gfm";
|
||||||
|
|
||||||
interface RenderMarkdownProps {
|
interface RenderMarkdownProps {
|
||||||
children: string;
|
children: string;
|
||||||
|
path: string;
|
||||||
|
currentLanguage: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function RenderMarkdown({ children }: RenderMarkdownProps) {
|
export default function RenderMarkdown(pageprops: RenderMarkdownProps) {
|
||||||
return (
|
return (
|
||||||
<ReactMarkdown
|
<ReactMarkdown
|
||||||
remarkPlugins={[remarkGfm]}
|
remarkPlugins={[remarkGfm]}
|
||||||
rehypePlugins={[rehypeRaw, rehypeHighlight, rehypeSlug]}
|
rehypePlugins={[rehypeRaw, rehypeHighlight, rehypeSlug]}
|
||||||
components={{
|
components={{
|
||||||
a: ({ node, ...props }) => {
|
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 (
|
return (
|
||||||
<Link legacyBehavior href={props.href as string}>
|
<Link legacyBehavior href={href as string}>
|
||||||
<a>{props.children ? props.children[0] : props.href}</a>
|
<a>{props.children ? props.children[0] : href}</a>
|
||||||
</Link>
|
</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>
|
</ReactMarkdown>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ export default interface WikiPage {
|
||||||
slug: string;
|
slug: string;
|
||||||
layout?: string;
|
layout?: string;
|
||||||
content: string;
|
content: string;
|
||||||
|
language: string;
|
||||||
|
path: string;
|
||||||
data: {
|
data: {
|
||||||
layout?: string;
|
layout?: string;
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,11 +20,16 @@ interface TableOfContentsItem {
|
||||||
function WikiLandingPage(props: WikiLandingPageProps) {
|
function WikiLandingPage(props: WikiLandingPageProps) {
|
||||||
const [wikiContent, setWikiContent] = useState<ReactElement>(<></>);
|
const [wikiContent, setWikiContent] = useState<ReactElement>(<></>);
|
||||||
const [indexContent, setIndexContent] = useState<TableOfContentsItem[]>([]);
|
const [indexContent, setIndexContent] = useState<TableOfContentsItem[]>([]);
|
||||||
|
const [showMobileIndex, setShowMobileIndex] = useState<boolean>(false);
|
||||||
|
|
||||||
// needed for proper hydration due to replacing some elements
|
// needed for proper hydration due to replacing some elements
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setWikiContent(<PageBody>{props.page.content}</PageBody>);
|
setWikiContent(
|
||||||
}, [props.page.content]);
|
<PageBody currentLanguage={props.page.language} path={props.page.path}>
|
||||||
|
{props.page.content}
|
||||||
|
</PageBody>
|
||||||
|
);
|
||||||
|
}, [props.page.content, props.page.language, props.page.path]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const toc: TableOfContentsItem[] = [];
|
const toc: TableOfContentsItem[] = [];
|
||||||
|
@ -39,7 +44,6 @@ function WikiLandingPage(props: WikiLandingPageProps) {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
setIndexContent(toc);
|
setIndexContent(toc);
|
||||||
console.log(toc);
|
|
||||||
}, [wikiContent]);
|
}, [wikiContent]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -71,6 +75,62 @@ function WikiLandingPage(props: WikiLandingPageProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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">
|
<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
|
<m.div
|
||||||
initial={{ opacity: 0 }}
|
initial={{ opacity: 0 }}
|
||||||
|
@ -126,6 +186,8 @@ export async function getStaticProps({ params }: Params) {
|
||||||
page: {
|
page: {
|
||||||
slug: params.slug,
|
slug: params.slug,
|
||||||
content: pageData.content,
|
content: pageData.content,
|
||||||
|
language: lang,
|
||||||
|
path: path,
|
||||||
data: pageData.data,
|
data: pageData.data,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue