mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: Task List Behaviour in Editor (#2789)
* better variable names and comments * drag drop migrated * custom horizontal rule created * init transaction hijack * fixed code block with better contrast, keyboard tripple enter press disabled and syntax highlighting * fixed link selector closing on open behaviour * added better keymaps and syntax highlights * made drag and drop working for code blocks * fixed drag drop for code blocks * moved drag drop only to rich text editor * fixed drag and drop only for description * enabled drag handles for peek overview and main issues * got images to old state * fixed task lists to be smaller * removed validate image functions and uncessary imports * table icons svg attributes fixed * custom list keymap extension added * more uncessary imports of validate image removed * removed console logs * fixed drag-handle styles * space styles updated for the editor * removed showing quotes from blockquotes * removed validateImage for now * added better comments and improved redundant renders * removed uncessary console logs * created util for creating the drag handle element * fixed file names
This commit is contained in:
parent
a987df38f4
commit
0c63f21718
@ -31,11 +31,10 @@
|
|||||||
"@blueprintjs/popover2": "^2.0.10",
|
"@blueprintjs/popover2": "^2.0.10",
|
||||||
"@tiptap/core": "^2.1.7",
|
"@tiptap/core": "^2.1.7",
|
||||||
"@tiptap/extension-code-block-lowlight": "^2.1.12",
|
"@tiptap/extension-code-block-lowlight": "^2.1.12",
|
||||||
"highlight.js": "^11.8.0",
|
|
||||||
"lowlight": "^3.0.0",
|
|
||||||
"@tiptap/extension-color": "^2.1.11",
|
"@tiptap/extension-color": "^2.1.11",
|
||||||
"@tiptap/extension-image": "^2.1.7",
|
"@tiptap/extension-image": "^2.1.7",
|
||||||
"@tiptap/extension-link": "^2.1.7",
|
"@tiptap/extension-link": "^2.1.7",
|
||||||
|
"@tiptap/extension-list-item": "^2.1.12",
|
||||||
"@tiptap/extension-mention": "^2.1.12",
|
"@tiptap/extension-mention": "^2.1.12",
|
||||||
"@tiptap/extension-table": "^2.1.6",
|
"@tiptap/extension-table": "^2.1.6",
|
||||||
"@tiptap/extension-table-cell": "^2.1.6",
|
"@tiptap/extension-table-cell": "^2.1.6",
|
||||||
@ -58,7 +57,9 @@
|
|||||||
"eslint": "8.36.0",
|
"eslint": "8.36.0",
|
||||||
"eslint-config-next": "13.2.4",
|
"eslint-config-next": "13.2.4",
|
||||||
"eventsource-parser": "^0.1.0",
|
"eventsource-parser": "^0.1.0",
|
||||||
|
"highlight.js": "^11.8.0",
|
||||||
"jsx-dom-cjs": "^8.0.3",
|
"jsx-dom-cjs": "^8.0.3",
|
||||||
|
"lowlight": "^3.0.0",
|
||||||
"lucide-react": "^0.244.0",
|
"lucide-react": "^0.244.0",
|
||||||
"prosemirror-async-query": "^0.0.4",
|
"prosemirror-async-query": "^0.0.4",
|
||||||
"react-markdown": "^8.0.7",
|
"react-markdown": "^8.0.7",
|
||||||
|
@ -1 +0,0 @@
|
|||||||
export type ValidateImage = (assetUrlWithWorkspaceId: string) => Promise<any>;
|
|
@ -0,0 +1 @@
|
|||||||
|
export * from "./list-keymap";
|
@ -0,0 +1,30 @@
|
|||||||
|
import { getNodeType } from '@tiptap/core'
|
||||||
|
import { NodeType } from '@tiptap/pm/model'
|
||||||
|
import { EditorState } from '@tiptap/pm/state'
|
||||||
|
|
||||||
|
export const findListItemPos = (typeOrName: string | NodeType, state: EditorState) => {
|
||||||
|
const { $from } = state.selection
|
||||||
|
const nodeType = getNodeType(typeOrName, state.schema)
|
||||||
|
|
||||||
|
let currentNode = null
|
||||||
|
let currentDepth = $from.depth
|
||||||
|
let currentPos = $from.pos
|
||||||
|
let targetDepth: number | null = null
|
||||||
|
|
||||||
|
while (currentDepth > 0 && targetDepth === null) {
|
||||||
|
currentNode = $from.node(currentDepth)
|
||||||
|
|
||||||
|
if (currentNode.type === nodeType) {
|
||||||
|
targetDepth = currentDepth
|
||||||
|
} else {
|
||||||
|
currentDepth -= 1
|
||||||
|
currentPos -= 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetDepth === null) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return { $pos: state.doc.resolve(currentPos), depth: targetDepth }
|
||||||
|
}
|
@ -0,0 +1,20 @@
|
|||||||
|
import { getNodeAtPosition } from "@tiptap/core";
|
||||||
|
import { EditorState } from "@tiptap/pm/state";
|
||||||
|
|
||||||
|
import { findListItemPos } from "./find-list-item-pos";
|
||||||
|
|
||||||
|
export const getNextListDepth = (typeOrName: string, state: EditorState) => {
|
||||||
|
const listItemPos = findListItemPos(typeOrName, state);
|
||||||
|
|
||||||
|
if (!listItemPos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [, depth] = getNodeAtPosition(
|
||||||
|
state,
|
||||||
|
typeOrName,
|
||||||
|
listItemPos.$pos.pos + 4,
|
||||||
|
);
|
||||||
|
|
||||||
|
return depth;
|
||||||
|
};
|
@ -0,0 +1,78 @@
|
|||||||
|
import { Editor, isAtStartOfNode, isNodeActive } from "@tiptap/core";
|
||||||
|
import { Node } from "@tiptap/pm/model";
|
||||||
|
|
||||||
|
import { findListItemPos } from "./find-list-item-pos";
|
||||||
|
import { hasListBefore } from "./has-list-before";
|
||||||
|
|
||||||
|
export const handleBackspace = (
|
||||||
|
editor: Editor,
|
||||||
|
name: string,
|
||||||
|
parentListTypes: string[],
|
||||||
|
) => {
|
||||||
|
// this is required to still handle the undo handling
|
||||||
|
if (editor.commands.undoInputRule()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the cursor is not at the start of a node
|
||||||
|
// do nothing and proceed
|
||||||
|
if (!isAtStartOfNode(editor.state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the current item is NOT inside a list item &
|
||||||
|
// the previous item is a list (orderedList or bulletList)
|
||||||
|
// move the cursor into the list and delete the current item
|
||||||
|
if (
|
||||||
|
!isNodeActive(editor.state, name) &&
|
||||||
|
hasListBefore(editor.state, name, parentListTypes)
|
||||||
|
) {
|
||||||
|
const { $anchor } = editor.state.selection;
|
||||||
|
|
||||||
|
const $listPos = editor.state.doc.resolve($anchor.before() - 1);
|
||||||
|
|
||||||
|
const listDescendants: Array<{ node: Node; pos: number }> = [];
|
||||||
|
|
||||||
|
$listPos.node().descendants((node, pos) => {
|
||||||
|
if (node.type.name === name) {
|
||||||
|
listDescendants.push({ node, pos });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const lastItem = listDescendants.at(-1);
|
||||||
|
|
||||||
|
if (!lastItem) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const $lastItemPos = editor.state.doc.resolve(
|
||||||
|
$listPos.start() + lastItem.pos + 1,
|
||||||
|
);
|
||||||
|
|
||||||
|
return editor
|
||||||
|
.chain()
|
||||||
|
.cut(
|
||||||
|
{ from: $anchor.start() - 1, to: $anchor.end() + 1 },
|
||||||
|
$lastItemPos.end(),
|
||||||
|
)
|
||||||
|
.joinForward()
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the cursor is not inside the current node type
|
||||||
|
// do nothing and proceed
|
||||||
|
if (!isNodeActive(editor.state, name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const listItemPos = findListItemPos(name, editor.state);
|
||||||
|
|
||||||
|
if (!listItemPos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if current node is a list item and cursor it at start of a list node,
|
||||||
|
// simply lift the list item i.e. remove it as a list item (task/bullet/ordered)
|
||||||
|
// irrespective of above node being a list or not
|
||||||
|
return editor.chain().liftListItem(name).run();
|
||||||
|
};
|
@ -0,0 +1,34 @@
|
|||||||
|
import { Editor, isAtEndOfNode, isNodeActive } from "@tiptap/core";
|
||||||
|
|
||||||
|
import { nextListIsDeeper } from "./next-list-is-deeper";
|
||||||
|
import { nextListIsHigher } from "./next-list-is-higher";
|
||||||
|
|
||||||
|
export const handleDelete = (editor: Editor, name: string) => {
|
||||||
|
// if the cursor is not inside the current node type
|
||||||
|
// do nothing and proceed
|
||||||
|
if (!isNodeActive(editor.state, name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if the cursor is not at the end of a node
|
||||||
|
// do nothing and proceed
|
||||||
|
if (!isAtEndOfNode(editor.state, name)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if the next node is a list with a deeper depth
|
||||||
|
if (nextListIsDeeper(name, editor.state)) {
|
||||||
|
return editor
|
||||||
|
.chain()
|
||||||
|
.focus(editor.state.selection.from + 4)
|
||||||
|
.lift(name)
|
||||||
|
.joinBackward()
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextListIsHigher(name, editor.state)) {
|
||||||
|
return editor.chain().joinForward().joinBackward().run();
|
||||||
|
}
|
||||||
|
|
||||||
|
return editor.commands.joinItemForward();
|
||||||
|
};
|
@ -0,0 +1,15 @@
|
|||||||
|
import { EditorState } from '@tiptap/pm/state'
|
||||||
|
|
||||||
|
export const hasListBefore = (editorState: EditorState, name: string, parentListTypes: string[]) => {
|
||||||
|
const { $anchor } = editorState.selection
|
||||||
|
|
||||||
|
const previousNodePos = Math.max(0, $anchor.pos - 2)
|
||||||
|
|
||||||
|
const previousNode = editorState.doc.resolve(previousNodePos).node()
|
||||||
|
|
||||||
|
if (!previousNode || !parentListTypes.includes(previousNode.type.name)) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import { EditorState } from '@tiptap/pm/state'
|
||||||
|
|
||||||
|
export const hasListItemAfter = (typeOrName: string, state: EditorState): boolean => {
|
||||||
|
const { $anchor } = state.selection
|
||||||
|
|
||||||
|
const $targetPos = state.doc.resolve($anchor.pos - $anchor.parentOffset - 2)
|
||||||
|
|
||||||
|
if ($targetPos.index() === $targetPos.parent.childCount - 1) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($targetPos.nodeAfter?.type.name !== typeOrName) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import { EditorState } from '@tiptap/pm/state'
|
||||||
|
|
||||||
|
export const hasListItemBefore = (typeOrName: string, state: EditorState): boolean => {
|
||||||
|
const { $anchor } = state.selection
|
||||||
|
|
||||||
|
const $targetPos = state.doc.resolve($anchor.pos - 2)
|
||||||
|
|
||||||
|
if ($targetPos.index() === 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($targetPos.nodeBefore?.type.name !== typeOrName) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
@ -0,0 +1,9 @@
|
|||||||
|
export * from "./find-list-item-pos";
|
||||||
|
export * from "./get-next-list-depth";
|
||||||
|
export * from "./handle-backspace";
|
||||||
|
export * from "./handle-delete";
|
||||||
|
export * from "./has-list-before";
|
||||||
|
export * from "./has-list-item-after";
|
||||||
|
export * from "./has-list-item-before";
|
||||||
|
export * from "./next-list-is-deeper";
|
||||||
|
export * from "./next-list-is-higher";
|
@ -0,0 +1,19 @@
|
|||||||
|
import { EditorState } from "@tiptap/pm/state";
|
||||||
|
|
||||||
|
import { findListItemPos } from "./find-list-item-pos";
|
||||||
|
import { getNextListDepth } from "./get-next-list-depth";
|
||||||
|
|
||||||
|
export const nextListIsDeeper = (typeOrName: string, state: EditorState) => {
|
||||||
|
const listDepth = getNextListDepth(typeOrName, state);
|
||||||
|
const listItemPos = findListItemPos(typeOrName, state);
|
||||||
|
|
||||||
|
if (!listItemPos || !listDepth) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listDepth > listItemPos.depth) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
@ -0,0 +1,19 @@
|
|||||||
|
import { EditorState } from "@tiptap/pm/state";
|
||||||
|
|
||||||
|
import { findListItemPos } from "./find-list-item-pos";
|
||||||
|
import { getNextListDepth } from "./get-next-list-depth";
|
||||||
|
|
||||||
|
export const nextListIsHigher = (typeOrName: string, state: EditorState) => {
|
||||||
|
const listDepth = getNextListDepth(typeOrName, state);
|
||||||
|
const listItemPos = findListItemPos(typeOrName, state);
|
||||||
|
|
||||||
|
if (!listItemPos || !listDepth) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listDepth < listItemPos.depth) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
@ -0,0 +1,94 @@
|
|||||||
|
import { Extension } from "@tiptap/core";
|
||||||
|
|
||||||
|
import { handleBackspace, handleDelete } from "./list-helpers";
|
||||||
|
|
||||||
|
export type ListKeymapOptions = {
|
||||||
|
listTypes: Array<{
|
||||||
|
itemName: string;
|
||||||
|
wrapperNames: string[];
|
||||||
|
}>;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ListKeymap = Extension.create<ListKeymapOptions>({
|
||||||
|
name: "listKeymap",
|
||||||
|
|
||||||
|
addOptions() {
|
||||||
|
return {
|
||||||
|
listTypes: [
|
||||||
|
{
|
||||||
|
itemName: "listItem",
|
||||||
|
wrapperNames: ["bulletList", "orderedList"],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
itemName: "taskItem",
|
||||||
|
wrapperNames: ["taskList"],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
},
|
||||||
|
|
||||||
|
addKeyboardShortcuts() {
|
||||||
|
return {
|
||||||
|
Delete: ({ editor }) => {
|
||||||
|
let handled = false;
|
||||||
|
|
||||||
|
this.options.listTypes.forEach(({ itemName }) => {
|
||||||
|
if (editor.state.schema.nodes[itemName] === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handleDelete(editor, itemName)) {
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
},
|
||||||
|
"Mod-Delete": ({ editor }) => {
|
||||||
|
let handled = false;
|
||||||
|
|
||||||
|
this.options.listTypes.forEach(({ itemName }) => {
|
||||||
|
if (editor.state.schema.nodes[itemName] === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handleDelete(editor, itemName)) {
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
},
|
||||||
|
Backspace: ({ editor }) => {
|
||||||
|
let handled = false;
|
||||||
|
|
||||||
|
this.options.listTypes.forEach(({ itemName, wrapperNames }) => {
|
||||||
|
if (editor.state.schema.nodes[itemName] === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handleBackspace(editor, itemName, wrapperNames)) {
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
},
|
||||||
|
"Mod-Backspace": ({ editor }) => {
|
||||||
|
let handled = false;
|
||||||
|
|
||||||
|
this.options.listTypes.forEach(({ itemName, wrapperNames }) => {
|
||||||
|
if (editor.state.schema.nodes[itemName] === undefined) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handleBackspace(editor, itemName, wrapperNames)) {
|
||||||
|
handled = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return handled;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
});
|
@ -11,7 +11,6 @@ import TableHeader from "./table/table-header/table-header";
|
|||||||
import Table from "./table/table";
|
import Table from "./table/table";
|
||||||
import TableCell from "./table/table-cell/table-cell";
|
import TableCell from "./table/table-cell/table-cell";
|
||||||
import TableRow from "./table/table-row/table-row";
|
import TableRow from "./table/table-row/table-row";
|
||||||
import DragDrop from "./drag-drop";
|
|
||||||
import HorizontalRule from "./horizontal-rule";
|
import HorizontalRule from "./horizontal-rule";
|
||||||
|
|
||||||
import ImageExtension from "./image";
|
import ImageExtension from "./image";
|
||||||
@ -20,10 +19,10 @@ import { DeleteImage } from "../../types/delete-image";
|
|||||||
import { isValidHttpUrl } from "../../lib/utils";
|
import { isValidHttpUrl } from "../../lib/utils";
|
||||||
import { IMentionSuggestion } from "../../types/mention-suggestion";
|
import { IMentionSuggestion } from "../../types/mention-suggestion";
|
||||||
import { Mentions } from "../mentions";
|
import { Mentions } from "../mentions";
|
||||||
import { ValidateImage } from "../../types/validate-image";
|
|
||||||
|
|
||||||
import { CustomKeymap } from "./keymap";
|
import { CustomKeymap } from "./keymap";
|
||||||
import { CustomCodeBlock } from "./code";
|
import { CustomCodeBlock } from "./code";
|
||||||
|
import { ListKeymap } from "./custom-list-keymap";
|
||||||
|
|
||||||
export const CoreEditorExtensions = (
|
export const CoreEditorExtensions = (
|
||||||
mentionConfig: {
|
mentionConfig: {
|
||||||
@ -31,7 +30,6 @@ export const CoreEditorExtensions = (
|
|||||||
mentionHighlights: string[];
|
mentionHighlights: string[];
|
||||||
},
|
},
|
||||||
deleteFile: DeleteImage,
|
deleteFile: DeleteImage,
|
||||||
validateFile?: ValidateImage,
|
|
||||||
cancelUploadImage?: () => any,
|
cancelUploadImage?: () => any,
|
||||||
) => [
|
) => [
|
||||||
StarterKit.configure({
|
StarterKit.configure({
|
||||||
@ -64,6 +62,7 @@ export const CoreEditorExtensions = (
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
CustomKeymap,
|
CustomKeymap,
|
||||||
|
ListKeymap,
|
||||||
TiptapLink.configure({
|
TiptapLink.configure({
|
||||||
protocols: ["http", "https"],
|
protocols: ["http", "https"],
|
||||||
validate: (url) => isValidHttpUrl(url),
|
validate: (url) => isValidHttpUrl(url),
|
||||||
@ -72,7 +71,7 @@ export const CoreEditorExtensions = (
|
|||||||
"text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer",
|
"text-custom-primary-300 underline underline-offset-[3px] hover:text-custom-primary-500 transition-colors cursor-pointer",
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
ImageExtension(deleteFile, validateFile, cancelUploadImage).configure({
|
ImageExtension(deleteFile, cancelUploadImage).configure({
|
||||||
HTMLAttributes: {
|
HTMLAttributes: {
|
||||||
class: "rounded-lg border border-custom-border-300",
|
class: "rounded-lg border border-custom-border-300",
|
||||||
},
|
},
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
const icons = {
|
const icons = {
|
||||||
colorPicker: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" style="transform: ;msFilter:;"><path fill="rgb(var(--color-text-300))" d="M20 14c-.092.064-2 2.083-2 3.5 0 1.494.949 2.448 2 2.5.906.044 2-.891 2-2.5 0-1.5-1.908-3.436-2-3.5zM9.586 20c.378.378.88.586 1.414.586s1.036-.208 1.414-.586l7-7-.707-.707L11 4.586 8.707 2.293 7.293 3.707 9.586 6 4 11.586c-.378.378-.586.88-.586 1.414s.208 1.036.586 1.414L9.586 20zM11 7.414 16.586 13H5.414L11 7.414z"></path></svg>`,
|
colorPicker: `<svg xmlns="http://www.w3.org/2000/svg" length="24" viewBox="0 0 24 24" style="transform: ;msFilter:;"><path fill="rgb(var(--color-text-300))" d="M20 14c-.092.064-2 2.083-2 3.5 0 1.494.949 2.448 2 2.5.906.044 2-.891 2-2.5 0-1.5-1.908-3.436-2-3.5zM9.586 20c.378.378.88.586 1.414.586s1.036-.208 1.414-.586l7-7-.707-.707L11 4.586 8.707 2.293 7.293 3.707 9.586 6 4 11.586c-.378.378-.586.88-.586 1.414s.208 1.036.586 1.414L9.586 20zM11 7.414 16.586 13H5.414L11 7.414z"></path></svg>`,
|
||||||
deleteColumn: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="#e53e3e" d="M0 0H24V24H0z"/><path d="M12 3c.552 0 1 .448 1 1v8c.835-.628 1.874-1 3-1 2.761 0 5 2.239 5 5s-2.239 5-5 5c-1.032 0-1.99-.313-2.787-.848L13 20c0 .552-.448 1-1 1H6c-.552 0-1-.448-1-1V4c0-.552.448-1 1-1h6zm-1 2H7v14h4V5zm8 10h-6v2h6v-2z"/></svg>`,
|
deleteColumn: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" length="24"><path fill="#e53e3e" d="M0 0H24V24H0z"/><path d="M12 3c.552 0 1 .448 1 1v8c.835-.628 1.874-1 3-1 2.761 0 5 2.239 5 5s-2.239 5-5 5c-1.032 0-1.99-.313-2.787-.848L13 20c0 .552-.448 1-1 1H6c-.552 0-1-.448-1-1V4c0-.552.448-1 1-1h6zm-1 2H7v14h4V5zm8 10h-6v2h6v-2z"/></svg>`,
|
||||||
deleteRow: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24"><path fill="#e53e3e" d="M0 0H24V24H0z"/><path d="M20 5c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1 .628.835 1 1.874 1 3 0 2.761-2.239 5-5 5s-5-2.239-5-5c0-1.126.372-2.165 1-3H4c-.552 0-1-.448-1-1V6c0-.552.448-1 1-1h16zm-7 10v2h6v-2h-6zm6-8H5v4h14V7z"/></svg>`,
|
deleteRow: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" length="24"><path fill="#e53e3e" d="M0 0H24V24H0z"/><path d="M20 5c.552 0 1 .448 1 1v6c0 .552-.448 1-1 1 .628.835 1 1.874 1 3 0 2.761-2.239 5-5 5s-5-2.239-5-5c0-1.126.372-2.165 1-3H4c-.552 0-1-.448-1-1V6c0-.552.448-1 1-1h16zm-7 10v2h6v-2h-6zm6-8H5v4h14V7z"/></svg>`,
|
||||||
insertLeftTableIcon: `<svg
|
insertLeftTableIcon: `<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width={24}
|
length={24}
|
||||||
height={24}
|
|
||||||
viewBox="0 -960 960 960"
|
viewBox="0 -960 960 960"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
@ -16,8 +15,7 @@ const icons = {
|
|||||||
`,
|
`,
|
||||||
insertRightTableIcon: `<svg
|
insertRightTableIcon: `<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width={24}
|
length={24}
|
||||||
height={24}
|
|
||||||
viewBox="0 -960 960 960"
|
viewBox="0 -960 960 960"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
@ -28,8 +26,7 @@ const icons = {
|
|||||||
`,
|
`,
|
||||||
insertTopTableIcon: `<svg
|
insertTopTableIcon: `<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width={24}
|
length={24}
|
||||||
height={24}
|
|
||||||
viewBox="0 -960 960 960"
|
viewBox="0 -960 960 960"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
@ -40,8 +37,7 @@ const icons = {
|
|||||||
`,
|
`,
|
||||||
insertBottomTableIcon: `<svg
|
insertBottomTableIcon: `<svg
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
width={24}
|
length={24}
|
||||||
height={24}
|
|
||||||
viewBox="0 -960 960 960"
|
viewBox="0 -960 960 960"
|
||||||
>
|
>
|
||||||
<path
|
<path
|
||||||
|
@ -1,12 +1,6 @@
|
|||||||
import { useEditor as useCustomEditor, Editor } from "@tiptap/react";
|
import { useEditor as useCustomEditor, Editor } from "@tiptap/react";
|
||||||
import {
|
import { useImperativeHandle, useRef, MutableRefObject } from "react";
|
||||||
useImperativeHandle,
|
|
||||||
useRef,
|
|
||||||
MutableRefObject,
|
|
||||||
useEffect,
|
|
||||||
} from "react";
|
|
||||||
import { DeleteImage } from "../../types/delete-image";
|
import { DeleteImage } from "../../types/delete-image";
|
||||||
import { ValidateImage } from "../../types/validate-image";
|
|
||||||
import { CoreEditorProps } from "../props";
|
import { CoreEditorProps } from "../props";
|
||||||
import { CoreEditorExtensions } from "../extensions";
|
import { CoreEditorExtensions } from "../extensions";
|
||||||
import { EditorProps } from "@tiptap/pm/view";
|
import { EditorProps } from "@tiptap/pm/view";
|
||||||
@ -17,7 +11,6 @@ import { IMentionSuggestion } from "../../types/mention-suggestion";
|
|||||||
|
|
||||||
interface CustomEditorProps {
|
interface CustomEditorProps {
|
||||||
uploadFile: UploadImage;
|
uploadFile: UploadImage;
|
||||||
validateFile?: ValidateImage;
|
|
||||||
setIsSubmitting?: (
|
setIsSubmitting?: (
|
||||||
isSubmitting: "submitting" | "submitted" | "saved",
|
isSubmitting: "submitting" | "submitted" | "saved",
|
||||||
) => void;
|
) => void;
|
||||||
@ -37,7 +30,6 @@ interface CustomEditorProps {
|
|||||||
export const useEditor = ({
|
export const useEditor = ({
|
||||||
uploadFile,
|
uploadFile,
|
||||||
deleteFile,
|
deleteFile,
|
||||||
validateFile,
|
|
||||||
cancelUploadImage,
|
cancelUploadImage,
|
||||||
editorProps = {},
|
editorProps = {},
|
||||||
value,
|
value,
|
||||||
@ -62,7 +54,6 @@ export const useEditor = ({
|
|||||||
mentionHighlights: mentionHighlights ?? [],
|
mentionHighlights: mentionHighlights ?? [],
|
||||||
},
|
},
|
||||||
deleteFile,
|
deleteFile,
|
||||||
validateFile,
|
|
||||||
cancelUploadImage,
|
cancelUploadImage,
|
||||||
),
|
),
|
||||||
...extensions,
|
...extensions,
|
||||||
|
@ -0,0 +1,23 @@
|
|||||||
|
export function createDragHandleElement(): HTMLElement {
|
||||||
|
let dragHandleElement = document.createElement("div");
|
||||||
|
dragHandleElement.draggable = true;
|
||||||
|
dragHandleElement.dataset.dragHandle = "";
|
||||||
|
dragHandleElement.classList.add("drag-handle");
|
||||||
|
|
||||||
|
const dragHandleContainer = document.createElement("div");
|
||||||
|
dragHandleContainer.classList.add("drag-handle-container");
|
||||||
|
dragHandleElement.appendChild(dragHandleContainer);
|
||||||
|
|
||||||
|
const dotsContainer = document.createElement("div");
|
||||||
|
dotsContainer.classList.add("drag-handle-dots");
|
||||||
|
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
const spanElement = document.createElement("span");
|
||||||
|
spanElement.classList.add("drag-handle-dot");
|
||||||
|
dotsContainer.appendChild(spanElement);
|
||||||
|
}
|
||||||
|
|
||||||
|
dragHandleContainer.appendChild(dotsContainer);
|
||||||
|
|
||||||
|
return dragHandleElement;
|
||||||
|
}
|
@ -3,6 +3,7 @@ import { Extension } from "@tiptap/core";
|
|||||||
import { PluginKey, NodeSelection, Plugin } from "@tiptap/pm/state";
|
import { PluginKey, NodeSelection, Plugin } from "@tiptap/pm/state";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import { __serializeForClipboard, EditorView } from "@tiptap/pm/view";
|
import { __serializeForClipboard, EditorView } from "@tiptap/pm/view";
|
||||||
|
import { createDragHandleElement } from "../../lib/utils/DragHandleElement";
|
||||||
|
|
||||||
export interface DragHandleOptions {
|
export interface DragHandleOptions {
|
||||||
dragHandleWidth: number;
|
dragHandleWidth: number;
|
||||||
@ -135,25 +136,7 @@ function DragHandle(options: DragHandleOptions) {
|
|||||||
return new Plugin({
|
return new Plugin({
|
||||||
key: new PluginKey("dragHandle"),
|
key: new PluginKey("dragHandle"),
|
||||||
view: (view) => {
|
view: (view) => {
|
||||||
dragHandleElement = document.createElement("div");
|
dragHandleElement = createDragHandleElement();
|
||||||
dragHandleElement.draggable = true;
|
|
||||||
dragHandleElement.dataset.dragHandle = "";
|
|
||||||
dragHandleElement.classList.add("drag-handle");
|
|
||||||
|
|
||||||
const dragHandleContainer = document.createElement("div");
|
|
||||||
dragHandleContainer.classList.add("drag-handle-container");
|
|
||||||
dragHandleElement.appendChild(dragHandleContainer);
|
|
||||||
|
|
||||||
const dotsContainer = document.createElement("div");
|
|
||||||
dotsContainer.classList.add("drag-handle-dots");
|
|
||||||
|
|
||||||
for (let i = 0; i < 6; i++) {
|
|
||||||
const spanElement = document.createElement("span");
|
|
||||||
spanElement.classList.add("drag-handle-dot");
|
|
||||||
dotsContainer.appendChild(spanElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
dragHandleContainer.appendChild(dotsContainer);
|
|
||||||
dragHandleElement.addEventListener("dragstart", (e) => {
|
dragHandleElement.addEventListener("dragstart", (e) => {
|
||||||
handleDragStart(e, view);
|
handleDragStart(e, view);
|
||||||
});
|
});
|
||||||
@ -213,7 +196,7 @@ function DragHandle(options: DragHandleOptions) {
|
|||||||
if (!dragHandleElement) return;
|
if (!dragHandleElement) return;
|
||||||
|
|
||||||
dragHandleElement.style.left = `${rect.left - rect.width}px`;
|
dragHandleElement.style.left = `${rect.left - rect.width}px`;
|
||||||
dragHandleElement.style.top = `${rect.top}px`;
|
dragHandleElement.style.top = `${rect.top + 3}px`;
|
||||||
showDragHandle();
|
showDragHandle();
|
||||||
},
|
},
|
||||||
keydown: () => {
|
keydown: () => {
|
||||||
|
@ -11,7 +11,6 @@ import { RichTextEditorExtensions } from "./extensions";
|
|||||||
|
|
||||||
export type UploadImage = (file: File) => Promise<string>;
|
export type UploadImage = (file: File) => Promise<string>;
|
||||||
export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise<any>;
|
export type DeleteImage = (assetUrlWithWorkspaceId: string) => Promise<any>;
|
||||||
export type ValidateImage = (assetUrlWithWorkspaceId: string) => Promise<any>;
|
|
||||||
|
|
||||||
export type IMentionSuggestion = {
|
export type IMentionSuggestion = {
|
||||||
id: string;
|
id: string;
|
||||||
@ -29,7 +28,6 @@ interface IRichTextEditor {
|
|||||||
dragDropEnabled?: boolean;
|
dragDropEnabled?: boolean;
|
||||||
uploadFile: UploadImage;
|
uploadFile: UploadImage;
|
||||||
deleteFile: DeleteImage;
|
deleteFile: DeleteImage;
|
||||||
validateFile?: ValidateImage;
|
|
||||||
noBorder?: boolean;
|
noBorder?: boolean;
|
||||||
borderOnFocus?: boolean;
|
borderOnFocus?: boolean;
|
||||||
cancelUploadImage?: () => any;
|
cancelUploadImage?: () => any;
|
||||||
@ -65,7 +63,6 @@ const RichTextEditor = ({
|
|||||||
value,
|
value,
|
||||||
uploadFile,
|
uploadFile,
|
||||||
deleteFile,
|
deleteFile,
|
||||||
validateFile,
|
|
||||||
noBorder,
|
noBorder,
|
||||||
cancelUploadImage,
|
cancelUploadImage,
|
||||||
borderOnFocus,
|
borderOnFocus,
|
||||||
@ -82,7 +79,6 @@ const RichTextEditor = ({
|
|||||||
value,
|
value,
|
||||||
uploadFile,
|
uploadFile,
|
||||||
cancelUploadImage,
|
cancelUploadImage,
|
||||||
validateFile,
|
|
||||||
deleteFile,
|
deleteFile,
|
||||||
forwardedRef,
|
forwardedRef,
|
||||||
extensions: RichTextEditorExtensions(
|
extensions: RichTextEditorExtensions(
|
||||||
|
@ -103,7 +103,6 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props: any) => {
|
|||||||
editor={props.editor!}
|
editor={props.editor!}
|
||||||
isOpen={isNodeSelectorOpen}
|
isOpen={isNodeSelectorOpen}
|
||||||
setIsOpen={() => {
|
setIsOpen={() => {
|
||||||
console.log("setIsNodeSelectorOpen");
|
|
||||||
setIsNodeSelectorOpen(!isNodeSelectorOpen);
|
setIsNodeSelectorOpen(!isNodeSelectorOpen);
|
||||||
setIsLinkSelectorOpen(false);
|
setIsLinkSelectorOpen(false);
|
||||||
}}
|
}}
|
||||||
@ -113,7 +112,6 @@ export const EditorBubbleMenu: FC<EditorBubbleMenuProps> = (props: any) => {
|
|||||||
editor={props.editor!!}
|
editor={props.editor!!}
|
||||||
isOpen={isLinkSelectorOpen}
|
isOpen={isLinkSelectorOpen}
|
||||||
setIsOpen={() => {
|
setIsOpen={() => {
|
||||||
console.log("setIsLinkSelectorOpen");
|
|
||||||
setIsLinkSelectorOpen(!isLinkSelectorOpen);
|
setIsLinkSelectorOpen(!isLinkSelectorOpen);
|
||||||
setIsNodeSelectorOpen(false);
|
setIsNodeSelectorOpen(false);
|
||||||
}}
|
}}
|
||||||
|
@ -53,11 +53,12 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
|
|||||||
background-color: rgb(var(--color-background-100));
|
background-color: rgb(var(--color-background-100));
|
||||||
margin: 0;
|
margin: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 1.2rem;
|
width: 0.8rem;
|
||||||
height: 1.2rem;
|
height: 0.8rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
border: 2px solid rgb(var(--color-text-100));
|
border: 1.5px solid rgb(var(--color-text-100));
|
||||||
margin-right: 0.3rem;
|
margin-right: 0.2rem;
|
||||||
|
margin-top: 0.15rem;
|
||||||
display: grid;
|
display: grid;
|
||||||
place-content: center;
|
place-content: center;
|
||||||
|
|
||||||
@ -71,8 +72,8 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
|
|||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
content: "";
|
content: "";
|
||||||
width: 0.65em;
|
width: 0.5em;
|
||||||
height: 0.65em;
|
height: 0.5em;
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
transition: 120ms transform ease-in-out;
|
transition: 120ms transform ease-in-out;
|
||||||
box-shadow: inset 1em 1em;
|
box-shadow: inset 1em 1em;
|
||||||
@ -229,3 +230,93 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
|
|||||||
.ProseMirror table * .is-empty::before {
|
.ProseMirror table * .is-empty::before {
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.ProseMirror pre {
|
||||||
|
background: rgba(var(--color-background-80));
|
||||||
|
border-radius: 0.5rem;
|
||||||
|
color: rgba(var(--color-text-100));
|
||||||
|
font-family: "JetBrainsMono", monospace;
|
||||||
|
padding: 0.75rem 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ProseMirror pre code {
|
||||||
|
background: none;
|
||||||
|
color: inherit;
|
||||||
|
font-size: 0.8rem;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ProseMirror:not(.dragging) .ProseMirror-selectednode:not(img):not(pre) {
|
||||||
|
outline: none !important;
|
||||||
|
border-radius: 0.2rem;
|
||||||
|
background-color: rgb(var(--color-background-90));
|
||||||
|
border: 1px solid #5abbf7;
|
||||||
|
padding: 4px 2px 4px 2px;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle {
|
||||||
|
position: fixed;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity ease-in 0.2s;
|
||||||
|
height: 18px;
|
||||||
|
width: 15px;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
z-index: 10;
|
||||||
|
cursor: grab;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: rgb(var(--color-background-90));
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle:hover {
|
||||||
|
background-color: rgb(var(--color-background-80));
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle.hidden {
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
.drag-handle {
|
||||||
|
display: none;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle-container {
|
||||||
|
height: 15px;
|
||||||
|
width: 15px;
|
||||||
|
cursor: grab;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle-dots {
|
||||||
|
height: 100%;
|
||||||
|
width: 12px;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
place-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.drag-handle-dot {
|
||||||
|
height: 2.75px;
|
||||||
|
width: 3px;
|
||||||
|
background-color: rgba(var(--color-text-200));
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
div[data-type="horizontalRule"] {
|
||||||
|
line-height: 0;
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
|
||||||
|
& > div {
|
||||||
|
border-bottom: 1px solid rgb(var(--color-text-100));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -34,7 +34,6 @@ export class FileService extends APIService {
|
|||||||
constructor() {
|
constructor() {
|
||||||
super(API_BASE_URL);
|
super(API_BASE_URL);
|
||||||
this.uploadFile = this.uploadFile.bind(this);
|
this.uploadFile = this.uploadFile.bind(this);
|
||||||
// this.validateFile = this.validateFile.bind(this);
|
|
||||||
this.deleteImage = this.deleteImage.bind(this);
|
this.deleteImage = this.deleteImage.bind(this);
|
||||||
this.cancelUpload = this.cancelUpload.bind(this);
|
this.cancelUpload = this.cancelUpload.bind(this);
|
||||||
}
|
}
|
||||||
@ -63,14 +62,6 @@ export class FileService extends APIService {
|
|||||||
this.cancelSource.cancel("Upload cancelled");
|
this.cancelSource.cancel("Upload cancelled");
|
||||||
}
|
}
|
||||||
|
|
||||||
// async validateFile(assetUrlWithWorkspaceId: string): Promise<any> {
|
|
||||||
// console.log("bruh", assetUrlWithWorkspaceId);
|
|
||||||
// const res = await this.get(`/api/workspaces/file-assets/${assetUrlWithWorkspaceId}/`);
|
|
||||||
// const data = res?.data;
|
|
||||||
// console.log("data inside fucntion");
|
|
||||||
// return data.status;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
getUploadFileFunction(workspaceSlug: string): (file: File) => Promise<string> {
|
getUploadFileFunction(workspaceSlug: string): (file: File) => Promise<string> {
|
||||||
return async (file: File) => {
|
return async (file: File) => {
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
|
@ -6,6 +6,12 @@
|
|||||||
height: 0;
|
height: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* block quotes */
|
||||||
|
.ProseMirror blockquote p::before,
|
||||||
|
.ProseMirror blockquote p::after {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.ProseMirror .is-empty::before {
|
.ProseMirror .is-empty::before {
|
||||||
content: attr(data-placeholder);
|
content: attr(data-placeholder);
|
||||||
float: left;
|
float: left;
|
||||||
@ -53,11 +59,12 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
|
|||||||
background-color: rgb(var(--color-background-100));
|
background-color: rgb(var(--color-background-100));
|
||||||
margin: 0;
|
margin: 0;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 1.2rem;
|
width: 0.8rem;
|
||||||
height: 1.2rem;
|
height: 0.8rem;
|
||||||
position: relative;
|
position: relative;
|
||||||
border: 2px solid rgb(var(--color-text-100));
|
border: 1.5px solid rgb(var(--color-text-100));
|
||||||
margin-right: 0.3rem;
|
margin-right: 0.2rem;
|
||||||
|
margin-top: 0.15rem;
|
||||||
display: grid;
|
display: grid;
|
||||||
place-content: center;
|
place-content: center;
|
||||||
|
|
||||||
@ -71,8 +78,8 @@ ul[data-type="taskList"] li > label input[type="checkbox"] {
|
|||||||
|
|
||||||
&::before {
|
&::before {
|
||||||
content: "";
|
content: "";
|
||||||
width: 0.65em;
|
width: 0.5em;
|
||||||
height: 0.65em;
|
height: 0.5em;
|
||||||
transform: scale(0);
|
transform: scale(0);
|
||||||
transition: 120ms transform ease-in-out;
|
transition: 120ms transform ease-in-out;
|
||||||
box-shadow: inset 1em 1em;
|
box-shadow: inset 1em 1em;
|
||||||
@ -259,26 +266,18 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
|
|||||||
position: fixed;
|
position: fixed;
|
||||||
opacity: 1;
|
opacity: 1;
|
||||||
transition: opacity ease-in 0.2s;
|
transition: opacity ease-in 0.2s;
|
||||||
|
height: 18px;
|
||||||
|
width: 15px;
|
||||||
display: grid;
|
display: grid;
|
||||||
place-items: center;
|
place-items: center;
|
||||||
height: 20px;
|
|
||||||
width: 15px;
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
background-color: rgb(var(--color-background-90));
|
background-color: rgb(var(--color-background-90));
|
||||||
&:hover {
|
|
||||||
background-color: rgb(var(--color-background-80));
|
|
||||||
}
|
|
||||||
|
|
||||||
&.hide {
|
|
||||||
opacity: 0;
|
|
||||||
pointer-events: none;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.drag-handle:hover {
|
.drag-handle:hover {
|
||||||
background-color: #0d0d0d 10;
|
background-color: rgb(var(--color-background-80));
|
||||||
transition: background-color 0.2s;
|
transition: background-color 0.2s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -295,7 +294,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.drag-handle-container {
|
.drag-handle-container {
|
||||||
height: 20px;
|
height: 15px;
|
||||||
width: 15px;
|
width: 15px;
|
||||||
cursor: grab;
|
cursor: grab;
|
||||||
display: grid;
|
display: grid;
|
||||||
@ -313,7 +312,7 @@ ul[data-type="taskList"] li[data-checked="true"] > div > p {
|
|||||||
.drag-handle-dot {
|
.drag-handle-dot {
|
||||||
height: 2.75px;
|
height: 2.75px;
|
||||||
width: 3px;
|
width: 3px;
|
||||||
background-color: rgba(var(--color-text-100));
|
background-color: rgba(var(--color-text-200));
|
||||||
border-radius: 50%;
|
border-radius: 50%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user