From a680ddc03225566ee41d5b9215ca0dbc91d4116f Mon Sep 17 00:00:00 2001 From: Daniele Guido Date: Thu, 20 Oct 2022 12:44:26 +0200 Subject: [PATCH 1/7] Fix/issue 475 (#476) undefined --- .../AbstractSubmissionCallForPapers.js | 114 +++++++++++++----- src/logic/params.js | 3 + src/pages/AbstractSubmission.js | 21 +++- .../AbstractSubmissionCallForPapers.scss | 39 ++++++ src/translations.json | 6 +- 5 files changed, 148 insertions(+), 35 deletions(-) diff --git a/src/components/AbstractSubmissionCallForPapers.js b/src/components/AbstractSubmissionCallForPapers.js index 988f696b..4e0593f2 100644 --- a/src/components/AbstractSubmissionCallForPapers.js +++ b/src/components/AbstractSubmissionCallForPapers.js @@ -1,14 +1,18 @@ import React from 'react' import { useGetJSON } from '../logic/api/fetchData' -import { Row, Col } from 'react-bootstrap' +import { Row, Col, DropdownButton, Dropdown } from 'react-bootstrap' import LangLink from './LangLink' import { StatusSuccess, BootstrapColumLayout } from '../constants' import '../styles/components/AbstractSubmissionCallForPapers.scss' +import { useTranslation } from 'react-i18next' const AbstractSubmissionCallForPapers = ({ // cfp is a vaild slug identifier, tested on logic/params.js cfp = '', + // function to update current CFP + onChange, }) => { + const { t } = useTranslation() const url = cfp.length ? `${process.env.REACT_APP_NOTEBOOK_CFP_BASE_URL}/${cfp}/${cfp}.ipynb` : null @@ -17,6 +21,16 @@ const AbstractSubmissionCallForPapers = ({ delay: 0, raw: true, }) + + const { + data: listOfCfps, + error: errorListOfCfps, + status: statusListofCfps, + } = useGetJSON({ + url: '/api/callofpaper', + delay: 100, + }) + console.debug( '[AbstractSubmissionCallForPapers] url:', url, @@ -24,39 +38,77 @@ const AbstractSubmissionCallForPapers = ({ error, status ) - if (!url) { - return null - } - if (error) { - console.error(error) - return null - } + console.debug( + '[AbstractSubmissionCallForPapers] url:', + '/api/callofpaper', + listOfCfps, + errorListOfCfps, + statusListofCfps + ) + const dropdownButtonTitle = cfp.length + ? status === StatusSuccess + ? data.metadata.title + : t('loading') + : t('openCallForPapers') + return ( -
- {status === StatusSuccess ? ( -
-

- Call for papers:{' '} - {data.metadata.title} -

-
- - {data.metadata.jdh.helmet['twitter:data1']} -
- - {data.metadata.jdh.helmet['twitter:data2']} -
-
- ) : ( -

{status}

- )} +
+
+ {cfp.length > 0 && ( +
+ {status === StatusSuccess ? ( +
+

+ Call for papers:  + {data.metadata.title} +

+
+ + {data.metadata.jdh.helmet['twitter:data1']} +
+ + {data.metadata.jdh.helmet['twitter:data2']} +
+
+ ) : ( +

+ )} +
+ )} ) @@ -65,6 +117,6 @@ const AbstractSubmissionCallForPapers = ({ export default React.memo( AbstractSubmissionCallForPapers, (prevProps, nextProps) => { - return prevProps.url === nextProps.url + return prevProps.cfp === nextProps.cfp } ) diff --git a/src/logic/params.js b/src/logic/params.js index 4a8cea38..459b222f 100644 --- a/src/logic/params.js +++ b/src/logic/params.js @@ -7,4 +7,7 @@ export const CfpParam = { } return null }, + encode(value) { + return value + }, } diff --git a/src/pages/AbstractSubmission.js b/src/pages/AbstractSubmission.js index 0eb2f2ef..942063a9 100644 --- a/src/pages/AbstractSubmission.js +++ b/src/pages/AbstractSubmission.js @@ -27,7 +27,10 @@ console.info('%cRecaptcha site key', 'font-weight:bold', ReCaptchaSiteKey) const AbstractSubmission = ({ allowGithubId = false }) => { const { t } = useTranslation() const history = useHistory() - const [callForPapers] = useQueryParam('cfp', withDefault(CfpParam, '')) + const [callForPapers, setCallForPapers] = useQueryParam( + 'cfp', + withDefault(CfpParam, '') + ) const [isPreviewMode, setPreviewMode] = useState(false) const [isSubmitting, setIsSubmitting] = useState(false) const [confirmModalShow, setConfirmModalShow] = useState(false) @@ -107,6 +110,17 @@ const AbstractSubmission = ({ allowGithubId = false }) => { ) }, [temporaryAbstractSubmission]) + useEffect(() => { + console.info( + '[AbstractSubmission] @useEffect \n - callForPapers:', + callForPapers + ) + handleChange({ + id: 'callForPapers', + value: callForPapers, + isValid: true, + }) + }, [callForPapers]) const handleSubmit = async (event) => { event.preventDefault() if (isSubmitting) { @@ -223,7 +237,10 @@ const AbstractSubmission = ({ allowGithubId = false }) => {

{t('pages.abstractSubmission.title')}

- + setCallForPapers(cfp)} + cfp={callForPapers} + />
diff --git a/src/styles/components/AbstractSubmissionCallForPapers.scss b/src/styles/components/AbstractSubmissionCallForPapers.scss index d05f53ef..63a8a6ae 100644 --- a/src/styles/components/AbstractSubmissionCallForPapers.scss +++ b/src/styles/components/AbstractSubmissionCallForPapers.scss @@ -19,3 +19,42 @@ padding: 10px; margin-bottom: 3px; } + +.AbstractSubmissionCallForPapers .dropdown-menu { + border: 1px solid var(--accent); + border-radius: 5px; + background: var(--accent); + padding: var(--spacer-1); + margin-top: 2px; + + // box-shadow: 0 0 0 3px rgb(94 43 255 / 50%); + .dropdown-item { + color: var(--white); + border: 0px transparent; + box-shadow: none; + padding: var(--spacer-1); + } + .dropdown-item > span { + padding: var(--spacer-1); + border-radius: 3px; + } + .dropdown-item:hover, + .dropdown-item.active { + color: var(--white); + background: var(--accent); + } + .dropdown-item:hover > span, + .dropdown-item.active:hover > span { + color: var(--accent); + background-color: var(--white); + } + .dropdown-item.active > span { + border: 1px solid var(--white); + background-color: var(--accent); + } +} +.AbstractSubmissionCallForPapers .dropdown.show > button { + // background-color: var(--accent); + // color: var(--white); + box-shadow: none; +} diff --git a/src/translations.json b/src/translations.json index 6223182f..1ee53637 100644 --- a/src/translations.json +++ b/src/translations.json @@ -13,7 +13,7 @@ "articleHermeneutics": "hermeneutic layer", "articleHermeneuticsData": "hermeneutic layer", "articleData": "data", - "issue":"Articles & Issues", + "issue": "Articles & Issues", "releaseNotes": "Release notes", "faq": "Frequently asked questions" }, @@ -23,6 +23,7 @@ "contactUsingEmail": "Contact us at jdh.admin@uni.lu", "FormNotebookUrl_GenerateLink": "View notebook as journal article!", "Navigation_NotebookViewer": "Preview Notebook", + "openCallForPapers": "Open call for papers", "Pages_NotebookViewer_Title": "Jupyter notebook viewer", "pages": { "about": { @@ -46,7 +47,7 @@ "subheading": "You will soon be contacted by our editors via the email you have indicated in the contact form.", "moreInfo": "If any information needs to be changed, please contact us via email at jdh.admin@uni.lu" }, - "cfp":{ + "cfp": { "applyCallForPapers": "Submit an Abstract" }, "releaseNotes": { @@ -209,6 +210,7 @@ "enum": "not valid", "binderUrlNotAvailable": "Binder is not available for this notebook ..." }, + "selectCallForPapers": "Please select the relevant call for papers:", "schemaErrors": { "instance-acceptConditions": "... and don't forget to check the terms and conditions", "instance-contact": "Please fill the \"Contact\" section with your email and ORCID URL", From 7985c5ea8db9a201d82b441a921097bb2f07e117 Mon Sep 17 00:00:00 2001 From: Daniele Guido Date: Mon, 24 Oct 2022 11:49:06 +0200 Subject: [PATCH 2/7] add base numbering for tables (#479) fix issue #477 --- src/logic/ipynb.js | 570 ++++++++++++++++++++++++++------------------- 1 file changed, 325 insertions(+), 245 deletions(-) diff --git a/src/logic/ipynb.js b/src/logic/ipynb.js index dab634d8..23e16830 100644 --- a/src/logic/ipynb.js +++ b/src/logic/ipynb.js @@ -11,15 +11,23 @@ import ArticleReference from '../models/ArticleReference' import ArticleFigure from '../models/ArticleFigure' import ArticleAnchor from '../models/ArticleAnchor' import { - SectionChoices, SectionDefault, - LayerChoices, LayerNarrative, // LayerHermeneuticsStep, - RoleHidden, RoleFigure, RoleMetadata, RoleCitation, RoleDefault, RoleQuote, - CellTypeMarkdown, CellTypeCode, + SectionChoices, + SectionDefault, + LayerChoices, + LayerNarrative, // LayerHermeneuticsStep, + RoleHidden, + RoleFigure, + RoleMetadata, + RoleCitation, + RoleDefault, + RoleQuote, + CellTypeMarkdown, + CellTypeCode, FigureRefPrefix, TableRefPrefix, CoverRefPrefix, QuoteRefPrefix, - AnchorRefPrefix + AnchorRefPrefix, } from '../constants' const encodeNotebookURL = (url) => btoa(encodeURIComponent(url)) @@ -28,15 +36,15 @@ const decodeNotebookURL = (encodedUrl) => decodeURIComponent(atob(encodedUrl)) const markdownParser = MarkdownIt({ html: false, linkify: true, - typographer: true + typographer: true, }) markdownParser.use(MarkdownItAttrs, { // optional, these are default options leftDelimiter: '{', rightDelimiter: '}', - allowedAttributes: ['class', 'id'] // empty array = all attributes are allowed -}); + allowedAttributes: ['class', 'id'], // empty array = all attributes are allowed +}) markdownParser.use(MarkdownItMathjax) const renderMarkdownWithReferences = ({ @@ -44,27 +52,33 @@ const renderMarkdownWithReferences = ({ referenceIndex = {}, citationsFromMetadata = {}, figures = [], - anchors = [] + anchors = [], }) => { const references = [] // console.info('markdownParser.render', markdownParser.render(sources)) - const content = markdownParser.render(sources) + const content = markdownParser + .render(sources) .replace(/<a[^&]*>(.*)<\/a>/g, '') // replace links "figure-*" ending with automatic numbering syntax - .replace(/([^<]+)<\/a>/g, (m, anchorRef, c, content) => { - const ref = anchorRef.indexOf('anchor-') !== -1 - ? anchors.find(d => d.ref === anchorRef) - : figures.find(d => d.ref === anchorRef) - if (ref) { - return `figure ${ref.num}` + .replace( + /([^<]+)<\/a>/g, + (m, anchorRef, c, content) => { + const ref = + anchorRef.indexOf('anchor-') !== -1 + ? anchors.find((d) => d.ref === anchorRef) + : figures.find((d) => d.ref === anchorRef) + if (ref) { + return `figure ${ref.num}` + } + return `${content}` } - return `${content}` - }) + ) // replace links "figure-" add data-idx attribute containing a figure id .replace(//g, (m, anchorRef) => { - const ref = anchorRef.indexOf('anchor-') !== -1 - ? anchors.find(d => d.ref === anchorRef) - : figures.find(d => d.ref === anchorRef) + const ref = + anchorRef.indexOf('anchor-') !== -1 + ? anchors.find((d) => d.ref === anchorRef) + : figures.find((d) => d.ref === anchorRef) if (ref) { return `` } @@ -81,17 +95,22 @@ const renderMarkdownWithReferences = ({ // "Compiling a collection of tweets of this nature raises considerable methodological issues. // While we will not go into detail, we would refer our readers to previous publications // that touches on these subjects ." - .replace(/<cite\s+data-cite=.([/\dA-Z]+).><\/cite>/g, (m, id) => { - const reference = new ArticleReference({ - ref: citationsFromMetadata[id], - }) - references.push(reference) - return ` + .replace( + /<cite\s+data-cite=.([/\dA-Z]+).><\/cite>/g, + (m, id) => { + const reference = new ArticleReference({ + ref: citationsFromMetadata[id], + }) + references.push(reference) + return ` - ${reference.shortRef || '['+id+']'} + ${ + reference.shortRef || '[' + id + ']' + } ` - }) + } + ) // look for footnotes .replace(/<sup>(\d+)<\/sup>/g, (m, num) => { // add footnote nuber and optionally the Author, year @@ -109,7 +128,7 @@ const renderMarkdownWithReferences = ({ ` }) - return {content, references} + return { content, references } } /** @@ -122,9 +141,13 @@ const renderMarkdownWithReferences = ({ * @param {Array} choices - list of possible valid outputs * @param {Array} defaultChoice - optional. Section default choice * @return {Number|String} - Return one and only one valid value among the choices or the defaultChoice -*/ -const getFirstValidMatchFromChoices = (candidates=[], choiches=[], defaultChoice=null) => { - for (let i=0; i < candidates.length; i++) { + */ +const getFirstValidMatchFromChoices = ( + candidates = [], + choiches = [], + defaultChoice = null +) => { + for (let i = 0; i < candidates.length; i++) { if (choiches.includes(candidates[i])) { return candidates[i] } @@ -140,11 +163,13 @@ const getFirstValidMatchFromChoices = (candidates=[], choiches=[], defaultChoice * * @param {Object} metadata - Notebook cell metadata object * @return {null|String} - Return one and only one valid section or undefined -*/ -const getSectionFromCellMetadata = (metadata) => getFirstValidMatchFromChoices( - [].concat(metadata.tags, metadata.jdh?.section), - SectionChoices, SectionDefault -) + */ +const getSectionFromCellMetadata = (metadata) => + getFirstValidMatchFromChoices( + [].concat(metadata.tags, metadata.jdh?.section), + SectionChoices, + SectionDefault + ) /** * getLayerFromCellMetadata * @@ -154,13 +179,15 @@ const getSectionFromCellMetadata = (metadata) => getFirstValidMatchFromChoices( * * @param {Object} metadata - Notebook cell metadata object * @return {null|String} - Return one and only one valid section or undefined -*/ -const getLayerFromCellMetadata = (metadata) => getFirstValidMatchFromChoices( - [].concat(metadata.tags, metadata.jdh?.layer), - LayerChoices, LayerNarrative -) + */ +const getLayerFromCellMetadata = (metadata) => + getFirstValidMatchFromChoices( + [].concat(metadata.tags, metadata.jdh?.layer), + LayerChoices, + LayerNarrative + ) -const getArticleTreeFromIpynb = ({ id, cells=[], metadata={} }) => { +const getArticleTreeFromIpynb = ({ id, cells = [], metadata = {} }) => { const headings = [] const headingsPositions = [] const figures = [] @@ -169,6 +196,7 @@ const getArticleTreeFromIpynb = ({ id, cells=[], metadata={} }) => { const anchors = [] const sectionsIndex = {} let citationsFromMetadata = metadata?.cite2c?.citations + let tableAutonumbering = 0 if (citationsFromMetadata) { // if one of the key is named "udefined" (sic) @@ -176,24 +204,31 @@ const getArticleTreeFromIpynb = ({ id, cells=[], metadata={} }) => { delete citationsFromMetadata.undefined } // add property issued to correct Cite library bug on date-parts - citationsFromMetadata = Object.keys(citationsFromMetadata).reduce((acc, k) => { - const d = citationsFromMetadata[k] - if (!d.id) { - d.id = k - } - if (typeof d.issued === 'object' && d.issued.year && !d.issued['date-parts']) { - acc[d.id] = { - ...d, - issued: { - ...d.issued, - ['date-parts']: [[d.issued.year]] + citationsFromMetadata = Object.keys(citationsFromMetadata).reduce( + (acc, k) => { + const d = citationsFromMetadata[k] + if (!d.id) { + d.id = k + } + if ( + typeof d.issued === 'object' && + d.issued.year && + !d.issued['date-parts'] + ) { + acc[d.id] = { + ...d, + issued: { + ...d.issued, + ['date-parts']: [[d.issued.year]], + }, } + } else { + acc[d.id] = d } - } else { - acc[d.id] = d - } - return acc - }, {}) + return acc + }, + {} + ) } // this contain footnotes => zotero id to remap reference at paragraph level const referenceIndex = {} @@ -201,190 +236,232 @@ const getArticleTreeFromIpynb = ({ id, cells=[], metadata={} }) => { let bibliography = null // parse biobliographic elements if (citationsFromMetadata instanceof Object) { - bibliography = new Cite(Object.values(citationsFromMetadata).filter(d => d)) + bibliography = new Cite( + Object.values(citationsFromMetadata).filter((d) => d) + ) } let paragraphNumber = 0 // cycle through notebook cells to fill ArticleCells, figures, headings - cells.map((cell, idx) => { - const sources = Array.isArray(cell.source) - ? cell.source.join('\n') - : cell.source - // find footnote citations (with the number) - const footnote = sources.match(//) - const coverRef = cell.metadata.tags?.find(d => d.indexOf(CoverRefPrefix) === 0) - const figureRef = cell.metadata.tags?.find(d => d.indexOf(FigureRefPrefix) === 0) - const tableRef = cell.metadata.tags?.find(d => d.indexOf(TableRefPrefix) === 0) - const quoteRef = cell.metadata.tags?.find(d => d.indexOf(QuoteRefPrefix) === 0) - const anchorRef = cell.metadata.tags?.find(d => d.indexOf(AnchorRefPrefix) === 0) - // get section and layer from metadata - cell.section = getSectionFromCellMetadata(cell.metadata) - cell.layer = getLayerFromCellMetadata(cell.metadata) - cell.role = RoleDefault - // get role in a secont step - if (sources.length === 0 || cell.metadata.tags?.includes('hidden') || cell.metadata.jdh?.hidden) { - // is hidden (e.g. uninteresting code, like pip install) - cell.hidden = true - cell.role = RoleHidden - } else if (footnote) { - // it is a footnote cell given by Cite2c - referenceIndex[footnote[1]] = footnote[2] - cell.hidden = true - cell.role = RoleCitation - } else if (figureRef) { - // this is a proper figure, nothing to say about it. - figures.push(new ArticleFigure({ - ref: figureRef, idx , - num: figures.length + 1 - })) - cell.role = RoleFigure - } else if (coverRef) { - figures.push(new ArticleFigure({ ref: coverRef, idx, isCover:true })) - cell.role = RoleFigure - } else if (tableRef) { - // this is a proper figure, nothing to say about it. - figures.push(new ArticleFigure({ ref: tableRef, idx, isTable: true })) - cell.role = RoleFigure - } else if (quoteRef) { - cell.role = RoleQuote - } else if (idx < cells.length && cell.cell_type === 'code' && Array.isArray(cell.outputs) && cell.outputs.length) { - // this is a "Figure" candindate. - // Let's check whether the cell outputs JDH metadata and if jdh namespace contains **module**; - const cellOutputJdhMetadata = cell.outputs.find(d => d.metadata?.jdh?.module) - if (cellOutputJdhMetadata) { - // if yes, these metadata AND its output will be added to this cell. - cell.metadata = { - ...cell.metadata, - jdh: { - ...cell.metadata.jdh, - ...cellOutputJdhMetadata.metadata.jdh, - ref: idx, - outputs: cell.outputs + cells + .map((cell, idx) => { + const sources = Array.isArray(cell.source) + ? cell.source.join('\n') + : cell.source + // find footnote citations (with the number) + const footnote = sources.match( + // + ) + const coverRef = cell.metadata.tags?.find( + (d) => d.indexOf(CoverRefPrefix) === 0 + ) + const figureRef = cell.metadata.tags?.find( + (d) => d.indexOf(FigureRefPrefix) === 0 + ) + const tableRef = cell.metadata.tags?.find( + (d) => d.indexOf(TableRefPrefix) === 0 + ) + const quoteRef = cell.metadata.tags?.find( + (d) => d.indexOf(QuoteRefPrefix) === 0 + ) + const anchorRef = cell.metadata.tags?.find( + (d) => d.indexOf(AnchorRefPrefix) === 0 + ) + // get section and layer from metadata + cell.section = getSectionFromCellMetadata(cell.metadata) + cell.layer = getLayerFromCellMetadata(cell.metadata) + cell.role = RoleDefault + // get role in a secont step + if ( + sources.length === 0 || + cell.metadata.tags?.includes('hidden') || + cell.metadata.jdh?.hidden + ) { + // is hidden (e.g. uninteresting code, like pip install) + cell.hidden = true + cell.role = RoleHidden + } else if (footnote) { + // it is a footnote cell given by Cite2c + referenceIndex[footnote[1]] = footnote[2] + cell.hidden = true + cell.role = RoleCitation + } else if (figureRef) { + // this is a proper figure, nothing to say about it. + figures.push( + new ArticleFigure({ + ref: figureRef, + idx, + num: figures.length + 1, + }) + ) + cell.role = RoleFigure + } else if (coverRef) { + figures.push(new ArticleFigure({ ref: coverRef, idx, isCover: true })) + cell.role = RoleFigure + } else if (tableRef) { + tableAutonumbering += 1 + // this is a proper figure, nothing to say about it. + figures.push( + new ArticleFigure({ + ref: tableRef, + idx, + isTable: true, + num: +tableAutonumbering, + }) + ) + cell.role = RoleFigure + } else if (quoteRef) { + cell.role = RoleQuote + } else if ( + idx < cells.length && + cell.cell_type === 'code' && + Array.isArray(cell.outputs) && + cell.outputs.length + ) { + // this is a "Figure" candindate. + // Let's check whether the cell outputs JDH metadata and if jdh namespace contains **module**; + const cellOutputJdhMetadata = cell.outputs.find( + (d) => d.metadata?.jdh?.module + ) + if (cellOutputJdhMetadata) { + // if yes, these metadata AND its output will be added to this cell. + cell.metadata = { + ...cell.metadata, + jdh: { + ...cell.metadata.jdh, + ...cellOutputJdhMetadata.metadata.jdh, + ref: idx, + outputs: cell.outputs, + }, } + figures.push( + new ArticleFigure({ + module: cell.metadata.jdh.module, + type: cell.metadata.jdh.object?.type, + idx, + num: figures.length + 1, + }) + ) + cell.role = RoleFigure } - figures.push(new ArticleFigure({ - module: cell.metadata.jdh.module, - type: cell.metadata.jdh.object?.type, - idx, - num: figures.length + 1 - })) - cell.role = RoleFigure + // this is not a real "Figure", just a "Data..." + } else if (cell.section !== SectionDefault) { + cell.role = RoleMetadata } - // this is not a real "Figure", just a "Data..." - } else if (cell.section !== SectionDefault) { - cell.role = RoleMetadata - } - if (anchorRef) { - anchors.push(new ArticleAnchor({ ref: anchorRef, idx })) - } - cell.source = Array.isArray(cell.source) - ? cell.source - : [cell.source] - if (cell.role !== RoleMetadata) { - paragraphNumber += 1 - cell.num = paragraphNumber - } - return cell - }).forEach((cell, idx) => { - // console.info('ipynb', cell.role, cell.num) - if (cell.cell_type === CellTypeMarkdown) { - const sources = cell.source.join('') - // exclude rendering of reference references - let tokens = [] - try { - tokens = markdownParser.parse(sources); - } catch(err) { - console.warn('Couldn\'t parse cell markdown tokens', cell, err) - } - const {content, references} = renderMarkdownWithReferences({ - sources, - referenceIndex, - citationsFromMetadata, - figures, - anchors - }) - // get tokens 'heading_open' to get the first h1,h2,h3 in source. - const headerIdx = tokens.findIndex(t => t.type === 'heading_open'); - if (headerIdx > -1) { - // We used to get heading content from the next token, as this is the - // first element after the heading_open. - // If it has only one child, everything works as expected: - // we can safely get its plain text from the `content` property as it is - // a text node (DOM). - // However, sometimes authors want to put emphasised text in their - // heading. For instance, the sentence: - // - // "Quantifying the *epigraphic habit*, in space and time" - // - // is composed of 5 children: - // - // [text] "Quantifying the ", - // [em_open] "", - // [text] "epigraphic habit", - // [em_close] "", - // [text] ", in space and time" - // - // Hence, if we want to have only the plain text content, - // we have to join the content of the children of the next token... - const headingContent = tokens[headerIdx + 1].children - .map(d => d.content) - .join('') - - headings.push(new ArticleHeading({ - level: parseInt(tokens[headerIdx].tag.replace(/[^\d]/, '')), - tag: tokens[headerIdx].tag, - content: headingContent, - idx - })) + if (anchorRef) { + anchors.push(new ArticleAnchor({ ref: anchorRef, idx })) } - if(headerIdx > -1 || cell.role === RoleFigure) { - headingsPositions.push(idx) + cell.source = Array.isArray(cell.source) ? cell.source : [cell.source] + if (cell.role !== RoleMetadata) { + paragraphNumber += 1 + cell.num = paragraphNumber } - articleCells.push(new ArticleCell({ - type: CellTypeMarkdown, - content, - source: cell.source, - section: cell.section, - metadata: cell.metadata, - layer: cell.layer, - role: cell.role, - idx, - num: cell.num, - references, - hidden: !!cell.hidden, - heading: headerIdx > -1 - ? headings[headings.length - 1] - : null, - level: headerIdx > -1 - ? tokens[headerIdx].tag - : 'p', - figure: cell.role === RoleFigure - ? figures.find((d) => d.idx === idx) - : null - })) - } else if (cell.cell_type === CellTypeCode) { - articleCells.push(new ArticleCell({ - type: CellTypeCode, - content: cell.source.join(''), - section: cell.section, - source: cell.source, - metadata: cell.metadata, - role: cell.role, - layer: cell.layer, - idx, - num: cell.num, - outputs: cell.outputs, - hidden: !!cell.hidden, - level: 'code', - figure: cell.role === RoleFigure - ? figures.find((d) => d.idx === idx) - : null - })) - if(cell.role === RoleFigure) { - headingsPositions.push(idx) + return cell + }) + .forEach((cell, idx) => { + // console.info('ipynb', cell.role, cell.num) + if (cell.cell_type === CellTypeMarkdown) { + const sources = cell.source.join('') + // exclude rendering of reference references + let tokens = [] + try { + tokens = markdownParser.parse(sources) + } catch (err) { + console.warn("Couldn't parse cell markdown tokens", cell, err) + } + const { content, references } = renderMarkdownWithReferences({ + sources, + referenceIndex, + citationsFromMetadata, + figures, + anchors, + }) + // get tokens 'heading_open' to get the first h1,h2,h3 in source. + const headerIdx = tokens.findIndex((t) => t.type === 'heading_open') + if (headerIdx > -1) { + // We used to get heading content from the next token, as this is the + // first element after the heading_open. + // If it has only one child, everything works as expected: + // we can safely get its plain text from the `content` property as it is + // a text node (DOM). + // However, sometimes authors want to put emphasised text in their + // heading. For instance, the sentence: + // + // "Quantifying the *epigraphic habit*, in space and time" + // + // is composed of 5 children: + // + // [text] "Quantifying the ", + // [em_open] "", + // [text] "epigraphic habit", + // [em_close] "", + // [text] ", in space and time" + // + // Hence, if we want to have only the plain text content, + // we have to join the content of the children of the next token... + const headingContent = tokens[headerIdx + 1].children + .map((d) => d.content) + .join('') + + headings.push( + new ArticleHeading({ + level: parseInt(tokens[headerIdx].tag.replace(/[^\d]/, '')), + tag: tokens[headerIdx].tag, + content: headingContent, + idx, + }) + ) + } + if (headerIdx > -1 || cell.role === RoleFigure) { + headingsPositions.push(idx) + } + articleCells.push( + new ArticleCell({ + type: CellTypeMarkdown, + content, + source: cell.source, + section: cell.section, + metadata: cell.metadata, + layer: cell.layer, + role: cell.role, + idx, + num: cell.num, + references, + hidden: !!cell.hidden, + heading: headerIdx > -1 ? headings[headings.length - 1] : null, + level: headerIdx > -1 ? tokens[headerIdx].tag : 'p', + figure: + cell.role === RoleFigure + ? figures.find((d) => d.idx === idx) + : null, + }) + ) + } else if (cell.cell_type === CellTypeCode) { + articleCells.push( + new ArticleCell({ + type: CellTypeCode, + content: cell.source.join(''), + section: cell.section, + source: cell.source, + metadata: cell.metadata, + role: cell.role, + layer: cell.layer, + idx, + num: cell.num, + outputs: cell.outputs, + hidden: !!cell.hidden, + level: 'code', + figure: + cell.role === RoleFigure + ? figures.find((d) => d.idx === idx) + : null, + }) + ) + if (cell.role === RoleFigure) { + headingsPositions.push(idx) + } } - } - }) - for (let i = 0; i < articleCells.length; i+=1) { + }) + for (let i = 0; i < articleCells.length; i += 1) { // add cell to section (for role Metadata) if (!sectionsIndex[articleCells[i].section]) { sectionsIndex[articleCells[i].section] = [] @@ -425,24 +502,27 @@ const getArticleTreeFromIpynb = ({ id, cells=[], metadata={} }) => { headingsPositions, cells: articleCells, paragraphs: articleParagraphs, - paragraphsPositions: articleParagraphs.map(d => d.idx), + paragraphsPositions: articleParagraphs.map((d) => d.idx), sections: sectionsIndex, - bibliography, figures, anchors, - citationsFromMetadata + bibliography, + figures, + anchors, + citationsFromMetadata, }) } const getStepsFromMetadata = ({ metadata }) => { - return (metadata.jdh.steps ?? []).map(step => ({ + return (metadata.jdh.steps ?? []).map((step) => ({ ...step, - content: markdownParser.render(step.source.join('\n')) + content: markdownParser.render(step.source.join('\n')), })) } -const getParsedSteps = ({ steps }) => steps.map(step => ({ - ...step, - content: markdownParser.render(step.source.join(' \n')) -})) +const getParsedSteps = ({ steps }) => + steps.map((step) => ({ + ...step, + content: markdownParser.render(step.source.join(' \n')), + })) export { markdownParser, @@ -450,5 +530,5 @@ export { getArticleTreeFromIpynb, getStepsFromMetadata, encodeNotebookURL, - decodeNotebookURL + decodeNotebookURL, } From 71f66e9f572e51b5f0154bb81fafa78a504e65ac Mon Sep 17 00:00:00 2001 From: eliselavy <35602279+eliselavy@users.noreply.github.com> Date: Mon, 24 Oct 2022 15:54:16 +0200 Subject: [PATCH 3/7] readme docker-compose --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 336ef127..ba426393 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,13 @@ # journal of digital history Frontend app (React) for the JDH journal: journal issues, write and read scholar publication on digital history +## run via docker en development +``` + docker-compose up +``` + + and laucnh via the browser http://localhost:3000/ + ## installation yarn install From af429a94f7dbdb1286e8b439d65cd6c1b99c15df Mon Sep 17 00:00:00 2001 From: eliselavy <35602279+eliselavy@users.noreply.github.com> Date: Mon, 24 Oct 2022 15:54:44 +0200 Subject: [PATCH 4/7] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ba426393..3f7d14be 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # journal of digital history Frontend app (React) for the JDH journal: journal issues, write and read scholar publication on digital history -## run via docker en development +## run via docker in development mode ``` docker-compose up ``` From 01d7f492fc832cf8c951bdd7bbf02e739064f0b6 Mon Sep 17 00:00:00 2001 From: Daniele Guido Date: Mon, 24 Oct 2022 16:01:00 +0200 Subject: [PATCH 5/7] Fix/issue 478 (#480) * allow specific tags to become articlecell tags * add style for `article-info` * upgrade node:19.0-alpine --- Dockerfile.dev | 2 +- src/components/Article/ArticleCell.js | 118 +++++-- src/components/Article/ArticleCellFigure.js | 105 +++--- src/constants.js | 126 ++++--- src/styles/article.scss | 358 +++++++++++--------- 5 files changed, 427 insertions(+), 282 deletions(-) diff --git a/Dockerfile.dev b/Dockerfile.dev index 4b690c41..15461e7b 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,4 +1,4 @@ -FROM node:13.12.0-alpine +FROM node:19.0-alpine ARG GIT_TAG ARG GIT_BRANCH diff --git a/src/components/Article/ArticleCell.js b/src/components/Article/ArticleCell.js index 84cadc8b..86c18a2e 100644 --- a/src/components/Article/ArticleCell.js +++ b/src/components/Article/ArticleCell.js @@ -1,57 +1,91 @@ -import React, { lazy } from 'react'; -import { Container, Row, Col} from 'react-bootstrap' +import React, { lazy } from 'react' +import { Container, Row, Col } from 'react-bootstrap' import ArticleCellOutputs from './ArticleCellOutputs' import ArticleCellContent from './ArticleCellContent' import ArticleCellSourceCode from './ArticleCellSourceCode' import ArticleCellFigure from './ArticleCellFigure' import { - ModuleStack, ModuleTextObject, ModuleObject, ModuleQuote, + ModuleStack, + ModuleTextObject, + ModuleObject, + ModuleQuote, BootstrapColumLayout, BootstrapQuoteColumLayout, BootstrapNarrativeStepColumnLayout, BootstrapNarrativeStepFigureColumnLayout, - RoleQuote + RoleQuote, + ArticleCellContainerClassNames, } from '../../constants' -const ArticleCellVisualisation = lazy(() => import('./ArticleCellVisualisation')) +const ArticleCellVisualisation = lazy(() => + import('./ArticleCellVisualisation') +) const ArticleCellTextObject = lazy(() => import('./ArticleCellTextObject')) const ArticleCellObject = lazy(() => import('./ArticleCellObject')) - const ArticleCell = ({ - type, layer, num=1, content='', idx, outputs=[], hideNum, metadata = {}, + type, + layer, + num = 1, + content = '', + idx, + outputs = [], + hideNum, + metadata = {}, role, - progress, active = false, + progress, + active = false, isNarrativeStep, figure, // ArticleFigure instance - headingLevel=0, // if isHeading, set this to its ArticleHeading.level value + headingLevel = 0, // if isHeading, set this to its ArticleHeading.level value isJavascriptTrusted = false, onNumClick, }) => { - let cellBootstrapColumnLayout = metadata.jdh?.text?.bootstrapColumLayout || BootstrapColumLayout; + let cellBootstrapColumnLayout = + metadata.jdh?.text?.bootstrapColumLayout || BootstrapColumLayout // we override or set the former layout if it appears in narrative-step if (isNarrativeStep) { cellBootstrapColumnLayout = BootstrapNarrativeStepColumnLayout } // this layout will be applied to module:"object" and module: "text_object" - let cellObjectBootstrapColumnLayout = metadata.jdh?.object?.bootstrapColumLayout || BootstrapColumLayout; + let cellObjectBootstrapColumnLayout = + metadata.jdh?.object?.bootstrapColumLayout || BootstrapColumLayout if (isNarrativeStep && figure) { cellObjectBootstrapColumnLayout = BootstrapNarrativeStepFigureColumnLayout } const cellModule = metadata.jdh?.module + const containerClassNames = (metadata.tags ?? []).filter((d) => + ArticleCellContainerClassNames.includes(d) + ) + if (cellModule === ModuleStack) { - return + return ( + + ) } if (cellModule === ModuleTextObject) { return ( - + - - + + - - + + @@ -59,10 +93,15 @@ const ArticleCell = ({ } if (!figure && cellModule === ModuleObject) { return ( - + - - + + @@ -70,9 +109,9 @@ const ArticleCell = ({ } if (cellModule === ModuleQuote || role === RoleQuote) { return ( - + - + + - + } + sourceCode={ + + } + containerClassName={containerClassNames.join(' ')} > ) } return ( - + - -
-
- + +
+
+ ) } - return (
unknown type: {type}
) + return
unknown type: {type}
} export default React.memo(ArticleCell, (prevProps, nextProps) => { - if (prevProps.memoid === nextProps.memoid || prevProps.active === nextProps.active) { + if ( + prevProps.memoid === nextProps.memoid || + prevProps.active === nextProps.active + ) { return true // props are equal } return false // props are not equal -> update the component diff --git a/src/components/Article/ArticleCellFigure.js b/src/components/Article/ArticleCellFigure.js index 72e67afe..2a3e5144 100644 --- a/src/components/Article/ArticleCellFigure.js +++ b/src/components/Article/ArticleCellFigure.js @@ -2,19 +2,29 @@ import React from 'react' import ArticleCellOutputs from './ArticleCellOutputs' import ArticleFigure from './ArticleFigure' import { markdownParser } from '../../logic/ipynb' -import {BootstrapColumLayout} from '../../constants' -import { Container, Row, Col} from 'react-bootstrap' +import { BootstrapColumLayout } from '../../constants' +import { Container, Row, Col } from 'react-bootstrap' const ArticleCellFigure = ({ - figure, metadata={}, outputs=[], sourceCode, + figure, + metadata = {}, + outputs = [], + sourceCode, isJavascriptTrusted, figureColumnLayout, - children + children, + containerClassName, }) => { - const isFluidContainer = figure.isCover || (metadata.tags && metadata.tags.includes('full-width')) + const isFluidContainer = + figure.isCover || (metadata.tags && metadata.tags.includes('full-width')) const captions = outputs.reduce((acc, output) => { - if (output.metadata && Array.isArray(output.metadata?.jdh?.object?.source)) { - acc.push(markdownParser.render(output.metadata.jdh.object.source.join('\n'))) + if ( + output.metadata && + Array.isArray(output.metadata?.jdh?.object?.source) + ) { + acc.push( + markdownParser.render(output.metadata.jdh.object.source.join('\n')) + ) } return acc }, []) @@ -23,48 +33,61 @@ const ArticleCellFigure = ({ captions.push(markdownParser.render(metadata.jdh.object.source.join('\n'))) } - let columnLayout = figureColumnLayout ?? outputs.reduce((acc, output) => { - if (output.metadata && output.metadata.jdh?.object?.bootstrapColumLayout) { - acc = { acc, ...output.metadata.jdh?.object?.bootstrapColumLayout } - } - return acc - }, BootstrapColumLayout) + let columnLayout = + figureColumnLayout ?? + outputs.reduce((acc, output) => { + if ( + output.metadata && + output.metadata.jdh?.object?.bootstrapColumLayout + ) { + acc = { acc, ...output.metadata.jdh?.object?.bootstrapColumLayout } + } + return acc + }, BootstrapColumLayout) if (metadata.jdh?.object?.bootstrapColumLayout) { - figureColumnLayout = { ...figureColumnLayout, ...metadata.jdh?.object?.bootstrapColumLayout } + figureColumnLayout = { + ...figureColumnLayout, + ...metadata.jdh?.object?.bootstrapColumLayout, + } } - return ( -
- - - -
-
- -
- {children} - - - - {figure.isCover ? null : ( - - - - {sourceCode} -

').replace(/(Fig.|figure|table)\s+[\da-z-]+\s*:\s+/i, ''), - }} /> +

+ + + +
+
+ +
+ {children} - )} + {figure.isCover ? null : ( + + + + {sourceCode} + +

') + .replace(/(Fig.|figure|table)\s+[\da-z-]+\s*:\s+/i, ''), + }} + /> + + + + + )}

) } diff --git a/src/constants.js b/src/constants.js index 230689de..2bf06cba 100644 --- a/src/constants.js +++ b/src/constants.js @@ -1,26 +1,53 @@ import { isMobile, isTablet } from 'react-device-detect' -export const IsPortrait = window.innerWidth < window.innerHeight +export const IsPortrait = window.innerWidth < window.innerHeight export const IsMobile = isMobile ? true : false export const IsTablet = isTablet ? true : false -export const HomeRoute = { to:'/', label: 'navigation.home'} -export const ReferencesRoute = { to: '/references', label: 'navigation.references' } +export const HomeRoute = { to: '/', label: 'navigation.home' } +export const ReferencesRoute = { + to: '/references', + label: 'navigation.references', +} export const DatasetsRoute = { to: '/datasets', label: 'navigation.datasets' } -export const AbstractSubmissionRoute = { to: '/submit', label: 'navigation.submit' } +export const AbstractSubmissionRoute = { + to: '/submit', + label: 'navigation.submit', +} export const AboutRoute = { to: '/about', label: 'navigation.about' } -export const AbstractSubmissionPreviewRoute = { to:'/abstract', label: 'navigation.abstract'} -export const ArticleRoute = { to:'/article', label: 'navigation.article'} -export const ArticleHermeneuticsRoute = { to:'/article/hermeneutics', label: 'navigation.articleHermeneutics'} -export const ArticleHermeneuticsDataRoute = { to:'/article/hermeneutics,data', label: 'navigation.articleHermeneuticsData'} -export const TermsOfUseRoute = { to:'/terms', label: 'navigation.termsOfUse'} -export const GuidelinesRoute = { to:'/guidelines', label: 'navigation.guidelines'} -export const NotebookViewerRoute = { to:'/notebook-viewer-form', label: 'Navigation_NotebookViewer'} -export const IssueRoute = { to:'/issues', label: 'navigation.issue'} -export const ArticlesRoute = { to:'/articles', label: 'navigation.issue', alias:['/issues', '/article/', '/issue/']} -export const ReleaseNotesRoute = { to:'/release-notes', label: 'navigation.releaseNotes'} -export const FaqRoute = { to:'/faq', label: 'navigation.faq'} - +export const AbstractSubmissionPreviewRoute = { + to: '/abstract', + label: 'navigation.abstract', +} +export const ArticleRoute = { to: '/article', label: 'navigation.article' } +export const ArticleHermeneuticsRoute = { + to: '/article/hermeneutics', + label: 'navigation.articleHermeneutics', +} +export const ArticleHermeneuticsDataRoute = { + to: '/article/hermeneutics,data', + label: 'navigation.articleHermeneuticsData', +} +export const TermsOfUseRoute = { to: '/terms', label: 'navigation.termsOfUse' } +export const GuidelinesRoute = { + to: '/guidelines', + label: 'navigation.guidelines', +} +export const NotebookViewerRoute = { + to: '/notebook-viewer-form', + label: 'Navigation_NotebookViewer', +} +export const IssueRoute = { to: '/issues', label: 'navigation.issue' } +export const ArticlesRoute = { + to: '/articles', + label: 'navigation.issue', + alias: ['/issues', '/article/', '/issue/'], +} +export const ReleaseNotesRoute = { + to: '/release-notes', + label: 'navigation.releaseNotes', +} +export const FaqRoute = { to: '/faq', label: 'navigation.faq' } export const PrimaryRoutes = [ HomeRoute, @@ -39,45 +66,45 @@ export const NotebookPoweredPaths = [ '/notebook-viewer/', '/cfp/', '/guidelines/', - '/guidelines' + '/guidelines', ] export const ReCaptchaSiteKey = process.env.REACT_APP_RECAPTCHA_SITE_KEY export const GaTrackingId = process.env.REACT_APP_GA_TRACKING_ID export const BootstrapColumLayout = Object.freeze({ - md: { span:8, offset:1 }, - lg: { span:8, offset:2 } + md: { span: 8, offset: 1 }, + lg: { span: 8, offset: 2 }, }) export const BootstrapFullColumLayout = Object.freeze({ - md: { span:10, offset:1 }, - lg: { span:8, offset:2 } + md: { span: 10, offset: 1 }, + lg: { span: 8, offset: 2 }, }) export const BootstrapSideColumLayout = Object.freeze({ - md: { span:2, offset:0 }, + md: { span: 2, offset: 0 }, }) export const BootstrapMainColumLayout = Object.freeze({ - md: { span:6, offset:1 }, + md: { span: 6, offset: 1 }, }) export const BootstrapQuoteColumLayout = Object.freeze({ - md: { span:6, offset:3 }, - lg: { span:6, offset:3 } + md: { span: 6, offset: 3 }, + lg: { span: 6, offset: 3 }, }) export const BootstrapNarrativeStepFigureColumnLayout = Object.freeze({ - md: { span:12 }, - lg: { span:12 } + md: { span: 12 }, + lg: { span: 12 }, }) export const BootstrapNarrativeStepColumnLayout = Object.freeze({ - md: { span:4, offset:6 }, - lg: { span:3, offset:7 } + md: { span: 4, offset: 6 }, + lg: { span: 3, offset: 7 }, }) export const BootstrapNarrativeStepCaptionColumnLayout = Object.freeze({ - md: { span:4, offset:1 }, - lg: { span:4, offset:1 } + md: { span: 4, offset: 1 }, + lg: { span: 4, offset: 1 }, }) export const StatusIdle = 'IDLE' @@ -93,7 +120,6 @@ export const ModuleQuote = 'quote' export const ScrollamaThreshold = 0 - // Cell layer choices export const LayerNarrative = 'narrative' export const LayerHermeneutics = 'hermeneutics' @@ -102,8 +128,12 @@ export const LayerNarrativeStep = 'narrative-step' export const LayerData = 'data' export const LayerHidden = 'hidden' export const LayerChoices = [ - LayerNarrative, LayerHermeneutics, LayerHermeneuticsStep, LayerData, - LayerHidden, LayerNarrativeStep + LayerNarrative, + LayerHermeneutics, + LayerHermeneuticsStep, + LayerData, + LayerHidden, + LayerNarrativeStep, ] // Cell sections @@ -116,9 +146,13 @@ export const SectionCover = 'cover' export const SectionDisclaimer = 'disclaimer' export const SectionDefault = 'text' // default export const SectionChoices = [ - SectionTitle, SectionAbstract, SectionContributor, + SectionTitle, + SectionAbstract, + SectionContributor, SectionCollaborators, - SectionKeywords, SectionDisclaimer, SectionDefault + SectionKeywords, + SectionDisclaimer, + SectionDefault, ] // Cell Roles @@ -129,9 +163,12 @@ export const RoleCitation = 'citation' export const RoleQuote = 'quote' export const RoleDefault = 'none' // default export const RoleChoices = [ - RoleHidden, RoleFigure, - RoleMetadata, RoleCitation, RoleQuote, - RoleDefault + RoleHidden, + RoleFigure, + RoleMetadata, + RoleCitation, + RoleQuote, + RoleDefault, ] export const CellTypeCode = 'code' @@ -167,4 +204,13 @@ export const ArticleStatusDraft = 'Draft' // article component version export const ArticleVersionQueryParam = 'v' -export const URLPathsAlwaysTrustJS = (process.env.REACT_APP_ALWAYS_JS_FROM_URL_PATH_PREFIX || '').split(',') +export const URLPathsAlwaysTrustJS = ( + process.env.REACT_APP_ALWAYS_JS_FROM_URL_PATH_PREFIX || '' +).split(',') + +export const ArticleCellContainerClassNames = [ + 'alert-info', + 'alert-success', + 'alert-danger', + 'alert-warning', +] diff --git a/src/styles/article.scss b/src/styles/article.scss index 37d52446..2d0e8a51 100644 --- a/src/styles/article.scss +++ b/src/styles/article.scss @@ -6,20 +6,20 @@ $breakpoint-lg: 992px; } .ArticleCellContent blockquote { - border-left: 3px solid rgba(0,0,0,.3); + border-left: 3px solid rgba(0, 0, 0, 0.3); padding-left: var(--spacer-3); margin-left: 0; } @media (min-width: $breakpoint-tablet) { - .ArticleCellContent blockquote{ + .ArticleCellContent blockquote { border-left: var(--spacer-1) solid; padding-left: var(--spacer-4); margin-left: var(--spacer-4); } } -.ArticleCellObserver.active .ArticleCellContent_num{ +.ArticleCellObserver.active .ArticleCellContent_num { color: var(--secondary); } @@ -35,15 +35,18 @@ $breakpoint-lg: 992px; font-size: 12px; top: 4px; will-change: color; - transition: color .25s ease-in-out; + transition: color 0.25s ease-in-out; - &.level_H2{ + &.level_H2 { top: 14px; } - &.level_H3, &.level_H4, &.level_H5, &.level_H6{ + &.level_H3, + &.level_H4, + &.level_H5, + &.level_H6 { top: 20px; } - &.selectable{ + &.selectable { cursor: pointer; text-decoration: underline; } @@ -59,9 +62,9 @@ $breakpoint-lg: 992px; color: var(--dark); } -.ArticleCellQuote{ +.ArticleCellQuote { font-size: var(--font-size-2); - blockquote{ + blockquote { border-left-width: 0; margin-left: 0; padding-left: 0; @@ -69,19 +72,21 @@ $breakpoint-lg: 992px; } } -.ArticleStream_paragraph{ - +.ArticleStream_paragraph { position: relative; border-left: 1px solid transparent; margin-top: var(--spacer-3); margin-bottom: var(--spacer-3); - h2,h3,h4{ + h2, + h3, + h4 { margin-top: var(--spacer-3); margin-bottom: 0; } - h3, h4{ + h3, + h4 { font-family: var(--font-family-monospace); font-weight: bold; font-size: inherit; @@ -106,76 +111,73 @@ $breakpoint-lg: 992px; // } } -.ArticleStream_paragraph.hermeneutics .ArticleCellContent p{ +.ArticleStream_paragraph.hermeneutics .ArticleCellContent p { color: var(--accent); } @media (min-width: $breakpoint-lg) { .ArticleStream_paragraph.hermeneutics { overflow-x: hidden; - .container{ - transform: translate3d(8%, 0, 0) + .container { + transform: translate3d(8%, 0, 0); } } } - -.ArticleText_toc{ - z-index:1031; +.ArticleText_toc { + z-index: 1031; pointer-events: none; position: fixed; right: 0; } @media (min-width: $breakpoint-lg) { - .ArticleText_toc{ + .ArticleText_toc { width: 16%; } } - -.ArticleToc_Level_P,.ArticleToc_Level_CODE{ +.ArticleToc_Level_P, +.ArticleToc_Level_CODE { &.ArticleToc_afterNextHeading, - &.ArticleToc_beforePreviousHeading{ + &.ArticleToc_beforePreviousHeading { height: 1px; border-top-width: 0; } - &.ArticleToc_beforeNextHeading{ + &.ArticleToc_beforeNextHeading { height: 5px; } } -.ArticleToc_Level_H1{ +.ArticleToc_Level_H1 { margin-left: var(--negative-spacer-4); width: 10px; height: 10px; } // -.ArticleToc_Level_H2{ +.ArticleToc_Level_H2 { margin-left: var(--negative-spacer-3); width: 10px; height: 10px; } // .ArticleToc_Level_H3, -.ArticleToc_Level_H4{ +.ArticleToc_Level_H4 { margin-left: var(--negative-spacer-2); - } -.ArticleToc_Type_code{ +.ArticleToc_Type_code { border-radius: 0; // transform: rotate(45deg); border: 1px solid var(--accent); } -.ArticleToc_References{ +.ArticleToc_References { background-color: var(--secondary); width: var(--spacer-1); height: var(--spacer-1); border-radius: var(--spacer-1); } - -.ArticleToc_Heading, .ArticleToc_Figure{ - +.ArticleToc_Heading, +.ArticleToc_Figure { text-align: right; right: var(--spacer-3); top: var(--negative-spacer-1); @@ -185,10 +187,10 @@ $breakpoint-lg: 992px; overflow: hidden; width: 120px; white-space: nowrap; - &:hover{ + &:hover { text-decoration: underline; } - &.active{ + &.active { font-weight: bold; // width: 200px; // text-overflow:ellipsis; @@ -197,7 +199,7 @@ $breakpoint-lg: 992px; } } -.ArticleReference_num{ +.ArticleReference_num { display: none; } @@ -206,18 +208,18 @@ $breakpoint-lg: 992px; // margin-right: var(--spacer-2); // } -.ArticleReference_shortRef{ +.ArticleReference_shortRef { // font-weight: bold; // font-family: var(--font-family-monospace); display: inline-block; color: var(--gray-600); cursor: pointer; - > a{ + > a { box-shadow: 0px 1px 0px var(--gray-600); } - &:hover{ + &:hover { color: var(--secondary); - > a{ + > a { box-shadow: 0px 1px 0px var(--secondary); } } @@ -228,7 +230,7 @@ $breakpoint-lg: 992px; // .ArticleReference_shortRef::after{ // content:")"; // } -.ArticleReference_pointer{ +.ArticleReference_pointer { // position: absolute; // left: var(--negative-spacer-4); // // border-top: 1px solid var(--secondary); @@ -243,16 +245,16 @@ $breakpoint-lg: 992px; .ArticleCellVisualisation { will-change: opacity; - transition: opacity .6s ease-in-out; + transition: opacity 0.6s ease-in-out; } .ArticleCellVisualisation_step { color: var(--dark); will-change: opacity; - transition: opacity .6s ease-in-out; + transition: opacity 0.6s ease-in-out; opacity: 0; - &.active{ - opacity: 1 + &.active { + opacity: 1; } } @@ -262,88 +264,88 @@ $breakpoint-lg: 992px; max-width: 100%; } -.ArticleCellOutput table, .ArticleCellFigure table{ - font-size: .8em; +.ArticleCellOutput table, +.ArticleCellFigure table { + font-size: 0.8em; // .table-striped border: 0; border: 1px solid var(--gray-400); // border-bottom: 1px solid var(--gray-400); background-color: var(--gray-100); - caption{ + caption { display: none; } tbody tr:nth-of-type(odd) { background-color: var(--gray-200); } - td, th{ + td, + th { padding: var(--spacer-2); } } -.ArticleCellFigure img{ +.ArticleCellFigure img { max-width: 100%; } // .ArticleCellOutput_display_data { // background-color: var(--gray-200); // } -.ArticleCellOutput_display_data img{ +.ArticleCellOutput_display_data img { max-width: 100%; } .ArticleCellOutput_display_data .label, .ArticleCellOutput_execute_result .label, .ArticleCellOutput_stream .label, -.ArticleCellSourceCode_no_output{ - background: var(--gray-300); +.ArticleCellSourceCode_no_output { + background: var(--gray-300); display: inline-block; padding: var(--spacer-0) var(--spacer-2); font-weight: bold; } .ArticleCellOutput_display_data .label:before, .ArticleCellOutput_execute_result .label:before, -.ArticleCellOutput_stream .label:before{ - content: "↘ ", +.ArticleCellOutput_stream .label:before { + content: '↘ '; } .ArticleCellContent pre, .ArticleCellOutput_execute_result pre, -.ArticleCellOutput_stream pre{ +.ArticleCellOutput_stream pre { background-color: var(--gray-300); padding: var(--spacer-2); } - -.ArticleText.hermeneutics{ - .ArticleText_scrollama{ +.ArticleText.hermeneutics { + .ArticleText_scrollama { // transform: translate3d(-8%, 0, 0); } } -.ArticleNote{ - z-index: 100; - position: fixed; - bottom: 0; - width: 100%; - max-height: 50vh; - display: flex; - align-items: center; - background: var(--dark); - overflow: scroll; - p{ - +.ArticleNote { + z-index: 100; + position: fixed; + bottom: 0; + width: 100%; + max-height: 50vh; + display: flex; + align-items: center; + background: var(--dark); + overflow: scroll; + p { color: var(--gray-300); - } - transform: translate(0, 15vh); - will-change: transform; - transition: transform 0.5s cubic-bezier(0.85, 0, 0.15, 1); + } + transform: translate(0, 15vh); + will-change: transform; + transition: transform 0.5s cubic-bezier(0.85, 0, 0.15, 1); - &.active{ - transform: translate(0, 0); - } + &.active { + transform: translate(0, 0); + } } -.ArticleShadowHandle{ +.ArticleShadowHandle { background: var(--dark); // border: 1px solid var(--dark); z-index: 3; @@ -357,12 +359,12 @@ $breakpoint-lg: 992px; cursor: pointer; pointer-events: auto; touch-events: none; - transition: background-color .25s ease-in-out; + transition: background-color 0.25s ease-in-out; & > svg { - margin-left:15px; - margin-top:15px; + margin-left: 15px; + margin-top: 15px; } - & > label{ + & > label { opacity: 0; position: absolute; line-height: 15px; @@ -375,30 +377,30 @@ $breakpoint-lg: 992px; right: 60px; width: 100px; text-align: right; - transition: opacity .25s ease-in-out; + transition: opacity 0.25s ease-in-out; } - &:hover{ + &:hover { background-color: var(--primary); - label{ + label { opacity: 1; } } } -.ArticleShadowLayer{ +.ArticleShadowLayer { position: fixed; z-index: 2; top: 0px; pointer-events: none; } -ArticleShadowLayer_animatedLabel{ +ArticleShadowLayer_animatedLabel { height: 20px; } -.ArticleFigure{ +.ArticleFigure { min-height: 50px; - margin-top: var(--spacer-3); + margin-top: var(--spacer-3); } .ArticleFigure_figcaption_num { @@ -411,77 +413,75 @@ ArticleShadowLayer_animatedLabel{ font-weight: bold; } - -svg.ArticleFingerprint{ - - g.type-code{ +svg.ArticleFingerprint { + g.type-code { // is type===cell - line{ - stroke: var(--accent) + line { + stroke: var(--accent); } - circle{ + circle { stroke: transparent; fill: var(--accent); } } - g.type-markdown{ + g.type-markdown { // is type===markdown - line{ - stroke: var(--gray-500) + line { + stroke: var(--gray-500); } - circle{ + circle { fill: var(--gray-700); stroke: transparent; } - circle.refs{ + circle.refs { stroke: transparent; fill: var(--gray-700); } } - g.is-heading{ - circle.origin{ + g.is-heading { + circle.origin { fill: var(--secondary); stroke: transparent; } - circle{ + circle { fill: transparent; stroke: var(--secondary); } - circle.heading-placeholder{ + circle.heading-placeholder { fill: transparent; stroke: var(--secondary); } } - g.is-hl{ - circle.origin{ + g.is-hl { + circle.origin { fill: var(--secondary); stroke: transparent; } //isHermeneutic - circle{ + circle { fill: var(--primary); stroke: var(--gray-300); } - line{ - stroke: var(--primary) + line { + stroke: var(--primary); } } - g.is-hl.type-code{ - circle{ + g.is-hl.type-code { + circle { stroke: transparent; fill: var(--accent); } - line{ - stroke: var(--accent) + line { + stroke: var(--accent); } } } -.ArticleCellFigure table{ +.ArticleCellFigure table { width: 100%; } -.ArticleCellAccordionCustomToggle{ +.ArticleCellAccordionCustomToggle { white-space: nowrap; border-radius: 15px; background: white; @@ -493,14 +493,14 @@ svg.ArticleFingerprint{ // border-color: var(--gray-300); // color: var(--dark); // } - &.active{ + &.active { border-color: var(--primary-dark); background-color: var(--primary-dark); } - &.active:focus{ - box-shadow: 0 0 0 0.25rem rgba(34, 35, 34, 0.25) + &.active:focus { + box-shadow: 0 0 0 0.25rem rgba(34, 35, 34, 0.25); } - &:hover{ + &:hover { color: var(--white); border-color: var(--primary-dark); background-color: var(--primary-dark); @@ -508,7 +508,7 @@ svg.ArticleFingerprint{ } @media (min-width: $breakpoint-tablet) { - .ArticleCellAccordionCustomToggle{ + .ArticleCellAccordionCustomToggle { left: -35px; } } @@ -517,13 +517,13 @@ svg.ArticleFingerprint{ // transition: transform 0.5s cubic-bezier(0.85, 0, 0.15, 1); // // } -.ArticleToCStep{ +.ArticleToCStep { position: relative; - font-size: .8em; + font-size: 0.8em; height: 20px; pointer-events: auto; - label{ + label { position: absolute; top: 0; overflow: hidden; @@ -535,7 +535,7 @@ svg.ArticleFingerprint{ cursor: pointer; } - &:hover label{ + &:hover label { text-decoration: underline; } } @@ -554,12 +554,12 @@ svg.ArticleFingerprint{ position: absolute; right: -24px; top: 0; - svg{ - position:absolute; + svg { + position: absolute; top: 5px; left: -6px; } - &::before{ + &::before { position: absolute; left: 0px; height: 6px; @@ -568,7 +568,7 @@ svg.ArticleFingerprint{ background-color: var(--dark); content: ''; } - &::after{ + &::after { position: absolute; left: 0px; height: 6px; @@ -579,8 +579,7 @@ svg.ArticleFingerprint{ } } - -.ArticleToCStep_icon_circle{ +.ArticleToCStep_icon_circle { position: absolute; left: 0; width: 12px; @@ -589,14 +588,14 @@ svg.ArticleFingerprint{ border-radius: 10px; } -.ArticleToCStep_Level_H2{ +.ArticleToCStep_Level_H2 { margin-top: 20px; margin-bottom: 10px; - .ArticleToCStep_icon::after{ + .ArticleToCStep_icon::after { top: 17px; height: 14px; } - .ArticleToCStep_icon_circle{ + .ArticleToCStep_icon_circle { width: 15px; height: 15px; top: 3px; @@ -605,14 +604,14 @@ svg.ArticleFingerprint{ } .ArticleToCStep_Level_H3 { - .ArticleToCStep_icon::before{ + .ArticleToCStep_icon::before { top: 0px; height: 7px; } - .ArticleToCStep_icon::after{ + .ArticleToCStep_icon::after { top: 14px; } - .ArticleToCStep_icon_circle{ + .ArticleToCStep_icon_circle { width: 9px; height: 9px; left: -4px; @@ -620,16 +619,18 @@ svg.ArticleFingerprint{ } } -.ArticleToCStep_Level_H4, .ArticleToCStep_Level_H5, .ArticleToCStep_Level_H6 { - .ArticleToCStep_icon::before{ +.ArticleToCStep_Level_H4, +.ArticleToCStep_Level_H5, +.ArticleToCStep_Level_H6 { + .ArticleToCStep_icon::before { top: 0px; height: 8px; } - .ArticleToCStep_icon::after{ + .ArticleToCStep_icon::after { top: 13px; height: 7px; } - .ArticleToCStep_icon_circle{ + .ArticleToCStep_icon_circle { width: 5px; height: 5px; left: -2px; @@ -637,8 +638,8 @@ svg.ArticleFingerprint{ } } -.ArticleToCStep.active{ - label{ +.ArticleToCStep.active { + label { font-weight: bold; } .ArticleToCStep_icon_circle { @@ -653,40 +654,39 @@ svg.ArticleFingerprint{ display: none; } -.ArticleToCStep.hermeneutics{ +.ArticleToCStep.hermeneutics { color: var(--primary-dark); } -.ArticleToC_layerSelector{ +.ArticleToC_layerSelector { cursor: pointer; display: inline-block; padding: 0 var(--spacer-2); border-radius: var(--spacer-1); - &.active{ + &.active { background: var(--dark); color: var(--white); } } -.ArticleCellAccordion{ +.ArticleCellAccordion { // border-top: 1px solid var(--dark); color: var(--primary-dark); min-height: 1px; } -.ArticleCellAccordion_button{ +.ArticleCellAccordion_button { border-top: 1px solid var(--primary-dark); } - -.ArticleTextShadow{ +.ArticleTextShadow { display: none; position: fixed; top: 0; overflow: scroll; z-index: 2; } -.ArticleTextShadow_mask{ +.ArticleTextShadow_mask { position: fixed; top: 0; z-index: 2; @@ -694,31 +694,31 @@ svg.ArticleFingerprint{ width: 100%; } @media (min-width: $breakpoint-tablet) { - .ArticleTextShadow{ + .ArticleTextShadow { display: block; } } -.ArticleBilbiography .csl-entry{ +.ArticleBilbiography .csl-entry { margin-bottom: var(--spacer-3); - a{ + a { word-break: break-all; } } -.ArticleMobileDisclaimer_popup{ +.ArticleMobileDisclaimer_popup { top: 0; } -.ArticleMobileDisclaimer_popup_back{ +.ArticleMobileDisclaimer_popup_back { background: linear-gradient(#ffffff00, #ffffffaa, #ffffff00); - height:100%; - top:0; - width:100%; + height: 100%; + top: 0; + width: 100%; opacity: 0; } -.ArticleMobileDisclaimer_popup_inner{ +.ArticleMobileDisclaimer_popup_inner { border-radius: 5px; background-color: white; margin-top: 40%; @@ -731,15 +731,14 @@ svg.ArticleFingerprint{ } .ArticleMobileDisclaimer_popup.active { - .ArticleMobileDisclaimer_popup_back{ + .ArticleMobileDisclaimer_popup_back { opacity: 1; } - .ArticleMobileDisclaimer_popup_inner{ + .ArticleMobileDisclaimer_popup_inner { transform: translate(0, 0); } } - .ArticleFingerprintTooltip { z-index: 1000; font-size: 12px; @@ -752,16 +751,39 @@ svg.ArticleFingerprint{ left: 100px; } -.ArticleFingerprintTooltip_heading{ +.ArticleFingerprintTooltip_heading { font-weight: bold; text-transform: uppercase; font-family: var(--font-family-monospace); } -.ArticleFingerprintTooltip_content{ - pre{ +.ArticleFingerprintTooltip_content { + pre { word-break: break-all; - white-space:pre; + white-space: pre; font-family: var(--font-family-monospace); } } + +.container.alert-info .ArticleCellContent { + border: 2px solid var(--capri); + border-radius: 3px; + padding: var(--spacer-2) var(--spacer-3) 0; + position: relative; + // p { + // color: var(--capri); + // } + &:before { + position: absolute; + content: 'info'; + border-radius: 3px; + border-radius: 3px; + top: -8px; + background-color: var(--capri); + text-transform: uppercase; + font-size: 11px; + font-weight: bold; + padding: 3px 6px 1px; + line-height: 12px; + } +} From a03b88cd4f742ab09945f1c5df449bf090afa29b Mon Sep 17 00:00:00 2001 From: Daniele Guido Date: Thu, 27 Oct 2022 12:28:01 +0200 Subject: [PATCH 6/7] Hotfix/issue 483 (#484) * add prettier file * add showTemplateLink flag for the guideline page to toggle button visibility * add hideFigures flag to force table of content to hide figures :) * Update ArticleToC.js --- .prettierignore | 7 + .prettierrc | 8 + src/components/ArticleV2/Article.js | 162 ++++++------ src/components/ArticleV2/ArticleFlow.js | 139 +++++----- src/components/ArticleV2/ArticleToC.js | 328 +++++++++++++----------- src/pages/Guidelines.js | 89 ++++--- 6 files changed, 414 insertions(+), 319 deletions(-) create mode 100644 .prettierignore create mode 100644 .prettierrc diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 00000000..d71a79b4 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,7 @@ +build/ +node_modules/ +internals/generators/ +internals/scripts/ +package-lock.json +yarn.lock +package.json diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 00000000..99c74700 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "printWidth": 100, + "tabWidth": 2, + "useTabs": false, + "semi": false, + "singleQuote": true, + "trailingComma": "all" +} diff --git a/src/components/ArticleV2/Article.js b/src/components/ArticleV2/Article.js index 6f68c6c2..9807d710 100644 --- a/src/components/ArticleV2/Article.js +++ b/src/components/ArticleV2/Article.js @@ -12,7 +12,7 @@ import LangNavLink from '../LangNavLink' import Logo from '../Logo' const Article = ({ - memoid='', + memoid = '', isLocal = false, // pid, // Notebook instance, an object containing {cells:[], metadata:{}} @@ -30,11 +30,11 @@ const Article = ({ binderUrl, bibjson, emailAddress, - isJavascriptTrusted=false, + isJavascriptTrusted = false, // used to remove publication info from ArticleHeader - ignorePublicationStatus=false, + ignorePublicationStatus = false, // used to put page specific helmet in the parent component - ignoreHelmet=false, + ignoreHelmet = false, // if it is defined, will override the style of the ArticleLayout pushFixed // header pageBackgroundColor, @@ -43,18 +43,20 @@ const Article = ({ // a translatable string that defines the article header if ignorePublicationStatus is true category, // if false, binder url notice will be hidden - ignoreBinder=false, + ignoreBinder = false, + // if true, force table of contetts to hide figures. + hideFigures = false, // Children will be put right aftr the ArticleHeader. children, }) => { const { t } = useTranslation() const [selectedDataHref, setSelectedDataHref] = useState(null) - const { height, width } = useCurrentWindowDimensions() + const { height, width } = useCurrentWindowDimensions() const articleTree = useIpynbNotebookParagraphs({ id: memoid || url, cells: ipynb?.content?.cells ?? ipynb?.cells ?? [], - metadata: ipynb?.content?.metadata ?? ipynb?.metadata ?? {} + metadata: ipynb?.content?.metadata ?? ipynb?.metadata ?? {}, }) const { title, @@ -62,91 +64,103 @@ const Article = ({ keywords, contributor, collaborators, - disclaimer = [] + disclaimer = [], } = articleTree.sections console.debug(`[Article] component rendered ${width}x${height}px`) console.debug('[Article] binderUrl:', binderUrl) console.debug('[Article] loading articleTree anchors:', articleTree.anchors) - console.debug('[Article] loading articleTree paragraphs:', articleTree.paragraphs.length) + console.debug( + '[Article] loading articleTree paragraphs:', + articleTree.paragraphs.length + ) const onDataHrefClickHandler = (d) => { console.debug('DataHref click handler') setSelectedDataHref(d) } const renderedBibliographyComponent = ( - + + ) + const renderedFooterComponent =
+ const renderedLogoComponent = ( + +
+ +
+
+
) - const renderedFooterComponent = (
) - const renderedLogoComponent =( - -
-
-
-
) - return ( <> - {!ignoreHelmet && ( - - )} -
+ )} +
+ + + + {typeof children === 'function' ? children(articleTree) : children} + + {articleTree.citationsFromMetadata ? ( + + ) : null} +
) } diff --git a/src/components/ArticleV2/ArticleFlow.js b/src/components/ArticleV2/ArticleFlow.js index dc90b180..a046aa42 100644 --- a/src/components/ArticleV2/ArticleFlow.js +++ b/src/components/ArticleV2/ArticleFlow.js @@ -7,8 +7,8 @@ import styles from './ArticleFlow.module.css' import { useArticleToCStore } from '../../store' const ArticleFlow = ({ - memoid='', - paragraphs=[], + memoid = '', + paragraphs = [], height, width, // onCellChange, @@ -16,33 +16,37 @@ const ArticleFlow = ({ // onVisibilityChange hasBibliography, onDataHrefClick, - binderUrl=null, + binderUrl = null, // emailAddress, - headingsPositions=[], - tocOffset=99, - layers=[LayerNarrative, LayerHermeneutics], + headingsPositions = [], + tocOffset = 99, + layers = [LayerNarrative, LayerHermeneutics], isJavascriptTrusted = false, - ignoreBinder=false, - renderedBibliographyComponent=null, - renderedFooterComponent=null, + ignoreBinder = false, + hideFigures = false, + renderedBibliographyComponent = null, + renderedFooterComponent = null, // if it is defined, it overrides the style of the ArticleLayout pushFixed // header pageBackgroundColor, // article on mobile must have the logo visible somewhere - renderedLogoComponent=null, - children + renderedLogoComponent = null, + children, }) => { - const setVisibleCell = useArticleToCStore(store => store.setVisibleCell) + const setVisibleCell = useArticleToCStore((store) => store.setVisibleCell) const paragraphsGroups = React.useMemo(() => { const buffers = [] let previousLayer = null let buffer = new Array() - paragraphs.forEach((cell,i) => { + paragraphs.forEach((cell, i) => { // skip hidden paragraphs if (cell.layer === LayerHidden) { return } - if (i > 0 && (cell.layer !== previousLayer || cell.isHeading || cell.isFigure || cell.isTable )) { + if ( + i > 0 && + (cell.layer !== previousLayer || cell.isHeading || cell.isFigure || cell.isTable) + ) { buffers.push([...buffer]) buffer = [] } @@ -56,8 +60,8 @@ const ArticleFlow = ({ return buffers }, [memoid]) - const onPlaceholderClickHandler = (e,cell) => { - console.debug('[ArticleFlow] @onPlaceholderClickHandler', e,cell) + const onPlaceholderClickHandler = (e, cell) => { + console.debug('[ArticleFlow] @onPlaceholderClickHandler', e, cell) } const onCellIntersectionChangeHandler = ({ idx, isIntersecting }) => { // console.debug('[ArticleFlow] @onCellIntersectionChangeHandler', idx) @@ -66,52 +70,63 @@ const ArticleFlow = ({ console.debug(`[ArticleFlow] component rendered, size: ${width}x${height}px`) return ( <> -
-
- {!IsMobile && ( -
+
+ {!IsMobile && ( + + )} +
+ +
+ - )} -
- -
- - - {children} - -
+ width={width} + pageBackgroundColor={pageBackgroundColor} + isJavascriptTrusted={isJavascriptTrusted} + renderedBibliographyComponent={renderedBibliographyComponent} + renderedFooterComponent={renderedFooterComponent} + renderedLogoComponent={renderedLogoComponent} + > + {children} + +
) } @@ -120,6 +135,10 @@ export default React.memo(ArticleFlow, (nextProps, prevProps) => { if (nextProps.width !== prevProps.width || nextProps.height !== prevProps.height) { return false } - console.debug('[ArticleFlow] rendering requested, memoid:', nextProps.memoid, nextProps.memoid === prevProps.memoid) + console.debug( + '[ArticleFlow] rendering requested, memoid:', + nextProps.memoid, + nextProps.memoid === prevProps.memoid, + ) return nextProps.memoid === prevProps.memoid }) diff --git a/src/components/ArticleV2/ArticleToC.js b/src/components/ArticleV2/ArticleToC.js index 92e37fdb..530daad6 100644 --- a/src/components/ArticleV2/ArticleToC.js +++ b/src/components/ArticleV2/ArticleToC.js @@ -10,29 +10,30 @@ import { DisplayLayerCellTopQueryParam, DisplayPreviousLayerQueryParam, DisplayLayerSectionParam, - DisplayLayerSectionBibliography + DisplayLayerSectionBibliography, } from '../../constants' import ArticleToCStep from './ArticleToCStep' import ArticleToCBookmark from './ArticleToCBookmark' const ArticleToC = ({ - memoid='', - layers=[], - paragraphs=[], - headingsPositions=[], - binderUrl=null, - ignoreBinder=false, - width=100, - height=100, - hasBibliography=false, + memoid = '', + layers = [], + paragraphs = [], + headingsPositions = [], + binderUrl = null, + ignoreBinder = false, + width = 100, + height = 100, + hideFigures = false, + hasBibliography = false, }) => { const { t } = useTranslation() - const visibleCellsIdx = useArticleToCStore(state => state.visibleCellsIdx) - const setVisibleCellsIdx = useArticleToCStore(state => state.setVisibleCellsIdx) - const [{ - [DisplayLayerQueryParam]:selectedLayer, - [DisplayLayerCellIdxQueryParam]:selectedCellIdx, - }, setQuery] = useQueryParams({ + const visibleCellsIdx = useArticleToCStore((state) => state.visibleCellsIdx) + const setVisibleCellsIdx = useArticleToCStore((state) => state.setVisibleCellsIdx) + const [ + { [DisplayLayerQueryParam]: selectedLayer, [DisplayLayerCellIdxQueryParam]: selectedCellIdx }, + setQuery, + ] = useQueryParams({ [DisplayLayerCellIdxQueryParam]: withDefault(NumberParam, -1), [DisplayLayerQueryParam]: withDefault(StringParam, LayerNarrative), [DisplayLayerCellTopQueryParam]: withDefault(NumberParam, 100), @@ -40,63 +41,76 @@ const ArticleToC = ({ }) let count = 0 - const cellIndex = React.useMemo(() => paragraphs.reduce((acc, cell) => { - acc[cell.idx] = cell - return acc - }, {}), [memoid]) - - const steps = React.useMemo(() => headingsPositions.reduce((acc, idx, i) => { - const cell = cellIndex[idx] - if (!cell) { - // is possible that there are headingPositions outside of the - // articleTree.paragraphs list (e.g in the metadata section). - // In this case, we just skip. - return acc - } - if (cell.hidden) { + const cellIndex = React.useMemo( + () => + paragraphs.reduce((acc, cell) => { + acc[cell.idx] = cell + return acc + }, {}), + [memoid], + ) - // is possible that there are headingPositions within hidden cells. - // In this case, we just skip. - return acc - } - const nextCell = i < headingsPositions.length - 1 - ? cellIndex[headingsPositions[i + 1]] - : null - let isSectionStart = false - let isSectionEnd = false - if(cell.isHeading && cell.heading.level === 2) { - isSectionStart = true - } - if (count === 0) { - isSectionEnd = true - isSectionStart = true - } - if (nextCell && nextCell.isHeading && nextCell.heading.level === 2 ) { - isSectionEnd = true - } - if (!nextCell) { - isSectionEnd = true - } + const steps = React.useMemo( + () => + headingsPositions.reduce((acc, idx, i) => { + const cell = cellIndex[idx] + if (!cell) { + // is possible that there are headingPositions outside of the + // articleTree.paragraphs list (e.g in the metadata section). + // In this case, we just skip. + return acc + } + if (cell.hidden) { + // is possible that there are headingPositions within hidden cells. + // In this case, we just skip. + return acc + } + if (cell.figure && hideFigures) { + return acc + } + const nextCell = + i < headingsPositions.length - 1 ? cellIndex[headingsPositions[i + 1]] : null + let isSectionStart = false + let isSectionEnd = false + if (cell.isHeading && cell.heading.level === 2) { + isSectionStart = true + } + if (count === 0) { + isSectionEnd = true + isSectionStart = true + } + if (nextCell && nextCell.isHeading && nextCell.heading.level === 2) { + isSectionEnd = true + } + if (!nextCell) { + isSectionEnd = true + } - count++ - // is last only if next heading is higher than this one, or it is a hermeneutic - const isHermeneutics = cell.layer === LayerHermeneutics - return acc.concat([{ - isSectionStart, - isSectionEnd, - isHermeneutics, - cell, - count - }]) - }, []), [memoid]) + count++ + // is last only if next heading is higher than this one, or it is a hermeneutic + const isHermeneutics = cell.layer === LayerHermeneutics + return acc.concat([ + { + isSectionStart, + isSectionEnd, + isHermeneutics, + cell, + count, + }, + ]) + }, []), + [memoid, hideFigures], + ) const firstVisibleCellIdx = visibleCellsIdx.length ? visibleCellsIdx[0] : -1 - const lastVisibleCellIdx = visibleCellsIdx.length ? visibleCellsIdx[visibleCellsIdx.length -1] : -1 + const lastVisibleCellIdx = visibleCellsIdx.length + ? visibleCellsIdx[visibleCellsIdx.length - 1] + : -1 - const { previousHeadingIdx } = React.useMemo(()=> { + const { previousHeadingIdx } = React.useMemo(() => { let previousHeadingIdx = -1 let nextHeadingIdx = -1 - for(let i = 0; i < headingsPositions.length; i++) { + for (let i = 0; i < headingsPositions.length; i++) { if (headingsPositions[i] <= firstVisibleCellIdx) { previousHeadingIdx = headingsPositions[i] } @@ -107,9 +121,9 @@ const ArticleToC = ({ } return { previousHeadingIdx, - nextHeadingIdx + nextHeadingIdx, } - }, [ firstVisibleCellIdx, lastVisibleCellIdx ]) + }, [firstVisibleCellIdx, lastVisibleCellIdx]) const onStepClickHandler = (step) => { console.debug('[ArticleToC] @onClickHandler step:', step, selectedLayer) @@ -117,7 +131,7 @@ const ArticleToC = ({ setQuery({ [DisplayLayerCellIdxQueryParam]: step.cell.idx, [DisplayPreviousLayerQueryParam]: undefined, - [DisplayLayerSectionParam]: undefined + [DisplayLayerSectionParam]: undefined, }) } @@ -126,7 +140,7 @@ const ArticleToC = ({ [DisplayLayerCellIdxQueryParam]: selectedCellIdx, [DisplayPreviousLayerQueryParam]: undefined, [DisplayLayerCellTopQueryParam]: 100, - [DisplayLayerSectionParam]: undefined + [DisplayLayerSectionParam]: undefined, }) } @@ -135,7 +149,7 @@ const ArticleToC = ({ setQuery({ [DisplayLayerCellIdxQueryParam]: undefined, [DisplayPreviousLayerQueryParam]: undefined, - [DisplayLayerSectionParam]: section + [DisplayLayerSectionParam]: section, }) } @@ -150,20 +164,31 @@ const ArticleToC = ({ console.debug('[ArticleToC] @useEffect @timeout!') let visibilityChanged = false const updatedVisibleCellsIdx = [] - for (let i=0, l=visibleCellsIdx.length; i < l; i++) { + for (let i = 0, l = visibleCellsIdx.length; i < l; i++) { const el = document.getElementById(selectedLayer + visibleCellsIdx[i]) if (el) { const rect = el.getBoundingClientRect() - if ( rect.top < 0 || rect.top > height) { - console.debug('[ArticleToC]', visibleCellsIdx[i], 'is not visible anymore', rect.top, height) + if (rect.top < 0 || rect.top > height) { + console.debug( + '[ArticleToC]', + visibleCellsIdx[i], + 'is not visible anymore', + rect.top, + height, + ) visibilityChanged = true } else { updatedVisibleCellsIdx.push(visibleCellsIdx[i]) } } } - if(visibilityChanged) { - console.debug('[ArticleToC] visibilityChanged from', visibleCellsIdx, 'to', updatedVisibleCellsIdx) + if (visibilityChanged) { + console.debug( + '[ArticleToC] visibilityChanged from', + visibleCellsIdx, + 'to', + updatedVisibleCellsIdx, + ) setVisibleCellsIdx(updatedVisibleCellsIdx) } }, 100) @@ -174,77 +199,92 @@ const ArticleToC = ({ }, [visibleCellsIdx, selectedLayer]) return ( <> -
- {layers.length > 1 && layers.map((d,i) => ( -
setQuery({[DisplayLayerQueryParam]: d})} - >{d}
- ))} - {!ignoreBinder && ( -

- )} -

-
- {steps.map((step, i) => { - const showBookmark = i < steps.length - 1 - ? selectedCellIdx >= step.cell.idx && selectedCellIdx < steps[i+1].cell.idx - : false - return ( -
- {showBookmark ? ( - step.cell.idx - ? '100%' - : (selectedCellIdx < step.cell.idx ? 0 : '50%') - }} - /> - ): null} +
+ {layers.length > 1 && + layers.map((d, i) => ( +
setQuery({ [DisplayLayerQueryParam]: d })} + > + {d} +
+ ))} + {!ignoreBinder && ( +

+ )} +

+
+ {steps.map((step, i) => { + const showBookmark = + i < steps.length - 1 + ? selectedCellIdx >= step.cell.idx && selectedCellIdx < steps[i + 1].cell.idx + : false + return ( +
+ {showBookmark ? ( + step.cell.idx + ? '100%' + : selectedCellIdx < step.cell.idx + ? 0 + : '50%', + }} + /> + ) : null} + = previousHeadingIdx && step.cell.idx <= lastVisibleCellIdx} + className={step.isHermeneutics ? 'hermeneutics' : ''} + > + {step.cell.isHeading + ? step.cell.heading.content + : step.cell.isFigure + ? t(step.cell.figure.tNLabel, { n: step.cell.figure.tNum }) + : '(na)'} + +
+ ) + })} +
+ {hasBibliography && ( +
= previousHeadingIdx && step.cell.idx <= lastVisibleCellIdx} - className={step.isHermeneutics ? 'hermeneutics': ''} + cell={{ + level: 'H2', + }} + width={width * 0.16} + isSectionStart + isSectionEnd + selected + active={false} + className="" + onStepClick={(e) => onSectionClickHandler(e, DisplayLayerSectionBibliography)} > - {step.cell.isHeading - ? step.cell.heading.content - : step.cell.isFigure - ? t(step.cell.figure.tNLabel, {n: step.cell.figure.tNum}) - : '(na)' - } + {t('bibliography')} -
- )})} -
- {hasBibliography && ( -
- onSectionClickHandler(e, DisplayLayerSectionBibliography)} - >{t('bibliography')} -
- )} +
+ )} ) } diff --git a/src/pages/Guidelines.js b/src/pages/Guidelines.js index 57824b3e..3f0b2d33 100644 --- a/src/pages/Guidelines.js +++ b/src/pages/Guidelines.js @@ -9,51 +9,58 @@ import NotebookHelmet from '../components/NotebookHelmet' import Article from '../components/ArticleV2' import { BootstrapColumLayout, StatusSuccess } from '../constants' -// -const GuidelinesArticle = ({ data, status, isFake=false}) => { +const GuidelinesArticle = ({ data, status, isFake = false, showTemplateLink = false }) => { const { t } = useTranslation() - console.debug('[GuidelinesArticle] props:', {status, isFake}) + console.debug('[GuidelinesArticle] props:', { status, isFake }) const memoid = process.env.REACT_APP_NOTEBOOK_GUIDELINES_URL + (isFake ? '-fake' : '') return ( <> - + ) } From 3b045570b79761cfc4b73bc4ffcdbb52b4dd7ab7 Mon Sep 17 00:00:00 2001 From: eliselavy Date: Thu, 27 Oct 2022 13:16:36 +0200 Subject: [PATCH 7/7] increment version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 75341c8f..9deac0f0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "jdh", - "version": "3.4.1", + "version": "4.0.0", "private": true, "dependencies": { "@auth0/auth0-react": "^1.1.0",