Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 58 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"preview": "vite preview"
},
"dependencies": {
"@formkit/tempo": "^0.1.2",
"@icons-pack/react-simple-icons": "^10.2.0",
"@monaco-editor/react": "^4.6.0",
"@radix-ui/react-alert-dialog": "^1.1.6",
Expand All @@ -23,6 +24,7 @@
"@radix-ui/react-select": "^2.1.4",
"@radix-ui/react-slot": "^1.1.2",
"@radix-ui/react-switch": "^1.1.3",
"@radix-ui/react-tooltip": "^1.1.8",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
Expand All @@ -41,6 +43,7 @@
},
"devDependencies": {
"@eslint/js": "^9.17.0",
"@types/file-saver": "^2.0.7",
"@types/node": "^22.13.14",
"@types/react": "^18.3.18",
"@types/react-dom": "^18.3.5",
Expand All @@ -49,6 +52,7 @@
"eslint": "^9.23.0",
"eslint-plugin-react-hooks": "^5.2.0",
"eslint-plugin-react-refresh": "^0.4.19",
"file-saver": "^2.0.5",
"globals": "^15.14.0",
"peggy": "^4.2.0",
"postcss": "^8.4.49",
Expand All @@ -58,4 +62,4 @@
"vite": "^6.2.5",
"vitest": "^3.0.9"
}
}
}
47 changes: 47 additions & 0 deletions src/components/download-button.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Button, ButtonProps } from "@/components/ui/button";
import { saveAs } from "file-saver";
import { Download } from "lucide-react";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { cn } from "@/lib/utils";
import { useJSONPath } from "@/hooks/use-jsonpath";
import { format } from "@formkit/tempo";

export const DownloadButton = ({ className }: ButtonProps) => {
const { result } = useJSONPath();

const handleDownload = () => {
const text = result.isValid ? JSON.stringify(result.values, null, 2) : "[]";
const blob = new Blob([text], {
type: "application/json",
});
saveAs(
blob,
`evaluation_results_${format(new Date(), "YYYYMMDD_HHmmss")}.json`
);
};

return (
<TooltipProvider>
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="outline"
size="icon"
className={cn("rounded-full", className)}
onClick={handleDownload}
>
<Download />
</Button>
</TooltipTrigger>
<TooltipContent>
<p>Download file</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
);
};
57 changes: 57 additions & 0 deletions src/components/drop-zone.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Upload } from "lucide-react";
import { ReactNode, useState } from "react";

interface DropZoneProps {
onDrop?: (file: File) => void;
children: ReactNode;
}

export const DropZone = ({ onDrop, children }: DropZoneProps) => {
const [isDragging, setIsDragging] = useState(false);

const handleOnDrop = (e: React.DragEvent<HTMLDivElement>) => {
e.preventDefault();
setIsDragging(false);
const file = e.dataTransfer.files[0];
if (file) {
onDrop?.(file);
}
};

return (
<div
onDrop={handleOnDrop}
onDragOver={(e) => {
setIsDragging(true);
e.preventDefault();
}}
onDragEnter={() => setIsDragging(true)}
onDragLeave={() => setIsDragging(false)}
data-drag={isDragging ? "true" : "false"}
className="relative"
>
{children}
<div
data-drag={isDragging ? "true" : "false"}
className="
invisible data-[drag=true]:visible opacity-0 data-[drag=true]:opacity-80
absolute flex w-full h-full top-0 left-0 p-2 bg-white
transition-opacity duration-200
"
>
<div
className="
flex flex-col items-center justify-center gap-4
w-full h-full
border-2 border-dashed border-joe-green-600 rounded-lg text-lg
"
>
<div>Drop JSON file here</div>
<div>
<Upload />
</div>
</div>
</div>
</div>
);
};
50 changes: 31 additions & 19 deletions src/components/editor/json-editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
findSmallestNode,
generateNormalizedPathNode,
} from "@/lib/normalized-path";
import { DropZone } from "../drop-zone";

export const JSONEditor = () => {
const { document, setDocument, jsonDocument } = useJSONPath();
Expand Down Expand Up @@ -63,25 +64,36 @@ export const JSONEditor = () => {
setDocument(value || "");
};

const handleOnDrop = (file: File) => {
const reader = new FileReader();
reader.onload = (event) => {
const content = event.target?.result as string;
setDocument(content);
};
reader.readAsText(file);
};

return (
<Editor
className={cn("border-2", jsonDocument.error && "border-red-400")}
height="600px"
path="json"
defaultLanguage="json"
value={document}
loading="Loading..."
onMount={handleEditorDidMount}
onChange={handleOnChange}
options={{
wordWrap: "on",
minimap: {
enabled: false,
},
scrollBeyondLastLine: false,
formatOnPaste: true,
formatOnType: true,
}}
/>
<DropZone onDrop={handleOnDrop}>
<Editor
className={cn("border-2", jsonDocument.error && "border-red-400")}
height="600px"
path="json"
defaultLanguage="json"
value={document}
loading="Loading..."
onMount={handleEditorDidMount}
onChange={handleOnChange}
options={{
wordWrap: "on",
minimap: {
enabled: false,
},
scrollBeyondLastLine: false,
formatOnPaste: true,
formatOnType: true,
}}
/>
</DropZone>
);
};
68 changes: 68 additions & 0 deletions src/components/import-file.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { useRef } from "react";
import { Button } from "./ui/button";
import { useJSONPath } from "@/hooks/use-jsonpath";

export const ImportFile = () => {
const { setDocument } = useJSONPath();
const inputRef = useRef<HTMLInputElement>(null);

const handleOnClick = () => {
inputRef.current?.click();
};

const handleOnInput = (event: React.ChangeEvent<HTMLInputElement>) => {
const file = event.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = (event) => {
const content = event.target?.result as string;
setDocument(content);
};
reader.readAsText(file);
}
};

return (
<div>
<Button variant="outline" onClick={handleOnClick}>
Import File
</Button>
<input
ref={inputRef}
className="hidden"
type="file"
onInput={handleOnInput}
accept="
.json,
.jsonl,
.ndjson,
.geojson,
.topojson,
.jwt,
.webmanifest,
.har,
.mcstructure,
.eslintrc,
.prettierrc,
.babelrc,
.code-snippets,
.ipynb,
.vg,
.vl,
.template,
application/json,
application/geo+json,
application/x-ndjson,
application/jsonlines,
application/schema+json,
application/jwt,
application/feed+json,
application/vnd.oai.openapi+json,
application/vnd.swagger+json,
application/manifest+json,
application/x-ipynb+json,
"
></input>
</div>
);
};
Loading