diff --git a/CHANGELOG.md b/CHANGELOG.md index d8159ecbf..32ac0940a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -72,6 +72,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0 - The intro page content can be changed by editing `public/intro.md`. - When pasting tables (e.g. from LibreOffice Calc or MS Excel) they get reformatted to markdown tables. - The history page supports URL parameters that allow bookmarking of a specific search of tags filter. +- Users can change the pinning state of a note directly from the editor. ### Changed diff --git a/src/components/editor-page/editor-page.tsx b/src/components/editor-page/editor-page.tsx index 836999b1d..f08cc9cf8 100644 --- a/src/components/editor-page/editor-page.tsx +++ b/src/components/editor-page/editor-page.tsx @@ -35,6 +35,7 @@ import { useEditorModeFromUrl } from './hooks/useEditorModeFromUrl' import { UiNotifications } from '../notifications/ui-notifications' import { useNotificationTest } from './use-notification-test' import { IframeCommunicatorContextProvider } from './render-context/iframe-communicator-context-provider' +import { useUpdateLocalHistoryEntry } from './hooks/useUpdateLocalHistoryEntry' export interface EditorPagePathParams { id: string @@ -77,6 +78,8 @@ export const EditorPage: React.FC = () => { const [error, loading] = useLoadNoteFromServer() + useUpdateLocalHistoryEntry(!error && !loading) + const setRendererToScrollSource = useCallback(() => { scrollSource.current = ScrollSource.RENDERER }, []) diff --git a/src/components/editor-page/hooks/useUpdateLocalHistoryEntry.ts b/src/components/editor-page/hooks/useUpdateLocalHistoryEntry.ts new file mode 100644 index 000000000..349db8b35 --- /dev/null +++ b/src/components/editor-page/hooks/useUpdateLocalHistoryEntry.ts @@ -0,0 +1,51 @@ +/* + * SPDX-FileCopyrightText: 2021 The HedgeDoc developers (see AUTHORS file) + * + * SPDX-License-Identifier: AGPL-3.0-only + */ + +import equal from 'fast-deep-equal' +import { useEffect, useRef } from 'react' +import { useSelector } from 'react-redux' +import { ApplicationState, store } from '../../../redux' +import { useParams } from 'react-router-dom' +import { EditorPagePathParams } from '../editor-page' +import { HistoryEntry, HistoryEntryOrigin } from '../../../redux/history/types' +import { updateLocalHistoryEntry } from '../../../redux/history/methods' + +export const useUpdateLocalHistoryEntry = (updateReady: boolean): void => { + const { id } = useParams() + const userExists = useSelector((state: ApplicationState) => !!state.user) + const currentNoteTitle = useSelector((state: ApplicationState) => state.noteDetails.noteTitle) + const currentNoteTags = useSelector((state: ApplicationState) => state.noteDetails.frontmatter.tags) + + const lastNoteTitle = useRef('') + const lastNoteTags = useRef([]) + + useEffect(() => { + if (!updateReady || userExists) { + return + } + if (currentNoteTitle === lastNoteTitle.current && equal(currentNoteTags, lastNoteTags.current)) { + return + } + const history = store.getState().history + const entry: HistoryEntry = history.find(entry => entry.identifier === id) ?? { + identifier: id, + title: '', + pinStatus: false, + lastVisited: '', + tags: [], + origin: HistoryEntryOrigin.LOCAL + } + if (entry.origin === HistoryEntryOrigin.REMOTE) { + return + } + entry.title = currentNoteTitle + entry.tags = currentNoteTags + entry.lastVisited = new Date().toISOString() + updateLocalHistoryEntry(id, entry) + lastNoteTitle.current = currentNoteTitle + lastNoteTags.current = currentNoteTags + }, [updateReady, id, userExists, currentNoteTitle, currentNoteTags]) +} diff --git a/src/components/editor-page/sidebar/pin-note-sidebar-entry.tsx b/src/components/editor-page/sidebar/pin-note-sidebar-entry.tsx index 7282e786b..971c6139a 100644 --- a/src/components/editor-page/sidebar/pin-note-sidebar-entry.tsx +++ b/src/components/editor-page/sidebar/pin-note-sidebar-entry.tsx @@ -4,20 +4,40 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import React from 'react' +import React, { useCallback, useMemo } from 'react' import { Trans, useTranslation } from 'react-i18next' import { SidebarButton } from './sidebar-button' import { SpecificSidebarEntryProps } from './types' +import { useParams } from 'react-router-dom' +import { EditorPagePathParams } from '../editor-page' +import { useSelector } from 'react-redux' +import { ApplicationState } from '../../../redux' +import { toggleHistoryEntryPinning } from '../../../redux/history/methods' +import { showErrorNotification } from '../../../redux/ui-notifications/methods' export const PinNoteSidebarEntry: React.FC = ({ className, hide }) => { - useTranslation() + const { t } = useTranslation() + const { id } = useParams() + const history = useSelector((state: ApplicationState) => state.history) - const isPinned = true - const i18nKey = isPinned ? 'editor.documentBar.pinNoteToHistory' : 'editor.documentBar.pinnedToHistory' + const isPinned = useMemo(() => { + const entry = history.find(entry => entry.identifier === id) + if (!entry) { + return false + } + return entry.pinStatus + }, [id, history]) + + const onPinClicked = useCallback(() => { + toggleHistoryEntryPinning(id).catch( + showErrorNotification(t('landing.history.error.updateEntry.text')) + ) + }, [id, t]) return ( - - + + ) } diff --git a/src/components/editor-page/sidebar/style/colors.scss b/src/components/editor-page/sidebar/style/colors.scss index 5dee8cc5e..ade9aaf24 100644 --- a/src/components/editor-page/sidebar/style/colors.scss +++ b/src/components/editor-page/sidebar/style/colors.scss @@ -33,6 +33,10 @@ background: $entry-hover-bg; } } + + &.icon-highlighted > .sidebar-icon { + color: $orange + } } }