diff --git a/app/components/CopyPathButton.tsx b/app/components/CopyPathButton.tsx
new file mode 100644
index 000000000..57950c5b7
--- /dev/null
+++ b/app/components/CopyPathButton.tsx
@@ -0,0 +1,74 @@
+import { ClipboardIcon, CogIcon } from "@heroicons/react/outline";
+import { useCallback, useState } from "react";
+import { CopyText } from "./CopyText";
+import { Body } from "./Primitives/Body";
+import { Dialog, DialogTrigger, DialogContent } from "./UI/Dialog";
+import { PathComponent } from '@jsonhero/path'
+import { getPathValue, languages } from "~/utilities/programmingLanguages";
+import classnames from "~/utilities/classnames";
+import { CopyPathPreferences } from "./CopyPathPreferences";
+import { usePreferences } from "./PreferencesProvider";
+
+export type CopyPathButtonProps = {
+ heroPathComponents: PathComponent[];
+ className?: string;
+};
+
+export function CopyPathButton({ heroPathComponents, className }: CopyPathButtonProps) {
+ const [copied, setCopied] = useState(false);
+ const [settingsOpen, setSettingsOpen] = useState(false)
+ const [preferences] = usePreferences()
+ const [variableName, setVariableName] = useState("");
+ const [useOptChaining, setUseOptionalChaining] = useState(false);
+
+ const onCopied = useCallback(() => {
+ setCopied(true);
+ const timeout = setTimeout(() => {
+ setCopied(false);
+ }, 1500);
+ }, [heroPathComponents]);
+ return (
+ <>
+
+ {copied ? (
+ Copied!
+ ) : (
+
+
+ Copy Path
+
+ )}
+
+
+ >
+ );
+}
diff --git a/app/components/CopyPathPreferences.tsx b/app/components/CopyPathPreferences.tsx
new file mode 100644
index 000000000..fb303fcfe
--- /dev/null
+++ b/app/components/CopyPathPreferences.tsx
@@ -0,0 +1,76 @@
+import { languages, canUseOptChaining } from "~/utilities/programmingLanguages";
+import { usePreferences } from "./PreferencesProvider";
+import { useState } from "react";
+
+export type CopyPathPreferencesProps = {
+ variableName: string;
+ onVariableNameChange: (value: string) => void;
+ useOptChaining: boolean;
+ onUseOptionalChainingChange: (value: boolean) => void;
+};
+
+export function CopyPathPreferences({
+ variableName,
+ onVariableNameChange,
+ useOptChaining,
+ onUseOptionalChainingChange,
+}: CopyPathPreferencesProps) {
+ const [preferences, setPreferences] = usePreferences();
+
+ return (
+
+ );
+}
diff --git a/app/components/InfoHeader.tsx b/app/components/InfoHeader.tsx
index d7bbebb50..0130b42eb 100644
--- a/app/components/InfoHeader.tsx
+++ b/app/components/InfoHeader.tsx
@@ -10,6 +10,7 @@ import { concatenated, getHierarchicalTypes } from "~/utilities/dataType";
import { formatRawValue } from "~/utilities/formatter";
import { isNullable } from "~/utilities/nullable";
import { CopyTextButton } from "./CopyTextButton";
+import { CopyPathButton } from "./CopyPathButton";
import { Body } from "./Primitives/Body";
import { LargeMono } from "./Primitives/LargeMono";
import { Title } from "./Primitives/Title";
@@ -45,7 +46,8 @@ export function InfoHeader({ relatedPaths }: InfoHeaderProps) {
return isNullable(relatedPaths, json);
}, [relatedPaths, json]);
- const [hovering, setHovering] = useState(false);
+ const [hoveringKey, setHoveringKey] = useState(false);
+ const [hoveringValue, setHoveringValue] = useState(false);
console.warn(selectedInfo);
const newPath = formattedSelectedInfo.replace(/^#/, "$").replace(/\//g, ".");
@@ -56,10 +58,24 @@ export function InfoHeader({ relatedPaths }: InfoHeaderProps) {
return (
-
-
+ setHoveringKey(true)}
+ onMouseLeave={() => setHoveringKey(false)}
+ >
+
{ selectedName ?? "nothing" }
+
+
+
setHovering(true)}
- onMouseLeave={() => setHovering(false)}
+ onMouseEnter={() => setHoveringValue(true)}
+ onMouseLeave={() => setHoveringValue(false)}
>
{isSelectedLeafNode && (
{selectedNode.name === "$ref" && checkPathExists(json, newPath) ? (
@@ -90,7 +106,7 @@ export function InfoHeader({ relatedPaths }: InfoHeaderProps) {
)}
;
+
type PreferencesContextType = [
- Preferences | undefined,
- Dispatch>
+ PartialPreferences,
+ Dispatch>
];
const PreferencesContext = createContext(undefined);
@@ -30,7 +35,7 @@ export function PreferencesProvider({
}: {
children: ReactNode;
}) {
- const [preferences, setPreferences] = useState();
+ const [preferences, setPreferences] = useState(PreferencesDefaults);
useEffect(() => {
const preferences = loadPreferences();
@@ -39,7 +44,7 @@ export function PreferencesProvider({
useEffect(() => {
if (preferences === undefined) return;
- savePreferences(preferences);
+ savePreferences(preferences as Preferences);
}, [preferences]);
return (
diff --git a/app/utilities/programmingLanguages.ts b/app/utilities/programmingLanguages.ts
new file mode 100644
index 000000000..d9e0de337
--- /dev/null
+++ b/app/utilities/programmingLanguages.ts
@@ -0,0 +1,25 @@
+import { PathComponent } from "@jsonhero/path"
+
+export enum languages {
+ javascript = "javascript",
+ python = "python"
+}
+
+export const canUseOptChaining = {
+ [languages.javascript]: true,
+ [languages.python]: false,
+}
+
+export const defaultLangauge = languages.javascript
+
+export const getPathValue = (language: languages, variableName: string, useOptChaining: boolean, paths: PathComponent[]): string => {
+ const path_base = variableName
+ switch(language) {
+ case languages.python:
+ return `${path_base}${paths.slice(1).map(p => p.isArray ? `[${p.toString()}]` : `["${p.toString()}"]`).join("")}`
+ case languages.javascript:
+ default:
+ return `${path_base}${paths.slice(1).map(p => p.isArray ? `${useOptChaining ? "?[" : "["}${p.toString()}]` : `${useOptChaining ? "?." : "."}${p.toString()}`).join("")}`
+ }
+}
+