diff --git a/src/components/Editor/components/Editor.tsx b/src/components/Editor/components/Editor.tsx
index 9b9a5415..584fa0ea 100644
--- a/src/components/Editor/components/Editor.tsx
+++ b/src/components/Editor/components/Editor.tsx
@@ -1,9 +1,8 @@
import type { EditorView } from 'prosemirror-view'
import type { EditorState } from 'prosemirror-state'
-import { useState } from '../store'
-import { ProseMirror } from '../components/ProseMirror'
+import { useState } from '../store/context'
+import { ProseMirror } from './ProseMirror'
import '../styles/Editor.scss'
-import type { ProseMirrorExtension, ProseMirrorState } from '../prosemirror/helpers'
export const Editor = () => {
const [store, ctrl] = useState()
@@ -23,9 +22,9 @@ export const Editor = () => {
// eslint-disable-next-line solid/no-react-specific-props
className="editor"
style={style()}
- editorView={store.editorView as EditorView}
- text={store.text as ProseMirrorState}
- extensions={store.extensions as ProseMirrorExtension[]}
+ editorView={store.editorView}
+ text={store.text}
+ extensions={store.extensions}
onInit={onInit}
onReconfigure={onReconfigure}
onChange={onChange}
diff --git a/src/components/Editor/components/Error.tsx b/src/components/Editor/components/Error.tsx
index e53d2abe..106dce79 100644
--- a/src/components/Editor/components/Error.tsx
+++ b/src/components/Editor/components/Error.tsx
@@ -1,5 +1,5 @@
import { Switch, Match } from 'solid-js'
-import { useState } from '../store'
+import { useState } from '../store/context'
import '../styles/Button.scss'
export default () => {
@@ -12,8 +12,8 @@ export default () => {
-
-
+
+
)
@@ -48,8 +48,8 @@ const Other = () => {
const onClick = () => ctrl.discard()
const getMessage = () => {
- const { error } = store.error.props as any
- return typeof error === 'string' ? error : error.message
+ const err = (store.error.props as any).error
+ return typeof err === 'string' ? err : err.message
}
return (
diff --git a/src/components/Editor/components/Layout.tsx b/src/components/Editor/components/Layout.tsx
index a7059887..f8fe6a3b 100644
--- a/src/components/Editor/components/Layout.tsx
+++ b/src/components/Editor/components/Layout.tsx
@@ -1,8 +1,9 @@
-import type { Config } from '../store'
+import type { JSX } from 'solid-js/jsx-runtime'
+import type { Config } from '../store/context'
import '../styles/Layout.scss'
export type Styled = {
- children: any
+ children: JSX.Element
config?: Config
'data-testid'?: string
onClick?: () => void
diff --git a/src/components/Editor/components/ProseMirror.tsx b/src/components/Editor/components/ProseMirror.tsx
index f384a2ed..b85af777 100644
--- a/src/components/Editor/components/ProseMirror.tsx
+++ b/src/components/Editor/components/ProseMirror.tsx
@@ -1,16 +1,16 @@
-import { EditorState, type Transaction } from 'prosemirror-state'
-import { EditorView } from 'prosemirror-view'
-import { unwrap } from 'solid-js/store'
import { createEffect, untrack } from 'solid-js'
-import { createEditorState } from '../prosemirror'
-import type { ProseMirrorState, ProseMirrorExtension } from '../prosemirror/helpers'
+import { Store, unwrap } from 'solid-js/store'
+import { EditorState, EditorStateConfig, Transaction } from 'prosemirror-state'
+import { EditorView } from 'prosemirror-view'
+import { Schema } from 'prosemirror-model'
+import type { NodeViewFn, ProseMirrorExtension, ProseMirrorState } from '../prosemirror/helpers'
interface Props {
style?: string
className?: string
- text?: ProseMirrorState
- editorView?: EditorView
- extensions?: ProseMirrorExtension[]
+ text?: Store
+ editorView?: Store
+ extensions?: Store
onInit: (s: EditorState, v: EditorView) => void
onReconfigure: (s: EditorState) => void
onChange: (s: EditorState) => void
@@ -19,6 +19,7 @@ interface Props {
export const ProseMirror = (props: Props) => {
let editorRef: HTMLDivElement
const editorView = () => untrack(() => unwrap(props.editorView))
+
const dispatchTransaction = (tr: Transaction) => {
if (!editorView()) return
const newState = editorView().state.apply(tr)
@@ -28,10 +29,10 @@ export const ProseMirror = (props: Props) => {
}
createEffect(
- (state: [EditorState, ProseMirrorExtension[]]) => {
- const [prevText, prevExtensions] = state
+ (payload: [EditorState, ProseMirrorExtension[]]) => {
+ const [prevText, prevExtensions] = payload
const text = unwrap(props.text)
- const extensions = unwrap(props.extensions)
+ const extensions: ProseMirrorExtension[] = unwrap(props.extensions)
if (!text || !extensions?.length) {
return [text, extensions]
}
@@ -61,3 +62,46 @@ export const ProseMirror = (props: Props) => {
return
}
+
+const createEditorState = (
+ text: ProseMirrorState,
+ extensions: ProseMirrorExtension[],
+ prevText?: EditorState
+): {
+ editorState: EditorState
+ nodeViews: { [key: string]: NodeViewFn }
+} => {
+ const reconfigure = text instanceof EditorState && prevText?.schema
+ let schemaSpec = { nodes: {} }
+ let nodeViews = {}
+ let plugins = []
+
+ for (const extension of extensions) {
+ if (extension.schema) {
+ schemaSpec = extension.schema(schemaSpec)
+ }
+
+ if (extension.nodeViews) {
+ nodeViews = { ...nodeViews, ...extension.nodeViews }
+ }
+ }
+
+ const schema = reconfigure ? prevText.schema : new Schema(schemaSpec)
+ for (const extension of extensions) {
+ if (extension.plugins) {
+ plugins = extension.plugins(plugins, schema)
+ }
+ }
+
+ let editorState: EditorState
+ if (reconfigure) {
+ editorState = text.reconfigure({ schema, plugins } as EditorStateConfig)
+ } else if (text instanceof EditorState) {
+ editorState = EditorState.fromJSON({ schema, plugins }, text.toJSON())
+ } else if (text) {
+ console.debug(text)
+ editorState = EditorState.fromJSON({ schema, plugins }, text)
+ }
+
+ return { editorState, nodeViews }
+}
diff --git a/src/components/Editor/components/Sidebar.tsx b/src/components/Editor/components/Sidebar.tsx
index 68082ea0..5c81ba6c 100644
--- a/src/components/Editor/components/Sidebar.tsx
+++ b/src/components/Editor/components/Sidebar.tsx
@@ -1,14 +1,12 @@
-import { Show, createEffect, createSignal, onCleanup, For } from 'solid-js'
+import { For, Show, createEffect, createSignal, onCleanup, onMount } from 'solid-js'
import { unwrap } from 'solid-js/store'
import { undo, redo } from 'prosemirror-history'
-import { useState } from '../store'
+import { Draft, useState /*, Config, PrettierConfig */ } from '../store/context'
+import * as remote from '../remote'
+import { isEmpty /*, isInitialized*/ } from '../prosemirror/helpers'
import type { Styled } from './Layout'
-
import '../styles/Sidebar.scss'
-import { router } from '../../../stores/router'
import { t } from '../../../utils/intl'
-import { isEmpty } from '../prosemirror/helpers'
-import type { EditorState } from 'prosemirror-state'
const Off = (props) =>
@@ -29,23 +27,22 @@ const Link = (
)
-const mod = 'Ctrl'
const Keys = (props) => (
- {(k: string) => {k}}
+ {(k: Element) => {k}}
)
-interface SidebarProps {
- error?: string
-}
-
-// eslint-disable-next-line sonarjs/cognitive-complexity
-export const Sidebar = (_props: SidebarProps) => {
+export const Sidebar = () => {
+ const [isMac, setIsMac] = createSignal(false)
+ onMount(() => setIsMac(window?.navigator.platform.includes('Mac')))
+ // eslint-disable-next-line unicorn/consistent-function-scoping
+ // const isDark = () => window.matchMedia('(prefers-color-scheme: dark)').matches
+ const mod = isMac() ? 'Cmd' : 'Ctrl'
+ // const alt = isMac() ? 'Cmd' : 'Alt'
const [store, ctrl] = useState()
const [lastAction, setLastAction] = createSignal()
const toggleTheme = () => {
- // TODO: use dark/light toggle somewhere
document.body.classList.toggle('dark')
ctrl.updateConfig({ theme: document.body.className })
}
@@ -58,20 +55,51 @@ export const Sidebar = (_props: SidebarProps) => {
}
const editorView = () => unwrap(store.editorView)
const onToggleMarkdown = () => ctrl.toggleMarkdown()
+ const onOpenDraft = (draft: Draft) => ctrl.openDraft(unwrap(draft))
const collabUsers = () => store.collab?.y?.provider.awareness.meta.size ?? 0
const onUndo = () => undo(editorView().state, editorView().dispatch)
const onRedo = () => redo(editorView().state, editorView().dispatch)
- const onNew = () => ctrl.newFile()
+ const onCopyAllAsMd = () =>
+ remote.copyAllAsMarkdown(editorView().state).then(() => setLastAction('copy-md'))
const onDiscard = () => ctrl.discard()
const [isHidden, setIsHidden] = createSignal()
- // eslint-disable-next-line unicorn/consistent-function-scoping
- const onHistory = () => {
- console.log('[editor.sidebar] implement history handling')
- router.open('/create/settings')
- }
const toggleSidebar = () => setIsHidden(!isHidden())
toggleSidebar()
+ // eslint-disable-next-line sonarjs/cognitive-complexity
+ const DraftLink = (p: { draft: Draft }) => {
+ const length = 100
+ let content = ''
+ const getContent = (node: any) => {
+ if (node.text) content += node.text
+ if (content.length > length) {
+ content = content.slice(0, Math.max(0, length)) + '...'
+ return content
+ }
+
+ if (node.content) {
+ for (const child of node.content) {
+ if (content.length >= length) break
+ content = getContent(child)
+ }
+ }
+
+ return content
+ }
+
+ const text = () =>
+ p.draft.path
+ ? p.draft.path.slice(Math.max(0, p.draft.path.length - length))
+ : getContent(p.draft.text?.doc)
+
+ return (
+ // eslint-disable-next-line solid/no-react-specific-props
+ onOpenDraft(p.draft)} data-testid="open">
+ {text()} {p.draft.path && '📎'}
+
+ )
+ }
+
const onCollab = () => {
const state = unwrap(store)
store.collab?.started ? ctrl.stopCollab(state) : ctrl.startCollab(state)
@@ -88,19 +116,11 @@ export const Sidebar = (_props: SidebarProps) => {
}, 1000)
onCleanup(() => clearTimeout(id))
})
- const discardText = () => {
- if (store.path) {
- return t('Close')
- } else if (store.drafts.length > 0 && isEmpty(store.text as EditorState)) {
- return t('Delete')
- } else {
- return t('Clear')
- }
- }
+
return (