From dddd6b4c489646043203d3f0ebce1d37ae056627 Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Sun, 9 Feb 2025 12:46:02 +0000 Subject: [PATCH 1/4] Removed unnecessary classes from Dialog --- apps/webapp/app/components/primitives/Dialog.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/webapp/app/components/primitives/Dialog.tsx b/apps/webapp/app/components/primitives/Dialog.tsx index 5e67afab77..7a78b5e02b 100644 --- a/apps/webapp/app/components/primitives/Dialog.tsx +++ b/apps/webapp/app/components/primitives/Dialog.tsx @@ -94,7 +94,7 @@ const DialogTitle = React.forwardRef< >(({ className, ...props }, ref) => ( )); From 8f657089866da0d31481437f80759aff4638246e Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Sun, 9 Feb 2025 12:51:54 +0000 Subject: [PATCH 2/4] Display large modal with code and copy button --- apps/webapp/app/components/code/CodeBlock.tsx | 425 ++++++++++++------ 1 file changed, 295 insertions(+), 130 deletions(-) diff --git a/apps/webapp/app/components/code/CodeBlock.tsx b/apps/webapp/app/components/code/CodeBlock.tsx index a7050202ea..07057b92ab 100644 --- a/apps/webapp/app/components/code/CodeBlock.tsx +++ b/apps/webapp/app/components/code/CodeBlock.tsx @@ -1,8 +1,11 @@ +import { ArrowsPointingOutIcon } from "@heroicons/react/20/solid"; 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, useState } from "react"; 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"; @@ -51,6 +54,9 @@ type CodeBlockProps = { /** title text for the Title row */ rowTitle?: string; + + /** Whether to show the open in modal button */ + showOpenInModal?: boolean; }; const dimAmount = 0.5; @@ -178,6 +184,7 @@ export const CodeBlock = forwardRef( { showCopyButton = true, showLineNumbers = true, + showOpenInModal = true, highlightedRanges, code, className, @@ -193,6 +200,9 @@ export const CodeBlock = forwardRef( ) => { const [mouseOver, setMouseOver] = useState(false); const [copied, setCopied] = useState(false); + const [modalCopied, setModalCopied] = useState(false); + const [isModalOpen, setIsModalOpen] = useState(false); + const onCopied = useCallback( (event: React.MouseEvent) => { event.preventDefault(); @@ -206,6 +216,19 @@ export const CodeBlock = forwardRef( [code] ); + const onModalCopied = useCallback( + (event: React.MouseEvent) => { + event.preventDefault(); + event.stopPropagation(); + navigator.clipboard.writeText(code); + setModalCopied(true); + setTimeout(() => { + setModalCopied(false); + }, 1500); + }, + [code] + ); + code = code.trim(); const lineCount = code.split("\n").length; const maxLineWidth = lineCount.toString().length; @@ -222,147 +245,289 @@ export const CodeBlock = forwardRef( const shouldHighlight = lineCount <= 1000; return ( -
- {showChrome && } - {rowTitle && } - {showCopyButton && ( - - - setMouseOver(true)} - onMouseLeave={() => setMouseOver(false)} - className={cn( - "absolute right-3 z-50 transition-colors duration-100 focus-custom hover:cursor-pointer", - showChrome ? "top-10" : "top-2.5", - copied ? "text-emerald-500" : "text-charcoal-500 hover:text-charcoal-300" - )} - > - {copied ? : } - - - {copied ? "Copied" : "Copy"} - - - - )} - - {shouldHighlight ? ( - - {({ - className: inheritedClassName, - style: inheritedStyle, - tokens, - getLineProps, - getTokenProps, - }) => ( -
-
+        
+ {showChrome && } + {rowTitle && } +
+ {showCopyButton && ( + + + setMouseOver(true)} + onMouseLeave={() => setMouseOver(false)} + className={cn( + "transition-colors duration-100 focus-custom hover:cursor-pointer", + showChrome ? "top-10" : "top-2.5", + copied ? "text-success" : "text-text-dimmed hover:text-text-bright" + )} + > + {copied ? ( + + ) : ( + + )} + + + {copied ? "Copied" : "Copy"} + + + + )} + {showOpenInModal && ( + + + setIsModalOpen(true)}> + + + + Expand + + + + )} +
+ + {shouldHighlight ? ( + + {({ + className: inheritedClassName, + style: inheritedStyle, + tokens, + getLineProps, + getTokenProps, + }) => ( +
- {tokens - .map((line, index) => { - if ( - index === tokens.length - 1 && - line.length === 1 && - line[0].content === "\n" - ) { - return null; - } - - const lineNumber = index + 1; - const lineProps = getLineProps({ line, key: index }); - - let hasAnyHighlights = highlightLines ? highlightLines.length > 0 : false; - - let shouldDim = hasAnyHighlights; - if (hasAnyHighlights && highlightLines?.includes(lineNumber)) { - shouldDim = false; - } - - return ( -
- {showLineNumbers && ( +
+                    {tokens
+                      .map((line, index) => {
+                        if (
+                          index === tokens.length - 1 &&
+                          line.length === 1 &&
+                          line[0].content === "\n"
+                        ) {
+                          return null;
+                        }
+
+                        const lineNumber = index + 1;
+                        const lineProps = getLineProps({ line, key: index });
+
+                        let hasAnyHighlights = highlightLines ? highlightLines.length > 0 : false;
+
+                        let shouldDim = hasAnyHighlights;
+                        if (hasAnyHighlights && highlightLines?.includes(lineNumber)) {
+                          shouldDim = false;
+                        }
+
+                        return (
+                          
+ {showLineNumbers && ( +
+ {lineNumber} +
+ )} + +
+ {line.map((token, key) => { + const tokenProps = getTokenProps({ token, key }); + return ( + + ); + })} +
+
+
+ ); + }) + .filter(Boolean)} +
+
+ )} + + ) : ( +
+
+                {code}
+              
+
+ )} +
+ + + + + + {fileName && fileName} + {rowTitle && rowTitle} + + + + + {shouldHighlight ? ( + + {({ + className: inheritedClassName, + style: inheritedStyle, + tokens, + getLineProps, + getTokenProps, + }) => ( +
+
+                      {tokens
+                        .map((line, index) => {
+                          if (
+                            index === tokens.length - 1 &&
+                            line.length === 1 &&
+                            line[0].content === "\n"
+                          ) {
+                            return null;
+                          }
+
+                          const lineNumber = index + 1;
+                          const lineProps = getLineProps({ line, key: index });
+
+                          let hasAnyHighlights = highlightLines ? highlightLines.length > 0 : false;
+
+                          let shouldDim = hasAnyHighlights;
+                          if (hasAnyHighlights && highlightLines?.includes(lineNumber)) {
+                            shouldDim = false;
+                          }
+
+                          return (
                             
- {lineNumber} -
- )} - -
- {line.map((token, key) => { - const tokenProps = getTokenProps({ token, key }); - return ( - - ); - })} -
-
-
- ); - }) - .filter(Boolean)} + > + {lineNumber} +
+ )} + +
+ {line.map((token, key) => { + const tokenProps = getTokenProps({ token, key }); + return ( + + ); + })} +
+
+
+ ); + }) + .filter(Boolean)} +
+
+ )} +
+ ) : ( +
+
+                  {code}
                 
)} - - ) : ( -
-
-              {code}
-            
-
- )} -
+ + + ); } ); From 3eeadc8a1dbc075d5946a0ab735ec6779708fd83 Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Sun, 9 Feb 2025 12:54:46 +0000 Subject: [PATCH 3/4] Fixes button position if chrome is shown --- apps/webapp/app/components/code/CodeBlock.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/apps/webapp/app/components/code/CodeBlock.tsx b/apps/webapp/app/components/code/CodeBlock.tsx index 07057b92ab..d03c9bb508 100644 --- a/apps/webapp/app/components/code/CodeBlock.tsx +++ b/apps/webapp/app/components/code/CodeBlock.tsx @@ -257,7 +257,12 @@ export const CodeBlock = forwardRef( > {showChrome && } {rowTitle && } -
+
{showCopyButton && ( @@ -267,7 +272,6 @@ export const CodeBlock = forwardRef( onMouseLeave={() => setMouseOver(false)} className={cn( "transition-colors duration-100 focus-custom hover:cursor-pointer", - showChrome ? "top-10" : "top-2.5", copied ? "text-success" : "text-text-dimmed hover:text-text-bright" )} > From e8d9b9953855999a14fe8daf36231c77892c3d5f Mon Sep 17 00:00:00 2001 From: James Ritchie Date: Tue, 18 Feb 2025 10:27:38 +0000 Subject: [PATCH 4/4] Removes the duplication of the Highlight component --- apps/webapp/app/components/code/CodeBlock.tsx | 320 ++++++++---------- 1 file changed, 136 insertions(+), 184 deletions(-) diff --git a/apps/webapp/app/components/code/CodeBlock.tsx b/apps/webapp/app/components/code/CodeBlock.tsx index d03c9bb508..db1d165220 100644 --- a/apps/webapp/app/components/code/CodeBlock.tsx +++ b/apps/webapp/app/components/code/CodeBlock.tsx @@ -302,99 +302,16 @@ export const CodeBlock = forwardRef(
{shouldHighlight ? ( - - {({ - className: inheritedClassName, - style: inheritedStyle, - tokens, - getLineProps, - getTokenProps, - }) => ( -
-
-                    {tokens
-                      .map((line, index) => {
-                        if (
-                          index === tokens.length - 1 &&
-                          line.length === 1 &&
-                          line[0].content === "\n"
-                        ) {
-                          return null;
-                        }
-
-                        const lineNumber = index + 1;
-                        const lineProps = getLineProps({ line, key: index });
-
-                        let hasAnyHighlights = highlightLines ? highlightLines.length > 0 : false;
-
-                        let shouldDim = hasAnyHighlights;
-                        if (hasAnyHighlights && highlightLines?.includes(lineNumber)) {
-                          shouldDim = false;
-                        }
-
-                        return (
-                          
- {showLineNumbers && ( -
- {lineNumber} -
- )} - -
- {line.map((token, key) => { - const tokenProps = getTokenProps({ token, key }); - return ( - - ); - })} -
-
-
- ); - }) - .filter(Boolean)} -
-
- )} -
+ ) : (
( - + {fileName && fileName} {rowTitle && rowTitle} @@ -429,96 +346,16 @@ export const CodeBlock = forwardRef( {shouldHighlight ? ( - - {({ - className: inheritedClassName, - style: inheritedStyle, - tokens, - getLineProps, - getTokenProps, - }) => ( -
-
-                      {tokens
-                        .map((line, index) => {
-                          if (
-                            index === tokens.length - 1 &&
-                            line.length === 1 &&
-                            line[0].content === "\n"
-                          ) {
-                            return null;
-                          }
-
-                          const lineNumber = index + 1;
-                          const lineProps = getLineProps({ line, key: index });
-
-                          let hasAnyHighlights = highlightLines ? highlightLines.length > 0 : false;
-
-                          let shouldDim = hasAnyHighlights;
-                          if (hasAnyHighlights && highlightLines?.includes(lineNumber)) {
-                            shouldDim = false;
-                          }
-
-                          return (
-                            
- {showLineNumbers && ( -
- {lineNumber} -
- )} - -
- {line.map((token, key) => { - const tokenProps = getTokenProps({ token, key }); - return ( - - ); - })} -
-
-
- ); - }) - .filter(Boolean)} -
-
- )} -
+ ) : (
); } + +type HighlightCodeProps = { + theme: PrismTheme; + code: string; + language: Language; + showLineNumbers: boolean; + highlightLines?: number[]; + maxLineWidth?: number; + className?: string; + preClassName?: string; +}; + +function HighlightCode({ + theme, + code, + language, + showLineNumbers, + highlightLines, + maxLineWidth, + className, + preClassName, +}: HighlightCodeProps) { + return ( + + {({ + className: inheritedClassName, + style: inheritedStyle, + tokens, + getLineProps, + getTokenProps, + }) => ( +
+
+            {tokens
+              .map((line, index) => {
+                if (index === tokens.length - 1 && line.length === 1 && line[0].content === "\n") {
+                  return null;
+                }
+
+                const lineNumber = index + 1;
+                const lineProps = getLineProps({ line, key: index });
+
+                let hasAnyHighlights = highlightLines ? highlightLines.length > 0 : false;
+
+                let shouldDim = hasAnyHighlights;
+                if (hasAnyHighlights && highlightLines?.includes(lineNumber)) {
+                  shouldDim = false;
+                }
+
+                return (
+                  
+ {showLineNumbers && ( +
+ {lineNumber} +
+ )} + +
+ {line.map((token, key) => { + const tokenProps = getTokenProps({ token, key }); + return ( + + ); + })} +
+
+
+ ); + }) + .filter(Boolean)} +
+
+ )} +
+ ); +}