Skip to content

Commit c8305a1

Browse files
authored
Merge pull request #91 from ashphy/ashphy/issue27
Bookmark feature
2 parents 07332ab + 3a0782f commit c8305a1

18 files changed

+562
-59
lines changed

eslint.config.js

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
1-
import js from '@eslint/js'
2-
import globals from 'globals'
3-
import reactHooks from 'eslint-plugin-react-hooks'
4-
import reactRefresh from 'eslint-plugin-react-refresh'
5-
import tseslint from 'typescript-eslint'
1+
import js from "@eslint/js";
2+
import globals from "globals";
3+
import reactHooks from "eslint-plugin-react-hooks";
4+
import reactRefresh from "eslint-plugin-react-refresh";
5+
import tseslint from "typescript-eslint";
66

77
export default tseslint.config(
8-
{ ignores: ['dist', 'src/lib/json-parser'] },
8+
{ ignores: ["dist", "src/lib/json-parser", "src/components/ui"] },
99
{
1010
extends: [js.configs.recommended, ...tseslint.configs.recommended],
11-
files: ['**/*.{ts,tsx}'],
11+
files: ["**/*.{ts,tsx}"],
1212
languageOptions: {
1313
ecmaVersion: 2020,
1414
globals: globals.browser,
1515
},
1616
plugins: {
17-
'react-hooks': reactHooks,
18-
'react-refresh': reactRefresh,
17+
"react-hooks": reactHooks,
18+
"react-refresh": reactRefresh,
1919
},
2020
rules: {
2121
...reactHooks.configs.recommended.rules,
22-
'react-refresh/only-export-components': [
23-
'warn',
22+
"react-refresh/only-export-components": [
23+
"warn",
2424
{ allowConstantExport: true },
2525
],
2626
},
27-
},
28-
)
27+
}
28+
);

package-lock.json

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

package.json

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,13 @@
1515
"dependencies": {
1616
"@icons-pack/react-simple-icons": "^10.2.0",
1717
"@monaco-editor/react": "^4.6.0",
18+
"@radix-ui/react-alert-dialog": "^1.1.6",
1819
"@radix-ui/react-collapsible": "^1.1.2",
1920
"@radix-ui/react-dialog": "^1.1.4",
2021
"@radix-ui/react-label": "^2.1.1",
2122
"@radix-ui/react-popover": "^1.1.4",
2223
"@radix-ui/react-select": "^2.1.4",
23-
"@radix-ui/react-slot": "^1.1.1",
24+
"@radix-ui/react-slot": "^1.1.2",
2425
"@radix-ui/react-switch": "^1.1.3",
2526
"class-variance-authority": "^0.7.1",
2627
"clsx": "^2.1.1",
@@ -34,7 +35,9 @@
3435
"react-github-btn": "^1.4.0",
3536
"react-share": "^5.1.2",
3637
"tailwind-merge": "^2.6.0",
37-
"tailwindcss-animate": "^1.0.7"
38+
"tailwindcss-animate": "^1.0.7",
39+
"usehooks-ts": "^3.1.1",
40+
"valibot": "^1.0.0"
3841
},
3942
"devDependencies": {
4043
"@eslint/js": "^9.17.0",
@@ -55,4 +58,4 @@
5558
"vite": "^6.2.2",
5659
"vitest": "^3.0.9"
5760
}
58-
}
61+
}

src/components/app-title.tsx

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import { SiGithub } from "@icons-pack/react-simple-icons";
2+
import { ShareButton } from "./share-button";
3+
import { ResetButton } from "./reset-button";
24

35
export const AppTitle = () => {
46
return (
@@ -7,24 +9,22 @@ export const AppTitle = () => {
79
w-full h-full px-4 flex items-center justify-between
810
bg-gradient-to-r from-joe-green-600 to-emerald-600"
911
>
10-
<h1 className="py-2 text-3xl text-white">
11-
JSONPath Online Evaluator
12-
{/* <small className="text-xl font-normal text-slate-100">
13-
{" "}
14-
- jsonpath.com
15-
</small> */}
16-
</h1>
17-
<div className="justify-self-end">
18-
<a
19-
href="https://github.com/ashphy/jsonpath-online-evaluator"
20-
target="_blank"
21-
className="inline-flex items-center gap-1 hover:underline"
22-
>
23-
<SiGithub
24-
color="white"
25-
title="View source code on GitHub: ashphy/jsonpath-online-evaluator"
26-
/>
27-
</a>
12+
<h1 className="py-2 text-3xl text-white">JSONPath Online Evaluator</h1>
13+
<div className="justify-self-end flex gap-1 items-center">
14+
<ResetButton />
15+
<ShareButton />
16+
<div className="pl-2">
17+
<a
18+
href="https://github.com/ashphy/jsonpath-online-evaluator"
19+
target="_blank"
20+
className="hover:underline"
21+
>
22+
<SiGithub
23+
color="white"
24+
title="View source code on GitHub: ashphy/jsonpath-online-evaluator"
25+
/>
26+
</a>
27+
</div>
2828
</div>
2929
</div>
3030
);

src/components/editor/json-editor.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ export const JSONEditor = () => {
6969
height="600px"
7070
path="json"
7171
defaultLanguage="json"
72-
defaultValue={document}
72+
value={document}
7373
loading="Loading..."
7474
onMount={handleEditorDidMount}
7575
onChange={handleOnChange}

src/components/online-evaluator.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ import { Query } from "./query";
22
import { JSONEditor } from "./editor/json-editor";
33
import { Result } from "./editor/result";
44
import { OutputPathSwitch } from "./output-path-switch";
5-
import { useState } from "react";
5+
import { useJSONPath } from "@/hooks/use-jsonpath";
66

77
export const JSONPathOnlineEvaluator = () => {
8-
const [outputPathMode, setOutputPathMode] = useState(false);
8+
const { outputPaths, setOutputPaths } = useJSONPath();
99

1010
return (
1111
<div className="w-full flex flex-col gap-4">
@@ -21,9 +21,9 @@ export const JSONPathOnlineEvaluator = () => {
2121
<h2 className="py-1 text-xl text-joe-green-950">
2222
Evaluation Results
2323
</h2>
24-
<OutputPathSwitch onChange={setOutputPathMode} />
24+
<OutputPathSwitch checked={outputPaths} onChange={setOutputPaths} />
2525
</div>
26-
<Result outputPathMode={outputPathMode} />
26+
<Result outputPathMode={outputPaths} />
2727
</div>
2828
</div>
2929
</div>

src/components/output-path-switch.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ import { Switch } from "@/components/ui/switch";
22
import { Label } from "@/components/ui/label";
33

44
interface Props {
5+
checked?: boolean;
56
onChange?: (pathOutput: boolean) => void;
67
}
78

8-
export const OutputPathSwitch = ({ onChange }: Props) => {
9+
export const OutputPathSwitch = ({ checked = false, onChange }: Props) => {
910
return (
1011
<div className="flex items-center space-x-2">
1112
<Switch
1213
id="output-paths"
14+
checked={checked}
1315
onCheckedChange={(checked) => onChange?.(checked)}
1416
/>
1517
<Label htmlFor="output-paths">Output Paths</Label>

src/components/reset-button.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { RotateCcw } from "lucide-react";
2+
import { Button } from "./ui/button";
3+
import { useJSONPath } from "@/hooks/use-jsonpath";
4+
import {
5+
AlertDialog,
6+
AlertDialogAction,
7+
AlertDialogCancel,
8+
AlertDialogContent,
9+
AlertDialogDescription,
10+
AlertDialogFooter,
11+
AlertDialogHeader,
12+
AlertDialogTitle,
13+
AlertDialogTrigger,
14+
} from "./ui/alert-dialog";
15+
16+
export const ResetButton = () => {
17+
const { reset } = useJSONPath();
18+
19+
return (
20+
<AlertDialog>
21+
<AlertDialogTrigger asChild>
22+
<Button variant="ghost" className="text-white">
23+
<RotateCcw />
24+
Reset
25+
</Button>
26+
</AlertDialogTrigger>
27+
<AlertDialogContent>
28+
<AlertDialogHeader>
29+
<AlertDialogTitle>Are you sure you want to reset?</AlertDialogTitle>
30+
<AlertDialogDescription>
31+
All of your query and code will be permanently deleted and cannot be
32+
recovered.
33+
</AlertDialogDescription>
34+
</AlertDialogHeader>
35+
<AlertDialogFooter>
36+
<AlertDialogCancel>Cancel</AlertDialogCancel>
37+
<AlertDialogAction asChild>
38+
<Button variant="destructive" onClick={reset}>
39+
Reset
40+
</Button>
41+
</AlertDialogAction>
42+
</AlertDialogFooter>
43+
</AlertDialogContent>
44+
</AlertDialog>
45+
);
46+
};

src/components/share-button.tsx

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { Check, Share2 } from "lucide-react";
2+
import { Button } from "./ui/button";
3+
import { useJSONPath } from "@/hooks/use-jsonpath";
4+
import { useCopyToClipboard, useInterval } from "usehooks-ts";
5+
import { useState } from "react";
6+
7+
export const ShareButton = () => {
8+
const { createShareURL } = useJSONPath();
9+
const [, copy] = useCopyToClipboard();
10+
11+
const [isShowCopy, setIsShowCopy] = useState(false);
12+
13+
useInterval(
14+
() => {
15+
setIsShowCopy(false);
16+
},
17+
isShowCopy ? 2000 : null
18+
);
19+
20+
const handleOnShare = async () => {
21+
setIsShowCopy(true);
22+
const shareURL = await createShareURL();
23+
copy(shareURL);
24+
};
25+
26+
return (
27+
<Button
28+
variant="ghost"
29+
className="text-white transition-all duration-700"
30+
onClick={handleOnShare}
31+
>
32+
{isShowCopy && (
33+
<>
34+
<Check />
35+
Copied
36+
</>
37+
)}
38+
{!isShowCopy && (
39+
<>
40+
<Share2 />
41+
Share
42+
</>
43+
)}
44+
</Button>
45+
);
46+
};

0 commit comments

Comments
 (0)