From 4df702fb7931cfb805b378b6c9db544c020427ba Mon Sep 17 00:00:00 2001 From: Lloyd Date: Thu, 11 Sep 2025 22:25:06 +1000 Subject: [PATCH] =?UTF-8?q?=F0=9F=99=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/lib/components/grid/cell.svelte | 51 ++++++++++++++++--- frontend/src/lib/components/grid/grid.svelte | 23 ++++++--- .../src/lib/components/grid/grid.svelte.ts | 49 ++++++++++++++---- 3 files changed, 101 insertions(+), 22 deletions(-) diff --git a/frontend/src/lib/components/grid/cell.svelte b/frontend/src/lib/components/grid/cell.svelte index 903cdcb..b15dd04 100644 --- a/frontend/src/lib/components/grid/cell.svelte +++ b/frontend/src/lib/components/grid/cell.svelte @@ -102,12 +102,29 @@ {onmousedown} data-row={pos.row} data-col={pos.col} + ondragstart={(e) => e.preventDefault()} style:width style:height - class={clsx('placeholder bg-background p-1', { primaryactive, active }, cla)} + class={clsx( + 'placeholder bg-background p-1', + { + primaryactive, + active, + 'active-top': grid.isActiveTop(pos), + 'active-bottom': grid.isActiveBottom(pos), + 'active-right': grid.isActiveRight(pos), + 'active-left': grid.isActiveLeft(pos), + 'only-active': grid.isActive(pos) && grid.isSingleActive() + }, + cla + )} > {#if cell && (cell.raw !== '' || getEvalLiteral(cell.eval) !== '')} - + {#if externalediting} {cell.temp_raw} {:else if cell.eval} @@ -129,19 +146,39 @@ } .primaryactive { - z-index: 30; - border: 1px solid var(--color-primary); + z-index: 30 !important; + border: 1px solid var(--color-primary) !important; outline: 1px solid var(--color-primary); } .active { z-index: 20; - background-color: color-mix(in oklab, var(--color-primary) 50%, var(--color-background) 90%); - - /* border: 1px solid var(--color-primary); */ + background-color: color-mix(in oklab, var(--color-primary) 20%, var(--color-background) 80%); + border: 1px solid color-mix(in oklab, var(--input) 100%, var(--color-foreground) 5%); /* outline: 1px solid var(--color-primary); */ } + .only-active { + background-color: transparent !important; + } + + /* Borders for edges */ + .active-top { + border-top: 1px solid var(--color-primary); + } + + .active-bottom { + border-bottom: 1px solid var(--color-primary); + } + + .active-left { + border-left: 1px solid var(--color-primary); + } + + .active-right { + border-right: 1px solid var(--color-primary); + } + .active:has(.err), .placeholder:has(.err) { position: relative; /* needed for absolute positioning */ diff --git a/frontend/src/lib/components/grid/grid.svelte b/frontend/src/lib/components/grid/grid.svelte index 5b14eb1..9b51571 100644 --- a/frontend/src/lib/components/grid/grid.svelte +++ b/frontend/src/lib/components/grid/grid.svelte @@ -80,8 +80,6 @@ grid.stopEditingActive(); } }; - window.addEventListener('click', handler); - onDestroy(() => window.removeEventListener('click', handler)); const handleMouseMove = (e: MouseEvent) => { if (!dragging) return; @@ -92,20 +90,34 @@ const row = parseInt(el.dataset.row, 10); const col = parseInt(el.dataset.col, 10); - // expand selection as you drag - console.log(`moved to ${refToStr(row, col)}`); grid.setActive(grid.primary_active, new Position(row, col)); } }; - const handleMouseUp = () => { + const handleMouseUp = (e: MouseEvent) => { dragging = false; // stop tracking + // + // const el = document.elementFromPoint(e.clientX, e.clientY); + // + // if (el && el instanceof HTMLElement && el.dataset.row && el.dataset.col) { + // const row = parseInt(el.dataset.row, 10); + // const col = parseInt(el.dataset.col, 10); + // + // // expand selection as you drag + // let pos = new Position(row, col); + // + // if (grid.isActive(pos) && grid.isEditing(pos)) return; + // + // grid.stopAnyEditing(); + // } }; + window.addEventListener('click', handler); window.addEventListener('mousemove', handleMouseMove); window.addEventListener('mouseup', handleMouseUp); onDestroy(() => { + window.removeEventListener('click', handler); window.removeEventListener('mousemove', handleMouseMove); window.removeEventListener('mouseup', handleMouseUp); }); @@ -216,7 +228,6 @@ height={grid.getRowHeight(i)} width={grid.getColWidth(j)} onmousedown={(e) => { - console.log(`down at ${refToStr(i, j)}`); handleCellMouseDown(i, j, e); }} /> diff --git a/frontend/src/lib/components/grid/grid.svelte.ts b/frontend/src/lib/components/grid/grid.svelte.ts index b71b542..e3cc20a 100644 --- a/frontend/src/lib/components/grid/grid.svelte.ts +++ b/frontend/src/lib/components/grid/grid.svelte.ts @@ -126,6 +126,30 @@ class Grid { return this.default_row_height; } + public isActiveTop(pos: Position): boolean { + const tl = this.getActiveTopLeft(); + if (!tl) return false; + return this.isActive(pos) && pos.row === tl.row; + } + + public isActiveBottom(pos: Position): boolean { + const br = this.getActiveBottomRight(); + if (!br) return false; + return this.isActive(pos) && pos.row === br.row; + } + + public isActiveLeft(pos: Position): boolean { + const tl = this.getActiveTopLeft(); + if (!tl) return false; + return this.isActive(pos) && pos.col === tl.col; + } + + public isActiveRight(pos: Position): boolean { + const br = this.getActiveBottomRight(); + if (!br) return false; + return this.isActive(pos) && pos.col === br.col; + } + public setRowHeight(row: number, height: string) { if (height === this.default_row_height) { delete this.row_heights[row]; @@ -159,6 +183,10 @@ class Grid { // this.setCell(pos); } + public stopAnyEditing() { + this.editing_cell = null; + } + public stopEditingActive() { if (!this.anyIsActive() || !this.primary_active?.equals(this.secondary_active)) return; this.stopEditing(this.primary_active); @@ -219,18 +247,17 @@ class Grid { } public getActiveRangeStr(): string { - const tl = this.getActiveTopLeft(); - const br = this.getActiveBottomRight(); + const tl = this.getActiveTopLeft(); + const br = this.getActiveBottomRight(); - if (tl === null || br === null) return ''; + if (tl === null || br === null) return ''; - // Single-cell selection - if (tl.equals(br)) return tl.str(); - - // Range selection - return `${tl.str()}:${br.str()}`; -} + // Single-cell selection + if (tl.equals(br)) return tl.str(); + // Range selection + return `${tl.str()}:${br.str()}`; + } public getActivePos(): Position | null { if ( @@ -277,6 +304,10 @@ class Grid { return this.primary_active.equals(pos); } + public isSingleActive(): boolean { + return this.getActivePos() !== null; + } + public anyIsActive(): boolean { return this.primary_active !== null && this.secondary_active !== null; }