diff options
| author | netop://ウィビ <paul@webb.page> | 2026-04-26 20:18:30 -0700 |
|---|---|---|
| committer | netop://ウィビ <paul@webb.page> | 2026-04-26 20:18:30 -0700 |
| commit | 3c06c95f396b6e911076bc3291d5855ed01b5caa (patch) | |
| tree | 17cd218339c52fbeee93d931303b04a3ff294f8b /source/library/components/HistoryPanel.svelte | |
| parent | f059d97ab7f6d74d61139ac698cb871be7cb632e (diff) | |
| download | graphiql-3c06c95f396b6e911076bc3291d5855ed01b5caa.tar.gz graphiql-3c06c95f396b6e911076bc3291d5855ed01b5caa.zip | |
cleanup and ready for launch
Diffstat (limited to 'source/library/components/HistoryPanel.svelte')
| -rw-r--r-- | source/library/components/HistoryPanel.svelte | 225 |
1 files changed, 122 insertions, 103 deletions
diff --git a/source/library/components/HistoryPanel.svelte b/source/library/components/HistoryPanel.svelte index 01f397a..e224e1e 100644 --- a/source/library/components/HistoryPanel.svelte +++ b/source/library/components/HistoryPanel.svelte @@ -1,4 +1,5 @@ <script lang="ts"> + /*** UTILITY ------------------------------------------ ***/ import type { HistoryEntry } from "../state/history.svelte.ts"; type Props = { @@ -34,6 +35,7 @@ return b.timestamp - a.timestamp; })); + /*** HELPER ------------------------------------------- ***/ function formatTimestamp(ms: number): string { const d = new Date(ms); return d.toLocaleString(); @@ -50,10 +52,6 @@ } } - function onImportClick() { - fileInput?.click(); - } - function onFileChange(event: Event) { const input = event.currentTarget as HTMLInputElement; const file = input.files?.[0]; @@ -63,22 +61,29 @@ input.value = ""; } + + function onImportClick() { + fileInput?.click(); + } </script> <style lang="scss"> .panel { - background: var(--graphiql-panel, #252526); - border-right: 1px solid var(--graphiql-border, #333); + background-color: var(--uchu-yin-9); + color: var(--uchu-yin-1); display: grid; + font-size: 0.8rem; grid-template-rows: auto 1fr; - height: 100%; min-height: 0; + height: 100%; overflow: hidden; + z-index: 2; } - .header { + .header, + .notice { align-items: center; - border-bottom: 1px solid var(--graphiql-border, #333); + border-bottom: 1px solid var(--uchu-yin-8); display: flex; gap: 0.5rem; justify-content: space-between; @@ -86,26 +91,32 @@ } .title { - font-size: 0.8125rem; font-weight: 600; } .actions { display: flex; gap: 0.5rem; + + .action { + background: none; + border: none; + cursor: pointer; + font-family: inherit; + font-size: 0.75rem; + padding: 0; + } } - .action { - background: none; - border: none; - color: var(--graphiql-muted, #858585); - cursor: pointer; - font-family: inherit; - font-size: 0.75rem; - padding: 0; + .action, + .notice-dismiss, + .remove { + &:not(:hover) { + color: var(--uchu-yin-5); + } &:hover { - color: var(--graphiql-fg, #d4d4d4); + color: var(--uchu-yin-1); } } @@ -113,38 +124,20 @@ display: none; } - .notice { - align-items: center; - background: var(--graphiql-bg, #1e1e1e); - border-bottom: 1px solid var(--graphiql-border, #333); - color: var(--graphiql-fg, #d4d4d4); - display: flex; - font-size: 0.75rem; - gap: 0.5rem; - justify-content: space-between; - padding: 0.375rem 0.75rem; - } - - .notice-dismiss { + .notice-dismiss, + .remove { background: none; border: none; - color: var(--graphiql-muted, #858585); cursor: pointer; - font-size: 0.875rem; + font-size: 1rem; line-height: 1; padding: 0 0.25rem; - - &:hover { - color: var(--graphiql-fg, #d4d4d4); - } } .list { display: grid; - gap: 0.125rem; min-height: 0; overflow-y: auto; - padding: 0.375rem 0; } .entry { @@ -154,22 +147,56 @@ gap: 0.125rem; grid-template-columns: auto 1fr auto; padding: 0.375rem 0.75rem; + transition: opacity 0.1s; + + &:not(:last-of-type) { + border-bottom: 1px solid var(--uchu-yin); + } &:hover { - background: var(--graphiql-bg, #1e1e1e); + background-color: var(--uchu-yin); + } + + .list:has(.entry:hover) &:not(:hover) { + opacity: 0.4; + } + + &-title { + font-size: 0.8rem; + margin-bottom: 0.1rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + + &-time { + color: var(--uchu-yin-5); + font-size: 0.7rem; } } .star { + align-self: center; background: none; border: none; - color: var(--graphiql-muted, #858585); cursor: pointer; - font-size: 0.875rem; + font-size: 0.8rem; padding: 0 0.375rem 0 0; + &:not(.active) { + color: var(--uchu-yin-5); + } + &.active { - color: var(--graphiql-accent, #e3b341); + color: var(--uchu-orange-4); + + svg { + fill: currentColor; + } + } + + svg { + width: 1rem; } } @@ -178,75 +205,55 @@ min-width: 0; } - .entry-title { - font-size: 0.8125rem; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; - } - - .entry-time { - color: var(--graphiql-muted, #858585); - font-size: 0.7rem; - } - .remove { align-self: center; - background: none; - border: none; - color: var(--graphiql-muted, #858585); - cursor: pointer; - font-size: 1rem; - line-height: 1; - padding: 0 0.25rem; - - &:hover { - color: var(--graphiql-fg, #d4d4d4); - } } .empty { - color: var(--graphiql-muted, #858585); - font-size: 0.8125rem; + color: var(--uchu-yin-5); + font-size: 0.8rem; padding: 0.75rem; } </style> <div class="panel"> - <div> - <div class="header"> - <span class="title">History</span> - <div class="actions"> - {#if onExport} - <button class="action" onclick={onExport} type="button">Export</button> - {/if} - {#if onImport} - <button class="action" onclick={onImportClick} type="button">Import</button> - <input - accept="application/json" - bind:this={fileInput} - class="hidden-input" - onchange={onFileChange} - type="file"/> - {/if} - {#if entries.length > 0} - <button class="action" onclick={onClear} type="button">Clear</button> - {/if} - </div> + <div class="header"> + <span class="title">History</span> + + <div class="actions"> + {#if onExport} + <button class="action" onclick={onExport} type="button">Export</button> + {/if} + + {#if onImport} + <button class="action" onclick={onImportClick} type="button">Import</button> + <input + accept="application/json" + bind:this={fileInput} + class="hidden-input" + onchange={onFileChange} + type="file"/> + {/if} + + {#if entries.length > 0} + <button class="action" onclick={onClear} type="button">Clear</button> + {/if} </div> - {#if notice} - <div class="notice"> - <span>{notice}</span> - {#if onDismissNotice} - <button - aria-label="Dismiss notice" - class="notice-dismiss" - onclick={onDismissNotice} - type="button">×</button> - {/if} - </div> - {/if} </div> + + {#if notice} + <div class="notice"> + <span>{notice}</span> + {#if onDismissNotice} + <button + aria-label="Dismiss notice" + class="notice-dismiss" + onclick={onDismissNotice} + type="button">×</button> + {/if} + </div> + {/if} + <div class="list"> {#if sorted.length === 0} <div class="empty">No history yet.</div> @@ -264,16 +271,28 @@ class="star" class:active={entry.favorite} onclick={(e) => { e.stopPropagation(); onFavorite(entry.id); }} - type="button">{entry.favorite ? "★" : "☆"}</button> + type="button"> + {#if entry.favorite} + <svg viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> + <path d="M12 2L14.9389 7.95492L21.5106 8.90983L16.7553 13.5451L17.8779 20.0902L12 17L6.12215 20.0902L7.24472 13.5451L2.48944 8.90983L9.06108 7.95492L12 2Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/> + </svg> + {:else} + <svg viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"> + <path d="M12 2L14.9389 7.95492L21.5106 8.90983L16.7553 13.5451L17.8779 20.0902L12 17L6.12215 20.0902L7.24472 13.5451L2.48944 8.90983L9.06108 7.95492L12 2Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/> + </svg> + {/if} + </button> + <div class="meta"> <div class="entry-title">{entry.title}</div> <div class="entry-time">{formatTimestamp(entry.timestamp)}</div> </div> + <button aria-label="Remove entry" class="remove" onclick={(e) => { e.stopPropagation(); onRemove(entry.id); }} - type="button">×</button> + type="button">×</button> </div> {/each} {/if} |