diff --git a/.gitignore b/.gitignore index 0f5009b..687c8f9 100644 --- a/.gitignore +++ b/.gitignore @@ -26,4 +26,6 @@ references sveltekit-cloudflare-workers -inlay \ No newline at end of file +inlay + +scripts/backups \ No newline at end of file diff --git a/src/lib/cards/_base/BaseCard/BaseCard.svelte b/src/lib/cards/_base/BaseCard/BaseCard.svelte index 6c04aaa..a0f2597 100644 --- a/src/lib/cards/_base/BaseCard/BaseCard.svelte +++ b/src/lib/cards/_base/BaseCard/BaseCard.svelte @@ -45,8 +45,9 @@ draggable={false} class={[ fillPage - ? 'card group/card selection:bg-accent-600/50 focus-within:outline-accent-500 @container/card relative isolate z-0 h-full w-full outline-offset-2 transition-[outline] duration-200 focus-within:outline-2' - : 'card group/card selection:bg-accent-600/50 focus-within:outline-accent-500 @container/card absolute isolate z-0 rounded-3xl outline-offset-2 transition-[outline] duration-200 focus-within:outline-2', + ? 'card group/card selection:bg-accent-600/50 @container/card relative isolate z-0 h-full w-full outline-offset-2 transition-[outline] duration-200' + : 'card group/card selection:bg-accent-600/50 @container/card absolute isolate z-0 rounded-3xl outline-offset-2 transition-[outline] duration-200', + isEditing ? 'transition-all' : '', !fillPage ? (color ? (colors[color] ?? colors.accent) : colors.base) : '', color !== 'accent' && item.color !== 'base' && item.color !== 'transparent' ? color : '', showOutline ? 'outline-2' : '', diff --git a/src/lib/cards/_base/BaseCard/BaseEditingCard.svelte b/src/lib/cards/_base/BaseCard/BaseEditingCard.svelte index 3235d5c..5cba4d4 100644 --- a/src/lib/cards/_base/BaseCard/BaseEditingCard.svelte +++ b/src/lib/cards/_base/BaseCard/BaseEditingCard.svelte @@ -63,7 +63,21 @@ let selectedCardId = getSelectedCardId(); let selectCard = getSelectCard(); let isSelected = $derived(selectedCardId?.() === item.id); - let isDimmed = $derived(isCoarse?.() && selectedCardId?.() != null && !isSelected); + + // Track pointer down position so we only select on click, not on drag + let overlayDownX = 0; + let overlayDownY = 0; + function handleOverlayPointerDown(e: PointerEvent) { + overlayDownX = e.clientX; + overlayDownY = e.clientY; + } + function handleOverlayPointerUp(e: PointerEvent) { + const dx = Math.abs(e.clientX - overlayDownX); + const dy = Math.abs(e.clientY - overlayDownY); + if (dx < 5 && dy < 5) { + selectCard?.(item.id); + } + } let colorPopoverOpen = $state(false); @@ -184,25 +198,23 @@ {item} isEditing={true} bind:ref - showOutline={isResizing || (isCoarse?.() && isSelected)} + showOutline={isResizing || isSelected} locked={item.cardData?.locked} class={[ 'scale-100 starting:scale-0 starting:opacity-0', - isCoarse?.() && isSelected ? 'ring-accent-500 z-10 ring-2 ring-offset-2' : '', - isDimmed ? 'opacity-70' : 'opacity-100' + isSelected ? 'outline-accent-500 z-10' : '' ]} {...rest} > - {#if isCoarse?.() && !isSelected} - + {#if !isSelected} +
{ - e.stopPropagation(); - selectCard?.(item.id); - }} + class="absolute inset-0 z-20 cursor-pointer focus:outline-none" + onpointerdown={handleOverlayPointerDown} + onpointerup={handleOverlayPointerUp} >
{/if} {@render children?.()} @@ -299,7 +311,7 @@
(); - for (const card of data.cards) { - originalCardsById.set(card.id, card); - } - - // find all cards that have been updated (where items differ from originalItems) + // Save all current cards. We don't diff against originals because the + // server-side load can modify cards (e.g. fixing overlaps), so the + // "original" the client sees is already the post-fix version — there's + // nothing reliable to diff against. for (let item of currentItems) { - const orig = originalCardsById.get(item.id); - const originalItem = orig && cardsEqual(orig, item) ? orig : undefined; + item.updatedAt = new Date().toISOString(); + // run optional upload function for this card type + const cardDef = CardDefinitionsByType[item.cardType]; - if (!originalItem) { - console.log('updated or new item', item); - item.updatedAt = new Date().toISOString(); - // run optional upload function for this card type - const cardDef = CardDefinitionsByType[item.cardType]; - - if (cardDef?.upload) { - item = await cardDef?.upload(item); - } + if (cardDef?.upload) { + item = await cardDef?.upload(item); + } - const parsedItem = JSON.parse(JSON.stringify(item)); + const parsedItem = JSON.parse(JSON.stringify(item)); - parsedItem.page = data.page; - parsedItem.version = 2; + parsedItem.page = data.page; + parsedItem.version = 2; - promises.push( - putRecord({ - collection: 'app.blento.card', - rkey: parsedItem.id, - record: parsedItem - }) - ); - } + promises.push( + putRecord({ + collection: 'app.blento.card', + rkey: parsedItem.id, + record: parsedItem + }) + ); } // delete items that are in originalItems but not in items - for (const originalItem of data.cards) { + for (const originalItem of originalCards) { const item = currentItems.find((i) => i.id === originalItem.id); if (!item) { console.log('deleting item', originalItem); diff --git a/src/lib/layout/EditableGrid.svelte b/src/lib/layout/EditableGrid.svelte index 99522bf..73b129d 100644 --- a/src/lib/layout/EditableGrid.svelte +++ b/src/lib/layout/EditableGrid.svelte @@ -32,9 +32,14 @@ ref = container; }); - const getY = (item: Item) => (isMobile ? (item.mobileY ?? item.y) : item.y); - const getH = (item: Item) => (isMobile ? (item.mobileH ?? item.h) : item.h); - let maxHeight = $derived(items.reduce((max, item) => Math.max(max, getY(item) + getH(item)), 0)); + let maxHeight = $derived( + items.reduce((max, item) => { + const y = isMobile ? (item.mobileY ?? item.y) : item.y; + const h = isMobile ? (item.mobileH ?? item.h) : item.h; + return Math.max(max, y + h); + }, 0) + ); + // --- Drag state --- type Phase = 'idle' | 'pending' | 'active'; @@ -387,7 +392,12 @@ > {@render children()} -
+ +