Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Improve tiptop-integration of toolbars for better UX #43

Open
wants to merge 13 commits into
base: main
Choose a base branch
from

Conversation

fsbraun
Copy link
Member

@fsbraun fsbraun commented Dec 26, 2024

UX improvements

This PR introduces a new toolbar system for improved user experience.

  • The toolbars move into the editable div as Prosemirror decorations. This avoids problems with timeouts when the editable div blurs.
  • Visibility of toolbar and dropdown can be defined more clearly using CSS
  • The block toolbar is moved from a dialog tag to a div tag to leverage the different focus concepts.
  • The block toolbar button now can be used as a block handle for draging block content.
  • Events are (largely) handled by the Prosemirror engine for better consistency.
  • The toolbar code has been fully refactored and moved into its own module.

Summary by Sourcery

New Features:

  • Introduce a new toolbar system that enhances user experience.

Copy link
Contributor

sourcery-ai bot commented Dec 26, 2024

Reviewer's Guide by Sourcery

This PR refactors the toolbar system to improve UX by moving the toolbars into the editable div, changing the block toolbar from a dialog to a div, and refactoring the toolbar code into its own module.

Sequence diagram for toolbar interaction flow

sequenceDiagram
    actor User
    participant Editor
    participant Toolbar
    participant ProseMirror

    User->>Editor: Click in editable area
    Editor->>ProseMirror: Focus event
    ProseMirror->>Toolbar: Show toolbar decorations
    User->>Toolbar: Click toolbar button
    Toolbar->>ProseMirror: Execute command
    ProseMirror->>Editor: Update content
    Editor->>Toolbar: Update button states
Loading

Class diagram for the new toolbar system

classDiagram
    class CmsToolbarPlugin {
        +addProseMirrorPlugins()
    }
    class ToolbarPlugin {
        +props
        +state
        -handleDOMEvents
        -createToolbar()
        -updateToolbar()
    }
    class TiptapToolbar {
        +action()
        +enabled()
        +active()
        +type: string
    }
    CmsToolbarPlugin --> ToolbarPlugin
    ToolbarPlugin --> TiptapToolbar
    note for CmsToolbarPlugin "Extension that adds toolbar functionality"
    note for ToolbarPlugin "ProseMirror plugin for toolbar management"
    note for TiptapToolbar "Toolbar button definitions and handlers"
Loading

File-Level Changes

Change Details Files
Toolbars are now decorations within the ProseMirror editor
  • Toolbars moved into the editable div as decorations
  • Events are handled by the ProseMirror engine
  • Toolbar code refactored and moved into its own module
private/js/tiptap_plugins/cms.toolbar.js
private/js/cms.tiptap.js
private/css/cms.tiptap.css
Block toolbar is now a div
  • Block toolbar changed from dialog to div
  • Block toolbar button can be used as a block handle for dragging
private/js/tiptap_plugins/cms.toolbar.js
private/css/cms.tiptap.css
private/css/cms.text.css
Toolbar button states are updated dynamically
  • Toolbar button states are updated based on editor state
private/js/tiptap_plugins/cms.toolbar.js
Dropdown and form handling improved
  • Dropdown positioning and behavior improved
  • Form handling and submission updated
private/js/tiptap_plugins/cms.toolbar.js
private/js/tiptap_plugins/cms.dynlink.js
private/js/tiptap_plugins/cms.formextension.js
private/css/cms.toolbar.css
djangocms_text/static/djangocms_text/css/cms.text.css
Table features enhanced
  • Table resizing disabled
  • Toggle header column and row features added
  • Table icons updated
private/js/tiptap_plugins/cms.toolbar.js
private/js/tiptap_plugins/cms.tiptap.toolbar.js
djangocms_text/editors.py

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time. You can also use
    this command to specify where the summary should be inserted.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

codecov bot commented Dec 26, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 81.16%. Comparing base (ee5db1a) to head (73bdc0d).

Additional details and impacted files
@@           Coverage Diff           @@
##             main      #43   +/-   ##
=======================================
  Coverage   81.16%   81.16%           
=======================================
  Files          17       17           
  Lines         929      929           
  Branches      104      104           
=======================================
  Hits          754      754           
  Misses        132      132           
  Partials       43       43           

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@fsbraun fsbraun marked this pull request as ready for review December 26, 2024 23:03
Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @fsbraun - I've reviewed your changes and found some issues that need to be addressed.

Blocking issues:

  • Fix typo in mousedowxn event handler name (link)

Overall Comments:

  • Consider moving the SVG icon definitions to separate asset files to improve code readability and maintainability
Here's what I looked at during the review
  • 🔴 General issues: 1 blocking issue
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

private/js/tiptap_plugins/cms.toolbar.js Outdated Show resolved Hide resolved
private/js/tiptap_plugins/cms.toolbar.js Outdated Show resolved Hide resolved
private/js/tiptap_plugins/cms.toolbar.js Outdated Show resolved Hide resolved
private/js/tiptap_plugins/cms.toolbar.js Outdated Show resolved Hide resolved
private/js/tiptap_plugins/cms.toolbar.js Outdated Show resolved Hide resolved
private/js/tiptap_plugins/cms.toolbar.js Outdated Show resolved Hide resolved
private/js/tiptap_plugins/cms.toolbar.js Outdated Show resolved Hide resolved
private/js/tiptap_plugins/cms.toolbar.js Outdated Show resolved Hide resolved
fsbraun and others added 7 commits December 27, 2024 00:05
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
Co-authored-by: sourcery-ai[bot] <58596630+sourcery-ai[bot]@users.noreply.github.com>
…t into feat/pm-widgets

# Conflicts:
#	private/js/tiptap_plugins/cms.toolbar.js
@fsbraun
Copy link
Member Author

fsbraun commented Dec 26, 2024

@sourcery-ai review

Copy link
Contributor

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey @fsbraun - I've reviewed your changes and they look great!

Here's what I looked at during the review
  • 🟢 General issues: all looks good
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟡 Complexity: 1 issue found
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@@ -0,0 +1,563 @@
/* eslint-env es11 */
Copy link
Contributor

Choose a reason for hiding this comment

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

issue (complexity): Consider refactoring the toolbar creation and event handling to be more modular and reduce duplication.

The toolbar implementation has unnecessary complexity that can be reduced in two key areas:

  1. Break down the monolithic _populateToolbar function into focused component builders:
function _createToolbarButton(editor, item, filter) {
    // Existing button creation logic
}

function _createDropdown(editor, item, filter) {
    const dropdown = typeof item.items === 'function' 
        ? item.items(editor, items => _populateToolbar(editor, items, filter))
        : _populateToolbar(editor, item.items, filter);

    return `<span title='${item.title}' class="dropdown" role="button">
        ${item.icon}<div class="dropdown-content ${item.class || ''}">${dropdown}</div>
    </span>`;
}

function _populateToolbar(editor, array, filter) {
    return array.map(item => {
        if (Array.isArray(item)) return _handleGroup(editor, item, filter);
        if (item.constructor === Object) return _createDropdown(editor, item, filter);
        if (item === '|') return editor.options.separator_markup;
        return _createToolbarButton(editor, item, filter);
    }).join('');
}
  1. Consolidate duplicated event handling between block and top toolbar:
const sharedToolbarHandlers = {
    handleClick(view, event, editor) {
        if (this.containsTarget(event.target)) {
            _handleToolbarClick(event, editor);
            return true;
        }
        _closeAllDropdowns(event, editor);
        return false;
    },

    containsTarget(target) {
        return this.toolbar?.contains(target);
    }
};

function createToolbarPlugin(editor, type) {
    return new Plugin({
        props: {
            handleDOMEvents: {
                click(view, event) {
                    return sharedToolbarHandlers.handleClick(view, event, editor);
                }
            }
        }
        // ... rest of plugin config
    });
}

These changes maintain all functionality while making the code more maintainable and easier to understand.

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.

1 participant