Editor async loading, minor fixes

This commit is contained in:
Igor Lobanov 2022-11-01 20:27:43 +01:00
parent 72c5b1bc70
commit b2387543fc
10 changed files with 79 additions and 75 deletions

View File

@ -1,14 +1,14 @@
import { For, Show, createEffect, createSignal, onCleanup } 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 { Draft, useState } from '../store/context'
import { mod } from '../env'
import * as remote from '../remote'
import { isEmpty } from '../prosemirror/helpers'
import type { Styled } from './Layout'
import '../styles/Sidebar.scss'
import { clsx } from 'clsx'
import styles from './Sidebar.module.scss'
import { isServer } from 'solid-js/web'
const Off = (props) => <div class="sidebar-off">{props.children}</div>
@ -141,6 +141,12 @@ export const Sidebar = () => {
onCleanup(() => clearTimeout(id))
})
const [mod, setMod] = createSignal<'Ctrl' | 'Cmd'>('Ctrl')
onMount(() => {
setMod(navigator.platform.includes('Mac') ? 'Cmd' : 'Ctrl')
})
return (
<div class={'sidebar-container' + (isHidden() ? ' sidebar-container--hidden' : '')}>
<span class="sidebar-opener" onClick={toggleSidebar}>
@ -149,55 +155,54 @@ export const Sidebar = () => {
<Off onClick={() => editorView().focus()}>
<div class="sidebar-closer" onClick={toggleSidebar} />
<Show when={true}>
<div>
{store.path && (
<Label>
<i>({store.path.slice(Math.max(0, store.path.length - 24))})</i>
</Label>
)}
<Link>Пригласить соавторов</Link>
<Link>Настройки публикации</Link>
<Link>История правок</Link>
<div class="theme-switcher">
Ночная тема
<input type="checkbox" name="theme" id="theme" onClick={toggleTheme} />
<label for="theme">Ночная тема</label>
</div>
<Link
onClick={onDiscard}
disabled={!store.path && store.drafts.length === 0 && isEmpty(store.text)}
data-testid="discard"
>
{discardText()} <Keys keys={[mod, 'w']} />
</Link>
<Link onClick={onUndo}>
Undo <Keys keys={[mod, 'z']} />
</Link>
<Link onClick={onRedo}>
Redo <Keys keys={[mod, 'Shift', 'z']} />
</Link>
<Link onClick={onToggleMarkdown} data-testid="markdown">
Markdown mode {store.markdown && '✅'} <Keys keys={[mod, 'm']} />
</Link>
<Link onClick={onCopyAllAsMd}>Copy all as MD {lastAction() === 'copy-md' && '📋'}</Link>
<Show when={store.drafts.length > 0}>
<h4>Drafts:</h4>
<p>
<For each={store.drafts}>{(draft) => <DraftLink draft={draft} />}</For>
</p>
</Show>
<Link onClick={onCollab} title={store.collab?.error ? 'Connection error' : ''}>
Collab {collabText()}
</Link>
<Show when={collabUsers() > 0}>
<span>
{collabUsers()} {collabUsers() === 1 ? 'user' : 'users'} connected
</span>
</Show>
<div>
{store.path && (
<Label>
<i>({store.path.slice(Math.max(0, store.path.length - 24))})</i>
</Label>
)}
<Link>Пригласить соавторов</Link>
<Link>Настройки публикации</Link>
<Link>История правок</Link>
<div class="theme-switcher">
Ночная тема
<input type="checkbox" name="theme" id="theme" onClick={toggleTheme} />
<label for="theme">Ночная тема</label>
</div>
</Show>
<Link
onClick={onDiscard}
disabled={!store.path && store.drafts.length === 0 && isEmpty(store.text)}
data-testid="discard"
>
{discardText()} <Keys keys={[mod(), 'w']} />
</Link>
<Link onClick={onUndo}>
Undo <Keys keys={[mod(), 'z']} />
</Link>
<Link onClick={onRedo}>
Redo <Keys keys={[mod(), 'Shift', 'z']} />
</Link>
<Link onClick={onToggleMarkdown} data-testid="markdown">
Markdown mode {store.markdown && '✅'} <Keys keys={[mod(), 'm']} />
</Link>
<Link onClick={onCopyAllAsMd}>Copy all as MD {lastAction() === 'copy-md' && '📋'}</Link>
<Show when={store.drafts.length > 0}>
<h4>Drafts:</h4>
<p>
<For each={store.drafts}>{(draft) => <DraftLink draft={draft} />}</For>
</p>
</Show>
<Link onClick={onCollab} title={store.collab?.error ? 'Connection error' : ''}>
Collab {collabText()}
</Link>
<Show when={collabUsers() > 0}>
<span>
{collabUsers()} {collabUsers() === 1 ? 'user' : 'users'} connected
</span>
</Show>
</div>
</Off>
</div>
)

View File

@ -1,5 +1,6 @@
const dbPromise = async () => {
const { openDB } = await import('idb')
import { openDB } from 'idb'
const dbPromise = () => {
return openDB('discours.io', 2, {
upgrade(db) {
db.createObjectStore('keyval')

View File

@ -1,3 +1,2 @@
export const isDark = () => (window as any).matchMedia('(prefers-color-scheme: dark)').matches
export const mod = 'Ctrl'
export const alt = 'Alt'
export const isDark = () =>
typeof window !== undefined && window.matchMedia('(prefers-color-scheme: dark)').matches

View File

@ -7,7 +7,6 @@ import { undo as yUndo, redo as yRedo } from 'y-prosemirror'
import debounce from 'lodash/debounce'
import { createSchema, createExtensions, createEmptyText } from '../prosemirror/setup'
import { State, Draft, Config, ServiceError, newState, ExtensionsProps, EditorActions } from './context'
import { mod } from '../env'
import { serialize, createMarkdownParser } from '../markdown'
import db from '../db'
import { isEmpty, isInitialized } from '../prosemirror/helpers'
@ -102,13 +101,13 @@ export const createCtrl = (initial: State): [Store<State>, EditorActions] => {
return true
}
const keymap = {
[`${mod}-w`]: discard,
[`${mod}-z`]: onUndo,
[`Shift-${mod}-z`]: onRedo,
[`${mod}-y`]: onRedo,
[`${mod}-m`]: toggleMarkdown
} as ExtensionsProps['keymap']
const keymap: ExtensionsProps['keymap'] = {
[`Mod-w`]: discard,
[`Mod-z`]: onUndo,
[`Shift-Mod-z`]: onRedo,
[`Mod-y`]: onRedo,
[`Mod-m`]: toggleMarkdown
}
const createTextFromDraft = async (draft: Draft) => {
const state = unwrap(store)

View File

@ -63,7 +63,6 @@ export interface Collab {
export type LoadingType = 'loading' | 'initialized'
export interface State {
isMac?: boolean
text?: ProseMirrorState
editorView?: EditorView
extensions?: ProseMirrorExtension[]

View File

@ -1,3 +0,0 @@
.index {
width: 350px;
}

View File

@ -134,7 +134,7 @@ export const Header = (props: Props) => {
<div class={styles.usernav}>
<div class={clsx(styles.userControl, styles.userControl, 'col')}>
<div class={clsx(styles.userControlItem, styles.userControlItemWritePost)}>
<a href="/create">
<a href="/create" onClick={handleClientRouteLinkClick}>
<span class={styles.textLabel}>{t('Create post')}</span>
<Icon name="pencil" class={styles.icon} />
</a>

View File

@ -1,11 +1,15 @@
import { newState } from '../Editor/store/context'
import { lazy, Suspense } from 'solid-js'
import { MainLayout } from '../Layouts/MainLayout'
import { CreateView } from '../Views/Create'
import { Loading } from '../Loading'
const CreateView = lazy(() => import('../Views/Create'))
export const CreatePage = () => {
return (
<MainLayout>
<CreateView state={newState()} />
<Suspense fallback={<Loading />}>
<CreateView />
</Suspense>
</MainLayout>
)
}

View File

@ -1,6 +1,6 @@
import { Show, onCleanup, createEffect, onError, onMount, untrack } from 'solid-js'
import { createMutable, unwrap } from 'solid-js/store'
import { State, StateContext } from '../Editor/store/context'
import { State, StateContext, newState } from '../Editor/store/context'
import { createCtrl } from '../Editor/store/actions'
import { Layout } from '../Editor/components/Layout'
import { Editor } from '../Editor/components/Editor'
@ -9,16 +9,14 @@ import ErrorView from '../Editor/components/Error'
const matchDark = () => window.matchMedia('(prefers-color-scheme: dark)')
export const CreateView = (props: { state: State }) => {
let isMac = false
export const CreateView = () => {
const onChangeTheme = () => ctrl.updateTheme()
onMount(() => {
isMac = window?.navigator.platform.includes('Mac')
matchDark().addEventListener('change', onChangeTheme)
onCleanup(() => matchDark().removeEventListener('change', onChangeTheme))
})
const [store, ctrl] = createCtrl({ ...props.state, isMac })
const [store, ctrl] = createCtrl(newState())
const mouseEnterCoords = createMutable({ x: 0, y: 0 })
const onMouseEnter = (e: MouseEvent) => {
@ -66,3 +64,5 @@ export const CreateView = (props: { state: State }) => {
</StateContext.Provider>
)
}
export default CreateView