From 6de1e38526d23b40eb45f223d47073d62d5b525a Mon Sep 17 00:00:00 2001 From: Joe Fusco Date: Thu, 9 Nov 2023 12:44:07 -0500 Subject: [PATCH 1/4] Add shadcn skeleton Signed-off-by: Joe Fusco --- components/ui/skeleton.tsx | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 components/ui/skeleton.tsx diff --git a/components/ui/skeleton.tsx b/components/ui/skeleton.tsx new file mode 100644 index 0000000..d7e45f7 --- /dev/null +++ b/components/ui/skeleton.tsx @@ -0,0 +1,15 @@ +import { cn } from "@/lib/utils" + +function Skeleton({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
+ ) +} + +export { Skeleton } From 74053b8f15816a286804493a59767d6ec33a1660 Mon Sep 17 00:00:00 2001 From: Joe Fusco Date: Fri, 10 Nov 2023 13:21:23 -0500 Subject: [PATCH 2/4] Add shadcn dependencies Signed-off-by: Joe Fusco --- components/ui/scroll-area.tsx | 53 +++++++++++++++++++++++++++++++++ components/ui/tabs.tsx | 55 +++++++++++++++++++++++++++++++++++ package-lock.json | 42 +++++++++++++++++++++++++- package.json | 3 +- 4 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 components/ui/scroll-area.tsx create mode 100644 components/ui/tabs.tsx diff --git a/components/ui/scroll-area.tsx b/components/ui/scroll-area.tsx new file mode 100644 index 0000000..2426616 --- /dev/null +++ b/components/ui/scroll-area.tsx @@ -0,0 +1,53 @@ +"use client" + +import * as React from "react" +import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" + +import { cn } from "@/lib/utils" + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + {children} + + + + +)) +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, orientation = "vertical", ...props }, ref) => ( + + + +)) +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName + +export { ScrollArea, ScrollBar } diff --git a/components/ui/tabs.tsx b/components/ui/tabs.tsx new file mode 100644 index 0000000..0f4caeb --- /dev/null +++ b/components/ui/tabs.tsx @@ -0,0 +1,55 @@ +"use client" + +import * as React from "react" +import * as TabsPrimitive from "@radix-ui/react-tabs" + +import { cn } from "@/lib/utils" + +const Tabs = TabsPrimitive.Root + +const TabsList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsList.displayName = TabsPrimitive.List.displayName + +const TabsTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsTrigger.displayName = TabsPrimitive.Trigger.displayName + +const TabsContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)) +TabsContent.displayName = TabsPrimitive.Content.displayName + +export { Tabs, TabsList, TabsTrigger, TabsContent } diff --git a/package-lock.json b/package-lock.json index 0c94daf..8426b0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,8 +24,9 @@ "@radix-ui/react-label": "^2.0.1", "@radix-ui/react-navigation-menu": "^1.1.3", "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-separator": "^1.0.2", - "@radix-ui/react-tabs": "^1.0.3", + "@radix-ui/react-tabs": "^1.0.4", "@sindresorhus/slugify": "^2.1.1", "@tailwindcss/typography": "^0.5.8", "acorn": "^8.8.1", @@ -3944,6 +3945,14 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@radix-ui/number": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.0.1.tgz", + "integrity": "sha512-T5gIdVO2mmPW3NNhjNgEP3cqMXjXL9UbO0BzWcXfvdBs+BohbQxvd/K5hSVKmn9/lbTdsQVKbUcP5WLCwvUbBg==", + "dependencies": { + "@babel/runtime": "^7.13.10" + } + }, "node_modules/@radix-ui/primitive": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.0.1.tgz", @@ -4542,6 +4551,37 @@ } } }, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.0.5.tgz", + "integrity": "sha512-b6PAgH4GQf9QEn8zbT2XUHpW5z8BzqEc7Kl11TwDrvuTrxlkcjTD5qa/bxgKr+nmuXKu4L/W5UZ4mlP/VG/5Gw==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@radix-ui/number": "1.0.1", + "@radix-ui/primitive": "1.0.1", + "@radix-ui/react-compose-refs": "1.0.1", + "@radix-ui/react-context": "1.0.1", + "@radix-ui/react-direction": "1.0.1", + "@radix-ui/react-presence": "1.0.1", + "@radix-ui/react-primitive": "1.0.3", + "@radix-ui/react-use-callback-ref": "1.0.1", + "@radix-ui/react-use-layout-effect": "1.0.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0", + "react-dom": "^16.8 || ^17.0 || ^18.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, "node_modules/@radix-ui/react-separator": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.0.3.tgz", diff --git a/package.json b/package.json index d1c015b..ca7cc30 100644 --- a/package.json +++ b/package.json @@ -30,8 +30,9 @@ "@radix-ui/react-label": "^2.0.1", "@radix-ui/react-navigation-menu": "^1.1.3", "@radix-ui/react-popover": "^1.0.7", + "@radix-ui/react-scroll-area": "^1.0.5", "@radix-ui/react-separator": "^1.0.2", - "@radix-ui/react-tabs": "^1.0.3", + "@radix-ui/react-tabs": "^1.0.4", "@sindresorhus/slugify": "^2.1.1", "@tailwindcss/typography": "^0.5.8", "acorn": "^8.8.1", From ee569c1d85415cdd5ad386f65b993cf72d6830b9 Mon Sep 17 00:00:00 2001 From: Joe Fusco Date: Mon, 13 Nov 2023 17:29:12 -0500 Subject: [PATCH 3/4] Use official GraphiQL editor Signed-off-by: Joe Fusco --- components/DraggablePaneContainer.jsx | 36 - components/LayoutArchive.jsx | 1 + components/MiniGraphQL.jsx | 128 --- components/MiniGraphiQL.jsx | 158 ++++ components/SiteHeader.jsx | 4 +- components/ThemeProvider.jsx | 8 + components/ThemeSelector.jsx | 166 +--- components/ui/dropdown-menu.tsx | 205 ++++ components/ui/input.tsx | 12 +- components/ui/scroll-area.tsx | 53 -- package-lock.json | 1194 ++++++++++++------------ package.json | 8 +- pages/_app.js | 38 +- pages/_document.js | 42 +- styles/mini-graphiql-client.module.css | 50 + tailwind.config.js | 1 - wp-blocks/AcfGraphqlQuery.js | 8 +- wp-templates/single-field_type.js | 56 +- 18 files changed, 1144 insertions(+), 1024 deletions(-) delete mode 100644 components/DraggablePaneContainer.jsx delete mode 100644 components/MiniGraphQL.jsx create mode 100644 components/MiniGraphiQL.jsx create mode 100644 components/ThemeProvider.jsx create mode 100644 components/ui/dropdown-menu.tsx delete mode 100644 components/ui/scroll-area.tsx create mode 100644 styles/mini-graphiql-client.module.css diff --git a/components/DraggablePaneContainer.jsx b/components/DraggablePaneContainer.jsx deleted file mode 100644 index 343c4b9..0000000 --- a/components/DraggablePaneContainer.jsx +++ /dev/null @@ -1,36 +0,0 @@ -import { Allotment } from "allotment"; -import PropTypes from "prop-types"; -import React from "react"; -import "allotment/dist/style.css"; - -// DraggablePaneContainer: A component that uses Allotment to create a resizable pane container. -// Fixed height is set on the container wrapping the Allotment component. -const DraggablePaneContainer = ({ children, height = '500px' }) => { - // Ensure children is an array with two elements for two panes. - if (children.length !== 2) { - throw new Error("DraggablePaneContainer requires exactly two children."); - } - - const containerStyle = { height }; - const innerPaneStyle = { overflowY: "auto", height: "100%" }; - - return ( -
- - -
{children[0]}
-
- -
{children[1]}
-
-
-
- ); -}; - -DraggablePaneContainer.propTypes = { - children: PropTypes.arrayOf(PropTypes.node).isRequired, - height: PropTypes.string, -}; - -export default DraggablePaneContainer; diff --git a/components/LayoutArchive.jsx b/components/LayoutArchive.jsx index e4d219e..45c02d3 100644 --- a/components/LayoutArchive.jsx +++ b/components/LayoutArchive.jsx @@ -1,5 +1,6 @@ import { gql } from '@apollo/client' import { flatListToHierarchical } from '@faustwp/core' +import Head from 'next/head' import { FooterNavigation } from './FooterNavigation' import { PrimaryNavigation } from './PrimaryNavigation' diff --git a/components/MiniGraphQL.jsx b/components/MiniGraphQL.jsx deleted file mode 100644 index 7faf39e..0000000 --- a/components/MiniGraphQL.jsx +++ /dev/null @@ -1,128 +0,0 @@ -import hljs from 'highlight.js/lib/core' -import graphql from 'highlight.js/lib/languages/graphql' -import json from 'highlight.js/lib/languages/json' -import React, { useState, useEffect, useRef } from 'react' - -import 'highlight.js/styles/atom-one-dark.css' -import DraggablePaneContainer from './DraggablePaneContainer' - -// Register GraphQL and JSON for syntax highlighting -hljs.registerLanguage('graphql', graphql) -hljs.registerLanguage('json', json) - -export function MiniGraphQL({ initialQuery, initialVariables, endpoint }) { - const [query, setQuery] = useState(initialQuery || '') - const [variables, setVariables] = useState(initialVariables || {}) - const [data, setData] = useState(null) - const [loading, setLoading] = useState(false) - const [error, setError] = useState(null) - const queryRef = useRef(null) - - // eslint-disable-next-line react-hooks/exhaustive-deps - useEffect(highlightQuery, []) // Highlight query on mount - - function highlightQuery() { - if (query && queryRef.current) { - queryRef.current.innerHTML = hljs.highlight(query, { - language: 'graphql', - }).value - } - } - - function resetForm() { - setQuery(initialQuery || '') // Reset query to initial - setVariables(initialVariables || {}) // Reset variables to initial - setData(null) // Clear fetched data - setError(null) // Clear any errors - } - - async function fetchData() { - if (loading) return // Prevent fetching if already loading - - setLoading(true) - setError(null) - - try { - const response = await fetch(endpoint, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ query, variables }), - }) - - const result = await response.json() - if (response.ok && result.data) { - setData(result.data) - } else { - setError( - new Error( - result.errors?.map((e) => e.message).join('\n') || - 'Error fetching data', - ), - ) - } - } catch (e) { - setError(e) - } finally { - setLoading(false) - } - } - - function handleQueryChange() { - if (queryRef.current) { - setQuery(queryRef.current.textContent) - resetForm() // Reset the form when query changes - } - } - - function handleBlur() { - highlightQuery() // Re-highlight the query on blur - } - - function handleRunQuery() { - if (data) { - resetForm() // Act as reset if data is present - } else { - fetchData() // Fetch data if no data present - } - } - - return ( -
- -
-
-        
-
-
- {error && ( -
{error.message}
- )} - {data && ( -
-                
-                  {JSON.stringify(data, null, 2)}
-                
-              
- )} -
-
-
-
- -
-
- ) -} diff --git a/components/MiniGraphiQL.jsx b/components/MiniGraphiQL.jsx new file mode 100644 index 0000000..35b0bfe --- /dev/null +++ b/components/MiniGraphiQL.jsx @@ -0,0 +1,158 @@ +import React, { useEffect, useState } from 'react'; +import PropTypes from 'prop-types'; +import { useTheme } from 'next-themes'; + +const MiniGraphiQLClient = ({ initialQuery, initialVariables, endpoint, readOnly }) => { + const [GraphiQL, setGraphiQL] = useState(null); + const { theme, resolvedTheme } = useTheme(); + + useEffect(() => { + let isMounted = true; + (async () => { + if (typeof window !== 'undefined') { + try { + const GraphiQLModule = await import('graphiql'); + await import('graphiql/graphiql.min.css'); + if (isMounted) { + setGraphiQL(() => GraphiQLModule.default); + } + } catch (error) { + console.error('Failed to load GraphiQL module:', error); + } + } + })(); + + return () => { + isMounted = false; + }; + }, []); + + useEffect(() => { + if (typeof window !== 'undefined') { + localStorage.removeItem('graphiql:tabState'); + localStorage.setItem('graphiql:theme', theme); + + // Check for the theme and update the body class + const bodyClassList = document.body.classList; + if (theme === 'dark') { + bodyClassList.add('graphiql-dark'); + } else { + bodyClassList.remove('graphiql-dark'); + } + } + }, [theme]); + + const fetcher = async (graphQLParams) => { + try { + const response = await fetch(endpoint, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(graphQLParams), + }); + + if (!response.ok) { + throw new Error(`Network response was not ok: ${response.statusText}`); + } + + return await response.json(); + } catch (error) { + console.error('Error fetching data:', error); + throw error; // Re-throw to make sure GraphiQL displays the error + } + }; + + let parsedVariables = initialVariables; + if (typeof initialVariables === 'string') { + try { + parsedVariables = JSON.parse(initialVariables); + } catch (e) { + console.error('Failed to parse variables as JSON:', e); + } + } + + const containerStyles = { + height: '80vh', + maxHeight: 'auto', + borderRadius: '4px', + padding: '0.5rem', + display: 'flex', + flex: '1 1 0%', + }; + + const graphiqlStyles = ` + :root { + color-scheme: ${theme}; + } + .graphiql-container { + background-color: transparent !important; + font-size: 14px; + } + .graphiql-container * { + box-shadow: none !important; + } + .graphiql-container .graphiql-editor-tools button:nth-child(2) { + display: none; + } + .graphiql-container .graphiql-editors { + border-radius: 2px; + } + .graphiql-container .graphiql-editors.full-height { + margin-top: 8px; + } + .graphiql-container .graphiql-query-editor { + border-bottom: 0; + padding: 6px; + column-gap: 6px; + } + .graphiql-container .graphiql-response .result-window { + padding-top: 8px; + } + .graphiql-container .graphiql-session-header { + display: none; + } + .graphiql-container .graphiql-sessions { + border-radius: 2px; + } + .graphiql-container .graphiql-sidebar { + display: none; + } + .graphiql-toolbar button:nth-child(2) { + display: none; /* prettify */ + } + .graphiql-toolbar button:nth-child(3) { + display: none; /* merge */ + } + `; + + return ( +
+