diff --git a/src/uix/eidos/components/words/words-activate.svelte b/src/uix/eidos/components/words/words-activate.svelte index 168e06d93..2ed01e530 100644 --- a/src/uix/eidos/components/words/words-activate.svelte +++ b/src/uix/eidos/components/words/words-activate.svelte @@ -104,4 +104,16 @@ el.setAttribute('data-words-depth', String(segments.length)); } }); + + // There is ALWAYS an active block: on first load (no click yet) select the + // first top-level block so the inspector + the gutter rail have a target + // from the start instead of "nothing selected". + let seeded = false; + $effect(() => { + if (seeded || !enabled) return; + const first = api.document.children[0]; + if (!first?.id) return; + if (!api.activeBlockId) api.setActiveBlock(first.id); + seeded = true; + }); diff --git a/src/uix/eidos/components/words/words-active-rail.svelte b/src/uix/eidos/components/words/words-active-rail.svelte new file mode 100644 index 000000000..f31167fbf --- /dev/null +++ b/src/uix/eidos/components/words/words-active-rail.svelte @@ -0,0 +1,55 @@ + + +{#if rail} +
+{/if} diff --git a/src/uix/eidos/components/words/words.css b/src/uix/eidos/components/words/words.css index 6e01f6789..fecbb0161 100644 --- a/src/uix/eidos/components/words/words.css +++ b/src/uix/eidos/components/words/words.css @@ -1064,32 +1064,21 @@ button[data-words-breadcrumb-crumb]:focus-visible { (not border → zero reflow) shows the inspector's current target on the canvas. The hue shifts by depth so nested structure reads at a glance: blue at top level, then teal / violet / amber descending into columns. */ -[data-words-content] [data-words-active] { - position: relative; -} -/* The active-block marker lives in the GUTTER, not on the block: a vertical - accent rail in the left margin (`::before`, just left of the block) spanning - the block height. Depth-coloured via `--_words-active-outline`. The block - stays `position: relative` so the rail anchors to it. */ -[data-words-content] [data-words-active]::before { - content: ''; +/* Active-block rail — a single vertical bar in the GUTTER (left margin), at a + FIXED column (frame-relative, so it never shifts right for nested blocks), + one fixed colour. Its top/height track the active block; the rail element is + rendered by `words-active-rail.svelte` and positioned here. */ +[data-words-active-rail] { position: absolute; - inset-block: 0; - inset-inline-start: -0.7rem; + inset-inline-start: calc(var(--_words-content-px) - 1.4rem); + z-index: 1; inline-size: 3px; border-radius: 2px; - background: var(--_words-active-outline, var(--color-primary-solid)); + background: var(--color-primary-solid); pointer-events: none; - animation: words-outline-in var(--words-transition-duration) var(--words-transition-ease); -} -[data-words-content] [data-words-active][data-words-depth='2'] { - --_words-active-outline: var(--color-affirm-solid); /* teal — column level */ -} -[data-words-content] [data-words-active][data-words-depth='3'] { - --_words-active-outline: var(--color-loss-solid); /* violet — block in a column */ -} -[data-words-content] [data-words-active][data-words-depth='4'] { - --_words-active-outline: var(--color-risk-solid); /* amber — deeper nesting */ + transition: + top 120ms var(--words-transition-ease), + height 120ms var(--words-transition-ease); } [data-words-content] :where([data-words-node='block']):first-child { diff --git a/src/uix/eidos/components/words/words.svelte b/src/uix/eidos/components/words/words.svelte index b360425be..861c6bd3b 100644 --- a/src/uix/eidos/components/words/words.svelte +++ b/src/uix/eidos/components/words/words.svelte @@ -19,6 +19,7 @@ import { Popover } from '$uix/eidos/components/popover'; import { SlidersHorizontal, X } from '$uix/eidos/components/icon'; import WordsActivate from './words-activate.svelte'; + import WordsActiveRail from './words-active-rail.svelte'; import WordsBlockDrag from './words-block-drag.svelte'; import WordsBlockGutter from './words-block-gutter.svelte'; import WordsBubble from './words-bubble.svelte'; @@ -111,6 +112,7 @@ {#if contentEl}