diff options
Diffstat (limited to 'source/library/components/Toolbar.svelte')
| -rw-r--r-- | source/library/components/Toolbar.svelte | 150 |
1 files changed, 150 insertions, 0 deletions
diff --git a/source/library/components/Toolbar.svelte b/source/library/components/Toolbar.svelte new file mode 100644 index 0000000..a17191c --- /dev/null +++ b/source/library/components/Toolbar.svelte @@ -0,0 +1,150 @@ +<script lang="ts"> + import type { OperationInfo } from "../graphql/operations.ts"; + + type Props = { + disabled: boolean; + docsAvailable?: boolean; + docsOpen?: boolean; + historyOpen?: boolean; + onRun: () => void; + onSelectOperation?: (name: string | null) => void; + onToggleDocs?: () => void; + onToggleHistory?: () => void; + operationName?: string | null; + operations?: OperationInfo[]; + running: boolean; + schemaLoading: boolean; + }; + + let { + disabled, + docsAvailable = false, + docsOpen = false, + historyOpen = false, + onRun, + onSelectOperation, + onToggleDocs, + onToggleHistory, + operationName = null, + operations = [], + running, + schemaLoading + }: Props = $props(); + + const namedOperations = $derived(operations.filter((o) => o.name !== null)); + + function onPick(event: Event) { + const value = (event.currentTarget as HTMLSelectElement).value; + onSelectOperation?.(value || null); + } +</script> + +<style lang="scss"> + .toolbar { + align-items: center; + background: var(--graphiql-panel, #252526); + border-bottom: 1px solid var(--graphiql-border, #333); + display: flex; + gap: 0.75rem; + padding: 0.5rem 0.75rem; + } + + .run { + background: var(--graphiql-accent, #0e639c); + border: none; + border-radius: 3px; + color: #fff; + cursor: pointer; + font-size: 0.875rem; + padding: 0.375rem 1rem; + + &:disabled { + cursor: not-allowed; + opacity: 0.5; + } + } + + .hint { + color: var(--graphiql-muted, #858585); + font-size: 0.75rem; + } + + .picker { + background: var(--graphiql-bg, #1e1e1e); + border: 1px solid var(--graphiql-border, #333); + border-radius: 3px; + color: var(--graphiql-fg, #d4d4d4); + font-family: inherit; + font-size: 0.8125rem; + padding: 0.25rem 0.5rem; + } + + .spacer { + flex: 1; + } + + .toggle { + background: none; + border: 1px solid var(--graphiql-border, #333); + border-radius: 3px; + color: var(--graphiql-muted, #858585); + cursor: pointer; + font-family: inherit; + font-size: 0.75rem; + padding: 0.25rem 0.625rem; + + &.active { + background: var(--graphiql-bg, #1e1e1e); + color: var(--graphiql-fg, #d4d4d4); + } + + &:disabled { + cursor: not-allowed; + opacity: 0.4; + } + + &:hover:not(:disabled) { + color: var(--graphiql-fg, #d4d4d4); + } + } +</style> + +<div class="toolbar"> + <button class="run" {disabled} onclick={onRun}> + {running ? "Running…" : "Run"} + </button> + {#if namedOperations.length > 1} + <select + aria-label="Operation" + class="picker" + onchange={onPick} + value={operationName ?? ""}> + <option value="">Select operation…</option> + {#each namedOperations as op} + <option value={op.name}>{op.type} {op.name}</option> + {/each} + </select> + {/if} + <span class="hint">⌘/Ctrl + Enter</span> + {#if schemaLoading} + <span class="hint">Loading schema…</span> + {/if} + <span class="spacer"></span> + {#if onToggleHistory} + <button + aria-pressed={historyOpen} + class="toggle" + class:active={historyOpen} + onclick={onToggleHistory} + type="button">History</button> + {/if} + {#if onToggleDocs} + <button + aria-pressed={docsOpen} + class="toggle" + class:active={docsOpen} + disabled={!docsAvailable} + onclick={onToggleDocs} + type="button">Docs</button> + {/if} +</div> |