diff options
Diffstat (limited to '')
| -rw-r--r-- | source/library/components/DocExplorer.svelte | 134 | ||||
| -rw-r--r-- | source/library/components/DocExplorer/FieldView.svelte | 46 | ||||
| -rw-r--r-- | source/library/components/DocExplorer/TypeLink.svelte | 16 | ||||
| -rw-r--r-- | source/library/components/DocExplorer/TypeView.svelte | 71 |
4 files changed, 154 insertions, 113 deletions
diff --git a/source/library/components/DocExplorer.svelte b/source/library/components/DocExplorer.svelte index 536cb2a..48525e1 100644 --- a/source/library/components/DocExplorer.svelte +++ b/source/library/components/DocExplorer.svelte @@ -1,18 +1,19 @@ <script lang="ts"> - import FieldView from "./DocExplorer/FieldView.svelte"; - import TypeView from "./DocExplorer/TypeView.svelte"; + /*** IMPORT ------------------------------------------- ***/ import { isInputObjectType, isInterfaceType, - isObjectType - } from "graphql"; - import type { - GraphQLField, - GraphQLInputField, - GraphQLNamedType, - GraphQLSchema + isObjectType, + type GraphQLField, + type GraphQLInputField, + type GraphQLNamedType, + type GraphQLSchema } from "graphql"; + /*** UTILITY ------------------------------------------ ***/ + import FieldView from "./DocExplorer/FieldView.svelte"; + import TypeView from "./DocExplorer/TypeView.svelte"; + type NavEntry = | { kind: "field"; fieldName: string; typeName: string } | { kind: "type"; name: string }; @@ -22,7 +23,6 @@ }; let { schema }: Props = $props(); - let stack = $state<NavEntry[]>([]); const current = $derived<NavEntry | null>(stack.length > 0 ? stack[stack.length - 1] : null); @@ -63,23 +63,17 @@ return null; }); + /*** HELPER ------------------------------------------- ***/ function crumbLabel(entry: NavEntry): string { return entry.kind === "type" ? entry.name : entry.fieldName; } - function gotoRoot() { - stack = []; - } - function gotoIndex(index: number) { stack = stack.slice(0, index + 1); } - function pushType(name: string) { - if (!schema.getType(name)) - return; - - stack = [...stack, { kind: "type", name }]; + function gotoRoot() { + stack = []; } function pushField(fieldName: string) { @@ -90,54 +84,62 @@ stack = [...stack, { fieldName, kind: "field", typeName }]; } + + function pushType(name: string) { + if (!schema.getType(name)) + return; + + stack = [...stack, { kind: "type", name }]; + } </script> <style lang="scss"> .explorer { - background: var(--graphiql-panel, #252526); - border-left: 1px solid var(--graphiql-border, #333); + background-color: color-mix(in oklch shorter hue, var(--uchu-gray-1) 20%, var(--uchu-yang) 80%); + border-left: 1px solid var(--uchu-gray-2); display: grid; grid-template-rows: auto 1fr; height: 100%; min-height: 0; overflow: hidden; + z-index: 1; } .breadcrumbs { align-items: center; - border-bottom: 1px solid var(--graphiql-border, #333); + border-bottom: 1px solid var(--uchu-gray-2); display: flex; flex-wrap: wrap; font-size: 0.8125rem; gap: 0.25rem; padding: 0.5rem 0.75rem; - } - .crumb { - background: none; - border: none; - color: var(--graphiql-link, #79b8ff); - cursor: pointer; - font-family: inherit; - font-size: inherit; - padding: 0; - - &:hover { - text-decoration: underline; - } + .crumb { + background: none; + border: none; + cursor: pointer; + font-family: inherit; + font-size: inherit; + padding: 0; + + &:not(.current) { + color: var(--uchu-blue-3); + text-decoration: underline; + } - &.current { - color: var(--graphiql-fg, #d4d4d4); - cursor: default; + &.current { + color: var(--uchu-yin-4); + cursor: default; - &:hover { - text-decoration: none; + &:hover { + text-decoration: none; + } } } } .separator { - color: var(--graphiql-muted, #858585); + color: var(--uchu-gray-3); } .body { @@ -149,39 +151,39 @@ display: grid; gap: 0.75rem; padding: 0.75rem 1rem; + + &-list { + display: grid; + gap: 0.375rem; + } + + &-link { + background: none; + border: none; + color: var(--uchu-blue-3); + cursor: pointer; + font-family: inherit; + font-size: 0.95rem; + padding: 0; + text-align: left; + + &:hover { + text-decoration: underline; + } + } } .section-label { - color: var(--graphiql-muted, #858585); + color: var(--uchu-yin-6); font-size: 0.7rem; - letter-spacing: 0.05em; + letter-spacing: 0.05rem; margin-bottom: 0.25rem; text-transform: uppercase; } - .root-list { - display: grid; - gap: 0.375rem; - } - - .root-link { - background: none; - border: none; - color: var(--graphiql-link, #79b8ff); - cursor: pointer; - font-family: inherit; - font-size: 0.875rem; - padding: 0; - text-align: left; - - &:hover { - text-decoration: underline; - } - } - .empty { - color: var(--graphiql-muted, #858585); - font-size: 0.8125rem; + color: var(--uchu-yin-6); + font-size: 0.8rem; padding: 0.75rem 1rem; } </style> @@ -200,10 +202,12 @@ onclick={() => gotoIndex(i)}>{crumbLabel(entry)}</button> {/each} </div> + <div class="body"> {#if stack.length === 0} <div class="root"> <div class="section-label">Root Types</div> + <div class="root-list"> {#each rootTypes as entry} <button class="root-link" onclick={() => pushType(entry.type.name)}> diff --git a/source/library/components/DocExplorer/FieldView.svelte b/source/library/components/DocExplorer/FieldView.svelte index 71d215c..1cc62ae 100644 --- a/source/library/components/DocExplorer/FieldView.svelte +++ b/source/library/components/DocExplorer/FieldView.svelte @@ -1,7 +1,11 @@ <script lang="ts"> - import TypeLink from "./TypeLink.svelte"; + /*** IMPORT ------------------------------------------- ***/ import type { GraphQLField, GraphQLInputField } from "graphql"; + /*** UTILITY ------------------------------------------ ***/ + import { markdown } from "../../graphql/markdown.ts"; + import TypeLink from "./TypeLink.svelte"; + type Props = { field: GraphQLField<unknown, unknown> | GraphQLInputField; onNavigate: (typeName: string) => void; @@ -15,7 +19,7 @@ <style lang="scss"> .field { display: grid; - gap: 0.75rem; + gap: 1.5rem; padding: 0.75rem 1rem; } @@ -24,60 +28,62 @@ font-weight: 600; } + .section-label, + .description, + .arg-description { + color: var(--uchu-yin-6); + } + .section-label { - color: var(--graphiql-muted, #858585); font-size: 0.7rem; - letter-spacing: 0.05em; + letter-spacing: 0.05rem; margin-bottom: 0.25rem; text-transform: uppercase; } .description { - color: var(--graphiql-muted, #858585); - font-size: 0.8125rem; + font-size: 0.8rem; line-height: 1.4; } .args { display: grid; - gap: 0.375rem; + gap: 1.5rem; } .arg { - font-size: 0.8125rem; - } + font-size: 0.8rem; - .arg-name { - color: var(--graphiql-fg, #d4d4d4); - } - - .arg-description { - color: var(--graphiql-muted, #858585); - font-size: 0.75rem; - margin-left: 1rem; - margin-top: 0.125rem; + &-description { + font-size: 0.7rem; + margin-left: 1rem; + margin-top: 0.125rem; + } } </style> <div class="field"> <div class="heading">{field.name}</div> {#if field.description} - <div class="description">{field.description}</div> + <div class="description">{@html markdown(field.description)}</div> {/if} + <div> <div class="section-label">Type</div> <TypeLink {onNavigate} type={field.type}/> </div> + {#if args.length > 0} <div> <div class="section-label">Arguments</div> + <div class="args"> {#each args as arg} <div class="arg"> <span class="arg-name">{arg.name}</span>: <TypeLink {onNavigate} type={arg.type}/> {#if arg.description} - <div class="arg-description">{arg.description}</div> + <div class="arg-description">{@html markdown(arg.description)}</div> {/if} </div> {/each} diff --git a/source/library/components/DocExplorer/TypeLink.svelte b/source/library/components/DocExplorer/TypeLink.svelte index 253d16e..03f5c1e 100644 --- a/source/library/components/DocExplorer/TypeLink.svelte +++ b/source/library/components/DocExplorer/TypeLink.svelte @@ -1,7 +1,13 @@ <script lang="ts"> - import { getNamedType, isListType, isNonNullType } from "graphql"; - import type { GraphQLType } from "graphql"; - + /*** IMPORT ------------------------------------------- ***/ + import { + getNamedType, + isListType, + isNonNullType, + type GraphQLType + } from "graphql"; + + /*** UTILITY ------------------------------------------ ***/ type Props = { onNavigate: (typeName: string) => void; type: GraphQLType; @@ -27,13 +33,13 @@ .link { background: none; border: none; - color: var(--graphiql-link, #79b8ff); + color: var(--uchu-blue-3); cursor: pointer; font-family: inherit; font-size: inherit; padding: 0; - &:hover { + &:not(:hover) { text-decoration: underline; } } diff --git a/source/library/components/DocExplorer/TypeView.svelte b/source/library/components/DocExplorer/TypeView.svelte index 31a1ca3..c1978d6 100644 --- a/source/library/components/DocExplorer/TypeView.svelte +++ b/source/library/components/DocExplorer/TypeView.svelte @@ -1,14 +1,18 @@ <script lang="ts"> - import TypeLink from "./TypeLink.svelte"; + /*** IMPORT ------------------------------------------- ***/ import { isEnumType, isInputObjectType, isInterfaceType, isObjectType, isScalarType, - isUnionType + isUnionType, + type GraphQLNamedType } from "graphql"; - import type { GraphQLNamedType } from "graphql"; + + /*** UTILITY ------------------------------------------ ***/ + import { markdown } from "../../graphql/markdown.ts"; + import TypeLink from "./TypeLink.svelte"; type Props = { onNavigateField: (fieldName: string) => void; @@ -72,7 +76,7 @@ <style lang="scss"> .type { display: grid; - gap: 0.75rem; + gap: 1.5rem; padding: 0.75rem 1rem; } @@ -81,67 +85,80 @@ font-weight: 600; } + .kind, + .description, + .entry-description { + color: var(--uchu-yin-6); + } + .kind { - color: var(--graphiql-muted, #858585); font-weight: normal; margin-right: 0.375rem; } .description { - color: var(--graphiql-muted, #858585); - font-size: 0.8125rem; + font-size: 0.8rem; line-height: 1.4; + + :global(a) { + background-color: oklch(var(--uchu-blue-1-raw) / 25%); + color: var(--uchu-blue-4); + } + + :global(code) { + background-color: var(--uchu-yellow-1); + } } .section-label { - color: var(--graphiql-muted, #858585); font-size: 0.7rem; - letter-spacing: 0.05em; + letter-spacing: 0.05rem; margin-bottom: 0.25rem; text-transform: uppercase; } .list { display: grid; - gap: 0.375rem; + gap: 1.5rem; } .entry { - font-size: 0.8125rem; + font-size: 0.8rem; + + &-description { + font-size: 0.7rem; + margin-left: 1rem; + margin-top: 0.125rem; + } } .field-button { background: none; border: none; - color: var(--graphiql-fg, #d4d4d4); cursor: pointer; font-family: inherit; font-size: inherit; padding: 0; - &:hover { + &:not(:hover) { text-decoration: underline; } } - - .entry-description { - color: var(--graphiql-muted, #858585); - font-size: 0.75rem; - margin-left: 1rem; - margin-top: 0.125rem; - } </style> <div class="type"> <div class="heading"> {#if kindLabel}<span class="kind">{kindLabel}</span>{/if}{type.name} </div> + {#if type.description} - <div class="description">{type.description}</div> + <div class="description">{@html markdown(type.description)}</div> {/if} + {#if interfaces.length > 0} <div> <div class="section-label">Implements</div> + <div class="list"> {#each interfaces as iface} <div class="entry"> @@ -151,9 +168,11 @@ </div> </div> {/if} + {#if fields.length > 0} <div> <div class="section-label">Fields</div> + <div class="list"> {#each fields as field} <div class="entry"> @@ -161,17 +180,20 @@ class="field-button" onclick={() => onNavigateField(field.name)}>{field.name}</button>: <TypeLink onNavigate={onNavigateType} type={field.type}/> + {#if field.description} - <div class="entry-description">{field.description}</div> + <div class="entry-description">{@html markdown(field.description)}</div> {/if} </div> {/each} </div> </div> {/if} + {#if unionMembers.length > 0} <div> <div class="section-label">Members</div> + <div class="list"> {#each unionMembers as member} <div class="entry"> @@ -181,15 +203,18 @@ </div> </div> {/if} + {#if enumValues.length > 0} <div> <div class="section-label">Values</div> + <div class="list"> {#each enumValues as value} <div class="entry"> <span>{value.name}</span> + {#if value.description} - <div class="entry-description">{value.description}</div> + <div class="entry-description">{@html markdown(value.description)}</div> {/if} </div> {/each} |