Skip to content

Commit

Permalink
Merge pull request #31 from wp-graphql/feature/query-block-25
Browse files Browse the repository at this point in the history
Initial component
  • Loading branch information
josephfusco committed Nov 9, 2023
2 parents afbef5a + 58b2f48 commit 0041534
Show file tree
Hide file tree
Showing 16 changed files with 824 additions and 22 deletions.
6 changes: 3 additions & 3 deletions components/DocsSidebarNavigation.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,14 @@ export function DocsSidebarNavigation({ className, data, navigation }) {
<li key={section.title}>
<div className="flex items-center">
<Link href={section.href} className='block w-full'>
<h2 className="cursor-pointer font-display font-medium text-slate-900 dark:text-white hover:text-slate-600 dark:hover:text-gray-300">
<h2 className="cursor-pointer font-display font-medium text-slate-900 hover:text-slate-600 dark:text-white dark:hover:text-gray-300">
{section.title}
</h2>
</Link>
<div className="inline-flex items-center justify-center rounded-full transition-colors duration-300 hover:bg-gray-200 dark:hover:bg-gray-800 mr-0 ml-auto">
<div className="ml-auto mr-0 inline-flex items-center justify-center rounded-full transition-colors duration-300 hover:bg-gray-200 dark:hover:bg-gray-800">
<button
onClick={() => toggleSection(section.title)}
className="text-slate-900 transition-transform duration-300 dark:text-white p-2"
className="p-2 text-slate-900 transition-transform duration-300 dark:text-white"
>
<svg
className={clsx(
Expand Down
36 changes: 36 additions & 0 deletions components/DraggablePaneContainer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
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 (
<div style={containerStyle}>
<Allotment>
<Allotment.Pane>
<div style={innerPaneStyle}>{children[0]}</div>
</Allotment.Pane>
<Allotment.Pane>
<div style={innerPaneStyle}>{children[1]}</div>
</Allotment.Pane>
</Allotment>
</div>
);
};

DraggablePaneContainer.propTypes = {
children: PropTypes.arrayOf(PropTypes.node).isRequired,
height: PropTypes.string,
};

export default DraggablePaneContainer;
6 changes: 3 additions & 3 deletions components/FeatureTabsLeft.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,16 @@ const FeatureTabsLeft = (layout) => {
'group relative my-2 rounded-full px-4 py-1 lg:rounded-l-xl lg:rounded-r-none lg:p-6',
selectedIndex === featureIndex
? 'bg-slate-600 group-hover:text-white dark:bg-slate-800 lg:ring-1 lg:ring-inset lg:ring-white/10 lg:dark:bg-slate-700 '
: 'bg-gray-100 hover:bg-slate-600 group-hover:text-white dark:hover:bg-slate-800 lg:dark:hover:bg-slate-700',
: 'bg-gray-100 group-hover:text-white hover:bg-slate-600 dark:hover:bg-slate-800 lg:dark:hover:bg-slate-700',
)}
>
<h3>
<Tab
className={clsx(
'font-display text-lg [&:not(:focus-visible)]:focus:outline-none',
selectedIndex === featureIndex
? 'text-white hover:text-white group-hover:text-white dark:text-slate-200 dark:hover:text-slate-300 lg:dark:hover:text-slate-200'
: 'text-slate-800 hover:text-white group-hover:text-white dark:hover:text-slate-200',
? 'text-white group-hover:text-white hover:text-white dark:text-slate-200 dark:hover:text-slate-300 lg:dark:hover:text-slate-200'
: 'text-slate-800 group-hover:text-white hover:text-white dark:hover:text-slate-200',
)}
>
<span className="absolute inset-0 rounded-full lg:rounded-l-xl lg:rounded-r-none" />
Expand Down
128 changes: 128 additions & 0 deletions components/MiniGraphQL.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
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 (
<div className="mini-graphql flex w-full flex-col">
<DraggablePaneContainer>
<div className="query-panel h-full flex-1 overflow-auto">
<pre
ref={queryRef}
className="not-prose graphql-query content-editable overflow-auto p-1 dark:bg-gray-800 dark:text-white text-sm"
contentEditable={!loading}
onInput={handleQueryChange}
onBlur={handleBlur}
suppressContentEditableWarning={true}
/>
</div>
<div className="response-panel h-full flex-1 overflow-auto">
<div className="data-panel h-full">
{error && (
<pre className="not-prose p-1 text-red-500 text-sm">{error.message}</pre>
)}
{data && (
<pre className="not-prose json-data h-full overflow-auto p-1 dark:bg-gray-800 dark:text-white text-sm">
<code className="whitespace-pre-wrap">
{JSON.stringify(data, null, 2)}
</code>
</pre>
)}
</div>
</div>
</DraggablePaneContainer>
<div className="button-panel flex py-4">
<button
onClick={handleRunQuery}
disabled={loading}
className="run-query-button rounded bg-blue-500 px-4 py-2 text-sm text-white font-semibold hover:bg-blue-700 disabled:bg-blue-300 dark:bg-gray-700 dark:text-white dark:hover:bg-gray-600 dark:disabled:bg-gray-500 lg:text-base"
>
{loading ? 'Loading...' : data ? 'Reset' : 'Run Query'}
</button>
</div>
</div>
)
}
2 changes: 1 addition & 1 deletion components/Prose.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export function Prose({ as: Component = 'div', className, ...props }) {
// hr
'dark:prose-hr:border-slate-800',
// code
'prose-code:rounded-md prose-code:border prose-code:border-solid prose-code:border-gray-200 prose-code:bg-gray-100 prose-code:px-2.5 prose-code:py-0.5 prose-code:tracking-wide prose-code:before:content-none prose-code:after:content-none dark:prose-code:border-gray-700 dark:prose-code:bg-gray-800',
// 'prose-code:rounded-md prose-code:border prose-code:border-solid prose-code:border-gray-200 prose-code:bg-gray-100 prose-code:px-2.5 prose-code:py-0.5 prose-code:tracking-wide prose-code:before:content-none prose-code:after:content-none dark:prose-code:border-gray-700 dark:prose-code:bg-gray-800',
)}
{...props}
/>
Expand Down
12 changes: 12 additions & 0 deletions components/icons/CheckIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function CheckIcon() {
return (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M11.4669 3.72684C11.7558 3.91574 11.8369 4.30308 11.648 4.59198L7.39799 11.092C7.29783 11.2452 7.13556 11.3467 6.95402 11.3699C6.77247 11.3931 6.58989 11.3355 6.45446 11.2124L3.70446 8.71241C3.44905 8.48022 3.43023 8.08494 3.66242 7.82953C3.89461 7.57412 4.28989 7.55529 4.5453 7.78749L6.75292 9.79441L10.6018 3.90792C10.7907 3.61902 11.178 3.53795 11.4669 3.72684Z"
fill="currentColor"
/>
</svg>
)
}
12 changes: 12 additions & 0 deletions components/icons/PlayIcon.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export function PlayIcon() {
return (
<svg width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M3.24182 2.32181C3.3919 2.23132 3.5784 2.22601 3.73338 2.30781L12.7334 7.05781C12.8974 7.14436 13 7.31457 13 7.5C13 7.68543 12.8974 7.85564 12.7334 7.94219L3.73338 12.6922C3.5784 12.774 3.3919 12.7687 3.24182 12.6782C3.09175 12.5877 3 12.4252 3 12.25V2.75C3 2.57476 3.09175 2.4123 3.24182 2.32181ZM4 3.57925V11.4207L11.4288 7.5L4 3.57925Z"
fill="currentColor"
/>
</svg>
)
}
2 changes: 1 addition & 1 deletion components/ui/navigation-menu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ NavigationMenuList.displayName = NavigationMenuPrimitive.List.displayName
const NavigationMenuItem = NavigationMenuPrimitive.Item

const navigationMenuTriggerStyle = cva(
'group inline-flex h-10 w-max items-center justify-center rounded-md bg-transparent px-4 py-2 text-sm font-medium transition-colors hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50 data-[active]:bg-accent/50 data-[state=open]:bg-accent/50',
'group inline-flex h-10 w-max items-center justify-center rounded-md bg-transparent px-4 py-2 text-sm font-medium transition-colors data-[active]:bg-accent/50 data-[state=open]:bg-accent/50 hover:bg-accent hover:text-accent-foreground focus:bg-accent focus:text-accent-foreground focus:outline-none disabled:pointer-events-none disabled:opacity-50',
)

const NavigationMenuTrigger = React.forwardRef<
Expand Down
Loading

1 comment on commit 0041534

@headless-platform-by-wp-engine

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Check out the recent updates to your Atlas environment:

App Environment URL Build
acf.wpgraphql.com main https://hb…wered.com ✅ (logs)

Learn more about building on Atlas in our documentation.

Please sign in to comment.