@@ -13,13 +13,13 @@ import { usePanelLayoutStore } from "@features/panels";
1313import { useFileTreeStore } from "@features/right-sidebar/stores/fileTreeStore" ;
1414import { useCwd } from "@features/sidebar/hooks/useCwd" ;
1515import { useIsWorkspaceCloudRun } from "@features/workspace/hooks/useWorkspace" ;
16- import { Code , Eye } from "@phosphor-icons/react" ;
16+ import { Check , Code , Copy , Eye } from "@phosphor-icons/react" ;
1717import { Box , Flex , IconButton , Text } from "@radix-ui/themes" ;
1818import { trpcClient , useTRPC } from "@renderer/trpc/client" ;
1919import type { Task } from "@shared/types" ;
2020
2121import { useQuery } from "@tanstack/react-query" ;
22- import { useCallback , useMemo } from "react" ;
22+ import { useCallback , useMemo , useState } from "react" ;
2323import type { Components } from "react-markdown" ;
2424import ReactMarkdown from "react-markdown" ;
2525import remarkGfm from "remark-gfm" ;
@@ -47,6 +47,7 @@ export function CodeEditorPanel({
4747 ) ;
4848 const openFileInSplit = usePanelLayoutStore ( ( s ) => s . openFileInSplit ) ;
4949 const expandToFile = useFileTreeStore ( ( s ) => s . expandToFile ) ;
50+ const [ copied , setCopied ] = useState ( false ) ;
5051
5152 const handleMarkdownLinkClick = useCallback (
5253 ( e : React . MouseEvent < HTMLAnchorElement > , href : string ) => {
@@ -193,6 +194,12 @@ export function CodeEditorPanel({
193194 }
194195
195196 if ( isMarkdown ) {
197+ const handleCopySource = ( ) => {
198+ navigator . clipboard . writeText ( fileContent ) ;
199+ setCopied ( true ) ;
200+ setTimeout ( ( ) => setCopied ( false ) , 2000 ) ;
201+ } ;
202+
196203 return (
197204 < Flex direction = "column" height = "100%" className = "overflow-hidden" >
198205 < Flex
@@ -208,17 +215,31 @@ export function CodeEditorPanel({
208215 >
209216 { filePath }
210217 </ Text >
211- < Tooltip content = { preferRendered ? "View source" : "View rendered" } >
212- < IconButton
213- size = "1"
214- variant = "ghost"
215- color = "gray"
216- className = "cursor-pointer"
217- onClick = { togglePreferRendered }
218- >
219- { preferRendered ? < Code size = { 14 } /> : < Eye size = { 14 } /> }
220- </ IconButton >
221- </ Tooltip >
218+ < Flex align = "center" gap = "1" >
219+ < Tooltip content = { copied ? "Copied" : "Copy source" } >
220+ < IconButton
221+ size = "1"
222+ variant = "ghost"
223+ color = "gray"
224+ className = "cursor-pointer"
225+ onClick = { handleCopySource }
226+ aria-label = "Copy source"
227+ >
228+ { copied ? < Check size = { 14 } /> : < Copy size = { 14 } /> }
229+ </ IconButton >
230+ </ Tooltip >
231+ < Tooltip content = { preferRendered ? "View source" : "View rendered" } >
232+ < IconButton
233+ size = "1"
234+ variant = "ghost"
235+ color = "gray"
236+ className = "cursor-pointer"
237+ onClick = { togglePreferRendered }
238+ >
239+ { preferRendered ? < Code size = { 14 } /> : < Eye size = { 14 } /> }
240+ </ IconButton >
241+ </ Tooltip >
242+ </ Flex >
222243 </ Flex >
223244 < Box className = "flex-1 overflow-auto" >
224245 { preferRendered ? (
0 commit comments