Skip to content

Redesign study block editor UI with drag-and-drop, add/rename, and group study modal#116

Open
hendriebeats wants to merge 18 commits into
masterfrom
study-block-editor-ui-enhancement
Open

Redesign study block editor UI with drag-and-drop, add/rename, and group study modal#116
hendriebeats wants to merge 18 commits into
masterfrom
study-block-editor-ui-enhancement

Conversation

@hendriebeats

@hendriebeats hendriebeats commented Feb 19, 2026

Copy link
Copy Markdown
Contributor

Replaces the minimal study block editor with a fully redesigned modal that supports drag-and-drop reordering, block removal/restore, adding new blocks, and inline block renaming. Also redesigns the group study modal with an inline invite form.

Reviewer notes

Study block editor — drag-and-drop

The drag implementation uses position: fixed during the drag and a placeholder div to hold the vacated space, rather than the previous approach of swapping adjacent siblings. This is needed to support dragging across two separate lists (active vs. removed blocks) — the old sibling-swap approach can't span two containers.

Study block editor — removed blocks

Removed blocks stay in the DOM in a "removed" section rather than being deleted immediately, letting users restore them before committing. The remove/restore buttons swap visibility in-place; the section itself is hidden when empty.

Cross-list drag hysteresis

The mousemove handler uses a 10px hysteresis band when deciding whether to move the placeholder back from the removed list to the active list. Without this, the placeholder oscillates when the mouse is near the boundary because moving the placeholder changes the section's top position, immediately re-triggering the opposite condition.

abortDrag on modal close

If the modal is closed (e.g., via the × button) during an active drag, abortDrag cleans up the fixed-positioned element and placeholder. Without this, the dragged item would be left floating.

startFixedTop calculation

startFixedTop = rect.top - (e.clientY - startMouseY) anchors the element at its pre-drag screen position so it doesn't jump when the 3px threshold is crossed to start the drag.

Block rename via textarea

Block names use a <textarea rows="1"> instead of <input> so they auto-grow vertically for long names; Enter is suppressed since names are single-line.

withRenamedHeader / createGeneralStudyBlockNode

New editorUtils helpers produce ProseMirror nodes for renamed and newly-created blocks. They live in editorUtils rather than StudyBlockEditor.ts because they operate on ProseMirror schema types and belong with the other schema utilities.

Group study modal — inline invite form

The old flow opened a separate /group_study/invite/:groupId route to render an "Invite New People" view. The invite form is now embedded directly in groupStudyHTML, making getInvite and getInviteNewMemberHTML dead code — both are removed along with the route.

Pencil icon changes

The gray circle background was removed and the stroke colour changed to blue (#0057d1) to match the new button style context the icon appears in.

Cyrillic → Latin "x" in SidebarSections

The remove button was using a Cyrillic "х" (U+0445) that looks like Latin "x" but renders differently across fonts/OSes.

Modal close buttons

All three modals (#groupStudy create, #groupStudy view, #newStudy) previously used bare <img onclick> for the close icon — not keyboard-accessible and invisible to screen readers. Changed to <button aria-label="Close"> with a decorative <img alt=""> child, matching the pattern already used in the study block editor modal.

ProseMirror mousedown guards

Four places in Editor.tsx had onclick handlers on non-editable widgets without a mousedown guard. ProseMirror processes mousedown first, repositioning the cursor before the click handler fired. Adding e.preventDefault() on mousedown (and adding "mousedown" to stopEvent for the question-mark decoration) prevents the double cursor placement.

@hendriebeats hendriebeats changed the title Improve study block editor with smooth drag-and-drop and restore Improve study block editor UI and button styles Feb 19, 2026
hendriebeats and others added 5 commits February 19, 2026 12:18
Redesign the study block editor modal with better layout, drag handles,
animated reordering with placeholder insertion, and a "Removed" section
that lets users restore deleted blocks before confirming.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…icate CSS

- Remove unused grabOffsetY and siblingHeight variables
- Fix typo: newPosistions → newPositions
- Add e.preventDefault() on mousedown to prevent text selection during drag
- Remove redundant container re-declaration in update handler
- Merge duplicate .studyBlock CSS rules
- Convert pencil icon into a labeled button with "Edit blocks" text
- Remove gray circle background from pencil SVG, recolor stroke to blue
- Add ghostBlue button variant (white bg, gray border, blue text, light
  blue fill on hover)
- Soften lightBlue button: thinner border (1px), lighter hover color
- Add --blue-35 CSS variable for subtler hover states
- Reduce global button font-weight from 600 to 500
…anup

- Remove unused Node import from prosemirror-model
- Use strict equality (=== / !==) consistently
- Add e.stopPropagation() on remove button to prevent drag activation
- Remove comments that restate what the code does
- Remove extra blank lines
@hendriebeats hendriebeats force-pushed the study-block-editor-ui-enhancement branch from c9a0ad1 to 8bd5377 Compare February 19, 2026 17:20
…button

- Remove horizontal drag, scale/rotate transform, and complex settle
  animation from study block reorder UI; drop now snaps cleanly in place
- Add stopEvent to StudyBlocksView to prevent ProseMirror moving the
  cursor when the Edit blocks button is clicked
- Fix Cyrillic x that crept into sidebar section remove button
- Add missing semicolon in StudyBlocksView descendants callback
@hendriebeats hendriebeats changed the title Improve study block editor UI and button styles Study block editor: reorder & remove blocks Feb 21, 2026
hendriebeats and others added 9 commits February 20, 2026 19:18
Add mousedown preventDefault so clicking the button doesn't
relocate the editor cursor or focus in Firefox.
The update handler was using currentIndex attributes as array indices
to build the new block order. After remove/restore operations these
indices had gaps or stale values, producing undefined holes in the
array passed to reorderStudyBlock.

Switch to iterating container.children in DOM order and pushing
sequentially — DOM order already correctly reflects the visual state
after all drag, remove, and restore operations.
- Convert closeModalIcon from <img> to <button> with aria-label
- Convert remove icon from <img> to <button> with inner <img>
- restoreBtn was already changed to <button>; add user-select:none to CSS
- Update .closeModalIcon and .remove CSS to reset button defaults and
  nest the img width/dimensions inside
- Remove now-dead currentIndex attribute mutations in StudyBlockEditor
  (update handler uses DOM order; currentIndex is no longer read)
- Replace separate invite page flow with an inline invite form (email + role + button) directly in the group study modal
- Restyle member/share rows as a unified "people with access" list with name, email, role badge, and remove button
- Add status badges (Invited/Rejected/Expired) for pending shares
- Show member email and owner/member role label in the people list
- Expose email field on GetUser entity so member rows can display it
- Add close button to both the create and view group study modals
- Fix verse ref widget to use onmousedown + getPos() to avoid stale position captures and remove contentEditable from the span
- Resolve merge from master into study-block-editor-ui-enhancement

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Add createGeneralStudyBlockNode and withRenamedHeader helpers to editorUtils
- Replace plain-text block list with header+body preview rows matching the editor table layout
- Header cell uses a textarea (auto-resizing, Enter blocked) for renaming; Questions block is read-only plain text
- Body cell renders rich text via DOMSerializer (respects newlines, bold, italic, colours, etc.), capped at 2 paragraphs
- Add "+ Add block" button that appends a new editable row
- Update handler creates new nodes for added blocks and renames existing ones before reordering
- Header column width matches editor (220px = 200px content + 10px padding each side)
- Blocks sit flush against each other with no vertical gap; drag handle and remove button centred
- Modal max-width widened to 800px
- Update subtitle text to reflect new capabilities
…cross-list drag

Previously, removed blocks were rebuilt as stripped-down DOM elements with
a different grid layout, plain text strikethrough, and no blockPreview. This
made the removed section visually inconsistent and hard to distinguish at a
glance from the active list.

- Removed blocks now share the same DOM structure (drag handle, blockPreview
  with header and body) as active blocks; only the action button changes
  from X to an undo icon
- Items can be dragged between the active and removed sections in both
  directions; new blocks are included in this behaviour for consistency
- Drag logic switched from position:absolute with a swap animation to
  position:fixed, enabling clean cross-list movement
- Hysteresis added to the list-switching boundary to prevent the placeholder
  from oscillating when the container shifts as items move between lists
- Fixed removeBtn/restoreBtn click handlers to use div.parentElement rather
  than hardcoded list references (would throw after a cross-list drag)
- Fixed positional jump at drag-start threshold by adjusting startFixedTop
- Added drag abort on modal cancel to clean up listeners and fixed styles
- Raised .moving z-index to 1000 and added pointer-events:none
- Moved .studyBlock and .addBlockBtn CSS scopes so styles apply regardless
  of which list an item is in; merged duplicate :last-child rule
- Removed blocks styled with muted colours and strikethrough title rather
  than opacity, so the drag handle remains visually prominent

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Replace bare <img onclick> close icons with accessible <button
  aria-label="Close"> in all three modals (groupStudy create,
  groupStudy view, newStudy), matching existing study.css pattern
- Update groupstudy.css and newstudy.css to use button-reset styles
  (background/border none, line-height 0) so the icons size correctly
- Add mousedown guards to QuestionsView placeholder, QuestionView
  addAnswer button, bible-text placeholder, and questionMarkPlugin
  stopEvent to prevent ProseMirror repositioning the cursor before
  click handlers fire
- Remove dead getInvite handler and getInviteNewMemberHTML template
  (superseded by the inline invite form in groupStudyHTML)
- Remove debug console.log that leaked full document contents to DevTools
Replace width: 22px + transform: scale(1.26) with a straightforward
width: 28px so layout and visual size agree.
@hendriebeats hendriebeats changed the title Study block editor: reorder & remove blocks Redesign study block editor UI with drag-and-drop, add/rename, and group study modal Feb 21, 2026
@hendriebeats

Copy link
Copy Markdown
Contributor Author

@boxyoman as per our last conversation, I buffed this up quite a bit.

@hendriebeats hendriebeats added the Size: Large 401–1,000 lines: Higher risk; usually should be split unless it’s a mechanical refactor. label Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Size: Large 401–1,000 lines: Higher risk; usually should be split unless it’s a mechanical refactor.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant