diff --git a/keepachangelog.hbs b/keepachangelog.hbs index 55c433329..1f2a33a44 100644 --- a/keepachangelog.hbs +++ b/keepachangelog.hbs @@ -1,5 +1,3 @@ -# Changelog - All notable changes to the ORKG will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and we adhere to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). diff --git a/src/assets/scss/ThemeVariables.scss b/src/assets/scss/ThemeVariables.scss index 81bb6cd17..f86dbd9dc 100644 --- a/src/assets/scss/ThemeVariables.scss +++ b/src/assets/scss/ThemeVariables.scss @@ -19,6 +19,7 @@ $border-radius: 6px; $theme-colors: ( primary-darker: $primary-darker, secondary-darker: $secondary-darker, + light-darker: $light-darker, body: $body-color ); diff --git a/src/components/ListPage/ListPage.js b/src/components/ListPage/ListPage.js index 7863503dc..095152a32 100644 --- a/src/components/ListPage/ListPage.js +++ b/src/components/ListPage/ListPage.js @@ -6,6 +6,7 @@ import PropTypes from 'prop-types'; import { useCallback, useEffect, useState } from 'react'; import { usePrevious } from 'react-use'; import { ButtonGroup, Container, ListGroup } from 'reactstrap'; +import TitleBar from 'components/TitleBar/TitleBar'; const ListPage = ({ label, resourceClass, renderListItem, buttons, fetchItems, boxShadow, pageSize = 25 }) => { const [results, setResults] = useState([]); @@ -79,17 +80,20 @@ const ListPage = ({ label, resourceClass, renderListItem, buttons, fetchItems, b return ( <> - -
-

View {label}

-
+ {totalElements === 0 && isLoading ? : totalElements} {label}
-
- - {buttons} - -
+ } + buttonGroup={ + <> + {buttons} + + } + > + View {label} + {results.length > 0 && ( diff --git a/src/components/MainTitle/MainTitle.js b/src/components/MainTitle/MainTitle.js deleted file mode 100644 index 57c6776b2..000000000 --- a/src/components/MainTitle/MainTitle.js +++ /dev/null @@ -1,65 +0,0 @@ -import { faBars } from '@fortawesome/free-solid-svg-icons'; -import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; -import PropTypes from 'prop-types'; -import { useState } from 'react'; -import { Button, ButtonGroup, Container } from 'reactstrap'; -import styled from 'styled-components'; - -const ButtonGroupStyled = styled(ButtonGroup)` - @media (max-width: 480px) { - display: none; - flex-direction: column; - width: 100%; - - > { - margin-right: 0 !important; - } - > button:first-child, - > .btn-group:first-child > button:first-child { - border-radius: ${props => props.theme.borderRadius} ${props => props.theme.borderRadius} 0 0 !important; - } - > button:last-child, - > .btn-group:last-child > button { - border-radius: 0 0 ${props => props.theme.borderRadius} ${props => props.theme.borderRadius} !important; - } - > * { - margin-top: 1px !important; - margin-left: 0 !important; - margin-right: 0 !important; - } - } -`; - -const MenuButton = styled(Button)` - width: 100%; - display: none; - - @media (max-width: 480px) { - display: block; - } -`; - -const MainTitle = ({ title = '', children = null }) => { - const [isMenuOpen, setIsMenuOpen] = useState(false); - - return ( - -

{title}

- - setIsMenuOpen(v => !v)}> - Menu - - - {children} - -
- ); -}; - -MainTitle.propTypes = { - title: PropTypes.string, - buttons: PropTypes.node, - children: PropTypes.node -}; - -export default MainTitle; diff --git a/src/components/ResearchField/ResearchFieldHeader.js b/src/components/ResearchField/ResearchFieldHeader.js index fba2da572..50572d65b 100644 --- a/src/components/ResearchField/ResearchFieldHeader.js +++ b/src/components/ResearchField/ResearchFieldHeader.js @@ -32,6 +32,7 @@ import CheckSlug from 'components/CheckSlug/CheckSlug'; import CheckClasses from 'components/CheckClasses/CheckClasses'; import { reverseWithSlug } from 'utils'; import { CLASSES } from 'constants/graphSettings'; +import TitleBar from 'components/TitleBar/TitleBar'; const ResearchFieldHeader = ({ id }) => { const [menuOpen, setMenuOpen] = useState(false); @@ -88,46 +89,54 @@ const ResearchFieldHeader = ({ id }) => { )} {!isLoading && !isFailedLoading && ( <> - -

Research field

- <> - - {researchFieldData.label} - - {editMode && ( - setEditMode(v => !v)} - id={id} - label={researchFieldData.label} - enableEdit={true} - syncBackend={true} - /> - )} - - {isCurationAllowed && ( - setEditMode(v => !v)} - > - Edit - - )} - setMenuOpen(v => !v)} nav inNavbar> - - - - - - View resource - - - - -
+ {editMode && ( + setEditMode(v => !v)} + id={id} + label={researchFieldData.label} + enableEdit={true} + syncBackend={true} + /> + )} + + + {researchFieldData.label} + + } + buttonGroup={ + <> + {isCurationAllowed && ( + setEditMode(v => !v)} + style={{ marginRight: 2 }} + > + Edit + + )} + setMenuOpen(v => !v)} nav inNavbar> + + + + + + View resource + + + + + } + wrap={false} + > + Research field + + {(researchFieldData.description || researchFieldData.sameAs) && ( diff --git a/src/components/ResearchProblem/ResearchProblemHeader.js b/src/components/ResearchProblem/ResearchProblemHeader.js index 3144be097..6197d7597 100644 --- a/src/components/ResearchProblem/ResearchProblemHeader.js +++ b/src/components/ResearchProblem/ResearchProblemHeader.js @@ -38,6 +38,7 @@ import CheckSlug from 'components/CheckSlug/CheckSlug'; import { reverseWithSlug } from 'utils'; import CheckClasses from 'components/CheckClasses/CheckClasses'; import { CLASSES } from 'constants/graphSettings'; +import TitleBar from 'components/TitleBar/TitleBar'; const ResearchProblemHeader = ({ id }) => { const [menuOpen, setMenuOpen] = useState(false); @@ -96,44 +97,51 @@ const ResearchProblemHeader = ({ id }) => { {!isLoading && !isFailedLoading && ( <> - -

Research problem

- <> - - {researchProblemData.label} - - {editMode && ( - setEditMode(v => !v)} - id={id} - label={researchProblemData.label} - enableEdit={true} - syncBackend={true} - /> - )} - - setEditMode(v => !v)} - > - Edit - - setMenuOpen(v => !v)} nav inNavbar> - - - - - - View resource - - - - -
+ + + {researchProblemData.label} + + } + buttonGroup={ + <> + setEditMode(v => !v)} + style={{ marginRight: 2 }} + > + Edit + + setMenuOpen(v => !v)} nav inNavbar> + + + + + + View resource + + + + + } + wrap={false} + > + Research problem + + {editMode && ( + setEditMode(v => !v)} + id={id} + label={researchProblemData.label} + enableEdit={true} + syncBackend={true} + /> + )} diff --git a/src/components/TitleBar/TitleBar.js b/src/components/TitleBar/TitleBar.js new file mode 100644 index 000000000..bc38100cd --- /dev/null +++ b/src/components/TitleBar/TitleBar.js @@ -0,0 +1,94 @@ +import { faEllipsisV } from '@fortawesome/free-solid-svg-icons'; +import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; +import PropTypes from 'prop-types'; +import { useState } from 'react'; +import { Button, ButtonGroup, Container } from 'reactstrap'; +import styled from 'styled-components'; + +const ContainerStyled = styled(Container)` + @media (max-width: 480px) { + margin-top: 1rem !important; + flex-wrap: wrap; + } +`; +const ButtonGroupStyled = styled(ButtonGroup)` + margin-left: auto; + + @media (max-width: 480px) { + display: none; + flex-direction: column; + width: 100%; + + > { + margin-right: 0 !important; + } + > button:first-child, + > .btn:first-child, + > .btn-group:first-child > button:first-child { + border-radius: ${props => props.theme.borderRadius} ${props => props.theme.borderRadius} 0 0 !important; + } + > button:last-child, + > .btn:last-child, + > .btn-group:last-child > button { + border-radius: 0 0 ${props => props.theme.borderRadius} ${props => props.theme.borderRadius} !important; + } + > button:first-child:last-child, + .btn:first-child:last-child, + .btn-group:first-child:last-child > button { + border-radius: ${props => props.theme.borderRadius} !important; + } + > * { + margin-top: 1px !important; + margin-left: 0 !important; + margin-right: 0 !important; + } + + .dropdown-menu { + width: calc(100% - 0rem); + } + } +`; + +const MenuButton = styled(Button)` + display: none; + flex-grow: 0; + margin-left: auto; + + @media (max-width: 480px) { + display: block; + } +`; + +const TitleBar = ({ buttonGroup = null, titleAddition = null, children = '', wrap = true }) => { + const [isMenuOpen, setIsMenuOpen] = useState(false); + + return ( + +

{children}

{titleAddition} + {buttonGroup && ( + setIsMenuOpen(v => !v)} + > + + + )} + {buttonGroup && ( + + {buttonGroup} + + )} +
+ ); +}; + +TitleBar.propTypes = { + buttonGroup: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), + titleAddition: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), + children: PropTypes.oneOfType([PropTypes.node, PropTypes.string]), + wrap: PropTypes.bool +}; + +export default TitleBar; diff --git a/src/components/ViewPaper/PaperHeaderBar/PaperMenuBar.js b/src/components/ViewPaper/PaperHeaderBar/PaperMenuBar.js index aee797842..0fd5598c8 100644 --- a/src/components/ViewPaper/PaperHeaderBar/PaperMenuBar.js +++ b/src/components/ViewPaper/PaperHeaderBar/PaperMenuBar.js @@ -15,59 +15,52 @@ function PaperMenuBar(props) { return ( <> - - {props.paperLink && ( - - View paper - - )} - + + {!props.editMode && ( + props.toggle('showGraphModal')} + onClick={() => (!props.disableEdit ? props.toggle('editMode') : setIsOpenPWCModal(true))} > - Graph view - + Edit + + )} - {!props.editMode && ( - (!props.disableEdit ? props.toggle('editMode') : setIsOpenPWCModal(true))} - > - Edit - - )} + {props.editMode && ( + + )} - {props.editMode && ( - - )} + setMenuOpen(v => !v)}> + + + + + + View resource + + + - setMenuOpen(v => !v)} nav inNavbar> - - - - - - View resource - - - - setIsOpenPWCModal(v => !v)} label={props.label} /> ); diff --git a/src/components/styled.js b/src/components/styled.js index 3f913274b..218c7c3c4 100644 --- a/src/components/styled.js +++ b/src/components/styled.js @@ -3,21 +3,29 @@ import styled from 'styled-components'; import Gravatar from 'react-gravatar'; export const SubtitleSeparator = styled.div` + @media (max-width: 480px) { + display: none; + } background: ${props => props.theme.secondary}; width: 2px; height: 24px; - margin: 0 15px; + margin: 3px 15px; content: ''; display: block; opacity: 0.7; + float: left; `; export const SubTitle = styled.div` white-space: nowrap; text-overflow: ellipsis; overflow: hidden; + float: left; margin-right: 20px; color: ${props => props.theme.secondary}; + margin-top: 3px; + min-width: 0; + margin-bottom: 0; `; export const StyledGravatar = styled(Gravatar)` diff --git a/src/pages/About.js b/src/pages/About.js index 153ec0708..128f1798e 100644 --- a/src/pages/About.js +++ b/src/pages/About.js @@ -2,6 +2,7 @@ import CheckSlug from 'components/CheckSlug/CheckSlug'; import PageContentLoader from 'components/Page/PageContentLoader'; import usePage from 'components/Page/usePage'; import { CmsPage } from 'components/styled'; +import TitleBar from 'components/TitleBar/TitleBar'; import ROUTES from 'constants/routes'; import NotFound from 'pages/NotFound'; import { useEffect, useState } from 'react'; @@ -68,9 +69,7 @@ const About = () => {
{!isLoading && params?.id && page?.title && } - -

About ORKG

-
+ About ORKG {!isLoadingMenu && menuItems.length > 0 && ( diff --git a/src/pages/AddComparison.js b/src/pages/AddComparison.js index 9c12b2a0d..284d7cd4f 100644 --- a/src/pages/AddComparison.js +++ b/src/pages/AddComparison.js @@ -3,6 +3,7 @@ import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; import comparisonPublishImg from 'assets/img/AddComparison/comparison-publish-preview.png'; import contributionEditorPreview from 'assets/img/AddComparison/contribution-editor-preview.png'; import csvImportPreview from 'assets/img/AddComparison/csv-import-preview.png'; +import TitleBar from 'components/TitleBar/TitleBar'; import ROUTES from 'constants/routes'; import { Link } from 'react-router-dom'; import { Button, Col, Container, Row } from 'reactstrap'; @@ -12,9 +13,7 @@ const AddComparison = () => { return (
- -

Add comparison

-
+ Add comparison diff --git a/src/pages/AddPaper.js b/src/pages/AddPaper.js index e4fcf4da2..823d4f0fd 100644 --- a/src/pages/AddPaper.js +++ b/src/pages/AddPaper.js @@ -18,6 +18,8 @@ import { openTour, closeTour, blockNavigation, loadPaperData } from '../actions/ import { Prompt } from 'react-router'; import GizmoGraphViewModal from '../components/ViewPaper/GraphView/GizmoGraphViewModal'; import env from '@beam-australia/react-env'; +import TitleBar from 'components/TitleBar/TitleBar'; +import { SubTitle, SubtitleSeparator } from 'components/styled'; const Help = styled.div` box-sizing: border-box; @@ -81,22 +83,13 @@ const AnimationContainer = styled(CSSTransition)` } `; -const SubtitleSeparator = styled.div` - background: ${props => props.theme.secondary}; - width: 2px; - height: 30px; - margin: 0 15px; - content: ''; - display: block; - opacity: 0.7; -`; - const PaperTitle = styled.div` white-space: nowrap; text-overflow: ellipsis; overflow: hidden; margin-right: 20px; color: #62687d; + margin-top: 5px; `; class AddPaper extends Component { @@ -194,38 +187,32 @@ class AddPaper extends Component { return (
- -

Add paper

- - {this.props.currentStep > 1 && ( - <> - - - {this.props.addPaper.title} - - )} - {/* - - Options - - - this.toggle('showGraphModal')}>Show graph visualization - - */} + 1 && ( + <> + + {this.props.addPaper.title} + + ) + } + buttonGroup={ + + } + wrap={false} + > + Add paper + - - -
- diff --git a/src/pages/AuthorPage.js b/src/pages/AuthorPage.js index 0cdb84b74..ed1ca38ce 100644 --- a/src/pages/AuthorPage.js +++ b/src/pages/AuthorPage.js @@ -16,6 +16,7 @@ import { Link } from 'react-router-dom'; import ContentLoader from 'react-content-loader'; import ROUTES from 'constants/routes.js'; import { reverse } from 'named-urls'; +import TitleBar from 'components/TitleBar/TitleBar'; const AuthorMetaInfo = styled.div` .key { @@ -137,29 +138,31 @@ class AuthorPage extends Component { )} {!this.state.loading && (
- -

Author: {this.state.author.label}

- - - this.setState(prevState => ({ - menuOpen: !prevState.menuOpen - })) - } - nav - inNavbar - > - - - - - - View resource - - - -
+ + this.setState(prevState => ({ + menuOpen: !prevState.menuOpen + })) + } + nav + inNavbar + > + + + + + + View resource + + + + } + > + Author: {this.state.author.label} +
diff --git a/src/pages/Benchmarks/Benchmark.js b/src/pages/Benchmarks/Benchmark.js index c55504ccf..414d9daec 100644 --- a/src/pages/Benchmarks/Benchmark.js +++ b/src/pages/Benchmarks/Benchmark.js @@ -20,6 +20,7 @@ import StatementBrowserDialog from 'components/StatementBrowser/StatementBrowser import { useParams } from 'react-router-dom'; import { usePrevious } from 'react-use'; import { useTable, useSortBy } from 'react-table'; +import TitleBar from 'components/TitleBar/TitleBar'; function getTicksAxisH(data) { const dateRange = data.slice(1).map(function(value, index) { @@ -200,46 +201,53 @@ function Benchmark() { {!isLoading && isFailedLoading &&
Failed loading the resource
} {!isLoading && !isFailedLoading && ( <> - -

Benchmark

- <> - - - {problemData.label} on {resourceData.label} - - - {editMode && ( - setEditMode(v => !v)} - id={datasetId} - label={resourceData.label} - enableEdit={true} - syncBackend={true} - /> - )} - - setEditMode(v => !v)} - > - Edit - - setMenuOpen(v => !v)} nav inNavbar> - - - - - - View resource - - - - -
+ + + + {problemData.label} on {resourceData.label} + + + } + buttonGroup={ + <> + setEditMode(v => !v)} + > + Edit + + setMenuOpen(v => !v)} nav inNavbar> + + + + + + View resource + + + + + } + > + Benchmark + + + {editMode && ( + setEditMode(v => !v)} + id={datasetId} + label={resourceData.label} + enableEdit={true} + syncBackend={true} + /> + )} + diff --git a/src/pages/Benchmarks/Benchmarks.js b/src/pages/Benchmarks/Benchmarks.js index 4c5709e39..1879d8bb2 100644 --- a/src/pages/Benchmarks/Benchmarks.js +++ b/src/pages/Benchmarks/Benchmarks.js @@ -7,6 +7,7 @@ import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; import { Row, Container } from 'reactstrap'; import { SearchStyled, InputStyled, SearchButtonStyled } from 'components/styled'; import PWCProvenanceBox from 'components/Benchmarks/PWCProvenanceBox/PWCProvenanceBox'; +import TitleBar from 'components/TitleBar/TitleBar'; function Benchmarks() { const { benchmarks, isLoadingBenchmarks } = useBenchmarks(); @@ -14,23 +15,25 @@ function Benchmarks() { return ( <> - -
-

View all benchmarks

-
+ {benchmarks.length === 0 && isLoadingBenchmarks ? : benchmarks.length} benchmarks{' '} {!!filter && `(${benchmarks.filter(b => b.research_problem.label.toLowerCase().includes(filter.toLowerCase())).length} filtered)`}
-
- - - setFilter(e.target.value)} /> - - - - -
+ } + buttonGroup={ + + setFilter(e.target.value)} /> + + + + + } + > + View all benchmarks +
diff --git a/src/pages/Changelog/Changelog.js b/src/pages/Changelog/Changelog.js index 698145d99..aeeca516f 100644 --- a/src/pages/Changelog/Changelog.js +++ b/src/pages/Changelog/Changelog.js @@ -2,6 +2,7 @@ import { Component } from 'react'; import { Container } from 'reactstrap'; import changelogPath from './CHANGELOG.md'; import marked from 'marked'; +import TitleBar from 'components/TitleBar/TitleBar'; class Changelog extends Component { state = { @@ -24,7 +25,8 @@ class Changelog extends Component { render() { return (
- + Changelog +
{ const isURI = new RegExp(REGEX.URL); @@ -45,11 +46,9 @@ const AddClass = () => { return ( <> - -

Create class

-
+ Create class -
+
Loading ...} {!isLoading && error && <>{error.statusCode === 404 ? : }} {!isLoading && !error && ( - -
-
-
-

- Class:{' '} - {label || ( - - No label - - )} - - - Add resource - - setModalImportIsOpen(true)} - > - Import Instances - - -

-
-
+ <> + + {' '} + + Add resource + + setModalImportIsOpen(true)}> + Import Instances + + + } + > + Class:{' '} + {label || ( + + No label + + )} + + @@ -181,8 +178,8 @@ function ClassDetails(props) { toggle={() => setModalImportIsOpen(v => !v)} callBack={() => setKeyInstances(Math.random())} /> - - + + )} ); diff --git a/src/pages/Classes/Classes.js b/src/pages/Classes/Classes.js index cb5b05d03..82dcb6d00 100644 --- a/src/pages/Classes/Classes.js +++ b/src/pages/Classes/Classes.js @@ -8,6 +8,7 @@ import { getClasses } from 'services/backend/classes'; import { reverse } from 'named-urls'; import { Link } from 'react-router-dom'; import ROUTES from 'constants/routes'; +import TitleBar from 'components/TitleBar/TitleBar'; const Classes = () => { const pageSize = 25; @@ -50,14 +51,13 @@ const Classes = () => { return ( <> - -
-

View all classes

-
+ {totalElements === 0 && isNextPageLoading ? : totalElements} classes
-
- + } + buttonGroup={ { > Create class - -
+ } + > + View all classes + diff --git a/src/pages/Comparisons/Comparison.js b/src/pages/Comparisons/Comparison.js index 7253a7af3..220f92376 100644 --- a/src/pages/Comparisons/Comparison.js +++ b/src/pages/Comparisons/Comparison.js @@ -43,7 +43,7 @@ import { NavLink } from 'react-router-dom'; import { reverse } from 'named-urls'; import env from '@beam-australia/react-env'; import AppliedRule from 'components/Comparison/Filters/AppliedRule'; -import MainTitle from 'components/MainTitle/MainTitle'; +import TitleBar from 'components/TitleBar/TitleBar'; function Comparison(props) { const { @@ -208,187 +208,187 @@ function Comparison(props) { return (
- - Contribution comparison{' '} - {!isFailedLoadingMetaData && contributionsList.length > 1 && ( - - - - {contributionsList.length} - - - - )} - - } - > - {contributionsList.length > 1 && !isLoadingComparisonResult && !isFailedLoadingComparisonResult && ( - <> - setDropdownDensityOpen(v => !v)} style={{ marginRight: 2 }}> - - View - - - - {fullWidth ? 'Reduced width' : 'Full width'} - - toggleTranspose(v => !v)}>Transpose table - - View density - handleViewDensity('spacious')}> - Spacious - - handleViewDensity('normal')}> - Normal - - handleViewDensity('compact')}> - Compact - - - - {!!metaData.id ? ( - - ) : ( - - + 1 && + !isLoadingComparisonResult && + !isFailedLoadingComparisonResult && ( + <> + setDropdownDensityOpen(v => !v)} style={{ marginRight: 2 }}> + + View + + + + {fullWidth ? 'Reduced width' : 'Full width'} + + toggleTranspose(v => !v)}>Transpose table + + View density + handleViewDensity('spacious')}> + Spacious + + handleViewDensity('normal')}> + Normal + + handleViewDensity('compact')}> + Compact + + + + {!!metaData.id ? ( + + ) : ( + - Export as RDF - - {metaData?.id && metaData?.doi && ( - setShowExportCitationsDialog(v => !v)}>Export Citation - )} - {metaData?.id && ( + + Visualize + + + )} + setDropdownOpen(v => !v)}> + + More + + + Customize + setShowAddContribution(v => !v)}>Add contribution + setShowPropertiesDialog(v => !v)}>Select properties + setDropdownMethodOpen(v => !v)} direction="left"> + + Comparison method + + +
+ handleChangeType('merge')} + active={comparisonType !== 'path'} + > + Intelligent merge example + + + handleChangeType('path')} + active={comparisonType === 'path'} + > + Exact match example + +
+
+
+ Edit contributions + + + Export + setShowLatexDialog(v => !v)}>Export as LaTeX + {matrixData ? ( + setDropdownOpen(v => !v)} + > + Export as CSV + + ) : ( + '' + )} + + generateRdfDataVocabularyFile( + data, + contributions, + properties, + metaData.id + ? { + title: metaData.title, + description: metaData.description, + creator: metaData.createdBy, + date: metaData.createdAt + } + : { title: '', description: '', creator: '', date: '' } + ) + } > - Jupyter Notebook + Export as RDF - )} - - setShowShareDialog(v => !v)}>Share link - { - if (!props.user) { - props.openAuthDialog({ action: 'signin', signInRequired: true }); - } else { - setShowPublishDialog(v => !v); - } - }} - > - Publish - - {!isLoadingVersions && versions?.length > 1 && ( - <> - - setShowComparisonVersions(v => !v)}> - History - - - )} - {metaData?.id && ( - <> - - - View resource + {metaData?.id && metaData?.doi && ( + setShowExportCitationsDialog(v => !v)}>Export Citation + )} + {metaData?.id && ( + + Jupyter Notebook - - )} -
-
- + )} + + setShowShareDialog(v => !v)}>Share link + { + if (!props.user) { + props.openAuthDialog({ action: 'signin', signInRequired: true }); + } else { + setShowPublishDialog(v => !v); + } + }} + > + Publish + + {!isLoadingVersions && versions?.length > 1 && ( + <> + + setShowComparisonVersions(v => !v)}> + History + + + )} + {metaData?.id && ( + <> + + + View resource + + + )} + + + + ) + } + > + Contribution comparison{' '} + {!isFailedLoadingMetaData && contributionsList.length > 1 && ( + + + + {contributionsList.length} + + + )} -
+ {!isLoadingVersions && hasNextVersion && ( diff --git a/src/pages/Comparisons/ComparisonDiff.js b/src/pages/Comparisons/ComparisonDiff.js index f40efcc04..4fe586b88 100644 --- a/src/pages/Comparisons/ComparisonDiff.js +++ b/src/pages/Comparisons/ComparisonDiff.js @@ -16,6 +16,7 @@ import { Alert, Button, ButtonGroup, Container } from 'reactstrap'; import queryString from 'query-string'; import { getStatementsBySubject } from 'services/backend/statements'; import { getResource } from 'services/backend/resources'; +import TitleBar from 'components/TitleBar/TitleBar'; const ComparisonDiff = () => { const { oldId, newId } = useParams(); @@ -66,21 +67,20 @@ const ComparisonDiff = () => { return ( <> - -
-

Compare versions

-
- - - - -
-
-
+ + + + + } + > + Compare versions + {switchedVersions && (
diff --git a/src/pages/Comparisons/Comparisons.js b/src/pages/Comparisons/Comparisons.js index 73b7703fc..9cf6b1aa3 100644 --- a/src/pages/Comparisons/Comparisons.js +++ b/src/pages/Comparisons/Comparisons.js @@ -1,7 +1,7 @@ import { useState, useEffect } from 'react'; import { getStatementsBySubjects } from 'services/backend/statements'; import { getResourcesByClass } from 'services/backend/resources'; -import { Container, ButtonGroup, ListGroup } from 'reactstrap'; +import { Container, ListGroup } from 'reactstrap'; import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; import { faSpinner } from '@fortawesome/free-solid-svg-icons'; import { getComparisonData, groupVersionsOfComparisons } from 'utils'; @@ -9,6 +9,7 @@ import { find, flatten } from 'lodash'; import ComparisonCard from 'components/ComparisonCard/ComparisonCard'; import { CLASSES } from 'constants/graphSettings'; import HeaderSearchButton from 'components/HeaderSearchButton/HeaderSearchButton'; +import TitleBar from 'components/TitleBar/TitleBar'; const Comparisons = () => { const pageSize = 15; @@ -70,17 +71,16 @@ const Comparisons = () => { return ( <> - -
-

View all published comparisons

-
+ {totalElements === 0 && isNextPageLoading ? : totalElements} comparisons
-
- - - -
+ } + buttonGroup={} + > + View all published comparisons + diff --git a/src/pages/ContributionEditor.js b/src/pages/ContributionEditor.js index 40b00e710..d123c069f 100644 --- a/src/pages/ContributionEditor.js +++ b/src/pages/ContributionEditor.js @@ -18,6 +18,7 @@ import { useDispatch, useSelector } from 'react-redux'; import { Link } from 'react-router-dom'; import env from '@beam-australia/react-env'; import { Alert, Button, ButtonGroup, Container } from 'reactstrap'; +import TitleBar from 'components/TitleBar/TitleBar'; const ContributionEditor = () => { const [isOpenAddContribution, setIsOpenAddContribution] = useState(false); @@ -93,29 +94,29 @@ const ContributionEditor = () => { return ( <> - -
-

Contribution editor

-
- - - - - -
+ + + + + } + > + Contribution editor + {!hasFailed && contributionAmount === 0 && ( diff --git a/src/pages/Data.js b/src/pages/Data.js index a49a593b5..56bba9502 100644 --- a/src/pages/Data.js +++ b/src/pages/Data.js @@ -2,6 +2,7 @@ import { useEffect } from 'react'; import { Container, Button, Card, CardTitle, CardText, Row, Col } from 'reactstrap'; import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; import { faPython } from '@fortawesome/free-brands-svg-icons'; +import TitleBar from 'components/TitleBar/TitleBar'; const Data = () => { useEffect(() => { @@ -10,9 +11,7 @@ const Data = () => { return (
- -

Data Access

-
+ Data Access
diff --git a/src/pages/FeaturedComparisons.js b/src/pages/FeaturedComparisons.js index a70af3c14..dec68638c 100644 --- a/src/pages/FeaturedComparisons.js +++ b/src/pages/FeaturedComparisons.js @@ -11,6 +11,7 @@ import { PREDICATES, CLASSES } from 'constants/graphSettings'; import { kebabCase, isString } from 'lodash'; import { useLocation, useHistory } from 'react-router'; import styled from 'styled-components'; +import TitleBar from 'components/TitleBar/TitleBar'; const Header = styled.h2` &:hover a { @@ -125,14 +126,15 @@ const FeaturedComparisons = () => { return (
- -

Featured paper comparisons

- + View all comparisons - -
+ } + > + Featured paper comparisons + With the paper data inside the ORKG, you can build powerful paper comparisons. On this page, we list the featured comparisons that diff --git a/src/pages/HelpCenter/HelpCenter.js b/src/pages/HelpCenter/HelpCenter.js index 84000586e..675d7971f 100644 --- a/src/pages/HelpCenter/HelpCenter.js +++ b/src/pages/HelpCenter/HelpCenter.js @@ -1,4 +1,5 @@ import HelpCenterSearchInput from 'components/HelpCenterSearchInput/HelpCenterSearchInput'; +import TitleBar from 'components/TitleBar/TitleBar'; import ROUTES from 'constants/routes'; import { times } from 'lodash'; import { reverse } from 'named-urls'; @@ -38,9 +39,7 @@ const HelpCenter = () => { return (
- -

Help center

-
+ Help center diff --git a/src/pages/HelpCenter/HelpCenterArticle.js b/src/pages/HelpCenter/HelpCenterArticle.js index d17b7e9e9..a79518a2c 100644 --- a/src/pages/HelpCenter/HelpCenterArticle.js +++ b/src/pages/HelpCenter/HelpCenterArticle.js @@ -2,6 +2,7 @@ import CheckSlug from 'components/CheckSlug/CheckSlug'; import PageContentLoader from 'components/Page/PageContentLoader'; import usePage from 'components/Page/usePage'; import { CmsPage } from 'components/styled'; +import TitleBar from 'components/TitleBar/TitleBar'; import ROUTES from 'constants/routes'; import { reverse } from 'named-urls'; import NotFound from 'pages/NotFound'; @@ -35,9 +36,7 @@ const HelpCenterArticle = () => {
{!isLoading && params?.id && page?.title && } - -

Help center

-
+ Help center {isLoading && } diff --git a/src/pages/HelpCenter/HelpCenterCategory.js b/src/pages/HelpCenter/HelpCenterCategory.js index 78482fced..74085a3e7 100644 --- a/src/pages/HelpCenter/HelpCenterCategory.js +++ b/src/pages/HelpCenter/HelpCenterCategory.js @@ -1,3 +1,4 @@ +import TitleBar from 'components/TitleBar/TitleBar'; import ROUTES from 'constants/routes'; import NotFound from 'pages/NotFound'; import { useEffect, useState } from 'react'; @@ -39,9 +40,7 @@ const HelpCenterCategory = () => { return (
- -

Help center

-
+ Help center {isLoading && 'Loading...'} diff --git a/src/pages/HelpCenter/HelpCenterSearch.js b/src/pages/HelpCenter/HelpCenterSearch.js index 84c006d69..ff76eef3b 100644 --- a/src/pages/HelpCenter/HelpCenterSearch.js +++ b/src/pages/HelpCenter/HelpCenterSearch.js @@ -1,4 +1,5 @@ import HelpCenterSearchInput from 'components/HelpCenterSearchInput/HelpCenterSearchInput'; +import TitleBar from 'components/TitleBar/TitleBar'; import ROUTES from 'constants/routes'; import { useEffect, useState } from 'react'; import { useParams } from 'react-router'; @@ -41,9 +42,7 @@ const HelpCenterSearch = () => { return (
- -

Help center

-
+ Help center {isLoading && 'Loading...'} diff --git a/src/pages/InternalServerError.js b/src/pages/InternalServerError.js index 527565e2d..c1e49ad07 100644 --- a/src/pages/InternalServerError.js +++ b/src/pages/InternalServerError.js @@ -4,6 +4,7 @@ import { Link } from 'react-router-dom'; import ROUTES from 'constants/routes.js'; import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; import { faBug } from '@fortawesome/free-solid-svg-icons'; +import TitleBar from 'components/TitleBar/TitleBar'; class InternalServerError extends Component { componentDidMount = () => { @@ -13,9 +14,7 @@ class InternalServerError extends Component { render() { return (
- -

An error has occurred

-
+ An error has occurred
diff --git a/src/pages/NotFound.js b/src/pages/NotFound.js index b86b09271..f6c81658a 100644 --- a/src/pages/NotFound.js +++ b/src/pages/NotFound.js @@ -4,6 +4,7 @@ import { Link } from 'react-router-dom'; import ROUTES from 'constants/routes.js'; import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; import { faBug } from '@fortawesome/free-solid-svg-icons'; +import TitleBar from 'components/TitleBar/TitleBar'; class NotFound extends Component { componentDidMount = () => { @@ -13,9 +14,7 @@ class NotFound extends Component { render() { return (
- -

An error has occurred

-
+ An error has occurred
diff --git a/src/pages/Observatories/Observatories.js b/src/pages/Observatories/Observatories.js index 9316e879b..88fb75791 100644 --- a/src/pages/Observatories/Observatories.js +++ b/src/pages/Observatories/Observatories.js @@ -11,6 +11,7 @@ import styled from 'styled-components'; import { withRouter } from 'react-router-dom'; import PropTypes from 'prop-types'; import { groupBy } from 'lodash'; +import TitleBar from 'components/TitleBar/TitleBar'; const TabPaneStyled = styled(TabPane)` border-top: 0; @@ -131,9 +132,7 @@ class Observatories extends Component { render() { return ( <> - -

View all observatories

-
+ View all observatories

Observatories organize research contributions in a particular research field and are curated by research organizations diff --git a/src/pages/Observatories/Observatory.js b/src/pages/Observatories/Observatory.js index e14f920cb..cf2c36b5b 100644 --- a/src/pages/Observatories/Observatory.js +++ b/src/pages/Observatories/Observatory.js @@ -16,6 +16,7 @@ import { useParams } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { faPen } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; +import TitleBar from 'components/TitleBar/TitleBar'; const Observatory = () => { const [error, setError] = useState(null); @@ -73,20 +74,25 @@ const Observatory = () => { {!isLoading && !error && label && ( <> - -

Observatory

- <> - - {label} - - {!!user && user.isCurationAllowed && ( - + + + {label} + + } + buttonGroup={ + !!user && + user.isCurationAllowed && ( - - )} -
+ ) + } + wrap={false} + > + Observatory + {description && ( diff --git a/src/pages/Organizations/AddOrganization.js b/src/pages/Organizations/AddOrganization.js index 36f35af66..c9bff404a 100644 --- a/src/pages/Organizations/AddOrganization.js +++ b/src/pages/Organizations/AddOrganization.js @@ -14,6 +14,7 @@ import { getPublicUrl } from 'utils'; import slugify from 'slugify'; import ROUTES from 'constants/routes'; import Tooltip from 'components/Utils/Tooltip'; +import TitleBar from 'components/TitleBar/TitleBar'; class AddOrganization extends Component { constructor(props) { @@ -118,9 +119,7 @@ class AddOrganization extends Component { return ( <> - -

Create new organization

-
+ Create new organization {!!this.props.user && this.props.user.isCurationAllowed && (
diff --git a/src/pages/Organizations/OrganizationDetails.js b/src/pages/Organizations/OrganizationDetails.js index f629f6b58..e5f503b50 100644 --- a/src/pages/Organizations/OrganizationDetails.js +++ b/src/pages/Organizations/OrganizationDetails.js @@ -16,6 +16,7 @@ import { faPen, faPlus } from '@fortawesome/free-solid-svg-icons'; import EditOrganization from 'components/Organization/EditOrganization'; import { SubTitle, SubtitleSeparator } from 'components/styled'; import { reverse } from 'named-urls'; +import TitleBar from 'components/TitleBar/TitleBar'; const StyledOrganizationHeader = styled.div` .logoContainer { @@ -89,23 +90,36 @@ const OrganizationDetails = () => { {!isLoading && error && <>{error.statusCode === 404 ? : }} {!isLoading && !error && label && ( <> - -

Organization

- <> - - {label} - - {!!user && (user.id === createdBy || user.isCurationAllowed) && ( - - - - - )} -
+ + + {label} + + } + buttonGroup={ + !!user && + (user.id === createdBy || user.isCurationAllowed) && ( + <> + + + + ) + } + wrap={false} + > + Organization + diff --git a/src/pages/Organizations/Organizations.js b/src/pages/Organizations/Organizations.js index 45e2dc4bf..1d115d943 100644 --- a/src/pages/Organizations/Organizations.js +++ b/src/pages/Organizations/Organizations.js @@ -10,6 +10,7 @@ import { Link } from 'react-router-dom'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import ROUTES from 'constants/routes'; +import TitleBar from 'components/TitleBar/TitleBar'; class Organizations extends Component { constructor(props) { @@ -51,20 +52,24 @@ class Organizations extends Component { render() { return ( <> - -

View all organizations

- {!!this.props.user && this.props.user.isCurationAllowed && ( - - Create new organization - - )} -
+ + Create new organization + + ) + } + > + View all organizations + {this.state.organizations.length > 0 && (
diff --git a/src/pages/Page.js b/src/pages/Page.js index aa4bd98e2..4b617ff34 100644 --- a/src/pages/Page.js +++ b/src/pages/Page.js @@ -1,6 +1,7 @@ import PageContentLoader from 'components/Page/PageContentLoader'; import usePage from 'components/Page/usePage'; import { CmsPage } from 'components/styled'; +import TitleBar from 'components/TitleBar/TitleBar'; import NotFound from 'pages/NotFound'; import { useEffect } from 'react'; import { useParams } from 'react-router'; @@ -29,9 +30,7 @@ const Page = () => { return (
- -

{page?.title}

-
+ {page?.title} {isLoading && } diff --git a/src/pages/Papers.js b/src/pages/Papers.js index 27527b8af..fe39d2d11 100644 --- a/src/pages/Papers.js +++ b/src/pages/Papers.js @@ -1,5 +1,5 @@ import { useState, useEffect } from 'react'; -import { ButtonDropdown, DropdownToggle, Container, ListGroup, ListGroupItem, DropdownItem, DropdownMenu, ButtonGroup } from 'reactstrap'; +import { ButtonDropdown, DropdownToggle, Container, ListGroup, ListGroupItem, DropdownItem, DropdownMenu } from 'reactstrap'; import { getStatementsBySubjects } from 'services/backend/statements'; import { getResourcesByClass } from 'services/backend/resources'; import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; @@ -8,6 +8,7 @@ import PaperCardDynamic from 'components/PaperCard/PaperCardDynamic'; import { CLASSES } from 'constants/graphSettings'; import { useSelector } from 'react-redux'; import HeaderSearchButton from 'components/HeaderSearchButton/HeaderSearchButton'; +import TitleBar from 'components/TitleBar/TitleBar'; const Papers = () => { const pageSize = 25; @@ -98,31 +99,35 @@ const Papers = () => { return ( <> - -
-

View all papers

-
+ {totalElements === 0 && isNextPageLoading ? : totalElements} papers
-
- - {!!user && user.isCurationAllowed && ( - - - {verified === true && 'Verified'} - {verified === false && 'Unverified'} - {verified === null && 'All'} - - - changeFilter(null)}>All - changeFilter(true)}>Verified - changeFilter(false)}>Unverified - - - )} - {verified === null && } - -
+ } + buttonGroup={ + <> + {!!user && user.isCurationAllowed && ( + + + {verified === true && 'Verified'} + {verified === false && 'Unverified'} + {verified === null && 'All'} + + + changeFilter(null)}>All + changeFilter(true)}>Verified + changeFilter(false)}>Unverified + + + )} + {verified === null && } + + } + > + View all papers + + {paperResources.length > 0 && diff --git a/src/pages/Properties/AddProperty.js b/src/pages/Properties/AddProperty.js index 5e36408b9..68fbac650 100644 --- a/src/pages/Properties/AddProperty.js +++ b/src/pages/Properties/AddProperty.js @@ -5,6 +5,7 @@ import { useHistory } from 'react-router-dom'; import { toast } from 'react-toastify'; import { reverse } from 'named-urls'; import ROUTES from 'constants/routes'; +import TitleBar from 'components/TitleBar/TitleBar'; const AddProperty = () => { const [label, setLabel] = useState(''); @@ -37,11 +38,9 @@ const AddProperty = () => { return ( <> - -

Create property

-
+ Create property -
+
{ const pageSize = 25; @@ -52,20 +53,29 @@ const Properties = () => { return ( <> - -
-

View all properties

-
+ {totalElements === 0 && isNextPageLoading ? : totalElements} properties
-
- - - Create property - - - -
+ } + buttonGroup={ + <> + + Create property + + + + } + > + View all properties + diff --git a/src/pages/Properties/Property.js b/src/pages/Properties/Property.js index 33970102c..e7db83a83 100644 --- a/src/pages/Properties/Property.js +++ b/src/pages/Properties/Property.js @@ -12,6 +12,7 @@ import PropTypes from 'prop-types'; import { PREDICATE_TYPE_ID } from 'constants/misc'; import { useLocation } from 'react-router-dom'; import PropertyStatements from 'components/PropertyStatements/PropertyStatements'; +import TitleBar from 'components/TitleBar/TitleBar'; function Property(props) { const location = useLocation(); @@ -46,24 +47,27 @@ function Property(props) { {!isLoading && error && <>{error.statusCode === 404 ? : }} {!isLoading && !error && ( <> - -

Property view

- {!editMode ? ( - setEditMode(v => !v)} - > - Edit - - ) : ( - - )} -
+ setEditMode(v => !v)} + > + Edit + + ) : ( + + ) + } + > + Property view + {editMode && ( diff --git a/src/pages/ResearchFields/ResearchFields.js b/src/pages/ResearchFields/ResearchFields.js index fba02fcbb..92a6eecdd 100644 --- a/src/pages/ResearchFields/ResearchFields.js +++ b/src/pages/ResearchFields/ResearchFields.js @@ -11,6 +11,7 @@ import { useCallback, useEffect, useState } from 'react'; import { Link, NavLink } from 'react-router-dom'; import { Button, ButtonDropdown, Col, Container, DropdownItem, DropdownMenu, DropdownToggle, Row } from 'reactstrap'; import { reverseWithSlug } from 'utils'; +import TitleBar from 'components/TitleBar/TitleBar'; const ResearchFields = () => { const [menuOpen, setMenuOpen] = useState(false); @@ -46,20 +47,22 @@ const ResearchFields = () => { return ( <> - -

Research fields taxonomy

- - setMenuOpen(v => !v)} nav inNavbar> - - - - - - View resource - - - -
+ setMenuOpen(v => !v)} nav inNavbar> + + + + + + View resource + + + + } + > + Research fields taxonomy +
diff --git a/src/pages/Resources/AddResource.js b/src/pages/Resources/AddResource.js index 573cfb7d3..edf7a321f 100644 --- a/src/pages/Resources/AddResource.js +++ b/src/pages/Resources/AddResource.js @@ -15,6 +15,7 @@ import ROUTES from 'constants/routes'; import { useSelector } from 'react-redux'; import { PREDICATES, ENTITIES, CLASSES } from 'constants/graphSettings'; import { getArrayParamFromQueryString } from 'utils'; +import TitleBar from 'components/TitleBar/TitleBar'; const AddResource = () => { const isDOI = new RegExp(REGEX.DOI); @@ -115,11 +116,9 @@ const AddResource = () => { return ( <> - -

Create resource

-
+ Create resource -
+
{error.statusCode === 404 ? : }} {!isLoading && !error && ( <> - -

Resource view

- - - Create resource - - {dedicatedLink && ( - - )} - {canEdit ? ( - !editMode ? ( - Create resource + + {dedicatedLink && ( + - ) - ) : ( - c.id === CLASSES.RESEARCH_FIELD) ? true : false} - content={ - env('PWC_USER_ID') === createdBy ? ( - 'This resource cannot be edited because it is from an external source. Our provenance feature is in active development.' - ) : classes.find(c => c.id === CLASSES.RESEARCH_FIELD) ? ( - <> - This resource can not be edited. Please visit the{' '} - - ORKG help center - {' '} - if you have any suggestions to improve the research fields taxonomy. - - ) : ( - 'This resource can not be edited because it has a published DOI.' - ) - } - > - - Edit - - - )} - -
+ )} + {canEdit ? ( + !editMode ? ( + (env('PWC_USER_ID') === createdBy ? setIsOpenPWCModal(true) : setEditMode(v => !v))} + > + Edit + + ) : ( + + ) + ) : ( + c.id === CLASSES.RESEARCH_FIELD) ? true : false} + content={ + env('PWC_USER_ID') === createdBy ? ( + 'This resource cannot be edited because it is from an external source. Our provenance feature is in active development.' + ) : classes.find(c => c.id === CLASSES.RESEARCH_FIELD) ? ( + <> + This resource can not be edited. Please visit the{' '} + + ORKG help center + {' '} + if you have any suggestions to improve the research fields taxonomy. + + ) : ( + 'This resource can not be edited because it has a published DOI.' + ) + } + > + + Edit + + + )} + + } + > + Resource view + {editMode && hasDOI && ( This resource should not be edited because it has a published DOI, please make sure that you know what are you doing! diff --git a/src/pages/Resources/Resources.js b/src/pages/Resources/Resources.js index 0b17642d5..6471f1ca4 100644 --- a/src/pages/Resources/Resources.js +++ b/src/pages/Resources/Resources.js @@ -10,6 +10,7 @@ import { RESOURCE_TYPE_ID } from 'constants/misc'; import ROUTES from 'constants/routes'; import { reverse } from 'named-urls'; import HeaderSearchButton from 'components/HeaderSearchButton/HeaderSearchButton'; +import TitleBar from 'components/TitleBar/TitleBar'; const Resources = () => { const pageSize = 25; @@ -52,26 +53,29 @@ const Resources = () => { return ( <> - -
-

View all resources

-
+ {totalElements === 0 && isNextPageLoading ? : totalElements} resources
-
- - - Create resource - - - -
+ } + buttonGroup={ + <> + + Create resource + + + + } + > + View all resources + diff --git a/src/pages/Search.js b/src/pages/Search.js index 6ad453eea..351ef93d0 100644 --- a/src/pages/Search.js +++ b/src/pages/Search.js @@ -18,6 +18,7 @@ import { toast } from 'react-toastify'; import { CLASSES } from 'constants/graphSettings'; import { getPaperByDOI } from 'services/backend/misc'; import REGEX from 'constants/regex'; +import TitleBar from 'components/TitleBar/TitleBar'; class Search extends Component { constructor(props) { @@ -274,10 +275,8 @@ class Search extends Component { const allFilters = unionBy(this.defaultsFilters, this.state.selectedFilters, 'id'); return (
+ Search results -

Search results

-
-
diff --git a/src/pages/SmartReview/SmartReview.js b/src/pages/SmartReview/SmartReview.js index bad008f90..05c7c0e91 100644 --- a/src/pages/SmartReview/SmartReview.js +++ b/src/pages/SmartReview/SmartReview.js @@ -42,6 +42,7 @@ import ReferencesSection from 'components/SmartReview/References/ReferencesSecti import ShouldPublishModal from 'components/SmartReview/ShouldPublishModal'; import { usePrevious } from 'react-use'; import LoadingOverlay from 'components/SmartReview/LoadingOverlay'; +import TitleBar from 'components/TitleBar/TitleBar'; const GlobalStyle = createGlobalStyle` // ensure printing only prints the contents and no other elements @@ -129,134 +130,132 @@ const SmartReview = () => {
{researchField && } - -
-
-

SmartReview

- {publicationDate && ( - <> - - - - Published on - Version {versionNumber} - - - - )} -
-
+ + + + Published on - Version {versionNumber} + + + + ) + } + buttonGroup={ + <> {isEditing && ( - <> +
{isLoadingInline ? ( - + ) : ( - + )} +
+ )} + {!isEditing && ( + <> + )} - - {!isEditing && ( - <> - - - )} - {!isEditing ? ( - <> - + {!isEditing ? ( + <> + - - Edit - - - ) : ( - <> - - - - - )} - - - - - - - View resource - - - - -
-
-
+ + Edit + + + ) : ( + <> + + + + + )} + + + + + + + View resource + + + + + } + > + SmartReview + {!isLoading && isEditing && ( -
+
diff --git a/src/pages/SmartReview/SmartReviewDiff.js b/src/pages/SmartReview/SmartReviewDiff.js index b84618901..474737562 100644 --- a/src/pages/SmartReview/SmartReviewDiff.js +++ b/src/pages/SmartReview/SmartReviewDiff.js @@ -13,6 +13,7 @@ import { useHistory, useParams } from 'react-router-dom'; import { useLocation } from 'react-use'; import { Alert, Button, ButtonGroup, Container } from 'reactstrap'; import queryString from 'query-string'; +import TitleBar from 'components/TitleBar/TitleBar'; const SmartReviewDiff = () => { const { oldId, newId } = useParams(); @@ -70,18 +71,15 @@ const SmartReviewDiff = () => { return ( <> - <Container> - <div className="d-flex align-items-center"> - <h1 className="h4 mt-4 mb-4 flex-grow-1">Compare SmartReview versions</h1> - <div style={{ marginLeft: 'auto' }} className="flex-shrink-0 mt-4"> - <ButtonGroup className="float-right mb-4 ml-1"> - <Button size="sm" color="secondary" onClick={() => setFullWidth(v => !v)}> - <Icon icon={faArrowsAltH} className="mr-1" /> Full width - </Button> - </ButtonGroup> - </div> - </div> - </Container> + <TitleBar + buttonGroup={ + <Button size="sm" color="secondary" onClick={() => setFullWidth(v => !v)}> + <Icon icon={faArrowsAltH} className="mr-1" /> Full width + </Button> + } + > + Compare SmartReview versions + </TitleBar> <ContainerAnimated style={containerStyle} className="box rounded p-0 overflow-hidden"> {switchedVersions && ( <div className="m-3"> diff --git a/src/pages/SmartReview/SmartReviewNew.js b/src/pages/SmartReview/SmartReviewNew.js index c09b4670d..8c8afe2a5 100644 --- a/src/pages/SmartReview/SmartReviewNew.js +++ b/src/pages/SmartReview/SmartReviewNew.js @@ -2,6 +2,7 @@ import { faQuestionCircle, faSpinner } from '@fortawesome/free-solid-svg-icons'; import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; import Tippy from '@tippyjs/react'; import useSave from 'components/SmartReview/hooks/useSave'; +import TitleBar from 'components/TitleBar/TitleBar'; import ROUTES from 'constants/routes'; import { reverse } from 'named-urls'; import React, { useEffect, useState } from 'react'; @@ -29,11 +30,7 @@ const SmartReviewNew = () => { return ( <> - <Container> - <div className="d-flex align-items-center"> - <h1 className="h4 mt-4 mb-4 flex-grow-1">Create SmartReview</h1> - </div> - </Container> + <TitleBar>Create SmartReview</TitleBar> <Container className="box rounded pt-4 pb-4 pl-5 pr-5"> <p> SmartReviews are dynamic, community maintained scholarly articles and are especially suitable for survey papers. Before creating diff --git a/src/pages/Stats.js b/src/pages/Stats.js index 3c0a459ce..6b6b30ba9 100644 --- a/src/pages/Stats.js +++ b/src/pages/Stats.js @@ -7,6 +7,7 @@ import { toast } from 'react-toastify'; import { getStats } from 'services/backend/stats'; import ROUTES from 'constants/routes'; import { reverse } from 'named-urls'; +import TitleBar from 'components/TitleBar/TitleBar'; const Stats = () => { const [isLoading, setIsLoading] = useState(false); @@ -28,9 +29,7 @@ const Stats = () => { return ( <div> - <Container> - <h1 className="h4 mt-4 mb-4">General statistics</h1> - </Container> + <TitleBar>General statistics</TitleBar> <Container> <Row> diff --git a/src/pages/Templates/Template.js b/src/pages/Templates/Template.js index 36aa0579f..21844fce3 100644 --- a/src/pages/Templates/Template.js +++ b/src/pages/Templates/Template.js @@ -39,6 +39,7 @@ import ROUTES from 'constants/routes.js'; import PropTypes from 'prop-types'; import { reverse } from 'named-urls'; import { NavLink as RouterNavLink } from 'react-router-dom'; +import TitleBar from 'components/TitleBar/TitleBar'; const TabPaneStyled = styled(TabPane)` border: 1px solid #ced4da; @@ -118,11 +119,10 @@ class Template extends Component { return ( <> - <Container className="d-flex align-items-center"> - <div className="mt-4 mb-4 d-flex flex-grow-1"> - <h1 className="h4 m-0">{!this.props.match.params.id ? 'Create new template' : 'Template'}</h1> + <TitleBar + titleAddition={ <Tippy content="Open help popup"> - <span className="ml-3"> + <span> <Button color="link" outline @@ -135,49 +135,53 @@ class Template extends Component { </Button> </span> </Tippy> - </div> - <ButtonGroup className="flex-shrink-0"> - {!this.props.editMode && !this.props.isSaving ? ( - <RequireAuthentication component={Button} color="secondary" size="sm" onClick={() => this.props.setEditMode(true)}> - <Icon icon={faPen} /> Edit - </RequireAuthentication> - ) : ( - <Button - disabled={this.props.isSaving} - style={{ marginLeft: 1 }} - color="secondary-darker" - size="sm" - onClick={() => this.props.saveTemplate(this.props.template)} - > - {this.props.isSaving && <Icon icon={faSpinner} spin />} - {this.props.editMode && <Icon icon={faSave} />} - {!this.props.isSaving ? ' Save' : ' Saving'} - </Button> - )} - {this.props.match.params.id && ( - <ButtonDropdown - className="flex-shrink-0" - isOpen={this.state.menuOpen} - toggle={() => - this.setState(prevState => ({ - menuOpen: !prevState.menuOpen - })) - } - nav - inNavbar - > - <DropdownToggle size="sm" color="secondary" className="px-3 rounded-right" style={{ marginLeft: 2 }}> - <Icon icon={faEllipsisV} /> - </DropdownToggle> - <DropdownMenu right> - <DropdownItem tag={RouterNavLink} exact to={reverse(ROUTES.RESOURCE, { id: this.props.match.params.id })}> - View resource - </DropdownItem> - </DropdownMenu> - </ButtonDropdown> - )} - </ButtonGroup> - </Container> + } + buttonGroup={ + <> + {!this.props.editMode && !this.props.isSaving ? ( + <RequireAuthentication component={Button} color="secondary" size="sm" onClick={() => this.props.setEditMode(true)}> + <Icon icon={faPen} /> Edit + </RequireAuthentication> + ) : ( + <Button + disabled={this.props.isSaving} + style={{ marginLeft: 1 }} + color="secondary-darker" + size="sm" + onClick={() => this.props.saveTemplate(this.props.template)} + > + {this.props.isSaving && <Icon icon={faSpinner} spin />} + {this.props.editMode && <Icon icon={faSave} />} + {!this.props.isSaving ? ' Save' : ' Saving'} + </Button> + )} + {this.props.match.params.id && ( + <ButtonDropdown + className="flex-shrink-0" + isOpen={this.state.menuOpen} + toggle={() => + this.setState(prevState => ({ + menuOpen: !prevState.menuOpen + })) + } + nav + inNavbar + > + <DropdownToggle size="sm" color="secondary" className="px-3 rounded-right" style={{ marginLeft: 2 }}> + <Icon icon={faEllipsisV} /> + </DropdownToggle> + <DropdownMenu right> + <DropdownItem tag={RouterNavLink} exact to={reverse(ROUTES.RESOURCE, { id: this.props.match.params.id })}> + View resource + </DropdownItem> + </DropdownMenu> + </ButtonDropdown> + )} + </> + } + > + {!this.props.match.params.id ? 'Create new template' : 'Template'} + </TitleBar> <StyledContainer className="p-0"> {this.state.showHeaderBar && <TemplateEditorHeaderBar id={this.props.match.params.id} />} {(this.props.editMode || this.props.isSaving) && ( diff --git a/src/pages/Templates/Templates.js b/src/pages/Templates/Templates.js index 666474aea..6c5584ff5 100644 --- a/src/pages/Templates/Templates.js +++ b/src/pages/Templates/Templates.js @@ -12,6 +12,7 @@ import { reverse } from 'named-urls'; import { debounce } from 'lodash'; import ROUTES from 'constants/routes'; import { CLASSES, PREDICATES, ENTITIES } from 'constants/graphSettings'; +import TitleBar from 'components/TitleBar/TitleBar'; const Templates = () => { const pageSize = 25; @@ -154,24 +155,27 @@ const Templates = () => { return ( <> - <Container className="d-flex align-items-center"> - <div className="d-flex flex-grow-1 mt-4 mb-4"> - <h1 className="h4">View all templates</h1> - <div className="text-muted ml-3 mt-1"> + <TitleBar + titleAddition={ + <div className="text-muted mt-1"> {totalElements === 0 && isNextPageLoading ? <Icon icon={faSpinner} spin /> : totalElements}{' '} {isFilterApplied() ? 'template found by applying the filter' : 'template'} </div> - </div> - <RequireAuthentication - component={Link} - color="secondary" - size="sm" - className="btn btn-secondary btn-sm flex-shrink-0" - to={reverse(ROUTES.TEMPLATE)} - > - <Icon icon={faPlus} /> Create template - </RequireAuthentication> - </Container> + } + buttonGroup={ + <RequireAuthentication + component={Link} + color="secondary" + size="sm" + className="btn btn-secondary btn-sm flex-shrink-0" + to={reverse(ROUTES.TEMPLATE)} + > + <Icon icon={faPlus} /> Create template + </RequireAuthentication> + } + > + View all templates + </TitleBar> <Container className="box rounded pt-4 pb-2 pl-5 pr-5 clearfix"> <Alert color="info" fade={false}> Templates allows to specify the structure of content types, and they can be used when describing research contributions. Further diff --git a/src/pages/Unauthorized.js b/src/pages/Unauthorized.js index c3f20f878..9bd2e100a 100644 --- a/src/pages/Unauthorized.js +++ b/src/pages/Unauthorized.js @@ -6,6 +6,7 @@ import { FontAwesomeIcon as Icon } from '@fortawesome/react-fontawesome'; import { faLock } from '@fortawesome/free-solid-svg-icons'; import { openAuthDialog } from 'actions/auth'; import { useDispatch, useSelector } from 'react-redux'; +import TitleBar from 'components/TitleBar/TitleBar'; /** * Unauthorized can mean both unauthenticated and unauthorized. So when a user is not signed in, @@ -29,9 +30,7 @@ const Unauthorized = () => { return ( <> - <Container className="p-0"> - <h1 className="h4 mt-4 mb-4">Authentication required</h1> - </Container> + <TitleBar>Authentication required</TitleBar> <Container className="box rounded pt-4 pb-4 pl-5 pr-5"> <div className="container"> <div className="row justify-content-center"> diff --git a/src/pages/UserSettings.js b/src/pages/UserSettings.js index 7d66da24a..c5ee3815f 100644 --- a/src/pages/UserSettings.js +++ b/src/pages/UserSettings.js @@ -4,6 +4,7 @@ import styled from 'styled-components'; import classnames from 'classnames'; import GeneralSettings from '../components/UserSettings/GeneralSettings'; import Password from '../components/UserSettings/Password'; +import TitleBar from 'components/TitleBar/TitleBar'; export const StyledSettingsMenu = styled.div` list-style: none; @@ -52,9 +53,7 @@ class UserSettings extends Component { render = () => ( <> - <Container className="p-0"> - <h1 className="h4 mt-4 mb-4">Account Settings</h1> - </Container> + <TitleBar>Account settings</TitleBar> <Container className="p-0"> <Row> <div className="col-3 justify-content-center"> diff --git a/src/pages/VenuePage.js b/src/pages/VenuePage.js index 3ae5bf5ec..93e96e84d 100644 --- a/src/pages/VenuePage.js +++ b/src/pages/VenuePage.js @@ -14,6 +14,7 @@ import PropTypes from 'prop-types'; import { PREDICATES } from 'constants/graphSettings'; import { NavLink } from 'react-router-dom'; import { reverse } from 'named-urls'; +import TitleBar from 'components/TitleBar/TitleBar'; class VenuePage extends Component { constructor(props) { @@ -119,29 +120,31 @@ class VenuePage extends Component { )} {!this.state.loading && ( <div> - <Container className="d-flex align-items-center"> - <h1 className="h4 mt-4 mb-4 flex-grow-1">Venue</h1> - - <ButtonDropdown - isOpen={this.state.menuOpen} - toggle={() => - this.setState(prevState => ({ - menuOpen: !prevState.menuOpen - })) - } - nav - inNavbar - > - <DropdownToggle size="sm" color="secondary" className="px-3 rounded-right" style={{ marginLeft: 2 }}> - <Icon icon={faEllipsisV} /> - </DropdownToggle> - <DropdownMenu right> - <DropdownItem tag={NavLink} exact to={reverse(ROUTES.RESOURCE, { id: this.props.match.params.venueId })}> - View resource - </DropdownItem> - </DropdownMenu> - </ButtonDropdown> - </Container> + <TitleBar + buttonGroup={ + <ButtonDropdown + isOpen={this.state.menuOpen} + toggle={() => + this.setState(prevState => ({ + menuOpen: !prevState.menuOpen + })) + } + nav + inNavbar + > + <DropdownToggle size="sm" color="secondary" className="px-3 rounded-right" style={{ marginLeft: 2 }}> + <Icon icon={faEllipsisV} /> + </DropdownToggle> + <DropdownMenu right> + <DropdownItem tag={NavLink} exact to={reverse(ROUTES.RESOURCE, { id: this.props.match.params.venueId })}> + View resource + </DropdownItem> + </DropdownMenu> + </ButtonDropdown> + } + > + Venue + </TitleBar> <Container className="p-0"> <Card> <CardHeader> diff --git a/src/pages/ViewPaper.js b/src/pages/ViewPaper.js index d7cb68f69..a4a76ed42 100644 --- a/src/pages/ViewPaper.js +++ b/src/pages/ViewPaper.js @@ -16,6 +16,7 @@ import env from '@beam-australia/react-env'; import PaperHeaderBar from 'components/ViewPaper/PaperHeaderBar/PaperHeaderBar'; import PaperMenuBar from 'components/ViewPaper/PaperHeaderBar/PaperMenuBar'; import styled from 'styled-components'; +import TitleBar from 'components/TitleBar/TitleBar'; export const EditModeHeader = styled(Container)` background-color: #80869b !important; @@ -89,17 +90,20 @@ const ViewPaper = () => { <Breadcrumbs researchFieldId={viewPaper.researchField ? viewPaper.researchField.id : null} /> <VisibilitySensor onChange={handleShowHeaderBar}> - <Container className="d-flex align-items-center"> - <h1 className="h4 mt-4 mb-4 flex-grow-1">View paper</h1> - <PaperMenuBar - disableEdit={env('PWC_USER_ID') === viewPaper.paperResource.created_by} - editMode={editMode} - paperLink={paperLink} - toggle={toggle} - id={resourceId} - label={viewPaper.paperResource?.label} - /> - </Container> + <TitleBar + buttonGroup={ + <PaperMenuBar + disableEdit={env('PWC_USER_ID') === viewPaper.paperResource.created_by} + editMode={editMode} + paperLink={paperLink} + toggle={toggle} + id={resourceId} + label={viewPaper.paperResource?.label} + /> + } + > + View paper + </TitleBar> </VisibilitySensor> {editMode && ( diff --git a/src/pages/Visualizations/Visualizations.js b/src/pages/Visualizations/Visualizations.js index 04a8d1afa..3317f6ce2 100644 --- a/src/pages/Visualizations/Visualizations.js +++ b/src/pages/Visualizations/Visualizations.js @@ -9,6 +9,7 @@ import { find } from 'lodash'; import VisualizationCard from 'components/VisualizationCard/VisualizationCard'; import { CLASSES, PREDICATES } from 'constants/graphSettings'; import HeaderSearchButton from 'components/HeaderSearchButton/HeaderSearchButton'; +import TitleBar from 'components/TitleBar/TitleBar'; const Visualizations = () => { const pageSize = 10; @@ -73,17 +74,16 @@ const Visualizations = () => { return ( <> - <Container className="d-flex align-items-center"> - <div className="d-flex flex-grow-1 mt-4 mb-4"> - <h1 className="h4">View all published visualizations</h1> - <div className="text-muted ml-3 mt-1"> + <TitleBar + buttonGroup={<HeaderSearchButton placeholder="Search visualizations..." type={CLASSES.VISUALIZATION} />} + titleAddition={ + <div className="text-muted mt-1"> {totalElements === 0 && isNextPageLoading ? <Icon icon={faSpinner} spin /> : totalElements} visualizations </div> - </div> - <ButtonGroup> - <HeaderSearchButton placeholder="Search visualizations..." type={CLASSES.VISUALIZATION} /> - </ButtonGroup> - </Container> + } + > + View all published visualizations + </TitleBar> <Container className="p-0"> <ListGroup flush className="box rounded" style={{ overflow: 'hidden' }}>