mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-01-04 17:48:50 +01:00
finish highlight.js styling (for chatgpt)
This commit is contained in:
parent
e95e22de15
commit
c58a9bbe93
12 changed files with 851 additions and 150 deletions
|
|
@ -1 +1,71 @@
|
|||
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-formula,.hljs-keyword{color:#c678dd}.hljs-deletion,.hljs-name,.hljs-section,.hljs-selector-tag,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string,.hljs-regexp,.hljs-string{color:#98c379}.hljs-attr,.hljs-number,.hljs-selector-attr,.hljs-selector-class,.hljs-selector-pseudo,.hljs-template-variable,.hljs-type,.hljs-variable{color:#d19a66}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-symbol,.hljs-title{color:#61aeee}.hljs-built_in,.hljs-class .hljs-title,.hljs-title.class_{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}
|
||||
pre code.hljs {
|
||||
display: block;
|
||||
overflow-x: auto;
|
||||
padding: 1em;
|
||||
}
|
||||
code.hljs {
|
||||
padding: 3px 5px;
|
||||
}
|
||||
.hljs {
|
||||
color: #abb2bf;
|
||||
background: #282c34;
|
||||
}
|
||||
.hljs-comment,
|
||||
.hljs-quote {
|
||||
color: #5c6370;
|
||||
font-style: italic;
|
||||
}
|
||||
.hljs-doctag,
|
||||
.hljs-formula,
|
||||
.hljs-keyword {
|
||||
color: #c678dd;
|
||||
}
|
||||
.hljs-deletion,
|
||||
.hljs-name,
|
||||
.hljs-section,
|
||||
.hljs-selector-tag,
|
||||
.hljs-subst {
|
||||
color: #e06c75;
|
||||
}
|
||||
.hljs-literal {
|
||||
color: #56b6c2;
|
||||
}
|
||||
.hljs-addition,
|
||||
.hljs-attribute,
|
||||
.hljs-meta .hljs-string,
|
||||
.hljs-regexp,
|
||||
.hljs-string {
|
||||
color: #98c379;
|
||||
}
|
||||
.hljs-attr,
|
||||
.hljs-number,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-pseudo,
|
||||
.hljs-template-variable,
|
||||
.hljs-type,
|
||||
.hljs-variable {
|
||||
color: #d19a66;
|
||||
}
|
||||
.hljs-bullet,
|
||||
.hljs-link,
|
||||
.hljs-meta,
|
||||
.hljs-selector-id,
|
||||
.hljs-symbol,
|
||||
.hljs-title {
|
||||
color: #61aeee;
|
||||
}
|
||||
.hljs-built_in,
|
||||
.hljs-class .hljs-title,
|
||||
.hljs-title.class_ {
|
||||
color: #e6c07b;
|
||||
}
|
||||
.hljs-emphasis {
|
||||
font-style: italic;
|
||||
}
|
||||
.hljs-strong {
|
||||
font-weight: 700;
|
||||
}
|
||||
.hljs-link {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,55 +0,0 @@
|
|||
import React from 'react';
|
||||
import Embed from './Embed';
|
||||
import hljs from 'highlight.js';
|
||||
import Highlight from 'react-highlight';
|
||||
|
||||
export default function CodeWrapper({ text }) {
|
||||
if (text.includes('```')) {
|
||||
const codeRegex = /(```[^`]+?```)/g;
|
||||
const inLineRegex = /(`[^`]+?`)/g;
|
||||
const parts = text.split(codeRegex);
|
||||
// console.log(parts);
|
||||
const codeParts = parts.map((part, i) => {
|
||||
if (part.match(codeRegex)) {
|
||||
return (
|
||||
<Embed
|
||||
key={i}
|
||||
language="javascript"
|
||||
>
|
||||
{hljs.highlightAuto(part.slice(1, -1)).value}
|
||||
{/* <Highlight className="!whitespace-pre">{part.slice(1, -1)}</Highlight> */}
|
||||
|
||||
</Embed>
|
||||
);
|
||||
} else if (part.match(inLineRegex)) {
|
||||
const innerParts = part.split(inLineRegex);
|
||||
return innerParts.map((part, i) => {
|
||||
if (part.match(inLineRegex)) {
|
||||
return <code key={i}>{part.slice(1, -1)}</code>;
|
||||
} else {
|
||||
return part;
|
||||
}
|
||||
});
|
||||
} else {
|
||||
return part;
|
||||
}
|
||||
});
|
||||
|
||||
return <>{codeParts}</>; // return the wrapped text
|
||||
} else {
|
||||
const matchRegex = /(`[^`]+?`)/g;
|
||||
const parts = text.split(matchRegex);
|
||||
// console.log('parts', parts);
|
||||
|
||||
// map over the parts and wrap any text between tildes with <code> tags
|
||||
const codeParts = parts.map((part, i) => {
|
||||
if (part.match(matchRegex)) {
|
||||
return <code key={i}>{part.slice(1, -1)}</code>;
|
||||
} else {
|
||||
return part;
|
||||
}
|
||||
});
|
||||
|
||||
return <>{codeParts}</>; // return the wrapped text
|
||||
}
|
||||
}
|
||||
|
|
@ -4,8 +4,8 @@ import React from 'react';
|
|||
export default function Embed({ children, language = ''}) {
|
||||
return (
|
||||
<pre>
|
||||
<div className="mb-4 rounded-md bg-black">
|
||||
<div className="relative flex items-center bg-gray-800 px-4 py-2 font-sans text-xs text-gray-200">
|
||||
<div className="mb-2 rounded-md bg-black">
|
||||
<div className="relative flex items-center bg-gray-800 px-4 py-2 font-sans text-xs text-gray-200 rounded-tl-md rounded-tr-md">
|
||||
<span className="">{ language }</span>
|
||||
<button className="ml-auto flex gap-2">
|
||||
<svg
|
||||
|
|
@ -35,26 +35,6 @@ export default function Embed({ children, language = ''}) {
|
|||
</div>
|
||||
<div className="overflow-y-auto p-4">
|
||||
{ children }
|
||||
{/* <span className="hljs-keyword">export</span> <span className="hljs-keyword">default</span> <span className="hljs-keyword">function</span> <span className="hljs-title function_">CodeWrapper</span>(<span className="hljs-params">{ text }</span>) {
|
||||
<span className="hljs-keyword">const</span> matchRegex = <span className="hljs-regexp">/(`[^`]+?`)/g</span>; <span className="hljs-comment">// regex to match backticks and text between them</span>
|
||||
<span className="hljs-keyword">const</span> parts = text.<span className="hljs-title function_">split</span>(matchRegex);
|
||||
<span className="hljs-variable language_">console</span>.<span className="hljs-title function_">log</span>(<span className="hljs-string">'parts'</span>, parts);
|
||||
|
||||
<span className="hljs-comment">// map over the parts and wrap any backticked text with <code> tags</span>
|
||||
<span className="hljs-keyword">const</span> codeParts = parts.<span className="hljs-title function_">map</span>(<span className="hljs-function">(<span className="hljs-params">part, index</span>) =></span> {
|
||||
<span className="hljs-keyword">if</span> (part.<span className="hljs-title function_">match</span>(matchRegex)) {
|
||||
<>
|
||||
<span className="hljs-keyword">return</span> <span className="xml"><span className="hljs-tag"><<span className="hljs-name">code</span> <span className="hljs-attr">key</span>=<span className="hljs-string">{index}</span>></span>{part}<span className="hljs-tag"></<span className="hljs-name">code</span>></span></span>;
|
||||
</>
|
||||
} <span className="hljs-keyword">else</span> {
|
||||
<>
|
||||
<span className="hljs-keyword">return</span> part.<span className="hljs-title function_">trim</span>(); <span className="hljs-comment">// remove leading/trailing whitespace from non-backticked text</span>
|
||||
</>
|
||||
}
|
||||
});
|
||||
|
||||
<span className="hljs-keyword">return</span> <span className="xml"><span className="hljs-tag"><></span>{codeParts}<span className="hljs-tag"></></span></span>; <span className="hljs-comment">// return the wrapped text</span>
|
||||
} */}
|
||||
</div>
|
||||
</div>
|
||||
</pre>
|
||||
|
|
|
|||
16
src/components/Messages/Highlight.jsx
Normal file
16
src/components/Messages/Highlight.jsx
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import hljs from 'highlight.js';
|
||||
|
||||
export default function Highlight({language, code}) {
|
||||
const [highlightedCode, setHighlightedCode] = useState(code);
|
||||
|
||||
useEffect(() => {
|
||||
setHighlightedCode(hljs.highlight(code, { language }).value);
|
||||
}, [code, language]);
|
||||
|
||||
return (
|
||||
<pre>
|
||||
<code className={`language-${language}`} dangerouslySetInnerHTML={{__html: highlightedCode}}/>
|
||||
</pre>
|
||||
);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
import React, { useState, useEffect } from 'react';
|
||||
import CodeWrapper from './CodeWrapper';
|
||||
import TextWrapper from './TextWrapper';
|
||||
import { useSelector } from 'react-redux';
|
||||
import GPTIcon from '../svg/GPTIcon';
|
||||
import BingIcon from '../svg/BingIcon';
|
||||
|
|
@ -13,7 +13,8 @@ export default function Message({
|
|||
}) {
|
||||
const { isSubmitting } = useSelector((state) => state.submit);
|
||||
const [abortScroll, setAbort] = useState(false);
|
||||
const blinker = isSubmitting && last && sender.toLowerCase() !== 'user';
|
||||
const notUser = sender.toLowerCase() !== 'user';
|
||||
const blinker = isSubmitting && last && notUser;
|
||||
|
||||
useEffect(() => {
|
||||
if (blinker && !abortScroll) {
|
||||
|
|
@ -34,15 +35,12 @@ export default function Message({
|
|||
'w-full border-b border-black/10 dark:border-gray-900/50 text-gray-800 dark:text-gray-100 group dark:bg-gray-800'
|
||||
};
|
||||
|
||||
if (sender.toLowerCase() !== 'user') {
|
||||
props.className =
|
||||
'w-full border-b border-black/10 dark:border-gray-900/50 text-gray-800 dark:text-gray-100 group bg-gray-100 dark:bg-[#444654]';
|
||||
}
|
||||
|
||||
let icon = `${sender}:`;
|
||||
const isGPT = sender === 'chatgpt' || sender === 'davinci' || sender === 'GPT';
|
||||
|
||||
if (sender.toLowerCase() !== 'user') {
|
||||
if (notUser) {
|
||||
props.className =
|
||||
'w-full border-b border-black/10 dark:border-gray-900/50 text-gray-800 dark:text-gray-100 group bg-gray-100 dark:bg-[#444654]';
|
||||
icon = (
|
||||
<div
|
||||
style={isGPT ? { backgroundColor: 'rgb(16, 163, 127)' } : {}}
|
||||
|
|
@ -53,7 +51,7 @@ export default function Message({
|
|||
);
|
||||
}
|
||||
|
||||
const wrapText = (text) => <CodeWrapper text={text} />;
|
||||
const wrapText = (text) => <TextWrapper text={text} />;
|
||||
|
||||
return (
|
||||
<div
|
||||
|
|
@ -67,13 +65,13 @@ export default function Message({
|
|||
{error ? (
|
||||
<div className="flex flex min-h-[20px] flex-row flex-col items-start gap-4 gap-2 whitespace-pre-wrap text-red-500">
|
||||
<div className="rounded-md border border-red-500 bg-red-500/10 py-2 px-3 text-sm text-gray-600 dark:text-gray-100">
|
||||
{wrapText(text)}
|
||||
{text}
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex min-h-[20px] flex-col items-start gap-4 whitespace-pre-wrap">
|
||||
<div className="markdown prose dark:prose-invert light w-full break-words">
|
||||
{wrapText(text)}
|
||||
{notUser ? wrapText(text) : text}
|
||||
{blinker && <span className="result-streaming">█</span>}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
87
src/components/Messages/TextWrapper.jsx
Normal file
87
src/components/Messages/TextWrapper.jsx
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
import React from 'react';
|
||||
import Embed from './Embed';
|
||||
import Highlight from './Highlight';
|
||||
import regexSplit from '~/utils/regexSplit';
|
||||
// const codeRegex = /(```[^`]+?```)/g;
|
||||
const codeRegex = /(```[\s\S]*?```)/g;
|
||||
const inLineRegex = /(`[^`]+?`)/g;
|
||||
const matchRegex = /(`[^`]+?`)/g;
|
||||
const languageMatch = /^```(\w+)/;
|
||||
const newLineMatch = /^```(\n+)/;
|
||||
const languages = [
|
||||
'java',
|
||||
'c',
|
||||
'python',
|
||||
'c++',
|
||||
'javascript',
|
||||
'csharp',
|
||||
'php',
|
||||
'typescript',
|
||||
'swift',
|
||||
'objectivec',
|
||||
'sql',
|
||||
'r',
|
||||
'kotlin',
|
||||
'ruby',
|
||||
'go',
|
||||
'x86asm',
|
||||
'matlab',
|
||||
'perl',
|
||||
'pascal'
|
||||
];
|
||||
|
||||
const inLineWrap = (parts) =>
|
||||
parts.map((part, i) => {
|
||||
if (part.match(matchRegex)) {
|
||||
return <code key={i}>{part.slice(1, -1)}</code>;
|
||||
} else {
|
||||
// return <p key={i}>{part}</p>;
|
||||
return part;
|
||||
}
|
||||
});
|
||||
|
||||
export default function CodeWrapper({ text }) {
|
||||
if (text.includes('```')) {
|
||||
// const parts = text.split(codeRegex);
|
||||
const parts = regexSplit(text);
|
||||
console.log(parts);
|
||||
const codeParts = parts.map((part, i) => {
|
||||
if (part.match(codeRegex)) {
|
||||
let language = 'javascript';
|
||||
|
||||
if (part.match(languageMatch)) {
|
||||
language = part.match(languageMatch)[1].toLowerCase();
|
||||
const validLanguage = languages.some((lang) => language === lang);
|
||||
part = validLanguage ? part.replace(languageMatch, '```') : part;
|
||||
language = validLanguage ? language : 'javascript';
|
||||
}
|
||||
|
||||
part = part.replace(newLineMatch, '```');
|
||||
|
||||
return (
|
||||
<Embed
|
||||
key={i}
|
||||
language={language}
|
||||
>
|
||||
<Highlight
|
||||
code={part.slice(3, -3)}
|
||||
language={language}
|
||||
/>
|
||||
</Embed>
|
||||
);
|
||||
} else if (part.match(inLineRegex)) {
|
||||
const innerParts = part.split(inLineRegex);
|
||||
return inLineWrap(innerParts);
|
||||
} else {
|
||||
return part;
|
||||
}
|
||||
});
|
||||
|
||||
return <>{codeParts}</>; // return the wrapped text
|
||||
} else {
|
||||
// map over the parts and wrap any text between tildes with <code> tags
|
||||
const parts = text.split(matchRegex);
|
||||
const codeParts = inLineWrap(parts);
|
||||
return <>{codeParts}</>; // return the wrapped text
|
||||
}
|
||||
}
|
||||
584
src/style.css
584
src/style.css
|
|
@ -6,28 +6,6 @@
|
|||
box-sizing: border-box;
|
||||
outline: 1px solid limegreen !important;
|
||||
} */
|
||||
.prose :where(code):not(:where([class~="not-prose"] *)) {
|
||||
color: var(--tw-prose-code);
|
||||
font-size: .875em;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.prose :where(code):not(:where([class~="not-prose"] *))::before {
|
||||
content: "`";
|
||||
}
|
||||
|
||||
.prose :where(code):not(:where([class~="not-prose"] *))::after {
|
||||
content: "`";
|
||||
}
|
||||
|
||||
code, pre {
|
||||
font-family: Söhne Mono,Monaco,Andale Mono,Ubuntu Mono,monospace !important;
|
||||
}
|
||||
|
||||
code, kbd, pre, samp {
|
||||
font-family: Söhne Mono,Monaco,Andale Mono,Ubuntu Mono,monospace;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.scroll-down-enter {
|
||||
opacity: 0;
|
||||
|
|
@ -101,6 +79,568 @@ code, kbd, pre, samp {
|
|||
}
|
||||
}
|
||||
|
||||
.prose {
|
||||
color:var(--tw-prose-body);
|
||||
max-width:65ch
|
||||
}
|
||||
.prose :where([class~=lead]):not(:where([class~=not-prose] *)) {
|
||||
color:var(--tw-prose-lead);
|
||||
font-size:1.25em;
|
||||
line-height:1.6;
|
||||
margin-bottom:1.2em;
|
||||
margin-top:1.2em
|
||||
}
|
||||
.prose :where(a):not(:where([class~=not-prose] *)) {
|
||||
color:var(--tw-prose-links);
|
||||
font-weight:500;
|
||||
text-decoration:underline
|
||||
}
|
||||
.prose :where(strong):not(:where([class~=not-prose] *)) {
|
||||
color:var(--tw-prose-bold);
|
||||
font-weight:600
|
||||
}
|
||||
.prose :where(a strong):not(:where([class~=not-prose] *)) {
|
||||
color:inherit
|
||||
}
|
||||
.prose :where(blockquote strong):not(:where([class~=not-prose] *)) {
|
||||
color:inherit
|
||||
}
|
||||
.prose :where(thead th strong):not(:where([class~=not-prose] *)) {
|
||||
color:inherit
|
||||
}
|
||||
.prose :where(ol):not(:where([class~=not-prose] *)) {
|
||||
list-style-type:decimal;
|
||||
margin-bottom:1.25em;
|
||||
margin-top:1.25em;
|
||||
padding-left:1.625em
|
||||
}
|
||||
.prose :where(ol[type=A]):not(:where([class~=not-prose] *)) {
|
||||
list-style-type:upper-alpha
|
||||
}
|
||||
.prose :where(ol[type=a]):not(:where([class~=not-prose] *)) {
|
||||
list-style-type:lower-alpha
|
||||
}
|
||||
.prose :where(ol[type=A s]):not(:where([class~=not-prose] *)) {
|
||||
list-style-type:upper-alpha
|
||||
}
|
||||
.prose :where(ol[type=a s]):not(:where([class~=not-prose] *)) {
|
||||
list-style-type:lower-alpha
|
||||
}
|
||||
.prose :where(ol[type=I]):not(:where([class~=not-prose] *)) {
|
||||
list-style-type:upper-roman
|
||||
}
|
||||
.prose :where(ol[type=i]):not(:where([class~=not-prose] *)) {
|
||||
list-style-type:lower-roman
|
||||
}
|
||||
.prose :where(ol[type=I s]):not(:where([class~=not-prose] *)) {
|
||||
list-style-type:upper-roman
|
||||
}
|
||||
.prose :where(ol[type=i s]):not(:where([class~=not-prose] *)) {
|
||||
list-style-type:lower-roman
|
||||
}
|
||||
.prose :where(ol[type="1"]):not(:where([class~=not-prose] *)) {
|
||||
list-style-type:decimal
|
||||
}
|
||||
.prose :where(ul):not(:where([class~=not-prose] *)) {
|
||||
list-style-type:disc;
|
||||
margin-bottom:1.25em;
|
||||
margin-top:1.25em;
|
||||
padding-left:1.625em
|
||||
}
|
||||
.prose :where(ol>li):not(:where([class~=not-prose] *))::marker {
|
||||
color:var(--tw-prose-counters);
|
||||
font-weight:400
|
||||
}
|
||||
.prose :where(ul>li):not(:where([class~=not-prose] *))::marker {
|
||||
color:var(--tw-prose-bullets)
|
||||
}
|
||||
.prose :where(hr):not(:where([class~=not-prose] *)) {
|
||||
border-color:var(--tw-prose-hr);
|
||||
border-top-width:1px;
|
||||
margin-bottom:3em;
|
||||
margin-top:3em
|
||||
}
|
||||
.prose :where(blockquote):not(:where([class~=not-prose] *)) {
|
||||
border-left-color:var(--tw-prose-quote-borders);
|
||||
border-left-width:.25rem;
|
||||
color:var(--tw-prose-quotes);
|
||||
font-style:italic;
|
||||
font-style:normal;
|
||||
font-weight:500;
|
||||
margin-bottom:1.6em;
|
||||
margin-top:1.6em;
|
||||
padding-left:1em;
|
||||
quotes:"\201C""\201D""\2018""\2019"
|
||||
}
|
||||
.prose :where(blockquote p:first-of-type):not(:where([class~=not-prose] *)):before {
|
||||
content:open-quote
|
||||
}
|
||||
.prose :where(blockquote p:last-of-type):not(:where([class~=not-prose] *)):after {
|
||||
content:close-quote
|
||||
}
|
||||
.prose :where(h1):not(:where([class~=not-prose] *)) {
|
||||
color:var(--tw-prose-headings);
|
||||
font-size:2.25em;
|
||||
font-weight:800;
|
||||
line-height:1.1111111;
|
||||
margin-bottom:.8888889em;
|
||||
margin-top:0
|
||||
}
|
||||
.prose :where(h1 strong):not(:where([class~=not-prose] *)) {
|
||||
color:inherit;
|
||||
font-weight:900
|
||||
}
|
||||
.prose :where(h2):not(:where([class~=not-prose] *)) {
|
||||
color:var(--tw-prose-headings);
|
||||
font-size:1.5em;
|
||||
font-weight:700;
|
||||
line-height:1.3333333;
|
||||
margin-bottom:1em;
|
||||
margin-top:2em
|
||||
}
|
||||
.prose :where(h2 strong):not(:where([class~=not-prose] *)) {
|
||||
color:inherit;
|
||||
font-weight:800
|
||||
}
|
||||
.prose :where(h3):not(:where([class~=not-prose] *)) {
|
||||
color:var(--tw-prose-headings);
|
||||
font-size:1.25em;
|
||||
font-weight:600;
|
||||
line-height:1.6;
|
||||
margin-bottom:.6em;
|
||||
margin-top:1.6em
|
||||
}
|
||||
.prose :where(h3 strong):not(:where([class~=not-prose] *)) {
|
||||
color:inherit;
|
||||
font-weight:700
|
||||
}
|
||||
.prose :where(h4):not(:where([class~=not-prose] *)) {
|
||||
color:var(--tw-prose-headings);
|
||||
font-weight:600;
|
||||
line-height:1.5;
|
||||
margin-bottom:.5em;
|
||||
margin-top:1.5em
|
||||
}
|
||||
.prose :where(h4 strong):not(:where([class~=not-prose] *)) {
|
||||
color:inherit;
|
||||
font-weight:700
|
||||
}
|
||||
.prose :where(img):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:2em;
|
||||
margin-top:2em
|
||||
}
|
||||
.prose :where(figure>*):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:0;
|
||||
margin-top:0
|
||||
}
|
||||
.prose :where(figcaption):not(:where([class~=not-prose] *)) {
|
||||
color:var(--tw-prose-captions);
|
||||
font-size:.875em;
|
||||
line-height:1.4285714;
|
||||
margin-top:.8571429em
|
||||
}
|
||||
.prose :where(code):not(:where([class~=not-prose] *)) {
|
||||
color:var(--tw-prose-code);
|
||||
font-size:.875em;
|
||||
font-weight:600
|
||||
}
|
||||
.prose :where(code):not(:where([class~=not-prose] *)):before {
|
||||
content:"`"
|
||||
}
|
||||
.prose :where(code):not(:where([class~=not-prose] *)):after {
|
||||
content:"`"
|
||||
}
|
||||
.prose :where(a code):not(:where([class~=not-prose] *)) {
|
||||
color:inherit
|
||||
}
|
||||
.prose :where(h1 code):not(:where([class~=not-prose] *)) {
|
||||
color:inherit
|
||||
}
|
||||
.prose :where(h2 code):not(:where([class~=not-prose] *)) {
|
||||
color:inherit;
|
||||
font-size:.875em
|
||||
}
|
||||
.prose :where(h3 code):not(:where([class~=not-prose] *)) {
|
||||
color:inherit;
|
||||
font-size:.9em
|
||||
}
|
||||
.prose :where(h4 code):not(:where([class~=not-prose] *)) {
|
||||
color:inherit
|
||||
}
|
||||
.prose :where(blockquote code):not(:where([class~=not-prose] *)) {
|
||||
color:inherit
|
||||
}
|
||||
.prose :where(thead th code):not(:where([class~=not-prose] *)) {
|
||||
color:inherit
|
||||
}
|
||||
.prose :where(pre):not(:where([class~=not-prose] *)) {
|
||||
background-color:transparent;
|
||||
border-radius:.375rem;
|
||||
color:currentColor;
|
||||
font-size:.875em;
|
||||
font-weight:400;
|
||||
line-height:1.7142857;
|
||||
margin:0;
|
||||
overflow-x:auto;
|
||||
padding:0
|
||||
}
|
||||
.prose :where(pre code):not(:where([class~=not-prose] *)) {
|
||||
background-color:transparent;
|
||||
border-radius:0;
|
||||
border-width:0;
|
||||
color:inherit;
|
||||
font-family:inherit;
|
||||
font-size:inherit;
|
||||
font-weight:inherit;
|
||||
line-height:inherit;
|
||||
padding:0
|
||||
}
|
||||
.prose :where(pre code):not(:where([class~=not-prose] *)):before {
|
||||
content:none
|
||||
}
|
||||
.prose :where(pre code):not(:where([class~=not-prose] *)):after {
|
||||
content:none
|
||||
}
|
||||
.prose :where(table):not(:where([class~=not-prose] *)) {
|
||||
font-size:.875em;
|
||||
line-height:1.7142857;
|
||||
margin-bottom:2em;
|
||||
margin-top:2em;
|
||||
table-layout:auto;
|
||||
text-align:left;
|
||||
width:100%
|
||||
}
|
||||
.prose :where(thead):not(:where([class~=not-prose] *)) {
|
||||
border-bottom-color:var(--tw-prose-th-borders);
|
||||
border-bottom-width:1px
|
||||
}
|
||||
.prose :where(thead th):not(:where([class~=not-prose] *)) {
|
||||
color:var(--tw-prose-headings);
|
||||
font-weight:600;
|
||||
padding-bottom:.5714286em;
|
||||
padding-left:.5714286em;
|
||||
padding-right:.5714286em;
|
||||
vertical-align:bottom
|
||||
}
|
||||
.prose :where(tbody tr):not(:where([class~=not-prose] *)) {
|
||||
border-bottom-color:var(--tw-prose-td-borders);
|
||||
border-bottom-width:1px
|
||||
}
|
||||
.prose :where(tbody tr:last-child):not(:where([class~=not-prose] *)) {
|
||||
border-bottom-width:0
|
||||
}
|
||||
.prose :where(tbody td):not(:where([class~=not-prose] *)) {
|
||||
vertical-align:baseline
|
||||
}
|
||||
.prose :where(tfoot):not(:where([class~=not-prose] *)) {
|
||||
border-top-color:var(--tw-prose-th-borders);
|
||||
border-top-width:1px
|
||||
}
|
||||
.prose :where(tfoot td):not(:where([class~=not-prose] *)) {
|
||||
vertical-align:top
|
||||
}
|
||||
.prose {
|
||||
--tw-prose-body:#374151;
|
||||
--tw-prose-headings:#111827;
|
||||
--tw-prose-lead:#4b5563;
|
||||
--tw-prose-links:#111827;
|
||||
--tw-prose-bold:#111827;
|
||||
--tw-prose-counters:#6b7280;
|
||||
--tw-prose-bullets:#d1d5db;
|
||||
--tw-prose-hr:#e5e7eb;
|
||||
--tw-prose-quotes:#111827;
|
||||
--tw-prose-quote-borders:#e5e7eb;
|
||||
--tw-prose-captions:#6b7280;
|
||||
--tw-prose-code:#111827;
|
||||
--tw-prose-pre-code:#e5e7eb;
|
||||
--tw-prose-pre-bg:#1f2937;
|
||||
--tw-prose-th-borders:#d1d5db;
|
||||
--tw-prose-td-borders:#e5e7eb;
|
||||
--tw-prose-invert-body:#d1d5db;
|
||||
--tw-prose-invert-headings:#fff;
|
||||
--tw-prose-invert-lead:#9ca3af;
|
||||
--tw-prose-invert-links:#fff;
|
||||
--tw-prose-invert-bold:#fff;
|
||||
--tw-prose-invert-counters:#9ca3af;
|
||||
--tw-prose-invert-bullets:#4b5563;
|
||||
--tw-prose-invert-hr:#374151;
|
||||
--tw-prose-invert-quotes:#f3f4f6;
|
||||
--tw-prose-invert-quote-borders:#374151;
|
||||
--tw-prose-invert-captions:#9ca3af;
|
||||
--tw-prose-invert-code:#fff;
|
||||
--tw-prose-invert-pre-code:#d1d5db;
|
||||
--tw-prose-invert-pre-bg:rgba(0,0,0,.5);
|
||||
--tw-prose-invert-th-borders:#4b5563;
|
||||
--tw-prose-invert-td-borders:#374151;
|
||||
font-size:1rem;
|
||||
line-height:1.75
|
||||
}
|
||||
.prose :where(p):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.25em;
|
||||
margin-top:1.25em
|
||||
}
|
||||
.prose :where(video):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:2em;
|
||||
margin-top:2em
|
||||
}
|
||||
.prose :where(figure):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:2em;
|
||||
margin-top:2em
|
||||
}
|
||||
.prose :where(li):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:.5em;
|
||||
margin-top:.5em
|
||||
}
|
||||
.prose :where(ol>li):not(:where([class~=not-prose] *)) {
|
||||
padding-left:.375em
|
||||
}
|
||||
.prose :where(ul>li):not(:where([class~=not-prose] *)) {
|
||||
padding-left:.375em
|
||||
}
|
||||
.prose :where(.prose>ul>li p):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:.75em;
|
||||
margin-top:.75em
|
||||
}
|
||||
.prose :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.25em
|
||||
}
|
||||
.prose :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.25em
|
||||
}
|
||||
.prose :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.25em
|
||||
}
|
||||
.prose :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.25em
|
||||
}
|
||||
.prose :where(ul ul,
|
||||
ul ol,
|
||||
ol ul,
|
||||
ol ol):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:.75em;
|
||||
margin-top:.75em
|
||||
}
|
||||
.prose :where(hr+*):not(:where([class~=not-prose] *)) {
|
||||
margin-top:0
|
||||
}
|
||||
.prose :where(h2+*):not(:where([class~=not-prose] *)) {
|
||||
margin-top:0
|
||||
}
|
||||
.prose :where(h3+*):not(:where([class~=not-prose] *)) {
|
||||
margin-top:0
|
||||
}
|
||||
.prose :where(h4+*):not(:where([class~=not-prose] *)) {
|
||||
margin-top:0
|
||||
}
|
||||
.prose :where(thead th:first-child):not(:where([class~=not-prose] *)) {
|
||||
padding-left:0
|
||||
}
|
||||
.prose :where(thead th:last-child):not(:where([class~=not-prose] *)) {
|
||||
padding-right:0
|
||||
}
|
||||
.prose :where(tbody td,
|
||||
tfoot td):not(:where([class~=not-prose] *)) {
|
||||
padding:.5714286em
|
||||
}
|
||||
.prose :where(tbody td:first-child,
|
||||
tfoot td:first-child):not(:where([class~=not-prose] *)) {
|
||||
padding-left:0
|
||||
}
|
||||
.prose :where(tbody td:last-child,
|
||||
tfoot td:last-child):not(:where([class~=not-prose] *)) {
|
||||
padding-right:0
|
||||
}
|
||||
.prose :where(.prose>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:0
|
||||
}
|
||||
.prose :where(.prose>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:0
|
||||
}
|
||||
.prose-sm :where(.prose>ul>li p):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:.5714286em;
|
||||
margin-top:.5714286em
|
||||
}
|
||||
.prose-sm :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.1428571em
|
||||
}
|
||||
.prose-sm :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.1428571em
|
||||
}
|
||||
.prose-sm :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.1428571em
|
||||
}
|
||||
.prose-sm :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.1428571em
|
||||
}
|
||||
.prose-sm :where(.prose>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:0
|
||||
}
|
||||
.prose-sm :where(.prose>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:0
|
||||
}
|
||||
.prose-base :where(.prose>ul>li p):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:.75em;
|
||||
margin-top:.75em
|
||||
}
|
||||
.prose-base :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.25em
|
||||
}
|
||||
.prose-base :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.25em
|
||||
}
|
||||
.prose-base :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.25em
|
||||
}
|
||||
.prose-base :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.25em
|
||||
}
|
||||
.prose-base :where(.prose>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:0
|
||||
}
|
||||
.prose-base :where(.prose>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:0
|
||||
}
|
||||
.prose-lg :where(.prose>ul>li p):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:.8888889em;
|
||||
margin-top:.8888889em
|
||||
}
|
||||
.prose-lg :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.3333333em
|
||||
}
|
||||
.prose-lg :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.3333333em
|
||||
}
|
||||
.prose-lg :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.3333333em
|
||||
}
|
||||
.prose-lg :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.3333333em
|
||||
}
|
||||
.prose-lg :where(.prose>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:0
|
||||
}
|
||||
.prose-lg :where(.prose>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:0
|
||||
}
|
||||
.prose-xl :where(.prose>ul>li p):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:.8em;
|
||||
margin-top:.8em
|
||||
}
|
||||
.prose-xl :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.2em
|
||||
}
|
||||
.prose-xl :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.2em
|
||||
}
|
||||
.prose-xl :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.2em
|
||||
}
|
||||
.prose-xl :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.2em
|
||||
}
|
||||
.prose-xl :where(.prose>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:0
|
||||
}
|
||||
.prose-xl :where(.prose>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:0
|
||||
}
|
||||
.prose-2xl :where(.prose>ul>li p):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:.8333333em;
|
||||
margin-top:.8333333em
|
||||
}
|
||||
.prose-2xl :where(.prose>ul>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.3333333em
|
||||
}
|
||||
.prose-2xl :where(.prose>ul>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.3333333em
|
||||
}
|
||||
.prose-2xl :where(.prose>ol>li>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:1.3333333em
|
||||
}
|
||||
.prose-2xl :where(.prose>ol>li>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:1.3333333em
|
||||
}
|
||||
.prose-2xl :where(.prose>:first-child):not(:where([class~=not-prose] *)) {
|
||||
margin-top:0
|
||||
}
|
||||
.prose-2xl :where(.prose>:last-child):not(:where([class~=not-prose] *)) {
|
||||
margin-bottom:0
|
||||
}
|
||||
|
||||
code,
|
||||
pre {
|
||||
font-family: Söhne Mono, Monaco, Andale Mono, Ubuntu Mono, monospace !important;
|
||||
}
|
||||
code[class='language-plaintext'] {
|
||||
white-space: pre-line;
|
||||
}
|
||||
code.hljs,
|
||||
code[class*='language-'],
|
||||
pre[class*='language-'] {
|
||||
word-wrap: normal;
|
||||
background: none;
|
||||
color: #fff;
|
||||
-webkit-hyphens: none;
|
||||
hyphens: none;
|
||||
font-size: .85rem;
|
||||
line-height: 1.5;
|
||||
tab-size: 4;
|
||||
text-align: left;
|
||||
white-space: pre;
|
||||
word-break: normal;
|
||||
word-spacing: normal;
|
||||
}
|
||||
pre[class*='language-'] {
|
||||
border-radius: 0.3em;
|
||||
overflow: auto;
|
||||
}
|
||||
:not(pre) > code.hljs,
|
||||
:not(pre) > code[class*='language-'] {
|
||||
border-radius: 0.3em;
|
||||
padding: 0.1em;
|
||||
white-space: normal;
|
||||
}
|
||||
.hljs-comment {
|
||||
color: hsla(0, 0%, 100%, 0.5);
|
||||
}
|
||||
.hljs-meta {
|
||||
color: hsla(0, 0%, 100%, 0.6);
|
||||
}
|
||||
.hljs-built_in,
|
||||
.hljs-class .hljs-title {
|
||||
color: #e9950c;
|
||||
}
|
||||
.hljs-doctag,
|
||||
.hljs-formula,
|
||||
.hljs-keyword,
|
||||
.hljs-literal {
|
||||
color: #2e95d3;
|
||||
}
|
||||
.hljs-addition,
|
||||
.hljs-attribute,
|
||||
.hljs-meta-string,
|
||||
.hljs-regexp,
|
||||
.hljs-string {
|
||||
color: #00a67d;
|
||||
}
|
||||
.hljs-attr,
|
||||
.hljs-number,
|
||||
.hljs-selector-attr,
|
||||
.hljs-selector-class,
|
||||
.hljs-selector-pseudo,
|
||||
.hljs-template-variable,
|
||||
.hljs-type,
|
||||
.hljs-variable {
|
||||
color: #df3079;
|
||||
}
|
||||
.hljs-bullet,
|
||||
.hljs-link,
|
||||
.hljs-selector-id,
|
||||
.hljs-symbol,
|
||||
.hljs-title {
|
||||
color: #f22c3d;
|
||||
}
|
||||
|
||||
.dark .dark\:md\:bg-vert-dark-gradient {
|
||||
background-image: linear-gradient(180deg, rgba(53, 55, 64, 0), #353740 58.85%);
|
||||
}
|
||||
|
|
|
|||
20
src/utils/regexSplit.js
Normal file
20
src/utils/regexSplit.js
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
// const string = 'Some text before\n```python\nThis is some `Python` code with ```backticks``` inside the enclosure\n```\nSome text after\n```javascript\nThis is some JavaScript code\n```\n';
|
||||
const regex = /```([^`\n]*?)\n([\s\S]*?)\n```/g;
|
||||
|
||||
export default function regexSplit(string) {
|
||||
const matches = [...string.matchAll(regex)];
|
||||
const output = [matches[0].input.slice(0, matches[0].index)];
|
||||
|
||||
for (let i = 0; i < matches.length; i++) {
|
||||
const [fullMatch, language, code] = matches[i];
|
||||
// const formattedCode = code.replace(/`+/g, '\\`');
|
||||
const formattedCode = code;
|
||||
output.push(`\`\`\`${language}\n${formattedCode}\n\`\`\``);
|
||||
if (i < matches.length - 1) {
|
||||
const nextText = string.slice(matches[i].index + fullMatch.length, matches[i + 1].index);
|
||||
output.push(nextText.trim());
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue