Skip to content

Commit

Permalink
Merge pull request #34 from sereneinserenade/feat/draggable-blocks
Browse files Browse the repository at this point in the history
feat: draggable blocks
  • Loading branch information
sereneinserenade authored Nov 7, 2022
2 parents 8276b6a + 6939713 commit fc53873
Show file tree
Hide file tree
Showing 15 changed files with 517 additions and 12 deletions.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"manifest_version": 3,
"version": "1.2.4",
"version": "1.2.5",
"name": "PlaceNoter",
"description": "Turns browser's home page to a Note-Taking-App.",
"offline_enabled": true,
Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "placenoter",
"version": "1.2.4",
"version": "1.2.5",
"description": "New tab replaced by note taking app.",
"license": "MIT",
"repository": {
Expand Down
2 changes: 2 additions & 0 deletions src/components/Sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ const Sidebar = () => {
// Adding note to `binNotes`
// TODO: don't need so much vars/consts
setBinNotes(JSON.parse(JSON.stringify([note, ...binNotes])))

if (id === activeNote?.id) setActiveNote(undefined)
}

const initiateMoveToBin = (e: any, note: Note) => {
Expand Down
28 changes: 26 additions & 2 deletions src/components/editor/Menubar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { Button, Input, Tooltip, Text } from '@nextui-org/react';
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { debounce } from 'lodash';
import { RiSearch2Line, RiArrowDownSLine } from 'react-icons/ri'
import { MdSpellcheck } from 'react-icons/md'
import { MdEdit, MdPreview, MdSpellcheck } from 'react-icons/md'
import { useLocalStorage } from 'react-use';

import { stopPrevent } from '../../utils'
Expand Down Expand Up @@ -159,9 +159,17 @@ type MenubarProps = {
editor: Editor,
isLocalSearchVisible: boolean,
onSearchTooltipClose: () => any
isPreview: boolean,
toggleIsPreview: () => any
}

const Menubar = ({ editor, isLocalSearchVisible, onSearchTooltipClose }: MenubarProps) => {
const Menubar = ({
editor,
isLocalSearchVisible,
onSearchTooltipClose,
isPreview,
toggleIsPreview,
}: MenubarProps) => {
if (!editor) return null

const activeNote = useRecoilValue(activeNoteState)
Expand Down Expand Up @@ -362,6 +370,22 @@ const Menubar = ({ editor, isLocalSearchVisible, onSearchTooltipClose }: Menubar
</button>
</Tooltip>

<Tooltip
placement='top'
content={isPreview ? 'Edit' : 'Preview'}
>
<button
className={`menubar-button flex ${isPreview ? 'active' : ''}`}
onClick={toggleIsPreview}
>
{
isPreview
? <MdEdit />
: <MdPreview />
}
</button>
</Tooltip>

{LinkModal({ visible: linkModalVisible, onClose: closeLinkModalAndUpdateLink })}

{BubbleMenu({ editor, debouncedCalculateIsActiveStates, isActiveStates, openLinkModal })}
Expand Down
6 changes: 6 additions & 0 deletions src/components/editor/Tiptap.scss
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
pointer-events: none;
}

h1,
h2,
h3 {
margin: 0;
}

ul,
ol {
padding: 0 1rem;
Expand Down
36 changes: 33 additions & 3 deletions src/components/editor/Tiptap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import TableRow from '@tiptap/extension-table-row';

import './Tiptap.scss'
import Menubar from './Menubar'
import { suggestions, Commands, SearchAndReplace, SmilieReplacer } from './extensions'
import { suggestions, Commands, SearchAndReplace, SmilieReplacer, Doc, DBlock, NodeMover } from './extensions'
import { CodeBlockLowLight } from './extensions/CodeBlockLowLight';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import { currentLinkUrlState, linkModalState, spellCheckState } from '../../Store';
Expand All @@ -36,6 +36,8 @@ const Tiptap = ({ onUpdate, content, isNoteInBin }: TiptapProps) => {

const [isLocalSearchVisible, setIsLocalSearchVisible] = useState<boolean>(false)

const [isPreview, setIsPreview] = useState<boolean>(false)

const spellcheckRecoilState = useRecoilValue(spellCheckState)

const focusSearchInput = async (): Promise<void> => {
Expand All @@ -56,7 +58,17 @@ const Tiptap = ({ onUpdate, content, isNoteInBin }: TiptapProps) => {

const editor = useEditor({
extensions: [
StarterKit.configure({ codeBlock: false }),
Doc,
StarterKit.configure({
codeBlock: false,
document: false,
dropcursor: {
color: 'skyblue',
width: 2
}
}),
DBlock,
NodeMover,
Placeholder.configure({
placeholder: "Type '/' for commands…"
}),
Expand Down Expand Up @@ -126,6 +138,17 @@ const Tiptap = ({ onUpdate, content, isNoteInBin }: TiptapProps) => {
})
}, [spellcheckRecoilState])

useEffect(() => {
editor?.setEditable(!isPreview)
}, [isPreview])

const [editorContentKey, setEditorContentKey] = useState(`${Math.random()}`)

const toggleIsPreview = () => {
setIsPreview(!isPreview)
setEditorContentKey(`${Math.random()}`)
}

return (
<>
{
Expand All @@ -134,11 +157,18 @@ const Tiptap = ({ onUpdate, content, isNoteInBin }: TiptapProps) => {
editor={editor}
isLocalSearchVisible={isLocalSearchVisible}
onSearchTooltipClose={() => setIsLocalSearchVisible(false)}
isPreview={isPreview}
toggleIsPreview={toggleIsPreview}
/>
)
}

<EditorContent className='editor-content' editor={editor} />
<EditorContent
key={editorContentKey}
className='editor-content'
editor={editor}
suppressContentEditableWarning
/>

<Text className='word-and-character-count-section flex'>
<span>
Expand Down
111 changes: 111 additions & 0 deletions src/components/editor/extensions/dBlock/DBlockNodeView.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/* eslint-disable jsx-a11y/no-static-element-interactions */

import { Button, Tooltip, styled } from '@nextui-org/react';
import { NodeViewContent, NodeViewProps, NodeViewWrapper } from "@tiptap/react";
import React, { useMemo } from "react";
import { BiPlus } from 'react-icons/bi';
import { MdClose, MdDragIndicator } from 'react-icons/md';
import { RiArrowDownLine, RiArrowUpLine } from 'react-icons/ri';

import './DBlockStyle.scss'

const LeftSection = styled('section', {
display: 'flex',
gap: '4px',
alignItems: 'center'
})

const MoveButtonsContainer = styled('div', {
display: 'flex',
justifyContent: 'space-between'
})

export const DBlockNodeView: React.FC<NodeViewProps> = ({
node,
getPos,
editor,
deleteNode
}) => {
const isTable = useMemo(() => {
const { content } = node.content as any;

return content[0].type.name === "table";
}, [node.content]);

const createNodeAfter = () => {
const pos = getPos() + node.nodeSize;

editor
.chain()
.insertContentAt(pos, {
type: "dBlock",
content: [
{
type: "paragraph",
},
],
})
.focus(pos + 2)
.run();
};

const onDeleteClicked = () => {
deleteNode()

setTimeout(() => editor.commands.focus())
}

const moveNode = (dir: 'up' | 'down') => {
const { from, to } = editor.state.selection
const [nodeFrom, nodeTo] = [getPos(), getPos() + node.nodeSize]

if (!(nodeFrom <= from && to <= nodeTo)) editor.commands.focus(getPos() + 2)

setTimeout(() => editor.chain().moveNode(dir).focus().run())
}

return (
<NodeViewWrapper as="div" className="dBlockWrapper flex">
{
editor.isEditable && (
<LeftSection
aria-label="left-menu"
contentEditable="false"
>
<button
className="d-block-button"
onClick={createNodeAfter}
>
<BiPlus />
</button>
<Tooltip
content={(
<MoveButtonsContainer>
<Button.Group size='sm' css={{ padding: 0, margin: 0 }} flat>
<Button auto size={'sm'} icon={<RiArrowUpLine />} onPress={() => moveNode('up')} />
<Button auto size={'sm'} icon={<MdClose />} onPress={onDeleteClicked} />
<Button auto size={'sm'} icon={<RiArrowDownLine />} onPress={() => moveNode('down')} />
</Button.Group>
</MoveButtonsContainer>
)}
trigger={'click'}
hideArrow
placement='bottom'
>
<div
className="d-block-button drag-handle"
contentEditable={false}
draggable
data-drag-handle
>
<MdDragIndicator />
</div>
</Tooltip>
</LeftSection>
)
}

<NodeViewContent className={`content w-full ${isTable ? "is-table" : ""}`} />
</NodeViewWrapper>
);
};
47 changes: 47 additions & 0 deletions src/components/editor/extensions/dBlock/DBlockStyle.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
.dBlockWrapper {
gap: 8px;
width: 100%;
position: relative;

&:hover {
.d-block-button {
opacity: 1;
transition: none;
}
}

.d-block-button {
opacity: 0;
display: flex;
justify-content: center;
align-items: center;
background: none;
border: none !important;
height: 28px;
padding: 2px;
cursor: pointer;
border-radius: 4px;
transition: all 0.25s ease-in-out;

&:hover {
background: var(--nextui-colors-selection);
}

&.drag-handle {
cursor: grab;

&:hover:active {
cursor: grabbing;
}
}
}

.content {
width: 100%;
min-width: 4px;

&.is-table {
margin-left: 2rem;
}
}
}
Loading

0 comments on commit fc53873

Please sign in to comment.