Skip to content

Commit

Permalink
landing page: add blr related works section
Browse files Browse the repository at this point in the history
  • Loading branch information
jennur committed Dec 8, 2023
1 parent e9f2724 commit 22c5a15
Show file tree
Hide file tree
Showing 12 changed files with 695 additions and 1 deletion.
5 changes: 5 additions & 0 deletions assets/less/zenodo-rdm/globals/site.overrides
Original file line number Diff line number Diff line change
Expand Up @@ -138,4 +138,9 @@ a.inverted {
.ui.medium.header {
font-size: 1.45rem;
}
}

.image.thumbnail-image {
height: 150px;
object-fit: cover;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
// This file is part of Zenodo.
// Copyright (C) 2023 CERN.
//
// Zenodo is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// Zenodo is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Zenodo; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
// MA 02111-1307, USA.
//
// In applying this license, CERN does not
// waive the privileges and immunities granted to it by virtue of its status
// as an Intergovernmental Organization or submit itself to any jurisdiction.

import React from 'react';
import {
ReactSearchKit,
InvenioSearchApi,
SearchBar,
ResultsLoader,
ResultsMultiLayout,
Error,
EmptyResults,
Pagination,
BucketAggregation,
LayoutSwitcher
} from 'react-searchkit';
import { OverridableContext } from "react-overridable";
import { apiConfig } from "./api/config";
import { Grid, Segment, Container, Header } from 'semantic-ui-react';
import { ResultsGridLayout, ResultsListLayout } from "./components/ResultsLayout";
import { RecordGridItem, RecordListItem } from "./components/RecordItem";
import { FilterContainer, Filter, FilterValues } from "./components/Filter";
import { BlrSearchBar } from './components/BlrSearchBar';
import { LayoutSwitchButtons } from './components/LayoutSwitchButtons';
import { NoResults } from "./components/NoResults";

const blrSearchAppID = "blrSearch";

const overriddenComponents = {
[`${blrSearchAppID}.SearchBar.element`]: BlrSearchBar,
[`${blrSearchAppID}.ResultsGrid.container`]: ResultsGridLayout,
[`${blrSearchAppID}.ResultsGrid.item`]: RecordGridItem,
[`${blrSearchAppID}.ResultsList.container`]: ResultsListLayout,
[`${blrSearchAppID}.ResultsList.item`]: RecordListItem,
[`${blrSearchAppID}.BucketAggregation.element`]: FilterContainer,
[`${blrSearchAppID}.BucketAggregationContainer.element`]: Filter,
[`${blrSearchAppID}.BucketAggregationValues.element`]: FilterValues,
[`${blrSearchAppID}.LayoutSwitcher.element`]: LayoutSwitchButtons,
[`${blrSearchAppID}.EmptyResults.element`]: NoResults,
}

export const BlrSearch = ({ endpoint, recordDOI, resourceType }) => {

const relationType = (resourceType) => (
(resourceType === "Journal article" || resourceType === "Book chapter") ? "ispartof" : "haspart"
);

const queryString = (relationType, identifier) => (
`metadata.related_identifiers.relation_type.id:${relationType} AND metadata.related_identifiers.identifier:"${identifier}"`
);

const searchApi = new InvenioSearchApi(
//apiConfig(`${endpoint}?q=${queryString(relationType(resourceType), recordDOI)}`)
apiConfig(endpoint)
);

const initialState = {
queryString: queryString(relationType(resourceType), recordDOI),
sortBy: "bestmatch",
sortOrder: "asc",
page: 1,
size: 4,
layout: "list",
};

return (
<>
<Header as="h2">Related content</Header>
<OverridableContext.Provider value={overriddenComponents}>
<ReactSearchKit
appName={blrSearchAppID}
searchApi={searchApi}
urlHandlerApi={{ enabled: false }}
initialQueryState={initialState}
>
<>
<Grid>
<Grid.Column mobile="16" tablet="16" computer="7">
<BucketAggregation
agg={{ field: "resource_type", aggName: "resource_type" }}
/>
</Grid.Column>
<Grid.Column mobile="16" tablet="16" computer="9" textAlign="right" floated="right">
<div className="auto-column-grid no-wrap">
<SearchBar placeholder="Search for content..." />
<LayoutSwitcher />
</div>
</Grid.Column>
</Grid>

<Segment>
<ResultsLoader>
<ResultsMultiLayout />
<Error />
<EmptyResults />
</ResultsLoader>
<Container align="center" className="rel-pt-1">
<Pagination options={{ size: "mini", showEllipsis: true }} />
</Container>
</Segment>
</>
</ReactSearchKit>
</OverridableContext.Provider>
</>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// This file is part of Zenodo.
// Copyright (C) 2023 CERN.
//
// Zenodo is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// Zenodo is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Zenodo; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
// MA 02111-1307, USA.
//
// In applying this license, CERN does not
// waive the privileges and immunities granted to it by virtue of its status
// as an Intergovernmental Organization or submit itself to any jurisdiction.

export const apiConfig = (endpoint) => ({
axios: {
url: endpoint,
timeout: 5000,
headers: {
Accept: "application/vnd.inveniordm.v1+json",
},
},
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// This file is part of Zenodo.
// Copyright (C) 2023 CERN.
//
// Zenodo is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// Zenodo is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Zenodo; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
// MA 02111-1307, USA.
//
// In applying this license, CERN does not
// waive the privileges and immunities granted to it by virtue of its status
// as an Intergovernmental Organization or submit itself to any jurisdiction.

import React from "react";
import { Input, Icon } from "semantic-ui-react";

export const BlrSearchBar = ({
queryString,
onBtnSearchClick,
onInputChange,
onKeyPress,
placeholder,
actionProps,
uiProps,
}) => {

return (
<Input
fluid
action={{
content: (
<Icon name="search" className="m-0" />
),
onClick: () => {
onBtnSearchClick()
},
className: "p-10",
...actionProps,
}}
{...uiProps}
placeholder={placeholder || "Type something"}
onChange={(_, { value }) => {
onInputChange(value);
}}
value={queryString}
onKeyPress={onKeyPress}
/>
)
}

BlrSearchBar.propTypes = {
actionProps: PropTypes.object,
onBtnSearchClick: PropTypes.func,
onInputChange: PropTypes.func,
onKeyPress: PropTypes.func,
placeholder: PropTypes.string,
queryString: PropTypes.string,
uiProps: PropTypes.object,
};

BlrSearchBar.defaultProps = {
actionProps: null,
onBtnSearchClick: null,
onInputChange: null,
onKeyPress: null,
placeholder: "",
queryString: "",
uiProps: null,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// This file is part of Zenodo.
// Copyright (C) 2023 CERN.
//
// Zenodo is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// Zenodo is distributed in the hope that it will be
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Zenodo; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
// MA 02111-1307, USA.
//
// In applying this license, CERN does not
// waive the privileges and immunities granted to it by virtue of its status
// as an Intergovernmental Organization or submit itself to any jurisdiction.

import React from "react";
import { PropTypes } from "prop-types";
import { Dropdown, Label, Button, Icon } from "semantic-ui-react";

export const FilterContainer = ({agg, containerCmp, updateQueryFilters}) => {
const clearFacets = () => {
if (containerCmp.props.selectedFilters.length) {
updateQueryFilters([agg.aggName, ""], containerCmp.props.selectedFilters);
}
};

return (
<div className="flex align-items-center">
<div>
{containerCmp}
</div>
<div>
<Button onClick={clearFacets} content="Reset filters" />
</div>
</div>
);
}

FilterContainer.propTypes = {
agg: PropTypes.object.isRequired,
updateQueryFilters: PropTypes.func.isRequired,
containerCmp: PropTypes.node.isRequired,
};


export const Filter = ({ valuesCmp }) => {
return (
<Dropdown text="Filter by type" button>
<Dropdown.Menu>
{valuesCmp}
</Dropdown.Menu>
</Dropdown>
);
};

Filter.propTypes = {
valuesCmp: PropTypes.array.isRequired,
};


export const FilterValues = ({
bucket,
isSelected,
onFilterClicked,
label,
}) => {
return (
<Dropdown.Item
key={bucket.key}
id={`${bucket.key}-agg-value`}
selected={isSelected}
onClick={() => onFilterClicked(bucket.key)}
value={bucket.key}
className="flex align-items-center justify-space-between"
>
{isSelected &&
<Icon name="check" className="positive" />
}
<span>{label}</span>
<Label size="small" className="rel-ml-1 mr-0">
{bucket.doc_count.toLocaleString("en-US")}
</Label>
</Dropdown.Item>
);
};

FilterValues.propTypes = {
bucket: PropTypes.object.isRequired,
isSelected: PropTypes.bool.isRequired,
onFilterClicked: PropTypes.func.isRequired,
label: PropTypes.string.isRequired,
};
Loading

0 comments on commit 22c5a15

Please sign in to comment.