diff --git a/src/components/Articles/ArticlesGrid.js b/src/components/Articles/ArticlesGrid.js
new file mode 100644
index 00000000..2c06fe77
--- /dev/null
+++ b/src/components/Articles/ArticlesGrid.js
@@ -0,0 +1,235 @@
+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 } from 'react-spring'
+import { useHistory } from 'react-router'
+import { useBoundingClientRect } from '../../hooks/graphics'
+
+const ArticlesGrid = ({
+ items = [],
+ url,
+ issueId,
+ issues = [],
+ status,
+ // tag ategories to keep
+ categories = ['narrative', 'tool', 'issue'],
+}) => {
+ 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,
+ }))
+ 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,
+ }))
+ 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, 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])
+ console.debug(
+ '[Articles] \n- articles:',
+ Array.isArray(articles),
+ articles,
+ '\n- issueId:',
+ issueId,
+ selected,
+ )
+
+ return (
+
+
+
+
+ {t('pages.articles.title')}
+
+ {showFilters &&
{t('pages.articles.subheading')}
}
+
({
+ value,
+ label: t(`orderBy${value}`),
+ }))}
+ title={t(`orderBy${orderBy}`)}
+ onChange={({ value }) => setQuery({ [OrderByQueryParam]: value })}
+ />
+
+
+
+ {showFilters && (
+
+
+ {status === StatusSuccess && (
+
+ )}
+
+
+ )}
+
+ {orderBy === OrderByIssue &&
+ issues.map((issue) => {
+ // const issue = articlesByIssue[id][0].issue
+
+ return (
+
+
+
+
+
+
+
+
+ )
+ })}
+ {[OrderByPublicationDateAsc, OrderByPublicationDateDesc].includes(orderBy) && (
+
+ )}
+
+ )
+}
+
+export default ArticlesGrid
diff --git a/src/components/Issue/Issue.js b/src/components/Issue/Issue.js
index 4743e7a1..ba2c35bc 100644
--- a/src/components/Issue/Issue.js
+++ b/src/components/Issue/Issue.js
@@ -1,17 +1,80 @@
-import React from 'react'
+import React, { useLayoutEffect, useRef } from 'react'
+import PropTypes from 'prop-types'
import { useTranslation } from 'react-i18next'
+import { Col, Row } from 'react-bootstrap'
+import { a, useSpring } from '@react-spring/web'
-const Issue = ({ item }) => {
+const Issue = ({ item, className = '' }) => {
+ const ref = useRef()
+ const descriptionRef = useRef()
+ const buttonRef = useRef()
+ const isOpen = useRef(false)
+
+ const [{ height }, api] = useSpring(() => ({ height: 0 }))
const { t } = useTranslation()
+ const label = item.pid.replace(/jdh0+(\d+)/, (m, n) => t('numbers.issue', { n }))
+
+ const toggleHeight = () => {
+ isOpen.current = !isOpen.current
+ // change label on the button
+ buttonRef.current.textContent = isOpen.current ? 'less' : 'more ...'
+
+ api.start({
+ height: isOpen.current
+ ? descriptionRef.current.offsetHeight
+ : Math.min(ref.current.offsetHeight, descriptionRef.current.offsetHeight),
+ })
+ }
+
+ useLayoutEffect(() => {
+ if (ref.current) {
+ if (ref.current.offsetHeight < descriptionRef.current.offsetHeight) {
+ buttonRef.current.style.display = 'block'
+ } else {
+ buttonRef.current.style.display = 'none'
+ }
+ api.set({ height: Math.min(ref.current.offsetHeight, descriptionRef.current.offsetHeight) })
+ }
+ }, [ref])
+
return (
- <>
- {item.pid.replace(/jdh0+(\d+)/, (m,n) => t('numbers.issue', {n}))} · {new Date(item.publication_date).getFullYear()}
-
{item.name}
- {item.description ? (
- {item.pid} {item.description}
- ):null}
- >
+
+
+ {label} {item.status !== 'PUBLISHED' ? — {t('status.' + item.status)} : null}
+ {item.name}
+
+
+
+
+
+
+
+
+
)
}
+Issue.propTypes = {
+ item: PropTypes.shape({
+ pid: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+ description: PropTypes.string,
+ status: PropTypes.string.isRequired,
+ }).isRequired,
+ className: PropTypes.string,
+}
+
export default Issue
diff --git a/src/components/Issue/IssueArticles.js b/src/components/Issue/IssueArticles.js
index 7ed2e3b6..eefd5557 100644
--- a/src/components/Issue/IssueArticles.js
+++ b/src/components/Issue/IssueArticles.js
@@ -1,7 +1,6 @@
-import React from 'react'
+import React, { useLayoutEffect } from 'react'
import { Row, Col } from 'react-bootstrap'
import IssueArticleGridItem from './IssueArticleGridItem'
-import { useBoundingClientRect } from '../../hooks/graphics'
const BootstrapColumLayout = Object.freeze({
lg: { span: 4, offset: 0 },
@@ -26,8 +25,10 @@ const IssueArticles = ({
onArticleMouseOut,
respectOrdering = false,
+ children,
}) => {
- const [{ top, left }, ref] = useBoundingClientRect()
+ const ref = React.useRef()
+ const bboxRef = React.useRef()
const editorials = []
const articles = respectOrdering ? data : []
@@ -54,13 +55,30 @@ const IssueArticles = ({
}
// eslint-disable-next-line no-unused-vars
const onMouseMoveHandler = (e, datum, idx, article) => {
- if (typeof onArticleMouseMove === 'function') {
- onArticleMouseMove(e, datum, idx, article, { top, left })
+ if (typeof onArticleMouseMove === 'function' && bboxRef.current) {
+ onArticleMouseMove(e, datum, idx, article, {
+ top: bboxRef.current.top,
+ left: bboxRef.current.left,
+ })
}
}
- console.debug('[IssueArticles] selected', selected, articles)
+ const updateBboxRef = () => {
+ bboxRef.current = ref.current.getBoundingClientRect()
+ }
+
+ useLayoutEffect(() => {
+ if (!ref.current) return
+ bboxRef.current = ref.current.getBoundingClientRect()
+ window.addEventListener('resize', updateBboxRef)
+ return () => {
+ window.removeEventListener('resize', updateBboxRef)
+ }
+ }, [ref])
+ console.debug('[IssueArticles] rendered')
+
return (
+ {children}
{editorials.map((article, i) => {
if (Array.isArray(selected) && selected.indexOf(article.idx) === -1) {
return null
diff --git a/src/components/WindowEvents.js b/src/components/WindowEvents.js
index aa249617..22b48e4e 100644
--- a/src/components/WindowEvents.js
+++ b/src/components/WindowEvents.js
@@ -1,6 +1,8 @@
import { useEffect } from 'react'
import { debounce } from '../logic/viewport'
import { useWindowStore } from '../store'
+const setScrollPosition = useWindowStore.getState().setScrollPosition
+const setWindowDimensions = useWindowStore.getState().setWindowDimensions
/**
* React hook that reacts to window resize and scrolling events, and implements debounce to prevent too many calls for both events.
* @param {Object} options - An object containing optional parameters.
@@ -22,7 +24,7 @@ const WindowEvents = ({ debounceTime = 150, debounceResize = true, debounceScrol
'\n - window.innerHeight',
window.innerHeight,
)
- useWindowStore.setWindowDimensions(window.innerWidth, window.innerHeight)
+ setWindowDimensions(window.innerWidth, window.innerHeight)
}, debounceTime)
const handleScroll = debounce(() => {
console.debug(
@@ -32,20 +34,20 @@ const WindowEvents = ({ debounceTime = 150, debounceResize = true, debounceScrol
'\n - window.scrollY',
window.scrollY,
)
- useWindowStore.setScrollPosition(window.scrollX, window.scrollY)
+ setScrollPosition(window.scrollX, window.scrollY)
}, debounceTime)
if (debounceResize) {
window.addEventListener('resize', handleResize)
} else {
window.addEventListener('resize', () => {
- useWindowStore.setWindowDimensions(window.innerWidth, window.innerHeight)
+ setWindowDimensions(window.innerWidth, window.innerHeight)
})
}
if (debounceScroll) {
window.addEventListener('scroll', handleScroll)
} else {
window.addEventListener('scroll', () => {
- useWindowStore.setScrollPosition(window.scrollX, window.scrollY)
+ setScrollPosition(window.scrollX, window.scrollY)
})
}
return () => {
diff --git a/src/constants.js b/src/constants.js
index 131fb728..09b5426f 100644
--- a/src/constants.js
+++ b/src/constants.js
@@ -254,3 +254,15 @@ export const ArticleCellContainerClassNames = [
'alert-danger',
'alert-warning',
]
+
+export const OrderByQueryParam = 'orderBy'
+export const FilterByQueryparam = 'f'
+export const OrderByIssue = 'issue'
+export const OrderByPublicationDateAsc = 'dateAsc'
+export const OrderByPublicationDateDesc = 'dateDesc'
+
+export const AvailablesOrderByComparators = {
+ [OrderByIssue]: () => {},
+ [OrderByPublicationDateAsc]: (a, b) => a.publication_date - b.publication_date,
+ [OrderByPublicationDateDesc]: (a, b) => b.publication_date - a.publication_date,
+}
diff --git a/src/pages/Articles.js b/src/pages/Articles.js
index d5e5f75f..e92c3597 100644
--- a/src/pages/Articles.js
+++ b/src/pages/Articles.js
@@ -1,253 +1,98 @@
-import React, { useRef, useState, useMemo, useLayoutEffect } from 'react'
-import { useTranslation } from 'react-i18next'
-import groupBy from 'lodash/groupBy'
-import { Container, Row, Col } from 'react-bootstrap'
-import { useSpring, config } from 'react-spring'
-import { useHistory } from 'react-router'
-import StaticPageLoader from './StaticPageLoader'
-import IssueArticles from '../components/Issue/IssueArticles'
-import Issue from '../components/Issue'
-import ArticleFingerprintTooltip from '../components/ArticleV2/ArticleFingerprintTooltip'
-import {
- BootstrapColumLayout,
- DisplayLayerCellIdxQueryParam,
- DisplayLayerQueryParam,
- LayerNarrative,
- LayerHermeneutics,
- StatusSuccess,
-} from '../constants'
-import { useBoundingClientRect } from '../hooks/graphics'
-import '../styles/pages/Articles.scss'
-import { useQueryParams, withDefault } from 'use-query-params'
-import { asEnumParam, asRegexArrayParam } from '../logic/params'
-import OrderByDropdown from '../components/OrderByDropdown'
-import { sort } from 'd3-array'
-import Article from '../models/Article'
-import ArticlesFacets from '../components/Articles/ArticlesFacets'
-
-const OrderByQueryParam = 'orderBy'
-const FilterByQueryparam = 'f'
-const OrderByIssue = 'issue'
-const OrderByPublicationDateAsc = 'dateAsc'
-const OrderByPublicationDateDesc = 'dateDesc'
+import React, { useEffect } from 'react'
-const AvailablesOrderByComparators = {
- [OrderByIssue]: () => {},
- [OrderByPublicationDateAsc]: (a, b) => a.publication_date - b.publication_date,
- [OrderByPublicationDateDesc]: (a, b) => b.publication_date - a.publication_date,
-}
+import '../styles/pages/Articles.scss'
+import PropTypes from 'prop-types'
+import ArticlesGrid from '../components/Articles/ArticlesGrid'
+import { useQuery } from '@tanstack/react-query'
+import axios from 'axios'
+import { usePropsStore } from '../store'
+import { StatusError, StatusFetching, StatusSuccess } from '../constants'
+import ErrorViewer from './ErrorViewer'
-const ArticlesGrid = ({
- data: response = [],
- url,
- issueId,
- status,
- // tag ategories to keep
- categories = ['narrative', 'tool', 'issue'],
+const Articles = ({
+ match: {
+ params: { id: issueId },
+ },
}) => {
- const { t } = useTranslation()
- const [{ [OrderByQueryParam]: orderBy }, setQuery] = useQueryParams({
- [OrderByQueryParam]: withDefault(
- asEnumParam(Object.keys(AvailablesOrderByComparators)),
- OrderByIssue,
- ),
- [FilterByQueryparam]: asRegexArrayParam(),
+ console.debug('[Articles] match.params.id/issueId:', issueId)
+ const [setLoadingProgress, setLoadingProgressFromEvent] = usePropsStore((state) => [
+ state.setLoadingProgress,
+ state.setLoadingProgressFromEvent,
+ ])
+ const {
+ data: issues,
+ error: errorIssues,
+ status: statusIssues,
+ } = useQuery({
+ queryKey: ['/api/issues'],
+ queryFn: () =>
+ axios
+ .get('/api/issues?ordering=-pid', {
+ timeout: 10000,
+ onDownloadProgress: (e) => setLoadingProgressFromEvent(e, 'articles', 0.5, 0),
+ })
+ .then((res) => res.data.results),
})
-
- 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,
- }))
- const data = (response.results || []).map((d, idx) => new Article({ ...d, idx }))
- const articles = sort(data, AvailablesOrderByComparators[orderBy])
- const { articlesByIssue, issues, showFilters } = useMemo(() => {
- if (status !== StatusSuccess) {
- return {
- articlesByIssue: {},
- issues: [],
- sortedItems: [],
- showFilters: false,
- }
- }
- const sortedItems = data.map((item, idx) => ({
- ...item,
- idx,
- }))
- const articlesByIssue = groupBy(sortedItems, 'issue.pid')
- const issues = Object.keys(articlesByIssue).sort((a, b) => {
- return articlesByIssue[a][0].issue.pid < articlesByIssue[b][0].issue.pid
- })
- const showFilters = data.reduce((acc, d) => {
- return acc || d.tags.some((t) => categories.includes(t.category))
- }, false)
- return { articlesByIssue, issues, showFilters }
- }, [url, 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 = Math.min(width - 250, 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',
+ const {
+ data: articles,
+ error: errorArticles,
+ status: statusArticles,
+ } = useQuery({
+ queryKey: ['/api/articles'],
+ queryFn: () =>
+ axios
+ .get('/api/articles', {
+ timeout: 10000,
+ onDownloadProgress: (e) => setLoadingProgressFromEvent(e, 'articles', 0.5, 0.5),
})
+ .then((res) => res.data.results),
+ enabled: statusIssues === StatusSuccess,
+ })
+
+ useEffect(() => {
+ if (statusIssues === StatusFetching) {
+ setLoadingProgress(0.05, 'articles')
+ } else if (statusArticles === StatusSuccess) {
+ setLoadingProgress(1, 'articles')
+ } else if (statusArticles === StatusError) {
+ setLoadingProgress(0, 'articles')
}
- }, [status])
+ }, [statusIssues, statusArticles])
- useLayoutEffect(() => {
- setAnimatedProps.start({ opacity: 0 })
- }, [selected])
console.debug(
- '[Articles] \n- articles:',
+ '[Articles] \n- statusIssues:',
+ statusIssues,
+ '\n- issues:',
+ Array.isArray(issues),
+ issues,
+ '\n- statusArticles:',
+ statusArticles,
+ '\n- articles:',
Array.isArray(articles),
articles,
- '\n- issueId:',
- issueId,
)
return (
-
-
-
-
- {t('pages.articles.title')}
-
- {showFilters &&
{t('pages.articles.subheading')}
}
-
({
- value,
- label: t(`orderBy${value}`),
- }))}
- title={t(`orderBy${orderBy}`)}
- onChange={({ value }) => setQuery({ [OrderByQueryParam]: value })}
- />
-
-
-
- {showFilters && (
-
-
- {status === StatusSuccess && (
-
- )}
-
-
+ <>
+ {statusIssues === StatusError && (
+
)}
-
- {orderBy === OrderByIssue &&
- issues.map((id) => {
- const issue = articlesByIssue[id][0].issue
- return (
-
-
-
-
-
-
-
-
-
- )
- })}
- {[OrderByPublicationDateAsc, OrderByPublicationDateDesc].includes(orderBy) && (
-
+ {statusArticles === StatusError && (
+
+ )}
+ {statusIssues !== StatusError && statusArticles !== StatusError && (
+
)}
-
+ >
)
}
-const Articles = ({
- match: {
- params: { id: issueId },
- },
-}) => {
- console.debug('[Articles] issueId', issueId)
- return (
-
- )
+Articles.propTypes = {
+ match: PropTypes.shape({
+ params: PropTypes.shape({
+ id: PropTypes.string,
+ }).isRequired,
+ }).isRequired,
}
export default Articles
diff --git a/src/setupProxy.js b/src/setupProxy.js
index 47e956bc..627da878 100644
--- a/src/setupProxy.js
+++ b/src/setupProxy.js
@@ -6,7 +6,9 @@ const apiPath = process.env.REACT_APP_API_ROOT || '/api'
fs.appendFile(
'./setupProxy.log',
- `${new Date().toISOString()} target=${target} apiPath=${apiPath}\n`,
+ `${new Date().toISOString()} target=${target} apiPath=${apiPath} REACT_APP_PROXY=${
+ process.env.REACT_APP_PROXY
+ } \n`,
(err) => console.error(err),
)
diff --git a/src/store.js b/src/store.js
index bbdaa9a0..8b8032d9 100644
--- a/src/store.js
+++ b/src/store.js
@@ -154,6 +154,11 @@ export const usePropsStore = create((set) => ({
loadingLabel: '',
setLoadingProgress: (loadingProgress, loadingLabel = '') =>
set({ loadingProgress, loadingLabel }),
+ setLoadingProgressFromEvent: (e, loadingLabel = '', ratio = 1, initial = 0) => {
+ const { total, loaded } = e
+ const loadingProgress = Math.max(1, initial + ratio * (total ? loaded / total : 0))
+ set({ loadingProgress, loadingLabel })
+ },
}))
export const useWindowStore = create((set) => ({
diff --git a/src/styles/article.scss b/src/styles/article.scss
index 4c30230c..3042b1ac 100644
--- a/src/styles/article.scss
+++ b/src/styles/article.scss
@@ -736,7 +736,7 @@ svg.ArticleFingerprint {
padding: 9px 15px;
pointer-events: none;
width: 200px;
- left: 100px;
+ left: 0px;
}
.ArticleFingerprintTooltip_heading {
diff --git a/src/styles/index.scss b/src/styles/index.scss
index 2c5f7b60..530d6d84 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -98,7 +98,9 @@ html,
box-shadow: 0px 1px 0px var(--primary);
}
}
-
+.border-double {
+ border-width: 2px !important;
+}
.rounded {
border-radius: 0.25rem !important;
}
@@ -110,9 +112,9 @@ html,
}
.navbar .nav-link {
font-size: 0.9rem;
- // color: white;
box-shadow: none;
}
+
.navbar-brand {
box-shadow: none;
}
diff --git a/src/translations.json b/src/translations.json
index 5c6539e9..ee7dfc7e 100644
--- a/src/translations.json
+++ b/src/translations.json
@@ -43,7 +43,10 @@
},
"articles": {
"title": "Articles & Issues",
- "subheading": "Filter by keywords, libraries or browse the articles."
+ "subheading": "Filter by keywords, libraries or browse the articles.",
+ "status": {
+ "PEER_REVIEW": "Currently under Peer Review"
+ }
},
"loading": {
"title": "loading...",
@@ -313,6 +316,12 @@
"directions": ""
}
},
+ "status": {
+ "PEER_REVIEW": "Peer Review",
+ "PUBLISHED": "Published",
+ "DRAFT": "Coming soon",
+ "INTERNAL_REVIEW": "Internal Review"
+ },
"welcomeBack": "Logged in as"
}
}