Skip to content

Commit bd725de

Browse files
committed
fix #25: save the output as a file
1 parent d323e79 commit bd725de

File tree

6 files changed

+157
-7
lines changed

6 files changed

+157
-7
lines changed

package-lock.json

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

package.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"preview": "vite preview"
1414
},
1515
"dependencies": {
16+
"@formkit/tempo": "^0.1.2",
1617
"@icons-pack/react-simple-icons": "^10.2.0",
1718
"@monaco-editor/react": "^4.6.0",
1819
"@radix-ui/react-alert-dialog": "^1.1.6",
@@ -23,6 +24,7 @@
2324
"@radix-ui/react-select": "^2.1.4",
2425
"@radix-ui/react-slot": "^1.1.2",
2526
"@radix-ui/react-switch": "^1.1.3",
27+
"@radix-ui/react-tooltip": "^1.1.8",
2628
"class-variance-authority": "^0.7.1",
2729
"clsx": "^2.1.1",
2830
"cmdk": "^1.0.0",
@@ -41,6 +43,7 @@
4143
},
4244
"devDependencies": {
4345
"@eslint/js": "^9.17.0",
46+
"@types/file-saver": "^2.0.7",
4447
"@types/node": "^22.13.14",
4548
"@types/react": "^18.3.18",
4649
"@types/react-dom": "^18.3.5",
@@ -49,6 +52,7 @@
4952
"eslint": "^9.23.0",
5053
"eslint-plugin-react-hooks": "^5.2.0",
5154
"eslint-plugin-react-refresh": "^0.4.19",
55+
"file-saver": "^2.0.5",
5256
"globals": "^15.14.0",
5357
"peggy": "^4.2.0",
5458
"postcss": "^8.4.49",
@@ -58,4 +62,4 @@
5862
"vite": "^6.2.5",
5963
"vitest": "^3.0.9"
6064
}
61-
}
65+
}

src/components/download-button.tsx

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { Button, ButtonProps } from "@/components/ui/button";
2+
import { saveAs } from "file-saver";
3+
import { Download } from "lucide-react";
4+
import {
5+
Tooltip,
6+
TooltipContent,
7+
TooltipProvider,
8+
TooltipTrigger,
9+
} from "@/components/ui/tooltip";
10+
import { cn } from "@/lib/utils";
11+
import { useJSONPath } from "@/hooks/use-jsonpath";
12+
import { format } from "@formkit/tempo";
13+
14+
export const DownloadButton = ({ className }: ButtonProps) => {
15+
const { result } = useJSONPath();
16+
17+
const handleDownload = () => {
18+
const text = result.isValid ? JSON.stringify(result.values, null, 2) : "[]";
19+
const blob = new Blob([text], {
20+
type: "application/json",
21+
});
22+
saveAs(
23+
blob,
24+
`evaluation_results_${format(new Date(), "YYYYMMDD_HHmmss")}.json`
25+
);
26+
};
27+
28+
return (
29+
<TooltipProvider>
30+
<Tooltip>
31+
<TooltipTrigger asChild>
32+
<Button
33+
variant="outline"
34+
size="icon"
35+
className={cn("rounded-full", className)}
36+
onClick={handleDownload}
37+
>
38+
<Download />
39+
</Button>
40+
</TooltipTrigger>
41+
<TooltipContent>
42+
<p>Download file</p>
43+
</TooltipContent>
44+
</Tooltip>
45+
</TooltipProvider>
46+
);
47+
};

src/components/online-evaluator.tsx

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { JSONEditor } from "./editor/json-editor";
33
import { Result } from "./editor/result";
44
import { OutputPathSwitch } from "./output-path-switch";
55
import { useJSONPath } from "@/hooks/use-jsonpath";
6+
import { DownloadButton } from "./download-button";
67

78
export const JSONPathOnlineEvaluator = () => {
89
const { outputPaths, setOutputPaths } = useJSONPath();
@@ -13,17 +14,27 @@ export const JSONPathOnlineEvaluator = () => {
1314

1415
<div className="grid grid-cols-2 gap-4">
1516
<div>
16-
<h2 className="py-1 text-xl text-joe-green-950">Document</h2>
17+
<div className="flex justify-between items-center mb-1">
18+
<h2 className="py-1 text-xl text-joe-green-950">Document</h2>
19+
</div>
1720
<JSONEditor />
1821
</div>
1922
<div>
20-
<div className="flex justify-between">
23+
<div className="flex justify-between items-center mb-1">
2124
<h2 className="py-1 text-xl text-joe-green-950">
2225
Evaluation Results
2326
</h2>
24-
<OutputPathSwitch checked={outputPaths} onChange={setOutputPaths} />
27+
<div className="flex items-center gap-2">
28+
<OutputPathSwitch
29+
checked={outputPaths}
30+
onChange={setOutputPaths}
31+
/>
32+
</div>
33+
</div>
34+
<div className="relative">
35+
<Result outputPathMode={outputPaths} />
36+
<DownloadButton className="absolute bottom-2 right-6" />
2537
</div>
26-
<Result outputPathMode={outputPaths} />
2738
</div>
2839
</div>
2940
</div>

src/components/ui/tooltip.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import * as React from "react"
2+
import * as TooltipPrimitive from "@radix-ui/react-tooltip"
3+
4+
import { cn } from "@/lib/utils"
5+
6+
const TooltipProvider = TooltipPrimitive.Provider
7+
8+
const Tooltip = TooltipPrimitive.Root
9+
10+
const TooltipTrigger = TooltipPrimitive.Trigger
11+
12+
const TooltipContent = React.forwardRef<
13+
React.ElementRef<typeof TooltipPrimitive.Content>,
14+
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
15+
>(({ className, sideOffset = 4, ...props }, ref) => (
16+
<TooltipPrimitive.Portal>
17+
<TooltipPrimitive.Content
18+
ref={ref}
19+
sideOffset={sideOffset}
20+
className={cn(
21+
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
22+
className
23+
)}
24+
{...props}
25+
/>
26+
</TooltipPrimitive.Portal>
27+
))
28+
TooltipContent.displayName = TooltipPrimitive.Content.displayName
29+
30+
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }

src/index.css

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ h3 {
3434
--card-foreground: 240 10% 3.9%;
3535
--popover: 0 0% 100%;
3636
--popover-foreground: 240 10% 3.9%;
37-
--primary: 142.1 76.2% 36.3%;
37+
--primary: 175, 100%, 33%;
3838
--primary-foreground: 355.7 100% 97.3%;
3939
--secondary: 240 4.8% 95.9%;
4040
--secondary-foreground: 240 5.9% 10%;
@@ -46,7 +46,7 @@ h3 {
4646
--destructive-foreground: 0 0% 98%;
4747
--border: 240 5.9% 90%;
4848
--input: 240 5.9% 90%;
49-
--ring: 142.1 76.2% 36.3%;
49+
--ring: 175, 100%, 33%;
5050
--radius: 0.3rem;
5151
--chart-1: 12 76% 61%;
5252
--chart-2: 173 58% 39%;

0 commit comments

Comments
 (0)