Skip to content

feat: Text box editor with OCR improvements#149

Draft
Gnathonic wants to merge 25 commits into
developfrom
feature/text-box-editor-with-ocr
Draft

feat: Text box editor with OCR improvements#149
Gnathonic wants to merge 25 commits into
developfrom
feature/text-box-editor-with-ocr

Conversation

@Gnathonic

Copy link
Copy Markdown
Owner

Summary

Combines the text box editor feature with OCR editing improvements from @nguyenston.

Original text-box-editor features:

  • Dedicated edit page at /[manga]/[volume]/edit/[pageIndex]
  • Visual manipulation with 5 handles per box (move, delete, clone, resize, auto-size)
  • Non-destructive versioning with edited_pages field
  • Zoom modes, page navigation, inline text editing

OCR improvements by @nguyenston:

  • Port OCR editing components from mokuro-library
  • Fix reader not showing edited pages
  • Fix incorrect delta calculation on hiDPI devices
  • Allow custom zoom level via ctrl+scroll
  • Fix quick action page selector not accounting for reading direction
  • Adapt data loading to V3 database schema

Credits

This PR incorporates work from:

  • @nguyenston - OCR editor improvements (originally PR #283 on Gnathonic/mokuro-reader)

🤖 Generated with Claude Code

Gnathonic and others added 25 commits November 9, 2025 12:41
Implements a dedicated editing interface for modifying text box positions,
sizes, text content, and font sizes with automatic optimization.

Core Features:
- Dedicated edit page route (/[manga]/[volume]/edit/[pageIndex])
- Visual manipulation with 5 handles per selected box:
  - Move handle (top-left): Drag to reposition
  - Delete handle (top-right): Remove box
  - Clone handle (bottom-left): Duplicate and place
  - Resize handle (bottom-right): Adjust dimensions
  - Auto-size handle (right side): Automatically optimize font size

Versioning System:
- Added edited_pages field to VolumeData for non-destructive editing
- Original mokuro data preserved in pages field
- Reader automatically uses edited version via getCurrentPages() utility
- Save edits to IndexedDB, export .mokuro JSON file

UI/UX:
- Zoom modes: Fit to Screen, Fit to Width, Original Size
- Page navigation with unsaved changes warning
- Real-time font size preview
- Auto-size algorithm: increases until overflow, then decreases to fit
- Text editing: Click selected box to edit content inline

Entry Point:
- Edit button added to QuickActions floating menu
- Page selector modal for dual-page view
- Seamless navigation between reader and editor

Closes #145

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
…tate

Fixed DataCloneError that occurred when saving text box edits to IndexedDB. The issue was caused by attempting to store Svelte $state proxies and Dexie IndexedDB objects directly, which cannot be cloned by the structured clone algorithm.

## Changes
- Changed from `structuredClone()` to `JSON.parse(JSON.stringify())` for cloning pages
- Added serialization of `workingBlocks` before assignment to strip Svelte reactivity
- Updated comments to clarify the serialization is needed for both IndexedDB objects and Svelte proxies

## Technical Details
The error occurred in two places:
1. `currentPages` from Dexie had properties that couldn't be cloned
2. `workingBlocks` as a `$state` variable was wrapped in Svelte proxies

JSON serialization strips all non-serializable properties and proxies, leaving only plain data that IndexedDB can store.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Added visual indicators and the ability to revert edits to original mokuro data.

## Changes

**Visual Indicators:**
- Added yellow pencil badge to VolumeItem component (both list and grid views)
- Badge appears when a volume has edited pages
- Uses `hasEdits()` utility to check for `edited_pages` field

**Revert Functionality:**
- Added "Revert to Original" button in EditToolbar
- Button only appears when volume has edits
- Shows confirmation dialog before reverting
- Removes `edited_pages` field from database
- Reloads page data to show original content
- Shows success/error toasts

**Component Updates:**
- VolumeItem.svelte: Added `volumeHasEdits` state and pencil badge
- EditToolbar.svelte: Added `hasEdits` prop and revert button
- edit/+page.svelte: Added `volumeHasEdits` derived, `revertToOriginal()` function

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Added a comparison modal that displays original and edited versions side-by-side.

## Changes

**Comparison Modal:**
- Added "Compare" button in EditToolbar (purple, appears when volume has edits)
- Modal shows original (left) and edited (right) versions side-by-side
- Color-coded borders: blue for original boxes, green for edited boxes
- Full-size view with scrollable containers
- Maximum width set to 90vw for better visibility

**Technical Details:**
- Added `originalPageData` derived value using `getOriginalPages()`
- Added `showCompareModal` state for modal visibility
- Modal renders both versions with identical styling to editor
- Shows text boxes with proper font sizes, writing modes, and line breaks

**Component Updates:**
- EditToolbar.svelte: Added Compare button and onCompare prop
- edit/+page.svelte: Added comparison modal with side-by-side layout

This helps users visualize their changes before saving or reverting.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Changed from ArrowRotateBackwardSolid (doesn't exist) to UndoOutline.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Removed the comparison modal and added the ability to create new text boxes.

## Changes

**Add Textbox Button:**
- Added purple "Add Textbox" button in EditToolbar
- Creates new empty text box in center of page
- Default size: 200x100px, font size 20px
- Auto-selects new box for immediate editing
- Marks page as having unsaved changes

**Removed Features:**
- Removed comparison modal (original vs edited view)
- Removed onCompare callback and related code
- Removed unused imports (getOriginalPages, Modal)

**Component Updates:**
- EditToolbar.svelte: Replaced Compare button with Add Textbox
- edit/+page.svelte: Added addTextbox() function, removed compare modal

This makes it easier to add custom text annotations to manga pages.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Fixed two issues:
1. Changed PlusSolid to CirclePlusSolid (correct Flowbite icon name)
2. Added separate toast for revert operations to avoid confusion

## Changes
- EditToolbar.svelte: Use CirclePlusSolid instead of PlusSolid
- edit/+page.svelte: Added showRevertSuccess state and toast
- Revert now shows "Reverted to original" instead of "Edits saved successfully"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Implemented automatic font sizing during resize operations and removed the redundant manual auto-size button.

## Changes

**Auto-resize during drag:**
- Font size now automatically adjusts as you resize a text box
- Throttled to every 10th frame for smooth performance
- Final auto-size runs when resize completes for perfect fitting
- Uses fast overflow detection to increase/decrease font size

**Removed manual button:**
- Removed auto-size button (now redundant)
- Removed TextSizeOutline icon import
- Removed handle-font-auto CSS styles
- Updated resize handle tooltip to indicate auto-sizing

**Bug fixes:**
- Added data-block-index attribute for DOM queries
- Added text-container class for overflow detection
- Fixed page navigation not updating text boxes
- Added $effect to reload workingBlocks on page change
- Removed transition-all for instant position updates
- Fixed Modal import that was accidentally removed
- Fixed toast showing on page load with isMounted guard

**Technical improvements:**
- Used JSON serialization instead of structuredClone for Svelte state
- Throttled auto-size to prevent blocking resize operations
- requestAnimationFrame for non-blocking font updates

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
Resolved merge conflicts:
- QuickActions.svelte: Migrated from SpeedDial to custom buttons + added edit feature
- Reader.svelte: Added editor props (currentPage, showSecondPage)
- VolumeItem.svelte: Combined edits badge with image-only badge

Updated editor components for Flowbite v1:
- EditToolbar.svelte: on:change → onchange for Select
- Edit page: on:click → onclick for Button, updated Toast API to use snippets and conditional rendering
- Pass `seriesId` and `volumeId` explicitly from Reader to QuickActions
component
- Update QuickActions to use passed props instead of reading from
$page.params
- Fixes issue where editor URL would resolve to
/undefined/undefined/edit/... due to stale page parameters during
component initialization
- Update `loadVolumeData` to fetch from `volume_ocr` and `volume_files`
tables separately, as `volumes_data` does not exist in V3 schema
- Manually construct `VolumeData` object from separate table results
- Update `saveEdits` and `revertToOriginal` to target `volume_ocr` table
- Add `edited_pages` field to `VolumeOCR` type definition
- Refactor data loading to use `$effect` instead of `onMount` to prevent
race conditions when route parameters change
Status: Functional but needs integration review, reader currently not
using changed pages

Block-level (verbatim port):
- OcrBlock.svelte: Block drag, resize, child line orchestration
- OcrLine.svelte: Line editing with split/merge/navigation, double-click
to edit
- ResizeHandles.svelte: 8-point resize controls with hover/touch
visibility
- TouchToggle.svelte: Mobile-friendly hover/touch visibility wrapper
- ocrMath utilities: getImageDeltas, smartResizeFont, ligaturize
- Pointer events with manual delta calculation for consistent touch
behavior

Canvas-level (adapted for mokuro-reader):
- EditCanvas.svelte: Integrated OcrState, replaced EditableBox
architecture
- OcrState.svelte.ts: Adapted for manual CSS scale (no Panzoom instance)
- Focus/dirty state propagation via callbacks instead of stores
- workingBlocks bound directly to canvas instead of CRUD callbacks
- Exposed deleteFocusedBlock() and addTextboxToCenter() methods

Toolbar updates:
- Delete button with selection state tracking
- Responsive layout (hide labels on small screens)
- Button groups: block actions vs page actions
- Unsaved changes indicator
- Tooltips for icon-only buttons
…background

- Clicks on blocks or lines focuses the block
- Clicks on background remove focus for all
- Fetch edited_pages in catalog/index.ts
@vercel

vercel Bot commented Jan 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
mokuro-reader Ready Ready Preview, Comment Jan 19, 2026 5:37pm

@Gnathonic Gnathonic changed the base branch from main to develop January 23, 2026 13:51
vncthar pushed a commit to vncthar/mokuro-reader that referenced this pull request Mar 10, 2026
…tbox-resize

feat: Lazy-load textbox resize calculations on hover
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants