Code highlighting

This commit is contained in:
Weves 2024-05-20 12:20:49 -07:00 committed by Chris Weaver
parent dfd233b985
commit 26ef5b897d
7 changed files with 453 additions and 12 deletions

260
web/package-lock.json generated
View File

@ -19,6 +19,7 @@
"@types/js-cookie": "^3.0.3",
"@types/lodash": "^4.17.0",
"@types/node": "18.15.11",
"@types/prismjs": "^1.26.4",
"@types/react": "18.0.32",
"@types/react-dom": "18.0.11",
"@types/uuid": "^9.0.8",
@ -30,12 +31,14 @@
"next": "^14.2.3",
"npm": "^10.8.0",
"postcss": "^8.4.31",
"prismjs": "^1.29.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-dropzone": "^14.2.3",
"react-icons": "^4.8.0",
"react-loader-spinner": "^5.4.5",
"react-markdown": "^9.0.1",
"rehype-prism-plus": "^2.0.0",
"remark-gfm": "^4.0.0",
"semver": "^7.5.4",
"sharp": "^0.32.6",
@ -1762,6 +1765,11 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz",
"integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q=="
},
"node_modules/@types/prismjs": {
"version": "1.26.4",
"resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.4.tgz",
"integrity": "sha512-rlAnzkW2sZOjbqZ743IHUhFcvzaGbqijwOu8QZnZCjfQzBqFE3s4lOTJEsxikImav9uzz/42I+O7YUs1mWgMlg=="
},
"node_modules/@types/prop-types": {
"version": "15.7.12",
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
@ -3171,6 +3179,17 @@
"node": ">=10.13.0"
}
},
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"engines": {
"node": ">=0.12"
},
"funding": {
"url": "https://github.com/fb55/entities?sponsor=1"
}
},
"node_modules/es-abstract": {
"version": "1.23.3",
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
@ -4320,6 +4339,95 @@
"node": ">= 0.4"
}
},
"node_modules/hast-util-from-html": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/hast-util-from-html/-/hast-util-from-html-2.0.1.tgz",
"integrity": "sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g==",
"dependencies": {
"@types/hast": "^3.0.0",
"devlop": "^1.1.0",
"hast-util-from-parse5": "^8.0.0",
"parse5": "^7.0.0",
"vfile": "^6.0.0",
"vfile-message": "^4.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/hast-util-from-parse5": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-8.0.1.tgz",
"integrity": "sha512-Er/Iixbc7IEa7r/XLtuG52zoqn/b3Xng/w6aZQ0xGVxzhw5xUFxcRqdPzP6yFi/4HBYRaifaI5fQ1RH8n0ZeOQ==",
"dependencies": {
"@types/hast": "^3.0.0",
"@types/unist": "^3.0.0",
"devlop": "^1.0.0",
"hastscript": "^8.0.0",
"property-information": "^6.0.0",
"vfile": "^6.0.0",
"vfile-location": "^5.0.0",
"web-namespaces": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/hast-util-from-parse5/node_modules/hast-util-parse-selector": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-4.0.0.tgz",
"integrity": "sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==",
"dependencies": {
"@types/hast": "^3.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/hast-util-from-parse5/node_modules/hastscript": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-8.0.0.tgz",
"integrity": "sha512-dMOtzCEd3ABUeSIISmrETiKuyydk1w0pa+gE/uormcTpSYuaNJPbX1NU3JLyscSLjwAQM8bWMhhIlnCqnRvDTw==",
"dependencies": {
"@types/hast": "^3.0.0",
"comma-separated-tokens": "^2.0.0",
"hast-util-parse-selector": "^4.0.0",
"property-information": "^6.0.0",
"space-separated-tokens": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/hast-util-parse-selector": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz",
"integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==",
"dependencies": {
"@types/hast": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/hast-util-parse-selector/node_modules/@types/hast": {
"version": "2.3.10",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz",
"integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==",
"dependencies": {
"@types/unist": "^2"
}
},
"node_modules/hast-util-parse-selector/node_modules/@types/unist": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="
},
"node_modules/hast-util-to-jsx-runtime": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz",
@ -4346,6 +4454,18 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/hast-util-to-string": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.0.tgz",
"integrity": "sha512-OGkAxX1Ua3cbcW6EJ5pT/tslVb90uViVkcJ4ZZIMW/R33DX/AkcJcRrPebPwJkHYwlDHXz4aIwvAAaAdtrACFA==",
"dependencies": {
"@types/hast": "^3.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/hast-util-whitespace": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz",
@ -4358,6 +4478,35 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/hastscript": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz",
"integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==",
"dependencies": {
"@types/hast": "^2.0.0",
"comma-separated-tokens": "^2.0.0",
"hast-util-parse-selector": "^3.0.0",
"property-information": "^6.0.0",
"space-separated-tokens": "^2.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/hastscript/node_modules/@types/hast": {
"version": "2.3.10",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz",
"integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==",
"dependencies": {
"@types/unist": "^2"
}
},
"node_modules/hastscript/node_modules/@types/unist": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="
},
"node_modules/hoist-non-react-statics": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
@ -8801,6 +8950,22 @@
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="
},
"node_modules/parse-numeric-range": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz",
"integrity": "sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ=="
},
"node_modules/parse5": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
"integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
"dependencies": {
"entities": "^4.4.0"
},
"funding": {
"url": "https://github.com/inikulin/parse5?sponsor=1"
}
},
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@ -9126,6 +9291,14 @@
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/prismjs": {
"version": "1.29.0",
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
"integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
"engines": {
"node": ">=6"
}
},
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@ -9516,6 +9689,34 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/refractor": {
"version": "4.8.1",
"resolved": "https://registry.npmjs.org/refractor/-/refractor-4.8.1.tgz",
"integrity": "sha512-/fk5sI0iTgFYlmVGYVew90AoYnNMP6pooClx/XKqyeeCQXrL0Kvgn8V0VEht5ccdljbzzF1i3Q213gcntkRExg==",
"dependencies": {
"@types/hast": "^2.0.0",
"@types/prismjs": "^1.0.0",
"hastscript": "^7.0.0",
"parse-entities": "^4.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/refractor/node_modules/@types/hast": {
"version": "2.3.10",
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz",
"integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==",
"dependencies": {
"@types/unist": "^2"
}
},
"node_modules/refractor/node_modules/@types/unist": {
"version": "2.0.10",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="
},
"node_modules/regenerator-runtime": {
"version": "0.14.1",
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
@ -9539,6 +9740,33 @@
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/rehype-parse": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.0.tgz",
"integrity": "sha512-WG7nfvmWWkCR++KEkZevZb/uw41E8TsH4DsY9UxsTbIXCVGbAs4S+r8FrQ+OtH5EEQAs+5UxKC42VinkmpA1Yw==",
"dependencies": {
"@types/hast": "^3.0.0",
"hast-util-from-html": "^2.0.0",
"unified": "^11.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/rehype-prism-plus": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-2.0.0.tgz",
"integrity": "sha512-FeM/9V2N7EvDZVdR2dqhAzlw5YI49m9Tgn7ZrYJeYHIahM6gcXpH0K1y2gNnKanZCydOMluJvX2cB9z3lhY8XQ==",
"dependencies": {
"hast-util-to-string": "^3.0.0",
"parse-numeric-range": "^1.3.0",
"refractor": "^4.8.0",
"rehype-parse": "^9.0.0",
"unist-util-filter": "^5.0.0",
"unist-util-visit": "^5.0.0"
}
},
"node_modules/remark-gfm": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz",
@ -10692,6 +10920,16 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/unist-util-filter": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/unist-util-filter/-/unist-util-filter-5.0.1.tgz",
"integrity": "sha512-pHx7D4Zt6+TsfwylH9+lYhBhzyhEnCXs/lbq/Hstxno5z4gVdyc2WEW0asfjGKPyG4pEKrnBv5hdkO6+aRnQJw==",
"dependencies": {
"@types/unist": "^3.0.0",
"unist-util-is": "^6.0.0",
"unist-util-visit-parents": "^6.0.0"
}
},
"node_modules/unist-util-is": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz",
@ -10886,6 +11124,19 @@
"url": "https://opencollective.com/unified"
}
},
"node_modules/vfile-location": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-5.0.2.tgz",
"integrity": "sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==",
"dependencies": {
"@types/unist": "^3.0.0",
"vfile": "^6.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/vfile-message": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz",
@ -10920,6 +11171,15 @@
"d3-timer": "^3.0.1"
}
},
"node_modules/web-namespaces": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz",
"integrity": "sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -20,6 +20,7 @@
"@types/js-cookie": "^3.0.3",
"@types/lodash": "^4.17.0",
"@types/node": "18.15.11",
"@types/prismjs": "^1.26.4",
"@types/react": "18.0.32",
"@types/react-dom": "18.0.11",
"@types/uuid": "^9.0.8",
@ -31,12 +32,14 @@
"next": "^14.2.3",
"npm": "^10.8.0",
"postcss": "^8.4.31",
"prismjs": "^1.29.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-dropzone": "^14.2.3",
"react-icons": "^4.8.0",
"react-loader-spinner": "^5.4.5",
"react-markdown": "^9.0.1",
"rehype-prism-plus": "^2.0.0",
"remark-gfm": "^4.0.0",
"semver": "^7.5.4",
"sharp": "^0.32.6",

View File

@ -5,7 +5,6 @@ import {
BackendChatSession,
BackendMessage,
ChatFileType,
ChatSession,
ChatSessionSharedStatus,
DocumentsResponse,
FileDescriptor,
@ -16,12 +15,9 @@ import {
ToolRunKickoff,
} from "./interfaces";
import { ChatSidebar } from "./sessionSidebar/ChatSidebar";
import { DocumentSet, Tag, User, ValidSources } from "@/lib/types";
import { Persona } from "../admin/assistants/interfaces";
import { Header } from "@/components/header/Header";
import { HealthCheckBanner } from "@/components/health/healthcheck";
import { InstantSSRAutoRefresh } from "@/components/SSRAutoRefresh";
import { Settings } from "../admin/settings/interfaces";
import {
buildChatUrl,
buildLatestMessageChain,
@ -53,22 +49,16 @@ import { DanswerInitializingLoader } from "@/components/DanswerInitializingLoade
import { FeedbackModal } from "./modal/FeedbackModal";
import { ShareChatSessionModal } from "./modal/ShareChatSessionModal";
import { ChatPersonaSelector } from "./ChatPersonaSelector";
import { HEADER_PADDING } from "@/lib/constants";
import { FiSend, FiShare2, FiStopCircle } from "react-icons/fi";
import { FiShare2 } from "react-icons/fi";
import { ChatIntro } from "./ChatIntro";
import { AIMessage, HumanMessage } from "./message/Messages";
import { ThreeDots } from "react-loader-spinner";
import { StarterMessage } from "./StarterMessage";
import { SelectedDocuments } from "./modifiers/SelectedDocuments";
import { ChatFilters } from "./modifiers/ChatFilters";
import { AnswerPiecePacket, DanswerDocument } from "@/lib/search/interfaces";
import { buildFilters } from "@/lib/search/utils";
import { SettingsContext } from "@/components/settings/SettingsProvider";
import Dropzone from "react-dropzone";
import { LLMProviderDescriptor } from "../admin/models/llm/interfaces";
import { checkLLMSupportsImageInput, getFinalLLM } from "@/lib/llm/utils";
import { InputBarPreviewImage } from "./files/images/InputBarPreviewImage";
import { Folder } from "./folders/interfaces";
import { ChatInputBar } from "./input/ChatInputBar";
import { ConfigurationModal } from "./modal/configuration/ConfigurationModal";
import { useChatContext } from "@/components/context/ChatContext";

View File

@ -0,0 +1,95 @@
import React from "react";
import { useState, ReactNode } from "react";
import { FiCheck, FiCopy } from "react-icons/fi";
interface CodeBlockProps {
className?: string | undefined;
children?: ReactNode;
content: string;
[key: string]: any;
}
export function CodeBlock({
className = "",
children,
content,
...props
}: CodeBlockProps) {
const language = className
.split(" ")
.filter((cls) => cls.startsWith("language-"))
.map((cls) => cls.replace("language-", ""))
.join(" ");
const [copied, setCopied] = useState(false);
if (!language) {
return (
<code {...props} className={`text-sm ${className}`}>
{children}
</code>
);
}
let codeText: string | null = null;
if (
props.node?.position?.start?.offset &&
props.node?.position?.end?.offset
) {
codeText = content.slice(
props.node.position.start.offset,
props.node.position.end.offset
);
// Remove the language declaration and trailing backticks
const codeLines = codeText.split("\n");
if (codeLines.length > 1 && codeLines[0].startsWith("```")) {
codeLines.shift(); // Remove the first line with the language declaration
if (codeLines[codeLines.length - 1] === "```") {
codeLines.pop(); // Remove the last line with the trailing backticks
}
codeText = codeLines.join("\n");
}
}
const handleCopy = () => {
if (!codeText) {
return;
}
navigator.clipboard.writeText(codeText).then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000); // Reset copy status after 2 seconds
});
};
return (
<div className="overflow-x-hidden">
<div className="flex mx-3 py-2 text-xs">
{language}
{codeText && (
<div
className="ml-auto cursor-pointer select-none"
onClick={handleCopy}
>
{copied ? (
<div className="flex items-center space-x-2">
<FiCheck size={16} />
<span>Copied!</span>
</div>
) : (
<div className="flex items-center space-x-2">
<FiCopy size={16} />
<span>Copy code</span>
</div>
)}
</div>
)}
</div>
<pre {...props} className="overflow-x-scroll" style={{ padding: "1rem" }}>
<code className={`text-sm overflow-x-auto ${className}`}>
{children}
</code>
</pre>
</div>
);
}

View File

@ -1,3 +1,5 @@
"use client";
import {
FiCpu,
FiImage,
@ -24,6 +26,14 @@ import { ToolRunningAnimation } from "../tools/ToolRunningAnimation";
import { Hoverable } from "@/components/Hoverable";
import { DocumentPreview } from "../files/documents/DocumentPreview";
import { InMessageImage } from "../files/images/InMessageImage";
import { CodeBlock } from "./CodeBlock";
import rehypePrism from "rehype-prism-plus";
// Prism stuff
import Prism from "prismjs";
import "prismjs/themes/prism-tomorrow.css";
import "./custom-code-styles.css";
function FileDisplay({ files }: { files: FileDescriptor[] }) {
const imageFiles = files.filter((file) => file.type === ChatFileType.IMAGE);
@ -31,7 +41,6 @@ function FileDisplay({ files }: { files: FileDescriptor[] }) {
return (
<>
{" "}
{nonImgFiles && nonImgFiles.length > 0 && (
<div className="mt-2 mb-4">
<div className="flex flex-col gap-2">
@ -94,6 +103,36 @@ export const AIMessage = ({
handleForceSearch?: () => void;
retrievalDisabled?: boolean;
}) => {
const [isReady, setIsReady] = useState(false);
useEffect(() => {
Prism.highlightAll();
setIsReady(true);
}, []);
// this is needed to give Prism a chance to load
if (!isReady) {
return <div />;
}
if (!isComplete) {
const trimIncompleteCodeSection = (
content: string | JSX.Element
): string | JSX.Element => {
if (typeof content === "string") {
const pattern = /```[a-zA-Z]+[^\s]*$/;
const match = content.match(pattern);
if (match && match.index && match.index > 3) {
const newContent = content.slice(0, match.index - 3);
return newContent;
}
return content;
}
return content;
};
content = trimIncompleteCodeSection(content);
}
const loader =
currentTool === IMAGE_GENERATION_TOOL_NAME ? (
<div className="text-sm my-auto">
@ -181,6 +220,7 @@ export const AIMessage = ({
{typeof content === "string" ? (
<ReactMarkdown
key={messageId}
className="prose max-w-full"
components={{
a: ({ node, ...props }) => (
@ -191,8 +231,12 @@ export const AIMessage = ({
rel="noopener noreferrer"
/>
),
code: (props) => (
<CodeBlock {...props} content={content as string} />
),
}}
remarkPlugins={[remarkGfm]}
rehypePlugins={[rehypePrism]}
>
{content}
</ReactMarkdown>

View File

@ -0,0 +1,36 @@
pre[class*="language-"] {
padding: 0px; /* Override padding */
margin: 0px;
border: none;
}
.prose :where(pre):not(:where([class~="not-prose"], [class~="not-prose"] *)) {
padding: 0px; /* Override padding */
margin: 0px;
/* Override scrollbar style to match prism-tomorrow */
::-webkit-scrollbar {
width: 8px; /* Vertical scrollbar width */
height: 8px; /* Horizontal scrollbar height */
}
::-webkit-scrollbar-track {
background: #1f2937; /* Dark track background color */
}
::-webkit-scrollbar-thumb {
background: #4b5563; /* Dark handle color */
border-radius: 10px;
transition:
background 0.3s ease,
box-shadow 0.3s ease; /* Smooth transition for hover effect */
}
::-webkit-scrollbar-thumb:hover {
background: #6b7280; /* Dark handle color on hover */
box-shadow: 0 0 10px #6b7280; /* Light up effect on hover */
}
scrollbar-width: thin;
scrollbar-color: #4b5563 #1f2937; /* thumb and track colors */
}

View File

@ -2,6 +2,19 @@
@tailwind components;
@tailwind utilities;
@layer utilities {
/* Hide scrollbar for Chrome, Safari and Opera */
.no-scrollbar::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
.no-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
}
::-webkit-scrollbar-track {
background: #f9fafb; /* Track background color */
}