diff --git a/package-lock.json b/package-lock.json index a677b0d..1047108 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,7 +10,7 @@ "dependencies": { "@radix-ui/react-collapsible": "^1.1.7", "@radix-ui/react-dialog": "^1.1.10", - "@radix-ui/react-hover-card": "^1.1.14", + "@radix-ui/react-hover-card": "^1.1.15", "@radix-ui/react-label": "^2.1.7", "@radix-ui/react-separator": "^1.1.4", "@radix-ui/react-slot": "^1.2.3", @@ -1300,18 +1300,18 @@ } }, "node_modules/@radix-ui/react-hover-card": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.14.tgz", - "integrity": "sha512-CPYZ24Mhirm+g6D8jArmLzjYu4Eyg3TTUHswR26QgzXBHBe64BO/RHOJKzmF/Dxb4y4f9PKyJdwm/O/AhNkb+Q==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", + "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.2", + "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.10", - "@radix-ui/react-popper": "1.2.7", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.4", + "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2" }, @@ -1330,6 +1330,12 @@ } } }, + "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-arrow": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", @@ -1354,12 +1360,12 @@ } }, "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz", - "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.2", + "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-callback-ref": "1.1.1", @@ -1381,9 +1387,9 @@ } }, "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-popper": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz", - "integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", "license": "MIT", "dependencies": { "@floating-ui/react-dom": "^2.0.0", @@ -1437,9 +1443,9 @@ } }, "node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-presence": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz", - "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", "license": "MIT", "dependencies": { "@radix-ui/react-compose-refs": "1.1.2", diff --git a/package.json b/package.json index d47c13f..5ae01fc 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "dependencies": { "@radix-ui/react-collapsible": "^1.1.7", "@radix-ui/react-dialog": "^1.1.10", - "@radix-ui/react-hover-card": "^1.1.14", + "@radix-ui/react-hover-card": "^1.1.15", "@radix-ui/react-label": "^2.1.7", "@radix-ui/react-separator": "^1.1.4", "@radix-ui/react-slot": "^1.2.3", diff --git a/src/App.css b/src/App.css index d28c371..33a8576 100644 --- a/src/App.css +++ b/src/App.css @@ -1,25 +1,34 @@ @import url("https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap"); code { - font-family: "JetBrains Mono"; + font-family: "JetBrains Mono"; } -pre > code { - padding: 0.5rem; - font-size: 14px; +pre>code { + padding: 0.5rem; + font-size: 14px; } -h2 > code { - font-size: 1rem; +h2>code { + font-size: 1rem; } .btn[data-state="active"] { - box-shadow: none !important; + box-shadow: none !important; } button[data-state="active"] { - --tw-shadow: none; - --tw-shadow-colored: none; - box-shadow: - var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); + --tw-shadow: none; + --tw-shadow-colored: none; + box-shadow: + var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow); } + +/* .HoverCardContent { */ +/* width: 300px; */ +/* max-height: 500px; */ +/* } */ + +/* .HoverCardContent { */ +/* transform-origin: 10px; */ +/* } */ diff --git a/src/components/BodyLink.tsx b/src/components/BodyLink.tsx new file mode 100644 index 0000000..44e4b65 --- /dev/null +++ b/src/components/BodyLink.tsx @@ -0,0 +1,50 @@ +import { useEffect, useState } from "react" +import { useQueryClient } from "@tanstack/react-query" +import api from "@/api/eolas-api" + +export default function BodyLink({ link, children }) { + const [entryExists, setEntryExists] = useState(false) + const path = link.split("/").pop().split(".")[0] + const queryClient = useQueryClient() + + useEffect(() => { + const fetchEntryPreview = async () => { + const cachedEntry = queryClient.getQueryData([`entry_${path}`]) + if (cachedEntry) { + setEntryExists(true) + console.info("INFO: Entry exists in cache.") + } else { + try { + const remoteEntry = await queryClient.fetchQuery({ + queryKey: [`entry_${path}`], + queryFn: () => api.get(`/entries/${path}`).then((res) => res.data), + }) + + setEntryExists(true) + console.info("INFO: Entry exists on remote.") + } catch (error) { + console.log(`INFO: Could not fetch entry ${path} ${error}`) + setEntryExists(false) + } + } + } + + fetchEntryPreview() + }, [path, queryClient]) + + if (entryExists) { + return ( + + {children} + + ) + } else + return ( + + {children} + + ) +} diff --git a/src/components/EntriesListSidebar.tsx b/src/components/EntriesListSidebar.tsx index 7e10e7d..87b0866 100644 --- a/src/components/EntriesListSidebar.tsx +++ b/src/components/EntriesListSidebar.tsx @@ -10,68 +10,68 @@ import { Link } from "react-router" import { useState, useRef, useEffect } from "react" export default function EntriesListSidebar() { - const scrollRef = useRef(null) - const [isOpen, setIsOpen] = useState(() => { - if (typeof window !== "undefined") { - const saved = sessionStorage.getItem("entries_list_sidebar_open") - return saved ? JSON.parse(saved) : false - } - return false - }) + const scrollRef = useRef(null) + const [isOpen, setIsOpen] = useState(() => { + if (typeof window !== "undefined") { + const saved = sessionStorage.getItem("entries_list_sidebar_open") + return saved ? JSON.parse(saved) : false + } + return false + }) - const { data: entries, isLoading } = useQuery({ - queryKey: ["entries_list"], - queryFn: () => api.get("/entries").then((res) => res.data), - }) + const { data: entries, isLoading } = useQuery({ + queryKey: ["entries_list"], + queryFn: () => api.get("/entries").then((res) => res.data), + }) - useEffect(() => { - sessionStorage.setItem("entries_list_sidebar_open", JSON.stringify(isOpen)) - }, [isOpen]) + useEffect(() => { + sessionStorage.setItem("entries_list_sidebar_open", JSON.stringify(isOpen)) + }, [isOpen]) - useEffect(() => { - const savedScroll = sessionStorage.getItem("entries_list_sidebar_scroll_position") - if (savedScroll && scrollRef.current) { - scrollRef.current.scrollTop = parseInt(savedScroll) - } - }, [entries]) + useEffect(() => { + const savedScroll = sessionStorage.getItem("entries_list_sidebar_scroll_position") + if (savedScroll && scrollRef.current) { + scrollRef.current.scrollTop = parseInt(savedScroll) + } + }, [entries]) - const handleScroll = () => { - if (scrollRef.current) { - sessionStorage.setItem("entries_list_sidebar_scroll_position", scrollRef.current.scrollTop) - } - } + const handleScroll = () => { + if (scrollRef.current) { + sessionStorage.setItem("entries_list_sidebar_scroll_position", scrollRef.current.scrollTop) + } + } - return ( - - - - - - - Entries - - {entries?.count} - - - - - - -
- - {entries?.data.map((item, i) => ( - - - - {item.title.replace(/_/g, " ")} - - - - ))} - -
-
-
-
- ) + return ( + + + + + + + Entries + + {entries?.count} + + + + + + +
+ + {entries?.data.map((item, i) => ( + + + + {item.title.replace(/_/g, " ")} + + + + ))} + +
+
+
+
+ ) } diff --git a/src/components/EntryBody.tsx b/src/components/EntryBody.tsx index a6ae639..1a99f64 100644 --- a/src/components/EntryBody.tsx +++ b/src/components/EntryBody.tsx @@ -5,100 +5,99 @@ import remarkMath from "remark-math" import rehypeKatex from "rehype-katex" import "katex/dist/katex.min.css" import { Skeleton } from "@/components/ui/skeleton" +import BodyLink from "./BodyLink" const EntryLoadingSkeleton = () => { - return ( -
- {/* + return ( +
+ {/* */} - - - - - - -
- ) + + + + + + +
+ ) } const ImagePreprocessor = (src) => { - const filename = src.src.split("/").pop() - const s3RootUrl = "https://eolas.s3.systemsobscure.net/" - return + const filename = src.src.split("/").pop() + const s3RootUrl = "https://eolas.s3.systemsobscure.net/" + return } export default function EntryBody({ body, isLoading }) { - if (isLoading) { - return - } else - return ( -
- null, - h2: ({ children }) => ( -

{children}

- ), - h3: ({ children }) => ( -

{children}

- ), - h4: ({ children }) => ( -

{children}

- ), - p: ({ children }) => ( -

{children}

- ), - ul: ({ children }) => ( -
    {children}
- ), - ol: ({ children }) => ( -
    {children}
- ), - a: ({ href, children }) => ( - - {children} - - ), - table: ({ children }) => ( - {children}
- ), - tr: ({ children }) => ( - {children} - ), - th: ({ children }) => ( - - {children} - - ), - td: ({ children }) => ( - - {children} - - ), - blockquote: ({ children }) => ( -
- {children} -
- ), - pre: ({ children }) => { - const child = children.props - return {child.children} - }, - code: ({ children }) => ( - - {children} - - ), - img: ({ children, src }) => , - }} - > - {body} -
-
- ) + if (isLoading) { + return + } else + return ( +
+ null, + h2: ({ children }) => ( +

{children}

+ ), + h3: ({ children }) => ( +

{children}

+ ), + h4: ({ children }) => ( +

{children}

+ ), + p: ({ children }) => ( +

{children}

+ ), + ul: ({ children }) => ( +
    {children}
+ ), + ol: ({ children }) => ( +
    {children}
+ ), + table: ({ children }) => ( + {children}
+ ), + tr: ({ children }) => ( + {children} + ), + th: ({ children }) => ( + + {children} + + ), + td: ({ children }) => ( + + {children} + + ), + blockquote: ({ children }) => ( +
+ {children} +
+ ), + pre: ({ children }) => { + const child = children.props + return {child.children} + }, + code: ({ children }) => ( + + {children} + + ), + img: ({ src }) => , + a: ({ href, children }) => { + return + }, + }} + > + {body} +
+
+ ) } diff --git a/src/components/EntryReferences.tsx b/src/components/EntryReferences.tsx index c47d058..458fd4f 100644 --- a/src/components/EntryReferences.tsx +++ b/src/components/EntryReferences.tsx @@ -4,85 +4,84 @@ import { Link } from "react-router" import { Badge } from "./ui/badge" export default function EntryReferences({ entryTitle }) { - const { data: tags, isLoading: tagsLoading } = useQuery({ - queryKey: [`tags_for_${entryTitle}`], - queryFn: () => api.get(`/tags/${entryTitle}`).then((res) => res.data), - }) + const { data: tags, isLoading: tagsLoading } = useQuery({ + queryKey: [`tags_for_${entryTitle}`], + queryFn: () => api.get(`/tags/${entryTitle}`).then((res) => res.data), + }) - const { data: backlinks, isLoading: backlinksLoading } = useQuery({ - queryKey: [`backlinks_for_${entryTitle}`], - queryFn: () => api.get(`/entries/backlinks/${entryTitle}`).then((res) => res.data), - }) + const { data: backlinks, isLoading: backlinksLoading } = useQuery({ + queryKey: [`backlinks_for_${entryTitle}`], + queryFn: () => api.get(`/entries/backlinks/${entryTitle}`).then((res) => res.data), + }) - const { data: outlinks, isLoading: outlinksLoading } = useQuery({ - queryKey: [`outlinks_for_${entryTitle}`], - queryFn: () => api.get(`/entries/outlinks/${entryTitle}`).then((res) => res.data), - }) + const { data: outlinks, isLoading: outlinksLoading } = useQuery({ + queryKey: [`outlinks_for_${entryTitle}`], + queryFn: () => api.get(`/entries/outlinks/${entryTitle}`).then((res) => res.data), + }) - console.log(backlinks) - return ( -
-
-
-

Tags

- - {tags?.count} - -
-
- {tags?.data.map((item, i) => ( - - {item} - - ))} -
+ return ( +
+
+
+

Tags

+ + {tags?.count} + +
+
+ {tags?.data.map((item, i) => ( + + {item} + + ))} +
-
-

Incoming links

- - {backlinks?.count} - -
+
+

Incoming links

+ + {backlinks?.count} + +
-
- {backlinks && - backlinks?.data.map((item, i) => ( - - {item.replace(/_/g, " ")} - - ))} -
-
+
+ {backlinks && + backlinks?.data.map((item, i) => ( + + {item.replace(/_/g, " ")} + + ))} +
+
-
-
-

Outgoing links

- - {outlinks?.count} - -
+
+
+

Outgoing links

+ + {outlinks?.count} + +
-
- {outlinks && - outlinks?.data.map((item, i) => ( - - {item.replace(/_/g, " ")} - - ))} -
-
-
- ) +
+ {outlinks && + outlinks?.data.map((item, i) => ( + + {item.replace(/_/g, " ")} + + ))} +
+
+
+ ) } diff --git a/src/index.css b/src/index.css index 6618ff7..c71568e 100644 --- a/src/index.css +++ b/src/index.css @@ -1,6 +1,10 @@ @import "tailwindcss"; @import "tw-animate-css"; +html { + overflow-y: hidden; +} + @custom-variant dark (&:is(.dark *)); @theme inline {