diff options
| author | kamtschatka <sschatka@gmail.com> | 2024-06-09 15:30:56 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2024-06-09 14:30:56 +0100 |
| commit | be1bb388924f4422058099dcb0debdd1c857d36a (patch) | |
| tree | bd518e1df0a137f88950b4f7f083da90e8e29cbb | |
| parent | f7a77533240ec435c8a7b103b6f6be409bf995d8 (diff) | |
| download | karakeep-be1bb388924f4422058099dcb0debdd1c857d36a.tar.zst | |
feature(web): Add syntax highlighting to code blocks and a quick copy button. Fixes #195 (#197)
* Any plans to support copy to clipboard (markdown code) for notes? #195
added a button to copy the markdown and added code highlighting
* Any plans to support copy to clipboard (markdown code) for notes? #195
Changed the copy-button to a generic one
added a safeguard and a message to the copy button if copying is not possible
* Some code cleanups
---------
Co-authored-by: kamtschatka <simon.schatka@gmx.at>
Co-authored-by: MohamedBassem <me@mbassem.com>
| -rw-r--r-- | apps/web/components/dashboard/bookmarks/TextCard.tsx | 8 | ||||
| -rw-r--r-- | apps/web/components/dashboard/preview/TextContentSection.tsx | 6 | ||||
| -rw-r--r-- | apps/web/components/dashboard/settings/AddApiKey.tsx | 22 | ||||
| -rw-r--r-- | apps/web/components/ui/copy-button.tsx | 37 | ||||
| -rw-r--r-- | apps/web/components/ui/markdown-component.tsx | 58 | ||||
| -rw-r--r-- | apps/web/package.json | 2 | ||||
| -rw-r--r-- | pnpm-lock.yaml | 173 |
7 files changed, 280 insertions, 26 deletions
diff --git a/apps/web/components/dashboard/bookmarks/TextCard.tsx b/apps/web/components/dashboard/bookmarks/TextCard.tsx index 74b3e8e5..b18efc3d 100644 --- a/apps/web/components/dashboard/bookmarks/TextCard.tsx +++ b/apps/web/components/dashboard/bookmarks/TextCard.tsx @@ -1,10 +1,10 @@ "use client"; import { useState } from "react"; +import { MarkdownComponent } from "@/components/ui/markdown-component"; import { api } from "@/lib/trpc"; import { bookmarkLayoutSwitch } from "@/lib/userLocalSettings/bookmarksLayout"; import { cn } from "@/lib/utils"; -import Markdown from "react-markdown"; import type { ZBookmark } from "@hoarder/shared/types/bookmarks"; import { isBookmarkStillTagging } from "@hoarder/shared-react/utils/bookmarkUtils"; @@ -52,11 +52,7 @@ export default function TextCard({ /> <BookmarkLayoutAdaptingCard title={bookmark.title} - content={ - <Markdown className="prose dark:prose-invert"> - {bookmarkedText.text} - </Markdown> - } + content={<MarkdownComponent>{bookmarkedText.text}</MarkdownComponent>} footer={null} wrapTags={true} bookmark={bookmark} diff --git a/apps/web/components/dashboard/preview/TextContentSection.tsx b/apps/web/components/dashboard/preview/TextContentSection.tsx index eba7d28b..2df1e964 100644 --- a/apps/web/components/dashboard/preview/TextContentSection.tsx +++ b/apps/web/components/dashboard/preview/TextContentSection.tsx @@ -1,5 +1,5 @@ +import { MarkdownComponent } from "@/components/ui/markdown-component"; import { ScrollArea } from "@radix-ui/react-scroll-area"; -import Markdown from "react-markdown"; import type { ZBookmark } from "@hoarder/shared/types/bookmarks"; @@ -9,9 +9,7 @@ export function TextContentSection({ bookmark }: { bookmark: ZBookmark }) { } return ( <ScrollArea className="h-full"> - <Markdown className="prose mx-auto dark:prose-invert"> - {bookmark.content.text} - </Markdown> + <MarkdownComponent>{bookmark.content.text}</MarkdownComponent> </ScrollArea> ); } diff --git a/apps/web/components/dashboard/settings/AddApiKey.tsx b/apps/web/components/dashboard/settings/AddApiKey.tsx index 15a78d56..34fd2df7 100644 --- a/apps/web/components/dashboard/settings/AddApiKey.tsx +++ b/apps/web/components/dashboard/settings/AddApiKey.tsx @@ -5,6 +5,7 @@ import { useState } from "react"; import { useRouter } from "next/navigation"; import { ActionButton } from "@/components/ui/action-button"; import { Button } from "@/components/ui/button"; +import CopyBtn from "@/components/ui/copy-button"; import { Dialog, DialogClose, @@ -28,19 +29,10 @@ import { Input } from "@/components/ui/input"; import { toast } from "@/components/ui/use-toast"; import { api } from "@/lib/trpc"; import { zodResolver } from "@hookform/resolvers/zod"; -import { Check, Copy } from "lucide-react"; import { useForm } from "react-hook-form"; import { z } from "zod"; function ApiKeySuccess({ apiKey }: { apiKey: string }) { - const [isCopied, setCopied] = useState(false); - - const onCopy = () => { - navigator.clipboard.writeText(apiKey); - setCopied(true); - setTimeout(() => setCopied(false), 2000); - }; - return ( <div> <div className="py-4"> @@ -49,13 +41,11 @@ function ApiKeySuccess({ apiKey }: { apiKey: string }) { </div> <div className="flex space-x-2 pt-2"> <Input value={apiKey} readOnly /> - <Button onClick={onCopy}> - {!isCopied ? ( - <Copy className="size-4" /> - ) : ( - <Check className="size-4" /> - )} - </Button> + <CopyBtn + getStringToCopy={() => { + return apiKey; + }} + /> </div> </div> ); diff --git a/apps/web/components/ui/copy-button.tsx b/apps/web/components/ui/copy-button.tsx new file mode 100644 index 00000000..a51ce902 --- /dev/null +++ b/apps/web/components/ui/copy-button.tsx @@ -0,0 +1,37 @@ +import React, { useEffect } from "react";
+import { Check, Copy } from "lucide-react";
+
+export default function CopyBtn({
+ className,
+ getStringToCopy,
+}: {
+ className?: string;
+ getStringToCopy: () => string;
+}) {
+ const [copyOk, setCopyOk] = React.useState(false);
+ const [disabled, setDisabled] = React.useState(false);
+ useEffect(() => {
+ if (!navigator || !navigator.clipboard) {
+ setDisabled(true);
+ }
+ });
+
+ const handleClick = async () => {
+ await navigator.clipboard.writeText(getStringToCopy());
+ setCopyOk(true);
+ setTimeout(() => {
+ setCopyOk(false);
+ }, 2000);
+ };
+
+ return (
+ <button
+ className={className}
+ onClick={handleClick}
+ disabled={disabled}
+ title={disabled ? "Copying is only available over https" : undefined}
+ >
+ {copyOk ? <Check /> : <Copy />}
+ </button>
+ );
+}
diff --git a/apps/web/components/ui/markdown-component.tsx b/apps/web/components/ui/markdown-component.tsx new file mode 100644 index 00000000..f92cb3a3 --- /dev/null +++ b/apps/web/components/ui/markdown-component.tsx @@ -0,0 +1,58 @@ +import React from "react";
+import CopyBtn from "@/components/ui/copy-button";
+import { cn } from "@/lib/utils";
+import Markdown from "react-markdown";
+import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
+import { dracula } from "react-syntax-highlighter/dist/cjs/styles/prism";
+
+function PreWithCopyBtn({ className, ...props }: React.ComponentProps<"pre">) {
+ const ref = React.useRef<HTMLPreElement>(null);
+ return (
+ <span className="group relative">
+ <CopyBtn
+ className="absolute right-1 top-1 m-1 hidden text-white group-hover:block"
+ getStringToCopy={() => {
+ return ref.current?.textContent ?? "";
+ }}
+ />
+ <pre ref={ref} className={cn(className, "")} {...props} />
+ </span>
+ );
+}
+
+export function MarkdownComponent({
+ children: markdown,
+}: {
+ children: string;
+}) {
+ return (
+ <Markdown
+ className="prose dark:prose-invert"
+ components={{
+ pre({ ...props }) {
+ return <PreWithCopyBtn {...props} />;
+ },
+ code({ className, children, ...props }) {
+ const match = /language-(\w+)/.exec(className ?? "");
+ return match ? (
+ // @ts-expect-error -- Refs are not compatible for some reason
+ <SyntaxHighlighter
+ PreTag="div"
+ language={match[1]}
+ {...props}
+ style={dracula}
+ >
+ {String(children).replace(/\n$/, "")}
+ </SyntaxHighlighter>
+ ) : (
+ <code className={className} {...props}>
+ {children}
+ </code>
+ );
+ },
+ }}
+ >
+ {markdown}
+ </Markdown>
+ );
+}
diff --git a/apps/web/package.json b/apps/web/package.json index ebec0278..91743602 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -62,6 +62,7 @@ "react-markdown": "^9.0.1", "react-masonry-css": "^1.0.16", "react-select": "^5.8.0", + "react-syntax-highlighter": "^15.5.0", "sharp": "^0.33.3", "superjson": "^2.2.1", "tailwind-merge": "^2.2.1", @@ -76,6 +77,7 @@ "@types/emoji-mart": "^3.0.14", "@types/react": "^18.2.55", "@types/react-dom": "^18.2.19", + "@types/react-syntax-highlighter": "^15.5.13", "autoprefixer": "^10.4.17", "postcss": "^8.4.35", "tailwindcss": "^3.4.1", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6bea8ddb..eac8aee8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -577,6 +577,9 @@ importers: react-select: specifier: ^5.8.0 version: 5.8.0(@types/react@18.2.58)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) + react-syntax-highlighter: + specifier: ^15.5.0 + version: 15.5.0(react@18.2.0) sharp: specifier: ^0.33.3 version: 0.33.3 @@ -614,6 +617,9 @@ importers: '@types/react-dom': specifier: ^18.2.19 version: 18.2.19 + '@types/react-syntax-highlighter': + specifier: ^15.5.13 + version: 15.5.13 autoprefixer: specifier: ^10.4.17 version: 10.4.17(postcss@8.4.35) @@ -4178,6 +4184,9 @@ packages: '@types/har-format@1.2.15': resolution: {integrity: sha512-RpQH4rXLuvTXKR0zqHq3go0RVXYv/YVqv4TnPH95VbwUxZdQlK1EtcMvQvMpDngHbt13Csh9Z4qT9AbkiQH5BA==} + '@types/hast@2.3.10': + resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} @@ -4280,6 +4289,9 @@ packages: '@types/react-router@5.1.20': resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==} + '@types/react-syntax-highlighter@15.5.13': + resolution: {integrity: sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==} + '@types/react-transition-group@4.4.10': resolution: {integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==} @@ -5195,12 +5207,21 @@ packages: character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + character-entities-legacy@1.1.4: + resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} + character-entities-legacy@3.0.0: resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + character-entities@1.2.4: + resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} + character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + character-reference-invalid@1.1.4: + resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} + character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} @@ -5402,6 +5423,9 @@ packages: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + comma-separated-tokens@1.0.8: + resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==} + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} @@ -6750,6 +6774,9 @@ packages: fastq@1.17.1: resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} + fault@1.0.4: + resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==} + fault@2.0.1: resolution: {integrity: sha512-WtySTkS4OKev5JtpHXnib4Gxiurzh5NCGvWrFaZ34m6JehfTUhKZvn9njTfw48t6JumVQOmrKqpmGcdwxnhqBQ==} @@ -7247,6 +7274,9 @@ packages: hast-util-from-parse5@8.0.1: resolution: {integrity: sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==} + hast-util-parse-selector@2.2.5: + resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==} + hast-util-parse-selector@4.0.0: resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} @@ -7265,6 +7295,9 @@ packages: hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + hastscript@6.0.0: + resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==} + hastscript@8.0.0: resolution: {integrity: sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==} @@ -7291,6 +7324,9 @@ packages: resolution: {integrity: sha512-cnN7bQUm65UWOy6cbGcCcZ3rpwW8Q/j4OP5aWRhEry4Z2t2aR1cjrbp0BS+KiBN0smvP1caBgAuxutvyvJILzQ==} engines: {node: '>=8'} + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + history@4.10.1: resolution: {integrity: sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew==} @@ -7567,9 +7603,15 @@ packages: resolution: {integrity: sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q==} engines: {node: '>=8'} + is-alphabetical@1.0.4: + resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} + is-alphabetical@2.0.1: resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + is-alphanumerical@1.0.4: + resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} + is-alphanumerical@2.0.1: resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} @@ -7620,6 +7662,9 @@ packages: resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} engines: {node: '>= 0.4'} + is-decimal@1.0.4: + resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} + is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} @@ -7667,6 +7712,9 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-hexadecimal@1.0.4: + resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} + is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} @@ -8342,6 +8390,9 @@ packages: resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + lowlight@1.20.0: + resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} + lru-cache@10.2.0: resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} engines: {node: 14 || >=16.14} @@ -9384,6 +9435,9 @@ packages: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} + parse-entities@2.0.0: + resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} + parse-entities@4.0.1: resolution: {integrity: sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==} @@ -9960,6 +10014,10 @@ packages: peerDependencies: react: '>=16.0.0' + prismjs@1.27.0: + resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==} + engines: {node: '>=6'} + prismjs@1.29.0: resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} engines: {node: '>=6'} @@ -10000,6 +10058,9 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + property-information@5.6.0: + resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==} + property-information@6.4.1: resolution: {integrity: sha512-OHYtXfu5aI2sS2LWFSN5rgJjrQ4pCy8i1jubJLe2QvMF8JJ++HXTUIVWFLfXJoaOfvYYjk2SN8J2wFUWIGXT4w==} @@ -10421,6 +10482,11 @@ packages: '@types/react': optional: true + react-syntax-highlighter@15.5.0: + resolution: {integrity: sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==} + peerDependencies: + react: '>= 0.14.0' + react-transition-group@4.4.5: resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==} peerDependencies: @@ -10475,6 +10541,9 @@ packages: resolution: {integrity: sha512-62wgfC8dJWrmxv44CA36pLDnP6KKl3Vhxb7PL+8+qrrFMMoJij4vgiMP8zV4O8+CBMXY1mHxI5fITGHXFHVmQQ==} engines: {node: '>= 0.4'} + refractor@3.6.0: + resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} + regenerate-unicode-properties@10.1.1: resolution: {integrity: sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==} engines: {node: '>=4'} @@ -10989,6 +11058,9 @@ packages: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} deprecated: Please use @jridgewell/sourcemap-codec instead + space-separated-tokens@1.1.5: + resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==} + space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -18066,6 +18138,11 @@ snapshots: '@types/har-format@1.2.15': {} + '@types/hast@2.3.10': + dependencies: + '@types/unist': 2.0.10 + dev: false + '@types/hast@3.0.4': dependencies: '@types/unist': 3.0.2 @@ -18193,6 +18270,11 @@ snapshots: '@types/history': 4.7.11 '@types/react': 18.2.58 + '@types/react-syntax-highlighter@15.5.13': + dependencies: + '@types/react': 18.2.58 + dev: true + '@types/react-transition-group@4.4.10': dependencies: '@types/react': 18.2.58 @@ -19570,10 +19652,19 @@ snapshots: character-entities-html4@2.1.0: {} + character-entities-legacy@1.1.4: + dev: false + character-entities-legacy@3.0.0: {} + character-entities@1.2.4: + dev: false + character-entities@2.0.2: {} + character-reference-invalid@1.1.4: + dev: false + character-reference-invalid@2.0.1: {} charenc@0.0.2: @@ -19844,6 +19935,9 @@ snapshots: delayed-stream: 1.0.0 dev: false + comma-separated-tokens@1.0.8: + dev: false + comma-separated-tokens@2.0.3: {} command-exists@1.2.9: @@ -21709,6 +21803,11 @@ snapshots: dependencies: reusify: 1.0.4 + fault@1.0.4: + dependencies: + format: 0.2.2 + dev: false + fault@2.0.1: dependencies: format: 0.2.2 @@ -22375,6 +22474,9 @@ snapshots: web-namespaces: 2.0.1 dev: false + hast-util-parse-selector@2.2.5: + dev: false + hast-util-parse-selector@4.0.0: dependencies: '@types/hast': 3.0.4 @@ -22453,6 +22555,15 @@ snapshots: dependencies: '@types/hast': 3.0.4 + hastscript@6.0.0: + dependencies: + '@types/hast': 2.3.10 + comma-separated-tokens: 1.0.8 + hast-util-parse-selector: 2.2.5 + property-information: 5.6.0 + space-separated-tokens: 1.1.5 + dev: false + hastscript@8.0.0: dependencies: '@types/hast': 3.0.4 @@ -22489,6 +22600,9 @@ snapshots: source-map: 0.7.4 dev: false + highlight.js@10.7.3: + dev: false + history@4.10.1: dependencies: '@babel/runtime': 7.23.9 @@ -22836,8 +22950,17 @@ snapshots: is-absolute-url@3.0.3: dev: false + is-alphabetical@1.0.4: + dev: false + is-alphabetical@2.0.1: {} + is-alphanumerical@1.0.4: + dependencies: + is-alphabetical: 1.0.4 + is-decimal: 1.0.4 + dev: false + is-alphanumerical@2.0.1: dependencies: is-alphabetical: 2.0.1 @@ -22895,6 +23018,9 @@ snapshots: dependencies: has-tostringtag: 1.0.2 + is-decimal@1.0.4: + dev: false + is-decimal@2.0.1: {} is-directory@0.3.1: @@ -22933,6 +23059,9 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-hexadecimal@1.0.4: + dev: false + is-hexadecimal@2.0.1: {} is-installed-globally@0.4.0: @@ -23715,6 +23844,12 @@ snapshots: lowercase-keys@3.0.0: dev: false + lowlight@1.20.0: + dependencies: + fault: 1.0.4 + highlight.js: 10.7.3 + dev: false + lru-cache@10.2.0: {} lru-cache@5.1.1: @@ -25484,6 +25619,16 @@ snapshots: dependencies: callsites: 3.1.0 + parse-entities@2.0.0: + dependencies: + character-entities: 1.2.4 + character-entities-legacy: 1.1.4 + character-reference-invalid: 1.1.4 + is-alphanumerical: 1.0.4 + is-decimal: 1.0.4 + is-hexadecimal: 1.0.4 + dev: false + parse-entities@4.0.1: dependencies: '@types/unist': 2.0.10 @@ -26064,6 +26209,9 @@ snapshots: react: 18.2.0 dev: false + prismjs@1.27.0: + dev: false + prismjs@1.29.0: dev: false @@ -26107,6 +26255,11 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + property-information@5.6.0: + dependencies: + xtend: 4.0.2 + dev: false + property-information@6.4.1: {} proto-list@1.2.4: @@ -26792,6 +26945,16 @@ snapshots: tslib: 2.6.2 dev: false + react-syntax-highlighter@15.5.0(react@18.2.0): + dependencies: + '@babel/runtime': 7.23.9 + highlight.js: 10.7.3 + lowlight: 1.20.0 + prismjs: 1.29.0 + react: 18.2.0 + refractor: 3.6.0 + dev: false + react-transition-group@4.4.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0): dependencies: '@babel/runtime': 7.23.9 @@ -26874,6 +27037,13 @@ snapshots: globalthis: 1.0.3 which-builtin-type: 1.1.3 + refractor@3.6.0: + dependencies: + hastscript: 6.0.0 + parse-entities: 2.0.0 + prismjs: 1.27.0 + dev: false + regenerate-unicode-properties@10.1.1: dependencies: regenerate: 1.4.2 @@ -27609,6 +27779,9 @@ snapshots: sourcemap-codec@1.4.8: {} + space-separated-tokens@1.1.5: + dev: false + space-separated-tokens@2.0.2: {} spdy-transport@3.0.0: |
