diff --git a/package-lock.json b/package-lock.json index 62b9431f..daf1ca0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@hocuspocus/provider": "2.0.6", + "fast-deep-equal": "3.1.3", "form-data": "4.0.0", "i18next": "22.4.15", "mailgun.js": "8.2.1", @@ -8849,8 +8850,7 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-glob": { "version": "3.2.12", @@ -25813,8 +25813,7 @@ "fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "fast-glob": { "version": "3.2.12", diff --git a/package.json b/package.json index e0a32a61..855840f8 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ }, "dependencies": { "@hocuspocus/provider": "2.0.6", + "fast-deep-equal": "3.1.3", "form-data": "4.0.0", "i18next": "22.4.15", "mailgun.js": "8.2.1", diff --git a/public/locales/en/translation.json b/public/locales/en/translation.json index 1cb4269e..e23bb13c 100644 --- a/public/locales/en/translation.json +++ b/public/locales/en/translation.json @@ -72,7 +72,6 @@ "Create gallery": "Create gallery", "Create post": "Create post", "Create video": "Create video", - "contents": "contents", "Date of Birth": "Date of Birth", "Decline": "Decline", "Delete": "Delete", @@ -237,6 +236,7 @@ "Restore password": "Restore password", "Save draft": "Save draft", "Save settings": "Save settings", + "Saving...": "Saving...", "Scroll up": "Scroll up", "Search": "Search", "Search author": "Search author", @@ -340,6 +340,7 @@ "cancel": "cancel", "collections": "collections", "community": "community", + "contents": "contents", "delimiter": "delimiter", "discussion": "discourse", "drafts": "drafts", diff --git a/public/locales/ru/translation.json b/public/locales/ru/translation.json index 9814529a..ee2fa019 100644 --- a/public/locales/ru/translation.json +++ b/public/locales/ru/translation.json @@ -76,7 +76,6 @@ "Create gallery": "Создать галерею", "Create post": "Создать публикацию", "Create video": "Создать видео", - "contents": "оглавление", "Date of Birth": "Дата рождения", "Decline": "Отмена", "Delete": "Удалить", @@ -253,6 +252,7 @@ "Save": "Сохранить", "Save draft": "Сохранить черновик", "Save settings": "Сохранить настройки", + "Saving...": "Сохраняем...", "Scroll up": "Наверх", "Search": "Поиск", "Search author": "Поиск автора", @@ -358,6 +358,7 @@ "cancel": "отменить", "collections": "коллекции", "community": "сообщество", + "contents": "оглавление", "create_chat": "Создать чат", "create_group": "Создать группу", "delimiter": "разделитель", diff --git a/src/components/Draft/Draft.module.scss b/src/components/Draft/Draft.module.scss index 96b207ca..52b0804e 100644 --- a/src/components/Draft/Draft.module.scss +++ b/src/components/Draft/Draft.module.scss @@ -25,20 +25,20 @@ .actions { @include font-size(1.2rem); - a { + display: flex; + gap: 12px; + + .actionItem { border: 0; display: inline-block; - } + cursor: pointer; - a + a { - margin-left: 12px; - } + &.delete { + color: #d00820; + } - .deleteLink { - color: #d00820; - } - - .publishLink { - color: #2bb452; + &.publish { + color: #2bb452; + } } } diff --git a/src/components/Draft/Draft.tsx b/src/components/Draft/Draft.tsx index c600743c..f5095a65 100644 --- a/src/components/Draft/Draft.tsx +++ b/src/components/Draft/Draft.tsx @@ -53,13 +53,18 @@ export const Draft = (props: Props) => { {props.shout.title || t('Unnamed draft')} {props.shout.subtitle}
- {t('Edit')} - + + {t('Edit')} + + {t('Publish')} - - + + {t('Delete')} - +
) diff --git a/src/components/Editor/AutoSaveNotice/AutoSaveNotice.module.scss b/src/components/Editor/AutoSaveNotice/AutoSaveNotice.module.scss new file mode 100644 index 00000000..84acea15 --- /dev/null +++ b/src/components/Editor/AutoSaveNotice/AutoSaveNotice.module.scss @@ -0,0 +1,34 @@ +.AutoSaveNotice { + @include font-size(1.4rem); + + display: inline-flex; + flex-direction: row; + align-items: center; + gap: 8px; + position: sticky; + top: calc(100vh - 40px); + margin-left: auto; + padding: 2px 6px; + border-radius: 2px; + z-index: 2; + font-weight: 500; + transition: 0.6s ease-in-out; + background: rgba(white, 0.3); + backdrop-filter: blur(4px); + border: 1px solid var(--secondary-color); + left: 100%; + opacity: 0; + right: -14rem; + pointer-events: none; + + .icon { + position: relative; + width: 18px; + height: 18px; + } + + &.active { + opacity: 0.65; + right: 2rem; + } +} diff --git a/src/components/Editor/AutoSaveNotice/AutoSaveNotice.tsx b/src/components/Editor/AutoSaveNotice/AutoSaveNotice.tsx new file mode 100644 index 00000000..35669e97 --- /dev/null +++ b/src/components/Editor/AutoSaveNotice/AutoSaveNotice.tsx @@ -0,0 +1,20 @@ +import { clsx } from 'clsx' +import styles from './AutoSaveNotice.module.scss' +import { Loading } from '../../_shared/Loading' +import { useLocalize } from '../../../context/localize' + +type Props = { + active: boolean +} + +export const AutoSaveNotice = (props: Props) => { + const { t } = useLocalize() + return ( +
+
+ +
+
{t('Saving...')}
+
+ ) +} diff --git a/src/components/Editor/AutoSaveNotice/index.ts b/src/components/Editor/AutoSaveNotice/index.ts new file mode 100644 index 00000000..a01de3fa --- /dev/null +++ b/src/components/Editor/AutoSaveNotice/index.ts @@ -0,0 +1 @@ +export { AutoSaveNotice } from './AutoSaveNotice' diff --git a/src/components/Editor/Editor.tsx b/src/components/Editor/Editor.tsx index a1f2baa7..56bb2514 100644 --- a/src/components/Editor/Editor.tsx +++ b/src/components/Editor/Editor.tsx @@ -1,6 +1,5 @@ import { createEffect, createSignal, Show } from 'solid-js' import { createTiptapEditor, useEditorHTML } from 'solid-tiptap' -import { IndexeddbPersistence } from 'y-indexeddb' import uniqolor from 'uniqolor' import * as Y from 'yjs' import type { Doc } from 'yjs/dist/src/utils/Doc' @@ -58,7 +57,6 @@ type Props = { } const yDocs: Record = {} -const persisters: Record = {} const providers: Record = {} export const Editor = (props: Props) => { @@ -80,10 +78,6 @@ export const Editor = (props: Props) => { }) } - if (!persisters[docName]) { - persisters[docName] = new IndexeddbPersistence(docName, yDocs[docName]) - } - const editorElRef: { current: HTMLDivElement } = { diff --git a/src/components/Editor/Panel/Panel.tsx b/src/components/Editor/Panel/Panel.tsx index 5024e05e..515f0019 100644 --- a/src/components/Editor/Panel/Panel.tsx +++ b/src/components/Editor/Panel/Panel.tsx @@ -25,6 +25,7 @@ export const Panel = (props: Props) => { isEditorPanelVisible, wordCounter, editorRef, + form, actions: { toggleEditorPanel, saveShout, publishShout } } = useEditorContext() @@ -48,11 +49,11 @@ export const Panel = (props: Props) => { }) const handleSaveClick = () => { - saveShout() + saveShout(form) } const handlePublishClick = () => { - publishShout() + publishShout(form) } const handleFixTypographyClick = () => { diff --git a/src/components/Nav/HeaderAuth.tsx b/src/components/Nav/HeaderAuth.tsx index c7ecdf34..8359063c 100644 --- a/src/components/Nav/HeaderAuth.tsx +++ b/src/components/Nav/HeaderAuth.tsx @@ -15,17 +15,18 @@ import { Button } from '../_shared/Button' import { useEditorContext } from '../../context/editor' import { Popover } from '../_shared/Popover' -type HeaderAuthProps = { +type Props = { setIsProfilePopupVisible: (value: boolean) => void } -type IconedButton = { + +type IconedButtonProps = { value: string icon: string action: () => void } const MD_WIDTH_BREAKPOINT = 992 -export const HeaderAuth = (props: HeaderAuthProps) => { +export const HeaderAuth = (props: Props) => { const { t } = useLocalize() const { page } = useRouter() const [visibleWarnings, setVisibleWarnings] = createSignal(false) @@ -34,6 +35,7 @@ export const HeaderAuth = (props: HeaderAuthProps) => { const { session, isSessionLoaded, isAuthenticated } = useSession() const { + form, actions: { toggleEditorPanel, saveShout, publishShout } } = useEditorContext() @@ -61,11 +63,11 @@ export const HeaderAuth = (props: HeaderAuthProps) => { } const handleSaveButtonClick = () => { - saveShout() + saveShout(form) } const handlePublishButtonClick = () => { - publishShout() + publishShout(form) } const [width, setWidth] = createSignal(0) @@ -76,25 +78,25 @@ export const HeaderAuth = (props: HeaderAuthProps) => { onCleanup(() => window.removeEventListener('resize', handleResize)) }) - const renderIconedButton = (iconedButtonProps: IconedButton) => { + const renderIconedButton = (buttonProps: IconedButtonProps) => { return ( {iconedButtonProps.value}} + value={{buttonProps.value}} variant={'outline'} - onClick={handleSaveButtonClick} + onClick={buttonProps.action} /> } > - + {(ref) => (