aboutsummaryrefslogtreecommitdiff
path: root/source/library/components/Toolbar.svelte
diff options
context:
space:
mode:
Diffstat (limited to 'source/library/components/Toolbar.svelte')
-rw-r--r--source/library/components/Toolbar.svelte150
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>