apply: changes as per design reviews.

update: allow userColumns in the suggestions sheet.
This commit is contained in:
Darshan
2025-10-28 16:50:56 +05:30
parent c23dfa0621
commit cce531ed1f
3 changed files with 420 additions and 217 deletions
+2 -2
View File
@@ -24,9 +24,9 @@
"@ai-sdk/svelte": "^1.1.24",
"@appwrite.io/console": "https://pkg.pr.new/appwrite-labs/cloud/@appwrite.io/console@fe3277e",
"@appwrite.io/pink-icons": "0.25.0",
"@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc",
"@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43",
"@appwrite.io/pink-legacy": "^1.0.3",
"@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4",
"@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43",
"@faker-js/faker": "^9.9.0",
"@popperjs/core": "^2.11.8",
"@sentry/sveltekit": "^8.38.0",
+10 -10
View File
@@ -18,14 +18,14 @@ importers:
specifier: 0.25.0
version: 0.25.0
'@appwrite.io/pink-icons-svelte':
specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc
version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc(svelte@5.25.3)
specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43
version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43(svelte@5.25.3)
'@appwrite.io/pink-legacy':
specifier: ^1.0.3
version: 1.0.3
'@appwrite.io/pink-svelte':
specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4
version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4(svelte@5.25.3)
specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43
version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43(svelte@5.25.3)
'@faker-js/faker':
specifier: ^9.9.0
version: 9.9.0
@@ -269,8 +269,8 @@ packages:
peerDependencies:
svelte: ^4.0.0
'@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc':
resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc}
'@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43':
resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43}
version: 2.0.0-RC.1
peerDependencies:
svelte: ^4.0.0
@@ -284,8 +284,8 @@ packages:
'@appwrite.io/pink-legacy@1.0.3':
resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==}
'@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4':
resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4}
'@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43':
resolution: {tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43}
version: 2.0.0-RC.2
peerDependencies:
svelte: ^4.0.0
@@ -3709,7 +3709,7 @@ snapshots:
dependencies:
svelte: 5.25.3
'@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@50b60cc(svelte@5.25.3)':
'@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@85d1b43(svelte@5.25.3)':
dependencies:
svelte: 5.25.3
@@ -3722,7 +3722,7 @@ snapshots:
'@appwrite.io/pink-icons': 1.0.0
the-new-css-reset: 1.11.3
'@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@10305c4(svelte@5.25.3)':
'@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@85d1b43(svelte@5.25.3)':
dependencies:
'@appwrite.io/pink-icons-svelte': 2.0.0-RC.1(svelte@5.25.3)
'@floating-ui/dom': 1.6.13
@@ -11,10 +11,12 @@
Popover,
Badge
} from '@appwrite.io/pink-svelte';
import { IconFingerPrint, IconPlus } from '@appwrite.io/pink-icons-svelte';
import { IconFingerPrint, IconPlus, IconText } from '@appwrite.io/pink-icons-svelte';
import { isSmallViewport, isTabletViewport } from '$lib/stores/viewport';
import type { Column } from '$lib/helpers/types';
import { expandTabs } from '../table-[table]/store';
import { SortButton } from '$lib/components';
import { expandTabs, columnsOrder, columnsWidth, reorderItems } from '../table-[table]/store';
import { preferences } from '$lib/stores/preferences';
import SpreadsheetContainer from '../table-[table]/layout/spreadsheet.svelte';
import { onDestroy, onMount, tick } from 'svelte';
import { sdk } from '$lib/stores/sdk';
@@ -49,6 +51,47 @@
userColumns?: Column[];
} = $props();
const tableId = page.params.table;
const minimumUserColumnWidth = 168;
function getUserColumnWidth(
columnId: string,
defaultWidth: number | { min: number }
): number | { min: number; max?: number } {
const savedWidth = $columnsWidth?.[columnId];
if (!savedWidth) return defaultWidth;
return savedWidth.resized;
}
// apply order & width to user columns
const staticUserColumns = $derived.by(() => {
if (!userColumns.length) return [];
// apply widths to columns
const columnsWithWidths = userColumns.map((column) => {
const defaultWidth =
typeof column.width === 'object' && 'min' in column.width
? column.width
: typeof column.width === 'number'
? column.width
: minimumUserColumnWidth;
return {
...column,
width: getUserColumnWidth(column.id, defaultWidth),
resizable: false,
draggable: false
};
});
// apply ordering if preferences exist
if ($columnsOrder && $columnsOrder.length > 0) {
return reorderItems(columnsWithWidths, $columnsOrder);
}
return columnsWithWidths;
});
let resizeObserver: ResizeObserver;
let spreadsheetContainer: HTMLElement;
@@ -163,17 +206,43 @@
if (!hasRealColumns) {
// for placeholders or no columns,
// position overlay to cover custom columns area
const idCell = getById('$id');
let startCell = getById('$id');
if (staticUserColumns.length > 0) {
const lastUserColumn = staticUserColumns[staticUserColumns.length - 1];
let lastUserCell = getById(lastUserColumn.id);
// if not found with data-header="true", try without it
if (!lastUserCell) {
lastUserCell = headerElement!.querySelector<HTMLElement>(
`[role="cell"][data-column-id="${lastUserColumn.id}"]`
);
}
if (lastUserCell) {
startCell = lastUserCell;
}
}
const actionsCell = headerElement!.querySelector<HTMLElement>(
'[role="cell"][data-column-id="actions"]'
);
if (idCell && actionsCell) {
const idRect = idCell.getBoundingClientRect();
if (startCell && actionsCell) {
const startRect = startCell.getBoundingClientRect();
const actionsRect = actionsCell.getBoundingClientRect();
const left = Math.round(idRect.right - containerRect.left);
let left = Math.round(startRect.right - containerRect.left);
const actionsLeft = actionsRect.left - containerRect.left;
// ensure overlay doesn't go over select
const selectionRect = spreadsheetContainer
.querySelector('[data-select="true"]')
?.getBoundingClientRect();
if (selectionRect) {
const selectionRight = Math.round(selectionRect.right - containerRect.left);
left = Math.max(left, selectionRight);
}
const width = actionsLeft - left;
spreadsheetContainer.style.setProperty('--group-left', `${left - 2}px`);
@@ -226,15 +295,41 @@
.querySelector('[data-select="true"]')
?.getBoundingClientRect();
// Start overlay after selection column if it exists, otherwise after $id
// determine starting point for overlay
let startLeft = idRect.right;
if (selectionRect && selectionRect.right > idRect.right) {
startLeft = selectionRect.right;
}
// if userColumns exist,
// start overlay **after** the last userColumn
if (staticUserColumns.length > 0) {
const lastUserColumn = staticUserColumns[staticUserColumns.length - 1];
let lastUserCell = getById(lastUserColumn.id);
if (!lastUserCell) {
lastUserCell = headerElement!.querySelector<HTMLElement>(
`[role="cell"][data-column-id="${lastUserColumn.id}"]`
);
}
if (lastUserCell) {
const lastUserRect = lastUserCell.getBoundingClientRect();
startLeft = lastUserRect.right;
}
}
if (selectionRect) {
startLeft = Math.max(startLeft, selectionRect.right);
}
const left = Math.round(startLeft - containerRect.left);
// get the actions column and use its left border as the boundary
// use the last visible custom column's right edge as the overlay boundary
const endRect = endCell.getBoundingClientRect();
const endRight = Math.round(endRect.right - containerRect.left);
// also get the actions column to ensure we don't exceed it
const actionsCell = headerElement!.querySelector<HTMLElement>(
'[role="cell"][data-column-id="actions"]'
);
@@ -249,7 +344,9 @@
const actionsRect = actionsCell.getBoundingClientRect();
const actionsLeft = actionsRect.left - containerRect.left;
const width = actionsLeft - left;
// ensure overlay doesn't exceed bounds
const right = Math.min(endRight, actionsLeft);
const width = right - left;
// Apply overlay positioning
spreadsheetContainer.style.setProperty('--group-left', `${left - 2}px`);
@@ -258,26 +355,37 @@
// only for mobile, we can remove if not needed!
const scrollToFirstCustomColumn = () => {
if (!$isSmallViewport) return;
if (!staticUserColumns.length && !$isSmallViewport) return;
if (!headerElement || !headerElement.isConnected) {
headerElement = spreadsheetContainer.querySelector('[role="rowheader"]');
headerElement = spreadsheetContainer?.querySelector('[role="rowheader"]');
}
if (!headerElement) return;
const firstCustomColumnCell = headerElement.querySelector<HTMLElement>(
`[role="cell"][data-header="true"][data-column-id="${customColumns[0]?.key}"]`
);
const directAccessScroller =
hScroller ??
findHorizontalScroller(headerElement) ??
// internal spreadsheet root main container!
spreadsheetContainer.querySelector('.spreadsheet-container');
if (firstCustomColumnCell && directAccessScroller) {
const cellRect = firstCustomColumnCell.getBoundingClientRect();
if (!directAccessScroller) return;
let targetCell: HTMLElement | null = null;
if (staticUserColumns.length > 0) {
const lastUserColumn = staticUserColumns[staticUserColumns.length - 1];
targetCell = headerElement.querySelector<HTMLElement>(
`[role="cell"][data-header="true"][data-column-id="${lastUserColumn.id}"]`
);
} else {
targetCell = headerElement.querySelector<HTMLElement>(
`[role="cell"][data-header="true"][data-column-id="${customColumns[0]?.key}"]`
);
}
if (targetCell) {
const cellRect = targetCell.getBoundingClientRect();
const scrollerRect = directAccessScroller.getBoundingClientRect();
const scrollLeft =
directAccessScroller.scrollLeft + cellRect.left - scrollerRect.left - 40;
@@ -314,15 +422,53 @@
const isHovered = !selectedColumnId && hoveredColumnId;
const isFirstColumn = activeColumnId === customColumns[0]?.key;
const isLastColumn = activeColumnId === customColumns[customColumns.length - 1]?.key;
let leftAdjustment = -2;
let widthAdjustment = 2;
if (isHovered && isFirstColumn) {
if (isHovered && (isFirstColumn || isLastColumn)) {
leftAdjustment = 0;
}
// get actions boundary to prevent hover overlay over it
const actionsCell = headerElement.querySelector<HTMLElement>(
'[role="cell"][data-column-id="actions"]'
);
let finalWidth = width + widthAdjustment;
if (isHovered && actionsCell) {
const actionsRect = actionsCell.getBoundingClientRect();
const actionsLeft = actionsRect.left - containerRect.left;
const overlayRight = left + leftAdjustment + finalWidth;
const borderWidth = 2;
if (overlayRight + borderWidth > actionsLeft) {
finalWidth = actionsLeft - (left + leftAdjustment) - borderWidth;
}
}
spreadsheetContainer.style.setProperty('--highlight-left', `${left + leftAdjustment}px`);
spreadsheetContainer.style.setProperty('--highlight-width', `${width + widthAdjustment}px`);
spreadsheetContainer.style.setProperty('--highlight-width', `${finalWidth}px`);
if (isHovered) {
const tooltipElement =
spreadsheetContainer.querySelector<HTMLElement>('.custom-tooltip');
const tooltipWidth = tooltipElement ? tooltipElement.offsetWidth : 200;
const defaultOffset = 325;
const smallerOffset = 225;
const viewportWidth = window.innerWidth;
// check how much space is available to the right of the column
const columnRightEdge = left + leftAdjustment + finalWidth;
const availableSpace = viewportWidth - columnRightEdge;
// use smaller offset if there isn't enough space for default offset + tooltip
const shouldUseSmallerOffset = availableSpace < defaultOffset + tooltipWidth;
const tooltipOffset = shouldUseSmallerOffset ? smallerOffset : defaultOffset;
spreadsheetContainer.style.setProperty('--tooltip-offset', `${tooltipOffset}px`);
}
}
const recalcAll = () => {
@@ -345,6 +491,10 @@
resetSelectedColumn();
}
if (hoveredColumnId && !isColumnVisible(hoveredColumnId)) {
hoveredColumnId = null;
}
scrollAnimationFrame = null;
});
};
@@ -375,29 +525,31 @@
const minColumnWidth = 180;
const fixedWidths = { id: minColumnWidth, actions: 40, selection: 40 };
// calculate base widths and total
const columnsWithBase = customSuggestedColumns.map((col) => ({
...col,
baseWidth: Math.max(minColumnWidth, getColumnWidth(col.id))
}));
const equalWidthColumns = [...staticUserColumns, ...customSuggestedColumns];
const totalUsed =
const totalBaseWidth =
fixedWidths.id +
fixedWidths.actions +
fixedWidths.selection +
columnsWithBase.reduce((sum, col) => sum + col.baseWidth, 0);
equalWidthColumns.length * minColumnWidth;
// distribute excess space equally across custom columns
const viewportWidth =
spreadsheetContainer?.clientWidth ||
(typeof window !== 'undefined' ? window.innerWidth : totalUsed);
(typeof window !== 'undefined' ? window.innerWidth : totalBaseWidth);
const excessSpace = Math.max(0, viewportWidth - totalBaseWidth);
const extraPerColumn =
Math.max(0, viewportWidth - totalUsed) / (columnsWithBase.length || 1);
equalWidthColumns.length > 0 ? excessSpace / equalWidthColumns.length : 0;
const distributedWidth = minColumnWidth + extraPerColumn;
const finalCustomColumns = columnsWithBase.map((col) => ({
const userColumnsWithWidth = staticUserColumns.map((col) => ({
...col,
width: { min: col.baseWidth + extraPerColumn }
width: distributedWidth
}));
const finalCustomColumns = customSuggestedColumns.map((col) => ({
...col,
width: { min: distributedWidth }
}));
return [
@@ -409,8 +561,8 @@
icon: IconFingerPrint,
...baseColProps
},
...userColumnsWithWidth,
...finalCustomColumns,
/*...userColumns,*/
{
id: 'actions',
title: '',
@@ -426,7 +578,8 @@
const emptyCells = $derived(($isSmallViewport ? 14 : 17) + (!$expandTabs ? 2 : 0));
onMount(async () => {
userColumns; /* silences lint check, variable not read */
columnsOrder.set(preferences.getColumnOrder(tableId));
columnsWidth.set(preferences.getColumnWidths(tableId));
if (spreadsheetContainer) {
resizeObserver = new ResizeObserver(recalcAll);
@@ -460,10 +613,8 @@
async function suggestColumns() {
$tableColumnSuggestions.thinking = true;
if ($isSmallViewport) {
await tick();
scrollToFirstCustomColumn();
}
await tick();
scrollToFirstCustomColumn();
let suggestedColumns: {
total: number;
@@ -1031,6 +1182,23 @@
}
});
// mark suggested column cells so CSS can target them specifically
$effect(() => {
if (!spreadsheetContainer) return;
// get all custom column IDs
const suggestedColumnIds = customColumns.map((col) => col.key);
const allCells = spreadsheetContainer.querySelectorAll('[role="cell"][data-column-id]');
allCells.forEach((cell) => {
const columnId = cell.getAttribute('data-column-id');
if (columnId && suggestedColumnIds.includes(columnId)) {
cell.setAttribute('data-suggested-column', 'true');
} else {
cell.removeAttribute('data-suggested-column');
}
});
});
$effect(() => {
if (!spreadsheetContainer) return;
@@ -1093,11 +1261,16 @@
<!-- selection border -->
{#if selectedColumnId || hoveredColumnId}
{@const activeColumnId = selectedColumnId || hoveredColumnId}
{@const isHovered = !selectedColumnId && hoveredColumnId}
{@const isFirstColumn = activeColumnId === customColumns[0]?.key}
{@const isLastColumn = activeColumnId === customColumns[customColumns.length - 1]?.key}
<div
class="column-highlight-overlay"
class:hover={isHovered}
class:selected={!isHovered}
class:last-column={isHovered && isLastColumn}
class:first-column={isHovered && isFirstColumn}
class:slide={previousColumnId !== null && !isHovered}
style:height="100%"
style:left="var(--highlight-left, 0px)"
@@ -1134,160 +1307,188 @@
: '--overlay-icon-color'}
{@const isColumnInteractable =
isCustomColumn(column.id) && columnObj && !columnObj.isPlaceholder}
{@const isUserColumn =
column.id === '$id' ||
staticUserColumns.some((col) => col.id === column.id)}
<Options
enabled={isColumnInteractable}
headerTooltipText={isColumnInteractable && showHeadTooltip
? 'Right click for advanced editing'
: undefined}
onShowStateChanged={onPopoverShowStateChanged}
triggerOpen={() => {
if (triggerColumnId === column.id) {
triggerColumnId = null;
return true;
}
{#if isUserColumn}
<Spreadsheet.Header.Cell
{root}
column={column.id}
icon={column.icon ?? IconText}>
<Layout.Stack
gap="xs"
direction="row"
alignItems="center"
alignContent="center"
style="min-width: 0;">
<Typography.Text truncate>
{column.title}
</Typography.Text>
return false;
}}>
{#snippet children(toggle)}
<Spreadsheet.Header.Cell
{root}
isEditable={isColumnInteractable && !$isTabletViewport}
openEditOnTap={isColumnInteractable && !$isTabletViewport}
column={column.id}
on:contextmenu={(event) => {
// tablet viewport check because context-menu
// can be triggered on long hold clicks as well!
if (isColumnInteractable && !$isTabletViewport) {
toggle(event);
}
}}>
<Layout.Stack
direction="row"
alignItems="center"
alignContent="center"
justifyContent="space-between">
<span
class="column-title"
class:animate-in={!columnObj?.isPlaceholder}
style:--animation-delay={`${isColumnInteractable ? (index - 1) * 100 : 0}ms`}>
{column.title}
</span>
<SortButton disabled={true} column={column.id} />
</Layout.Stack>
</Spreadsheet.Header.Cell>
{:else}
<Options
enabled={isColumnInteractable}
headerTooltipText={isColumnInteractable && showHeadTooltip
? 'Right click for advanced editing'
: undefined}
onShowStateChanged={onPopoverShowStateChanged}
triggerOpen={() => {
if (triggerColumnId === column.id) {
triggerColumnId = null;
return true;
}
{@render changeColumnTypePopover({
id: column.id,
columnObj,
iconColor: columnIconColor,
icon: column.icon,
isColumnInteractable,
index
})}
</Layout.Stack>
<svelte:fragment slot="cell-editor">
{#if !$isTabletViewport}
<div
class="cell-editor"
onfocusin={() => {
isInlineEditing = true;
showHeadTooltip = false;
resetSelectedColumn();
handlePreviousColumnsBorder(column.id);
}}
onfocusout={() => {
showHeadTooltip = true;
isInlineEditing = false;
handlePreviousColumnsBorder(column.id, false);
}}>
<InputText
id="key"
autofocus
required
bind:value={columnObj.key}
pattern="^[A-Za-z0-9][A-Za-z0-9._\-]*$">
<svelte:fragment slot="end">
{#if columnIcon}
{@render changeColumnTypePopover({
id: column.id,
columnObj,
iconColor: columnIconColor,
icon: column.icon,
isColumnInteractable,
index
})}
{/if}
</svelte:fragment>
</InputText>
</div>
{/if}
</svelte:fragment>
</Spreadsheet.Header.Cell>
{/snippet}
{#snippet tooltipChildren()}
{#if columnObj}
{@const selectedOption = getColumnOption(
columnObj.type,
columnObj.format
)}
{@const ColumnComponent = selectedOption?.component}
<Layout.Stack gap="xl">
return false;
}}>
{#snippet children(toggle)}
<Spreadsheet.Header.Cell
{root}
isEditable={isColumnInteractable && !$isTabletViewport}
openEditOnTap={isColumnInteractable && !$isTabletViewport}
column={column.id}
on:contextmenu={(event) => {
// tablet viewport check because context-menu
// can be triggered on long hold clicks as well!
if (isColumnInteractable && !$isTabletViewport) {
toggle(event);
}
}}>
<Layout.Stack
direction={$isSmallViewport ? 'column' : 'row'}>
<InputText
id="key"
label="Key"
placeholder="Enter key"
bind:value={columnObj.key}
autofocus
required
pattern="^[A-Za-z0-9][A-Za-z0-9._\-]*$" />
direction="row"
alignItems="center"
alignContent="center"
justifyContent="space-between">
<span
class="column-title"
class:animate-in={!columnObj?.isPlaceholder}
style:--animation-delay={`${isColumnInteractable ? (index - 1) * 100 : 0}ms`}>
{column.title}
</span>
<InputSelect
id="type"
required
label="Type"
value={selectedOption?.name || 'String'}
on:change={(e) => {
const newOption = columnOptions.find(
(opt) => opt.name === e.detail
);
if (newOption) {
updateColumn(column.id, {
type: newOption.type,
format: newOption.format || null
});
}
}}
options={basicColumnOptions.map((col) => {
return {
label: col.name,
value: col.name,
leadingIcon: col.icon
};
})} />
{@render changeColumnTypePopover({
id: column.id,
columnObj,
iconColor: columnIconColor,
icon: column.icon,
isColumnInteractable,
index
})}
</Layout.Stack>
{#if ColumnComponent}
<ColumnComponent data={columnObj} autoIncreaseSize />
{/if}
</Layout.Stack>
{/if}
{/snippet}
<svelte:fragment slot="cell-editor">
{#if !$isTabletViewport}
<div
class="cell-editor"
onfocusin={() => {
isInlineEditing = true;
showHeadTooltip = false;
resetSelectedColumn();
handlePreviousColumnsBorder(column.id);
}}
onfocusout={() => {
showHeadTooltip = true;
isInlineEditing = false;
handlePreviousColumnsBorder(
column.id,
false
);
}}>
<InputText
id="key"
autofocus
required
bind:value={columnObj.key}
pattern="^[A-Za-z0-9][A-Za-z0-9._\-]*$">
<svelte:fragment slot="end">
{#if columnIcon}
{@render changeColumnTypePopover({
id: column.id,
columnObj,
iconColor: columnIconColor,
icon: column.icon,
isColumnInteractable,
index
})}
{/if}
</svelte:fragment>
</InputText>
</div>
{/if}
</svelte:fragment>
</Spreadsheet.Header.Cell>
{/snippet}
{#snippet mobileFooterChildren(toggle)}
<Button.Button
size="s"
variant="danger"
on:click={(event) => {
toggle(event);
deleteColumn(column.id);
}}
style="position: absolute; left: 1rem;"
>Delete
</Button.Button>
{/snippet}
</Options>
{#snippet tooltipChildren()}
{#if columnObj}
{@const selectedOption = getColumnOption(
columnObj.type,
columnObj.format
)}
{@const ColumnComponent = selectedOption?.component}
<Layout.Stack gap="xl">
<Layout.Stack
direction={$isSmallViewport ? 'column' : 'row'}>
<InputText
id="key"
label="Key"
placeholder="Enter key"
bind:value={columnObj.key}
autofocus
required
pattern="^[A-Za-z0-9][A-Za-z0-9._\-]*$" />
<InputSelect
id="type"
required
label="Type"
value={selectedOption?.name || 'String'}
on:change={(e) => {
const newOption = columnOptions.find(
(opt) => opt.name === e.detail
);
if (newOption) {
updateColumn(column.id, {
type: newOption.type,
format: newOption.format || null
});
}
}}
options={basicColumnOptions.map((col) => {
return {
label: col.name,
value: col.name,
leadingIcon: col.icon
};
})} />
</Layout.Stack>
{#if ColumnComponent}
<ColumnComponent
data={columnObj}
autoIncreaseSize />
{/if}
</Layout.Stack>
{/if}
{/snippet}
{#snippet mobileFooterChildren(toggle)}
<Button.Button
size="s"
variant="danger"
on:click={(event) => {
toggle(event);
deleteColumn(column.id);
}}
style="position: absolute; left: 1rem;"
>Delete
</Button.Button>
{/snippet}
</Options>
{/if}
{/if}
{/each}
</svelte:fragment>
@@ -1607,37 +1808,29 @@
}
&:has(.columns-range-overlay) {
:global(
[role='rowheader']
[role='cell']:has(.column-resizer-disabled):not([data-column-id^='$']):not(
[data-column-id='actions']
)
) {
:global([role='rowheader'][data-suggested-column='true']) {
background: var(--columns-range-pink-header-background-color);
}
:global(
[role='rowheader']
span:has([data-column-id='$id'])
+ span
[role='cell']:has(.column-resizer-disabled)
) {
margin-left: -2px;
}
:global(
[role='cell']:has(.column-resizer-disabled):not([data-column-id^='$']):not(
[data-column-id='actions']
)
) {
:global([role='cell']:has(.column-resizer-disabled)[data-suggested-column='true']) {
box-shadow: 0 -1px 0 0 var(--columns-range-pink-border-color) inset !important;
transition: box-shadow 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
:global([role='cell']:not([data-column-id='actions']) .column-resizer-disabled) {
:global(
[role='cell']:not([data-column-id='actions'])[data-suggested-column='true']
.column-resizer-disabled
) {
border-left: var(--border-width-s, 1px) solid var(--columns-range-pink-border-color) !important;
transition: border-color 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94);
}
:global(
[role='cell'][data-suggested-column='true']:has(+ [data-column-id='actions'])
.column-resizer-disabled
) {
display: none !important;
}
}
.column-highlight-overlay {
@@ -1653,10 +1846,20 @@
}
&.hover {
margin-left: 0;
background: rgba(253, 54, 110, 0.05);
border-radius: var(--border-radius-xxs);
border: var(--border-width-m) solid rgba(253, 54, 110, 0.24);
transition: background 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94);
&.first-column,
&.last-column {
margin-left: -2px;
}
&.last-column {
width: calc(var(--highlight-width, 0px) + 4.5px) !important;
}
}
&.slide {
@@ -1973,7 +2176,7 @@
border-radius: var(--border-radius-s);
padding: var(--space-2) var(--space-4);
background: var(--bgcolor-neutral-invert-weak);
left: calc(var(--highlight-left, 0px) + 325px);
left: calc(var(--highlight-left, 0px) + var(--tooltip-offset, 325px));
transition:
top 0.25s cubic-bezier(0.25, 0.46, 0.45, 0.94),