Skip to content

Footnotes creation UX improvements #78

@thibaudcolas

Description

@thibaudcolas

We’ve been getting feedback that it’s hard to create footnotes due to their content being authored in a separate field from the reference, potentially quite far. For a fair number of users, it seems more logical to initiate the footnote creation from the text where the reference is placed – rather than first going to the "Footnotes" field to create a new note, and then back to the editor.

Here’s a UX prototype attempting to resolve this:

footnotes.prototype.navigation.back.and.forth.mp4

It introduces:

  1. A "Create new footnote" button inside the footnote chooser within rich text. This takes the user to a new item within the Footnotes panel, and inserts a footnote reference to that item within the rich text field
  2. Navigation from footnote references to their corresponding footnote content field
  3. Navigation from footnote content fields, to their corresponding reference (assuming there’s only one)

This really is just a super rough UX PoC at this stage, but it wouldn’t be too complex to implement. Here’s the code for ref (very unusable as the basis for the production-ready code).

UX PoC code
  $.ajax({
    url: "/footnotes/footnotes_modal/",
    success: function (data) {
      $("body").append(data);
      var $btn = $("#id_footnotes-ADD");
      var $lst = $("#footnotes-listing");
      var table = $("#footnotes-listing tbody");
      table.empty();

+      // Add a "Create a new footnote" button
+      var $newbtn = $("<button class='button'>Create a new footnote</button>");
+      $lst.append($newbtn);
+      $newbtn.on("click", function () {
+        $btn.click();
+
+        $("#footnotes-modal").modal("hide");
+        document.querySelector(`#panel-child-content-footnotes-section`).scrollIntoView({ behavior: 'smooth' })
+        setTimeout(() => {
+          var uuid = document.querySelector("#id_footnotes-0-uuid_display-value").innerText;
+          document.querySelector("#id_footnotes-0-uuid_display-value").innerHTML = `<a href="#ref-${uuid}">${uuid.substring(0, 6)}</a>`;
+
+        // Uses the Draft.js API to create a new entity with the right data.
+        const contentWithEntity = content.createEntity(
+          entityType.type,
+          "IMMUTABLE",
+          {
+            footnote: uuid,
+          }
+        );
+        const entityKey = contentWithEntity.getLastCreatedEntityKey();
+
+        // We also add some text for the entity to be activated on.
+        const text = `[${uuid}]`;
+
+        const newContent = Modifier.replaceText(
+          content,
+          selection,
+          text,
+          null,
+          entityKey
+        );
+        const nextState = EditorState.push(
+          editorState,
+          newContent,
+          "insert-characters"
+        );
+
+        onComplete(nextState);
+        }, 300);
+      });

      var live_footnotes = document.querySelectorAll(
        "#id_footnotes-FORMS .w-panel"
      );

const Footnote = (props) => {
  const { entityKey, contentState } = props;
  const data = contentState.getEntity(entityKey).getData();
  return React.createElement("sup", {
    "id": `ref-${data.footnote}`,
+      "style": {
+        "color": "var(--w-color-secondary)",
+        "text-decoration": "underline",
+      },
+      onClick: () => document.querySelector(`#inline_child_footnotes-0-panel-content`).scrollIntoView({ behavior: 'smooth' }),
  }, props.children);
};

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions