diff --git a/components/ProjectModal.tsx b/components/ProjectModal.tsx index 4e87226..981696f 100644 --- a/components/ProjectModal.tsx +++ b/components/ProjectModal.tsx @@ -1,11 +1,13 @@ import type { NextPage } from "next"; -import { useEffect, useRef, useState } from "react"; +import { useEffect, useRef, useState, isValidElement } from "react"; import { useRouter } from "next/router"; import styles from "../styles/ProjectModal.module.css"; import type { Project, Diary } from "../lib/content/types"; import { useCommands } from "./contexts/CommandInterface"; import { generateContent, projectEmpty } from "../lib/content/generate"; import { useModalFunctions } from "./contexts/ModalFunctions"; +import Spinner from "./Spinner"; +import { renderToStaticMarkup } from "react-dom/server"; // Code Highlighting import hljs from "highlight.js"; @@ -17,25 +19,45 @@ hljs.registerLanguage("console", bash); hljs.registerLanguage("shell", bash); const ProjectModal: NextPage = () => { - const [visible, setVisible] = useState(false); - const [currentContent, setCurrentContent] = useState(undefined); + const [visible, _setVisible] = useState(false); + const [currentContent, _setCurrentContent] = useState(undefined); const [currentPage, setCurrentPage] = useState(0); - const [HTMLContent, setHTMLContent] = useState(projectEmpty); + const [HTMLContent, _setHTMLContent] = useState(projectEmpty); const router = useRouter(); const { updateCallbacks: updateCmdCallbacks, cmdContext } = useCommands(); const { updateCallbacks: updateModalCallbacks } = useModalFunctions(); + 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; + } + } + }; + const setModalContent = async (content: Project | Diary, selectedPage?: number) => { - setCurrentContent(content); + _setCurrentContent(content); router.replace("#", `#/${content.type}/${content.name}${content.type === "diary" && selectedPage ? `/${selectedPage}`: ""}`, {shallow: true}); if (content.type === "diary") setCurrentPage(selectedPage === undefined ? 0 : selectedPage); + setHTMLContent(); setHTMLContent(await generateContent(content, selectedPage)); }; - const setModalVisible = async (visible: boolean) => { + const setVisible = async (visible: boolean) => { if (!visible) router.replace("#", undefined, {shallow: true}); - setVisible(visible); + _setVisible(visible); }; const onContentReady = () => { @@ -43,8 +65,8 @@ const ProjectModal: NextPage = () => { if (selected[2]) cmdContext.executeCommand(`project ${selected[2]}`); }; - updateCmdCallbacks({ setModalVisible, setModalContent, setModalHTML: setHTMLContent }); - updateModalCallbacks({ setVisible: setModalVisible, setContent: setModalContent, setHtml: setHTMLContent, onContentReady }); + updateCmdCallbacks({ setModalVisible: setVisible, setModalContent, setModalHTML: setHTMLContent }); + updateModalCallbacks({ setVisible, setContent: setModalContent, setHtml: setHTMLContent, onContentReady }); useEffect(() => { hljs.highlightAll(); @@ -71,7 +93,7 @@ const ProjectModal: NextPage = () => { })(); return
- setModalVisible(false)} className={"fake-link"}> + setVisible(false)} className={"fake-link"}>
X
diff --git a/components/Spinner.tsx b/components/Spinner.tsx new file mode 100644 index 0000000..e223e1c --- /dev/null +++ b/components/Spinner.tsx @@ -0,0 +1,19 @@ +import type { NextPage } from "next"; +import styles from "../styles/Spinner.module.scss"; + +const Spinner: NextPage<{size: number}> = ({ size }) => { + const diameterY = 300; + const padding = 25; + + const rad = (angle: number) => angle * (Math.PI / 180); + const side = (diameterY / 2) / Math.sin(rad(60)); + const x0 = side * Math.sin(rad(30)); + const vbSizeX = (2 * x0) + side + (2 * padding); + const vbSizeY = diameterY + (2 * padding); + + return
+ +
; +}; + +export default Spinner; \ No newline at end of file diff --git a/components/contexts/CommandInterface.tsx b/components/contexts/CommandInterface.tsx index b0220b5..0a1ee63 100644 --- a/components/contexts/CommandInterface.tsx +++ b/components/contexts/CommandInterface.tsx @@ -6,7 +6,7 @@ import type { Diary, Project, ContentList } from "../../lib/content/types"; interface CommandInterfaceCallbacks { setModalVisible?: (visible: boolean) => void; setModalContent?: (content: Project | Diary, selectedPage?: number) => void; - setModalHTML?: (html: string) => void; + setModalHTML?: (html: any) => void; } const commandInterface = new CommandInterface(); diff --git a/components/contexts/ModalFunctions.tsx b/components/contexts/ModalFunctions.tsx index 0698cd3..bddcbb0 100644 --- a/components/contexts/ModalFunctions.tsx +++ b/components/contexts/ModalFunctions.tsx @@ -5,7 +5,7 @@ import type { Project, Diary } from "../../lib/content/types"; interface ModalFunctions { setVisible?: CallableFunction; setContent?: (content: Project| Diary) => void; - setHtml?: (html: string) => void; + setHtml?: (html: any) => void; onContentReady?: () => void; } diff --git a/package-lock.json b/package-lock.json index b78795f..9b0b343 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,6 +20,7 @@ "@types/color": "^3.0.3", "@types/node": "16.11.11", "@types/react": "17.0.37", + "@types/react-dom": "^18.0.5", "eslint": "7.32.0", "eslint-config-next": "12.0.4", "sass": "^1.49.7", @@ -520,6 +521,15 @@ "csstype": "^3.0.2" } }, + "node_modules/@types/react-dom": { + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.5.tgz", + "integrity": "sha512-OWPWTUrY/NIrjsAPkAk1wW9LZeIjSvkXRhclsFO8CZcZGCOg2G0YZy4ft+rOyYxy8B7ui5iZzi9OkDebZ7/QSA==", + "dev": true, + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", @@ -3948,6 +3958,15 @@ "csstype": "^3.0.2" } }, + "@types/react-dom": { + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.0.5.tgz", + "integrity": "sha512-OWPWTUrY/NIrjsAPkAk1wW9LZeIjSvkXRhclsFO8CZcZGCOg2G0YZy4ft+rOyYxy8B7ui5iZzi9OkDebZ7/QSA==", + "dev": true, + "requires": { + "@types/react": "*" + } + }, "@types/scheduler": { "version": "0.16.2", "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", diff --git a/package.json b/package.json index cddc185..d1e9634 100644 --- a/package.json +++ b/package.json @@ -22,6 +22,7 @@ "@types/color": "^3.0.3", "@types/node": "16.11.11", "@types/react": "17.0.37", + "@types/react-dom": "^18.0.5", "eslint": "7.32.0", "eslint-config-next": "12.0.4", "sass": "^1.49.7", diff --git a/styles/Spinner.module.scss b/styles/Spinner.module.scss new file mode 100644 index 0000000..aa86132 --- /dev/null +++ b/styles/Spinner.module.scss @@ -0,0 +1,28 @@ +.spinnerPath { + stroke: var(--repl-color); + stroke-width: 25; + fill: none; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 8.33%, 16.67% { transform: rotate(60deg); } + 25%, 33.33% { transform: rotate(120deg); } + 41.67%, 50% { transform: rotate(180deg); } + 58.33%, 66.67% { transform: rotate(240deg); } + 75%, 83.33% { transform: rotate(300deg); } + 91.67%, 100% { transform: rotate(360deg); } +} + +.spinnerContainer { + margin: 0 auto; + animation: spin 7s linear infinite; + position: relative; +} + +.spinner { + margin: 0 auto; + position: absolute; + top: 50%; + transform: translateY(-50%); +} \ No newline at end of file