diff --git a/packages/web/src/javascripts/Components/SuperEditor/BlocksEditor.tsx b/packages/web/src/javascripts/Components/SuperEditor/BlocksEditor.tsx index bab70ab1c..81b39e7d6 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/BlocksEditor.tsx +++ b/packages/web/src/javascripts/Components/SuperEditor/BlocksEditor.tsx @@ -27,7 +27,7 @@ import { RemoveBrokenTablesPlugin } from './Plugins/TablePlugin' import TableActionMenuPlugin from './Plugins/TableCellActionMenuPlugin' import ToolbarPlugin from './Plugins/ToolbarPlugin/ToolbarPlugin' import { useMediaQuery, MutuallyExclusiveMediaQueryBreakpoints } from '@/Hooks/useMediaQuery' -import { CheckListPlugin } from './Plugins/CheckListPlugin' +import { CheckListPlugin } from './Plugins/List/CheckListPlugin' type BlocksEditorProps = { onChange?: (value: string, preview: string) => void diff --git a/packages/web/src/javascripts/Components/SuperEditor/Lexical/Nodes/AllNodes.ts b/packages/web/src/javascripts/Components/SuperEditor/Lexical/Nodes/AllNodes.ts index 738a82b4c..d6ed373d2 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Lexical/Nodes/AllNodes.ts +++ b/packages/web/src/javascripts/Components/SuperEditor/Lexical/Nodes/AllNodes.ts @@ -16,8 +16,10 @@ import { FileNode } from '../../Plugins/EncryptedFilePlugin/Nodes/FileNode' import { BubbleNode } from '../../Plugins/ItemBubblePlugin/Nodes/BubbleNode' import { RemoteImageNode } from '../../Plugins/RemoteImagePlugin/RemoteImageNode' import { InlineFileNode } from '../../Plugins/InlineFilePlugin/InlineFileNode' +import { CreateEditorArgs } from 'lexical' +import { ListHTMLExportNode } from '../../Plugins/List/ListHTMLExportNode' -export const BlockEditorNodes = [ +const CommonNodes = [ AutoLinkNode, CodeHighlightNode, CodeNode, @@ -29,7 +31,6 @@ export const BlockEditorNodes = [ HorizontalRuleNode, LinkNode, ListItemNode, - ListNode, MarkNode, OverflowNode, QuoteNode, @@ -43,3 +44,15 @@ export const BlockEditorNodes = [ RemoteImageNode, InlineFileNode, ] + +export const BlockEditorNodes = [...CommonNodes, ListNode] +export const HTMLExportNodes: CreateEditorArgs['nodes'] = [ + ...CommonNodes, + ListHTMLExportNode, + { + replace: ListNode, + with(node) { + return new ListHTMLExportNode(node.getListType(), node.getStart()) + }, + }, +] diff --git a/packages/web/src/javascripts/Components/SuperEditor/Lexical/Theme/editor.scss b/packages/web/src/javascripts/Components/SuperEditor/Lexical/Theme/editor.scss index e42d99763..2cb5e8152 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Lexical/Theme/editor.scss +++ b/packages/web/src/javascripts/Components/SuperEditor/Lexical/Theme/editor.scss @@ -1,3 +1,5 @@ +@import 'lists'; + .Lexical__ltr { text-align: left; } @@ -163,70 +165,6 @@ box-shadow: 0 0 5px rgba(0, 0, 0, 0.4); border-radius: 3px; } -.Lexical__tableAddColumns { - position: absolute; - top: 0; - width: 20px; - background-color: #eee; - height: 100%; - right: 0; - animation: table-controls 0.2s ease; - border: 0; - cursor: pointer; -} -.Lexical__tableAddColumns:after { - background-image: url(#{$blocks-editor-icons-path}/plus.svg); - background-size: contain; - background-position: center; - background-repeat: no-repeat; - display: block; - content: ' '; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - opacity: 0.4; -} -.Lexical__tableAddColumns:hover { - background-color: #c9dbf0; -} -.Lexical__tableAddRows { - position: absolute; - bottom: -25px; - width: calc(100% - 25px); - background-color: #eee; - height: 20px; - left: 0; - animation: table-controls 0.2s ease; - border: 0; - cursor: pointer; -} -.Lexical__tableAddRows:after { - background-image: url(#{$blocks-editor-icons-path}/plus.svg); - background-size: contain; - background-position: center; - background-repeat: no-repeat; - display: block; - content: ' '; - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; - opacity: 0.4; -} -.Lexical__tableAddRows:hover { - background-color: #c9dbf0; -} -@keyframes table-controls { - 0% { - opacity: 0; - } - 100% { - opacity: 1; - } -} .Lexical__tableCellResizeRuler { display: block; position: absolute; @@ -261,125 +199,6 @@ display: inline; background-color: #ffbbbb !important; } -:root { - --lexical-ordered-list-left-margin: 16px; -} -.monospace-font { - --lexical-ordered-list-left-margin: 42px; -} -@for $i from 1 through 5 { - .Lexical__ol#{$i} { - padding: 0; - margin: 0; - margin-left: var(--lexical-ordered-list-left-margin); - list-style-position: outside; - - &.Lexical__rtl { - margin-left: 0; - margin-right: var(--lexical-ordered-list-left-margin); - } - } -} -.Lexical__ol2 { - list-style-type: upper-alpha; -} -.Lexical__ol3 { - list-style-type: lower-alpha; -} -.Lexical__ol4 { - list-style-type: upper-roman; -} -.Lexical__ol5 { - list-style-type: lower-roman; -} -.Lexical__ul { - padding: 0; - margin: 0; - margin-left: 16px; - list-style-position: outside; - - &.Lexical__rtl { - margin-left: 0; - margin-right: 16px; - } -} -.Lexical__checkList { - margin-left: 0; - .Lexical__nestedListItem & { - margin-left: 16px; - } -} -.Lexical__listItem { - margin: 0 0px; -} -.Lexical__listItemChecked, -.Lexical__listItemUnchecked { - position: relative; - padding-left: 24px; - padding-right: 24px; - list-style-type: none; - outline: none; - vertical-align: middle; -} -.Lexical__listItemChecked { - text-decoration: line-through; - opacity: 0.4; -} -.Lexical__listItemUnchecked:before, -.Lexical__listItemChecked:before { - content: ''; - width: 16px; - height: 16px; - left: 0; - top: 7px; - cursor: pointer; - background-size: cover; - position: absolute; -} -.Lexical__listItemUnchecked[dir='rtl']:before, -.Lexical__listItemChecked[dir='rtl']:before { - left: auto; - right: 0; -} -.Lexical__listItemUnchecked:focus:before, -.Lexical__listItemChecked:focus:before { - box-shadow: 0 0 0 2px #a6cdfe; - border-radius: 2px; -} -.Lexical__listItemUnchecked:before { - border: 1px solid #999; - border-radius: 2px; -} -.Lexical__listItemChecked:before { - border: 1px solid var(--sn-stylekit-info-color); - border-radius: 2px; - background-color: var(--sn-stylekit-info-color); - background-repeat: no-repeat; -} -.Lexical__listItemChecked:after { - content: ''; - cursor: pointer; - border-color: var(--sn-stylekit-info-contrast-color); - border-style: solid; - position: absolute; - display: block; - top: 9px; - width: 5px; - left: 6px; - height: 10px; - transform: rotate(45deg); - border-width: 0 2px 2px 0; -} -.Lexical__nestedListItem { - list-style-type: none; - &.Lexical__listItemUnchecked { - padding-left: 0; - } -} -.Lexical__nestedListItem:before, -.Lexical__nestedListItem:after { - display: none; -} .Lexical__tokenComment { color: slategray; } diff --git a/packages/web/src/javascripts/Components/SuperEditor/Lexical/Theme/lists.scss b/packages/web/src/javascripts/Components/SuperEditor/Lexical/Theme/lists.scss new file mode 100644 index 000000000..88d798989 --- /dev/null +++ b/packages/web/src/javascripts/Components/SuperEditor/Lexical/Theme/lists.scss @@ -0,0 +1,119 @@ +:root { + --lexical-ordered-list-left-margin: 16px; +} +.monospace-font { + --lexical-ordered-list-left-margin: 42px; +} +@for $i from 1 through 5 { + .Lexical__ol#{$i} { + padding: 0; + margin: 0; + margin-left: var(--lexical-ordered-list-left-margin); + list-style-position: outside; + + &.Lexical__rtl { + margin-left: 0; + margin-right: var(--lexical-ordered-list-left-margin); + } + } +} +.Lexical__ol2 { + list-style-type: upper-alpha; +} +.Lexical__ol3 { + list-style-type: lower-alpha; +} +.Lexical__ol4 { + list-style-type: upper-roman; +} +.Lexical__ol5 { + list-style-type: lower-roman; +} +.Lexical__ul { + padding: 0; + margin: 0; + margin-left: 16px; + list-style-position: outside; + + &.Lexical__rtl { + margin-left: 0; + margin-right: 16px; + } +} +.Lexical__checkList { + margin-left: 0; + .Lexical__nestedListItem & { + margin-left: 16px; + } +} +.Lexical__listItem { + margin: 0 0px; +} +.Lexical__listItemChecked, +.Lexical__listItemUnchecked { + position: relative; + padding-left: 24px; + padding-right: 24px; + list-style-type: none; + outline: none; + vertical-align: middle; +} +.Lexical__listItemChecked { + text-decoration: line-through; + opacity: 0.4; +} +.Lexical__listItemUnchecked:before, +.Lexical__listItemChecked:before { + content: ''; + width: 16px; + height: 16px; + left: 0; + top: 7px; + cursor: pointer; + background-size: cover; + position: absolute; +} +.Lexical__listItemUnchecked[dir='rtl']:before, +.Lexical__listItemChecked[dir='rtl']:before { + left: auto; + right: 0; +} +.Lexical__listItemUnchecked:focus:before, +.Lexical__listItemChecked:focus:before { + box-shadow: 0 0 0 2px #a6cdfe; + border-radius: 2px; +} +.Lexical__listItemUnchecked:before { + border: 1px solid #999; + border-radius: 2px; +} +.Lexical__listItemChecked:before { + border: 1px solid var(--sn-stylekit-info-color); + border-radius: 2px; + background-color: var(--sn-stylekit-info-color); + background-repeat: no-repeat; +} +.Lexical__listItemChecked:after { + content: ''; + cursor: pointer; + border-color: var(--sn-stylekit-info-contrast-color); + border-style: solid; + position: absolute; + display: block; + top: 9px; + width: 5px; + left: 6px; + height: 10px; + transform: rotate(45deg); + border-width: 0 2px 2px 0; +} +.Lexical__nestedListItem { + list-style-type: none; + &.Lexical__listItemUnchecked { + padding-left: 0; + } +} +.Lexical__nestedListItem:before, +.Lexical__nestedListItem:after { + display: none; +} diff --git a/packages/web/src/javascripts/Components/SuperEditor/Plugins/ExportPlugin/ExportPlugin.ts b/packages/web/src/javascripts/Components/SuperEditor/Plugins/ExportPlugin/ExportPlugin.ts index 0722f5351..d4cdce2fa 100644 --- a/packages/web/src/javascripts/Components/SuperEditor/Plugins/ExportPlugin/ExportPlugin.ts +++ b/packages/web/src/javascripts/Components/SuperEditor/Plugins/ExportPlugin/ExportPlugin.ts @@ -13,6 +13,38 @@ import { useCallback, useEffect, useRef } from 'react' import { useCommandService } from '@/Components/CommandProvider' import { HeadlessSuperConverter } from '../../Tools/HeadlessSuperConverter' +// @ts-expect-error Using inline loaders to load CSS as string +import superEditorCSS from '!css-loader!sass-loader!../../Lexical/Theme/editor.scss' +// @ts-expect-error Using inline loaders to load CSS as string +import snColorsCSS from '!css-loader!sass-loader!@standardnotes/styles/src/Styles/_colors.scss' + +const html = (title: string, content: string) => ` + + +
+ +