Some fixes

This commit is contained in:
Gregory Schier
2025-07-07 13:52:54 -07:00
parent 01f9c072a7
commit 7a11da42af
2 changed files with 86 additions and 36 deletions

View File

@@ -4,14 +4,14 @@ import classNames from 'classnames';
import type { GraphQLField, GraphQLInputField, GraphQLType } from 'graphql'; import type { GraphQLField, GraphQLInputField, GraphQLType } from 'graphql';
import { import {
getNamedType, getNamedType,
isEnumType,
isInputObjectType, isInputObjectType,
isInterfaceType,
isListType, isListType,
isNonNullType, isNonNullType,
isObjectType, isObjectType,
isScalarType, isScalarType,
isEnumType,
isUnionType, isUnionType,
isInterfaceType,
} from 'graphql'; } from 'graphql';
import { useAtomValue } from 'jotai'; import { useAtomValue } from 'jotai';
import { ReactNode, useState } from 'react'; import { ReactNode, useState } from 'react';
@@ -45,27 +45,40 @@ export function GraphQLDocsExplorer() {
return ( return (
<div> <div>
{activeItem == null ? ( {activeItem == null ? (
<div className="flex flex-col gap-3"> <div className="flex flex-col gap-3 overflow-auto h-full">
<Subheading>Root Types</Subheading> <Heading>Root Types</Heading>
<GqlTypeRow name="query" item={qryItem} setItem={setActiveItem} className="!my-0" />
<GqlTypeRow name="mutation" item={mutItem} setItem={setActiveItem} className="!my-0" />
<GqlTypeRow <GqlTypeRow
name="subscription" name={{ value: 'query', color: 'primary' }}
item={qryItem}
setItem={setActiveItem}
className="!my-0"
/>
<GqlTypeRow
name={{ value: 'mutation', color: 'primary' }}
item={mutItem}
setItem={setActiveItem}
className="!my-0"
/>
<GqlTypeRow
name={{ value: 'subscription', color: 'primary' }}
item={subItem} item={subItem}
setItem={setActiveItem} setItem={setActiveItem}
className="!my-0" className="!my-0"
/> />
<Subheading>All Schema Types</Subheading> <Subheading>All Schema Types</Subheading>
{Object.keys(allTypes).map((typeName) => { <Markdown>{graphqlSchema.description ?? null}</Markdown>
const t = allTypes[typeName]!; <div className="flex flex-col gap-1">
return ( {Object.keys(allTypes).map((typeName) => {
<GqlTypeLink const t = allTypes[typeName]!;
color="notice" return (
item={{ kind: 'type', type: t, from: null }} <GqlTypeLink
setItem={setActiveItem} color="notice"
/> item={{ kind: 'type', type: t, from: null }}
); setItem={setActiveItem}
})} />
);
})}
</div>
</div> </div>
) : ( ) : (
<div className="h-full grid grid-rows-[auto_minmax(0,1fr)] gap-y-3"> <div className="h-full grid grid-rows-[auto_minmax(0,1fr)] gap-y-3">
@@ -113,7 +126,7 @@ function GqlTypeInfo({
const heading = ( const heading = (
<div className="mb-3"> <div className="mb-3">
<h1 className="text-2xl font-semibold">{name}</h1> <h1 className="text-2xl font-semibold">{name}</h1>
<Markdown className="!text-text-subtle italic">{description ?? 'No description'}</Markdown> <Markdown className="!text-text-subtle italic">{description || 'No description'}</Markdown>
</div> </div>
); );
@@ -133,7 +146,11 @@ function GqlTypeInfo({
const fieldItem: ExplorerItem = { kind: 'field', type: field, from: item }; const fieldItem: ExplorerItem = { kind: 'field', type: field, from: item };
return ( return (
<div key={`${field.type}::${field.name}`} className="my-4"> <div key={`${field.type}::${field.name}`} className="my-4">
<GqlTypeRow item={fieldItem} setItem={setItem} name={fieldName} /> <GqlTypeRow
item={fieldItem}
setItem={setItem}
name={{ value: fieldName, color: 'primary' }}
/>
</div> </div>
); );
})} })}
@@ -182,7 +199,7 @@ function GqlTypeInfo({
{values.map((v) => ( {values.map((v) => (
<div key={v.name} className="my-4"> <div key={v.name} className="my-4">
<span className="text-primary">{v.value}</span> <span className="text-primary">{v.value}</span>
<Markdown className="!text-text-subtle">{v.description ?? ''}</Markdown> <Markdown className="!text-text-subtle">{v.description ?? null}</Markdown>
</div> </div>
))} ))}
</div> </div>
@@ -204,7 +221,7 @@ function GqlTypeInfo({
{item.type.args.map((a) => ( {item.type.args.map((a) => (
<div key={a.type + '::' + a.name} className="my-4"> <div key={a.type + '::' + a.name} className="my-4">
<GqlTypeRow <GqlTypeRow
name={a.name} name={{ value: a.name, color: 'info' }}
item={{ kind: 'input_field', type: a, from: item }} item={{ kind: 'input_field', type: a, from: item }}
setItem={setItem} setItem={setItem}
/> />
@@ -231,7 +248,11 @@ function GqlTypeInfo({
}; };
return ( return (
<div key={`${field.type}::${field.name}`} className="my-4"> <div key={`${field.type}::${field.name}`} className="my-4">
<GqlTypeRow item={fieldItem} setItem={setItem} name={fieldName} /> <GqlTypeRow
item={fieldItem}
setItem={setItem}
name={{ value: fieldName, color: 'primary' }}
/>
</div> </div>
); );
})} })}
@@ -254,7 +275,11 @@ function GqlTypeInfo({
}; };
return ( return (
<div key={`${field.type}::${field.name}`} className="my-4"> <div key={`${field.type}::${field.name}`} className="my-4">
<GqlTypeRow item={fieldItem} setItem={setItem} name={fieldName} /> <GqlTypeRow
item={fieldItem}
setItem={setItem}
name={{ value: fieldName, color: 'primary' }}
/>
</div> </div>
); );
})} })}
@@ -274,7 +299,11 @@ function GqlTypeInfo({
const fieldItem: ExplorerItem = { kind: 'field', type: field, from: item }; const fieldItem: ExplorerItem = { kind: 'field', type: field, from: item };
return ( return (
<div key={`${field.type}::${field.name}`} className="my-4"> <div key={`${field.type}::${field.name}`} className="my-4">
<GqlTypeRow item={fieldItem} setItem={setItem} name={fieldName} /> <GqlTypeRow
item={fieldItem}
setItem={setItem}
name={{ value: fieldName, color: 'primary' }}
/>
</div> </div>
); );
})} })}
@@ -295,7 +324,7 @@ function GqlTypeRow({
hideDescription, hideDescription,
}: { }: {
item: ExplorerItem; item: ExplorerItem;
name?: string; name?: { value: string; color: Color };
description?: string | null; description?: string | null;
setItem: (t: ExplorerItem) => void; setItem: (t: ExplorerItem) => void;
className?: string; className?: string;
@@ -309,12 +338,26 @@ function GqlTypeRow({
child = ( child = (
<> <>
<div> <div>
{name && <span className="text-primary">{name}:</span>}{' '} {name && (
<span
className={classNames(
name?.color === 'danger' && 'text-danger',
name?.color === 'primary' && 'text-primary',
name?.color === 'success' && 'text-success',
name?.color === 'warning' && 'text-warning',
name?.color === 'notice' && 'text-notice',
name?.color === 'info' && 'text-info',
)}
>
{name.value}:
</span>
)}{' '}
<GqlTypeLink color="notice" item={item} setItem={setItem} /> <GqlTypeLink color="notice" item={item} setItem={setItem} />
</div> </div>
{!hideDescription && ( {!hideDescription && (
<Markdown className="!text-text-subtle"> <Markdown className="!text-text-subtle">
{(description === undefined ? getNamedType(item.type).description : description) ?? ''} {(description === undefined ? getNamedType(item.type).description : description) ??
null}
</Markdown> </Markdown>
)} )}
</> </>
@@ -329,7 +372,7 @@ function GqlTypeRow({
<div> <div>
<div> <div>
<GqlTypeLink color="info" item={item} setItem={setItem}> <GqlTypeLink color="info" item={item} setItem={setItem}>
{name} {name?.value}
</GqlTypeLink> </GqlTypeLink>
{item.type.args.length > 0 && ( {item.type.args.length > 0 && (
<> <>
@@ -353,21 +396,17 @@ function GqlTypeRow({
<span className="text-text-subtle">:</span>{' '} <span className="text-text-subtle">:</span>{' '}
<GqlTypeLink color="notice" item={returnItem} setItem={setItem} /> <GqlTypeLink color="notice" item={returnItem} setItem={setItem} />
</div> </div>
{item.type.description && ( <Markdown className="!text-text-subtle mt-0.5">{item.type.description ?? null}</Markdown>
<Markdown className="!text-text-subtle mt-0.5">{item.type.description}</Markdown>
)}
</div> </div>
); );
} else if (item.kind === 'input_field') { } else if (item.kind === 'input_field') {
child = ( child = (
<> <>
<div> <div>
{name && <span className="text-primary">{name}:</span>}{' '} {name && <span className={name.color}>{name.value}:</span>}{' '}
<GqlTypeLink color="notice" item={item} setItem={setItem} /> <GqlTypeLink color="notice" item={item} setItem={setItem} />
</div> </div>
{item.type.description && ( <Markdown className="!text-text-subtle">{item.type.description ?? null}</Markdown>
<Markdown className="!text-text-subtle">{item.type.description}</Markdown>
)}
</> </>
); );
} }
@@ -443,3 +482,7 @@ function GqlTypeLabel({ item, children }: { item: ExplorerItem; children?: strin
function Subheading({ children }: { children: ReactNode }) { function Subheading({ children }: { children: ReactNode }) {
return <h2 className="font-bold text-lg mt-6">{children}</h2>; return <h2 className="font-bold text-lg mt-6">{children}</h2>;
} }
function Heading({ children }: { children: ReactNode }) {
return <h1 className="font-bold text-2xl">{children}</h1>;
}

View File

@@ -3,7 +3,14 @@ import remarkGfm from 'remark-gfm';
import { ErrorBoundary } from './ErrorBoundary'; import { ErrorBoundary } from './ErrorBoundary';
import { Prose } from './Prose'; import { Prose } from './Prose';
export function Markdown({ children, className }: { children: string; className?: string }) { interface Props {
children: string | null;
className?: string;
}
export function Markdown({ children, className }: Props) {
if (children == null) return null;
return ( return (
<Prose className={className}> <Prose className={className}>
<ErrorBoundary name="Markdown"> <ErrorBoundary name="Markdown">