Skip to content

feat(pages): add slash commands and @mentions to the page editor - #251

Merged
martian56 merged 2 commits into
mainfrom
feat/page-slash-commands
Jul 5, 2026
Merged

feat(pages): add slash commands and @mentions to the page editor#251
martian56 merged 2 commits into
mainfrom
feat/page-slash-commands

Conversation

@martian56

@martian56 martian56 commented Jul 5, 2026

Copy link
Copy Markdown
Member

What

Closes #188. The page editor's placeholder promised a "/" menu that never existed, and there was no way to mention people. Both work now.

  • Slash commands: type / to insert text, headings (H1-H3), bulleted / numbered / to-do lists, a quote, a code block, a 3x3 table, an image (by URL), or a divider. Type to filter the list; arrow keys + Enter to pick.
  • @mentions: type @ to mention a workspace member. The inserted chip carries the member's id (data-id). Members are loaded on the page and read lazily through a ref so members that arrive after the editor mounts still show up in the menu.

Both menus share a small suggestionPopup helper that renders a body-level menu under the caret with keyboard navigation, so there's no new popup dependency (uses the already-installed @tiptap/suggestion and @tiptap/extension-mention).

Scope note

This delivers the two interactive pieces the issue calls out as the priority ("at minimum, make the advertised '/' actually work") plus member mentions. Richer embed nodes (issue-link cards, sub-page embeds, iframe/video) are a larger, separate effort and are not included here.

Testing

tsc -b + ESLint clean. Browser-verified on a page:

  • Typed /, the full command menu appeared; picking "Heading 2" turned the block into an H2 and removed the / text.
  • Typed @, the member menu appeared; picking a member inserted a styled @Test Admin chip carrying the member id.
  • No console errors.

AI assistance

Produced with the help of Claude Code (Claude Opus 4.8). AI-assisted commits carry a Co-Authored-By trailer.

Summary by CodeRabbit

  • New Features
    • Added an @ mention member picker in the page editor with search, keyboard selection, avatar support, and an empty state when no members match.
    • Added / slash commands to insert common blocks (headings, lists, quote, code, table, image, divider).
    • Mention suggestions update dynamically from workspace member data.
  • Style
    • Added dedicated styling for mentioned text in the editor to highlight it.

The editor's placeholder promised a "/" menu that never existed, and there was
no way to mention people. Both work now.

- Slash menu: type "/" to insert text, headings, bulleted/numbered/to-do lists,
  a quote, a code block, a 3x3 table, an image, or a divider. Filter by typing.
- @mentions: type "@" to mention a workspace member; the chip stores the
  member id. Members are loaded on the page and read lazily so ones that arrive
  after the editor mounts still show up.

Both menus share a small suggestion-popup helper that renders a body-level menu
under the caret with arrow-key navigation and Enter to pick, so there's no extra
popup dependency.

Closes #188

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings July 5, 2026 06:58
@strix-security

strix-security Bot commented Jul 5, 2026

Copy link
Copy Markdown

Strix Security Review

No security issues found.

Updated for 77a81f2.


Reviewed by Strix
Re-run review · Configure security review settings

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: a02ff074-9645-43f3-b6f4-a7f900cae67c

📥 Commits

Reviewing files that changed from the base of the PR and between 64f8318 and 77a81f2.

📒 Files selected for processing (6)
  • apps/web/src/components/page-editor/MentionMenu.tsx
  • apps/web/src/components/page-editor/mentions.ts
  • apps/web/src/components/page-editor/slashCommands.tsx
  • apps/web/src/components/page-editor/suggestionPopup.tsx
  • apps/web/src/components/page-editor/usePageEditor.ts
  • apps/web/src/pages/PageDetailPage.tsx
🚧 Files skipped from review as they are similar to previous changes (6)
  • apps/web/src/components/page-editor/mentions.ts
  • apps/web/src/pages/PageDetailPage.tsx
  • apps/web/src/components/page-editor/usePageEditor.ts
  • apps/web/src/components/page-editor/MentionMenu.tsx
  • apps/web/src/components/page-editor/slashCommands.tsx
  • apps/web/src/components/page-editor/suggestionPopup.tsx

📝 Walkthrough

Walkthrough

Adds slash-command and @-mention support to the page editor with a shared suggestion popup, command/mention menus, editor hook wiring, workspace member loading, and mention styling.

Changes

Slash Commands and Mentions

Layer / File(s) Summary
Suggestion popup renderer
apps/web/src/components/page-editor/suggestionPopup.tsx
Adds SuggestionMenuProps, useActiveItemScroll, and a TipTap suggestion renderer that mounts, positions, updates, and cleans up a React popup.
Slash command catalog and menu
apps/web/src/components/page-editor/slashCommands.tsx
Defines slash-command items and actions, filters matches, renders the slash menu, and exports the TipTap slash extension.
Mention type, menu, and extension
apps/web/src/components/page-editor/mentionTypes.ts, MentionMenu.tsx, mentions.ts, index.ts
Adds the mention item type, mention menu UI, mention suggestion extension, and public re-export.
usePageEditor wiring
apps/web/src/components/page-editor/usePageEditor.ts
Adds mention-item options, keeps them in a ref-backed getter, and wires slash and mention extensions into the editor configuration.
PageDetailPage member loading and styling
apps/web/src/pages/PageDetailPage.tsx, apps/web/src/index.css
Loads workspace members into mention state, passes them to the editor hook, and adds mention styling.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
    participant PageDetailPage
    participant WorkspaceService
    participant usePageEditor
    participant TipTapEditor as TipTap Editor
    participant Renderer as createSuggestionRenderer
    participant Menu as SlashMenu / MentionMenu

    PageDetailPage->>WorkspaceService: listMembers(workspaceSlug)
    WorkspaceService-->>PageDetailPage: member list
    PageDetailPage->>usePageEditor: mentionItems = mentionMembers
    usePageEditor->>TipTapEditor: configure SlashCommand + createMention(getMentionItems)

    TipTapEditor->>Renderer: open suggestion for "/" or "@"
    Renderer->>Menu: render items and selection state
    Menu-->>Renderer: onSelect(index)
    Renderer->>TipTapEditor: props.command(item) / props.run(editor, range)
    TipTapEditor-->>PageDetailPage: inserted block or mention
Loading

Poem

A rabbit taps the editor key,
And slash and mention spring lively.
Popups hop, then scroll in view,
With members bright and commands too,
The page now chats in cozy style.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is helpful but does not follow the required template and omits several required sections like Type of change and Surface. Restructure it to match the template and fill the missing sections: Summary, linked issues, type/surface, what changed, why, testing, rollout, and checklist.
Linked Issues check ⚠️ Warning The PR covers slash commands and member mentions, but it does not implement the requested issue/page mentions or embed nodes from #188. Add the missing mention targets and embed nodes, or split them into explicit follow-up issues if they are intentionally out of scope.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise, conventional, and accurately summarizes the main page-editor slash command and mention changes.
Out of Scope Changes check ✅ Passed The changes stay focused on page-editor slash commands, mentions, and the supporting popup/data plumbing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/page-slash-commands

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds the missing TipTap “/” command menu promised by the page editor placeholder, and introduces @ mentions for workspace members, integrating both via a shared suggestion popup renderer.

Changes:

  • Adds a shared suggestionPopup helper to render a body-level suggestion menu under the caret with keyboard navigation.
  • Introduces a Slash Commands extension (headings/lists/quote/code/table/image/divider) and wires it into usePageEditor.
  • Adds workspace-member @mentions (member list loaded on the page and passed into the editor).

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
apps/web/src/pages/PageDetailPage.tsx Loads workspace members and passes them into usePageEditor for @ mention suggestions.
apps/web/src/index.css Styles inserted mention chips via .page-mention.
apps/web/src/components/page-editor/usePageEditor.ts Registers the new SlashCommand + mention extensions and keeps mention items current via a ref.
apps/web/src/components/page-editor/suggestionPopup.tsx New reusable renderer for TipTap Suggestion popups with keyboard selection.
apps/web/src/components/page-editor/slashCommands.tsx Implements the / command list, filtering, and command execution.
apps/web/src/components/page-editor/mentionTypes.ts Adds a shared MentionItem type.
apps/web/src/components/page-editor/mentions.ts Configures the TipTap mention extension and ties it to the suggestion popup + items provider.
apps/web/src/components/page-editor/MentionMenu.tsx Renders the mention suggestion UI with member avatars.
apps/web/src/components/page-editor/index.ts Re-exports MentionItem for consumers.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread apps/web/src/components/page-editor/usePageEditor.ts
Comment thread apps/web/src/components/page-editor/slashCommands.tsx
@martian56
martian56 requested a review from nazarli-shabnam July 5, 2026 07:07
@martian56 martian56 self-assigned this Jul 5, 2026
@martian56 martian56 added enhancement New feature or request UI labels Jul 5, 2026
@martian56 martian56 added this to the Finish w Enhancements milestone Jul 5, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
apps/web/src/pages/PageDetailPage.tsx (1)

195-199: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Mention label falls back to raw email address.

label: m.member_display_name || m.member_email || 'Member' will render a member's email directly into the mention chip text, which gets baked into the saved page HTML (renderLabel embeds @{label} in stored content). Consider omitting the email fallback (e.g. use a generic placeholder) to avoid persisting email addresses into page content.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/pages/PageDetailPage.tsx` around lines 195 - 199, The mention
label fallback in the member mapping currently uses member_email, which causes
raw email addresses to be stored in page HTML via renderLabel. Update the
mapping in PageDetailPage so the label for mentions uses member_display_name or
a generic placeholder like "Member", and avoid using member_email anywhere in
the mention chip text.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/components/page-editor/mentions.ts`:
- Around line 13-20: The mention suggestion filtering in the mentions setup is
still trimming and matching only a single token, which breaks multi-word names.
Update the suggestion configuration in the mention extension so it preserves
`allowSpaces` behavior and keeps filtering in the `items` callback for
multi-word queries like `@John Doe`, using the existing `suggestion`/`items`
logic as the place to adjust.

In `@apps/web/src/components/page-editor/slashCommands.tsx`:
- Around line 139-173: The active slash menu item is not kept visible when
selectedIndex changes during keyboard navigation. Update SlashMenu to track the
selected button and call scrollIntoView on the active item whenever
selectedIndex changes, using the existing button render in the items.map loop;
apply the same fix to MentionMenu as noted. Ensure the scroll happens inside the
max-h-72 scrollable container so ArrowUp/ArrowDown keeps the highlighted item in
view.

In `@apps/web/src/components/page-editor/suggestionPopup.tsx`:
- Around line 26-33: The popup positioning in suggestionPopup.tsx only updates
from the existing place() calls triggered by onStart/onUpdate, so the menu
drifts when the editor scrolls or resizes while it is open. Add active scroll
and resize listeners around the popup lifecycle in the shared renderer logic,
and have them call place() using the current caret rect so the slash-command and
mention popups stay anchored. Clean up those listeners when the popup closes or
is destroyed, and reference the existing place(), onStart, and onUpdate flow
when wiring the fix.

In `@apps/web/src/pages/PageDetailPage.tsx`:
- Around line 186-206: The `@-mention` member list in PageDetailPage can remain
stale when workspaceSlug changes, so clear mentionMembers as soon as the effect
reruns before calling workspaceService.listMembers. Update the useEffect that
loads members to reset the mention state on workspace changes, while keeping the
existing cancelled guard and mapping logic in place so only the current
workspace’s members can be selected.

---

Nitpick comments:
In `@apps/web/src/pages/PageDetailPage.tsx`:
- Around line 195-199: The mention label fallback in the member mapping
currently uses member_email, which causes raw email addresses to be stored in
page HTML via renderLabel. Update the mapping in PageDetailPage so the label for
mentions uses member_display_name or a generic placeholder like "Member", and
avoid using member_email anywhere in the mention chip text.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 437af2a2-0e48-4751-8344-9e2cc01966ef

📥 Commits

Reviewing files that changed from the base of the PR and between 53e19ba and 64f8318.

📒 Files selected for processing (9)
  • apps/web/src/components/page-editor/MentionMenu.tsx
  • apps/web/src/components/page-editor/index.ts
  • apps/web/src/components/page-editor/mentionTypes.ts
  • apps/web/src/components/page-editor/mentions.ts
  • apps/web/src/components/page-editor/slashCommands.tsx
  • apps/web/src/components/page-editor/suggestionPopup.tsx
  • apps/web/src/components/page-editor/usePageEditor.ts
  • apps/web/src/index.css
  • apps/web/src/pages/PageDetailPage.tsx

Comment thread apps/web/src/components/page-editor/mentions.ts
Comment thread apps/web/src/components/page-editor/slashCommands.tsx
Comment thread apps/web/src/components/page-editor/suggestionPopup.tsx
Comment thread apps/web/src/pages/PageDetailPage.tsx Outdated
@nazarli-shabnam

Copy link
Copy Markdown
Member

@martian56 fix ai comments?

CodeRabbit + Copilot on PR #251:

- validate the slash "Image" URL through safeUrl so an http(s)/relative URL is
  required, blocking javascript:/data: payloads in the img src.
- seed the mention ref from the initial members so an already-cached list works
  on the very first "@".
- allow spaces in mention queries so multi-word names keep filtering.
- reposition the suggestion popup on scroll/resize so it stays pinned to the
  caret while an editor with a scrollable body moves.
- scroll the keyboard-highlighted item into view in both menus.
- clear cached members when the workspace changes so the menu can't briefly
  offer, or insert, a member from the previous workspace.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@martian56
martian56 requested a review from nazarli-shabnam July 5, 2026 07:54
@martian56
martian56 merged commit 50a533b into main Jul 5, 2026
9 checks passed
@martian56
martian56 deleted the feat/page-slash-commands branch July 5, 2026 07:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEAT] Add slash commands, mentions, and embeds to the page editor

3 participants