diff --git a/geonode_mapstore_client/client/js/components/home/CardGrid.jsx b/geonode_mapstore_client/client/js/components/home/CardGrid.jsx
index 029674d00a..6eb41c86c1 100644
--- a/geonode_mapstore_client/client/js/components/home/CardGrid.jsx
+++ b/geonode_mapstore_client/client/js/components/home/CardGrid.jsx
@@ -12,6 +12,7 @@ import HTML from '@mapstore/framework/components/I18N/HTML';
import FaIcon from '@js/components/home/FaIcon';
import ResourceCard from '@js/components/home/ResourceCard';
import { withResizeDetector } from 'react-resize-detector';
+import useLocalStorage from '@js/hooks/useLocalStorage';
const Cards = withResizeDetector(({
resources,
@@ -29,8 +30,46 @@ const Cards = withResizeDetector(({
const cardWidth = width >= size + margin * 2
? Math.floor((width - margin * count) / count)
: '100%';
+
const ulPadding = Math.floor(margin / 2);
const isSingleCard = count === 0 || count === 1;
+ const [cardLayoutStyle] = useLocalStorage('layoutCardsStyle');
+
+ const gridLayoutSpace = (idx) => {
+
+ const gridSpace = isSingleCard
+ ? {
+ width: width - margin,
+ margin: ulPadding
+ }
+ : {
+ width: cardWidth,
+ marginRight: (idx + 1) % count === 0 ? 0 : margin,
+ marginTop: margin
+ };
+
+ return gridSpace;
+ };
+
+ const listLayoutSpace = {
+ width: '100%',
+ margin: ulPadding / 2
+ };
+
+
+ const layoutSpace = (cardLayoutStyle, idx) => {
+ let cardContainerSpace;
+ switch (cardLayoutStyle) {
+ case 'list':
+ cardContainerSpace = listLayoutSpace;
+ break;
+ default:
+ cardContainerSpace = gridLayoutSpace(idx);
+ }
+ return cardContainerSpace;
+ };
+
+
return (
);
diff --git a/geonode_mapstore_client/client/js/components/home/FiltersMenu.jsx b/geonode_mapstore_client/client/js/components/home/FiltersMenu.jsx
index 510577c1a7..dc1fa2e0e0 100644
--- a/geonode_mapstore_client/client/js/components/home/FiltersMenu.jsx
+++ b/geonode_mapstore_client/client/js/components/home/FiltersMenu.jsx
@@ -7,9 +7,11 @@
*/
import React, { forwardRef } from 'react';
-import { Dropdown } from 'react-bootstrap-v1';
+import { Dropdown, Button } from 'react-bootstrap-v1';
import ReactResizeDetector from 'react-resize-detector';
import Message from '@mapstore/framework/components/I18N/Message';
+import FaIcon from '@js/components/home/FaIcon';
+import useLocalStorage from '@js/hooks/useLocalStorage';
const FiltersMenu = forwardRef(({
formatHref,
@@ -18,11 +20,12 @@ const FiltersMenu = forwardRef(({
filters,
style,
onClick,
+ layoutSwitcher,
defaultLabelId
}, ref) => {
const selectedSort = orderOptions.find(({ value }) => order === value);
-
+ const [cardLayoutStyle] = useLocalStorage('layoutCardsStyle');
return (
)}
+
+
+
+
+
{orderOptions.length > 0 &&
{
const res = data;
const types = getTypesInfo();
const { icon } = types[res.doc_type] || types[res.resource_type] || {};
+
return (
-
-
-
- {icon &&
+
+
+
+
+ {icon &&
<>
>}
-
- {res.title}
-
-
-
- {res.raw_abstract ? res.raw_abstract : '...'}
-
-
- : {getUserName(res.owner)}
-
- {links && links.length > 0 &&
-
+ {res.title}
+
+
+
+ {res.raw_abstract ? res.raw_abstract : '...'}
+
+
+ : {getUserName(res.owner)}
+
+ {links && links.length > 0 &&
-
-
-
- {links.map(({ label, href }) => {
- return (
-
- {label}
-
- );
- })}
-
- }
-
+
+
+
+
+ {links.map(({ label, href }) => {
+ return (
+
+ {label}
+
+ );
+ })}
+
+ }
+
+
);
});
diff --git a/geonode_mapstore_client/client/js/hooks/__tests__/useLocalStorage-test.js b/geonode_mapstore_client/client/js/hooks/__tests__/useLocalStorage-test.js
new file mode 100644
index 0000000000..4b31517fa7
--- /dev/null
+++ b/geonode_mapstore_client/client/js/hooks/__tests__/useLocalStorage-test.js
@@ -0,0 +1,58 @@
+
+/*
+ * Copyright 2021, GeoSolutions Sas.
+ * All rights reserved.
+ *
+ * This source code is licensed under the BSD-style license found in the
+ * LICENSE file in the root directory of this source tree.
+ */
+
+import React from 'react';
+import ReactDOM from 'react-dom';
+import expect from 'expect';
+import useLocalStorage from '@js/hooks/useLocalStorage';
+
+function MockApp({ key, value }) {
+
+ const [inTest, setInTest] = useLocalStorage(key);
+ setInTest(value);
+ return (
+
+ );
+
+}
+export default MockApp;
+
+
+describe('Test useLocalStorage', () => {
+ beforeEach((done) => {
+ document.body.innerHTML = '
';
+ setTimeout(done);
+ });
+ afterEach((done) => {
+ ReactDOM.unmountComponentAtNode(document.getElementById("container"));
+ document.body.innerHTML = '';
+ setTimeout(done);
+ });
+
+ it('Test componet is rendered', () => {
+ ReactDOM.render(
+ , document.getElementById("container"));
+ const container = document.getElementById('container');
+ const el = container.querySelector('.MockApp');
+ expect(el).toExist();
+ });
+
+ it('Test component localStorage props', () => {
+ ReactDOM.render( , document.getElementById("container"));
+ const el = document.getElementsByClassName('MockApp');
+ expect(el).toExist();
+ const element = el[0].childNodes[0];
+ expect(element).toExist();
+ expect(element.innerHTML).toBe('test_value');
+ });
+
+
+});
diff --git a/geonode_mapstore_client/client/js/hooks/useLocalStorage.js b/geonode_mapstore_client/client/js/hooks/useLocalStorage.js
new file mode 100644
index 0000000000..e3690c1bb4
--- /dev/null
+++ b/geonode_mapstore_client/client/js/hooks/useLocalStorage.js
@@ -0,0 +1,52 @@
+import { useEffect, useState } from 'react';
+
+export default (key, initialValue) => {
+
+ const getValue = () => {
+ if (typeof window === 'undefined') {
+ return initialValue;
+ }
+
+ try {
+ const item = window.localStorage.getItem(key);
+ return item ? JSON.parse(item) : initialValue;
+ } catch (error) {
+ // Todo log error in persistent solution
+ console.log(`Error to get item key “${key}”:`, error);
+ return initialValue;
+ }
+ };
+
+ const [storedValue, setStoredValue] = useState(getValue);
+
+ const setValue = (value) => {
+
+ try {
+ const newValue = value instanceof Function ? value(storedValue) : value;
+ setStoredValue(newValue);
+ window.localStorage.setItem(key, JSON.stringify(newValue));
+ window.dispatchEvent(new Event('localStorage'));
+ } catch (error) {
+ // Todo log error in persistent solution
+ console.log(`Error “${key}”:`, error);
+ }
+ };
+
+ useEffect(() => {
+ setStoredValue(getValue());
+ }, []);
+
+ useEffect(() => {
+ const handleStoreChange = () => {
+ setStoredValue(getValue());
+ };
+ window.addEventListener('localStorage', handleStoreChange);
+
+ return () => {
+ window.removeEventListener('localStorage', handleStoreChange);
+ };
+ }, []);
+
+
+ return [storedValue, setValue];
+};
diff --git a/geonode_mapstore_client/client/js/routes/Home.jsx b/geonode_mapstore_client/client/js/routes/Home.jsx
index 1e96dfa744..bd2ea58590 100644
--- a/geonode_mapstore_client/client/js/routes/Home.jsx
+++ b/geonode_mapstore_client/client/js/routes/Home.jsx
@@ -44,6 +44,7 @@ import {
getOwners
} from '@js/api/geonode/v1';
import { getResourceTypes } from '@js/api/geonode/v2';
+import useLocalStorage from '@js/hooks/useLocalStorage';
import { toggleFiltersPanel } from '@js/actions/gnfiltersPanel';
@@ -251,6 +252,7 @@ function Home({
heroNodeHeight
};
+ const [cardLayoutStyle, setCardLayoutStyle] = useLocalStorage('layoutCardsStyle');
const [showFilterForm, setShowFilterForm] = useState( (isFilterForm && isToggle) || false);
const handleShowFilterForm = () => {
@@ -263,6 +265,12 @@ function Home({
};
+ const handleStoredLayoutStyle = () => {
+ let styleCard = cardLayoutStyle === 'grid' ? 'list' : 'grid';
+ setCardLayoutStyle(styleCard);
+ };
+
+
function handleUpdate(newParams, pathname) {
const { query } = url.parse(location.search, true);
onSearch({
@@ -484,9 +492,11 @@ function Home({
filters={queryFilters}
onClear={handleClear}
onClick={handleShowFilterForm}
+ layoutSwitcher={handleStoredLayoutStyle}
orderOptions={filters?.order?.options}
defaultLabelId={filters?.order?.defaultLabelId}
/>
+
diff --git a/geonode_mapstore_client/client/themes/geonode/scss/_card-grid.scss b/geonode_mapstore_client/client/themes/geonode/scss/_card-grid.scss
index 437b6245ed..7f7e2a0883 100644
--- a/geonode_mapstore_client/client/themes/geonode/scss/_card-grid.scss
+++ b/geonode_mapstore_client/client/themes/geonode/scss/_card-grid.scss
@@ -50,4 +50,17 @@
padding: 1rem;
text-align: center;
}
+ .card-resource-list {
+ display: flex;
+ flex: 1 1 auto;
+ .card-img-left{
+ width: 160px;
+ height: auto;
+ object-fit: cover;
+ }
+
+ }
+
+
+
}
diff --git a/geonode_mapstore_client/client/themes/geonode/scss/_filter-form.scss b/geonode_mapstore_client/client/themes/geonode/scss/_filter-form.scss
index 49eef0c5ae..6362e19f61 100644
--- a/geonode_mapstore_client/client/themes/geonode/scss/_filter-form.scss
+++ b/geonode_mapstore_client/client/themes/geonode/scss/_filter-form.scss
@@ -57,3 +57,10 @@
}
}
}
+
+.gn-main-home{
+ width: 100%;
+ padding: 0;
+ margin-right: auto;
+ margin-left: auto;
+}
\ No newline at end of file