diff --git a/apps/webapp/app/assets/icons/TextInlineIcon.tsx b/apps/webapp/app/assets/icons/TextInlineIcon.tsx new file mode 100644 index 0000000000..538d9768d0 --- /dev/null +++ b/apps/webapp/app/assets/icons/TextInlineIcon.tsx @@ -0,0 +1,41 @@ +export function TextInlineIcon({ className }: { className?: string }) { + return ( + + + + + + + + ); +} diff --git a/apps/webapp/app/assets/icons/TextWrapIcon.tsx b/apps/webapp/app/assets/icons/TextWrapIcon.tsx new file mode 100644 index 0000000000..ac37867e82 --- /dev/null +++ b/apps/webapp/app/assets/icons/TextWrapIcon.tsx @@ -0,0 +1,34 @@ +export function TextWrapIcon({ className }: { className?: string }) { + return ( + + + + + + + ); +} diff --git a/apps/webapp/app/components/code/CodeBlock.tsx b/apps/webapp/app/components/code/CodeBlock.tsx index eb133105b9..ca6200a18b 100644 --- a/apps/webapp/app/components/code/CodeBlock.tsx +++ b/apps/webapp/app/components/code/CodeBlock.tsx @@ -3,11 +3,13 @@ import { Clipboard, ClipboardCheck } from "lucide-react"; import type { Language, PrismTheme } from "prism-react-renderer"; import { Highlight, Prism } from "prism-react-renderer"; import { forwardRef, ReactNode, useCallback, useEffect, useState } from "react"; +import { TextWrapIcon } from "~/assets/icons/TextWrapIcon"; import { cn } from "~/utils/cn"; import { Button } from "../primitives/Buttons"; import { Dialog, DialogContent, DialogHeader, DialogTitle } from "../primitives/Dialog"; import { Paragraph } from "../primitives/Paragraph"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "../primitives/Tooltip"; +import { TextInlineIcon } from "~/assets/icons/TextInlineIcon"; //This is a fork of https://github.com/mantinedev/mantine/blob/master/src/mantine-prism/src/Prism/Prism.tsx //it didn't support highlighting lines by dimming the rest of the code, or animations on the highlighting @@ -31,6 +33,9 @@ type CodeBlockProps = { /** Show copy to clipboard button */ showCopyButton?: boolean; + /** Show text wrapping button */ + showTextWrapping?: boolean; + /** Display line numbers */ showLineNumbers?: boolean; @@ -183,6 +188,7 @@ export const CodeBlock = forwardRef( ( { showCopyButton = true, + showTextWrapping = false, showLineNumbers = true, showOpenInModal = true, highlightedRanges, @@ -202,6 +208,7 @@ export const CodeBlock = forwardRef( const [copied, setCopied] = useState(false); const [modalCopied, setModalCopied] = useState(false); const [isModalOpen, setIsModalOpen] = useState(false); + const [isWrapped, setIsWrapped] = useState(false); const onCopied = useCallback( (event: React.MouseEvent) => { @@ -263,6 +270,25 @@ export const CodeBlock = forwardRef( showChrome ? "right-1.5 top-1.5" : "top-2.5" )} > + {showTextWrapping && ( + + + setIsWrapped(!isWrapped)} + className="transition-colors focus-custom hover:cursor-pointer hover:text-text-bright" + > + {isWrapped ? ( + + ) : ( + + )} + + + {isWrapped ? "Unwrap" : "Wrap"} + + + + )} {showCopyButton && ( @@ -311,16 +337,27 @@ export const CodeBlock = forwardRef( maxLineWidth={maxLineWidth} className="px-2 py-3" preClassName="text-xs" + isWrapped={isWrapped} /> ) : (
-
+              
                 {code}
               
@@ -355,6 +392,7 @@ export const CodeBlock = forwardRef( maxLineWidth={maxLineWidth} className="min-h-full" preClassName="text-sm" + isWrapped={isWrapped} /> ) : (
{ - // This ensures the language definitions are loaded Promise.all([ //@ts-ignore import("prismjs/components/prism-json"), @@ -434,16 +473,23 @@ function HighlightCode({ ]).then(() => setIsLoaded(true)); }, []); + const containerClasses = cn( + "px-3 py-3 scrollbar-thin scrollbar-track-transparent scrollbar-thumb-charcoal-600", + !isWrapped && "overflow-x-auto", + isWrapped && "overflow-y-auto", + className + ); + + const preClasses = cn( + "relative mr-2 font-mono leading-relaxed", + preClassName, + isWrapped && "[&_span]:whitespace-pre-wrap [&_span]:break-words" + ); + if (!isLoaded) { return ( -
-
{code}
+
+
{code}
); } @@ -457,22 +503,8 @@ function HighlightCode({ getLineProps, getTokenProps, }) => ( -
-
+        
+
             {tokens
               .map((line, index) => {
                 if (index === tokens.length - 1 && line.length === 1 && line[0].content === "\n") {
@@ -495,7 +527,8 @@ function HighlightCode({
                     {...lineProps}
                     className={cn(
                       "flex w-full justify-start transition-opacity duration-500",
-                      lineProps.className
+                      lineProps.className,
+                      isWrapped && "flex-wrap"
                     )}
                     style={{
                       opacity: shouldDim ? dimAmount : undefined,
@@ -504,9 +537,10 @@ function HighlightCode({
                   >
                     {showLineNumbers && (
                       
); }