Skip to content

Commit 5c40ead

Browse files
authored
Fix: syntax highlighting auto detecting lang (#32)
1 parent 92d93ee commit 5c40ead

File tree

9 files changed

+288
-325
lines changed

9 files changed

+288
-325
lines changed

docker-compose.yml

Lines changed: 0 additions & 11 deletions
This file was deleted.

dockerfile

Lines changed: 0 additions & 20 deletions
This file was deleted.

nginx.conf

Lines changed: 0 additions & 28 deletions
This file was deleted.

package-lock.json

Lines changed: 24 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
"class-variance-authority": "^0.7.1",
2626
"clsx": "^2.1.1",
2727
"date-fns": "^4.1.0",
28+
"highlight.js": "^11.11.1",
2829
"lucide-react": "^0.462.0",
2930
"prismjs": "^1.29.0",
3031
"react": "19.0.0",

src/components/Chat.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ export function Chat() {
2727
<div className="w-[calc(100vw-18rem)]">
2828
<ChatMessageList>
2929
{(chat?.question_answers ?? []).map(({ question, answer }, index) => (
30-
<div key={index} className="flex flex-col w-full h-full p-4 gap-6">
30+
<div key={index} className="flex flex-col w-full h-full gap-6">
3131
<ChatBubble variant="sent">
3232
<ChatBubbleAvatar fallback="User" className="w-14" />
3333
<ChatBubbleMessage variant="sent" className="bg-zinc-700">

src/components/Dashboard.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,15 @@ const wrapObjectOutput = (input: string | MaliciousPkgType | null) => {
6565
const isObject = /\{"/.test(input);
6666
if (isObject) {
6767
return (
68-
<pre className="max-h-40 overflow-y-auto whitespace-pre-wrap bg-gray-100 p-2">
68+
<pre className="max-h-40 overflow-y-auto whitespace-pre-wrap bg-secondary p-2">
6969
<code>{input}</code>
7070
</pre>
7171
);
7272
}
7373
return (
74-
<Markdown className="bg-gray-100 overflow-auto w-fit p-1">{input}</Markdown>
74+
<Markdown className="bg-secondary rounded-lg overflow-auto w-fit p-1">
75+
{input}
76+
</Markdown>
7577
);
7678
};
7779

@@ -119,7 +121,7 @@ export function Dashboard() {
119121
setSearchParams(searchParams);
120122
toggleMaliciousFilter(isChecked);
121123
},
122-
[setSearchParams, setSearch, searchParams, toggleMaliciousFilter]
124+
[setSearchParams, setSearch, searchParams, toggleMaliciousFilter],
123125
);
124126

125127
const handleSearch = useCallback(
@@ -135,7 +137,7 @@ export function Dashboard() {
135137
}
136138
setSearchParams(searchParams);
137139
},
138-
[searchParams, setSearch, setSearchParams, toggleMaliciousFilter]
140+
[searchParams, setSearch, setSearchParams, toggleMaliciousFilter],
139141
);
140142

141143
return (

src/components/Markdown.tsx

Lines changed: 54 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,32 @@ import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
44
import { oneDark } from "react-syntax-highlighter/dist/esm/styles/prism";
55
import { cn } from "@/lib/utils";
66
import { CopyToClipboard } from "./CopyToClipboard";
7+
import hljs from "highlight.js";
8+
9+
const LANGUAGES_SUBSET_DETECTION = [
10+
"c",
11+
"cpp",
12+
"csharp",
13+
"css",
14+
"elixir",
15+
"go",
16+
"groovy",
17+
"haskell",
18+
"html",
19+
"java",
20+
"javascript",
21+
"json",
22+
"kotlin",
23+
"markdown",
24+
"php",
25+
"python",
26+
"ruby",
27+
"rust",
28+
"scala",
29+
"sql",
30+
"typescript",
31+
"yaml",
32+
];
733

834
interface Props {
935
children: string;
@@ -12,85 +38,58 @@ interface Props {
1238

1339
const customStyle = {
1440
...oneDark,
41+
'code[class*="language-"]': {
42+
...oneDark['code[class*="language-"]'],
43+
background: "none",
44+
},
1545
'pre[class*="language-"]': {
1646
...oneDark['pre[class*="language-"]'],
17-
whiteSpace: "pre-wrap",
1847
background: "#1a1b26",
1948
padding: "1.5rem",
2049
borderRadius: "0.5rem",
21-
margin: "1.5rem 0",
22-
fontSize: "10px",
23-
width: "80%", // Ensure the block takes full width
50+
width: "100%",
2451
position: "relative",
52+
boxSizing: "border-box",
2553
},
2654
};
27-
2855
export function Markdown({ children, className = "" }: Props) {
56+
SyntaxHighlighter.supportedLanguages = LANGUAGES_SUBSET_DETECTION;
2957
return (
3058
<ReactMarkdown
3159
components={{
32-
/* eslint-disable @typescript-eslint/no-explicit-any */
33-
code({ className, children, ...props }: any) {
60+
code({ className, children, ...props }) {
61+
const detectedLanguage =
62+
hljs.highlightAuto(children, LANGUAGES_SUBSET_DETECTION).language ??
63+
"plaintext";
3464
const match = /language-(\w+)/.exec(className || "");
35-
const inline = !match;
36-
return !inline ? (
37-
<div className="relative group w-full ml-0 px-4">
65+
const language = match ? match[1] : detectedLanguage;
66+
return (
67+
<div className="relative group w-full ml-0 my-4">
3868
<SyntaxHighlighter
39-
style={{
40-
...customStyle,
41-
'pre[class*="language-"]': {
42-
...oneDark['pre[class*="language-"]'],
43-
background: "#1a1b26",
44-
fontSize: "10x",
45-
whiteSpace: "pre-wrap",
46-
padding: "1.5rem",
47-
borderRadius: "0.5rem",
48-
margin: "1.5rem 0",
49-
position: "relative", // Critical for clipboard positioning
50-
width: "100%", // Ensure full width of parent container
51-
boxSizing: "border-box", // Prevent padding overflow
52-
},
53-
}}
54-
language={match[1]}
69+
style={customStyle}
70+
supportedLanguages={LANGUAGES_SUBSET_DETECTION}
71+
language={language}
5572
PreTag="div"
56-
className="rounded-lg overflow-hidden shadow-lg text-sm"
57-
showLineNumbers={false}
58-
wrapLines={true}
73+
className="rounded-lg overflow-hidden shadow-lg text-sm my-6 whitespace-normal"
74+
wrapLines
5975
{...props}
6076
>
6177
{String(children).replace(/\n$/, "")}
6278
</SyntaxHighlighter>
63-
<CopyToClipboard text={String(children).replace(/\n$/, "")} />
79+
{match && (
80+
<CopyToClipboard text={String(children).replace(/\n$/, "")} />
81+
)}
6482
</div>
65-
) : (
66-
<SyntaxHighlighter
67-
style={{
68-
...customStyle,
69-
'pre[class*="language-"]': {
70-
...oneDark['pre[class*="language-"]'],
71-
fontSize: "10x",
72-
whiteSpace: "pre-wrap",
73-
padding: "1.5rem",
74-
borderRadius: "0.5rem",
75-
margin: "1.5rem 0",
76-
position: "relative", // Critical for clipboard positioning
77-
width: "100%", // Ensure full width of parent container
78-
boxSizing: "border-box", // Prevent padding overflow
79-
},
80-
}}
81-
PreTag="div"
82-
className="rounded-lg overflow-hidden shadow-lg text-sm"
83-
showLineNumbers={false}
84-
wrapLines={true}
85-
{...props}
86-
>
87-
{children}
88-
</SyntaxHighlighter>
8983
);
9084
},
9185
p({ children }) {
9286
return (
93-
<p className={cn("text-gray-600 leading-relaxed mb-4", className)}>
87+
<p
88+
className={cn(
89+
"text-gray-600 leading-relaxed mt-6 mb-3",
90+
className,
91+
)}
92+
>
9493
{children}
9594
</p>
9695
);

0 commit comments

Comments
 (0)