Skip to content

Commit

Permalink
v4.4.2
Browse files Browse the repository at this point in the history
v4.4.2
  • Loading branch information
eliselavy authored Feb 15, 2024
2 parents db14345 + 48e6ee5 commit b46713f
Show file tree
Hide file tree
Showing 29 changed files with 734 additions and 291 deletions.
5 changes: 3 additions & 2 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ REACT_APP_GITHUB_WIKI_FAQ=https://raw.githubusercontent.com/wiki/c2dh/journal-of
REACT_APP_WIKI_VIDEO_RELEASES=https://raw.githubusercontent.com/wiki/c2dh/journal-of-digital-history/Video-Releases.md
REACT_APP_WIKI_TERMS_OF_USE=https://raw.githubusercontent.com/wiki/c2dh/journal-of-digital-history/Terms-Of-Use.md
REACT_APP_WIKI_HOMEPAGE=https://raw.githubusercontent.com/wiki/c2dh/journal-of-digital-history/Homepage.md
REACT_APP_WIKI_ABOUT=https://raw.githubusercontent.com/wiki/c2dh/journal-of-digital-history/About.md
REACT_APP_WIKI_ABOUT=https://raw.githubusercontent.com/wiki/c2dh/journal-of-digital-history/About-v2.md
REACT_APP_WIKI_FINGERPRINT_EXPLAINED=https://raw.githubusercontent.com/wiki/c2dh/journal-of-digital-history/Fingerprint-explained.md
REACT_APP_WIKI_EVENTS=https://raw.githubusercontent.com/wiki/c2dh/journal-of-digital-history/Events.md
REACT_APP_WIKI_EVENTS=https://raw.githubusercontent.com/wiki/c2dh/journal-of-digital-history/Events-v2.md
REACT_APP_WIKI_REVIEW_POLICY=https://raw.githubusercontent.com/wiki/c2dh/journal-of-digital-history/Journal-Of-Digital-History-Peer-Review-Ethics-Declaration.md
REACT_APP_NOTEBOOK_GUIDELINES_URL=/proxy-githubusercontent/C2DH/jdh-notebook/master/examples/Author_Guideline/skim-AuthorGuideline.ipynb
REACT_APP_NOTEBOOK_CFP_BASE_URL=/proxy-githubusercontent/C2DH/jdh-notebook/master/cfp
REACT_APP_NOTEBOOK_FINGERPRINT_EXPLAINED_URL=/proxy-githubusercontent/C2DH/jdh-notebook/master/examples/hermeneutic-layer.ipynb
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ node_modules
.vscode/settings.json
storybook-static
# _redirects
journal-of-digital-history.code-workspace
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jdh",
"version": "4.4.1",
"version": "4.4.2",
"private": true,
"dependencies": {
"@auth0/auth0-react": "^1.1.0",
Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ const Fingerprint = lazy(() => import('./pages/Fingerprint'))
const FingerprintViewer = lazy(() => import('./pages/FingerprintViewer'))
const FingerprintExplained = lazy(() => import('./pages/FingerprintExplained'))
const ReleaseNotes = lazy(() => import('./pages/ReleaseNotes'))
const ReviewPolicy = lazy(() => import('./pages/ReviewPolicy'))
const Faq = lazy(() => import('./pages/Faq'))

const { startLangShort, lang } = getStartLang()
Expand Down Expand Up @@ -162,6 +163,7 @@ function LangRoutes() {
<Route path={`${path}/fingerprint-explained/:encodedUrl?`} component={FingerprintExplained} />

<Route path={`${path}/release-notes`} component={ReleaseNotes} />
<Route path={`${path}/review-policy`} component={ReviewPolicy} />
<Route path={`${path}/faq`} component={Faq} />
<Route path={`${path}/notebook-viewer/:encodedUrl`} component={NotebookViewer} />
<Route path={`${path}/local-notebook`}>
Expand Down
5 changes: 3 additions & 2 deletions src/components/Articles/ArticlesFacets.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ const IssueListItem = (props) => {
const issue = props.items[group.indices[0]].issue
return (
<div className="d-flex align-items-center flex-nowrap" title={issue.name || group.key}>
<IssueLabel pid={issue.pid} publication_date={issue.publication_date} />
<IssueLabel pid={issue.pid} name={issue.name} />
<div>&nbsp;({group.count})</div>
</div>
)
Expand Down Expand Up @@ -105,14 +105,15 @@ const Dimensions = [
},
]

const ArticlesFacets = ({ items, onSelect, className }) => {
const ArticlesFacets = ({ items, onSelect, onShowMore, className }) => {
return (
<Facets
dimensions={Dimensions}
items={items}
onSelect={onSelect}
onInit={(args) => console.debug('[ArticlesFacets] @init', args)}
ShowMoreLabel={ShowMoreLabel}
onShowMore={onShowMore}
className={className}
/>
)
Expand Down
271 changes: 271 additions & 0 deletions src/components/Articles/ArticlesGrid.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
import React, { useMemo, useLayoutEffect, useState, useRef } from 'react'
import { useTranslation } from 'react-i18next'
import { sort } from 'd3-array'
import { useQueryParams, withDefault } from 'use-query-params'
import { asEnumParam, asRegexArrayParam } from '../../logic/params'
import {
AvailablesOrderByComparators,
FilterByQueryparam,
OrderByIssue,
OrderByPublicationDateAsc,
OrderByPublicationDateDesc,
OrderByQueryParam,
BootstrapColumLayout,
DisplayLayerCellIdxQueryParam,
DisplayLayerQueryParam,
LayerNarrative,
LayerHermeneutics,
StatusSuccess,
} from '../../constants'
import IssueArticles from '../Issue/IssueArticles'
import OrderByDropdown from '../OrderByDropdown'
import Article from '../../models/Article'
import ArticlesFacets from '../Articles/ArticlesFacets'
import Issue from '../Issue'
import ArticleFingerprintTooltip from '../ArticleV2/ArticleFingerprintTooltip'
import groupBy from 'lodash/groupBy'
import { Container, Row, Col } from 'react-bootstrap'
import { useSpring, config, a } from '@react-spring/web'
import { useHistory } from 'react-router'
import { useBoundingClientRect } from '../../hooks/graphics'
import { useWindowStore } from '../../store'

const ArticlesGrid = ({
items = [],
url,
issueId,
issues = [],
status,
// tag ategories to keep
categories = ['narrative', 'tool', 'issue'],
}) => {
const facetsRef = useRef()
const timerRef = useRef()
const { t } = useTranslation()
const [{ [OrderByQueryParam]: orderBy }, setQuery] = useQueryParams({
[OrderByQueryParam]: withDefault(
asEnumParam(Object.keys(AvailablesOrderByComparators)),
OrderByIssue,
),
[FilterByQueryparam]: asRegexArrayParam(),
})

const [selected, setSelected] = useState(null)
// pagination api contains results in data

const [{ width }, ref] = useBoundingClientRect()
const history = useHistory()
const animatedRef = useRef({ idx: '', length: '', datum: {} })
const [animatedProps, setAnimatedProps] = useSpring(() => ({
from: { x: 0, y: 0, id: '0-0', color: 'red', backgroundColor: 'transparent' },
x: 0,
y: 0,
opacity: 0,
id: '0-0',
color: 'var(--white)',
backgroundColor: 'var(--secondary)',
config: config.stiff,
}))
// animation properties to slide up and down the articleFacets block
const [facetsAnimatedProps, setFacetsAnimatedProps] = useSpring(() => ({
height: 0,
}))
const data = (items || []).map((d, idx) => new Article({ ...d, idx }))
const articles = sort(data, AvailablesOrderByComparators[orderBy])
const { articlesByIssue, showFilters } = useMemo(() => {
if (status !== StatusSuccess) {
return {
articlesByIssue: {},
issues: [],
sortedItems: [],
showFilters: false,
}
}
const sortedItems = data.map((item, idx) => ({
...item,
idx,
selected: selected?.includes(idx),
}))
const articlesByIssue = groupBy(sortedItems, 'issue.pid')

const showFilters = data.reduce((acc, d) => {
return acc || d.tags.some((t) => categories.includes(t.category))
}, false)
return { articlesByIssue, showFilters }
}, [url, selected, status])

const onArticleMouseMoveHandler = (e, datum, idx, article, bounds) => {
if (!isNaN(idx) && animatedRef.current.idx !== idx) {
animatedRef.current.idx = idx
animatedRef.current.length = article.fingerprint.cells.length
animatedRef.current.datum = datum
}
const x = bounds.left + Math.min(width - 200, e.clientX - bounds.left)
const y = e.clientY + 50
// this will change only animated toltip stuff
setAnimatedProps.start({
x,
y,
id: [article.abstract.id || 0, isNaN(idx) ? 0 : idx].join('-'),
color:
datum.type === 'code'
? 'var(--white)'
: datum.isHermeneutic
? 'var(--secondary)'
: 'var(--white)',
backgroundColor:
datum.type === 'code'
? 'var(--accent)'
: datum.isHermeneutic
? 'var(--primary)'
: 'var(--secondary)',
opacity: 1,
})
}
const onArticleMouseOutHandler = () => {
setAnimatedProps.start({ opacity: 0 })
}
const onArticleClickHandler = (e, datum, idx, article) => {
console.debug('@onArticleClickHandler', datum, idx, article)
e.stopPropagation()
// link to specific cell in article
const url = idx
? `/en/article/${
article.abstract.pid
}?${DisplayLayerCellIdxQueryParam}=${idx}&${DisplayLayerQueryParam}=${
datum.isHermeneutic ? LayerHermeneutics : LayerNarrative
}`
: `/en/article/${article.abstract.pid}`
history.push(url)
}

const onFacetsSelectHandler = (name, indices) => {
console.debug('[Articles] @onFacetsSelectHandler', name, indices)
setSelected(indices)
}

useLayoutEffect(() => {
// go to issueId as soon as it's ready.
if (issueId && status === StatusSuccess) {
console.debug('[Articles] goto issueId:', issueId)
const element = document.getElementById('anchor-' + issueId)
element &&
element.scrollIntoView({
behavior: 'smooth',
block: 'start',
inline: 'nearest',
})
}
}, [status])

useLayoutEffect(() => {
setAnimatedProps.start({ opacity: 0 })
}, [selected])

useLayoutEffect(() => {
if (status === StatusSuccess) {
setFacetsAnimatedProps.start({
height: facetsRef.current.firstChild.scrollHeight,
delay: 1000,
})
return useWindowStore.subscribe(() => {
clearTimeout(timerRef.current)
timerRef.current = setTimeout(() => {
setFacetsAnimatedProps.start({
height: facetsRef.current.firstChild.scrollHeight,
delay: 0,
})
}, 0)
})
}
}, [status])

return (
<Container ref={ref} className="Articles Issue page ">
<ArticleFingerprintTooltip forwardedRef={animatedRef} animatedProps={animatedProps} />
<Row className="mb-3">
<Col {...BootstrapColumLayout}>
<h1 className="mt-5">{t('pages.articles.title')}</h1>
<div className="d-flex align-items-center mb-2">
{showFilters && <p className="me-2 mb-0">{t('pages.articles.subheading')}</p>}
<OrderByDropdown
selectedValue={orderBy}
values={Object.keys(AvailablesOrderByComparators).map((value) => ({
value,
label: t(`orderBy${value}`),
}))}
title={t(`orderBy${orderBy}`)}
onChange={({ value }) => setQuery({ [OrderByQueryParam]: value })}
/>
</div>
</Col>
</Row>

<a.div
className="row mb-1 position-relative overflow-hidden"
ref={facetsRef}
style={facetsAnimatedProps}
>
<Col md={{ offset: 1, span: 10 }} className="position-absolute">
{status === StatusSuccess && (
<ArticlesFacets
items={data}
onShowMore={() => {
console.info('[ArticlesGrid] @showMore')
clearTimeout(timerRef.current)
setTimeout(() => {
setFacetsAnimatedProps.start({
height: facetsRef.current.firstChild.scrollHeight,
delay: 0,
})
}, 0)
}}
onSelect={onFacetsSelectHandler}
className="Articles_facets "
/>
)}
</Col>
</a.div>
{orderBy === OrderByIssue &&
issues.map((issue) => {
const numArticles = articlesByIssue[issue.pid]?.length
const numSelectedArticles = articlesByIssue[issue.pid]?.filter((d) => d.selected).length

return (
<React.Fragment key={issue.pid}>
<a className="anchor" id={`anchor-${issue.pid}`} />

<IssueArticles
selected={selected}
data={articlesByIssue[issue.pid] || []}
onArticleMouseMove={onArticleMouseMoveHandler}
onArticleClick={onArticleClickHandler}
onArticleMouseOut={onArticleMouseOutHandler}
>
<Issue
numArticles={numArticles}
isInFilterMode={Array.isArray(selected)}
numSelectedArticles={numSelectedArticles}
hasSelectedArticles={!!articlesByIssue[issue.pid]}
item={issue}
className="py-2 mb-1"
/>
</IssueArticles>
</React.Fragment>
)
})}
{[OrderByPublicationDateAsc, OrderByPublicationDateDesc].includes(orderBy) && (
<IssueArticles
selected={selected}
data={articles}
onArticleMouseMove={onArticleMouseMoveHandler}
onArticleClick={onArticleClickHandler}
onArticleMouseOut={onArticleMouseOutHandler}
respectOrdering
/>
)}
</Container>
)
}

export default ArticlesGrid
11 changes: 10 additions & 1 deletion src/components/Facets/Dimension.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ const Dimension = ({
onInit,
onSelect,
onMouseEnter,
onShowMore,
children,
ListItem = DimensionGroupListItem,
}) => {
Expand Down Expand Up @@ -174,7 +175,15 @@ const Dimension = ({
))}
{restGroups.length > 0 && (
<li>
<button className="Dimension_toggleShowMoreBtn" onClick={() => setShowMore(!showMore)}>
<button
className="Dimension_toggleShowMoreBtn"
onClick={() => {
if (typeof onShowMore === 'function') {
onShowMore(!showMore)
}
setShowMore(!showMore)
}}
>
<span>
{t(showMore ? 'dimensions.actions.showLess' : 'dimensions.actions.showMore', {
n: restGroups.length,
Expand Down
2 changes: 2 additions & 0 deletions src/components/Facets/Facets.js
Original file line number Diff line number Diff line change
Expand Up @@ -146,6 +146,7 @@ const Facets = ({
onSelect,
onInit,
onMouseEnter,
onShowMore,
className,
style,
}) => {
Expand Down Expand Up @@ -242,6 +243,7 @@ const Facets = ({
onSelect={onSelectHandler}
onInit={onInitHandler}
onMouseEnter={onMouseEnterHandler}
onShowMore={onShowMore}
ListItem={dimension.ListItem}
>
{reset === true && dims[dimension.name].selected.length > 0 && (
Expand Down
3 changes: 2 additions & 1 deletion src/components/Footer/Footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
AboutRoute,
ReleaseNotesRoute,
TermsOfUseRoute,
ReviewPolicy,
FaqRoute
} from '../../constants'
import { Twitter, Facebook, GitHub } from 'react-feather'
Expand Down Expand Up @@ -44,7 +45,7 @@ const Footer = ({ hideOnRoutes=[]}) => {
</div>
<div>
<Nav className="flex-column">
{[HomeRoute, AbstractSubmissionRoute, AboutRoute].map((route, i) => (
{[HomeRoute, AbstractSubmissionRoute, AboutRoute, ReviewPolicy].map((route, i) => (
<Nav.Item key={i}>
<LangNavLink to={route.to} exact>
<span>{t(route.label)}</span>
Expand Down
Loading

0 comments on commit b46713f

Please sign in to comment.