From 030d3e878a9d9992323a160adf2357e48058e19d Mon Sep 17 00:00:00 2001 From: Philipinho <16838612+Philipinho@users.noreply.github.com> Date: Mon, 27 Apr 2026 04:13:34 +0100 Subject: [PATCH] feat(base): extend inline embed scroll viewport leftward, anchor first cell with grid padding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bring back the leftward extension via negative margin-left so the scroll viewport reaches AppShell.Main's left edge, then offset the .grid with padding-left = extendLeft so the first cell still lines up with page-content on load. The extended area becomes scrollable empty space the user can pan into — same shape as Notion's inline databases. Done with one new CSS var (--embed-grid-pad-left) consumed by the .grid in grid.module.css. Standalone full-page bases never set the var, so it's a no-op there. --- .../features/base/components/base-table.tsx | 14 +++++++------ .../src/features/base/styles/grid.module.css | 6 ++++++ .../components/base-embed/base-embed-view.tsx | 21 ++++++++++++------- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/apps/client/src/features/base/components/base-table.tsx b/apps/client/src/features/base/components/base-table.tsx index 6dc00aa78..e1b31949e 100644 --- a/apps/client/src/features/base/components/base-table.tsx +++ b/apps/client/src/features/base/components/base-table.tsx @@ -315,14 +315,16 @@ export function BaseTable({ pageId, embedded }: BaseTableProps) { if (!base) return null; // When embedded inline in a doc page, the parent - // exposes --embed-extend-r (positive px). We pull the grid's right - // edge outward via negative margin-right — box-model: width: auto - // becomes parent_width + |margin|, so the box physically grows past - // its parent's bounds. Left edge stays at the wrapper's natural - // (page-content) position so the table aligns with page text on - // load. Toolbar is unchanged. + // exposes --embed-extend-l / --embed-extend-r (positive px). We + // pull both edges outward via negative margin so the scroll viewport + // grows toward AppShell.Main's edges. Initial visual alignment with + // page text is preserved by --embed-grid-pad-left, applied to the + // .grid in grid.module.css — that padding makes the first cell sit + // at page-content-left on load while still letting the user pan + // left into the extended viewport. Toolbar is unchanged. const gridExtendStyle = embedded ? ({ + marginLeft: "calc(-1 * var(--embed-extend-l, 0px))", marginRight: "calc(-1 * var(--embed-extend-r, 0px))", } as const) : undefined; diff --git a/apps/client/src/features/base/styles/grid.module.css b/apps/client/src/features/base/styles/grid.module.css index 2dccc4dec..f5dc16a32 100644 --- a/apps/client/src/features/base/styles/grid.module.css +++ b/apps/client/src/features/base/styles/grid.module.css @@ -13,6 +13,12 @@ border: 1px solid light-dark(var(--mantine-color-gray-2), var(--mantine-color-dark-4)); border-radius: var(--mantine-radius-sm); + /* When the embed wrapper extends the scroll viewport leftward, this + * padding pushes the first cell back to page-content alignment so + * the table looks aligned on load. The padded area is part of the + * scrollable region — the user can pan left into it. Standalone + * full-page bases never set the var, so it's a no-op there. */ + padding-left: var(--embed-grid-pad-left, 0); } .headerRow { diff --git a/apps/client/src/features/editor/components/base-embed/base-embed-view.tsx b/apps/client/src/features/editor/components/base-embed/base-embed-view.tsx index 4922aad1c..8da3401f6 100644 --- a/apps/client/src/features/editor/components/base-embed/base-embed-view.tsx +++ b/apps/client/src/features/editor/components/base-embed/base-embed-view.tsx @@ -6,23 +6,28 @@ import { useBaseQuery } from "@/features/base/queries/base-query"; const SIDE_GUTTER = 8; -// Extend the grid only to the right — toward AppShell.Main's right -// edge. The left edge stays at the wrapper's natural (page-content) -// position so the table is visually aligned with the page text on -// load, matching Notion. Leftward scroll-viewport extension is only -// meaningful once we add frozen columns that need to lock at the -// sidebar edge; deferred until then. +// Extend the scroll viewport on both sides (toward AppShell.Main's +// edges), but offset the grid content with padding-left = extendLeft +// so the first cell still lines up with page-content on load. The +// extra leftward area becomes scrollable empty space the user can +// pan into — same behavior as Notion's inline databases. function applyExtension(wrapper: HTMLDivElement) { const rect = wrapper.getBoundingClientRect(); if (rect.width === 0) return; const main = wrapper.closest("main") as HTMLElement | null; - const targetRight = main - ? main.getBoundingClientRect().right - SIDE_GUTTER + const mainRect = main?.getBoundingClientRect(); + const targetLeft = (mainRect?.left ?? 0) + SIDE_GUTTER; + const targetRight = mainRect + ? mainRect.right - SIDE_GUTTER : window.innerWidth - SIDE_GUTTER; + const extendLeft = Math.max(0, rect.left - targetLeft); const extendRight = Math.max(0, targetRight - rect.right); + + wrapper.style.setProperty("--embed-extend-l", `${extendLeft}px`); wrapper.style.setProperty("--embed-extend-r", `${extendRight}px`); + wrapper.style.setProperty("--embed-grid-pad-left", `${extendLeft}px`); } export function BaseEmbedView({ node }: NodeViewProps) {