diff --git a/src/components/Editor/prosemirror/extension/menu.ts b/src/components/Editor/prosemirror/extension/menu.ts index 2879d22f..6a56c549 100644 --- a/src/components/Editor/prosemirror/extension/menu.ts +++ b/src/components/Editor/prosemirror/extension/menu.ts @@ -341,7 +341,7 @@ export function buildMenuItems(schema: Schema) { ) r.listMenu = [r.wrapBulletList as MenuItem, r.wrapOrderedList as MenuItem] r.inlineMenu = [r.toggleStrong as MenuItem, r.toggleEm as MenuItem, r.toggleMark as MenuItem] - r.fullMenu = [...r.inlineMenu, tMenu as MenuItem, ...r.listMenu] + r.fullMenu = [...r.inlineMenu, tMenu as MenuItem, ...r.listMenu].filter(Boolean) return r } diff --git a/src/components/Editor/prosemirror/extension/selection.ts b/src/components/Editor/prosemirror/extension/selection.ts index 61300ad0..c9031579 100644 --- a/src/components/Editor/prosemirror/extension/selection.ts +++ b/src/components/Editor/prosemirror/extension/selection.ts @@ -11,6 +11,8 @@ export class SelectionTooltip { this.tooltip = document.createElement('div') this.tooltip.className = 'tooltip' view.dom.parentNode.appendChild(this.tooltip) + console.debug('[prosemirror] selection view', view) + console.debug('[prosemirror] selection menu', buildMenuItems(schema).fullMenu) const { dom } = renderGrouped(view, buildMenuItems(schema).fullMenu as any) this.tooltip.appendChild(dom) this.update(view, null) diff --git a/src/components/Editor/store/ctrl.ts b/src/components/Editor/store/ctrl.ts index 890acef8..da04a0e6 100644 --- a/src/components/Editor/store/ctrl.ts +++ b/src/components/Editor/store/ctrl.ts @@ -15,7 +15,6 @@ import { useStore } from '@nanostores/solid' import { createMemo } from 'solid-js' const isText = (x) => x && x.doc && x.selection -const isState = (x) => typeof x.lastModified !== 'string' && Array.isArray(x.drafts) const isDraft = (x): boolean => x && (x.text || x.path) const mod = 'Ctrl' @@ -133,7 +132,7 @@ export const createCtrl = (initial): [Store, { [key: string]: any }] => { }) } - const fetchData = async (): Promise => { + const readStoredState = async (): Promise => { const state: State = unwrap(store) const room = window.location.pathname?.slice(1).trim() const args = { room, draft: room } @@ -168,7 +167,13 @@ export const createCtrl = (initial): [Store, { [key: string]: any }] => { config: undefined }) - const newst = { + for (const draft of parsed.drafts || []) { + if (!isDraft(draft)) { + throw new ServiceError('invalid_draft', draft) + } + } + + return { ...parsed, text, extensions, @@ -176,18 +181,6 @@ export const createCtrl = (initial): [Store, { [key: string]: any }] => { args, lastModified: new Date(parsed.lastModified) } - - for (const draft of parsed.drafts) { - if (!isDraft(draft)) { - throw new ServiceError('invalid_draft', draft) - } - } - - if (!isState(newst)) { - throw new ServiceError('invalid_state', newst) - } - - return newst } const getTheme = (state: State) => ({ theme: state.config.theme }) @@ -197,7 +190,6 @@ export const createCtrl = (initial): [Store, { [key: string]: any }] => { ...newState(), loading: 'initialized', drafts: [], - fullscreen: store.fullscreen, lastModified: new Date(), error: undefined, text: undefined @@ -216,37 +208,37 @@ export const createCtrl = (initial): [Store, { [key: string]: any }] => { } const init = async () => { - let data = await fetchData() + let state = await readStoredState() try { - if (data.args.room) { - data = await doStartCollab(data) - } else if (data.args.text) { - data = await doOpenDraft(data, { - text: { ...JSON.parse(data.args.text) }, + if (state.args.room) { + state = await doStartCollab(state) + } else if (state.args.text) { + state = await doOpenDraft(state, { + text: { ...JSON.parse(state.args.text) }, lastModified: new Date() }) - } else if (data.args.draft) { - const draft = await loadDraft(data.config, data.args.draft) - data = await doOpenDraft(data, draft) - } else if (data.path) { - const draft = await loadDraft(data.config, data.path) - data = await doOpenDraft(data, draft) - } else if (!data.text) { + } else if (state.args.draft) { + const draft = await loadDraft(state.config, state.args.draft) + state = await doOpenDraft(state, draft) + } else if (state.path) { + const draft = await loadDraft(state.config, state.path) + state = await doOpenDraft(state, draft) + } else if (!state.text) { const text = createEmptyText() const extensions = createExtensions({ - config: data.config ?? store.config, - markdown: data.markdown ?? store.markdown, + config: state.config ?? store.config, + markdown: state.markdown ?? store.markdown, keymap: keymap }) - data = { ...data, text, extensions } + state = { ...state, text, extensions } } } catch (error) { - data = { ...data, error: error.errorObject } + state = { ...state, error: error.errorObject } } setState({ - ...data, - config: { ...data.config, ...getTheme(data) }, + ...state, + config: { ...state.config, ...getTheme(state) }, loading: 'initialized' }) } diff --git a/src/components/Editor/styles/Editor.scss b/src/components/Editor/styles/Editor.scss index 90f27531..63c54c12 100644 --- a/src/components/Editor/styles/Editor.scss +++ b/src/components/Editor/styles/Editor.scss @@ -7,62 +7,62 @@ min-width: 50%; min-height: fit-content; display: inline-block; - border: 1px dotted rgb(0 0 0 / 80%); -} - -a { - color: rgb(0 100 200); - text-decoration: none; -} - -a:hover { - text-decoration: underline; -} - -a:visited { - color: rgb(0 100 200 / 70%); -} - -label { - display: block; -} - -input, -button, -select, -textarea { - font-family: inherit; - font-size: inherit; - padding: 0.4em; - margin: 0 0 0.5em; - box-sizing: border-box; - border: 1px solid #ccc; - border-radius: 2px; -} - -input:disabled { - color: #ccc; -} - -button { - color: #333; - background-color: #f4f4f4; - outline: none; -} - -button:disabled { - color: #999; -} - -button:not(:disabled):active { - background-color: #ddd; -} - -button:focus { - border-color: #666; + border: 1px dashed rgb(0 0 0 / 80%); } .ProseMirror { + a { + color: rgb(0 100 200); + text-decoration: none; + } + + a:hover { + text-decoration: underline; + } + + a:visited { + color: rgb(0 100 200 / 70%); + } + + label { + display: block; + } + + input, + button, + select, + textarea { + font-family: inherit; + font-size: inherit; + padding: 0.4em; + margin: 0 0 0.5em; + box-sizing: border-box; + border: 1px solid #ccc; + border-radius: 2px; + } + + input:disabled { + color: #ccc; + } + + button { + color: #333; + background-color: #f4f4f4; + outline: none; + } + + button:disabled { + color: #999; + } + + button:not(:disabled):active { + background-color: #ddd; + } + + button:focus { + border-color: #666; + } + color: var(--foreground); background-color: var(--background); position: relative; diff --git a/src/pages/[...slug].astro b/src/pages/[...slug].astro index 717223b7..9ca1dbfd 100644 --- a/src/pages/[...slug].astro +++ b/src/pages/[...slug].astro @@ -6,7 +6,7 @@ import { initRouter } from '../stores/router' const slug = Astro.params.slug?.toString() if (slug.endsWith('.map')) { - return + return Astro.redirect('/404') } const article = await apiClient.getArticle({ slug })