frontpage/components/ProjectModal.tsx

110 lines
5.0 KiB
TypeScript
Raw Normal View History

2022-01-14 14:27:19 +01:00
import type { NextPage } from "next";
2022-06-15 00:35:49 +02:00
import { useEffect, useRef, useState, isValidElement } from "react";
2022-06-14 23:18:00 +02:00
import { useRouter } from "next/router";
2022-01-14 14:27:19 +01:00
import styles from "../styles/ProjectModal.module.css";
2022-06-12 14:22:15 +02:00
import type { Project, Diary } from "../lib/content/types";
2022-06-21 18:44:20 +02:00
import { useCommands } from "../lib/commands/ContextProvider";
2022-06-12 14:22:15 +02:00
import { generateContent, projectEmpty } from "../lib/content/generate";
import { useModalFunctions } from "./contexts/ModalFunctions";
2022-06-15 00:35:49 +02:00
import Spinner from "./Spinner";
import { renderToStaticMarkup } from "react-dom/server";
2022-01-14 14:27:19 +01:00
2022-06-13 13:14:00 +02:00
// Code Highlighting
import hljs from "highlight.js";
import rust from "highlight.js/lib/languages/rust";
import bash from "highlight.js/lib/languages/shell";
hljs.registerLanguage("rust", rust);
hljs.registerLanguage("bash", bash);
hljs.registerLanguage("console", bash);
hljs.registerLanguage("shell", bash);
2022-06-12 14:22:15 +02:00
const ProjectModal: NextPage = () => {
2022-06-15 00:35:49 +02:00
const [visible, _setVisible] = useState<boolean>(false);
const [currentContent, _setCurrentContent] = useState<Project | Diary | undefined>(undefined);
2022-06-13 12:54:40 +02:00
const [currentPage, setCurrentPage] = useState<number>(0);
2022-06-15 00:35:49 +02:00
const [HTMLContent, _setHTMLContent] = useState<string>(projectEmpty);
2022-06-14 23:18:00 +02:00
const router = useRouter();
const { updateCallbacks: updateCmdCallbacks, cmdContext } = useCommands();
const { updateCallbacks: updateModalCallbacks } = useModalFunctions();
2022-06-13 12:54:40 +02:00
2022-06-15 00:35:49 +02:00
const setHTMLContent = (html: any) => {
switch (true) {
case typeof html === "string": {
_setHTMLContent(html);
return;
}
case isValidElement(html): {
_setHTMLContent(renderToStaticMarkup(html));
return;
}
default: {
try {
_setHTMLContent(html.toString());
} catch {}
return;
}
}
};
2022-06-13 12:54:40 +02:00
const setModalContent = async (content: Project | Diary, selectedPage?: number) => {
2022-06-15 00:35:49 +02:00
_setCurrentContent(content);
2022-06-14 23:18:00 +02:00
router.replace("#", `#/${content.type}/${content.name}${content.type === "diary" && selectedPage ? `/${selectedPage}`: ""}`, {shallow: true});
2022-06-13 12:54:40 +02:00
if (content.type === "diary") setCurrentPage(selectedPage === undefined ? 0 : selectedPage);
2022-06-15 00:35:49 +02:00
setHTMLContent(<Spinner size={200} />);
2022-06-13 12:54:40 +02:00
setHTMLContent(await generateContent(content, selectedPage));
2022-06-12 14:22:15 +02:00
};
2022-01-14 14:27:19 +01:00
2022-06-15 00:35:49 +02:00
const setVisible = async (visible: boolean) => {
2022-06-14 23:18:00 +02:00
if (!visible) router.replace("#", undefined, {shallow: true});
2022-06-15 00:35:49 +02:00
_setVisible(visible);
2022-06-14 23:18:00 +02:00
};
const onContentReady = () => {
const selected = window.location.hash.split("/");
2022-07-29 14:26:22 +02:00
if (selected.length > 2) cmdContext.executeCommand(`project ${selected[2]}${selected[3] ? ` ${selected[3]}` : ""}`);
2022-06-14 23:18:00 +02:00
};
2022-06-15 00:35:49 +02:00
updateCmdCallbacks({ setModalVisible: setVisible, setModalContent, setModalHTML: setHTMLContent });
updateModalCallbacks({ setVisible, setContent: setModalContent, setHtml: setHTMLContent, onContentReady });
2022-02-04 23:29:51 +01:00
2022-06-13 13:14:00 +02:00
useEffect(() => {
hljs.highlightAll();
}, [HTMLContent]);
2022-06-12 14:22:15 +02:00
const containerRef = useRef<HTMLDivElement>(null);
2022-01-14 14:27:19 +01:00
2022-01-14 17:17:55 +01:00
if (!visible) return <></>;
2022-01-14 14:27:19 +01:00
2022-06-13 12:54:40 +02:00
const nextPageSelector = (() => {
if (!currentContent || currentContent?.type !== "diary" || currentContent.entries.length === 0) return null;
2022-07-30 17:49:29 +02:00
const prev = <span className={styles.leftSelectSpace}>{currentPage > 0 ? <a className={styles.fakeLink} onClick={() => setModalContent(currentContent, currentPage - 1)}>&lt; {currentPage - 1 > 0 ? currentContent.entries[currentPage - 2].title : "Main page"}</a> : null}</span>;
const next = <span className={styles.rightSelectSpace}>{currentPage < currentContent.entries.length ? <a className={styles.fakeLink} onClick={() => setModalContent(currentContent, currentPage + 1)}>{currentContent.entries[currentPage].title} &gt;</a> : null}</span>;
2022-06-13 12:54:40 +02:00
const select = (
<select onChange={(e) => setModalContent(currentContent, Number.parseInt(e.target.value))} value={currentPage}>
<option key={-1} value={0}>Main page</option>
{currentContent.entries.map((entry, i) => <option key={i} value={i + 1}>{entry.title}</option>)}
</select>
);
2022-06-13 15:41:29 +02:00
return <div className={styles.pageSelector}>{prev}<span style={{visibility: currentPage > 0 ? "visible" : "hidden"}}>&nbsp;&nbsp;|&nbsp;&nbsp;</span>{select}<span style={{visibility: currentPage < currentContent.entries.length ? "visible" : "hidden"}}>&nbsp;&nbsp;|&nbsp;&nbsp;</span>{next}</div>;
2022-06-13 12:54:40 +02:00
})();
2022-02-05 00:11:59 +01:00
return <div className={styles.modal}>
2022-07-30 17:49:29 +02:00
<a onClick={() => setVisible(false)} className={styles.fakeLink}>
2022-02-05 00:31:04 +01:00
<div className={styles.modalClose}><div className={styles.modalCloseAlign}>X</div></div>
</a>
2022-02-05 23:11:56 +01:00
<div className={styles.modalContainer}>
2022-06-13 12:54:40 +02:00
{nextPageSelector}
<div className={`${styles.modalText} asciidoc`} ref={containerRef} dangerouslySetInnerHTML={{ __html: HTMLContent ? HTMLContent : projectEmpty }}>
2022-02-05 23:11:56 +01:00
</div>
2022-06-13 12:54:40 +02:00
{nextPageSelector}
2022-01-14 14:27:19 +01:00
</div>
2022-01-14 17:17:55 +01:00
</div>;
};
2022-01-14 14:27:19 +01:00
export default ProjectModal;