From f4d6b76d5ab6e47bfc9430828a8121a2b337d6d2 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 13 Nov 2021 05:13:49 +0000 Subject: [PATCH 01/17] First run on the editor Implemented: Annotationcreate, annotation edit, keyboard shortcuts, markdown, autolinking What's missing: clear on save, styling of the editor and markdown translation --- package.json | 12 +- .../components/AnnotationCreate.tsx | 71 ++- src/annotations/components/AnnotationEdit.tsx | 66 ++- .../components/AnnotationEditable.tsx | 5 +- src/annotations/components/editor/editor.tsx | 60 +++ src/annotations/components/editor/styles.css | 53 +++ .../markdown-preview-insert-menu.tsx | 1 + tsconfig.jest.json | 3 +- yarn.lock | 435 ++++++++++++++++++ 9 files changed, 623 insertions(+), 83 deletions(-) create mode 100644 src/annotations/components/editor/editor.tsx create mode 100644 src/annotations/components/editor/styles.css diff --git a/package.json b/package.json index 691ab1a812..dae2ea3b00 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,13 @@ "@josephg/resolvable": "^1.0.0", "@styled-icons/feather": "^10.0.0", "@styled-icons/styled-icon": "^10.0.0", + "@tiptap/extension-bubble-menu": "^2.0.0-beta.49", + "@tiptap/extension-highlight": "^2.0.0-beta.30", + "@tiptap/extension-link": "^2.0.0-beta.28", + "@tiptap/extension-placeholder": "^2.0.0-beta.43", + "@tiptap/extension-typography": "^2.0.0-beta.19", + "@tiptap/react": "^2.0.0-beta.93", + "@tiptap/starter-kit": "^2.0.0-beta.140", "@types/socket.io-client": "^1.4.32", "@types/ua-parser-js": "^0.7.36", "approx-string-match": "^1.1.0", @@ -76,7 +83,9 @@ "immutability-helper": "^3.0.1", "jsdom": "^16.2.2", "json-date-parser": "^1.0.1", + "json2md": "^1.12.0", "lodash": "^4.17.4", + "marked": "^4.0.2", "moment": "^2.18.1", "moment-timezone": "^0.5.14", "mousetrap": "^1.6.5", @@ -85,7 +94,7 @@ "object-path": "^0.11.4", "openpgp": "^4.6.2", "page-metadata-parser": "^1.1.4", - "pdfjs-dist": "WorldBrain/pdfjs-dist#fix\/unsafe-eval", + "pdfjs-dist": "WorldBrain/pdfjs-dist#fix/unsafe-eval", "polished": "^4.0.3", "postcss-modules-values": "^2.0.0", "promise-limit": "^2.5.0", @@ -129,6 +138,7 @@ "styled-props": "^1.1.2", "through2": "^2.0.3", "traverse": "^0.6.6", + "turndown": "^7.1.1", "tweetnacl": "^1.0.1", "tweetnacl-async": "^2.0.0", "tweetnacl-util": "^0.15.0", diff --git a/src/annotations/components/AnnotationCreate.tsx b/src/annotations/components/AnnotationCreate.tsx index 5815a708f2..c342b1ffc8 100644 --- a/src/annotations/components/AnnotationCreate.tsx +++ b/src/annotations/components/AnnotationCreate.tsx @@ -12,11 +12,17 @@ import { HoverBox } from 'src/common-ui/components/design-library/HoverBox' import { ClickAway } from 'src/util/click-away-wrapper' import TagPicker, { TagPickerDependencies } from 'src/tags/ui/TagPicker' import SaveBtn from './save-btn' +import TipTap from './editor/editor' interface State { isTagPickerShown: boolean + contentToSave: string } +var TurndownService = require('turndown') + +var turndownService = new TurndownService() + export interface AnnotationCreateEventProps { onSave: (shouldShare: boolean, isProtected?: boolean) => Promise onCancel: () => void @@ -45,13 +51,14 @@ export class AnnotationCreate extends React.Component implements FocusableComponent { static ALT_KEY = getKeyName({ key: 'alt' }) static MOD_KEY = getKeyName({ key: 'mod' }) - private textAreaRef = React.createRef() - private markdownPreviewRef = React.createRef< - MarkdownPreviewAnnotationInsertMenu - >() + //private textAreaRef = React.createRef() + // private markdownPreviewRef = React.createRef< + // MarkdownPreviewAnnotationInsertMenu + // >() state: State = { isTagPickerShown: false, + contentToSave: null, } componentDidMount() { @@ -62,8 +69,8 @@ export class AnnotationCreate extends React.Component focus() { const inputLen = this.props.comment.length - this.textAreaRef.current.focus() - this.textAreaRef.current.setSelectionRange(inputLen, inputLen) + // this.textAreaRef.current.focus() + // this.textAreaRef.current.setSelectionRange(inputLen, inputLen) } handleClickOutside() { @@ -79,14 +86,6 @@ export class AnnotationCreate extends React.Component isProtected?: boolean, ) => { const saveP = this.props.onSave(shouldShare, isProtected) - - if ( - this.markdownPreviewRef?.current?.markdownPreviewRef.current?.state - .showPreview - ) { - this.markdownPreviewRef.current.markdownPreviewRef.current.togglePreview() - } - await saveP } @@ -119,15 +118,15 @@ export class AnnotationCreate extends React.Component return this.handleSave(false, false) } - if (e.key === 'Tab' && !e.shiftKey) { - e.preventDefault() - insertTab({ el: this.textAreaRef.current }) - } + // if (e.key === 'Tab' && !e.shiftKey) { + // e.preventDefault() + // insertTab({ el: this.textAreaRef.current }) + // } - if (e.key === 'Tab' && e.shiftKey) { - e.preventDefault() - uninsertTab({ el: this.textAreaRef.current }) - } + // if (e.key === 'Tab' && e.shiftKey) { + // e.preventDefault() + // uninsertTab({ el: this.textAreaRef.current }) + // } } private renderTagPicker() { @@ -181,26 +180,19 @@ export class AnnotationCreate extends React.Component ) } + private printContent(content) { + var content = turndownService.turndown(content) + this.setState({ contentToSave: content }) + this.props.onCommentChange(this.state.contentToSave) + } + render() { return ( - ( - - this.props.onCommentChange(e.target.value) - } - /> - )} + this.printContent(content)} + onKeyDown={(e) => this.handleInputKeyDown(e)} + placeholder={`

Add private note. Save with ${AnnotationCreate.MOD_KEY}+enter (+shift to share)

`} /> {this.props.comment !== '' && ( <> @@ -223,6 +215,7 @@ const TextBoxContainerStyled = styled.div` flex-direction: column; font-size: 14px; width: 100%; + padding: 0 10px; box-shadow: rgb(0 0 0 / 10%) 0px 1px 2px 0px; border-radius: 5px; background-color: ${(props) => (props.comment !== '' ? 'white' : 'none')}; diff --git a/src/annotations/components/AnnotationEdit.tsx b/src/annotations/components/AnnotationEdit.tsx index e63eee8224..e1328f52e2 100644 --- a/src/annotations/components/AnnotationEdit.tsx +++ b/src/annotations/components/AnnotationEdit.tsx @@ -5,6 +5,16 @@ import { MarkdownPreviewAnnotationInsertMenu } from 'src/markdown-preview/markdo import { FocusableComponent } from './types' import { uninsertTab, insertTab } from 'src/common-ui/utils' import { getKeyName } from 'src/util/os-specific-key-names' +import TipTap from './editor/editor' +const { marked } = require('marked') + +interface State { + contentToSave: string +} + +var TurndownService = require('turndown') + +var turndownService = new TurndownService() export interface AnnotationEditEventProps { onEditConfirm: (shouldShare: boolean, isProtected?: boolean) => void @@ -23,23 +33,11 @@ export interface Props rows: number } -class AnnotationEdit extends React.Component - implements FocusableComponent { +class AnnotationEdit extends React.Component { static MOD_KEY = getKeyName({ key: 'mod' }) - private textAreaRef = React.createRef() - - componentDidMount() { - this.focusOnInputEnd() - } - focus() { - this.textAreaRef.current.focus() - } - - focusOnInputEnd() { - const inputLen = this.props.comment.length - this.textAreaRef.current.setSelectionRange(inputLen, inputLen) - this.focus() + state: State = { + contentToSave: '', } private handleInputKeyDown: React.KeyboardEventHandler = (e) => { @@ -65,37 +63,27 @@ class AnnotationEdit extends React.Component this.props.onEditCancel() return } + } - if (e.key === 'Tab' && !e.shiftKey) { - e.preventDefault() - insertTab({ el: this.textAreaRef.current }) - } + private printContent(content) { + var content = turndownService.turndown(content) + this.setState({ contentToSave: content }) + this.props.onCommentChange(this.state.contentToSave) + } - if (e.key === 'Tab' && e.shiftKey) { - e.preventDefault() - uninsertTab({ el: this.textAreaRef.current }) - } + private parseMD2HTML() { + const html = marked.parse(this.props.comment) + // TODO const sanitisedHTML = + return html } render() { return ( <> - ( - - this.props.onCommentChange(e.target.value) - } - /> - )} + this.printContent(content)} + onKeyDown={(e) => this.handleInputKeyDown(e)} + comment={this.parseMD2HTML()} /> ) diff --git a/src/annotations/components/AnnotationEditable.tsx b/src/annotations/components/AnnotationEditable.tsx index 1756cdd827..861f8cb46e 100644 --- a/src/annotations/components/AnnotationEditable.tsx +++ b/src/annotations/components/AnnotationEditable.tsx @@ -85,9 +85,7 @@ export default class AnnotationEditable extends React.Component { hoverState: null, } - focus() { - this.annotEditRef?.current?.focusOnInputEnd() - } + focus() {} private get creationInfo() { // TODO: Figure out why these dates are so unpredictable and fix it @@ -198,6 +196,7 @@ export default class AnnotationEditable extends React.Component { ref={this.annotEditRef} {...annotationEditDependencies} rows={2} + comment={comment} /> ) } diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx new file mode 100644 index 0000000000..85bb78b07e --- /dev/null +++ b/src/annotations/components/editor/editor.tsx @@ -0,0 +1,60 @@ +import React from 'react' +import { useEditor, EditorContent, BubbleMenu } from '@tiptap/react' +import StarterKit from '@tiptap/starter-kit' +import Highlight from '@tiptap/extension-highlight' +import Typography from '@tiptap/extension-typography' +import Placeholder from '@tiptap/extension-placeholder' +import Link from '@tiptap/extension-link' +import './styles.css' +import styled from 'styled-components' + +interface Props { + updatedContent: (content) => void + onKeyDown: (event) => void + comment?: string + placeholder?: string + clearField?: boolean +} + +export default (props) => { + const editor = useEditor({ + extensions: [ + StarterKit, + Highlight, + Typography, + Link.configure({ + linkOnPaste: true, + }), + Placeholder.configure({ + placeholder: props.placeholder, + emptyEditorClass: 'is-editor-empty', + }), + ], + content: props.comment, + onUpdate: ({ editor }) => { + const content = editor.getHTML() + props.updatedContent(content) + }, + autofocus: true, + editorProps: { + handleDOMEvents: { + keydown: (view, event) => { + return props.onKeyDown(event) + }, + }, + attributes: { + class: + 'prose prose-sm sm:prose lg:prose-lg xl:prose-2xl mx-auto focus:outline-none', + }, + }, + }) + + // TODO: clear the content when the note is saved + //editor.commands.clearContent() + + return ( + <> + + + ) +} diff --git a/src/annotations/components/editor/styles.css b/src/annotations/components/editor/styles.css new file mode 100644 index 0000000000..158297f809 --- /dev/null +++ b/src/annotations/components/editor/styles.css @@ -0,0 +1,53 @@ +.ProseMirror { + > * + * { + margin-top: 0.75em; + } + + ul, + ol { + padding: 0 1rem; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + line-height: 1.1; + } + + code { + background-color: rgba(#616161, 0.1); + color: #616161; + } + + pre { + background: #0d0d0d; + color: #fff; + font-family: 'JetBrainsMono', monospace; + padding: 0.75rem 1rem; + border-radius: 0.5rem; + + code { + color: inherit; + padding: 0; + background: none; + font-size: 0.8rem; + } + } + + img { + max-width: 100%; + height: auto; + } + + hr { + margin: 1rem 0; + } + + blockquote { + padding-left: 1rem; + border-left: 2px solid rgba(#0d0d0d, 0.1); + } +} diff --git a/src/markdown-preview/markdown-preview-insert-menu.tsx b/src/markdown-preview/markdown-preview-insert-menu.tsx index 4da229ee77..b8d200d498 100644 --- a/src/markdown-preview/markdown-preview-insert-menu.tsx +++ b/src/markdown-preview/markdown-preview-insert-menu.tsx @@ -13,6 +13,7 @@ import { annotationMenuItems } from './insert-menu-entries' export interface Props extends MarkdownPreviewProps { menuItems?: MenuItemProps[] updateInputValue: (value: string) => void + onKeyDown: () => void } export class MarkdownPreviewAnnotationInsertMenu extends React.PureComponent< diff --git a/tsconfig.jest.json b/tsconfig.jest.json index ea41fe93d3..ccaba2d9ce 100644 --- a/tsconfig.jest.json +++ b/tsconfig.jest.json @@ -4,6 +4,7 @@ "target": "ES6", "module": "commonjs", "sourceMap": false, - "inlineSourceMap": true + "inlineSourceMap": true, + "jsx": "react-jsx" } } diff --git a/yarn.lock b/yarn.lock index 811574edd5..4b8c4df4a6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3176,6 +3176,11 @@ resolved "https://registry.yarnpkg.com/@opentelemetry/semantic-conventions/-/semantic-conventions-0.18.2.tgz#a0f15d2ef752567713c1f59f69c6742edb03030c" integrity sha512-+0P+PrP9qSFVaayNdek4P1OAGE+PEl2SsufuHDRmUpOY25Wzjo7Atyar56Trjc32jkNy4lID6ZFT6BahsR9P9A== +"@popperjs/core@^2.9.0": + version "2.10.2" + resolved "https://registry.yarnpkg.com/@popperjs/core/-/core-2.10.2.tgz#0798c03351f0dea1a5a4cabddf26a55a7cbee590" + integrity sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ== + "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": version "1.1.2" resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" @@ -3967,6 +3972,208 @@ "@testing-library/dom" "^6.15.0" "@types/testing-library__react" "^9.1.2" +"@tiptap/core@^2.0.0-beta.138": + version "2.0.0-beta.138" + resolved "https://registry.yarnpkg.com/@tiptap/core/-/core-2.0.0-beta.138.tgz#3a73b32b10f07ba2842142552457b52abf8cfc41" + integrity sha512-Cg3ig6c+NCBILYaVNf5h8vJdsRynhKzy+zQzH/91kLoWzpNV5J6R2sW32Oufuwvr0Kra1+kKKh/WIGpB3Ia4RA== + dependencies: + "@types/prosemirror-commands" "^1.0.4" + "@types/prosemirror-keymap" "^1.0.4" + "@types/prosemirror-model" "^1.13.2" + "@types/prosemirror-schema-list" "^1.0.3" + "@types/prosemirror-state" "^1.2.8" + "@types/prosemirror-transform" "^1.1.4" + "@types/prosemirror-view" "^1.19.1" + prosemirror-commands "^1.1.12" + prosemirror-keymap "^1.1.5" + prosemirror-model "^1.15.0" + prosemirror-schema-list "^1.1.6" + prosemirror-state "^1.3.4" + prosemirror-transform "^1.3.3" + prosemirror-view "^1.22.0" + +"@tiptap/extension-blockquote@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-blockquote/-/extension-blockquote-2.0.0-beta.24.tgz#4dcaf676ded8c3b551efd8f2d6b51cc882ba7d03" + integrity sha512-u9D/ZOziO4rMBKeLj7JA7fOc9h8wU6zrzVEsX9MbJwmuicoJZ1lIQ9cyrFWwmlfznzuXLaAxm3iZuHt7xxMppQ== + +"@tiptap/extension-bold@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bold/-/extension-bold-2.0.0-beta.24.tgz#a8d1076922580db528cc6988fde08f731dcfe733" + integrity sha512-2VTCtY2JI0wpDwWT0a2fMFkjbgxDpwD3wvtY3/ndh5pyNX0JQCXtJarFzfZZurWvLNQ8QPRRel73182RBYUOHQ== + +"@tiptap/extension-bubble-menu@^2.0.0-beta.49": + version "2.0.0-beta.49" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bubble-menu/-/extension-bubble-menu-2.0.0-beta.49.tgz#f9863b1abad5f87d298d4e6527005484137a6166" + integrity sha512-JbaSG3otBuMKRyTn0OqVscZnwqJ7c+qyKAnoZJit5EK1RS72cTfGWZvvAxaslAM4DeE9avJeudUi/tN5Iafv4A== + dependencies: + prosemirror-state "^1.3.4" + prosemirror-view "^1.22.0" + tippy.js "^6.3.6" + +"@tiptap/extension-bullet-list@^2.0.0-beta.23": + version "2.0.0-beta.23" + resolved "https://registry.yarnpkg.com/@tiptap/extension-bullet-list/-/extension-bullet-list-2.0.0-beta.23.tgz#64698c98039ad301c94a9041bbd117e82957be21" + integrity sha512-ReoUiz9f1IX87RX+GRE+fCaLEzNNwmiP4kli3QH8/qrLK3qxvZYr9N31fUeOHecCctUofPSbQB79B39zSo9Ouw== + +"@tiptap/extension-code-block@^2.0.0-beta.29": + version "2.0.0-beta.29" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code-block/-/extension-code-block-2.0.0-beta.29.tgz#ad7f537bc1f12decf027d66c7328f36a8b07795c" + integrity sha512-IoBJxqZ4F7dApRL3NisvMCBJmzpV0LmfJlFQacgm64Li15dP/QyDuvXpku03gT3y9e4f9Gv/KTKwJizXEVABhw== + dependencies: + prosemirror-state "^1.3.4" + +"@tiptap/extension-code@^2.0.0-beta.25": + version "2.0.0-beta.25" + resolved "https://registry.yarnpkg.com/@tiptap/extension-code/-/extension-code-2.0.0-beta.25.tgz#055dc8dc6d19d3f0439f57dd8ba6433e2f2fd733" + integrity sha512-kXBR4Zp79lpUEfqJtBGv9tO1mj9jFQLMj0iVhj8e8ZporNKei5JfDOY83kwFcKAE60i7tiRDtV3OizpAKMeqDg== + +"@tiptap/extension-document@^2.0.0-beta.15": + version "2.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@tiptap/extension-document/-/extension-document-2.0.0-beta.15.tgz#5d17a0289244a913ab2ef08e8495a1e46950711e" + integrity sha512-ypENC+xUYD5m2t+KOKNYqyXnanXd5fxyIyhR1qeEEwwQwMXGNrO3kCH6O4mIDCpy+/WqHvVay2tV5dVsXnvY8w== + +"@tiptap/extension-dropcursor@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-dropcursor/-/extension-dropcursor-2.0.0-beta.24.tgz#e0263c8d784304cb885aea299bfd5255d3435765" + integrity sha512-B4bzY84g82VY78kv6BFNSCgO9Sc3dtgkvzFDJ57X2QweYyLkXbYeZxI8SqO7Nva1QRZadBlFyRPm+aP1rLZsew== + dependencies: + "@types/prosemirror-dropcursor" "^1.0.3" + prosemirror-dropcursor "^1.3.5" + +"@tiptap/extension-floating-menu@^2.0.0-beta.44": + version "2.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@tiptap/extension-floating-menu/-/extension-floating-menu-2.0.0-beta.44.tgz#fca9eefd9bcc74fdf035b012b9eb9fbfda331cf1" + integrity sha512-R8EF6XXlwoiHvCuXV3qGsEKae5u0OYrKHJNeOgau5SANg/ab+pjFzr3Lrt43NFpOKf5rzD3p2OJxnikudceLSg== + dependencies: + prosemirror-state "^1.3.4" + prosemirror-view "^1.22.0" + tippy.js "^6.3.6" + +"@tiptap/extension-gapcursor@^2.0.0-beta.33": + version "2.0.0-beta.33" + resolved "https://registry.yarnpkg.com/@tiptap/extension-gapcursor/-/extension-gapcursor-2.0.0-beta.33.tgz#99414204e61655d4df61efc27823732176719532" + integrity sha512-Yu6BJ1bseyXIgLlcw/2R/2wWe1mIQilMwW7hhfDJPLbFwLJrMINtA9hxd2qY7mtW19/CveT5HOihQS6QEk59iw== + dependencies: + "@types/prosemirror-gapcursor" "^1.0.4" + prosemirror-gapcursor "^1.2.0" + +"@tiptap/extension-hard-break@^2.0.0-beta.30": + version "2.0.0-beta.30" + resolved "https://registry.yarnpkg.com/@tiptap/extension-hard-break/-/extension-hard-break-2.0.0-beta.30.tgz#165494f1194a7bad08907e6d64d349dd15851b72" + integrity sha512-X9xj/S+CikrbIE7ccUFVwit5QHEbflnKVxod+4zPwr1cxogFbE9AyLZE2MpYdx3z9LcnTYYi9leBqFrP4T/Olw== + +"@tiptap/extension-heading@^2.0.0-beta.23": + version "2.0.0-beta.23" + resolved "https://registry.yarnpkg.com/@tiptap/extension-heading/-/extension-heading-2.0.0-beta.23.tgz#8aafadc58a8d536b7f7885e4ff0f64d30908a868" + integrity sha512-/WLymJjY+MMvee79rWHSKDBGVRw4dbBUMrFLqKLjQQBS1xS8+UW2TYzRrAH6HAH4Tc6WO39ZDbd9K9kc9wqPnA== + +"@tiptap/extension-highlight@^2.0.0-beta.30": + version "2.0.0-beta.30" + resolved "https://registry.yarnpkg.com/@tiptap/extension-highlight/-/extension-highlight-2.0.0-beta.30.tgz#7a245214021356220839f852b4d28dabbd1f029e" + integrity sha512-68hMjVDUmj0UhTtq2Kp6BiTb9JPhpjT+HXHMch5SkZaoiLVfTleMF1jECU1HsDGs/hnktkCshUQN6BLJqo+4pg== + +"@tiptap/extension-history@^2.0.0-beta.21": + version "2.0.0-beta.21" + resolved "https://registry.yarnpkg.com/@tiptap/extension-history/-/extension-history-2.0.0-beta.21.tgz#5d96a17a83a7130744f0757a3275dd5b11eb1bf7" + integrity sha512-0v8Cl30V4dsabdpspLdk+f+lMoIvLFlJN5WRxtc7RRZ5gfJVxPHwooIKdvC51brfh/oJtWFCNMRjhoz0fRaF9A== + dependencies: + "@types/prosemirror-history" "^1.0.3" + prosemirror-history "^1.2.0" + +"@tiptap/extension-horizontal-rule@^2.0.0-beta.30": + version "2.0.0-beta.30" + resolved "https://registry.yarnpkg.com/@tiptap/extension-horizontal-rule/-/extension-horizontal-rule-2.0.0-beta.30.tgz#56d497f1187384d131f3f3320f30748c1e4b766f" + integrity sha512-h/PlkvfcMuoBGRfD7Cbeh8mxZiEc2pKveLDwOfCES9TKV5i2lqcIgctpohWyISuFcTq4K+OFgr910+Rsp8qwEg== + dependencies: + prosemirror-state "^1.3.4" + +"@tiptap/extension-italic@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.24.tgz#0a08d06dbd8dbf10f18ed17f019aa42d7ac9dbe0" + integrity sha512-pMAWFaLFb0Z0SC5pjoTKzC6m4CQOdUYeVlHvTS/550Z9lf8cqMawQ8H6Yk6brIuANyh7iUi4/zpq4H4rAdUCuw== + +"@tiptap/extension-link@^2.0.0-beta.28": + version "2.0.0-beta.28" + resolved "https://registry.yarnpkg.com/@tiptap/extension-link/-/extension-link-2.0.0-beta.28.tgz#4385f36b6bb31fab34a86fb7c686ca05a37ed572" + integrity sha512-dZNaEjoDhgjmts44KqgtOYObCdDYZq/yFhsZ8QfqEgNHJMvBNTDaPXwBDW9i3BTkkyLTmwR/qwWxqDrfDdKh2A== + dependencies: + linkifyjs "^3.0.3" + prosemirror-state "^1.3.4" + +"@tiptap/extension-list-item@^2.0.0-beta.19": + version "2.0.0-beta.19" + resolved "https://registry.yarnpkg.com/@tiptap/extension-list-item/-/extension-list-item-2.0.0-beta.19.tgz#657f2c5624a30f3effff723f4fadb0851a61dab8" + integrity sha512-z/5NrRKwwJc2ZkgoGxRQmA/VENxQugZoxKhUu2qoUdg5cJRcW+ERoKTiY1/AR+4M2k1izNWQMIz3nQNWMx1kQA== + +"@tiptap/extension-ordered-list@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-ordered-list/-/extension-ordered-list-2.0.0-beta.24.tgz#69c56e2cfbf582b338d5dbc94c5eda4593775cb5" + integrity sha512-pXgwV+vuBAHMBGnUPa8fjxHapGCitfBJ1k8o3XvhotO7243Y7KOfYT7kg6XrY6dmTwCX2WLkIc912PP/E60y3A== + +"@tiptap/extension-paragraph@^2.0.0-beta.22": + version "2.0.0-beta.22" + resolved "https://registry.yarnpkg.com/@tiptap/extension-paragraph/-/extension-paragraph-2.0.0-beta.22.tgz#7740fb6393296ec58e98332b2855ebdc3fd05226" + integrity sha512-BY6GWHlMvGiXLgPHcfZRUHKzMi1jKw3i1JrpMEQ8JLwYD3koI/6UOB/qphwUJkCkIPQXNkZw4/aSBxL9uChRDg== + +"@tiptap/extension-placeholder@^2.0.0-beta.43": + version "2.0.0-beta.43" + resolved "https://registry.yarnpkg.com/@tiptap/extension-placeholder/-/extension-placeholder-2.0.0-beta.43.tgz#8ea1dff868a9389950b31112a12ff7b869ffe531" + integrity sha512-EhZgkFClmHap8Bt9ChhAHGbTF+xvR0ZE/Y+xN8wEK73PUEHYYh8QBpAy1hTrgM+gQoO4AEIGNeT/7VvL2Ge7FQ== + dependencies: + prosemirror-model "^1.15.0" + prosemirror-state "^1.3.4" + prosemirror-view "^1.22.0" + +"@tiptap/extension-strike@^2.0.0-beta.26": + version "2.0.0-beta.26" + resolved "https://registry.yarnpkg.com/@tiptap/extension-strike/-/extension-strike-2.0.0-beta.26.tgz#19eda1a61706ac9690ecbc794c711deb4e1efc3e" + integrity sha512-BA+oqqYOZzRLiMYlHX6BJXlIGaNIR9LObgkHEXAj/JPK7do4wDOcuVaw+dlWS+tzvTebLbC9GYAALfNqVBlTwA== + +"@tiptap/extension-text@^2.0.0-beta.15": + version "2.0.0-beta.15" + resolved "https://registry.yarnpkg.com/@tiptap/extension-text/-/extension-text-2.0.0-beta.15.tgz#f08cff1b78f1c6996464dfba1fef8ec1e107617f" + integrity sha512-S3j2+HyV2gsXZP8Wg/HA+YVXQsZ3nrXgBM9HmGAxB0ESOO50l7LWfip0f3qcw1oRlh5H3iLPkA6/f7clD2/TFA== + +"@tiptap/extension-typography@^2.0.0-beta.19": + version "2.0.0-beta.19" + resolved "https://registry.yarnpkg.com/@tiptap/extension-typography/-/extension-typography-2.0.0-beta.19.tgz#3a3cf25590b7d84bcf40525d558ab5997c554b3d" + integrity sha512-9Y3or/X0IkHqfJg1eOqqMiPFgXKQKNOwDy+xN6qhORQSUzCPOCHttAUdp8AN/WUEQOoOK4uaRida8ik1ATK7ZQ== + +"@tiptap/react@^2.0.0-beta.93": + version "2.0.0-beta.93" + resolved "https://registry.yarnpkg.com/@tiptap/react/-/react-2.0.0-beta.93.tgz#353087e4254a996c906fd76fcdfc2af32ae68faa" + integrity sha512-kI3FV51IuP9njD3ZopGBaUhcQ0l+em36mK3HUM50fiFPOOyF5tCUtF6/AI+gw3ivUbBwLC13YfHEj1OnKkkjWQ== + dependencies: + "@tiptap/extension-bubble-menu" "^2.0.0-beta.49" + "@tiptap/extension-floating-menu" "^2.0.0-beta.44" + prosemirror-view "^1.22.0" + +"@tiptap/starter-kit@^2.0.0-beta.140": + version "2.0.0-beta.140" + resolved "https://registry.yarnpkg.com/@tiptap/starter-kit/-/starter-kit-2.0.0-beta.140.tgz#4610a28084742f3512ea7cbb8e8f2b2428690013" + integrity sha512-19E5duT0rRcp2SHZK0OYiIEjnYLn+Lf1GBBnsTFRoze8mHP2Zym11HmcpW6iyuaWj9mPFjlXJJr6yTc0HmpPpA== + dependencies: + "@tiptap/core" "^2.0.0-beta.138" + "@tiptap/extension-blockquote" "^2.0.0-beta.24" + "@tiptap/extension-bold" "^2.0.0-beta.24" + "@tiptap/extension-bullet-list" "^2.0.0-beta.23" + "@tiptap/extension-code" "^2.0.0-beta.25" + "@tiptap/extension-code-block" "^2.0.0-beta.29" + "@tiptap/extension-document" "^2.0.0-beta.15" + "@tiptap/extension-dropcursor" "^2.0.0-beta.24" + "@tiptap/extension-gapcursor" "^2.0.0-beta.33" + "@tiptap/extension-hard-break" "^2.0.0-beta.30" + "@tiptap/extension-heading" "^2.0.0-beta.23" + "@tiptap/extension-history" "^2.0.0-beta.21" + "@tiptap/extension-horizontal-rule" "^2.0.0-beta.30" + "@tiptap/extension-italic" "^2.0.0-beta.24" + "@tiptap/extension-list-item" "^2.0.0-beta.19" + "@tiptap/extension-ordered-list" "^2.0.0-beta.24" + "@tiptap/extension-paragraph" "^2.0.0-beta.22" + "@tiptap/extension-strike" "^2.0.0-beta.26" + "@tiptap/extension-text" "^2.0.0-beta.15" + "@tootallnate/once@1": version "1.1.2" resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" @@ -4207,6 +4414,11 @@ dependencies: "@types/bn.js" "*" +"@types/orderedmap@*": + version "1.0.0" + resolved "https://registry.yarnpkg.com/@types/orderedmap/-/orderedmap-1.0.0.tgz#807455a192bba52cbbb4517044bc82bdbfa8c596" + integrity sha512-dxKo80TqYx3YtBipHwA/SdFmMMyLCnP+5mkEqN0eMjcTBzHkiiX0ES118DsjDBjvD+zeSsSU9jULTZ+frog+Gw== + "@types/pdfjs-dist@^2.1.6": version "2.1.7" resolved "https://registry.yarnpkg.com/@types/pdfjs-dist/-/pdfjs-dist-2.1.7.tgz#a92d94b9d699a93ab8a762839f7819dc04e96484" @@ -4223,6 +4435,89 @@ dependencies: "@types/react" "*" +"@types/prosemirror-commands@*", "@types/prosemirror-commands@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-commands/-/prosemirror-commands-1.0.4.tgz#d08551415127d93ae62e7239d30db0b5e7208e22" + integrity sha512-utDNYB3EXLjAfYIcRWJe6pn3kcQ5kG4RijbT/0Y/TFOm6yhvYS/D9eJVnijdg9LDjykapcezchxGRqFD5LcyaQ== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + "@types/prosemirror-view" "*" + +"@types/prosemirror-dropcursor@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/prosemirror-dropcursor/-/prosemirror-dropcursor-1.0.3.tgz#49250849b8a0b86e8c29eb1ba70a463e53e46947" + integrity sha512-b0/8njnJ4lwyHKcGuCMf3x7r1KjxyugB1R/c2iMCjplsJHSC7UY9+OysqgJR5uUXRekUSGniiLgBtac/lvH6wg== + dependencies: + "@types/prosemirror-state" "*" + +"@types/prosemirror-gapcursor@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-gapcursor/-/prosemirror-gapcursor-1.0.4.tgz#7df7d373edb33ea8da12084bfd462cf84cd69761" + integrity sha512-9xKjFIG5947dzerFvkLWp6F53JwrUYoYwh3SgcTFEp8SbSfNNrez/PFYVZKPnoqPoaK5WtTdQTaMwpCV9rXQIg== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + +"@types/prosemirror-history@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/prosemirror-history/-/prosemirror-history-1.0.3.tgz#f1110efbe758129b5475e466ff077f0a8d9b964f" + integrity sha512-5TloMDRavgLjOAKXp1Li8u0xcsspzbT1Cm9F2pwHOkgvQOz1jWQb2VIXO7RVNsFjLBZdIXlyfSLivro3DuMWXg== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + +"@types/prosemirror-keymap@^1.0.4": + version "1.0.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-keymap/-/prosemirror-keymap-1.0.4.tgz#f73c79810e8d0e0a20d153d84f998f02e5afbc0c" + integrity sha512-ycevwkqUh+jEQtPwqO7sWGcm+Sybmhu8MpBsM8DlO3+YTKnXbKA6SDz/+q14q1wK3UA8lHJyfR+v+GPxfUSemg== + dependencies: + "@types/prosemirror-commands" "*" + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + "@types/prosemirror-view" "*" + +"@types/prosemirror-model@*", "@types/prosemirror-model@^1.13.2": + version "1.13.2" + resolved "https://registry.yarnpkg.com/@types/prosemirror-model/-/prosemirror-model-1.13.2.tgz#2adad3ec478f83204f155d7fb94c9dfde2fc3296" + integrity sha512-a2rDB0aZ+7aIP7uBqQq1wLb4Hg4qqEvpkCqvhsgT/gG8IWC0peCAZfQ24sgTco0qSJLeDgIbtPeU6mgr869/kg== + dependencies: + "@types/orderedmap" "*" + +"@types/prosemirror-schema-list@^1.0.3": + version "1.0.3" + resolved "https://registry.yarnpkg.com/@types/prosemirror-schema-list/-/prosemirror-schema-list-1.0.3.tgz#bdf1893a7915fbdc5c49b3cac9368e96213d70de" + integrity sha512-uWybOf+M2Ea7rlbs0yLsS4YJYNGXYtn4N+w8HCw3Vvfl6wBAROzlMt0gV/D/VW/7J/LlAjwMezuGe8xi24HzXA== + dependencies: + "@types/orderedmap" "*" + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + +"@types/prosemirror-state@*", "@types/prosemirror-state@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@types/prosemirror-state/-/prosemirror-state-1.2.8.tgz#65080eeec52f63c50bf7034377f07773b4f6b2ac" + integrity sha512-mq9uyQWcpu8jeamO6Callrdvf/e1H/aRLR2kZWSpZrPHctEsxWHBbluD/wqVjXBRIOoMHLf6ZvOkrkmGLoCHVA== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-transform" "*" + "@types/prosemirror-view" "*" + +"@types/prosemirror-transform@*", "@types/prosemirror-transform@^1.1.4": + version "1.1.4" + resolved "https://registry.yarnpkg.com/@types/prosemirror-transform/-/prosemirror-transform-1.1.4.tgz#c3565e81b2ef3ce3254e6927d6f63eb8d7bb20d0" + integrity sha512-HP1PauvkqSgDquZut8HaLOTUDQ6jja/LAy4OA7tTS1XG7wqRnX3gLUyEj0mD6vFd4y8BPkNddNdOh/BeGHlUjg== + dependencies: + "@types/prosemirror-model" "*" + +"@types/prosemirror-view@*", "@types/prosemirror-view@^1.19.1": + version "1.19.1" + resolved "https://registry.yarnpkg.com/@types/prosemirror-view/-/prosemirror-view-1.19.1.tgz#f12309ef07dfb701d20c2e4d0292d42ba34a081b" + integrity sha512-fyQ4NVxAdfISWrE2qT8cpZdosXoH/1JuVYMBs9CdaXPbvi/8R2L2tkkcMRM314piKrO8nfYH5OBZKzP2Ax3jtA== + dependencies: + "@types/prosemirror-model" "*" + "@types/prosemirror-state" "*" + "@types/prosemirror-transform" "*" + "@types/q@^1.5.1": version "1.5.2" resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.2.tgz#690a1475b84f2a884fd07cd797c00f5f31356ea8" @@ -9264,6 +9559,11 @@ domhandler@^4.0.0, domhandler@^4.1.0, domhandler@^4.2.0: dependencies: domelementtype "^2.2.0" +domino@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/domino/-/domino-2.1.6.tgz#fe4ace4310526e5e7b9d12c7de01b7f485a57ffe" + integrity sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ== + dompurify@^2.0.11: version "2.0.11" resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.0.11.tgz#cd47935774230c5e478b183a572e726300b3891d" @@ -12547,6 +12847,11 @@ indent-string@^4.0.0: resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== +indento@^1.1.13: + version "1.1.13" + resolved "https://registry.yarnpkg.com/indento/-/indento-1.1.13.tgz#751331b327c04740eeb7be40c5606e6e255c9e36" + integrity sha512-YZWk3mreBEM7sBPddsiQnW9Z8SGg/gNpFfscJq00HCDS7pxcQWWWMSVKJU7YkTRyDu1Zv2s8zaK8gQWKmCXHlg== + index-of@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/index-of/-/index-of-0.2.0.tgz#38c1e2367ea55dffad3b6eb592ec1cc3090d7d65" @@ -14537,6 +14842,13 @@ json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" +json2md@^1.12.0: + version "1.12.0" + resolved "https://registry.yarnpkg.com/json2md/-/json2md-1.12.0.tgz#3ac0a2f8f5af140d6f29d91ab1107ca696305165" + integrity sha512-bpJpuqECzkndCa10aGPxeJNikmkDN7PAGXHvrBGTI4uey6QbTL5p0rkhk9lB3lKU4J7yGvkSmVBt8VhzUGu/fA== + dependencies: + indento "^1.1.13" + json3@^3.3.2: version "3.3.3" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81" @@ -14867,6 +15179,11 @@ lines-and-columns@^1.1.6: resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= +linkifyjs@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/linkifyjs/-/linkifyjs-3.0.3.tgz#51ea2160b4c60c2c87c27757a1e9eacd422c6076" + integrity sha512-ba5opS5wRHSbDC8VaiDdN14nPGm6LqyRsIPQZGG4qXV4scFdrPneT/uoZOaq9QAPBf6W9I9D/6tNSzWH//815Q== + listenercount@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937" @@ -15482,6 +15799,11 @@ marked@^0.7.0: resolved "https://registry.yarnpkg.com/marked/-/marked-0.7.0.tgz#b64201f051d271b1edc10a04d1ae9b74bb8e5c0e" integrity sha512-c+yYdCZJQrsRjTPhUx7VKkApw9bwDkNbHUKo1ovgcfDjb2kc8rLuRbIFyXL5WOEUwzSSKo3IXpph2K6DqB/KZg== +marked@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/marked/-/marked-4.0.2.tgz#934301f536612b4bf2a3e45201d15c14b1f923ae" + integrity sha512-ze2N3qbBW/Ejqjw9FcSrSgsYJJHj8lA4k+VY6cxtTmK0Lw5CJl93iqdRbd6OPoTKzY1qBEYfOWukS9FtStdBdQ== + material-colors@^1.2.1: version "1.2.6" resolved "https://registry.yarnpkg.com/material-colors/-/material-colors-1.2.6.tgz#6d1958871126992ceecc72f4bcc4d8f010865f46" @@ -16926,6 +17248,11 @@ ora@^3.4.0: strip-ansi "^5.2.0" wcwidth "^1.0.1" +orderedmap@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/orderedmap/-/orderedmap-1.1.1.tgz#c618e77611b3b21d0fe3edc92586265e0059c789" + integrity sha512-3Ux8um0zXbVacKUkcytc0u3HgC0b0bBLT+I60r2J/En72cI0nZffqrA7Xtf2Hqs27j1g82llR5Mhbd0Z1XW4AQ== + original@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f" @@ -18690,6 +19017,90 @@ property-information@^5.0.1: dependencies: xtend "^4.0.1" +prosemirror-commands@^1.1.12: + version "1.1.12" + resolved "https://registry.yarnpkg.com/prosemirror-commands/-/prosemirror-commands-1.1.12.tgz#5cb0fef4e5a0039e2fa19b42a5626af03d7c2ec3" + integrity sha512-+CrMs3w/ZVPSkR+REg8KL/clyFLv/1+SgY/OMN+CB22Z24j9TZDje72vL36lOZ/E4NeRXuiCcmENcW/vAcG67A== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-dropcursor@^1.3.5: + version "1.4.0" + resolved "https://registry.yarnpkg.com/prosemirror-dropcursor/-/prosemirror-dropcursor-1.4.0.tgz#91a859d4ee79c99b1c0ba6ee61c093b195c0d9f0" + integrity sha512-6+YwTjmqDwlA/Dm+5wK67ezgqgjA/MhSDgaNxKUzH97SmeuWFXyLeDRxxOPZeSo7yTxcDGUCWTEjmQZsVBuMrQ== + dependencies: + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + prosemirror-view "^1.1.0" + +prosemirror-gapcursor@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/prosemirror-gapcursor/-/prosemirror-gapcursor-1.2.0.tgz#28fb60bf3d9baf1f920907d2c3e613137204e8f3" + integrity sha512-yCLy5+0rVqLir/KcHFathQj4Rf8aRHi80FmEfKtM0JmyzvwdomslLzDZ/pX4oFhFKDgjl/WBBBFNqDyNifWg7g== + dependencies: + prosemirror-keymap "^1.0.0" + prosemirror-model "^1.0.0" + prosemirror-state "^1.0.0" + prosemirror-view "^1.0.0" + +prosemirror-history@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/prosemirror-history/-/prosemirror-history-1.2.0.tgz#04cc4df8d2f7b2a46651a2780de191ada6d465ea" + integrity sha512-B9v9xtf4fYbKxQwIr+3wtTDNLDZcmMMmGiI3TAPShnUzvo+Rmv1GiUrsQChY1meetHl7rhML2cppF3FTs7f7UQ== + dependencies: + prosemirror-state "^1.2.2" + prosemirror-transform "^1.0.0" + rope-sequence "^1.3.0" + +prosemirror-keymap@^1.0.0, prosemirror-keymap@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/prosemirror-keymap/-/prosemirror-keymap-1.1.5.tgz#b5984c7d30f5c75956c853126c54e9e624c0327b" + integrity sha512-8SZgPH3K+GLsHL2wKuwBD9rxhsbnVBTwpHCO4VUO5GmqUQlxd/2GtBVWTsyLq4Dp3N9nGgPd3+lZFKUDuVp+Vw== + dependencies: + prosemirror-state "^1.0.0" + w3c-keyname "^2.2.0" + +prosemirror-model@^1.0.0, prosemirror-model@^1.14.3, prosemirror-model@^1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/prosemirror-model/-/prosemirror-model-1.15.0.tgz#23bc09098daa7c309dba90a76a1b989ce6f61405" + integrity sha512-hQJv7SnIhlAy9ga3lhPPgaufhvCbQB9tHwscJ9E1H1pPHmN8w5V/lURueoYv9Kc3/bpNWoyHa8r3g//m7N0ChQ== + dependencies: + orderedmap "^1.1.0" + +prosemirror-schema-list@^1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/prosemirror-schema-list/-/prosemirror-schema-list-1.1.6.tgz#c3e13fe2f74750e4a53ff88d798dc0c4ccca6707" + integrity sha512-aFGEdaCWmJzouZ8DwedmvSsL50JpRkqhQ6tcpThwJONVVmCgI36LJHtoQ4VGZbusMavaBhXXr33zyD2IVsTlkw== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-state@^1.0.0, prosemirror-state@^1.2.2, prosemirror-state@^1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/prosemirror-state/-/prosemirror-state-1.3.4.tgz#4c6b52628216e753fc901c6d2bfd84ce109e8952" + integrity sha512-Xkkrpd1y/TQ6HKzN3agsQIGRcLckUMA9u3j207L04mt8ToRgpGeyhbVv0HI7omDORIBHjR29b7AwlATFFf2GLA== + dependencies: + prosemirror-model "^1.0.0" + prosemirror-transform "^1.0.0" + +prosemirror-transform@^1.0.0, prosemirror-transform@^1.1.0, prosemirror-transform@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/prosemirror-transform/-/prosemirror-transform-1.3.3.tgz#5f6712b0577a119cc418686fe7588b6dd9b7464d" + integrity sha512-9NLVXy1Sfa2G6qPqhWMkEvwQQMTw7OyTqOZbJaGQWsCeH3hH5Cw+c5eNaLM1Uu75EyKLsEZhJ93XpHJBa6RX8A== + dependencies: + prosemirror-model "^1.0.0" + +prosemirror-view@^1.0.0, prosemirror-view@^1.1.0, prosemirror-view@^1.22.0: + version "1.23.0" + resolved "https://registry.yarnpkg.com/prosemirror-view/-/prosemirror-view-1.23.0.tgz#07f5539006ad4cba46eea81d78f1a892536858ac" + integrity sha512-lQlaOZqHa6+igCryOIaH7gMJKT8Jbi2w99NFiE6BEUrlhakI2OU5uUeqpHk5S5ejddwv7BEtFyGCMl3SPjak7A== + dependencies: + prosemirror-model "^1.14.3" + prosemirror-state "^1.0.0" + prosemirror-transform "^1.1.0" + protobufjs@^6.10.0, protobufjs@^6.10.2: version "6.11.2" resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.2.tgz#de39fabd4ed32beaa08e9bb1e30d08544c1edf8b" @@ -20451,6 +20862,11 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^3.0.0" inherits "^2.0.1" +rope-sequence@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/rope-sequence/-/rope-sequence-1.3.2.tgz#a19e02d72991ca71feb6b5f8a91154e48e3c098b" + integrity sha512-ku6MFrwEVSVmXLvy3dYph3LAMNS0890K7fabn+0YIRQ2T96T9F4gkFf0vf0WW0JUraNWwGRtInEpH7yO4tbQZg== + router@^1.3.1: version "1.3.3" resolved "https://registry.yarnpkg.com/router/-/router-1.3.3.tgz#c142f6b5ea4d6b3359022ca95b6580bd217f89cf" @@ -22338,6 +22754,13 @@ tinycolor2@^1.4.1: resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" integrity sha1-9PrTM0R7wLB9TcjpIJ2POaisd+g= +tippy.js@^6.3.6: + version "6.3.7" + resolved "https://registry.yarnpkg.com/tippy.js/-/tippy.js-6.3.7.tgz#8ccfb651d642010ed9a32ff29b0e9e19c5b8c61c" + integrity sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ== + dependencies: + "@popperjs/core" "^2.9.0" + tlds@^1.187.0: version "1.203.1" resolved "https://registry.yarnpkg.com/tlds/-/tlds-1.203.1.tgz#4dc9b02f53de3315bc98b80665e13de3edfc1dfc" @@ -22668,6 +23091,13 @@ tunnel-agent@~0.4.1: version "0.4.3" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" +turndown@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/turndown/-/turndown-7.1.1.tgz#96992f2d9b40a1a03d3ea61ad31b5a5c751ef77f" + integrity sha512-BEkXaWH7Wh7e9bd2QumhfAXk5g34+6QUmmWx+0q6ThaVOLuLUqsnkq35HQ5SBHSaxjSfSM7US5o4lhJNH7B9MA== + dependencies: + domino "^2.1.6" + tweetnacl-async@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/tweetnacl-async/-/tweetnacl-async-2.0.0.tgz#0f7eed1107f862f88d4d95cc05398eb9a6413d1d" @@ -23430,6 +23860,11 @@ w3c-hr-time@^1.0.2: dependencies: browser-process-hrtime "^1.0.0" +w3c-keyname@^2.2.0: + version "2.2.4" + resolved "https://registry.yarnpkg.com/w3c-keyname/-/w3c-keyname-2.2.4.tgz#4ade6916f6290224cdbd1db8ac49eab03d0eef6b" + integrity sha512-tOhfEwEzFLJzf6d1ZPkYfGj+FWhIpBux9ppoP3rlclw3Z0BZv3N7b7030Z1kYth+6rDuAsXUFr+d0VE6Ed1ikw== + w3c-xmlserializer@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz#30485ca7d70a6fd052420a3d12fd90e6339ce794" From ee5b885954bf4452cb21f329992878961723153a Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 13 Nov 2021 22:09:07 +0000 Subject: [PATCH 02/17] Add MarkdownHelpModal --- .../components/AnnotationCreate.tsx | 94 ++++++- src/annotations/components/AnnotationEdit.tsx | 15 +- .../components/AnnotationEditable.tsx | 96 +++++-- src/annotations/components/MarkdownHelp.tsx | 246 ++++++++++++++++++ src/annotations/components/editor/editor.tsx | 14 +- src/annotations/components/editor/styles.css | 143 +++++++++- .../components/design-library/HoverBox.tsx | 3 +- 7 files changed, 568 insertions(+), 43 deletions(-) create mode 100644 src/annotations/components/MarkdownHelp.tsx diff --git a/src/annotations/components/AnnotationCreate.tsx b/src/annotations/components/AnnotationCreate.tsx index c342b1ffc8..4193370f46 100644 --- a/src/annotations/components/AnnotationCreate.tsx +++ b/src/annotations/components/AnnotationCreate.tsx @@ -13,10 +13,13 @@ import { ClickAway } from 'src/util/click-away-wrapper' import TagPicker, { TagPickerDependencies } from 'src/tags/ui/TagPicker' import SaveBtn from './save-btn' import TipTap from './editor/editor' +import MarkdownHelp from './MarkdownHelp' +import * as icons from 'src/common-ui/components/design-library/icons' interface State { isTagPickerShown: boolean contentToSave: string + isMarkdownHelpShown: boolean } var TurndownService = require('turndown') @@ -56,9 +59,12 @@ export class AnnotationCreate extends React.Component // MarkdownPreviewAnnotationInsertMenu // >() + private editor; + state: State = { isTagPickerShown: false, contentToSave: null, + isMarkdownHelpShown: false, } componentDidMount() { @@ -80,12 +86,16 @@ export class AnnotationCreate extends React.Component } private hideTagPicker = () => this.setState({ isTagPickerShown: false }) + private hideMarkdownHelp = () => this.setState({ isMarkdownHelpShown: false }) private handleCancel = () => this.props.onCancel() private handleSave = async ( shouldShare: boolean, isProtected?: boolean, ) => { const saveP = this.props.onSave(shouldShare, isProtected) + + this.editor.commands.clearContent() + await saveP } @@ -135,7 +145,9 @@ export class AnnotationCreate extends React.Component this.setState({ isTagPickerShown }) const tagPicker = !this.state.isTagPickerShown ? null : ( - + setPickerShown(false)}> ) } + + private renderMarkdownHelpButton() { + const setPickerShown = (isMarkdownHelpShown: boolean) => + this.setState({ isMarkdownHelpShown }) + + return ( + + + + setPickerShown(!this.state.isMarkdownHelpShown) + } + /> + + + ) + } + private renderActionButtons() { return ( - + Cancel @@ -192,14 +226,32 @@ export class AnnotationCreate extends React.Component this.printContent(content)} onKeyDown={(e) => this.handleInputKeyDown(e)} - placeholder={`

Add private note. Save with ${AnnotationCreate.MOD_KEY}+enter (+shift to share)

`} + placeholder={`Add private note. Save with ${AnnotationCreate.MOD_KEY}+enter (+shift to share)`} + editorInstanceRef={editor => this.editor = editor} /> {this.props.comment !== '' && ( <> - {this.renderTagPicker()} - {this.renderActionButtons()} + + + {this.renderActionButtons()} + {this.renderMarkdownHelpButton()} + + {this.renderTagPicker()} + )} + {!this.state.isMarkdownHelpShown ? null : ( + + {/* setPickerShown(false)}>*/} + + {/**/} + + )}
) } @@ -207,6 +259,32 @@ export class AnnotationCreate extends React.Component export default onClickOutside(AnnotationCreate) +const FooterContainer = styled.div` + border-top: 1px solid #f0f0f0; + display: flex; + justify-content: space-between; + align-items: center; +` + +const SaveActionBar = styled.div` + display: flex; + justify-content: flex-start; + align-items: center; +` + +const MarkdownButtonContainer = styled.div` + display: flex; +` + +const MarkdownButton = styled.img` + display: flex; + height: 16px; + opacity: 0.8; + mask-position: center center; + margin-left: 10px; + cursor: pointer; +` + const TextBoxContainerStyled = styled.div` box-shadow: none; cursor: default; @@ -215,7 +293,6 @@ const TextBoxContainerStyled = styled.div` flex-direction: column; font-size: 14px; width: 100%; - padding: 0 10px; box-shadow: rgb(0 0 0 / 10%) 0px 1px 2px 0px; border-radius: 5px; background-color: ${(props) => (props.comment !== '' ? 'white' : 'none')}; @@ -261,8 +338,7 @@ const FooterStyled = styled.div` flex-direction: row-reverse; justify-content: flex-end; align-items: center; - margin: 0 5px 3px 5px; - height: 26px; + margin: 0 5px 0px 5px; animation: slideIn 0.2s ease-in-out; animation-fill-mode: forwards; ` @@ -289,6 +365,6 @@ const CancelBtnStyled = styled.div` const Flex = styled.div` display: flex; - padding: 0 5px 5px; justify-content: flex-end; + align-items: center; ` diff --git a/src/annotations/components/AnnotationEdit.tsx b/src/annotations/components/AnnotationEdit.tsx index e1328f52e2..0f7bbc6824 100644 --- a/src/annotations/components/AnnotationEdit.tsx +++ b/src/annotations/components/AnnotationEdit.tsx @@ -40,23 +40,29 @@ class AnnotationEdit extends React.Component { contentToSave: '', } + private editor + + private saveEdit(shouldShare, isProtected) { + this.props.onEditConfirm(shouldShare, isProtected) + } + private handleInputKeyDown: React.KeyboardEventHandler = (e) => { e.stopPropagation() if (e.key === 'Enter' && e.shiftKey && e.metaKey) { - return this.props.onEditConfirm(true, false) + return this.saveEdit(true, false) } if (e.key === 'Enter' && e.shiftKey && e.altKey) { - return this.props.onEditConfirm(true, true) + return this.saveEdit(true, true) } if (e.key === 'Enter' && e.altKey) { - return this.props.onEditConfirm(false, true) + return this.saveEdit(false, true) } if (e.key === 'Enter' && e.metaKey) { - return this.props.onEditConfirm(false, false) + return this.saveEdit(false, false) } if (e.key === 'Escape') { @@ -84,6 +90,7 @@ class AnnotationEdit extends React.Component { updatedContent={(content) => this.printContent(content)} onKeyDown={(e) => this.handleInputKeyDown(e)} comment={this.parseMD2HTML()} + editorInstanceRef={(editor) => (this.editor = editor)} /> ) diff --git a/src/annotations/components/AnnotationEditable.tsx b/src/annotations/components/AnnotationEditable.tsx index 861f8cb46e..c9ceba78a6 100644 --- a/src/annotations/components/AnnotationEditable.tsx +++ b/src/annotations/components/AnnotationEditable.tsx @@ -24,6 +24,9 @@ import Margin from 'src/dashboard-refactor/components/Margin' import type { NoteResultHoverState } from './types' import { getKeyName } from 'src/util/os-specific-key-names' import { getShareButtonData } from '../sharing-utils' +import MarkdownHelp from './MarkdownHelp' +import { ClickAway } from 'src/util/click-away-wrapper' +import { HoverBox } from 'src/common-ui/components/design-library/HoverBox' export interface HighlightProps extends AnnotationProps { body: string @@ -73,6 +76,10 @@ export interface AnnotationEditableEventProps { onUnhover?: React.MouseEventHandler } +interface State { + isMarkdownHelpShown: boolean +} + export type Props = (HighlightProps | NoteProps) & AnnotationEditableEventProps export default class AnnotationEditable extends React.Component { @@ -85,8 +92,14 @@ export default class AnnotationEditable extends React.Component { hoverState: null, } + state: State = { + isMarkdownHelpShown: false, + } + focus() {} + private hideMarkdownHelp = () => this.setState({ isMarkdownHelpShown: false }) + private get creationInfo() { // TODO: Figure out why these dates are so unpredictable and fix it const handleDateData = (date: string | number | Date): number => @@ -333,6 +346,26 @@ export default class AnnotationEditable extends React.Component { ] } + private renderMarkdownHelpButton() { + const setPickerShown = (isMarkdownHelpShown: boolean) => + this.setState({ isMarkdownHelpShown }) + return ( + + + + setPickerShown(!this.state.isMarkdownHelpShown) + } + /> + + + ) + } + private renderFooter() { const { mode, @@ -381,19 +414,22 @@ export default class AnnotationEditable extends React.Component { {mode === 'delete' && ( Really? )} - - - - Cancel - - - - {confirmBtn} - - + + + + + Cancel + + + + {confirmBtn} + + + {this.renderMarkdownHelpButton()} + ) } @@ -446,6 +482,16 @@ export default class AnnotationEditable extends React.Component { + {!this.state.isMarkdownHelpShown ? null : ( + + + + )} ) } @@ -494,6 +540,24 @@ const EditNoteIcon = styled.div` mask-size: 16px; cursor: pointer; ` +const MarkdownButtonContainer = styled.div` + display: flex; +` + +const MarkdownButton = styled.img` + display: flex; + height: 16px; + opacity: 0.8; + mask-position: center center; + margin-left: 10px; + cursor: pointer; +` + +const SaveActionBar = styled.div` + display: flex; + justify-content: flex-start; + align-items: center; +` const HighlightActionsBox = styled.div` position: absolute; @@ -696,7 +760,7 @@ const BtnContainerStyled = styled.div` flex-direction: row-reverse; width: 100%; justify-content: flex-end; - padding: 0 5px 5px; + align-items: center; ` const ActionBtnStyled = styled.button` @@ -728,5 +792,7 @@ const ActionBtnStyled = styled.button` const DeletionBox = styled.div` display: flex; justify-content: space-between; - padding-left: 10px; + border-top: 1px solid #f0f0f0; + padding: 5px; +} ` diff --git a/src/annotations/components/MarkdownHelp.tsx b/src/annotations/components/MarkdownHelp.tsx new file mode 100644 index 0000000000..13dcf66398 --- /dev/null +++ b/src/annotations/components/MarkdownHelp.tsx @@ -0,0 +1,246 @@ +import * as React from 'react' +import styled from 'styled-components' +import onClickOutside from 'react-onclickoutside' +import { getKeyName } from 'src/util/os-specific-key-names' + +interface Props {} + +interface State {} + +export class MarkdownHelp extends React.Component { + static MOD_KEY = getKeyName({ key: 'mod' }) + static ALT_KEY = getKeyName({ key: 'alt' }) + + render() { + return ( + + + Formatting + + + Bold + + **bold** + + {MarkdownHelp.MOD_KEY}+b + + + + + Italic + + *italic* + + {MarkdownHelp.MOD_KEY}+i + + + + + Highlight + + ==highlight== + + + {MarkdownHelp.MOD_KEY}+shift+h + + + + + + + Link + + + Highlight text and paste url + + {MarkdownHelp.MOD_KEY}+v + + + + + Inline Code + + `() => function(){}` + + + {MarkdownHelp.MOD_KEY}+shift+e + + + + + + + Multi-Line
+ Code Block +
+ + shift+enter in Inline Code + + + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+c + + + + + + Underline + + + + {MarkdownHelp.MOD_KEY}+u + + + + + Strikethrough + + ~~Strikethrough~~ + + + {MarkdownHelp.MOD_KEY}+shift+x + + + + + +
    +
  1. Ordered List
  2. +
+ + 1. Item One + + + {MarkdownHelp.MOD_KEY}+shift+7 + + + + + +
    +
  • Bullet List
  • +
+ + - Item One or * Item One + + + {MarkdownHelp.MOD_KEY}+shift+8 + + + + + +

Heading 1

+ + # Heading 1 + + + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+1 + + + + + +

Heading 2

+ + # Heading 2 + + + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+2 + + + + + +

Heading 3

+ + # Heading 3 + + + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+3 + + + +
+
+ ) + } +} + +const TutorialTable = styled.table` + width: 100%; + + & tr { + height: 40px; + display: flex; + justify-content: space-between; + align-items: center; + } + + & td:last-child { + display: flex; + justify-content: flex-end; + } + + & code { + border: 1px solid #f29d9d; + border-radius: 3px; + padding: 2px 5px; + width: fit-content; + align-self: flex-end; + background-color: #f29d9d60; + color: #ff2b2b; + font-weight: 500; + } + + & ul { + margin-inline-start: -30px; + } + + & ol { + margin-inline-start: -30px; + } +` + +const CodeBlock = styled.div` + border: 1px solid #f29d9d; + border-radius: 3px; + padding: 2px 5px; + width: fit-content; + text-align: left; + background-color: #f29d9d60; + color: #ff2b2b; + font-weight: 500; +` + +const Highlight = styled.div` + background-color: yellow; +` + +const Link = styled.a`` + +const ShortCuts = styled.div` + border: 1px solid #f29d9d; + border-radius: 3px; + padding: 2px 5px; + font-size: 12px; + width: fit-content; + align-self: flex-end; + background-color: #f29d9d60; +` + +const FormattingTitle = styled.div` + font-size: 16px; + color: #c0c0c0; + display: flex; + justify-content: space-between; + align-items: center; +` + +const MarkdownHelpContainer = styled.div` + padding: 15px; +` + +export default onClickOutside(MarkdownHelp) diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx index 85bb78b07e..7ced2f26fb 100644 --- a/src/annotations/components/editor/editor.tsx +++ b/src/annotations/components/editor/editor.tsx @@ -5,8 +5,8 @@ import Highlight from '@tiptap/extension-highlight' import Typography from '@tiptap/extension-typography' import Placeholder from '@tiptap/extension-placeholder' import Link from '@tiptap/extension-link' + import './styles.css' -import styled from 'styled-components' interface Props { updatedContent: (content) => void @@ -14,9 +14,10 @@ interface Props { comment?: string placeholder?: string clearField?: boolean + editorInstanceRef: () => void } -export default (props) => { +export default (props, styles) => { const editor = useEditor({ extensions: [ StarterKit, @@ -31,6 +32,7 @@ export default (props) => { }), ], content: props.comment, + onCreate: ({ editor }) => editor.commands.focus('end'), onUpdate: ({ editor }) => { const content = editor.getHTML() props.updatedContent(content) @@ -42,19 +44,17 @@ export default (props) => { return props.onKeyDown(event) }, }, - attributes: { - class: - 'prose prose-sm sm:prose lg:prose-lg xl:prose-2xl mx-auto focus:outline-none', - }, }, }) + props.editorInstanceRef(editor) + // TODO: clear the content when the note is saved //editor.commands.clearContent() return ( <> - + ) } diff --git a/src/annotations/components/editor/styles.css b/src/annotations/components/editor/styles.css index 158297f809..f2a2e999c6 100644 --- a/src/annotations/components/editor/styles.css +++ b/src/annotations/components/editor/styles.css @@ -1,11 +1,140 @@ -.ProseMirror { - > * + * { - margin-top: 0.75em; +:global .ProseMirror p.is-editor-empty:first-child::before { + content: attr(data-placeholder); + float: left; + color: #adb5bd; + pointer-events: none; + height: 0; +} + +:global .ProseMirror { + outline: none; + padding: 15px 15px; + + & ul { + margin-block-start: 0.5em; + margin-block-end: 0.5em; + } + + & > *:first-child { + margin-block-start: 0em; + } + + & > *:last-child { + margin-block-end: 0em; + } + + & p { + margin-block-start: 0.5em; + margin-block-end: 0.5em; + line-height: 20px; + } + + & h1 { + margin-block-start: 1em; + margin-block-end: 0.5em; + } + + & h2 { + margin-block-start: 1em; + margin-block-end: 0.5em; + } + + & h3 { + margin-block-start: 1em; + margin-block-end: 0.5em; } - ul, - ol { - padding: 0 1rem; + & h4 { + margin-block-start: 1em; + margin-block-end: 0.5em; + } + + & h5 { + margin-block-start: 1em; + margin-block-end: 0.5em; + } + + /* & p:first-child { + margin-block-start: 0em; + } + + & h1:first-child { + margin-block-start: 0em; + } + + & h2:first-child { + margin-block-start: 0em; + } + + & h3:first-child { + margin-block-start: 0em; + } + + & h4:first-child { + margin-block-start: 0em; + } + + & h5:first-child { + margin-block-start: 0em; + } + + & blockquote:first-child { + margin-block-start: 0em; + } + + & image:first-child { + margin-block-start: 0em; + } + + & pre:first-child { + margin-block-start: 0em; + } + + & p:last-child { + margin-block-end: 0em; + } + + & h1:last-child { + margin-block-end: 0em; + } + + & h2:last-child { + margin-block-end: 0em; + } + + & h3:last-child { + margin-block-end: 0em; + } + + & h4:last-child { + margin-block-end: 0em; + } + + & h5:last-child { + margin-block-end: 0em; + } + + & blockquote:last-child { + margin-block-end: 0em; + } + + & image:last-child { + margin-block-end: 0em; + } + + & pre:last-child { + margin-block-end: 0em; + } */ +} + +:global .ProseMirrorContainer { +} + +:global .ProseMirror:focus { + outline: none; + + /* > * + * { + margin-top: 3em; } h1, @@ -49,5 +178,5 @@ blockquote { padding-left: 1rem; border-left: 2px solid rgba(#0d0d0d, 0.1); - } + } */ } diff --git a/src/common-ui/components/design-library/HoverBox.tsx b/src/common-ui/components/design-library/HoverBox.tsx index b0f7a1dcd8..1039ad43f3 100644 --- a/src/common-ui/components/design-library/HoverBox.tsx +++ b/src/common-ui/components/design-library/HoverBox.tsx @@ -8,6 +8,7 @@ export interface Props { bottom?: string width?: string withRelativeContainer?: boolean + position?: string } export class HoverBox extends React.Component { @@ -34,7 +35,7 @@ export const HoverBoxDiv = styled.div` box-shadow: rgba(15, 15, 15, 0.05) 0px 0px 0px 1px, rgba(15, 15, 15, 0.1) 0px 3px 6px, rgba(15, 15, 15, 0.2) 0px 9px 24px; overflow: visible; - position: absolute; + position: ${(props) => (props.position ? props.position : 'absolute')};; border-radius: 3px; width: ${(props) => (props.width ? props.width : '300px')}; ${(props) => (props.top ? `top: ${props.top};` : '')} From d63d758e741837e18831069158b82b508a88be45 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sat, 13 Nov 2021 22:10:57 +0000 Subject: [PATCH 03/17] Experimental attempt to add the tag bar to the annotation create mode Needs fixing up because there are some type error, but it seems to work. --- .../components/AnnotationCreate.tsx | 68 +++++++++++++------ .../components/AnnotationEditable.tsx | 29 ++++---- .../HoverControlledAnnotationCreate.tsx | 37 ++++++++++ .../components/result-item-tags-segment.tsx | 14 ++-- .../AnnotationsSidebarContainer.tsx | 1 + src/tags/ui/tag-holder.css | 20 +++--- src/tags/ui/tag-holder.tsx | 26 +++---- 7 files changed, 131 insertions(+), 64 deletions(-) create mode 100644 src/annotations/components/HoverControlledAnnotationCreate.tsx diff --git a/src/annotations/components/AnnotationCreate.tsx b/src/annotations/components/AnnotationCreate.tsx index 4193370f46..a2baa0d5b1 100644 --- a/src/annotations/components/AnnotationCreate.tsx +++ b/src/annotations/components/AnnotationCreate.tsx @@ -8,6 +8,7 @@ import { FocusableComponent } from './types' import { insertTab, uninsertTab } from 'src/common-ui/utils' import { getKeyName } from 'src/util/os-specific-key-names' import TagHolder from 'src/tags/ui/tag-holder' +import type { AnnotationMode } from 'src/sidebar/annotations-sidebar/types' import { HoverBox } from 'src/common-ui/components/design-library/HoverBox' import { ClickAway } from 'src/util/click-away-wrapper' import TagPicker, { TagPickerDependencies } from 'src/tags/ui/TagPicker' @@ -15,6 +16,9 @@ import SaveBtn from './save-btn' import TipTap from './editor/editor' import MarkdownHelp from './MarkdownHelp' import * as icons from 'src/common-ui/components/design-library/icons' +import TagsSegment from 'src/common-ui/components/result-item-tags-segment' +import type { NoteResultHoverState } from './types' +import type { AnnotationFooterEventProps } from 'src/annotations/components/AnnotationFooter' interface State { isTagPickerShown: boolean @@ -31,6 +35,11 @@ export interface AnnotationCreateEventProps { onCancel: () => void onTagsUpdate: (tags: string[]) => void onCommentChange: (text: string) => void + onTagsHover?: React.MouseEventHandler + annotationFooterDependencies?: AnnotationFooterEventProps + onFooterHover?: React.MouseEventHandler + onNoteHover?: React.MouseEventHandler + onUnhover?: React.MouseEventHandler } export interface AnnotationCreateGeneralProps { @@ -38,6 +47,9 @@ export interface AnnotationCreateGeneralProps { autoFocus?: boolean comment: string tags: string[] + onTagClick?: (tag: string) => void + hoverState: NoteResultHoverState + mode: AnnotationMode } export interface Props @@ -59,7 +71,13 @@ export class AnnotationCreate extends React.Component // MarkdownPreviewAnnotationInsertMenu // >() - private editor; + static defaultProps: Pick = { + tags: [], + mode: 'default', + hoverState: null, + } + + private editor state: State = { isTagPickerShown: false, @@ -86,14 +104,15 @@ export class AnnotationCreate extends React.Component } private hideTagPicker = () => this.setState({ isTagPickerShown: false }) - private hideMarkdownHelp = () => this.setState({ isMarkdownHelpShown: false }) + private hideMarkdownHelp = () => + this.setState({ isMarkdownHelpShown: false }) private handleCancel = () => this.props.onCancel() private handleSave = async ( shouldShare: boolean, isProtected?: boolean, ) => { const saveP = this.props.onSave(shouldShare, isProtected) - + this.editor.commands.clearContent() await saveP @@ -145,9 +164,7 @@ export class AnnotationCreate extends React.Component this.setState({ isTagPickerShown }) const tagPicker = !this.state.isTagPickerShown ? null : ( - + setPickerShown(false)}> ) } - private renderMarkdownHelpButton() { const setPickerShown = (isMarkdownHelpShown: boolean) => this.setState({ isMarkdownHelpShown }) @@ -185,15 +201,15 @@ export class AnnotationCreate extends React.Component return ( - - setPickerShown(!this.state.isMarkdownHelpShown) - } - /> + + setPickerShown(!this.state.isMarkdownHelpShown) + } + /> ) @@ -227,10 +243,20 @@ export class AnnotationCreate extends React.Component updatedContent={(content) => this.printContent(content)} onKeyDown={(e) => this.handleInputKeyDown(e)} placeholder={`Add private note. Save with ${AnnotationCreate.MOD_KEY}+enter (+shift to share)`} - editorInstanceRef={editor => this.editor = editor} + editorInstanceRef={(editor) => (this.editor = editor)} /> {this.props.comment !== '' && ( <> + {this.renderActionButtons()} @@ -242,13 +268,13 @@ export class AnnotationCreate extends React.Component )} {!this.state.isMarkdownHelpShown ? null : ( {/* setPickerShown(false)}>*/} - + {/**/} )} @@ -264,6 +290,7 @@ const FooterContainer = styled.div` display: flex; justify-content: space-between; align-items: center; + padding: 5px 15px 5px 5px; ` const SaveActionBar = styled.div` @@ -338,7 +365,6 @@ const FooterStyled = styled.div` flex-direction: row-reverse; justify-content: flex-end; align-items: center; - margin: 0 5px 0px 5px; animation: slideIn 0.2s ease-in-out; animation-fill-mode: forwards; ` diff --git a/src/annotations/components/AnnotationEditable.tsx b/src/annotations/components/AnnotationEditable.tsx index c9ceba78a6..40455fceae 100644 --- a/src/annotations/components/AnnotationEditable.tsx +++ b/src/annotations/components/AnnotationEditable.tsx @@ -98,7 +98,8 @@ export default class AnnotationEditable extends React.Component { focus() {} - private hideMarkdownHelp = () => this.setState({ isMarkdownHelpShown: false }) + private hideMarkdownHelp = () => + this.setState({ isMarkdownHelpShown: false }) private get creationInfo() { // TODO: Figure out why these dates are so unpredictable and fix it @@ -352,15 +353,15 @@ export default class AnnotationEditable extends React.Component { return ( - - setPickerShown(!this.state.isMarkdownHelpShown) - } - /> + + setPickerShown(!this.state.isMarkdownHelpShown) + } + /> ) @@ -485,11 +486,11 @@ export default class AnnotationEditable extends React.Component { {!this.state.isMarkdownHelpShown ? null : ( - + )} @@ -674,7 +675,7 @@ const CommentBox = styled.div` padding: 10px 15px 10px 15px; line-height: 1.4; text-align: left; - border-top: 1px solid #e0e0e0; + border-top: 1px solid #f0f0f0; overflow: visible; flex-direction: row-reverse; display: flex; @@ -694,7 +695,7 @@ const CommentBox = styled.div` const DefaultFooterStyled = styled.div` display: flex; - border-top: 1px solid #e0e0e0; + border-top: 1px solid #f0f0f0; & div { border-top: none; diff --git a/src/annotations/components/HoverControlledAnnotationCreate.tsx b/src/annotations/components/HoverControlledAnnotationCreate.tsx new file mode 100644 index 0000000000..84590312a5 --- /dev/null +++ b/src/annotations/components/HoverControlledAnnotationCreate.tsx @@ -0,0 +1,37 @@ +import React from 'react' + +import AnnotationCreate, { Props } from './AnnotationCreate' +import { NoteResultHoverState } from './types' + +export * from './AnnotationCreate' + +interface State { + hoverState: NoteResultHoverState +} + +export default class HoverControlledAnnotationEditable extends React.Component< + Props, + State +> { + static defaultProps = AnnotationCreate + + state: State = { hoverState: null } + + private setHoverState: ( + hoverState: NoteResultHoverState, + ) => React.MouseEventHandler = (hoverState) => (e) => + this.setState({ hoverState }) + + render() { + return ( + + ) + } +} diff --git a/src/common-ui/components/result-item-tags-segment.tsx b/src/common-ui/components/result-item-tags-segment.tsx index 244aafec8f..398c08060e 100644 --- a/src/common-ui/components/result-item-tags-segment.tsx +++ b/src/common-ui/components/result-item-tags-segment.tsx @@ -5,7 +5,6 @@ import * as icons from 'src/common-ui/components/design-library/icons' export interface Props extends Pick, 'onMouseEnter'> { tags: string[] - maxTags?: number showEditBtn: boolean onTagClick?: (tag: string) => void onEditBtnClick: React.MouseEventHandler @@ -13,7 +12,6 @@ export interface Props extends Pick, 'onMouseEnter'> { export default function TagsSegment({ tags, - maxTags = 8, onTagClick, showEditBtn, onEditBtnClick, @@ -26,7 +24,7 @@ export default function TagsSegment({ return ( - {tags.slice(0, maxTags).map((tag) => ( + {tags.slice(0).map((tag) => ( onTagClick(tag) : undefined} @@ -41,15 +39,16 @@ export default function TagsSegment({ } const Container = styled.div` - display: flex; + display: inline-box; align-items: center; justify-content: space-between; - border-top: 1px solid #e0e0e0; - padding: 5px 15px; + border-top: 1px solid #f0f0f0; + padding: 5px 10px; ` const TagsContainer = styled.div` display: flex; + flex-wrap: wrap; ` const TagPill = styled.div` @@ -81,4 +80,7 @@ const EditIcon = styled.button` mask-repeat: no-repeat; mask-size: 16px; cursor: pointer; + right: 30px; + position: relative; + z-index: 10; ` diff --git a/src/sidebar/annotations-sidebar/containers/AnnotationsSidebarContainer.tsx b/src/sidebar/annotations-sidebar/containers/AnnotationsSidebarContainer.tsx index 8e08db62ed..9a35f34c56 100644 --- a/src/sidebar/annotations-sidebar/containers/AnnotationsSidebarContainer.tsx +++ b/src/sidebar/annotations-sidebar/containers/AnnotationsSidebarContainer.tsx @@ -39,6 +39,7 @@ import Icon from '@worldbrain/memex-common/lib/common-ui/components/icon' import { sidebarNotesTypeToString } from '../utils' import { getListShareUrl } from 'src/content-sharing/utils' import { ClickAway } from 'src/util/click-away-wrapper' +import type { AnnotationMode } from 'src/sidebar/annotations-sidebar/types' const DEF_CONTEXT: { context: AnnotationEventContext } = { context: 'pageAnnotations', diff --git a/src/tags/ui/tag-holder.css b/src/tags/ui/tag-holder.css index d77adb637d..d55e8b4bd2 100644 --- a/src/tags/ui/tag-holder.css +++ b/src/tags/ui/tag-holder.css @@ -1,11 +1,10 @@ .tagHolder { position: relative; - display: inline-block; - justify-content: flex-start; + display: flex; + justify-content: center; align-items: center; box-sizing: border-box; cursor: pointer; - padding: 5px 10px 5px 15px; } .tag { @@ -22,7 +21,7 @@ .tagIcon { mask-image: url('/img/tag_empty.svg'); - mask-size: 15px; + mask-size: 16px; width: 20px; height: 20px; mask-repeat: no-repeat; @@ -30,13 +29,18 @@ background-color: #3a2f45; opacity: 0.6; display: flex; - margin-right: 5px; } .tagText { vertical-align: center; } +.tagHolderContainer { + & > div { + display: flex; + } +} + .placeholder { display: inline-flex; color: #888; @@ -45,12 +49,6 @@ align-items: center; padding: 2px 5px; border-radius: 3px; - margin-left: -10px; - - &:hover { - color: #3a2f45; - background-color: #e0e0e0; - } } .placeholder_alt { diff --git a/src/tags/ui/tag-holder.tsx b/src/tags/ui/tag-holder.tsx index 533eac47f3..f06c1344ce 100644 --- a/src/tags/ui/tag-holder.tsx +++ b/src/tags/ui/tag-holder.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import classNames from 'classnames' - +import { ButtonTooltip } from 'src/common-ui/components' import { maxPossibleTags } from 'src/sidebar/annotations-sidebar/utils' import { ClickHandler } from 'src/sidebar/annotations-sidebar/types' @@ -72,17 +72,19 @@ class TagHolder extends React.Component { const { tags, clickHandler } = this.props return ( -
- {this._renderTags()} - 0 && styles.placeholder_alt, - )} - > - {!tags.length && } - Add tag - +
+ +
+ 0 && styles.placeholder_alt, + )} + > + + +
+
) } From 1ade84be11a1443806571a2f68cee4f651950ef6 Mon Sep 17 00:00:00 2001 From: Oliver Date: Sun, 14 Nov 2021 22:36:02 +0000 Subject: [PATCH 04/17] Improvements to editor - Make markdown compatible to textexporter - Style p, h1, h2, h3, blockquotes, code, codeblocks, links - make styles consistent for display and edito mode --- external/@worldbrain/memex-common | 2 +- package.json | 1 + .../components/AnnotationCreate.tsx | 9 +- src/annotations/components/AnnotationEdit.tsx | 4 + .../components/AnnotationEditable.tsx | 17 +- src/annotations/components/MarkdownHelp.tsx | 143 +++++++++-------- src/annotations/components/editor/editor.tsx | 8 +- src/annotations/components/editor/styles.css | 147 ++++++++++-------- .../components/result-item-tags-segment.tsx | 2 +- .../components/AnnotationsSidebar.tsx | 4 - 10 files changed, 195 insertions(+), 142 deletions(-) diff --git a/external/@worldbrain/memex-common b/external/@worldbrain/memex-common index b3ce0e4587..ff0d3d21dd 160000 --- a/external/@worldbrain/memex-common +++ b/external/@worldbrain/memex-common @@ -1 +1 @@ -Subproject commit b3ce0e4587898d2d3fd58f9e165fd98fb3246ab8 +Subproject commit ff0d3d21dd5fe217e2a1ecae5bee5065385a293c diff --git a/package.json b/package.json index dae2ea3b00..d4a9902c41 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@styled-icons/feather": "^10.0.0", "@styled-icons/styled-icon": "^10.0.0", "@tiptap/extension-bubble-menu": "^2.0.0-beta.49", + "@tiptap/extension-code-block": "^2.0.0-beta.29", "@tiptap/extension-highlight": "^2.0.0-beta.30", "@tiptap/extension-link": "^2.0.0-beta.28", "@tiptap/extension-placeholder": "^2.0.0-beta.43", diff --git a/src/annotations/components/AnnotationCreate.tsx b/src/annotations/components/AnnotationCreate.tsx index a2baa0d5b1..5869bdcc7b 100644 --- a/src/annotations/components/AnnotationCreate.tsx +++ b/src/annotations/components/AnnotationCreate.tsx @@ -28,7 +28,11 @@ interface State { var TurndownService = require('turndown') -var turndownService = new TurndownService() +var turndownService = new TurndownService({ + headingStyle: 'atx', + hr: '---', + codeBlockStyle: 'fenced', +}) export interface AnnotationCreateEventProps { onSave: (shouldShare: boolean, isProtected?: boolean) => Promise @@ -114,6 +118,9 @@ export class AnnotationCreate extends React.Component const saveP = this.props.onSave(shouldShare, isProtected) this.editor.commands.clearContent() + this.setState({ + isMarkdownHelpShown: false, + }) await saveP } diff --git a/src/annotations/components/AnnotationEdit.tsx b/src/annotations/components/AnnotationEdit.tsx index 0f7bbc6824..d08f3853e0 100644 --- a/src/annotations/components/AnnotationEdit.tsx +++ b/src/annotations/components/AnnotationEdit.tsx @@ -7,9 +7,11 @@ import { uninsertTab, insertTab } from 'src/common-ui/utils' import { getKeyName } from 'src/util/os-specific-key-names' import TipTap from './editor/editor' const { marked } = require('marked') +import AnnotationEditable from './AnnotationEditable' interface State { contentToSave: string + isMarkdownHelpShown: boolean } var TurndownService = require('turndown') @@ -38,12 +40,14 @@ class AnnotationEdit extends React.Component { state: State = { contentToSave: '', + isMarkdownHelpShown: false, } private editor private saveEdit(shouldShare, isProtected) { this.props.onEditConfirm(shouldShare, isProtected) + AnnotationEditable.removeMarkdownHelp() } private handleInputKeyDown: React.KeyboardEventHandler = (e) => { diff --git a/src/annotations/components/AnnotationEditable.tsx b/src/annotations/components/AnnotationEditable.tsx index 40455fceae..74967c138c 100644 --- a/src/annotations/components/AnnotationEditable.tsx +++ b/src/annotations/components/AnnotationEditable.tsx @@ -96,6 +96,12 @@ export default class AnnotationEditable extends React.Component { isMarkdownHelpShown: false, } + public removeMarkdownHelp() { + this.setState({ + isMarkdownHelpShown: false, + }) + } + focus() {} private hideMarkdownHelp = () => @@ -571,7 +577,6 @@ const HighlightActionsBox = styled.div` const NoteTextBox = styled.div` position: relative; - min-height: 30px; display: flex; justify-content: space-between; align-items: center; @@ -581,14 +586,6 @@ const NoteTextBox = styled.div` word-break: break-word; hyphens: auto; width: 100%; - - & *:first-child { - margin-top: 0px; - } - - & *:last-child { - margin-bottom: 0px; - } ` const NoteText = styled(Markdown)` @@ -672,7 +669,7 @@ const CommentBox = styled.div` word-wrap: break-word; white-space: pre-wrap; margin: 0px; - padding: 10px 15px 10px 15px; + padding: 15px 15px 15px 15px; line-height: 1.4; text-align: left; border-top: 1px solid #f0f0f0; diff --git a/src/annotations/components/MarkdownHelp.tsx b/src/annotations/components/MarkdownHelp.tsx index 13dcf66398..7b60515004 100644 --- a/src/annotations/components/MarkdownHelp.tsx +++ b/src/annotations/components/MarkdownHelp.tsx @@ -15,7 +15,7 @@ export class MarkdownHelp extends React.Component { return ( - Formatting + Editor Formatting Bold @@ -34,17 +34,6 @@ export class MarkdownHelp extends React.Component { {MarkdownHelp.MOD_KEY}+i - - - Highlight - - ==highlight== - - - {MarkdownHelp.MOD_KEY}+shift+h - - - { - Inline Code +
    +
  1. Ordered List
  2. +
- `() => function(){}` + 1. Item One - {MarkdownHelp.MOD_KEY}+shift+e + {MarkdownHelp.MOD_KEY}+shift+7 - - Multi-Line
- Code Block -
+
    +
  • Bullet List
  • +
- shift+enter in Inline Code + - Item One or * Item One - {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+c + {MarkdownHelp.MOD_KEY}+shift+8 - Underline +
Block Quote
- + > this is the quote - {MarkdownHelp.MOD_KEY}+u + + {MarkdownHelp.MOD_KEY}+shift+B + - Strikethrough +

Heading 1

- ~~Strikethrough~~ + # Heading 1 - {MarkdownHelp.MOD_KEY}+shift+x + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+1 -
    -
  1. Ordered List
  2. -
+

Heading 2

- 1. Item One + # Heading 2 - {MarkdownHelp.MOD_KEY}+shift+7 + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+2 -
    -
  • Bullet List
  • -
+

Heading 3

- - Item One or * Item One + # Heading 3 - {MarkdownHelp.MOD_KEY}+shift+8 + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+3 -

Heading 1

+ Inline Code - # Heading 1 + `inline Code` - {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+1 + {MarkdownHelp.MOD_KEY}+shift+e -

Heading 2

+ + Multi-Line
+ Code Block +
- # Heading 2 + ```code blocks``` - {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+2 + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+c -

Heading 3

+ Strikethrough - # Heading 3 + ~~Strikethrough~~ - {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+3 + {MarkdownHelp.MOD_KEY}+shift+x @@ -179,20 +170,30 @@ const TutorialTable = styled.table` align-items: center; } + td:first-child { + width: 50px; + white-space: nowrap; + } + + td:nth-child(2) { + white-space: nowrap; + text-align: center; + } + & td:last-child { display: flex; justify-content: flex-end; + width: 50px; } & code { - border: 1px solid #f29d9d; + padding: 2px 3px 1px; + border: 1px solid #1d1c1d21; border-radius: 3px; - padding: 2px 5px; - width: fit-content; - align-self: flex-end; - background-color: #f29d9d60; - color: #ff2b2b; - font-weight: 500; + background-color: #1d1c1d0a; + color: #e01e5a; + font-size: 14px; + font-family: Monaco, Menlo, Consolas, Courier New, monospace !important; } & ul { @@ -202,17 +203,35 @@ const TutorialTable = styled.table` & ol { margin-inline-start: -30px; } + + & h1 { + font-size: 18px; + } + + & h2 { + font-size: 16px; + } + + & h3 { + font-size: 14px; + } + + & blockquote { + border-left: #5cd9a6 3px solid; + margin-inline-start: 0px; + margin-inline-end: 0px; + padding-left: 10px; + } ` -const CodeBlock = styled.div` - border: 1px solid #f29d9d; - border-radius: 3px; - padding: 2px 5px; - width: fit-content; - text-align: left; - background-color: #f29d9d60; - color: #ff2b2b; - font-weight: 500; +const CodeBlock = styled.pre` + width: fit-content; + border: 1px solid #1d1c1d21; + border-radius: 3px; + background-color: #1d1c1d0a; + padding: 5px; + font-family: 'Monaco', 'Menlo', 'Consolas', 'Courier New', monospace !important; + } ` const Highlight = styled.div` diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx index 7ced2f26fb..2d966c6b10 100644 --- a/src/annotations/components/editor/editor.tsx +++ b/src/annotations/components/editor/editor.tsx @@ -1,10 +1,10 @@ import React from 'react' import { useEditor, EditorContent, BubbleMenu } from '@tiptap/react' import StarterKit from '@tiptap/starter-kit' -import Highlight from '@tiptap/extension-highlight' import Typography from '@tiptap/extension-typography' import Placeholder from '@tiptap/extension-placeholder' import Link from '@tiptap/extension-link' +import CodeBlock from '@tiptap/extension-code-block' import './styles.css' @@ -21,8 +21,12 @@ export default (props, styles) => { const editor = useEditor({ extensions: [ StarterKit, - Highlight, Typography, + CodeBlock.configure({ + HTMLAttributes: { + class: 'CodeBlock', + }, + }), Link.configure({ linkOnPaste: true, }), diff --git a/src/annotations/components/editor/styles.css b/src/annotations/components/editor/styles.css index f2a2e999c6..6f9160c119 100644 --- a/src/annotations/components/editor/styles.css +++ b/src/annotations/components/editor/styles.css @@ -6,21 +6,41 @@ height: 0; } +:global .ProseMirrorContainer { + min-height: 50px; + resize: vertical; + border-top: 1px solid #f0f0f0; + + &:first-child { + border-top: none; + } + + & > div { + background-color: white; + border: none; + border-radius: 3px; + } +} + :global .ProseMirror { outline: none; padding: 15px 15px; + width: fill-available; + background-color: #f0f0f07a; + border-radius: 3px; + border: 1px solid #e0e0e0; - & ul { - margin-block-start: 0.5em; - margin-block-end: 0.5em; + &:focus { + border-radius: 3px; } - & > *:first-child { - margin-block-start: 0em; + & * { + width: fill-available; } - & > *:last-child { - margin-block-end: 0em; + & ul { + margin-block-start: 0.5em; + margin-block-end: 0.5em; } & p { @@ -32,16 +52,19 @@ & h1 { margin-block-start: 1em; margin-block-end: 0.5em; + line-height: 22px; } & h2 { margin-block-start: 1em; margin-block-end: 0.5em; + line-height: 22px; } & h3 { margin-block-start: 1em; margin-block-end: 0.5em; + line-height: 22px; } & h4 { @@ -54,6 +77,62 @@ margin-block-end: 0.5em; } + & blockquote { + border-left: #5cd9a6 3px solid; + margin-inline-start: 10px; + padding-left: 10px; + } + + & h1 { + font-size: 18px; + } + + & h2 { + font-size: 16px; + } + + & h3 { + font-size: 14px; + } + + & a { + } + + & code { + padding: 2px 3px 1px; + border: 1px solid #1d1c1d21; + border-radius: 3px; + background-color: #1d1c1d0a; + color: #e01e5a; + font-family: 'Monaco', 'Menlo', 'Consolas', 'Courier New', monospace !important; + } + + & pre { + width: fill-available; + border: 1px solid #1d1c1d21; + border-radius: 3px; + background-color: #1d1c1d0a; + padding: 10px; + font-family: 'Monaco', 'Menlo', 'Consolas', 'Courier New', monospace !important; + + & code { + width: 100%; + padding: unset; + border: none; + border-radius: unset; + background-color: unset; + color: inherit; + } + } + + & > *:first-child { + margin-block-start: 0em; + } + + & > *:last-child { + margin-block-end: 0em; + } + /* & p:first-child { margin-block-start: 0em; } @@ -126,57 +205,3 @@ margin-block-end: 0em; } */ } - -:global .ProseMirrorContainer { -} - -:global .ProseMirror:focus { - outline: none; - - /* > * + * { - margin-top: 3em; - } - - h1, - h2, - h3, - h4, - h5, - h6 { - line-height: 1.1; - } - - code { - background-color: rgba(#616161, 0.1); - color: #616161; - } - - pre { - background: #0d0d0d; - color: #fff; - font-family: 'JetBrainsMono', monospace; - padding: 0.75rem 1rem; - border-radius: 0.5rem; - - code { - color: inherit; - padding: 0; - background: none; - font-size: 0.8rem; - } - } - - img { - max-width: 100%; - height: auto; - } - - hr { - margin: 1rem 0; - } - - blockquote { - padding-left: 1rem; - border-left: 2px solid rgba(#0d0d0d, 0.1); - } */ -} diff --git a/src/common-ui/components/result-item-tags-segment.tsx b/src/common-ui/components/result-item-tags-segment.tsx index 398c08060e..eeb8cd12f2 100644 --- a/src/common-ui/components/result-item-tags-segment.tsx +++ b/src/common-ui/components/result-item-tags-segment.tsx @@ -43,7 +43,7 @@ const Container = styled.div` align-items: center; justify-content: space-between; border-top: 1px solid #f0f0f0; - padding: 5px 10px; + padding: 5px 15px; ` const TagsContainer = styled.div` diff --git a/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx b/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx index bf6d3995c1..a61a48e9b2 100644 --- a/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx +++ b/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx @@ -674,10 +674,6 @@ const AnnotationsSectionStyled = styled.section` const NewAnnotationBoxStyled = styled.div` position: relative; width: 100%; - - &:hover { - background: white; - } ` const TopSectionStyled = styled.div` From f28d55c40922a346855a7d4b49a95f3470f5ee2a Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Nov 2021 01:59:16 +0000 Subject: [PATCH 05/17] small editor changes to the heading styles --- package.json | 1 + src/annotations/components/editor/editor.tsx | 4 ++++ src/annotations/components/editor/styles.css | 15 +++------------ 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index d4a9902c41..482b79fe6b 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "@styled-icons/styled-icon": "^10.0.0", "@tiptap/extension-bubble-menu": "^2.0.0-beta.49", "@tiptap/extension-code-block": "^2.0.0-beta.29", + "@tiptap/extension-heading": "^2.0.0-beta.23", "@tiptap/extension-highlight": "^2.0.0-beta.30", "@tiptap/extension-link": "^2.0.0-beta.28", "@tiptap/extension-placeholder": "^2.0.0-beta.43", diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx index 2d966c6b10..0cd42c1ada 100644 --- a/src/annotations/components/editor/editor.tsx +++ b/src/annotations/components/editor/editor.tsx @@ -5,6 +5,7 @@ import Typography from '@tiptap/extension-typography' import Placeholder from '@tiptap/extension-placeholder' import Link from '@tiptap/extension-link' import CodeBlock from '@tiptap/extension-code-block' +import Heading from '@tiptap/extension-heading' import './styles.css' @@ -27,6 +28,9 @@ export default (props, styles) => { class: 'CodeBlock', }, }), + Heading.configure({ + levels: [1, 2, 3], + }), Link.configure({ linkOnPaste: true, }), diff --git a/src/annotations/components/editor/styles.css b/src/annotations/components/editor/styles.css index 6f9160c119..6b80aec4c6 100644 --- a/src/annotations/components/editor/styles.css +++ b/src/annotations/components/editor/styles.css @@ -53,18 +53,21 @@ margin-block-start: 1em; margin-block-end: 0.5em; line-height: 22px; + font-size: 18px; } & h2 { margin-block-start: 1em; margin-block-end: 0.5em; line-height: 22px; + font-size: 16px; } & h3 { margin-block-start: 1em; margin-block-end: 0.5em; line-height: 22px; + font-size: 14px; } & h4 { @@ -83,18 +86,6 @@ padding-left: 10px; } - & h1 { - font-size: 18px; - } - - & h2 { - font-size: 16px; - } - - & h3 { - font-size: 14px; - } - & a { } From d1a9cda2a00e7b6137495bc9451120f6214c5f9d Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Nov 2021 02:00:22 +0000 Subject: [PATCH 06/17] small changes --- src/annotations/components/AnnotationEdit.tsx | 2 +- src/annotations/components/editor/styles.css | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/annotations/components/AnnotationEdit.tsx b/src/annotations/components/AnnotationEdit.tsx index d08f3853e0..709bfdd6b5 100644 --- a/src/annotations/components/AnnotationEdit.tsx +++ b/src/annotations/components/AnnotationEdit.tsx @@ -47,7 +47,7 @@ class AnnotationEdit extends React.Component { private saveEdit(shouldShare, isProtected) { this.props.onEditConfirm(shouldShare, isProtected) - AnnotationEditable.removeMarkdownHelp() + //AnnotationEditable.removeMarkdownHelp() } private handleInputKeyDown: React.KeyboardEventHandler = (e) => { diff --git a/src/annotations/components/editor/styles.css b/src/annotations/components/editor/styles.css index 6b80aec4c6..1f8b175cd3 100644 --- a/src/annotations/components/editor/styles.css +++ b/src/annotations/components/editor/styles.css @@ -86,9 +86,6 @@ padding-left: 10px; } - & a { - } - & code { padding: 2px 3px 1px; border: 1px solid #1d1c1d21; From cf4fc6e1eccc4bc19900da90f89a904aa89a14fe Mon Sep 17 00:00:00 2001 From: Jonathan Poltak Samosir Date: Mon, 15 Nov 2021 13:49:24 +0700 Subject: [PATCH 07/17] Clean up main types issues with new editor --- package.json | 1 + .../components/AnnotationCreate.tsx | 44 +++++-------------- src/annotations/components/editor/editor.tsx | 33 ++++++++------ .../lists-sidebar/index.tsx | 1 - .../AnnotationsSidebarContainer.tsx | 1 + yarn.lock | 5 +++ 6 files changed, 39 insertions(+), 46 deletions(-) diff --git a/package.json b/package.json index 6948ac6eee..e78f313821 100644 --- a/package.json +++ b/package.json @@ -196,6 +196,7 @@ "@types/simple-peer": "^6.1.6", "@types/sinon": "^7.0.3", "@types/styled-components": "^5.1.4", + "@types/turndown": "^5.0.1", "@types/url-regex": "^4.1.0", "@types/whatwg-url": "^6.4.0", "atob": "^2.1.2", diff --git a/src/annotations/components/AnnotationCreate.tsx b/src/annotations/components/AnnotationCreate.tsx index 5869bdcc7b..722c4747d1 100644 --- a/src/annotations/components/AnnotationCreate.tsx +++ b/src/annotations/components/AnnotationCreate.tsx @@ -1,19 +1,17 @@ import * as React from 'react' import styled from 'styled-components' import onClickOutside from 'react-onclickoutside' +import type { Editor } from '@tiptap/react' import { ButtonTooltip } from 'src/common-ui/components' -import { MarkdownPreviewAnnotationInsertMenu } from 'src/markdown-preview/markdown-preview-insert-menu' import { FocusableComponent } from './types' -import { insertTab, uninsertTab } from 'src/common-ui/utils' import { getKeyName } from 'src/util/os-specific-key-names' import TagHolder from 'src/tags/ui/tag-holder' -import type { AnnotationMode } from 'src/sidebar/annotations-sidebar/types' import { HoverBox } from 'src/common-ui/components/design-library/HoverBox' import { ClickAway } from 'src/util/click-away-wrapper' import TagPicker, { TagPickerDependencies } from 'src/tags/ui/TagPicker' import SaveBtn from './save-btn' -import TipTap from './editor/editor' +import MemexEditor from './editor/editor' import MarkdownHelp from './MarkdownHelp' import * as icons from 'src/common-ui/components/design-library/icons' import TagsSegment from 'src/common-ui/components/result-item-tags-segment' @@ -22,18 +20,9 @@ import type { AnnotationFooterEventProps } from 'src/annotations/components/Anno interface State { isTagPickerShown: boolean - contentToSave: string isMarkdownHelpShown: boolean } -var TurndownService = require('turndown') - -var turndownService = new TurndownService({ - headingStyle: 'atx', - hr: '---', - codeBlockStyle: 'fenced', -}) - export interface AnnotationCreateEventProps { onSave: (shouldShare: boolean, isProtected?: boolean) => Promise onCancel: () => void @@ -53,7 +42,6 @@ export interface AnnotationCreateGeneralProps { tags: string[] onTagClick?: (tag: string) => void hoverState: NoteResultHoverState - mode: AnnotationMode } export interface Props @@ -75,17 +63,15 @@ export class AnnotationCreate extends React.Component // MarkdownPreviewAnnotationInsertMenu // >() - static defaultProps: Pick = { + static defaultProps: Pick = { tags: [], - mode: 'default', hoverState: null, } - private editor + private editor: Editor state: State = { isTagPickerShown: false, - contentToSave: null, isMarkdownHelpShown: false, } @@ -117,10 +103,8 @@ export class AnnotationCreate extends React.Component ) => { const saveP = this.props.onSave(shouldShare, isProtected) - this.editor.commands.clearContent() - this.setState({ - isMarkdownHelpShown: false, - }) + this.editor?.commands.clearContent() + this.setState({ isMarkdownHelpShown: false }) await saveP } @@ -237,20 +221,16 @@ export class AnnotationCreate extends React.Component ) } - private printContent(content) { - var content = turndownService.turndown(content) - this.setState({ contentToSave: content }) - this.props.onCommentChange(this.state.contentToSave) - } - render() { return ( - this.printContent(content)} - onKeyDown={(e) => this.handleInputKeyDown(e)} - placeholder={`Add private note. Save with ${AnnotationCreate.MOD_KEY}+enter (+shift to share)`} + + this.props.onCommentChange(content) + } editorInstanceRef={(editor) => (this.editor = editor)} + placeholder={`Add private note. Save with ${AnnotationCreate.MOD_KEY}+enter (+shift to share)`} /> {this.props.comment !== '' && ( <> diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx index 0cd42c1ada..3c859756a9 100644 --- a/src/annotations/components/editor/editor.tsx +++ b/src/annotations/components/editor/editor.tsx @@ -1,5 +1,6 @@ import React from 'react' -import { useEditor, EditorContent, BubbleMenu } from '@tiptap/react' +import TurndownService from 'turndown' +import { useEditor, EditorContent, Editor } from '@tiptap/react' import StarterKit from '@tiptap/starter-kit' import Typography from '@tiptap/extension-typography' import Placeholder from '@tiptap/extension-placeholder' @@ -9,16 +10,22 @@ import Heading from '@tiptap/extension-heading' import './styles.css' +const turndownService = new TurndownService({ + headingStyle: 'atx', + hr: '---', + codeBlockStyle: 'fenced', +}) + interface Props { - updatedContent: (content) => void - onKeyDown: (event) => void comment?: string placeholder?: string clearField?: boolean - editorInstanceRef: () => void + onKeyDown: React.KeyboardEventHandler + updatedContent: (content: string) => void + editorInstanceRef: (instance: Editor) => void } -export default (props, styles) => { +const MemexEditor = (props: Props) => { const editor = useEditor({ extensions: [ StarterKit, @@ -42,14 +49,16 @@ export default (props, styles) => { content: props.comment, onCreate: ({ editor }) => editor.commands.focus('end'), onUpdate: ({ editor }) => { - const content = editor.getHTML() - props.updatedContent(content) + const htmlContent = editor.getHTML() + const markdownContent = turndownService.turndown(htmlContent) + props.updatedContent(markdownContent) }, autofocus: true, editorProps: { handleDOMEvents: { keydown: (view, event) => { - return props.onKeyDown(event) + props.onKeyDown(event as any) + return true }, }, }, @@ -60,9 +69,7 @@ export default (props, styles) => { // TODO: clear the content when the note is saved //editor.commands.clearContent() - return ( - <> - - - ) + return } + +export default MemexEditor diff --git a/src/dashboard-refactor/lists-sidebar/index.tsx b/src/dashboard-refactor/lists-sidebar/index.tsx index 23ceac870e..2370dc4e18 100644 --- a/src/dashboard-refactor/lists-sidebar/index.tsx +++ b/src/dashboard-refactor/lists-sidebar/index.tsx @@ -134,7 +134,6 @@ export default class ListsSidebar extends PureComponent { searchBarProps, listsGroups, } = this.props - console.log(listsGroups) return ( Date: Mon, 15 Nov 2021 13:50:08 +0700 Subject: [PATCH 08/17] Remove direct use of tiptap API to clear editor on-save - hide behind MemexEditorInstance interface --- .../components/AnnotationCreate.tsx | 7 +++--- src/annotations/components/editor/editor.tsx | 24 +++++++++++++------ 2 files changed, 20 insertions(+), 11 deletions(-) diff --git a/src/annotations/components/AnnotationCreate.tsx b/src/annotations/components/AnnotationCreate.tsx index 722c4747d1..1b4d8b290c 100644 --- a/src/annotations/components/AnnotationCreate.tsx +++ b/src/annotations/components/AnnotationCreate.tsx @@ -1,7 +1,6 @@ import * as React from 'react' import styled from 'styled-components' import onClickOutside from 'react-onclickoutside' -import type { Editor } from '@tiptap/react' import { ButtonTooltip } from 'src/common-ui/components' import { FocusableComponent } from './types' @@ -11,7 +10,7 @@ import { HoverBox } from 'src/common-ui/components/design-library/HoverBox' import { ClickAway } from 'src/util/click-away-wrapper' import TagPicker, { TagPickerDependencies } from 'src/tags/ui/TagPicker' import SaveBtn from './save-btn' -import MemexEditor from './editor/editor' +import MemexEditor, { MemexEditorInstance } from './editor/editor' import MarkdownHelp from './MarkdownHelp' import * as icons from 'src/common-ui/components/design-library/icons' import TagsSegment from 'src/common-ui/components/result-item-tags-segment' @@ -68,7 +67,7 @@ export class AnnotationCreate extends React.Component hoverState: null, } - private editor: Editor + private editor: MemexEditorInstance state: State = { isTagPickerShown: false, @@ -103,7 +102,7 @@ export class AnnotationCreate extends React.Component ) => { const saveP = this.props.onSave(shouldShare, isProtected) - this.editor?.commands.clearContent() + this.editor?.resetState() this.setState({ isMarkdownHelpShown: false }) await saveP diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx index 3c859756a9..97a425170e 100644 --- a/src/annotations/components/editor/editor.tsx +++ b/src/annotations/components/editor/editor.tsx @@ -1,6 +1,6 @@ -import React from 'react' +import React, { useRef, useEffect } from 'react' import TurndownService from 'turndown' -import { useEditor, EditorContent, Editor } from '@tiptap/react' +import { useEditor, EditorContent } from '@tiptap/react' import StarterKit from '@tiptap/starter-kit' import Typography from '@tiptap/extension-typography' import Placeholder from '@tiptap/extension-placeholder' @@ -16,13 +16,17 @@ const turndownService = new TurndownService({ codeBlockStyle: 'fenced', }) +export interface MemexEditorInstance { + resetState: () => void +} + interface Props { comment?: string placeholder?: string clearField?: boolean onKeyDown: React.KeyboardEventHandler updatedContent: (content: string) => void - editorInstanceRef: (instance: Editor) => void + editorInstanceRef: (instance: MemexEditorInstance) => void } const MemexEditor = (props: Props) => { @@ -63,13 +67,19 @@ const MemexEditor = (props: Props) => { }, }, }) + const memexEditorRef = useRef() - props.editorInstanceRef(editor) + useEffect(() => { + memexEditorRef.current = { + resetState: () => { + editor.commands.clearContent() + }, + } - // TODO: clear the content when the note is saved - //editor.commands.clearContent() + props.editorInstanceRef(memexEditorRef.current) + }) - return + return } export default MemexEditor From d2cca8849dc50b24995d8c3b2e79d6e0c1cc093a Mon Sep 17 00:00:00 2001 From: Jonathan Poltak Samosir Date: Mon, 15 Nov 2021 14:03:05 +0700 Subject: [PATCH 09/17] Fix tiptap duped extensions runtime warnings --- src/annotations/components/editor/editor.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx index 97a425170e..16aeb124c4 100644 --- a/src/annotations/components/editor/editor.tsx +++ b/src/annotations/components/editor/editor.tsx @@ -32,7 +32,10 @@ interface Props { const MemexEditor = (props: Props) => { const editor = useEditor({ extensions: [ - StarterKit, + StarterKit.configure({ + codeBlock: false, + heading: false, + }), Typography, CodeBlock.configure({ HTMLAttributes: { From 113c0d6fd2be51be2f357c6ebd00ad6f46ee41b0 Mon Sep 17 00:00:00 2001 From: Jonathan Poltak Samosir Date: Mon, 15 Nov 2021 14:32:19 +0700 Subject: [PATCH 10/17] Add full SerDes support for MemexEditor - didn't see AnnotationEdit's usage of this earlier - updated it to move the marked HTML serialization into the MemexEditor component - added marked package types + updated the props shape for MemexEditor --- package.json | 1 + .../components/AnnotationCreate.tsx | 5 ++- src/annotations/components/AnnotationEdit.tsx | 42 ++++--------------- src/annotations/components/editor/editor.tsx | 36 ++++++++-------- yarn.lock | 5 +++ 5 files changed, 36 insertions(+), 53 deletions(-) diff --git a/package.json b/package.json index e78f313821..676e109676 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "@tiptap/extension-typography": "^2.0.0-beta.19", "@tiptap/react": "^2.0.0-beta.93", "@tiptap/starter-kit": "^2.0.0-beta.140", + "@types/marked": "^4.0.0", "@types/socket.io-client": "^1.4.32", "@types/ua-parser-js": "^0.7.36", "approx-string-match": "^1.1.0", diff --git a/src/annotations/components/AnnotationCreate.tsx b/src/annotations/components/AnnotationCreate.tsx index 1b4d8b290c..1c5fbd96a5 100644 --- a/src/annotations/components/AnnotationCreate.tsx +++ b/src/annotations/components/AnnotationCreate.tsx @@ -225,10 +225,11 @@ export class AnnotationCreate extends React.Component + onContentUpdate={(content) => this.props.onCommentChange(content) } - editorInstanceRef={(editor) => (this.editor = editor)} + markdownContent={this.props.comment} + setEditorInstanceRef={(editor) => (this.editor = editor)} placeholder={`Add private note. Save with ${AnnotationCreate.MOD_KEY}+enter (+shift to share)`} /> {this.props.comment !== '' && ( diff --git a/src/annotations/components/AnnotationEdit.tsx b/src/annotations/components/AnnotationEdit.tsx index 709bfdd6b5..65dba79db5 100644 --- a/src/annotations/components/AnnotationEdit.tsx +++ b/src/annotations/components/AnnotationEdit.tsx @@ -1,23 +1,13 @@ import * as React from 'react' import styled from 'styled-components' -import { MarkdownPreviewAnnotationInsertMenu } from 'src/markdown-preview/markdown-preview-insert-menu' -import { FocusableComponent } from './types' -import { uninsertTab, insertTab } from 'src/common-ui/utils' import { getKeyName } from 'src/util/os-specific-key-names' -import TipTap from './editor/editor' -const { marked } = require('marked') -import AnnotationEditable from './AnnotationEditable' +import MemexEditor from './editor/editor' interface State { - contentToSave: string isMarkdownHelpShown: boolean } -var TurndownService = require('turndown') - -var turndownService = new TurndownService() - export interface AnnotationEditEventProps { onEditConfirm: (shouldShare: boolean, isProtected?: boolean) => void onEditCancel: () => void @@ -39,12 +29,9 @@ class AnnotationEdit extends React.Component { static MOD_KEY = getKeyName({ key: 'mod' }) state: State = { - contentToSave: '', isMarkdownHelpShown: false, } - private editor - private saveEdit(shouldShare, isProtected) { this.props.onEditConfirm(shouldShare, isProtected) //AnnotationEditable.removeMarkdownHelp() @@ -75,28 +62,15 @@ class AnnotationEdit extends React.Component { } } - private printContent(content) { - var content = turndownService.turndown(content) - this.setState({ contentToSave: content }) - this.props.onCommentChange(this.state.contentToSave) - } - - private parseMD2HTML() { - const html = marked.parse(this.props.comment) - // TODO const sanitisedHTML = - return html - } - render() { return ( - <> - this.printContent(content)} - onKeyDown={(e) => this.handleInputKeyDown(e)} - comment={this.parseMD2HTML()} - editorInstanceRef={(editor) => (this.editor = editor)} - /> - + + this.props.onCommentChange(content) + } + markdownContent={this.props.comment} + onKeyDown={this.handleInputKeyDown} + /> ) } } diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx index 16aeb124c4..e85b7c4b44 100644 --- a/src/annotations/components/editor/editor.tsx +++ b/src/annotations/components/editor/editor.tsx @@ -1,5 +1,6 @@ import React, { useRef, useEffect } from 'react' import TurndownService from 'turndown' +import { marked } from 'marked' import { useEditor, EditorContent } from '@tiptap/react' import StarterKit from '@tiptap/starter-kit' import Typography from '@tiptap/extension-typography' @@ -21,12 +22,11 @@ export interface MemexEditorInstance { } interface Props { - comment?: string + markdownContent: string placeholder?: string - clearField?: boolean - onKeyDown: React.KeyboardEventHandler - updatedContent: (content: string) => void - editorInstanceRef: (instance: MemexEditorInstance) => void + onKeyDown?: React.KeyboardEventHandler + onContentUpdate: (markdownContent: string) => void + setEditorInstanceRef?: (instance: MemexEditorInstance) => void } const MemexEditor = (props: Props) => { @@ -53,22 +53,24 @@ const MemexEditor = (props: Props) => { emptyEditorClass: 'is-editor-empty', }), ], - content: props.comment, + content: marked.parse(props.markdownContent), onCreate: ({ editor }) => editor.commands.focus('end'), onUpdate: ({ editor }) => { const htmlContent = editor.getHTML() const markdownContent = turndownService.turndown(htmlContent) - props.updatedContent(markdownContent) + props.onContentUpdate(markdownContent) }, autofocus: true, - editorProps: { - handleDOMEvents: { - keydown: (view, event) => { - props.onKeyDown(event as any) - return true - }, - }, - }, + editorProps: props.onKeyDown + ? { + handleDOMEvents: { + keydown: (view, event) => { + props.onKeyDown(event as any) + return true + }, + }, + } + : undefined, }) const memexEditorRef = useRef() @@ -79,8 +81,8 @@ const MemexEditor = (props: Props) => { }, } - props.editorInstanceRef(memexEditorRef.current) - }) + props.setEditorInstanceRef?.(memexEditorRef.current) + }, [editor]) return } diff --git a/yarn.lock b/yarn.lock index 9ed0cd0b61..674c675158 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4634,6 +4634,11 @@ resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== +"@types/marked@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/marked/-/marked-4.0.0.tgz#2e7036d348adc7f5916946349596194b99eb4673" + integrity sha512-Zuz0vlQDfPuop4aFFWFdFTTpVmFqkwAQJ4Onxmgc2ZMxhgaO0UxEwWpz23uHXd9QhwsFB1BJBmWNjheZmqdBuQ== + "@types/mdast@^3.0.0", "@types/mdast@^3.0.3": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/mdast/-/mdast-3.0.3.tgz#2d7d671b1cd1ea3deb306ea75036c2a0407d2deb" From 8da4a6ded481d607378a74757c018ab075c41430 Mon Sep 17 00:00:00 2001 From: Jonathan Poltak Samosir Date: Mon, 15 Nov 2021 14:36:29 +0700 Subject: [PATCH 11/17] Disable stylelint rules for global tiptap editor overrides - apart from this, the styles seems to be all set up and being applied to the editor --- src/annotations/components/editor/styles.css | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/annotations/components/editor/styles.css b/src/annotations/components/editor/styles.css index 1f8b175cd3..b825905f09 100644 --- a/src/annotations/components/editor/styles.css +++ b/src/annotations/components/editor/styles.css @@ -1,3 +1,5 @@ +/* stylelint-disable declaration-no-important, selector-pseudo-class-no-unknown */ + :global .ProseMirror p.is-editor-empty:first-child::before { content: attr(data-placeholder); float: left; From 631aa802999d4c3618c84038c9e6f190c9fb71e9 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Nov 2021 09:56:00 +0000 Subject: [PATCH 12/17] fix heading shortcuts --- src/annotations/components/MarkdownHelp.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/annotations/components/MarkdownHelp.tsx b/src/annotations/components/MarkdownHelp.tsx index 7b60515004..94e00a583f 100644 --- a/src/annotations/components/MarkdownHelp.tsx +++ b/src/annotations/components/MarkdownHelp.tsx @@ -100,7 +100,7 @@ export class MarkdownHelp extends React.Component {

Heading 2

- # Heading 2 + ## Heading 2 {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+2 @@ -111,7 +111,7 @@ export class MarkdownHelp extends React.Component {

Heading 3

- # Heading 3 + ### Heading 3 {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+3 From 5f8babee1f6bc5b026a99a57d25b77c1895bf054 Mon Sep 17 00:00:00 2001 From: Jonathan Poltak Samosir Date: Mon, 15 Nov 2021 20:21:07 +0700 Subject: [PATCH 13/17] Fix broken in-editor KB shortcuts --- src/annotations/components/editor/editor.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx index e85b7c4b44..9e878d313d 100644 --- a/src/annotations/components/editor/editor.tsx +++ b/src/annotations/components/editor/editor.tsx @@ -65,8 +65,10 @@ const MemexEditor = (props: Props) => { ? { handleDOMEvents: { keydown: (view, event) => { - props.onKeyDown(event as any) - return true + // NOTE: this seems to be typed incorrectly + // removing the 'as any's will throw errors at you, + // but fixing them result in editor KB shortcuts stop working + return props.onKeyDown(event as any) as any }, }, } From 8381be3c8b09dcde7948d4a711424d5ab909c784 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Nov 2021 17:05:41 +0000 Subject: [PATCH 14/17] Add image support and selection bubble menu to editor to annotations --- external/@worldbrain/memex-common | 2 +- package.json | 1 + .../components/AnnotationCreate.tsx | 23 ++-- src/annotations/components/AnnotationEdit.tsx | 8 +- .../components/AnnotationEditable.tsx | 16 ++- src/annotations/components/editor/editor.tsx | 74 +++++++++- src/annotations/components/editor/styles.css | 128 ++++++++++-------- .../components/AnnotationsSidebar.tsx | 99 +++++++++----- yarn.lock | 5 + 9 files changed, 245 insertions(+), 111 deletions(-) diff --git a/external/@worldbrain/memex-common b/external/@worldbrain/memex-common index 49494c47f0..f2c5517bb3 160000 --- a/external/@worldbrain/memex-common +++ b/external/@worldbrain/memex-common @@ -1 +1 @@ -Subproject commit 49494c47f01dba2a1d168721b9e2a2670fdb9a5e +Subproject commit f2c5517bb3574365d3954eec1ccd7ea30f8fc0d4 diff --git a/package.json b/package.json index 676e109676..7499be5f32 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@tiptap/extension-code-block": "^2.0.0-beta.29", "@tiptap/extension-heading": "^2.0.0-beta.23", "@tiptap/extension-highlight": "^2.0.0-beta.30", + "@tiptap/extension-image": "^2.0.0-beta.24", "@tiptap/extension-link": "^2.0.0-beta.28", "@tiptap/extension-placeholder": "^2.0.0-beta.43", "@tiptap/extension-typography": "^2.0.0-beta.19", diff --git a/src/annotations/components/AnnotationCreate.tsx b/src/annotations/components/AnnotationCreate.tsx index 1c5fbd96a5..28e9a6d78f 100644 --- a/src/annotations/components/AnnotationCreate.tsx +++ b/src/annotations/components/AnnotationCreate.tsx @@ -41,6 +41,7 @@ export interface AnnotationCreateGeneralProps { tags: string[] onTagClick?: (tag: string) => void hoverState: NoteResultHoverState + toggleMarkdownHelp?: () => void } export interface Props @@ -62,6 +63,8 @@ export class AnnotationCreate extends React.Component // MarkdownPreviewAnnotationInsertMenu // >() + private annotCreateRef = React.createRef() + static defaultProps: Pick = { tags: [], hoverState: null, @@ -93,6 +96,7 @@ export class AnnotationCreate extends React.Component } private hideTagPicker = () => this.setState({ isTagPickerShown: false }) + private toggleMarkdownHelp = () => this.props.toggleMarkdownHelp private hideMarkdownHelp = () => this.setState({ isMarkdownHelpShown: false }) private handleCancel = () => this.props.onCancel() @@ -196,9 +200,7 @@ export class AnnotationCreate extends React.Component > - setPickerShown(!this.state.isMarkdownHelpShown) - } + onClick={() => this.props.toggleMarkdownHelp()} /> @@ -231,6 +233,9 @@ export class AnnotationCreate extends React.Component markdownContent={this.props.comment} setEditorInstanceRef={(editor) => (this.editor = editor)} placeholder={`Add private note. Save with ${AnnotationCreate.MOD_KEY}+enter (+shift to share)`} + toggleMarkdownHelp={() => { + this.props.toggleMarkdownHelp() + }} /> {this.props.comment !== '' && ( <> @@ -253,18 +258,6 @@ export class AnnotationCreate extends React.Component )} - {!this.state.isMarkdownHelpShown ? null : ( - - {/* setPickerShown(false)}>*/} - - {/**/} - - )}
) } diff --git a/src/annotations/components/AnnotationEdit.tsx b/src/annotations/components/AnnotationEdit.tsx index 65dba79db5..ec820c5dde 100644 --- a/src/annotations/components/AnnotationEdit.tsx +++ b/src/annotations/components/AnnotationEdit.tsx @@ -2,7 +2,7 @@ import * as React from 'react' import styled from 'styled-components' import { getKeyName } from 'src/util/os-specific-key-names' -import MemexEditor from './editor/editor' +import MemexEditor, { MemexEditorInstance } from './editor/editor' interface State { isMarkdownHelpShown: boolean @@ -16,6 +16,7 @@ export interface AnnotationEditEventProps { export interface AnnotationEditGeneralProps { comment: string + toggleMarkdownHelp?: () => void } export interface Props @@ -32,6 +33,8 @@ class AnnotationEdit extends React.Component { isMarkdownHelpShown: false, } + private editor: MemexEditorInstance + private saveEdit(shouldShare, isProtected) { this.props.onEditConfirm(shouldShare, isProtected) //AnnotationEditable.removeMarkdownHelp() @@ -70,6 +73,9 @@ class AnnotationEdit extends React.Component { } markdownContent={this.props.comment} onKeyDown={this.handleInputKeyDown} + toggleMarkdownHelp={() => { + this.props.toggleMarkdownHelp() + }} /> ) } diff --git a/src/annotations/components/AnnotationEditable.tsx b/src/annotations/components/AnnotationEditable.tsx index 74967c138c..26a91893ff 100644 --- a/src/annotations/components/AnnotationEditable.tsx +++ b/src/annotations/components/AnnotationEditable.tsx @@ -66,6 +66,7 @@ export interface AnnotationProps { renderTagsPickerForAnnotation?: (id: string) => JSX.Element renderCopyPasterForAnnotation?: (id: string) => JSX.Element renderShareMenuForAnnotation?: (id: string) => JSX.Element + toggleMarkdownHelp?: () => void } export interface AnnotationEditableEventProps { @@ -217,6 +218,9 @@ export default class AnnotationEditable extends React.Component { {...annotationEditDependencies} rows={2} comment={comment} + toggleMarkdownHelp={() => { + this.props.toggleMarkdownHelp() + }} /> ) } @@ -452,8 +456,10 @@ export default class AnnotationEditable extends React.Component { }} > - {this.renderHighlightBody()} - {this.renderNote()} + + {this.renderHighlightBody()} + {this.renderNote()} + void setEditorInstanceRef?: (instance: MemexEditorInstance) => void + toggleMarkdownHelp?: () => void } const MemexEditor = (props: Props) => { + const renderer = { + image(url) { + return ` + {'test'}/ + ` + }, + } + + marked.use({ renderer }) + const editor = useEditor({ extensions: [ StarterKit.configure({ @@ -52,9 +69,14 @@ const MemexEditor = (props: Props) => { placeholder: props.placeholder, emptyEditorClass: 'is-editor-empty', }), + Image.configure({ + inline: true, + }), ], content: marked.parse(props.markdownContent), - onCreate: ({ editor }) => editor.commands.focus('end'), + onCreate: ({ editor }) => { + editor.commands.focus('end') + }, onUpdate: ({ editor }) => { const htmlContent = editor.getHTML() const markdownContent = turndownService.turndown(htmlContent) @@ -86,7 +108,53 @@ const MemexEditor = (props: Props) => { props.setEditorInstanceRef?.(memexEditorRef.current) }, [editor]) - return + return ( + <> + + {editor && ( + + + + + + + )} + + + ) } export default MemexEditor diff --git a/src/annotations/components/editor/styles.css b/src/annotations/components/editor/styles.css index b825905f09..c7b384a6e7 100644 --- a/src/annotations/components/editor/styles.css +++ b/src/annotations/components/editor/styles.css @@ -49,6 +49,11 @@ margin-block-start: 0.5em; margin-block-end: 0.5em; line-height: 20px; + + & img { + max-width: fill-available; + height: auto; + } } & h1 { @@ -58,6 +63,11 @@ font-size: 18px; } + & img { + max-width: fill-available; + height: auto; + } + & h2 { margin-block-start: 1em; margin-block-end: 0.5em; @@ -122,76 +132,78 @@ & > *:last-child { margin-block-end: 0em; } +} - /* & p:first-child { - margin-block-start: 0em; - } - - & h1:first-child { - margin-block-start: 0em; - } - - & h2:first-child { - margin-block-start: 0em; - } - - & h3:first-child { - margin-block-start: 0em; - } - - & h4:first-child { - margin-block-start: 0em; - } - - & h5:first-child { - margin-block-start: 0em; - } - - & blockquote:first-child { - margin-block-start: 0em; - } - - & image:first-child { - margin-block-start: 0em; - } - - & pre:first-child { - margin-block-start: 0em; - } +:global .bubble-menu { + display: flex; + background-color: #2a2a2a; + padding: 0.2rem; + border-radius: 0.5rem; + font-family: sans-serif; + cursor: pointer; - & p:last-child { - margin-block-end: 0em; + & > * { + all: initial; + line-height: 20px; } - & h1:last-child { - margin-block-end: 0em; + & button { + border: none; + background: #2a2a2a; + color: #fff; + font-size: 0.85rem; + font-family: sans-serif; + font-weight: 500; + padding: 1px 0.2rem 0 0.2rem; + cursor: pointer; + + &:hover, + &.is-active { + opacity: 1; + color: #d0d0d0; + text-decoration: solid 1px underline; + } } +} - & h2:last-child { - margin-block-end: 0em; - } +:global .floating-menu { + display: flex; + padding: 0.2rem; + border-radius: 0.5rem; + font-family: sans-serif; - & h3:last-child { - margin-block-end: 0em; + & > * { + all: initial; + line-height: 20px; } - & h4:last-child { - margin-block-end: 0em; - } + & button { + border: none; + background: none; + font-size: 14px; + color: #a0a0a0; + font-weight: 500; + padding: 0 0.2rem; + font-family: sans-serif; + + &:hover, + &.is-active { + opacity: 1; + } - & h5:last-child { - margin-block-end: 0em; - } + &:focus { + text-decoration: underline 1px solid #a0a0a0; + } - & blockquote:last-child { - margin-block-end: 0em; + &.is-active { + color: #545454; + } } - & image:last-child { - margin-block-end: 0em; + & .NoNotePlaceholder { + font-size: 14px; + color: #818181; + margin-right: 10px; + margin-left: -5px; } - - & pre:last-child { - margin-block-end: 0em; - } */ } diff --git a/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx b/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx index a61a48e9b2..a489339809 100644 --- a/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx +++ b/src/sidebar/annotations-sidebar/components/AnnotationsSidebar.tsx @@ -22,6 +22,8 @@ import { AnnotationEditGeneralProps, AnnotationEditEventProps, } from 'src/annotations/components/AnnotationEdit' +import { HoverBox } from 'src/common-ui/components/design-library/HoverBox' +import MarkdownHelp from 'src/annotations/components/MarkdownHelp' import type { AnnotationSharingAccess } from 'src/content-sharing/ui/types' import type { SidebarContainerState } from '../containers/types' import { ExternalLink } from 'src/common-ui/components/design-library/actions/ExternalLink' @@ -70,6 +72,7 @@ export interface AnnotationsSidebarProps interface AnnotationsSidebarState { searchText?: string + isMarkdownHelpShown?: boolean } class AnnotationsSidebar extends React.Component< @@ -77,8 +80,12 @@ class AnnotationsSidebar extends React.Component< AnnotationsSidebarState > { private annotationCreateRef // TODO: Figure out how to properly type refs to onClickOutside HOCs + private annotationEditRef - state = { searchText: '' } + state = { + searchText: '', + isMarkdownHelpShown: false, + } componentDidMount() { document.addEventListener('keydown', this.onKeydown, false) @@ -90,6 +97,9 @@ class AnnotationsSidebar extends React.Component< focusCreateForm = () => this.annotationCreateRef?.getInstance()?.focus() + private toggleMarkdownHelp = () => + this.setState({ isMarkdownHelpShown: !this.state.isMarkdownHelpShown }) + private onKeydown = (e: KeyboardEvent) => { if (e.key === 'Escape') { this.props.onClickOutside(e as any) @@ -153,13 +163,24 @@ class AnnotationsSidebar extends React.Component< return ( - - (this.annotationCreateRef = ref)} - autoFocus - /> - + this.toggleMarkdownHelp()} + /> + {!this.state.isMarkdownHelpShown ? null : ( + + {/* setPickerShown(false)}>*/} + + {/**/} + + )} ) } @@ -373,30 +394,46 @@ class AnnotationsSidebar extends React.Component< const annots = this.props.annotations.map((annot, i) => { const footerDeps = this.props.bindAnnotationFooterEventProps(annot) return ( - + 0 + } + toggleMarkdownHelp={() => this.toggleMarkdownHelp()} + ref={(ref) => (this.annotationEditRef = ref)} + /> + {!this.state.isMarkdownHelpShown ? null : ( + (this.annotationEditRef = ref)} + > + {/* setPickerShown(false)}>*/} + + {/**/} + )} - annotationFooterDependencies={footerDeps} - isClickable={ - this.props.theme.canClickAnnotations && - annot.body?.length > 0 - } - /> + ) }) diff --git a/yarn.lock b/yarn.lock index 674c675158..bc8840e38e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4296,6 +4296,11 @@ dependencies: prosemirror-state "^1.3.4" +"@tiptap/extension-image@^2.0.0-beta.24": + version "2.0.0-beta.24" + resolved "https://registry.yarnpkg.com/@tiptap/extension-image/-/extension-image-2.0.0-beta.24.tgz#1010676f79925cbe11a44b6d8eee1251910fbc1d" + integrity sha512-7oiX/Ovj9WN4xTBqWbQWd4H3SUO2eNzOiKHebVo3eqWG8NxzOGfuU0iRCENtEa7vTiRrFgyeBotneMALDpDnTQ== + "@tiptap/extension-italic@^2.0.0-beta.24": version "2.0.0-beta.24" resolved "https://registry.yarnpkg.com/@tiptap/extension-italic/-/extension-italic-2.0.0-beta.24.tgz#0a08d06dbd8dbf10f18ed17f019aa42d7ac9dbe0" From 51aa44ad0b0e3160c82d16c60b733d09e1cb73dd Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Nov 2021 20:41:44 +0000 Subject: [PATCH 15/17] Make YouTube timestamp insert work with keyboard shortcuts --- src/annotations/components/MarkdownHelp.tsx | 38 ++++++++++++++----- .../components/editor/YoutubeInsert.tsx | 19 ++++++++++ src/annotations/components/editor/editor.tsx | 25 +++++++++++- 3 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 src/annotations/components/editor/YoutubeInsert.tsx diff --git a/src/annotations/components/MarkdownHelp.tsx b/src/annotations/components/MarkdownHelp.tsx index 94e00a583f..045121f18b 100644 --- a/src/annotations/components/MarkdownHelp.tsx +++ b/src/annotations/components/MarkdownHelp.tsx @@ -22,7 +22,7 @@ export class MarkdownHelp extends React.Component { **bold** - {MarkdownHelp.MOD_KEY}+b + {MarkdownHelp.MOD_KEY}+B @@ -31,7 +31,7 @@ export class MarkdownHelp extends React.Component { *italic* - {MarkdownHelp.MOD_KEY}+i + {MarkdownHelp.MOD_KEY}+I @@ -45,7 +45,19 @@ export class MarkdownHelp extends React.Component { Highlight text and paste url - {MarkdownHelp.MOD_KEY}+v + {MarkdownHelp.MOD_KEY}+V + + + + YouTube timestamp + + + [1:15] + + + + In Editor:
+ {MarkdownHelp.MOD_KEY}+Y @@ -81,7 +93,7 @@ export class MarkdownHelp extends React.Component { > this is the quote - {MarkdownHelp.MOD_KEY}+shift+B + {MarkdownHelp.MOD_KEY}+shift+b @@ -125,7 +137,7 @@ export class MarkdownHelp extends React.Component { `inline Code` - {MarkdownHelp.MOD_KEY}+shift+e + {MarkdownHelp.MOD_KEY}+shift+E @@ -139,7 +151,7 @@ export class MarkdownHelp extends React.Component { ```code blocks``` - {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+c + {MarkdownHelp.MOD_KEY}+{MarkdownHelp.ALT_KEY}+C @@ -150,7 +162,7 @@ export class MarkdownHelp extends React.Component { ~~Strikethrough~~ - {MarkdownHelp.MOD_KEY}+shift+x + {MarkdownHelp.MOD_KEY}+shift+X @@ -184,6 +196,14 @@ const TutorialTable = styled.table` display: flex; justify-content: flex-end; width: 50px; + font-size: 14px; + white-space: nowrap; + display: flex; + align-items: center; + + & span { + margin-right: 5px; + } } & code { @@ -197,11 +217,11 @@ const TutorialTable = styled.table` } & ul { - margin-inline-start: -30px; + margin-inline-start: -20px; } & ol { - margin-inline-start: -30px; + margin-inline-start: -20px; } & h1 { diff --git a/src/annotations/components/editor/YoutubeInsert.tsx b/src/annotations/components/editor/YoutubeInsert.tsx new file mode 100644 index 0000000000..c593878a70 --- /dev/null +++ b/src/annotations/components/editor/YoutubeInsert.tsx @@ -0,0 +1,19 @@ +import { extractIdFromUrl, isUrlYTVideo } from 'src/util/youtube-url' + +export const GetYoutubeTimeStamp = () => { + const videoEl = document.querySelector('.video-stream') + + const timestampSecs = Math.trunc(videoEl?.currentTime ?? 0) + const humanTimestamp = `${Math.floor(timestampSecs / 60)}:${( + timestampSecs % 60 + ) + .toString() + .padStart(2, '0')}` + + const videoId = extractIdFromUrl(document.location.href) + const videoURLwithTime = `https://youtu.be/${videoId}?t=${timestampSecs}` + + const YoutubeData = [videoURLwithTime, humanTimestamp] + + return YoutubeData +} diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx index a1aa394238..4befcef6cb 100644 --- a/src/annotations/components/editor/editor.tsx +++ b/src/annotations/components/editor/editor.tsx @@ -14,6 +14,8 @@ import Link from '@tiptap/extension-link' import CodeBlock from '@tiptap/extension-code-block' import Heading from '@tiptap/extension-heading' import Image from '@tiptap/extension-image' +import { nodeInputRule } from '@tiptap/core' +import { GetYoutubeTimeStamp } from './YoutubeInsert' import './styles.css' @@ -44,9 +46,27 @@ const MemexEditor = (props: Props) => { ` }, } - marked.use({ renderer }) + const inputRegex = '/YT' + + const InsertYoutubeLink = Link.extend({ + addKeyboardShortcuts() { + return { + // ↓ your new keyboard shortcut + 'Mod-y': () => + this.editor + .chain() + .insertContent( + `${ + GetYoutubeTimeStamp()[1] + }`, + ) + .run(), + } + }, + }) + const editor = useEditor({ extensions: [ StarterKit.configure({ @@ -54,6 +74,7 @@ const MemexEditor = (props: Props) => { heading: false, }), Typography, + InsertYoutubeLink, CodeBlock.configure({ HTMLAttributes: { class: 'CodeBlock', @@ -76,6 +97,8 @@ const MemexEditor = (props: Props) => { content: marked.parse(props.markdownContent), onCreate: ({ editor }) => { editor.commands.focus('end') + console.log(getTextToInsert()[1]) + console.log(getTextToInsert()[0]) }, onUpdate: ({ editor }) => { const htmlContent = editor.getHTML() From 1d7e345308060786c150755e4fb5ee76b51f2661 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Nov 2021 20:58:05 +0000 Subject: [PATCH 16/17] Some clean up from old attempts of bringing youtube timestamps --- external/@worldbrain/memex-common | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/external/@worldbrain/memex-common b/external/@worldbrain/memex-common index f2c5517bb3..0897212463 160000 --- a/external/@worldbrain/memex-common +++ b/external/@worldbrain/memex-common @@ -1 +1 @@ -Subproject commit f2c5517bb3574365d3954eec1ccd7ea30f8fc0d4 +Subproject commit 0897212463ff6688fc5a7d27d5cf8673b99ecbb3 From c0445cfb92f1290945c4fc7bdbd1fbe23c27a279 Mon Sep 17 00:00:00 2001 From: Oliver Date: Mon, 15 Nov 2021 20:58:27 +0000 Subject: [PATCH 17/17] pt2: Some clean up from old attempts of bringing youtube timestamps --- src/annotations/components/editor/editor.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/annotations/components/editor/editor.tsx b/src/annotations/components/editor/editor.tsx index 4befcef6cb..e8f924b375 100644 --- a/src/annotations/components/editor/editor.tsx +++ b/src/annotations/components/editor/editor.tsx @@ -14,7 +14,6 @@ import Link from '@tiptap/extension-link' import CodeBlock from '@tiptap/extension-code-block' import Heading from '@tiptap/extension-heading' import Image from '@tiptap/extension-image' -import { nodeInputRule } from '@tiptap/core' import { GetYoutubeTimeStamp } from './YoutubeInsert' import './styles.css' @@ -42,14 +41,12 @@ const MemexEditor = (props: Props) => { const renderer = { image(url) { return ` - {'test'}/ + {'test'}/ ` }, } marked.use({ renderer }) - const inputRegex = '/YT' - const InsertYoutubeLink = Link.extend({ addKeyboardShortcuts() { return {