editor: add button to sort task list

This commit is contained in:
Abdullah Atta
2023-02-25 11:56:48 +05:00
committed by Abdullah Atta
parent ca2f924417
commit 912e97dc3c
3 changed files with 66 additions and 3 deletions

View File

@@ -19,7 +19,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
import { Box, Flex, Input, Text } from "@theme-ui/components";
import { findChildren, getNodeType } from "@tiptap/core";
import TaskItem from "@tiptap/extension-task-item";
import { Node } from "prosemirror-model";
import { useCallback, useEffect, useMemo, useState } from "react";
import { ToolButton } from "../../toolbar/components/tool-button";
@@ -27,7 +26,7 @@ import { findParentNodeOfTypeClosestToPos } from "../../utils/prosemirror";
import { ReactNodeViewProps } from "../react";
import { TaskItemNode } from "../task-item";
import { TaskListAttributes } from "./task-list";
import { countCheckedItems, deleteCheckedItems } from "./utils";
import { countCheckedItems, deleteCheckedItems, sortList } from "./utils";
export function TaskListComponent(
props: ReactNodeViewProps<TaskListAttributes>
@@ -120,6 +119,26 @@ export function TaskListComponent(
}}
/>
{editor.isEditable && (
<>
<ToolButton
toggled={false}
title="Move all checked tasks to bottom"
icon="sortTaskList"
variant="small"
sx={{
zIndex: 1
}}
onClick={() => {
const pos = getPos();
editor.current
?.chain()
.focus()
.command(({ tr }) => {
return !!sortList(tr, pos);
})
.run();
}}
/>
<ToolButton
toggled={false}
title="Clear completed tasks"
@@ -140,6 +159,7 @@ export function TaskListComponent(
.run();
}}
/>
</>
)}
<Text
variant={"body"}

View File

@@ -69,3 +69,44 @@ export function deleteCheckedItems(tr: Transaction, pos: number) {
return tr;
}
export function sortList(tr: Transaction, pos: number) {
const node = tr.doc.nodeAt(pos);
const parent = node ? { node, pos } : null;
if (!parent || parent.node.type.name !== TaskList.name) return;
const sublists: NodeWithPos[] = [];
parent.node.descendants((node, nodePos) => {
if (node.type.name === TaskList.name)
sublists.push({ node, pos: pos + nodePos + 1 });
});
if (sublists.length > 1) sublists.reverse();
sublists.push(parent);
for (const list of sublists) {
const children: {
checked: number;
index: number;
}[] = [];
list.node.forEach((node, _, index) => {
children.push({
index,
checked: node.attrs.checked ? 1 : 0
});
});
tr.replaceWith(
tr.mapping.map(list.pos),
tr.mapping.map(list.pos + list.node.nodeSize),
Fragment.from(
children
.sort((a, b) => a.checked - b.checked)
.map((c) => list.node.child(c.index))
)
);
}
if (!tr.steps.length) return null;
return tr;
}

View File

@@ -112,7 +112,8 @@ import {
mdiNewspaper,
mdiFullscreen,
mdiWeb,
mdiPageNextOutline
mdiPageNextOutline,
mdiSortBoolAscendingVariant
} from "@mdi/js";
export const Icons = {
@@ -190,6 +191,7 @@ export const Icons = {
borderColor:
"M4 24q-.825 0-1.412-.587Q2 22.825 2 22q0-.825.588-1.413Q3.175 20 4 20h16q.825 0 1.413.587Q22 21.175 22 22q0 .825-.587 1.413Q20.825 24 20 24Zm1-6q-.425 0-.713-.288Q4 17.425 4 17v-2.325q0-.2.075-.388q.075-.187.225-.337l8.75-8.75l3.75 3.75l-8.75 8.75q-.15.15-.337.225q-.188.075-.388.075Zm1-2h.9L14 8.95L13.05 8L6 15.1Zm11.925-8.15l-3.75-3.75l1.8-1.8q.275-.3.7-.288q.425.013.7.288l2.35 2.35q.275.275.275.688q0 .412-.275.712ZM6 16Z",
sortDesc: mdiSortDescending,
sortTaskList: mdiSortBoolAscendingVariant,
deleteTable: mdiTableOff,
mergeCells: mdiTableMergeCells,
splitCells: mdiTableSplitCell,