From 721c8c0e5a13fffa32b5bf2c057ee22d2b64fd76 Mon Sep 17 00:00:00 2001 From: Erik Michelson Date: Tue, 22 Dec 2020 21:17:40 +0100 Subject: [PATCH] Enhance share dialog (#860) --- CHANGELOG.md | 1 + public/locales/en.json | 4 +- .../copyable-field/copyable-field.tsx | 31 +++++++++++--- .../editor/app-bar/editor-view-mode.tsx | 6 +-- .../buttons/share-link-button.tsx | 41 +++++++++++++++---- src/components/editor/editor.tsx | 3 +- .../pad-view-only/pad-view-only.tsx | 3 +- src/redux/document-content/methods.ts | 23 +++++++++-- src/redux/document-content/reducers.ts | 22 +++++++++- src/redux/document-content/types.ts | 11 ++++- 10 files changed, 120 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b3468ec6..05be45d92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -57,6 +57,7 @@ SPDX-License-Identifier: CC-BY-SA-4.0 - Markdown files can be imported into an existing note directly from the editor. - The table button in the toolbar opens an overlay where the user can choose the number of columns and rows - A toggle in the editor preferences for turning ligatures on and off. +- Easier possibility to share notes via native share-buttons on supported devices. ### Changed diff --git a/public/locales/en.json b/public/locales/en.json index bf64bd628..5c56f47b0 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -389,7 +389,9 @@ }, "shareLink": { "title": "Share link", - "viewOnlyDescription": "This link points to a read-only version of this note. You can use this e.g. for feedback from friends and colleagues." + "editorDescription": "This link points to this note in the editor as you currently see it.", + "viewOnlyDescription": "This link points to a read-only version of this note. You can use this e.g. for feedback from friends and colleagues.", + "slidesDescription": "This link points to the presentation view of the slides." }, "preferences": { "title": "Preferences", diff --git a/src/components/common/copyable/copyable-field/copyable-field.tsx b/src/components/common/copyable/copyable-field/copyable-field.tsx index 98dbc9275..7097e7b0c 100644 --- a/src/components/common/copyable/copyable-field/copyable-field.tsx +++ b/src/components/common/copyable/copyable-field/copyable-field.tsx @@ -4,31 +4,52 @@ SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file) SPDX-License-Identifier: AGPL-3.0-only */ -import React, { Fragment, useRef } from 'react' +import React, { Fragment, useCallback, useRef } from 'react' import { Button, FormControl, InputGroup } from 'react-bootstrap' import { useTranslation } from 'react-i18next' import { ForkAwesomeIcon } from '../../fork-awesome/fork-awesome-icon' +import { ShowIf } from '../../show-if/show-if' import { CopyOverlay } from '../copy-overlay' export interface CopyableFieldProps { content: string + nativeShareButton?: boolean + url?: string } -export const CopyableField: React.FC = ({ content }) => { +export const CopyableField: React.FC = ({ content, nativeShareButton, url }) => { useTranslation() - const button = useRef(null) + const copyButton = useRef(null) + + const doShareAction = useCallback(() => { + navigator.share({ + text: content, + url: url + }).catch(err => { + console.error('Native sharing failed: ', err) + }) + }, [content, url]) + + const sharingSupported = typeof navigator.share === 'function' return ( - + + + + + - + ) } diff --git a/src/components/editor/app-bar/editor-view-mode.tsx b/src/components/editor/app-bar/editor-view-mode.tsx index bfb1a40a4..7b6552b28 100644 --- a/src/components/editor/app-bar/editor-view-mode.tsx +++ b/src/components/editor/app-bar/editor-view-mode.tsx @@ -13,9 +13,9 @@ import { setEditorMode } from '../../../redux/editor/methods' import { ForkAwesomeIcon } from '../../common/fork-awesome/fork-awesome-icon' export enum EditorMode { - PREVIEW, - BOTH, - EDITOR, + PREVIEW = 'view', + BOTH = 'both', + EDITOR = 'edit', } export const EditorViewMode: React.FC = () => { diff --git a/src/components/editor/document-bar/buttons/share-link-button.tsx b/src/components/editor/document-bar/buttons/share-link-button.tsx index 72591a46c..00a74e402 100644 --- a/src/components/editor/document-bar/buttons/share-link-button.tsx +++ b/src/components/editor/document-bar/buttons/share-link-button.tsx @@ -4,27 +4,54 @@ SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file) SPDX-License-Identifier: AGPL-3.0-only */ +import equal from 'fast-deep-equal' import React, { Fragment, useState } from 'react' import { Modal } from 'react-bootstrap' -import { Trans } from 'react-i18next' +import { Trans, useTranslation } from 'react-i18next' +import { useSelector } from 'react-redux' +import { useParams } from 'react-router-dom' +import { useFrontendBaseUrl } from '../../../../hooks/common/use-frontend-base-url' +import { ApplicationState } from '../../../../redux' import { CopyableField } from '../../../common/copyable/copyable-field/copyable-field' import { TranslatedIconButton } from '../../../common/icon-button/translated-icon-button' import { CommonModal } from '../../../common/modals/common-modal' +import { ShowIf } from '../../../common/show-if/show-if' +import { EditorPathParams } from '../../editor' export const ShareLinkButton: React.FC = () => { - const [showReadOnly, setShowReadOnly] = useState(false) + useTranslation() + const [showShareDialog, setShowShareDialog] = useState(false) + const noteMetadata = useSelector((state: ApplicationState) => state.documentContent.metadata, equal) + const editorMode = useSelector((state: ApplicationState) => state.editorConfig.editorMode) + const baseUrl = useFrontendBaseUrl() + const { id } = useParams() return ( - setShowReadOnly(true)} i18nKey={'editor.documentBar.shareLink'}/> + setShowShareDialog(true)} + i18nKey={'editor.documentBar.shareLink'} + /> setShowReadOnly(false)} + show={showShareDialog} + onHide={() => setShowShareDialog(false)} closeButton={true} titleI18nKey={'editor.modal.shareLink.title'}> - - + + + + + + + + + + diff --git a/src/components/editor/editor.tsx b/src/components/editor/editor.tsx index 81633db7c..cb2b1bf32 100644 --- a/src/components/editor/editor.tsx +++ b/src/components/editor/editor.tsx @@ -12,7 +12,7 @@ import useMedia from 'use-media' import { useApplyDarkMode } from '../../hooks/common/use-apply-dark-mode' import { useDocumentTitle } from '../../hooks/common/use-document-title' import { ApplicationState } from '../../redux' -import { setDocumentContent, setNoteId } from '../../redux/document-content/methods' +import { setDocumentContent, setDocumentMetadata, setNoteId } from '../../redux/document-content/methods' import { setEditorMode } from '../../redux/editor/methods' import { extractNoteTitle } from '../common/document-title/note-title-extractor' import { MotdBanner } from '../common/motd-banner/motd-banner' @@ -74,6 +74,7 @@ export const Editor: React.FC = () => { const onMetadataChange = useCallback((metaData: YAMLMetaData | undefined) => { noteMetadata.current = metaData + setDocumentMetadata(metaData) updateDocumentTitle() }, [updateDocumentTitle]) diff --git a/src/components/pad-view-only/pad-view-only.tsx b/src/components/pad-view-only/pad-view-only.tsx index c4b72ece5..89ee36575 100644 --- a/src/components/pad-view-only/pad-view-only.tsx +++ b/src/components/pad-view-only/pad-view-only.tsx @@ -11,7 +11,7 @@ import { useParams } from 'react-router' import { getNote, Note } from '../../api/notes' import { useApplyDarkMode } from '../../hooks/common/use-apply-dark-mode' import { useDocumentTitle } from '../../hooks/common/use-document-title' -import { setDocumentContent } from '../../redux/document-content/methods' +import { setDocumentContent, setDocumentMetadata } from '../../redux/document-content/methods' import { extractNoteTitle } from '../common/document-title/note-title-extractor' import { MotdBanner } from '../common/motd-banner/motd-banner' import { ShowIf } from '../common/show-if/show-if' @@ -44,6 +44,7 @@ export const PadViewOnly: React.FC = () => { const onMetadataChange = useCallback((metaData: YAMLMetaData | undefined) => { noteMetadata.current = metaData + setDocumentMetadata(metaData) updateDocumentTitle() }, [updateDocumentTitle]) diff --git a/src/redux/document-content/methods.ts b/src/redux/document-content/methods.ts index 0aa3c1703..921f0960c 100644 --- a/src/redux/document-content/methods.ts +++ b/src/redux/document-content/methods.ts @@ -5,12 +5,18 @@ */ import { store } from '..' -import { DocumentContentActionType, SetDocumentContentAction, SetNoteIdAction } from './types' +import { YAMLMetaData } from '../../components/editor/yaml-metadata/yaml-metadata' +import { + DocumentContentActionType, + SetDocumentContentAction, + SetDocumentMetadataAction, + SetNoteIdAction +} from './types' export const setDocumentContent = (content: string): void => { const action: SetDocumentContentAction = { type: DocumentContentActionType.SET_DOCUMENT_CONTENT, - content: content + content } store.dispatch(action) } @@ -18,7 +24,18 @@ export const setDocumentContent = (content: string): void => { export const setNoteId = (noteId: string): void => { const action: SetNoteIdAction = { type: DocumentContentActionType.SET_NOTE_ID, - noteId: noteId + noteId + } + store.dispatch(action) +} + +export const setDocumentMetadata = (metadata: YAMLMetaData | undefined): void => { + if (!metadata) { + return + } + const action: SetDocumentMetadataAction = { + type: DocumentContentActionType.SET_DOCUMENT_METADATA, + metadata } store.dispatch(action) } diff --git a/src/redux/document-content/reducers.ts b/src/redux/document-content/reducers.ts index 0ae700316..d27027b6f 100644 --- a/src/redux/document-content/reducers.ts +++ b/src/redux/document-content/reducers.ts @@ -9,13 +9,26 @@ import { DocumentContent, DocumentContentAction, DocumentContentActionType, - SetDocumentContentAction, + SetDocumentContentAction, SetDocumentMetadataAction, SetNoteIdAction } from './types' export const initialState: DocumentContent = { content: '', - noteId: '' + noteId: '', + metadata: { + title: '', + description: '', + tags: [], + robots: '', + lang: 'en', + dir: 'ltr', + breaks: true, + GA: '', + disqus: '', + type: '', + opengraph: new Map() + } } export const DocumentContentReducer: Reducer = (state: DocumentContent = initialState, action: DocumentContentAction) => { @@ -30,6 +43,11 @@ export const DocumentContentReducer: Reducer { @@ -27,3 +30,7 @@ export interface SetDocumentContentAction extends DocumentContentAction { export interface SetNoteIdAction extends DocumentContentAction { noteId: string } + +export interface SetDocumentMetadataAction extends DocumentContentAction { + metadata: YAMLMetaData +}