Skip to content

Commit d6c47f0

Browse files
authored
Update theme and fix issues (#15)
* Refactor tool editor UI and routing structure - Updated RuntimePreview component to simplify parameter handling and improve rendering logic. - Enhanced Tool schema to include category and tags for better organization. - Reorganized routing for tools, introducing separate edit and index routes for better clarity. - Added a Navbar component for improved navigation and user experience. - Implemented filtering options for tools based on categories and tags. - Removed deprecated tool route and replaced it with a new structure for better maintainability. - Enhanced the main index route with a more engaging hero section and detailed feature descriptions. - Updated tests for GeneratedCommand component to align with new props structure. * Refactor ToolCard and GeneratedCommand components; improve UI and command handling * Refactor theme switcher and tool editor components; enhance UI and command handling * Enhance ThemeSwitcher button variant; add delete functionality to ToolCard and improve layout in RootComponent * chore: update dependencies and improve ToolCard component - Updated @tanstack/react-router and related packages to version 1.123.0 - Updated oxlint to version 1.4.0 - Refactored ToolCard component: - Removed unnecessary onClick from Card component - Added conditional rendering for tool description with a fallback message - Changed button text from "View" to "Go" - Modified defaultTool function to set description as undefined instead of an empty string - Updated styles in tools index route: - Changed border color to muted - Added shadow to buttons for better visibility - Adjusted key prop in ListComponent for ToolCard to handle potential undefined names * feat: add HoverCard component and integrate into ToolCard; update dependencies * fix: adjust animation duration in ThemeSwitcher; improve UI styling in ToolEditor and RouteComponent; update button variant for better dark mode support * fix: update parameter filtering in RuntimePreview to include global parameters; adjust layout spacing in Tool route * Fix formatting
1 parent f1641ab commit d6c47f0

28 files changed

+1364
-461
lines changed

bun.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
},
1919
"dependencies": {
2020
"@hookform/resolvers": "^4.1.3",
21+
"@radix-ui/react-hover-card": "^1.1.14",
2122
"@radix-ui/react-label": "^2.1.7",
2223
"@radix-ui/react-select": "^2.2.5",
2324
"@radix-ui/react-slot": "^1.2.3",

src/components/tags.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import { Badge } from "./ui/badge";
1818

1919
export interface TagsProps {
2020
tags: string[];
21-
id: string;
2221
maxCount?: number;
2322
onOpenChange?: (isOpen: boolean, tags: string[]) => void;
2423
}

src/components/theme-switcher.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,11 @@ type Theme = "dark" | "light" | "system";
77
const storageKey = "ui-theme";
88

99
export function ThemeSwitcher() {
10+
if (typeof window === "undefined") {
11+
return null;
12+
}
1013
const [theme, setTheme] = useState<Theme>(
11-
() => (localStorage.getItem(storageKey) as Theme) || "system"
14+
() => (localStorage.getItem(storageKey) as Theme) || "dark"
1215
);
1316
const ref = useRef<HTMLButtonElement>(null);
1417

@@ -47,7 +50,7 @@ export function ThemeSwitcher() {
4750
]
4851
},
4952
{
50-
duration: 500,
53+
duration: 400,
5154
easing: "ease-in-out",
5255
pseudoElement: "::view-transition-new(root)"
5356
}
@@ -65,8 +68,8 @@ export function ThemeSwitcher() {
6568

6669
return (
6770
<Button
68-
variant="link"
6971
size="icon"
72+
variant="ghost"
7073
className="rounded-full"
7174
onClick={() =>
7275
theme === "dark" ? toggleDarkMode("light") : toggleDarkMode("dark")

src/components/tool-card.tsx

Lines changed: 115 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,62 +1,139 @@
1-
import { Card, CardContent } from "@/components/ui/card";
1+
import {
2+
Card,
3+
CardAction,
4+
CardContent,
5+
CardFooter,
6+
CardHeader,
7+
CardTitle
8+
} from "@/components/ui/card";
29
import { Badge } from "@/components/ui/badge";
3-
import { CheckIcon, ScanIcon } from "lucide-react";
4-
import { cn } from "@/lib/utils";
510
import { Tool } from "@/lib/types/tool-editor";
11+
import { Button } from "./ui/button";
12+
import { Link, useNavigate } from "@tanstack/react-router";
13+
import { Edit2Icon, Trash2Icon } from "lucide-react";
14+
import {
15+
HoverCard,
16+
HoverCardTrigger,
17+
HoverCardContent
18+
} from "@/components/ui/hover-card";
19+
import React, { useRef, useEffect, useState } from "react";
620

721
export function ToolCard({
822
tool,
9-
isSelected = false
23+
isLocal = false,
24+
onDelete
1025
}: {
1126
tool: Partial<Tool>;
12-
isSelected?: boolean;
27+
isLocal?: boolean;
28+
onDelete?: (tool: Partial<Tool>) => void;
1329
}) {
1430
const supportedIO = [...tool.supportedInput!, ...tool.supportedOutput!];
31+
const navigation = useNavigate();
32+
const descRef = useRef<HTMLParagraphElement>(null);
33+
const [isOverflowing, setIsOverflowing] = useState(false);
34+
35+
useEffect(() => {
36+
const el = descRef.current;
37+
if (el) {
38+
setIsOverflowing(
39+
el.scrollHeight > el.clientHeight || el.scrollWidth > el.clientWidth
40+
);
41+
}
42+
}, [tool.description]);
43+
44+
const handleClick = () => {
45+
navigation({
46+
to: "/tools/$toolName",
47+
params: { toolName: tool.name!! },
48+
search: isLocal ? { newTool: tool.name } : {}
49+
});
50+
};
1551

1652
return (
17-
<Card
18-
className={cn(
19-
"group hover:shadow-md transition-all duration-200 hover:-translate-y-1 cursor-pointer relative overflow-hidden",
20-
isSelected && "ring-2 ring-primary"
21-
)}
22-
>
23-
<div
24-
className={cn(
25-
"absolute inset-0 bg-background/60 backdrop-blur-[1px] opacity-0 transition-opacity duration-200",
26-
isSelected && "opacity-100"
27-
)}
28-
/>
29-
<CardContent className="p-6 flex flex-col items-center justify-center gap-4 min-h-[200px] relative">
30-
<div
31-
className={cn(
32-
"text-4xl text-muted-foreground transition-colors",
33-
isSelected ? "text-primary" : "group-hover:text-primary"
53+
<Card className="hover:shadow-md w-72 h-72 flex flex-col gap-0 py-3">
54+
<CardHeader className="border-b [.border-b]:pb-1 flex items-center justify-between">
55+
<CardTitle className="font-semibold">{tool.displayName}</CardTitle>
56+
<CardAction>
57+
<Button
58+
variant="link"
59+
size="icon"
60+
className="text-foreground dark:text-primary"
61+
asChild
62+
>
63+
<Link
64+
to="/tools/$toolName/edit"
65+
params={{ toolName: tool.name!! }}
66+
{...(isLocal ? { search: { newTool: tool.name } } : {})}
67+
>
68+
<Edit2Icon className="size-4" />
69+
</Link>
70+
</Button>
71+
{isLocal && (
72+
<Button
73+
size="icon"
74+
variant="link"
75+
className="text-foreground dark:text-primary cursor-pointer"
76+
onClick={(e) => {
77+
e.preventDefault();
78+
e.stopPropagation();
79+
onDelete?.(tool);
80+
}}
81+
>
82+
<Trash2Icon className="size-4" />
83+
</Button>
84+
)}
85+
</CardAction>
86+
</CardHeader>
87+
<CardContent
88+
className="flex flex-col items-center justify-center gap-4 flex-1 align-top mb-6 cursor-pointer"
89+
onClick={handleClick}
90+
>
91+
<div className="w-full flex-1 flex items-center justify-center py-1">
92+
{tool.description ? (
93+
isOverflowing ? (
94+
<HoverCard openDelay={0}>
95+
<HoverCardTrigger asChild>
96+
<p className="p-1 line-clamp-4 overflow-ellipsis text-justify cursor-pointer text-foreground/60">
97+
{tool.description}
98+
</p>
99+
</HoverCardTrigger>
100+
<HoverCardContent className="max-w-xs text-sm">
101+
{tool.description}
102+
</HoverCardContent>
103+
</HoverCard>
104+
) : (
105+
<p
106+
ref={descRef}
107+
className="p-1 line-clamp-4 overflow-ellipsis text-justify"
108+
>
109+
{tool.description}
110+
</p>
111+
)
112+
) : (
113+
<p className="text-muted">No description available</p>
34114
)}
35-
>
36-
<ScanIcon />
37-
</div>
38-
<div className="text-lg font-semibold text-center relative z-10">
39-
{tool.displayName}
40115
</div>
41-
<div className="flex flex-wrap gap-2 justify-center relative z-10">
116+
117+
<div className="flex flex-wrap gap-2 justify-center relative z-10 justify-self-end self-end">
42118
{supportedIO &&
43119
supportedIO.map((type) => (
44120
<Badge key={type} variant="secondary" className="text-xs">
45121
{type}
46122
</Badge>
47123
))}
48124
</div>
49-
<div
50-
className={cn(
51-
"absolute bottom-4 left-1/2 -translate-x-1/2 transform opacity-0 transition-all duration-200",
52-
isSelected && "opacity-100"
53-
)}
54-
>
55-
<div className="bg-primary text-primary-foreground rounded-full p-1.5 shadow-lg">
56-
<CheckIcon className="w-4 h-4" />
57-
</div>
58-
</div>
59125
</CardContent>
126+
<CardFooter className="flex justify-center gap-2 w-full mt-auto">
127+
<Button className="flex-1" asChild>
128+
<Link
129+
to="/tools/$toolName"
130+
params={{ toolName: tool.name! }}
131+
{...(isLocal ? { search: { newTool: tool.name } } : {})}
132+
>
133+
Go
134+
</Link>
135+
</Button>
136+
</CardFooter>
60137
</Card>
61138
);
62139
}

src/components/tool-editor-ui/dialogs/parameter-details-dialog.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -397,7 +397,6 @@ export function ParameterDetailsDialog() {
397397

398398
<TagsComponent
399399
tags={parameter.metadata?.tags || []}
400-
id={parameter.id}
401400
onOpenChange={(onOpen, tags) => {
402401
if (!onOpen) {
403402
updateParameter({ metadata: { tags } });

src/components/tool-editor-ui/dialogs/saved-commands-dialog.tsx

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -7,41 +7,36 @@ import {
77
DialogFooter
88
} from "@/components/ui/dialog";
99
import { SaveIcon, CopyIcon, Trash2Icon } from "lucide-react";
10-
import { useStore } from "@tanstack/react-store";
11-
import {
12-
toolBuilderStore,
13-
toolBuilderActions,
14-
toolBuilderSelectors
15-
} from "@/components/tool-editor-ui/tool-editor.store";
1610
import { toast } from "sonner";
11+
import { SavedCommand } from "@/lib/types/tool-editor";
1712

18-
export function SavedCommandsDialog() {
19-
const isOpen = useStore(
20-
toolBuilderStore,
21-
(state) => state.dialogs.savedCommands
22-
);
23-
const savedCommands = useStore(toolBuilderStore, (state) =>
24-
toolBuilderSelectors.getSavedCommandsForCurrentTool(state)
25-
);
26-
27-
const handleClose = () => {
28-
toolBuilderActions.setSavedCommandsDialogOpen(false);
29-
};
13+
interface SavedCommandsDialogProps {
14+
isOpen: boolean;
15+
onOpenChange: (open: boolean) => void;
16+
savedCommands: SavedCommand[];
17+
onDeleteCommand: (commandId: string) => void;
18+
}
3019

20+
export function SavedCommandsDialog({
21+
isOpen,
22+
onOpenChange,
23+
savedCommands,
24+
onDeleteCommand
25+
}: SavedCommandsDialogProps) {
3126
const copyCommand = (command: string) => {
3227
navigator.clipboard.writeText(command);
3328
toast("Command copied!");
3429
};
3530

3631
const deleteCommand = (commandId: string) => {
37-
toolBuilderActions.removeSavedCommand(commandId);
32+
onDeleteCommand(commandId);
3833
toast("Command Removed", {
3934
description: "Saved command has been removed successfully."
4035
});
4136
};
4237

4338
return (
44-
<Dialog open={isOpen} onOpenChange={handleClose}>
39+
<Dialog open={isOpen} onOpenChange={onOpenChange}>
4540
<DialogContent className="max-w-4xl max-h-[80vh]">
4641
<DialogHeader>
4742
<DialogTitle className="flex items-center gap-2">
@@ -92,7 +87,7 @@ export function SavedCommandsDialog() {
9287
)}
9388

9489
<DialogFooter>
95-
<Button variant="outline" onClick={handleClose}>
90+
<Button variant="outline" onClick={() => onOpenChange(false)}>
9691
Close
9792
</Button>
9893
</DialogFooter>

src/components/tool-editor-ui/dialogs/tool-details-dialog.tsx

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
SupportedToolInputType,
2121
SupportedToolOutputType
2222
} from "@/lib/types/tool-editor";
23+
import { TagsComponent } from "@/components/tags";
2324

2425
const supportedInputOptions = [
2526
{ value: "StandardInput", label: "Standard Input" },
@@ -88,6 +89,16 @@ export function ToolDetailsDialog() {
8889
}
8990
/>
9091
</div>
92+
<div className="flex flex-col gap-3">
93+
<Label htmlFor="tool-category">Category</Label>
94+
<Input
95+
id="tool-category"
96+
value={tool.category}
97+
onChange={(e) =>
98+
toolBuilderActions.updateTool({ category: e.target.value })
99+
}
100+
/>
101+
</div>
91102
</div>
92103
<div className="grid grid-cols-2 gap-4">
93104
<div className="flex flex-col gap-3">
@@ -125,6 +136,14 @@ export function ToolDetailsDialog() {
125136
/>
126137
</div>
127138
</div>
139+
<TagsComponent
140+
tags={tool.tags || []}
141+
onOpenChange={(onOpen, tags) => {
142+
if (!onOpen) {
143+
toolBuilderActions.updateTool({ tags });
144+
}
145+
}}
146+
/>
128147
<div className="flex flex-col gap-3">
129148
<Label htmlFor="tool-description">Description</Label>
130149
<Textarea

0 commit comments

Comments
 (0)