From 8a59f92d031963e23ecc84b75feecf43eb4dd146 Mon Sep 17 00:00:00 2001 From: "netop://ウィビ" Date: Fri, 24 Apr 2026 11:33:25 -0700 Subject: Initial commit: @eol/graphiql v0.3 Svelte 5 GraphiQL alternative for JSR. Covers: - HTTP fetcher with injectable fetch; SSE/WS stubs - Session store with tabs, auto-titling, persistence, rename - Operation detection via graphql parse(); Toolbar picker - CodeMirror 6 editor via cm6-graphql with theme prop - Light theme preset (hand-rolled EditorView.theme) - Doc explorer with breadcrumb nav and type guards - History panel with 100-entry cap, favorite pinning - Deno tests for operations, storage, and history eviction --- source/library/state/history.svelte.ts | 94 ++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 source/library/state/history.svelte.ts (limited to 'source/library/state/history.svelte.ts') diff --git a/source/library/state/history.svelte.ts b/source/library/state/history.svelte.ts new file mode 100644 index 0000000..2726283 --- /dev/null +++ b/source/library/state/history.svelte.ts @@ -0,0 +1,94 @@ + + + +/*** UTILITY ------------------------------------------ ***/ + +import { evict } from "./history-logic.ts"; +import type { Storage } from "./storage.ts"; + +const MAX_ENTRIES = 100; +const STORAGE_KEY = "history"; + +/*** EXPORT ------------------------------------------- ***/ + +export type HistoryEntry = { + favorite: boolean; + headers: string; + id: string; + operationName: string | null; + query: string; + timestamp: number; + title: string; + variables: string; +}; + +export type HistoryInput = { + headers: string; + operationName: string | null; + query: string; + title: string; + variables: string; +}; + +export class HistoryStore { + entries = $state([]); + + #storage: Storage; + + constructor(storage: Storage) { + this.#storage = storage; + + const restored = storage.get(STORAGE_KEY); + + if (Array.isArray(restored)) + this.entries = restored.map((e) => ({ + favorite: Boolean(e.favorite), + headers: e.headers ?? "{}", + id: e.id, + operationName: e.operationName ?? null, + query: e.query ?? "", + timestamp: e.timestamp ?? Date.now(), + title: e.title ?? "untitled", + variables: e.variables ?? "{}" + })); + } + + add(input: HistoryInput) { + const entry: HistoryEntry = { + favorite: false, + headers: input.headers, + id: crypto.randomUUID(), + operationName: input.operationName, + query: input.query, + timestamp: Date.now(), + title: input.title, + variables: input.variables + }; + + this.entries = [entry, ...this.entries]; + this.#evict(); + } + + clear() { + this.entries = this.entries.filter((e) => e.favorite); + } + + favorite(id: string) { + const entry = this.entries.find((e) => e.id === id); + + if (entry) + entry.favorite = !entry.favorite; + } + + persist() { + this.#storage.set(STORAGE_KEY, this.entries); + } + + remove(id: string) { + this.entries = this.entries.filter((e) => e.id !== id); + } + + #evict() { + this.entries = evict(this.entries, MAX_ENTRIES); + } +} -- cgit v1.2.3