From 6cbff3e4e6d1a391ff2b8e6a7e031535bb32240c Mon Sep 17 00:00:00 2001 From: Guillaume Grossetie Date: Thu, 7 Nov 2024 16:40:43 +0100 Subject: [PATCH] =?UTF-8?q?feat(toc):=20affiche=20la=20table=20des=20mati?= =?UTF-8?q?=C3=A8res=20au=20clique=20sur=20l'icone=20=C3=A0=20gauche=20du?= =?UTF-8?q?=20titre?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit resolves #1088 --- .../components/Write/ArticleEditorMenu.jsx | 2 - .../src/components/Write/TableOfContents.jsx | 47 +++++++++++++++ front/src/components/Write/WorkingVersion.jsx | 57 +++++++++++-------- .../Write/tableOfContents.module.scss | 11 ++++ .../CollaborativeEditorArticleHeader.jsx | 33 ++--------- front/src/locales/en/translation.json | 3 +- front/src/locales/fr/translation.json | 3 +- 7 files changed, 98 insertions(+), 58 deletions(-) create mode 100644 front/src/components/Write/TableOfContents.jsx create mode 100644 front/src/components/Write/tableOfContents.module.scss diff --git a/front/src/components/Write/ArticleEditorMenu.jsx b/front/src/components/Write/ArticleEditorMenu.jsx index 7919bdb9e..d21371398 100644 --- a/front/src/components/Write/ArticleEditorMenu.jsx +++ b/front/src/components/Write/ArticleEditorMenu.jsx @@ -5,7 +5,6 @@ import { useTranslation } from 'react-i18next' import styles from './articleEditorMenu.module.scss' import Stats from './Stats' import Biblio from './Biblio' -import Sommaire from './Sommaire' import Versions from './Versions' import { Sidebar } from 'react-feather' @@ -28,7 +27,6 @@ export default function ArticleEditorMenu ({ articleInfos, readOnly, compareTo, compareTo={compareTo} readOnly={readOnly} /> - )} diff --git a/front/src/components/Write/TableOfContents.jsx b/front/src/components/Write/TableOfContents.jsx new file mode 100644 index 000000000..3b60320b2 --- /dev/null +++ b/front/src/components/Write/TableOfContents.jsx @@ -0,0 +1,47 @@ +import { Link as GeistLink, Popover } from '@geist-ui/core' +import clsx from 'clsx' +import React, { useCallback } from 'react' +import { AlignLeft } from 'react-feather' +import { useTranslation } from 'react-i18next' +import { useDispatch, useSelector } from 'react-redux' +import { useRouteMatch } from 'react-router-dom' +import { usePandocAnchoring } from '../../hooks/pandoc.js' +import styles from './tableOfContents.module.scss' + +export default function TableOfContents () { + const dispatch = useDispatch() + const { t } = useTranslation() + const articleStructure = useSelector(state => state.articleStructure) + const routeMatch = useRouteMatch() + const getAnchor = usePandocAnchoring() + const hasHtmlAnchors = routeMatch.path === '/article/:id/preview' + const handleTableEntryClick = useCallback(({ target }) => { + hasHtmlAnchors + ? document.querySelector(`#${target.dataset.headingAnchor}`)?.scrollIntoView() + : dispatch({ type: 'UPDATE_EDITOR_CURSOR_POSITION', lineNumber: parseInt(target.dataset.index, 10), column: 0 }) + }, [hasHtmlAnchors]) + + const content = () => { + if (articleStructure.length === 0) { + return <> + } + return <> + + {t('toc.title')} + + {articleStructure.map((item) => ( + + {item.title} + + ))} + + } + + return ( + + + ) +} diff --git a/front/src/components/Write/WorkingVersion.jsx b/front/src/components/Write/WorkingVersion.jsx index 917d29eea..6861f6fef 100644 --- a/front/src/components/Write/WorkingVersion.jsx +++ b/front/src/components/Write/WorkingVersion.jsx @@ -1,17 +1,16 @@ -import { Modal as GeistModal } from '@geist-ui/core' import React, { useEffect, useMemo, useState, useCallback } from 'react' import { shallowEqual, useSelector } from 'react-redux' -import { Link } from "react-router-dom"; -import { AlertCircle, AlignLeft, Check, Edit3, Eye, Loader, Printer } from 'react-feather' +import { Link } from 'react-router-dom' +import { AlertCircle, Check, Edit3, Eye, Loader, Printer } from 'react-feather' import { useTranslation } from 'react-i18next' -import ArticleContributors from '../ArticleContributors.jsx' import TimeAgo from '../TimeAgo.jsx' +import TableOfContents from './TableOfContents.jsx' import styles from './workingVersion.module.scss' -import buttonStyles from "../button.module.scss"; -import Button from "../Button"; -import Modal from "../Modal"; -import Export from "../Export"; +import buttonStyles from '../button.module.scss' +import Button from '../Button' +import Modal from '../Modal' +import Export from '../Export' const ONE_MINUTE = 60000 @@ -71,8 +70,8 @@ export function ArticleSaveState ({ state, updatedAt, stateMessage }) { )} - {state === 'saved' && ()} - ) + {state === 'saved' && ()} + ) } export default function WorkingVersion ({ articleInfos, live, selectedVersion, mode }) { @@ -82,7 +81,6 @@ export default function WorkingVersion ({ articleInfos, live, selectedVersion, m const openExport = useCallback(() => setExporting(true), []) const { t } = useTranslation() - const previewUrl = selectedVersion ? `/article/${articleInfos._id}/version/${selectedVersion}/preview` : `/article/${articleInfos._id}/preview` @@ -96,27 +94,35 @@ export default function WorkingVersion ({ articleInfos, live, selectedVersion, m

- + {articleInfos.title}

{exporting && ( - + )}
    - {articleInfos.preview.stylesheet && (<>
  • - - Edit - -
  • -
  • - - {articleInfos.preview.stylesheet ? 'Paged.js' : HTML} -  Preview - -
  • )} + {articleInfos.preview.stylesheet && (<> +
  • + + Edit + +
  • +
  • + + {articleInfos.preview.stylesheet ? 'Paged.js' : + HTML} +  Preview + +
  • + )}
  • {!live.version &&
  • - +
  • }
diff --git a/front/src/components/Write/tableOfContents.module.scss b/front/src/components/Write/tableOfContents.module.scss new file mode 100644 index 000000000..fd93c1f86 --- /dev/null +++ b/front/src/components/Write/tableOfContents.module.scss @@ -0,0 +1,11 @@ +.tocTooltip.empty { + cursor: not-allowed; +} + +.tocTooltip { + cursor: pointer; +} + +.tocTooltip > svg { + display: flex; +} diff --git a/front/src/components/collaborative/CollaborativeEditorArticleHeader.jsx b/front/src/components/collaborative/CollaborativeEditorArticleHeader.jsx index 6843be94f..160ffbee6 100644 --- a/front/src/components/collaborative/CollaborativeEditorArticleHeader.jsx +++ b/front/src/components/collaborative/CollaborativeEditorArticleHeader.jsx @@ -1,23 +1,20 @@ -import { Loading, Popover, Link as GeistLink, useModal, Modal as GeistModal } from '@geist-ui/core' -import clsx from 'clsx' +import { Loading, useModal, Modal as GeistModal } from '@geist-ui/core' import { Link } from 'react-router-dom' import PropTypes from 'prop-types' import React, { useCallback } from 'react' -import { AlignLeft, Eye, Printer } from 'react-feather' -import { useDispatch, useSelector } from 'react-redux' +import { Eye, Printer } from 'react-feather' import useGraphQL from '../../hooks/graphql.js' import { getArticleInfo } from '../Article.graphql' import Button from '../Button.jsx' import buttonStyles from '../button.module.scss' import Export from '../Export.jsx' +import TableOfContents from '../Write/TableOfContents.jsx' import styles from './CollaborativeEditorArticleHeader.module.scss' export default function CollaborativeEditorArticleHeader ({ articleId }) { - const dispatch = useDispatch() - const articleStructure = useSelector(state => state.articleStructure) const { data, isLoading } = useGraphQL({ query: getArticleInfo, variables: { articleId } }, { revalidateIfStale: false, revalidateOnFocus: false, @@ -29,10 +26,6 @@ export default function CollaborativeEditorArticleHeader ({ articleId }) { bindings: exportModalBinding } = useModal() - const handleTableOfContentsEntryClicked = useCallback(({ target }) => { - dispatch({ type: 'UPDATE_EDITOR_CURSOR_POSITION', lineNumber: parseInt(target.dataset.index, 10), column: 0 }) - }, []) - const handleOpenExportModal = useCallback(() => { setExportModalVisible(true) }, []) @@ -41,27 +34,9 @@ export default function CollaborativeEditorArticleHeader ({ articleId }) { return } - const content = () => { - if (articleStructure.length === 0) { - return <> - } - return <> - - Table Of Contents - - {articleStructure.map((item) => ( - - {item.title} - - ))} - - } - return (

- - - + {data?.article?.title}

diff --git a/front/src/locales/en/translation.json b/front/src/locales/en/translation.json index 496e4ea65..7a6f20e55 100644 --- a/front/src/locales/en/translation.json +++ b/front/src/locales/en/translation.json @@ -269,5 +269,6 @@ "corpus.metadata.form.issue": "Issue", "corpus.metadata.form.issue.title": "Title", "corpus.metadata.form.issue.number": "N°", - "corpus.metadata.form.issue.identifier": "Identifier" + "corpus.metadata.form.issue.identifier": "Identifier", + "toc.title": "Table of contents" } diff --git a/front/src/locales/fr/translation.json b/front/src/locales/fr/translation.json index 872bf50e2..5cf425bc8 100644 --- a/front/src/locales/fr/translation.json +++ b/front/src/locales/fr/translation.json @@ -267,5 +267,6 @@ "corpus.metadata.form.issue": "Numéro de revue", "corpus.metadata.form.issue.title": "Titre", "corpus.metadata.form.issue.number": "N°", - "corpus.metadata.form.issue.identifier": "Identifiant" + "corpus.metadata.form.issue.identifier": "Identifiant", + "toc.title": "Table des matières" }