From 4eb0cdb2598ed147bfd37d9fc4fa6ddf596af9f6 Mon Sep 17 00:00:00 2001 From: Yann Amsellem Date: Mon, 13 Jan 2025 17:21:19 +0100 Subject: [PATCH] feat(tabs): add new tab and close tab --- src/lib/components/Editor/Editor.svelte | 16 +- src/lib/icons/XMark.svelte | 18 +++ src/routes/+page.svelte | 188 ++++++++++++++++++------ 3 files changed, 160 insertions(+), 62 deletions(-) create mode 100644 src/lib/icons/XMark.svelte diff --git a/src/lib/components/Editor/Editor.svelte b/src/lib/components/Editor/Editor.svelte index d7f7134..7083955 100644 --- a/src/lib/components/Editor/Editor.svelte +++ b/src/lib/components/Editor/Editor.svelte @@ -2,7 +2,7 @@ import type { Table } from '$lib/olap-engine'; import { sql } from '@codemirror/lang-sql'; import { Compartment, EditorState } from '@codemirror/state'; - import { EditorView, keymap, placeholder } from '@codemirror/view'; + import { EditorView, placeholder } from '@codemirror/view'; import { untrack } from 'svelte'; import './codemirror.css'; import { default_extensions, default_keymaps } from './extensions'; @@ -11,11 +11,10 @@ type Props = { value: string; - onExec?: () => unknown; tables?: Table[]; }; - let { value = $bindable(''), onExec, tables = [] }: Props = $props(); + let { value = $bindable(''), tables = [] }: Props = $props(); let container: HTMLDivElement; let editor_view: EditorView; @@ -37,16 +36,7 @@ value = update.state.doc.toString(); } }), - placeholder('Enter a query...'), - keymap.of([ - { - key: 'Mod-Enter', - run: () => { - onExec?.(); - return true; - } - } - ]) + placeholder('Enter a query...') ] }); diff --git a/src/lib/icons/XMark.svelte b/src/lib/icons/XMark.svelte new file mode 100644 index 0000000..18c0cab --- /dev/null +++ b/src/lib/icons/XMark.svelte @@ -0,0 +1,18 @@ + + + diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index 4129c7a..a7e213f 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -9,7 +9,9 @@ import { set_app_context } from '$lib/context'; import Bars3 from '$lib/icons/Bars3.svelte'; import Play from '$lib/icons/Play.svelte'; + import Plus from '$lib/icons/Plus.svelte'; import Save from '$lib/icons/Save.svelte'; + import XMark from '$lib/icons/XMark.svelte'; import type { Table } from '$lib/olap-engine'; import { engine, type OLAPResponse } from '$lib/olap-engine'; import { history_repository, type HistoryEntry } from '$lib/repositories/history'; @@ -23,19 +25,17 @@ let loading = $state(false); async function handleExec() { + const query = current_tab.contents; if (loading || !query) { return; } loading = true; - const query_to_execute = query; - response = await engine.exec(query_to_execute).finally(() => (loading = false)); + response = await engine.exec(query).finally(() => (loading = false)); const last = await history_repository.getLast(); - if (response && last?.content !== query_to_execute) { - await addHistoryEntry(query_to_execute); - } + if (response && last?.content !== query) await addHistoryEntry(query); } let tables = $state.raw([]); @@ -81,6 +81,8 @@ save_query_modal?.show(); } } + + if (event.key === 'Enter' && event.metaKey) handleExec(); } async function handleCreateQuery({ @@ -92,8 +94,7 @@ async function handleDeleteQuery(query: Query) { await query_repository.delete(query.id); - const index = queries.indexOf(query); - queries = queries.slice(0, index).concat(queries.slice(index + 1)); + queries = queries.toSpliced(queries.indexOf(query), 1); } function handleQueryOpen(_query: Query) { @@ -104,12 +105,7 @@ async function handleQueryRename(query: Query) { const updated = await query_repository.update(query); const index = queries.findIndex((query) => query.id === updated.id); - if (index !== -1) { - queries = queries - .slice(0, index) - .concat(updated) - .concat(queries.slice(index + 1)); - } + if (index !== -1) queries = queries.with(index, updated); } const context_menu = new ContextMenuState(); @@ -123,12 +119,27 @@ if (!is_mobile) open_drawer = false; }); - let tabs = [ - { id: '', content: 'select 1', name: 'new' }, - { id: '', content: 'select 2', name: 'query1' }, - { id: '', content: 'select 3', name: 'query2' } - ]; - let selected_tab = $state(0); + interface Tab { + id: string; + contents: string; + name: string; + query_id?: Query['id']; + } + + let tabs = $state([{ id: crypto.randomUUID(), contents: '', name: 'Untitled' }]); + let selected_tab_index = $state(0); + const current_tab = $derived(tabs[selected_tab_index]); + + function addNewTab() { + const next_index = tabs.length; + tabs.push({ id: crypto.randomUUID(), name: 'Untitled', contents: '' }); + selected_tab_index = next_index; + } + + function closeTab(index: number) { + tabs.splice(index, 1); + selected_tab_index = Math.max(0, index - 1); + } @@ -169,35 +180,57 @@ {#snippet a()}
-