@@ -12,7 +12,65 @@ import VisibilityIcon from "@mui/icons-material/Visibility";
1212import { Box , Button , Collapse , Typography } from "@mui/material" ;
1313import { Tooltip , IconButton } from "@mui/material" ;
1414import { Colors } from "design/theme" ;
15- import React from "react" ;
15+ import React , { useState } from "react" ;
16+
17+ // FileTreeRow.tsx (top of file, below imports)
18+ const LeafString : React . FC < { value : string } > = ( { value } ) => {
19+ const LIMIT = 120 ;
20+ const [ expanded , setExpanded ] = React . useState ( false ) ;
21+
22+ const isLong = value . length > LIMIT ;
23+ const display = expanded
24+ ? value
25+ : isLong
26+ ? value . slice ( 0 , LIMIT ) + "…"
27+ : value ;
28+
29+ return (
30+ < Box
31+ sx = { {
32+ display : "flex" ,
33+ alignItems : "baseline" ,
34+ gap : 1 ,
35+ mt : 0.25 ,
36+ minWidth : 0 ,
37+ } }
38+ >
39+ < Typography
40+ sx = { {
41+ fontFamily : "monospace" ,
42+ fontSize : "0.85rem" ,
43+ color : "text.secondary" ,
44+
45+ // collapsed: clamp to 2 lines; expanded: fully wrap
46+ display : expanded ? "block" : "-webkit-box" ,
47+ WebkitBoxOrient : "vertical" ,
48+ WebkitLineClamp : expanded ? ( "unset" as any ) : 2 ,
49+ whiteSpace : expanded ? "pre-wrap" : "normal" ,
50+ overflow : expanded ? "visible" : "hidden" ,
51+ textOverflow : expanded ? "unset" : "ellipsis" ,
52+ flex : 1 ,
53+ } }
54+ >
55+ { display }
56+ </ Typography >
57+
58+ { isLong && (
59+ < Button
60+ size = "small"
61+ variant = "text"
62+ onClick = { ( e ) => {
63+ e . stopPropagation ( ) ; // don’t toggle the row
64+ setExpanded ( ( v ) => ! v ) ;
65+ } }
66+ sx = { { px : 0.5 , minWidth : "auto" } }
67+ >
68+ { expanded ? "Show less" : "Show more" }
69+ </ Button >
70+ ) }
71+ </ Box >
72+ ) ;
73+ } ;
1674
1775type Props = {
1876 node : TreeNode ;
@@ -50,8 +108,9 @@ const FileTreeRow: React.FC<Props> = ({
50108 getInternalByPath,
51109 getJsonByPath,
52110} ) => {
53- const [ open , setOpen ] = React . useState ( false ) ;
54- const [ copied , setCopied ] = React . useState ( false ) ;
111+ const [ open , setOpen ] = useState ( false ) ;
112+ const [ copied , setCopied ] = useState ( false ) ;
113+ const [ showFull , setShowFull ] = useState ( false ) ;
55114 // const internal = getInternalByPath?.(node.path);
56115 // const internal = getInternalByPath ? getInternalByPath(node.path) : undefined;
57116 const internal = getInternalByPath ( node . path ) ;
@@ -69,14 +128,13 @@ const FileTreeRow: React.FC<Props> = ({
69128 } ;
70129
71130 if ( node . kind === "folder" ) {
72- // const isSubject = /^sub-/i.test(node.name); // subject folders only
73131 const isJson = / \. j s o n $ / i. test ( node . name ) ; // end with .json only
74132 return (
75133 < >
76134 < Box
77135 sx = { {
78136 display : "flex" ,
79- alignItems : "center " ,
137+ alignItems : "flex-start " ,
80138 gap : 1 ,
81139 py : 0.5 ,
82140 px : 1 ,
@@ -188,7 +246,9 @@ const FileTreeRow: React.FC<Props> = ({
188246 }
189247 // if the node is a file
190248 return (
191- < Box sx = { { display : "flex" , alignItems : "center" , gap : 1 , py : 0.5 , px : 1 } } >
249+ < Box
250+ sx = { { display : "flex" , alignItems : "flex-start" , gap : 1 , py : 0.5 , px : 1 } }
251+ >
192252 < Box sx = { { pl : level * 1.25 , pt : "2px" } } >
193253 < InsertDriveFileIcon
194254 fontSize = "small"
@@ -200,7 +260,6 @@ const FileTreeRow: React.FC<Props> = ({
200260 < Typography
201261 title = { node . name }
202262 sx = { {
203- // fontWeight: 500,
204263 whiteSpace : "nowrap" ,
205264 overflow : "hidden" ,
206265 textOverflow : "ellipsis" ,
@@ -209,7 +268,36 @@ const FileTreeRow: React.FC<Props> = ({
209268 { node . name }
210269 </ Typography >
211270
212- { ! node . link && node . value !== undefined && (
271+ { ! node . link &&
272+ node . value !== undefined &&
273+ ( typeof node . value === "string" ? (
274+ < LeafString value = { node . value } />
275+ ) : (
276+ < Typography
277+ title = {
278+ node . name === "_ArrayZipData_"
279+ ? "[compressed data]"
280+ : typeof node . value === "string"
281+ ? node . value
282+ : JSON . stringify ( node . value )
283+ }
284+ sx = { {
285+ fontFamily : "monospace" ,
286+ fontSize : "0.85rem" ,
287+ color : "text.secondary" ,
288+ whiteSpace : "nowrap" ,
289+ overflow : "hidden" ,
290+ textOverflow : "ellipsis" ,
291+ mt : 0.25 ,
292+ } }
293+ >
294+ { node . name === "_ArrayZipData_"
295+ ? "[compressed data]"
296+ : formatLeafValue ( node . value ) }
297+ </ Typography >
298+ ) ) }
299+
300+ { /* {!node.link && node.value !== undefined && (
213301 <Typography
214302 title={
215303 node.name === "_ArrayZipData_"
@@ -232,24 +320,26 @@ const FileTreeRow: React.FC<Props> = ({
232320 ? "[compressed data]"
233321 : formatLeafValue(node.value)}
234322 </Typography>
235- ) }
323+ )} */ }
236324 </ Box >
237325 { /* ALWAYS show copy for files, even when no external/internal */ }
238- < Tooltip title = { copied ? "Copied!" : "Copy JSON" } arrow >
239- < span >
240- < IconButton
241- size = "small"
242- onClick = { handleCopy }
243- disabled = { ! getJsonByPath } // optional safety
244- >
245- { copied ? (
246- < CheckIcon fontSize = "inherit" />
247- ) : (
248- < ContentCopyIcon fontSize = "inherit" />
249- ) }
250- </ IconButton >
251- </ span >
252- </ Tooltip >
326+ < Box sx = { { alignSelf : "flex-start" } } >
327+ < Tooltip title = { copied ? "Copied!" : "Copy JSON" } arrow >
328+ < span >
329+ < IconButton
330+ size = "small"
331+ onClick = { handleCopy }
332+ disabled = { ! getJsonByPath } // optional safety
333+ >
334+ { copied ? (
335+ < CheckIcon fontSize = "inherit" />
336+ ) : (
337+ < ContentCopyIcon fontSize = "inherit" />
338+ ) }
339+ </ IconButton >
340+ </ span >
341+ </ Tooltip >
342+ </ Box >
253343 { /* Placeholder to align with folder chevron */ }
254344 < Box sx = { { width : 28 } } />
255345 { ( externalUrl || internal ) && (
0 commit comments