This commit is contained in:
2025-09-07 03:48:48 +10:00
parent 2f3f853134
commit 8d03316b1b
63 changed files with 1941 additions and 420 deletions

View File

@@ -3,84 +3,57 @@
import Cell from '$lib/components/grid/cell.svelte';
import { onDestroy, onMount } from 'svelte';
import CellHeader from './cell-header.svelte';
import {
refFromStr,
splitErrorString,
colToStr,
refFromPos,
type CellData,
type CellValue
} from './utils';
import { colToStr, refToStr, type CellT } from './utils';
import clsx from 'clsx';
let {
socket
socket,
class: className = ''
}: {
class?: string;
socket: WebSocket;
} = $props();
socket.onmessage = (msg: MessageEvent) => {
const input = msg.data.toString().trim();
if (input.startsWith('ERR')) {
let split = splitErrorString(input);
toast.error(split[0], {
description: split[1]
});
let res: LeadMsg;
try {
res = JSON.parse(msg.data);
console.log(res);
} catch (err) {
console.error('Failed to parse LeadMsg:', err);
return;
}
let strRef: string | undefined;
let evalStr: string | undefined;
// Case 1: "Cell D4 = Integer(4)"
let match = input.match(/^Cell\s+([A-Z]+\d+)\s*=\s*(.+)$/);
if (match) {
[, strRef, evalStr] = match;
}
// Case 2: "D6 String("hello")" or "E9 Double(4.0)"
if (!match) {
match = input.match(/^([A-Z]+\d+)\s+(.+)$/);
if (match) {
[, strRef, evalStr] = match;
switch (res.msg_type) {
case 'error': {
toast.error('Error', {
description: res.raw
});
break;
}
case 'set': {
if (res.cell === undefined) {
console.error('Expected cell ref for SET response from server.');
return;
} else if (res.eval === undefined) {
console.error('Expected cell value for SET response from server.');
return;
}
setCellVal(res.cell.row, res.cell.col, res.eval.value);
break;
}
}
if (!strRef || !evalStr) {
console.warn('Unrecognized message:', input);
return;
}
console.log(`Cell: ${strRef}`);
console.log(`Eval: ${evalStr}`);
let { row, col } = refFromStr(strRef);
// Parse eval types
if (evalStr.startsWith('Integer(')) {
const num = parseInt(evalStr.match(/^Integer\(([-\d]+)\)$/)?.[1] ?? 'NaN', 10);
console.log(`Parsed integer:`, num);
setCellVal(row, col, num);
} else if (evalStr.startsWith('Double(')) {
const num = parseFloat(evalStr.match(/^Double\(([-\d.]+)\)$/)?.[1] ?? 'NaN');
console.log(`Parsed double:`, num);
setCellVal(row, col, num);
} else if (evalStr.startsWith('String(')) {
const str = evalStr.match(/^String\("(.+)"\)$/)?.[1];
console.log(`Parsed string:`, str);
setCellVal(row, col, str);
}
};
let rows = 100;
let cols = 60;
let rows = 50;
let cols = 40;
let default_row_height = '30px';
let default_col_width = '80px';
// Only store touched cells
let grid_vals: Record<string, CellData> = $state({});
let grid_vals: Record<string, CellT> = $state({});
let row_heights: Record<number, string> = $state({});
let col_widths: Record<number, string> = $state({});
@@ -136,7 +109,7 @@
}
};
const getCellVal = (i: number, j: number) => getCell(i, j)?.val ?? undefined;
const setCellVal = (i: number, j: number, val: CellValue) => {
const setCellVal = (i: number, j: number, val: LiteralValue) => {
if (grid_vals[key(i, j)] === undefined) {
console.warn('Cell raw value was undefined but recieved eval.');
} else {
@@ -144,20 +117,22 @@
}
};
const setCell = (i: number, j: number, v: string | undefined) => {
const setCell = (row: number, col: number, v: string | undefined) => {
// ignore “no value” so we dont create keys on mount
if (v == null || v === '') delete grid_vals[key(i, j)];
if (v == null || v === '') delete grid_vals[key(row, col)];
else {
setCellRaw(i, j, v);
console.log(i, j);
socket.send(`set ${refFromPos(i, j).str} ${v}`);
setCellRaw(row, col, v);
let msg: LeadMsg = {
msg_type: 'set',
cell: { row, col },
raw: v
};
socket.send(JSON.stringify(msg));
}
};
// $effect(() => {
// $inspect(grid_vals);
// });
function handleCellInteraction(i: number, j: number, e: MouseEvent) {
if (editing_cell) {
// Get the actual input element that's being edited
@@ -170,7 +145,7 @@
e.preventDefault();
// --- This is the same reference-inserting logic as before ---
const ref = refFromPos(i, j).str;
const ref = refToStr(i, j);
if (el) {
const { selectionStart, selectionEnd } = el;
const before = el.value.slice(0, selectionStart ?? 0);
@@ -202,15 +177,18 @@
});
</script>
<div class="grid-wrapper relative max-h-[100vh] max-w-full overflow-auto">
<div class="sticky top-0 z-40 flex w-fit">
<div class="sticky top-0 left-0 z-50">
<div
class={clsx('grid-wrapper relative h-full min-h-0 max-w-full min-w-0 overflow-auto', className)}
>
<div class="sticky top-0 flex w-fit" style="z-index: {rows + 70}">
<div class="sticky top-0 left-0" style="z-index: {rows + 70}">
<CellHeader
resizeable={false}
height={default_row_height}
width={default_col_width}
val=""
active={false}
direction="blank"
/>
</div>
@@ -226,8 +204,8 @@
{/each}
</div>
{#each Array(rows) as _, i}
<div class="flex w-fit">
<div class="sticky left-0 z-30 flex w-fit">
<div class="relative flex w-fit">
<div class="sticky left-0 flex w-fit" style="z-index: {rows - i + 40}">
<CellHeader
direction="row"
width={default_col_width}