diff --git a/AGENTS.md b/AGENTS.md index 81cf259c6..80f6780a4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,4 +1,5 @@ # Nexter (da-nx) + A shell/framework for Adobe AEM Edge Delivery Services. Provides shared blocks, styles, scripts, and utilities consumed by Adobe sites like da.live. ## Decisions & rationale @@ -49,6 +50,11 @@ A shell/framework for Adobe AEM Edge Delivery Services. Provides shared blocks, - Functions and styles in the public SDK cannot be broken in any way, they must always maintain backwards compatibility or provide an in-place upgrade of existing functionality. - Any commits to `/nx/public` must be intentional as they may be used in the wild. +## Reuse before building + +- Before implementing a utility, parser, or helper, check whether an equivalent already exists in the codebase — search both `nx/` and `nx2/`. Common examples: markdown parsing (`nx/deps/mdast`), IMS auth (`nx2/utils/ims.js`), hash routing (`nx2/utils/utils.js`). +- Also check `package.json` dependencies before reaching for a third-party package. The project already bundles remark, unified, mdast utilities, Lit, CodeMirror, and others that can be reused rather than re-implemented. + ## JavaScript conventions not enforced by lint - As a project purposefully avoiding TypeScript and build tools, be mindful of how variables and properties are named. If you see `somethingUrl`, this should be a proper URL object. If you see `href` this would imply a string that has all parts of a url: origin, pathname, search, hash, etc. but is not an actual URL object. diff --git a/WORKLOG.md b/WORKLOG.md index 2f8d3bdbc..cecead2cb 100644 --- a/WORKLOG.md +++ b/WORKLOG.md @@ -1,9 +1,150 @@ # Worklog +## 2026-05-11 + +### Remove `/index` stripping from `nx2/utils/utils.js` + +Removed the 3-line block in `parseWindowPath` that redirected `#/org/site/path/index` → `#/org/site/path`: + +```js +if (location.hash.endsWith('/index')) { + const clean = location.hash.slice(0, -5); + history.replaceState(null, '', clean); +} +``` + +**Reasoning:** `parseWindowPath` is shared by both browse and canvas. In canvas (da-live), this silently redirected hash URLs before the editor could read the path, breaking direct links to `index` files (e.g. `/canvas#/org/site/path/index`). The stripping was introduced by Claude in commit `9626865e` with no explanation — likely a browse UX convention (index ≡ directory) applied incorrectly to a shared parser. Removed from `nx2` only; `nx` is left unchanged as it's a separate code path. + +## 2026-05-08 + +### quick-edit merge conflict + +Resolved `origin/main` ↔ branch conflict in `nx/public/plugins/quick-edit/quick-edit.js`: kept a single `handleReady`, retained branch `checkDomain` + parent-controller flow, removed duplicate `checkDomain()` invocation left from the merge. + +## 2026-05-06 + +### Phase 3 continued — chat and tool-panel moved into da-live + +Moved `nx2/blocks/chat/` and `nx2/blocks/tool-panel/` from da-nx into da-live as `blocks/ew-chat/` and `blocks/ew-tool-panel/`, following the same procedure as canvas/inventory. + +**What landed in da-live `ew`:** +- `blocks/ew-chat/` — full chat block with sub-components (`pills`, `prompts`, `welcome`), controller, persistence, renderers, utils +- `blocks/ew-tool-panel/` — tool panel (picker, fullsize-dialog, header actions) +- `deps/mdast/` — copied from da-nx; used by `renderers.js` for markdown rendering + +**Custom element renames:** +- `nx-chat` → `ew-chat` +- `nx-tool-panel` → `ew-tool-panel` +- Internal sub-elements (`nx-chat-welcome`, `nx-chat-pills`, `nx-prompts`) kept as-is + +**Import adaptations:** +- `../../utils/utils.js` → `../shared/nxutils.js` (loadStyle, hashChange, getNx, DA_ADMIN) +- `../../utils/api.js` daFetch → `../shared/utils.js` daFetch (positional signature); api.js call site updated +- `../../utils/ims.js` loadIms → `../shared/utils.js` initIms (aliased as loadIms) +- `../shared/menu/menu.js` (static) → `await import(\`\${getNx()}/blocks/shared/menu/menu.js\`)` (top-level dynamic; menu stays in shell) +- `../../shared/picker/picker.js` (static) → `await import(\`\${getNx()}/blocks/shared/picker/picker.js\`)` in prompts.js and tool-panel.js + +**Icon migration applied (per feedback_icon_migration.md):** +- Removed `loadHrefSvg` / `ICONS_BASE` / `loadChatIcons` from all files +- chat.js: `ICON_SRCS` map with `/img/icons/s2-icon-*-20-n.svg` URLs; `icon()` returns `` TemplateResult +- tool-panel.js: close icon now `` +- CSS: `svg` selectors → `img`; removed `path { fill: ... }` rules; `/nx2/img/icons/` → `/img/icons/` (lowercase kebab); added `filter: invert(1)` on `.action-btn img` for dark-background buttons + +**canvas.js + inventory.js updated:** +- Dynamic imports now point to local `../ew-chat/chat.js` and `../ew-tool-panel/tool-panel.js` +- `document.createElement('nx-chat/nx-tool-panel')` → `ew-chat/ew-tool-panel` +- `querySelector('nx-tool-panel')` selectors updated to `ew-tool-panel` +- Removed `getNx` from canvas.js imports (no longer needed there) + +## 2026-04-28 + +### nx2 canvas — library vs extension panel split +- **`nx-panel-library.js`**: OOTB block library / templates / icons / placeholders UI (fetch, insert, preview, sprites); shares **`nx-panel-extensions.css`** with the iframe host. +- **`nx-panel-extensions.js`**: **`nx-panel-extension`** only chooses **`nx-panel-library`** vs BYO **`iframe`** + **`iframe-protocol`**. + +### nx2 canvas — tool panel sections (Editor / Library / Extensions) +- **`helpers.js`**: **`getCanvasToolPanelViews`** — Editor placeholder tab (`editor-coming-soon`), **Library** = OOTB plugins + **`aem-assets`** (sorted **`blocks` → `aem-assets` → `icons` → `templates` → `placeholders`**), **Extensions** = other configured plugins. +- **`tool-panel.js` / `.css`**: Picker items built with **`nx-picker`** **`section`** headings; initial tab is **`views[0]`**; prune **`_loaded`** / clear content when **`views`** empty or ids change. Placeholder host class **`.nx-tool-panel-editor-placeholder`**. +- **`canvas.js`**: loads **`getCanvasToolPanelViews`** instead of **`getExtensionViews`**. + +### nx2 utils — DA config API +- **`nx2/utils/daConfig.js`**: **`getFirstSheet`**, **`fetchDaConfigs`** (moved from **`nx-panel-extensions/config.js`**). Canvas **`helpers.js`** / **`aem-assets.js`** import from utils; branch **`ref`** stays local to **`helpers.js`**. + +### nx2 canvas — library panel action icons (da.live parity) +- **`nx-panel-extensions.js` / `.css`**: Add / Preview use the same **`/blocks/edit/img/`** SVGs and **`` / `#S2_Icon_ExperiencePreview`** pattern as da.live **`da-library`** (via shared **`inlinesvg`** preload). Source SVGs live in **`.ext-svg-sprites`** (visually hidden) so they are not laid out in the panel body. + +### nx2 canvas — block variants: no inline DOM preview +- **`nx-panel-extensions.js` / `.css`**: variant rows no longer embed **`v.dom`** in the Lit tree (avoids cloning / ownership issues). Insert still uses **`variant.dom`** via **`_insertBlock`**. + +### nx2 canvas — AEM Assets Cancel closes panel +- **`aem-assets.js`**: pass **`onClose`** through to **`PureJSSelectors.renderAssetSelector`** (same hook as da.live **`da-assets.js`**). +- **`nx-panel-extensions.js`**: **`onClose`** dispatches **`nx-panel-close`** so **`panel.js`** hides the right aside. + +### nx2 canvas — `experience` for picker / tab bypass (`window`, `fullsize-dialog`) +- **`helpers.js`**: **`extensionToPanelView`** passes through **`experience`** and **`sources`** from the extension config (no separate URL / modal flags). +- **`aem-assets.js`**: **`getAssetsPlugin`** uses **`experience: 'fullsize-dialog'`** (was **`aem-assets`**). +- **`picker.js` / `.css`**: **`experience === 'window'`** + **`sources[0]`** → new tab; **`fullsize-dialog`** → **`nx-picker-experience-dialog`** (no **`change`**); open-in icon for those rows. +- **`tool-panel.js` / `.css`**: same rules in **`_activate`** / **`showView`**; **`_fullsizeDialogViewId`** drives **`.tool-panel-fullsize-dialog`**; body mounts **`await view.load()`**. **`@nx-panel-close`** on **`dialog`** stops propagation and closes the dialog (not the whole panel). +- **`nx-panel-extensions.js`**: **`fullsize-dialog` + `aem-assets`** renders the assets host div and runs **`renderAssets`** from **`updated`**; other **`fullsize-dialog`** third-party configs use the iframe path as today. +- **`nx-panel-extensions.js`**: no inline AEM Assets mount (modal-only). + +## 2026-04-27 + +### nx2 chat — collab after approval +- **`chat-controller.js`**: **`_pageContextForAgent()`** shared by **`sendMessage`** and **`approveToolCall`** so post-approval **`/chat`** resumes include **`pageContext`** (da-agent collab gate). + +### nx-breadcrumb — drop large variant +- **`breadcrumb.js` / `breadcrumb.css`**: removed **`variant`** (was only **`large`**); typography and chevrons use the default **M** component tokens everywhere. +- **`nav.js`**: nav breadcrumb no longer sets **`variant="large"`**. + +## 2026-04-24 + +### nx2 canvas — slash “Open library” → Blocks tab +- **`command-defs.js`**: `nx-canvas-open-panel` detail includes `viewId: 'blocks'` so the after tool panel selects the Blocks extension when present. +- **`canvas.js`**: `openCanvasPanel` accepts optional `preferredViewId` from event `viewId`; after `syncToolPanelViews`, waits for `updateComplete` then calls **`nx-tool-panel` `showView`** only if `views` contains that id. +- **`tool-panel.js`**: public **`showView(id)`** wraps `_activate` for external callers. + +### nx2 nav / browse — hash breadcrumbs (minimal) +- **`nx2/blocks/shared/breadcrumb/`**: **`nx-breadcrumb`** — optional **`.baseUrl`**, **`.pathSegments`**; parent steps are plain **``** (hash-only or resolved via **`resolveBreadcrumbHref`** + current **`location.search`**). **`hashStateToPathSegments`** / **`pathSegmentsToCrumbs`** in **`utils.js`**. No custom events. +- **`nav.js` / `nav.css`**: **`decorateBreadcrumbs(fragment)`** — same idea as **`decorateBrand`**: mutates the loaded fragment, returns **`null`** or **`{ baseUrl }`**; **`loadNav`** sets **`_navBreadcrumbs`** (@state) and plain **`_breadcrumbBaseHref`**. **`HashController`**, **`brand-cluster`**, **`brand-area`** on the brand **``**. +- **`browse.js`**: unchanged integration — **`nx-breadcrumb`** with segments only (default / medium typography). + +### nx2 canvas — split editor view +- **`nx-canvas-header`**: third segmented control option `split` (grid-compare icon, `aria-label` / `title` “Split view”); `EDITOR_VIEWS` includes `split`. +- **`canvas.js` / `canvas.css`**: `normalizeCanvasEditorView` persists `split`. Split layout, gutter DOM, drag/persist ratio, and split-only CSS live in **`nx-editor-split/`** (`nx-editor-split.js` + `nx-editor-split.css`, adopted on import): **`nx-canvas-editor-mount--split`** row (**WYSIWYG left**, 2px **`nx-canvas-split-gutter`**, **doc right**), **`--nx-canvas-split-ratio`**, pointer-drag 15–85% → sessionStorage (`nx-canvas-split-ratio`). Split-mode **`nx-editor-wysiwyg`** uses matching **`flex-basis` / `width` / `min-width`** so the preview column does not collapse before the iframe is ready. +- **`nx-editor-doc` / `nx-editor-wysiwyg`**: visibility treats `split` like both single-pane modes (doc + preview visible when iframe port is ready). **`nx-editor-wysiwyg`**: host `hidden` only when the canvas mode hides the preview entirely; while cookies / quick-edit port load, **`.nx-editor-wysiwyg-surface`** is `hidden` so the custom element still participates in split flex sizing without a layout jump. +- **`selection-toolbar.js`**: ProseMirror selection toolbar sync runs in `split` as well as `content`. +- **`selection-toolbar.js` / `handlers.js`**: iframe `selection-change` marks PM transactions with meta and plugin state (`fromIframe`); doc-based `syncToolbar` / doc scroll positioning skip while the mirrored range came from WYSIWYG so split view does not draw the bar from doc `coordsAtPos`. Collapsed iframe selection dispatches a no-op tr to clear that origin. + +## 2026-04-23 + +### Canvas actions — no constructor +- `canvas-actions.js`: `HashController` and initial `_busy` moved to class fields so the custom constructor can be dropped; `_sendIcon` is not a reactive property (set once in `firstUpdated` + `requestUpdate()`); dropped redundant `requestUpdate()` after `_busy` / `_error` changes (Lit `@state` assignments schedule updates). + +### Canvas prose — undo/redo keymap +- `prose.js`: removed custom `handleUndo` / `handleRedo` that duplicated `yUndo` / `yRedo` from y-prosemirror (same pattern as `nx-editor-wysiwyg/utils/handlers.js` and da.live’s underlying commands). + +## 2026-04-22 + +### Canvas prose — keymap order aligned with da.live +- `prose.js`: moved `keymap(baseKeymap)` to after `buildKeymap` + `handleTableBackspace` (and `codemark` after `baseKeymap`), matching `da-live/blocks/edit/prose/index.js`, so full-table delete with Backspace and Enter in lists behave like da.live. + +### Canvas prose — plugins ported from da.live +- Added `nx2/blocks/canvas/nx-editor-doc/prose-plugins/`: `codemark`, `columnResizing` (from `da-y-wrapper`), `imageDrop`, `imageFocalPoint`, `tableSelectHandle`, `sectionPasteHandler`, `base64Uploader`, plus `sourceUploadContext`, `tableUtils`, `inlinesvg`, `focalPointDialog` (native ``; no face-api). +- Wired plugins in `prose.js` for writable sessions; styles in `nx-editor-doc.css`. Upload paths derive from the editor `source` URL. Focal-point block metadata still loads from `https://da.live/.../da-library/helpers/`. + +## 2026-04-21 + +### Canvas editor — selection toolbar + slash shared helpers +- **`selection-toolbar.js`**: exports `EDITOR_TEXT_FORMAT_ITEMS` and prose helpers (`applyHeadingLevel`, `wrapInBlockquote`, `setCodeBlock`, `setParagraph`, list wraps) for slash menu; block-type picker from `BLOCK_TYPE_PICKER_DEFS`; `STRUCTURE_COMMANDS` (`isActive` + `run`); `markIsActiveInSelection`; structure buttons from a toolbar subset of `EDITOR_TEXT_FORMAT_ITEMS`. +- **`slash-menu-items.js` / `slash-menu-handlers.js`**: import shared catalog/helpers from `selection-toolbar.js` (slash-only rows stay in items). + ## 2026-03-21 ### AGENTS.md creation + Created AGENTS.md to capture conventions not derivable from the code. Key entries: + - `undefined` vs empty array for loading state detection - `somethingUrl` (URL object) vs `href` (string) naming convention - Avoid attaching custom properties to `window` (built-in browser APIs are fine) @@ -13,7 +154,9 @@ Created AGENTS.md to capture conventions not derivable from the code. Key entrie - Functional style with companion utils ### Nav/sidenav semantic markup + Decided to wrap nav and sidenav in semantic HTML elements: + - `
` wraps `` - `