chemical_docs/components/CodeBlock.tsx
2025-06-13 18:13:43 +02:00

60 lines
2.3 KiB
TypeScript

import React from 'react';
// Basic syntax highlighting for keywords, strings, numbers, comments
const highlightLua = (code: string): React.ReactNode => {
const keywords = ['local', 'function', 'return', 'if', 'then', 'else', 'end', 'for', 'in', 'do', 'while', 'break', 'true', 'false', 'nil'];
// Regex for matching keywords in a part
const keywordRegex = new RegExp(`^\\b(${keywords.join('|')})\\b$`);
// Construct the main splitting regex pattern as a string
// Ensure backslashes and special characters are correctly escaped for the RegExp constructor
const keywordsPatternForSplit = keywords.join('|');
// Changed \\/ to / in the character class for punctuation
const splitPatternString = `(--\\[\\[.*?\\]\\]--|--.*?$|"[^"]*"|'[^']*'|\\b\\d+(\\.\\d+)?\\b|\\b(?:${keywordsPatternForSplit})\\b|[(){}[\\]\\.,:;=+\\-*\/%^#~<>&|@!])`;
const splitRegex = new RegExp(splitPatternString, 'gm');
const parts = code.split(splitRegex);
return parts.map((part, index) => {
if (!part) return null; // split can produce empty strings or undefined for some cases
if (keywordRegex.test(part)) {
return <span key={index} className="token keyword">{part}</span>;
}
if ((part.startsWith('"') && part.endsWith('"')) || (part.startsWith("'") && part.endsWith("'"))) {
return <span key={index} className="token string">{part}</span>;
}
if (part.match(/^\b\d+(\.\d+)?\b/)) {
return <span key={index} className="token number">{part}</span>;
}
if (part.startsWith('--')) {
return <span key={index} className="token comment">{part}</span>;
}
// Check for punctuation using a set for clarity
const punctuationChars = new Set(['{', '}', '(', ')', '[', ']', '.', ',', ':', ';', '=', '+', '-', '*', '/', '%', '^', '#', '~', '<', '>', '&', '|', '@', '!']);
if (punctuationChars.has(part)) {
return <span key={index} className="token punctuation">{part}</span>;
}
return part;
});
};
interface CodeBlockProps {
code: string;
language: string; // e.g., 'lua', 'typescript'
}
export const CodeBlock: React.FC<CodeBlockProps> = ({ code, language }) => {
const highlightedCode = language === 'lua' ? highlightLua(code.trim()) : code.trim();
return (
<pre className={`language-${language} text-sm rounded-md shadow-md`}>
<code>
{highlightedCode}
</code>
</pre>
);
};