postmerge, unstore drafts

This commit is contained in:
tonyrewin 2022-10-19 18:56:29 +03:00
parent c652c4ee84
commit 634c8ae59c
12 changed files with 29 additions and 29 deletions

View File

@ -9,7 +9,6 @@ export const Editor = () => {
const onInit = (text: EditorState, editorView: EditorView) => ctrl.setState({ editorView, text }) const onInit = (text: EditorState, editorView: EditorView) => ctrl.setState({ editorView, text })
const onReconfigure = (text: EditorState) => ctrl.setState({ text }) const onReconfigure = (text: EditorState) => ctrl.setState({ text })
const onChange = (text: EditorState) => ctrl.setState({ text, lastModified: new Date() }) const onChange = (text: EditorState) => ctrl.setState({ text, lastModified: new Date() })
// const editorCss = (config) => css``
const style = () => { const style = () => {
if (store.error) { if (store.error) {
return `display: none;` return `display: none;`

View File

@ -1,6 +1,7 @@
import { Switch, Match } from 'solid-js' import { Switch, Match } from 'solid-js'
import { useState } from '../store/context'
import '../styles/Button.scss' import '../styles/Button.scss'
import { ErrorObject, useState } from '../store/context'
import { t } from '../../../utils/intl'
export default () => { export default () => {
const [store] = useState() const [store] = useState()
@ -28,15 +29,13 @@ const InvalidState = (props: { title: string }) => {
<div class="container"> <div class="container">
<h1>{props.title}</h1> <h1>{props.title}</h1>
<p> <p>
There is an error with the editor state. This is probably due to an old version in which the data {t('Editing conflict, please copy your notes and refresh page')}
structure has changed. Automatic data migrations may be supported in the future. To fix this now,
you can copy important notes from below, clean the state and paste it again.
</p> </p>
<pre> <pre>
<code>{JSON.stringify(store.error.props)}</code> <code>{JSON.stringify(store.error.props)}</code>
</pre> </pre>
<button class="primary" onClick={onClick}> <button class="primary" onClick={onClick}>
Clean {t('Clean')}
</button> </button>
</div> </div>
</div> </div>
@ -48,7 +47,7 @@ const Other = () => {
const onClick = () => ctrl.discard() const onClick = () => ctrl.discard()
const getMessage = () => { const getMessage = () => {
const err = (store.error.props as any).error const err = (store.error.props as ErrorObject['props']).error
return typeof err === 'string' ? err : err.message return typeof err === 'string' ? err : err.message
} }

View File

@ -7,7 +7,7 @@ export type Styled = {
config?: Config config?: Config
'data-testid'?: string 'data-testid'?: string
onClick?: () => void onClick?: () => void
onMouseEnter?: (e: any) => void onMouseEnter?: (ev: MouseEvent) => void
} }
export const Layout = (props: Styled) => { export const Layout = (props: Styled) => {

View File

@ -1,7 +1,7 @@
import { For, Show, createEffect, createSignal, onCleanup, onMount } from 'solid-js' import { For, Show, createEffect, createSignal, onCleanup, onMount } from 'solid-js'
import { unwrap } from 'solid-js/store' import { unwrap } from 'solid-js/store'
import { undo, redo } from 'prosemirror-history' import { undo, redo } from 'prosemirror-history'
import { Draft, useState /*, Config, PrettierConfig */ } from '../store/context' import { Draft, useState } from '../store/context'
import * as remote from '../remote' import * as remote from '../remote'
import { isEmpty /*, isInitialized*/ } from '../prosemirror/helpers' import { isEmpty /*, isInitialized*/ } from '../prosemirror/helpers'
import type { Styled } from './Layout' import type { Styled } from './Layout'

View File

@ -122,7 +122,7 @@ export const markdownSerializer = new MarkdownSerializer(
} }
) )
function listIsTight(tokens: any, idx: number) { function listIsTight(tokens: any[], idx: number) {
let i = idx let i = idx
while (++i < tokens.length) { while (++i < tokens.length) {
if (tokens[i].type !== 'list_item_open') return tokens[i].hidden if (tokens[i].type !== 'list_item_open') return tokens[i].hidden

View File

@ -1,8 +1,8 @@
import { DOMSerializer, Node as ProsemirrorNode, NodeType, Schema } from 'prosemirror-model' import { DOMSerializer, Node as ProsemirrorNode, NodeType, Schema } from 'prosemirror-model'
import type { EditorView } from 'prosemirror-view'
import { inputRules, wrappingInputRule } from 'prosemirror-inputrules' import { inputRules, wrappingInputRule } from 'prosemirror-inputrules'
import { splitListItem } from 'prosemirror-schema-list' import { splitListItem } from 'prosemirror-schema-list'
import { keymap } from 'prosemirror-keymap' import { keymap } from 'prosemirror-keymap'
import type { EditorView } from 'prosemirror-view'
import type { ProseMirrorExtension } from '../helpers' import type { ProseMirrorExtension } from '../helpers'
const todoListRule = (nodeType: NodeType) => const todoListRule = (nodeType: NodeType) =>

View File

@ -5,13 +5,16 @@ import { Doc, XmlFragment } from 'yjs'
import type { Reaction } from '../../../graphql/types.gen' import type { Reaction } from '../../../graphql/types.gen'
import { setReactions } from '../../../stores/editor' import { setReactions } from '../../../stores/editor'
export const roomConnect = (room, username = '', keyname = 'collab'): [XmlFragment, WebrtcProvider] => { export const roomConnect = (room: string, username = '', keyname = 'collab'): [XmlFragment, WebrtcProvider] => {
const ydoc = new Doc() const ydoc = new Doc()
const yarr = ydoc.getArray(keyname + '-reactions') const yarr = ydoc.getArray(keyname + '-reactions')
// TODO: use reactions
yarr.observeDeep(() => { yarr.observeDeep(() => {
console.debug('[p2p] yarray updated', yarr.toArray()) console.debug('[p2p] yarray updated', yarr.toArray())
setReactions(yarr.toArray() as Reaction[]) setReactions(yarr.toArray() as Reaction[])
}) })
const yXmlFragment = ydoc.getXmlFragment(keyname) const yXmlFragment = ydoc.getXmlFragment(keyname)
const webrtcOptions = { const webrtcOptions = {
awareness: new Awareness(ydoc), awareness: new Awareness(ydoc),

View File

@ -19,6 +19,7 @@ import type { Command } from 'prosemirror-state'
import placeholder from './extension/placeholder' import placeholder from './extension/placeholder'
import todoList from './extension/todo-list' import todoList from './extension/todo-list'
import strikethrough from './extension/strikethrough' import strikethrough from './extension/strikethrough'
import scrollPlugin from './extension/scroll'
interface ExtensionsProps { interface ExtensionsProps {
data?: unknown data?: unknown
@ -29,6 +30,7 @@ interface ExtensionsProps {
y?: YOptions y?: YOptions
schema?: Schema schema?: Schema
collab?: boolean collab?: boolean
typewriterMode?: boolean
} }
const customKeymap = (props: ExtensionsProps): ProseMirrorExtension => ({ const customKeymap = (props: ExtensionsProps): ProseMirrorExtension => ({
@ -37,11 +39,11 @@ const customKeymap = (props: ExtensionsProps): ProseMirrorExtension => ({
export const createExtensions = (props: ExtensionsProps): ProseMirrorExtension[] => { export const createExtensions = (props: ExtensionsProps): ProseMirrorExtension[] => {
const eee = [ const eee = [
// scroll(props.config.typewriterMode),
placeholder(t('Just start typing...')), placeholder(t('Just start typing...')),
customKeymap(props), customKeymap(props),
base(props.markdown), base(props.markdown),
selectionMenu() selectionMenu(),
scrollPlugin(props.config?.typewriterMode)
] ]
if (props.markdown) { if (props.markdown) {
eee.push( eee.push(

View File

@ -10,9 +10,7 @@ import { State, Draft, Config, ServiceError, newState } from './context'
import { serialize, createMarkdownParser } from '../markdown' import { serialize, createMarkdownParser } from '../markdown'
import db from '../db' import db from '../db'
import { isEmpty, isInitialized } from '../prosemirror/helpers' import { isEmpty, isInitialized } from '../prosemirror/helpers'
import { drafts as draftsatom } from '../../../stores/editor' import { createSignal } from 'solid-js'
import { useStore } from '@nanostores/solid'
import { createMemo } from 'solid-js'
const isText = (x) => x && x.doc && x.selection const isText = (x) => x && x.doc && x.selection
const isDraft = (x): boolean => x && (x.text || x.path) const isDraft = (x): boolean => x && (x.text || x.path)
@ -239,8 +237,7 @@ export const createCtrl = (initial): [Store<State>, { [key: string]: any }] => {
} }
const loadDraft = async (config: Config, path: string): Promise<Draft> => { const loadDraft = async (config: Config, path: string): Promise<Draft> => {
const draftstore = useStore(draftsatom) const [draft, setDraft] = createSignal<Draft>()
const draft = createMemo(() => draftstore()[path])
const schema = createSchema({ const schema = createSchema({
config, config,
markdown: false, markdown: false,
@ -334,9 +331,9 @@ export const createCtrl = (initial): [Store<State>, { [key: string]: any }] => {
if (isInitialized(state.text as EditorState)) { if (isInitialized(state.text as EditorState)) {
if (state.path) { if (state.path) {
// const text = serialize(store.editorView.state) const text = serialize(store.editorView.state)
// TODO: saving draft logix here
// await remote.writeDraft(state.path, text) // await remote.writeDraft(state.path, text)
draftsatom.setKey(state.path, store.editorView.state)
} else { } else {
data.text = store.editorView.state.toJSON() data.text = store.editorView.state.toJSON()
} }

View File

@ -9,7 +9,7 @@ export interface Args {
cwd?: string cwd?: string
draft?: string draft?: string
room?: string room?: string
text?: any text?: string
} }
export interface PrettierConfig { export interface PrettierConfig {
@ -23,17 +23,17 @@ export interface PrettierConfig {
export interface Config { export interface Config {
theme: string theme: string
// codeTheme: string; // codeTheme: string;
// alwaysOnTop: boolean;
font: string font: string
fontSize: number fontSize: number
contentWidth: number contentWidth: number
// alwaysOnTop: boolean; typewriterMode?: boolean;
// typewriterMode: boolean;
prettier: PrettierConfig prettier: PrettierConfig
} }
export interface ErrorObject { export interface ErrorObject {
id: string id: string
props?: unknown props?: any
} }
export interface YOptions { export interface YOptions {
@ -78,7 +78,7 @@ export interface Draft {
export class ServiceError extends Error { export class ServiceError extends Error {
public errorObject: ErrorObject public errorObject: ErrorObject
constructor(id: string, props: unknown) { constructor(id: string, props: any) {
super(id) super(id)
this.errorObject = { id, props } this.errorObject = { id, props }
} }

View File

@ -11,6 +11,7 @@ const matchDark = () => window.matchMedia('(prefers-color-scheme: dark)')
export const CreateView = (props: { state: State }) => { export const CreateView = (props: { state: State }) => {
let isMac = false let isMac = false
const onChangeTheme = () => ctrl.updateTheme()
onMount(() => { onMount(() => {
isMac = window?.navigator.platform.includes('Mac') isMac = window?.navigator.platform.includes('Mac')
matchDark().addEventListener('change', onChangeTheme) matchDark().addEventListener('change', onChangeTheme)
@ -34,8 +35,6 @@ export const CreateView = (props: { state: State }) => {
await ctrl.init() await ctrl.init()
}) })
const onChangeTheme = () => ctrl.updateTheme()
onError((error) => { onError((error) => {
console.error('[create] error:', error) console.error('[create] error:', error)
ctrl.setState({ error: { id: 'exception', props: { error } } }) ctrl.setState({ error: { id: 'exception', props: { error } } })

View File

@ -162,5 +162,6 @@
"Restart collab": "Перезапустить коллаборацию", "Restart collab": "Перезапустить коллаборацию",
"Start collab": "Коллаборативный режим", "Start collab": "Коллаборативный режим",
"Clear": "Сбросить", "Clear": "Сбросить",
"Режим": "Theme" "Theme": "Режим",
"Editing conflict, please copy your version and refresh page": "Конфликт редактирования, пожалуйста, скопируйте вашу версию текста и обновите страницу"
} }