Skip to content

Commit 376e1b5

Browse files
authored
fix: handle file overflow properly, add hover tooltip (#759)
1 parent 00ff51c commit 376e1b5

File tree

1 file changed

+162
-147
lines changed

1 file changed

+162
-147
lines changed

apps/twig/src/renderer/features/task-detail/components/ChangesPanel.tsx

Lines changed: 162 additions & 147 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { FileIcon } from "@components/ui/FileIcon";
22
import { PanelMessage } from "@components/ui/PanelMessage";
3+
import { Tooltip } from "@components/ui/Tooltip";
34
import { isDiffTabActiveInTree, usePanelLayoutStore } from "@features/panels";
45
import { usePendingPermissionsForTask } from "@features/sessions/stores/sessionStore";
56
import { useCwd } from "@features/sidebar/hooks/useCwd";
@@ -18,7 +19,6 @@ import {
1819
Flex,
1920
IconButton,
2021
Text,
21-
Tooltip,
2222
} from "@radix-ui/themes";
2323
import { trpcVanilla } from "@renderer/trpc/client";
2424
import type { ChangedFile, GitFileStatus, Task } from "@shared/types";
@@ -45,20 +45,21 @@ interface ChangedFileItemProps {
4545

4646
function getStatusIndicator(status: GitFileStatus): {
4747
label: string;
48+
fullLabel: string;
4849
color: "green" | "orange" | "red" | "blue" | "gray";
4950
} {
5051
switch (status) {
5152
case "added":
5253
case "untracked":
53-
return { label: "A", color: "green" };
54+
return { label: "A", fullLabel: "Added", color: "green" };
5455
case "deleted":
55-
return { label: "D", color: "red" };
56+
return { label: "D", fullLabel: "Deleted", color: "red" };
5657
case "modified":
57-
return { label: "M", color: "orange" };
58+
return { label: "M", fullLabel: "Modified", color: "orange" };
5859
case "renamed":
59-
return { label: "R", color: "blue" };
60+
return { label: "R", fullLabel: "Renamed", color: "blue" };
6061
default:
61-
return { label: "?", color: "gray" };
62+
return { label: "?", fullLabel: "Unknown", color: "gray" };
6263
}
6364
}
6465

@@ -206,156 +207,170 @@ function ChangedFileItem({
206207
const hasLineStats =
207208
file.linesAdded !== undefined || file.linesRemoved !== undefined;
208209

210+
const tooltipContent = `${file.path} - ${indicator.fullLabel}`;
211+
209212
return (
210-
<Flex
211-
align="center"
212-
gap="1"
213-
onClick={handleClick}
214-
onDoubleClick={handleDoubleClick}
215-
onContextMenu={handleContextMenu}
216-
onMouseEnter={() => setIsHovered(true)}
217-
onMouseLeave={() => setIsHovered(false)}
218-
className={
219-
isActive
220-
? "border-accent-8 border-y bg-accent-4"
221-
: "border-transparent border-y hover:bg-gray-3"
222-
}
223-
style={{
224-
cursor: "pointer",
225-
whiteSpace: "nowrap",
226-
overflow: "hidden",
227-
height: "26px",
228-
paddingLeft: "8px",
229-
paddingRight: "8px",
230-
}}
231-
>
232-
<FileIcon filename={fileName} size={14} />
233-
<Text
234-
size="1"
235-
style={{
236-
userSelect: "none",
237-
flexShrink: 0,
238-
marginLeft: "2px",
239-
}}
240-
>
241-
{fileName}
242-
</Text>
243-
<Text
244-
size="1"
245-
color="gray"
213+
<Tooltip content={tooltipContent} side="top" delayDuration={500}>
214+
<Flex
215+
align="center"
216+
gap="1"
217+
onClick={handleClick}
218+
onDoubleClick={handleDoubleClick}
219+
onContextMenu={handleContextMenu}
220+
onMouseEnter={() => setIsHovered(true)}
221+
onMouseLeave={() => setIsHovered(false)}
222+
className={
223+
isActive
224+
? "border-accent-8 border-y bg-accent-4"
225+
: "border-transparent border-y hover:bg-gray-3"
226+
}
246227
style={{
247-
userSelect: "none",
228+
cursor: "pointer",
229+
whiteSpace: "nowrap",
248230
overflow: "hidden",
249-
textOverflow: "ellipsis",
250-
flex: 1,
251-
marginLeft: "4px",
231+
height: "26px",
232+
paddingLeft: "8px",
233+
paddingRight: "8px",
252234
}}
253235
>
254-
{file.originalPath ? `${file.originalPath}${file.path}` : file.path}
255-
</Text>
256-
257-
{hasLineStats && !isToolbarVisible && (
258-
<Flex
259-
align="center"
260-
gap="1"
261-
style={{ flexShrink: 0, fontSize: "10px", fontFamily: "monospace" }}
236+
<FileIcon filename={fileName} size={14} />
237+
<Text
238+
size="1"
239+
style={{
240+
userSelect: "none",
241+
overflow: "hidden",
242+
textOverflow: "ellipsis",
243+
marginLeft: "2px",
244+
flexShrink: 1,
245+
minWidth: 0,
246+
}}
262247
>
263-
{(file.linesAdded ?? 0) > 0 && (
264-
<Text style={{ color: "var(--green-9)" }}>+{file.linesAdded}</Text>
265-
)}
266-
{(file.linesRemoved ?? 0) > 0 && (
267-
<Text style={{ color: "var(--red-9)" }}>-{file.linesRemoved}</Text>
268-
)}
269-
</Flex>
270-
)}
271-
272-
{isToolbarVisible && (
273-
<Flex align="center" gap="1" style={{ flexShrink: 0 }}>
274-
<Tooltip content="Discard changes">
275-
<IconButton
276-
size="1"
277-
variant="ghost"
278-
color="gray"
279-
onClick={handleDiscard}
280-
style={{
281-
flexShrink: 0,
282-
width: "18px",
283-
height: "18px",
284-
padding: 0,
285-
marginLeft: "2px",
286-
marginRight: "2px",
287-
}}
288-
>
289-
<ArrowCounterClockwiseIcon size={12} />
290-
</IconButton>
291-
</Tooltip>
292-
293-
<DropdownMenu.Root
294-
open={isDropdownOpen}
295-
onOpenChange={setIsDropdownOpen}
248+
{fileName}
249+
</Text>
250+
<Text
251+
size="1"
252+
color="gray"
253+
style={{
254+
userSelect: "none",
255+
overflow: "hidden",
256+
textOverflow: "ellipsis",
257+
flex: 1,
258+
marginLeft: "4px",
259+
minWidth: 0,
260+
}}
261+
>
262+
{file.originalPath
263+
? `${file.originalPath}${file.path}`
264+
: file.path}
265+
</Text>
266+
267+
{hasLineStats && !isToolbarVisible && (
268+
<Flex
269+
align="center"
270+
gap="1"
271+
style={{ flexShrink: 0, fontSize: "10px", fontFamily: "monospace" }}
296272
>
297-
<Tooltip content="Open file">
298-
<DropdownMenu.Trigger>
299-
<IconButton
300-
size="1"
301-
variant="ghost"
302-
color="gray"
303-
onClick={(e) => e.stopPropagation()}
304-
style={{
305-
flexShrink: 0,
306-
width: "18px",
307-
height: "18px",
308-
padding: 0,
309-
}}
310-
>
311-
<FilePlus size={12} weight="regular" />
312-
</IconButton>
313-
</DropdownMenu.Trigger>
273+
{(file.linesAdded ?? 0) > 0 && (
274+
<Text style={{ color: "var(--green-9)" }}>
275+
+{file.linesAdded}
276+
</Text>
277+
)}
278+
{(file.linesRemoved ?? 0) > 0 && (
279+
<Text style={{ color: "var(--red-9)" }}>
280+
-{file.linesRemoved}
281+
</Text>
282+
)}
283+
</Flex>
284+
)}
285+
286+
{isToolbarVisible && (
287+
<Flex align="center" gap="1" style={{ flexShrink: 0 }}>
288+
<Tooltip content="Discard changes">
289+
<IconButton
290+
size="1"
291+
variant="ghost"
292+
color="gray"
293+
onClick={handleDiscard}
294+
style={{
295+
flexShrink: 0,
296+
width: "18px",
297+
height: "18px",
298+
padding: 0,
299+
marginLeft: "2px",
300+
marginRight: "2px",
301+
}}
302+
>
303+
<ArrowCounterClockwiseIcon size={12} />
304+
</IconButton>
314305
</Tooltip>
315-
<DropdownMenu.Content size="1" align="end">
316-
{detectedApps
317-
.filter((app) => app.type !== "terminal")
318-
.map((app) => (
319-
<DropdownMenu.Item
320-
key={app.id}
321-
onSelect={() => handleOpenWith(app.id)}
322-
>
323-
<Flex align="center" gap="2">
324-
{app.icon ? (
325-
<img
326-
src={app.icon}
327-
width={16}
328-
height={16}
329-
alt=""
330-
style={{ borderRadius: "2px" }}
331-
/>
332-
) : (
333-
<CodeIcon size={16} weight="regular" />
334-
)}
335-
<Text size="1">{app.name}</Text>
336-
</Flex>
337-
</DropdownMenu.Item>
338-
))}
339-
<DropdownMenu.Separator />
340-
<DropdownMenu.Item onSelect={handleCopyPath}>
341-
<Flex align="center" gap="2">
342-
<CopyIcon size={16} weight="regular" />
343-
<Text size="1">Copy Path</Text>
344-
</Flex>
345-
</DropdownMenu.Item>
346-
</DropdownMenu.Content>
347-
</DropdownMenu.Root>
348-
</Flex>
349-
)}
350306

351-
<Badge
352-
size="1"
353-
color={indicator.color}
354-
style={{ flexShrink: 0, fontSize: "10px", padding: "0 4px" }}
355-
>
356-
{indicator.label}
357-
</Badge>
358-
</Flex>
307+
<DropdownMenu.Root
308+
open={isDropdownOpen}
309+
onOpenChange={setIsDropdownOpen}
310+
>
311+
<Tooltip content="Open file">
312+
<DropdownMenu.Trigger>
313+
<IconButton
314+
size="1"
315+
variant="ghost"
316+
color="gray"
317+
onClick={(e) => e.stopPropagation()}
318+
style={{
319+
flexShrink: 0,
320+
width: "18px",
321+
height: "18px",
322+
padding: 0,
323+
}}
324+
>
325+
<FilePlus size={12} weight="regular" />
326+
</IconButton>
327+
</DropdownMenu.Trigger>
328+
</Tooltip>
329+
<DropdownMenu.Content size="1" align="end">
330+
{detectedApps
331+
.filter((app) => app.type !== "terminal")
332+
.map((app) => (
333+
<DropdownMenu.Item
334+
key={app.id}
335+
onSelect={() => handleOpenWith(app.id)}
336+
>
337+
<Flex align="center" gap="2">
338+
{app.icon ? (
339+
<img
340+
src={app.icon}
341+
width={16}
342+
height={16}
343+
alt=""
344+
style={{ borderRadius: "2px" }}
345+
/>
346+
) : (
347+
<CodeIcon size={16} weight="regular" />
348+
)}
349+
<Text size="1">{app.name}</Text>
350+
</Flex>
351+
</DropdownMenu.Item>
352+
))}
353+
<DropdownMenu.Separator />
354+
<DropdownMenu.Item onSelect={handleCopyPath}>
355+
<Flex align="center" gap="2">
356+
<CopyIcon size={16} weight="regular" />
357+
<Text size="1">Copy Path</Text>
358+
</Flex>
359+
</DropdownMenu.Item>
360+
</DropdownMenu.Content>
361+
</DropdownMenu.Root>
362+
</Flex>
363+
)}
364+
365+
<Badge
366+
size="1"
367+
color={indicator.color}
368+
style={{ flexShrink: 0, fontSize: "10px", padding: "0 4px" }}
369+
>
370+
{indicator.label}
371+
</Badge>
372+
</Flex>
373+
</Tooltip>
359374
);
360375
}
361376

0 commit comments

Comments
 (0)