feat: add custom body link component
This commit is contained in:
parent
f22f380b96
commit
47abc44506
8 changed files with 314 additions and 247 deletions
42
package-lock.json
generated
42
package-lock.json
generated
|
|
@ -10,7 +10,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/react-collapsible": "^1.1.7",
|
"@radix-ui/react-collapsible": "^1.1.7",
|
||||||
"@radix-ui/react-dialog": "^1.1.10",
|
"@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-label": "^2.1.7",
|
||||||
"@radix-ui/react-separator": "^1.1.4",
|
"@radix-ui/react-separator": "^1.1.4",
|
||||||
"@radix-ui/react-slot": "^1.2.3",
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
|
|
@ -1300,18 +1300,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@radix-ui/react-hover-card": {
|
"node_modules/@radix-ui/react-hover-card": {
|
||||||
"version": "1.1.14",
|
"version": "1.1.15",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.14.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz",
|
||||||
"integrity": "sha512-CPYZ24Mhirm+g6D8jArmLzjYu4Eyg3TTUHswR26QgzXBHBe64BO/RHOJKzmF/Dxb4y4f9PKyJdwm/O/AhNkb+Q==",
|
"integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/primitive": "1.1.2",
|
"@radix-ui/primitive": "1.1.3",
|
||||||
"@radix-ui/react-compose-refs": "1.1.2",
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
"@radix-ui/react-context": "1.1.2",
|
"@radix-ui/react-context": "1.1.2",
|
||||||
"@radix-ui/react-dismissable-layer": "1.1.10",
|
"@radix-ui/react-dismissable-layer": "1.1.11",
|
||||||
"@radix-ui/react-popper": "1.2.7",
|
"@radix-ui/react-popper": "1.2.8",
|
||||||
"@radix-ui/react-portal": "1.1.9",
|
"@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-primitive": "2.1.3",
|
||||||
"@radix-ui/react-use-controllable-state": "1.2.2"
|
"@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": {
|
"node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-arrow": {
|
||||||
"version": "1.1.7",
|
"version": "1.1.7",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
|
"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": {
|
"node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-dismissable-layer": {
|
||||||
"version": "1.1.10",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz",
|
||||||
"integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==",
|
"integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/primitive": "1.1.2",
|
"@radix-ui/primitive": "1.1.3",
|
||||||
"@radix-ui/react-compose-refs": "1.1.2",
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
"@radix-ui/react-primitive": "2.1.3",
|
"@radix-ui/react-primitive": "2.1.3",
|
||||||
"@radix-ui/react-use-callback-ref": "1.1.1",
|
"@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": {
|
"node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-popper": {
|
||||||
"version": "1.2.7",
|
"version": "1.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
|
||||||
"integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==",
|
"integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/react-dom": "^2.0.0",
|
"@floating-ui/react-dom": "^2.0.0",
|
||||||
|
|
@ -1437,9 +1443,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-presence": {
|
"node_modules/@radix-ui/react-hover-card/node_modules/@radix-ui/react-presence": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
|
||||||
"integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==",
|
"integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/react-compose-refs": "1.1.2",
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@radix-ui/react-collapsible": "^1.1.7",
|
"@radix-ui/react-collapsible": "^1.1.7",
|
||||||
"@radix-ui/react-dialog": "^1.1.10",
|
"@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-label": "^2.1.7",
|
||||||
"@radix-ui/react-separator": "^1.1.4",
|
"@radix-ui/react-separator": "^1.1.4",
|
||||||
"@radix-ui/react-slot": "^1.2.3",
|
"@radix-ui/react-slot": "^1.2.3",
|
||||||
|
|
|
||||||
|
|
@ -23,3 +23,12 @@ button[data-state="active"] {
|
||||||
box-shadow:
|
box-shadow:
|
||||||
var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-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; */
|
||||||
|
/* } */
|
||||||
|
|
|
||||||
50
src/components/BodyLink.tsx
Normal file
50
src/components/BodyLink.tsx
Normal file
|
|
@ -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 (
|
||||||
|
<a
|
||||||
|
className="text-foreground underline-offset-4 underline hover:text-gray-700 dark:hover:text-green-300"
|
||||||
|
href={`/entries/${path}`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
} else
|
||||||
|
return (
|
||||||
|
<a className="text-red-500 line-through" href={`/entries/${path}`}>
|
||||||
|
{children}
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -5,6 +5,7 @@ import remarkMath from "remark-math"
|
||||||
import rehypeKatex from "rehype-katex"
|
import rehypeKatex from "rehype-katex"
|
||||||
import "katex/dist/katex.min.css"
|
import "katex/dist/katex.min.css"
|
||||||
import { Skeleton } from "@/components/ui/skeleton"
|
import { Skeleton } from "@/components/ui/skeleton"
|
||||||
|
import BodyLink from "./BodyLink"
|
||||||
|
|
||||||
const EntryLoadingSkeleton = () => {
|
const EntryLoadingSkeleton = () => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -59,11 +60,6 @@ export default function EntryBody({ body, isLoading }) {
|
||||||
ol: ({ children }) => (
|
ol: ({ children }) => (
|
||||||
<ol className="list-decimal ml-10 mb-4 space-y-1">{children}</ol>
|
<ol className="list-decimal ml-10 mb-4 space-y-1">{children}</ol>
|
||||||
),
|
),
|
||||||
a: ({ href, children }) => (
|
|
||||||
<a href={href} target="_blank" rel="noopener noreferrer">
|
|
||||||
{children}
|
|
||||||
</a>
|
|
||||||
),
|
|
||||||
table: ({ children }) => (
|
table: ({ children }) => (
|
||||||
<table className="w-full mb-4 text-sm">{children}</table>
|
<table className="w-full mb-4 text-sm">{children}</table>
|
||||||
),
|
),
|
||||||
|
|
@ -94,7 +90,10 @@ export default function EntryBody({ body, isLoading }) {
|
||||||
{children}
|
{children}
|
||||||
</code>
|
</code>
|
||||||
),
|
),
|
||||||
img: ({ children, src }) => <ImagePreprocessor src={src} />,
|
img: ({ src }) => <ImagePreprocessor src={src} />,
|
||||||
|
a: ({ href, children }) => {
|
||||||
|
return <BodyLink link={href} children={children} />
|
||||||
|
},
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{body}
|
{body}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,6 @@ export default function EntryReferences({ entryTitle }) {
|
||||||
queryFn: () => api.get(`/entries/outlinks/${entryTitle}`).then((res) => res.data),
|
queryFn: () => api.get(`/entries/outlinks/${entryTitle}`).then((res) => res.data),
|
||||||
})
|
})
|
||||||
|
|
||||||
console.log(backlinks)
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full flex flex-row justify-between gap-3">
|
<div className="w-full flex flex-row justify-between gap-3">
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
@import "tailwindcss";
|
@import "tailwindcss";
|
||||||
@import "tw-animate-css";
|
@import "tw-animate-css";
|
||||||
|
|
||||||
|
html {
|
||||||
|
overflow-y: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
@custom-variant dark (&:is(.dark *));
|
@custom-variant dark (&:is(.dark *));
|
||||||
|
|
||||||
@theme inline {
|
@theme inline {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue