Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(toc): affiche la table des matières au clique sur l'icone à gauche du titre #1090

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions front/src/components/Write/ArticleEditorMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand All @@ -28,7 +27,6 @@ export default function ArticleEditorMenu ({ articleInfos, readOnly, compareTo,
compareTo={compareTo}
readOnly={readOnly}
/>
<Sommaire />
<Biblio readOnly={readOnly} article={articleInfos} />
<Stats stats={articleStats} />
</div>)}
Expand Down
48 changes: 48 additions & 0 deletions front/src/components/Write/TableOfContents.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
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 <div className={styles.tocPopover}>
<Popover.Item title>
<span>{t('toc.title')}</span>
</Popover.Item>
{articleStructure.map((item) => (
<Popover.Item key={`line-${item.index}-${item.line}`} tabIndex={0} data-index={item.index}
data-heading-anchor={getAnchor(item.line)}>
<GeistLink href="#" data-index={item.index} onClick={handleTableEntryClick}>{item.title}</GeistLink>
</Popover.Item>
))}
</div>
}

return (
<Popover className={clsx(styles.tocTooltip, articleStructure.length === 0 && styles.empty)}
placement="bottomStart"
content={content}
hideArrow={articleStructure.length === 0}>
<AlignLeft/>
</Popover>)
}
57 changes: 32 additions & 25 deletions front/src/components/Write/WorkingVersion.jsx
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -71,8 +70,8 @@ export function ArticleSaveState ({ state, updatedAt, stateMessage }) {
</span>)}
</span>

{state === 'saved' && (<TimeAgo date={isoString}/>)}
</>)
{state === 'saved' && (<TimeAgo date={isoString}/>)}
</>)
}

export default function WorkingVersion ({ articleInfos, live, selectedVersion, mode }) {
Expand All @@ -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`
Expand All @@ -96,27 +94,35 @@ export default function WorkingVersion ({ articleInfos, live, selectedVersion, m
<section className={styles.section}>
<header className={styles.header}>
<h1 className={styles.title}>
<AlignLeft/>
<TableOfContents/>
{articleInfos.title}
</h1>
</header>
{exporting && (
<Modal title="Export" cancel={cancelExport}>
<Export articleVersionId={selectedVersion} articleId={articleInfos._id} bib={live.bibPreview} name={articleInfos.title} />
<Export articleVersionId={selectedVersion} articleId={articleInfos._id} bib={live.bibPreview}
name={articleInfos.title}/>
</Modal>
)}
<ul className={styles.actions}>
{articleInfos.preview.stylesheet && (<><li>
<Link to={`/article/${articleInfos._id}`} className={mode === 'write' ? buttonStyles.primaryDisabled : buttonStyles.secondary} title="Edit article">
<Edit3/> Edit
</Link>
</li>
<li>
<Link to={`/article/${articleInfos._id}/preview`} className={mode === 'preview' ? buttonStyles.primaryDisabled : buttonStyles.secondary} title="Preview article">
<Eye/>{articleInfos.preview.stylesheet ? 'Paged.js' : <abbr title="HyperText Markup Language">HTML</abbr>}
&nbsp;Preview
</Link>
</li></>)}
{articleInfos.preview.stylesheet && (<>
<li>
<Link to={`/article/${articleInfos._id}`}
className={mode === 'write' ? buttonStyles.primaryDisabled : buttonStyles.secondary}
title="Edit article">
<Edit3/> Edit
</Link>
</li>
<li>
<Link to={`/article/${articleInfos._id}/preview`}
className={mode === 'preview' ? buttonStyles.primaryDisabled : buttonStyles.secondary}
title="Preview article">
<Eye/>{articleInfos.preview.stylesheet ? 'Paged.js' :
<abbr title="HyperText Markup Language">HTML</abbr>}
&nbsp;Preview
</Link>
</li>
</>)}
<li>
<Button icon title={t('write.title.buttonExport')} onClick={openExport}>
<Printer/>
Expand All @@ -138,7 +144,8 @@ export default function WorkingVersion ({ articleInfos, live, selectedVersion, m
<ArticleVersion version={live.version}/>
</li>
{!live.version && <li className={styles.lastSaved}>
<ArticleSaveState state={workingArticle.state} updatedAt={workingArticle.updatedAt} stateMessage={workingArticle.stateMessage}/>
<ArticleSaveState state={workingArticle.state} updatedAt={workingArticle.updatedAt}
stateMessage={workingArticle.stateMessage}/>
</li>}
</ul>
</div>
Expand Down
16 changes: 16 additions & 0 deletions front/src/components/Write/tableOfContents.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.tocTooltip.empty {
cursor: not-allowed;
}

.tocPopover {
max-height: calc(100vh - 250px);
overflow: auto;
}

.tocTooltip {
cursor: pointer;
}

.tocTooltip > svg {
display: flex;
}
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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)
}, [])
Expand All @@ -41,27 +34,9 @@ export default function CollaborativeEditorArticleHeader ({ articleId }) {
return <Loading/>
}

const content = () => {
if (articleStructure.length === 0) {
return <></>
}
return <>
<Popover.Item title>
<span>Table Of Contents</span>
</Popover.Item>
{articleStructure.map((item) => (
<Popover.Item key={`line-${item.index}-${item.line}`} tabIndex={0}>
<GeistLink href="#" data-index={item.index} onClick={handleTableOfContentsEntryClicked}>{item.title}</GeistLink>
</Popover.Item>
))}
</>
}

return (<header className={styles.header}>
<h1 className={styles.title}>
<Popover className={clsx(styles.tocTooltip, articleStructure.length === 0 && styles.empty)} placement="bottomStart" content={content} hideArrow={articleStructure.length === 0}>
<AlignLeft/>
</Popover>
<TableOfContents/>
{data?.article?.title}
</h1>

Expand Down
3 changes: 2 additions & 1 deletion front/src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
3 changes: 2 additions & 1 deletion front/src/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
Loading