diff --git a/src/actions/index.js b/src/actions/index.js index 6fefa9e..0841b52 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -8,7 +8,7 @@ import { GET_CHART_DATA_FROM_VISUALIZATION, GET_NAVSITEMAP, SET_CURRENT_VERSION, -} from '@eeacms/volto-forests-theme/constants/ActionTypes'; +} from "@eeacms/volto-forests-theme/constants/ActionTypes"; export function setCurrentVersion(payload) { return { @@ -21,7 +21,7 @@ export function getFrontpageSlides() { return { type: GET_FRONTPAGESLIDES, request: { - op: 'get', + op: "get", path: `/frontpage_slides?fullobjects`, }, }; @@ -31,7 +31,7 @@ export function getDefaultHeaderImage() { return { type: GET_DEFAULT_HEADER_IMAGE, request: { - op: 'get', + op: "get", path: `/default_header_image?fullobjects`, }, }; @@ -41,7 +41,7 @@ export function getLocalnavigation(folder) { return { type: GET_LOCALNAVIGATION, request: { - op: 'get', + op: "get", path: `${folder}/@localnavigation`, }, }; @@ -75,7 +75,7 @@ export function getParentFolderData(url) { return { type: GET_PARENT_FOLDER_DATA, request: { - op: 'get', + op: "get", path: `/${url}?fullobjects`, }, }; @@ -95,7 +95,7 @@ export function getChartDataFromVisualization(path) { return { type: GET_CHART_DATA_FROM_VISUALIZATION, request: { - op: 'get', + op: "get", path, }, }; @@ -106,7 +106,7 @@ export function getNavSiteMap(url, depth) { return { type: GET_NAVSITEMAP, request: { - op: 'get', + op: "get", path: `${url}/@navigation?expand.navigation.depth=${depth || 3}`, }, }; diff --git a/src/components/index.js b/src/components/index.js index c434f22..f22f931 100644 --- a/src/components/index.js +++ b/src/components/index.js @@ -8,4 +8,4 @@ * Footer, * }; */ -export CountryView from './theme/CountryView/CountryView'; +export CountryView from "@eeacms/volto-forests-theme/components/theme/CountryView/CountryView"; diff --git a/src/components/manage/Blocks/NavigationBlock/Edit.jsx b/src/components/manage/Blocks/NavigationBlock/Edit.jsx index a05b968..c3c69c2 100644 --- a/src/components/manage/Blocks/NavigationBlock/Edit.jsx +++ b/src/components/manage/Blocks/NavigationBlock/Edit.jsx @@ -16,6 +16,10 @@ const getSchema = (props) => { title: 'Classname', type: 'text', }, + fixedTabs: { + title: 'Fixed navigation', + type: 'boolean', + }, navFromParent: { title: 'Show navigation from parent', type: 'boolean', diff --git a/src/components/manage/Blocks/NavigationBlock/View.jsx b/src/components/manage/Blocks/NavigationBlock/View.jsx index a700e8d..8d55cdc 100644 --- a/src/components/manage/Blocks/NavigationBlock/View.jsx +++ b/src/components/manage/Blocks/NavigationBlock/View.jsx @@ -13,6 +13,11 @@ import { setQueryParam, } from '@eeacms/volto-datablocks/actions'; import { useEffect } from 'react'; +import './styles.css'; +import cookie from 'react-cookie'; +import { Icon } from '@plone/volto/components'; +import downIcon from '@plone/volto/icons/down-key.svg'; +import closeIcon from '@plone/volto/icons/clear.svg'; const View = ({ content, ...props }) => { const { data } = props; @@ -21,12 +26,16 @@ const View = ({ content, ...props }) => { }); const [navigationItems, setNavigationItems] = useState([]); const [pages, setPages] = useState([]); + const [isMobile, setIsMobile] = useState(false); + const [expand, setExpand] = useState(false); + + const isLoggedIn = cookie.load('auth_token'); + const parent = data?.navFromParent?.value && props.properties?.parent ? getBasePath(props.properties?.parent?.['@id']) : data.parent?.value; const history = useHistory(); - useEffect(() => { const pagesProperties = data.pages?.value ? data.pages?.value?.properties || {} @@ -35,12 +44,41 @@ const View = ({ content, ...props }) => { Object.keys(pagesProperties).map((page) => pagesProperties[page]) || []; setPages(newPages); setNavigationItems([...(props.navigation?.items || []), ...newPages]); - // eslint-disable-next-line react-hooks/exhaustive-deps + + const width = window && window.innerWidth ? window.innerWidth : ''; + if (width && width <= 600) { + setIsMobile(true); + } + if (width && width > 600) { + setIsMobile(false); + } }, [props.navigation, data.pages?.value]); + const isFixed = props.fixedTabs; + + const getActiveItemName = () => { + const activeItem = navigationItems.filter( + (i) => getBasePath(i.url) === props.pathname, + ); + const name = activeItem && activeItem[0] ? activeItem[0].title : ''; + + return name; + }; + + const handleNavigate = (url) => { + setExpand(false); + if (props.mode !== 'edit' && url !== history.location.pathname) { + history.push(`${url}${props.query}`); + } + }; + if (navigationItems.length < 2 && props.mode !== 'edit') return null; return (props.navigation?.items?.length && parent) || pages.length ? ( -
+
{ props.data.className?.value ? props.data.className.value : '' } > - {navigationItems.map((item, index) => { - const url = getBasePath(item.url); - const name = item.title; - if ( - props.navigation?.items?.filter( - (navItem) => navItem.title === item.title, - ).length - ) { - if (isActive(url, props.pathname) && url !== state.activeItem) { - setState({ - ...state, - activeItem: url, - }); - } else if ( - !isActive(url, props.pathname) && - url === state.activeItem + {isMobile ? ( + + {expand ? ( +
+ {navigationItems.map((item, index) => { + const url = getBasePath(item.url); + const name = item.title; + if ( + props.navigation?.items?.filter( + (navItem) => navItem.title === item.title, + ).length + ) { + if ( + isActive(url, props.pathname) && + url !== state.activeItem + ) { + setState({ + ...state, + activeItem: url, + }); + } else if ( + !isActive(url, props.pathname) && + url === state.activeItem + ) { + setState({ + ...state, + activeItem: '', + }); + } + } + + return ( +
+ 0 ? 'sibling-on-left' : '', + index < navigationItems.length - 1 + ? 'sibling-on-right' + : '', + 'nav-tab-item', + )} + name={name} + key={url} + active={ + state.activeItem + ? state.activeItem === url + : !url + ? isActive(url, props.pathname) + : false + } + onClick={() => handleNavigate(url)} + > + {isActive(url, props.pathname) && ( + setExpand(false)} + /> + )} +
+ ); + })} +
+ ) : ( +
+ setExpand(true)} + /> + setExpand(true)} + /> +
+ )} +
+ ) : ( + navigationItems.map((item, index) => { + const url = getBasePath(item.url); + const name = item.title; + if ( + props.navigation?.items?.filter( + (navItem) => navItem.title === item.title, + ).length ) { - setState({ - ...state, - activeItem: '', - }); + if (isActive(url, props.pathname) && url !== state.activeItem) { + setState({ + ...state, + activeItem: url, + }); + } else if ( + !isActive(url, props.pathname) && + url === state.activeItem + ) { + setState({ + ...state, + activeItem: '', + }); + } } - } - return ( - 0 ? 'sibling-on-left' : '', - index < navigationItems.length - 1 ? 'sibling-on-right' : '', - )} - name={name} - key={url} - active={ - state.activeItem - ? state.activeItem === url - : !url - ? isActive(url, props.pathname) - : false - } - onClick={() => { - history.push(`${url}${props.query}`); - }} - /> - ); - })} + return ( + 0 ? 'sibling-on-left' : '', + index < navigationItems.length - 1 ? 'sibling-on-right' : '', + 'nav-tab-item', + )} + name={name} + key={url} + active={ + state.activeItem + ? state.activeItem === url + : !url + ? isActive(url, props.pathname) + : false + } + onClick={() => handleNavigate(url)} + /> + ); + }) + )}
) : props.mode === 'edit' ? ( @@ -118,6 +238,7 @@ export default compose( discodata_resources: state.discodata_resources, navItems: state.navigation?.items, flags: state.flags, + fixedTabs: props.data?.fixedTabs?.value, navigation: props.properties?.parent ? getNavigationByParent( state.navigation?.items, diff --git a/src/components/manage/Blocks/NavigationBlock/helpers.js b/src/components/manage/Blocks/NavigationBlock/helpers.js index 2c924ae..3c7ff81 100644 --- a/src/components/manage/Blocks/NavigationBlock/helpers.js +++ b/src/components/manage/Blocks/NavigationBlock/helpers.js @@ -1,9 +1,5 @@ -/* PLUGINS */ import { isMatch } from 'lodash'; -/* ROOT */ -import config from '@plone/volto/registry'; -/* PLONE VOLTO */ -import { getBaseUrl } from '@plone/volto/helpers'; +import { getBaseUrl, flattenToAppURL } from '@plone/volto/helpers'; export const isActive = (url, pathname) => { return ( @@ -83,10 +79,5 @@ export function removeValue(arr) { } export function getBasePath(url) { - return ( - url && - getBaseUrl(url) - .replace(config.settings.apiPath, '') - .replace(config.settings.internalApiPath, '') - ); + return url && flattenToAppURL(getBaseUrl(url)); } diff --git a/src/components/manage/Blocks/NavigationBlock/styles.css b/src/components/manage/Blocks/NavigationBlock/styles.css new file mode 100644 index 0000000..b80a437 --- /dev/null +++ b/src/components/manage/Blocks/NavigationBlock/styles.css @@ -0,0 +1,68 @@ +.sticky-tabs { + position: sticky; + z-index: 9; + top: 101px; + margin: 25px 0; +} + +.modern-tabs { + padding-top: 0 !important; + margin: 25px 0; + margin-right: 0.6rem; + margin-left: 0.6rem; + background-color: #f1f0ee; + + box-shadow: 0 1px 6px 0 #c7d5d8; +} + +.nav-tab-item:hover { + background: #cd4200 !important; + color: #fff !important; +} + +.tabs-view-menu .ui.menu .active.item { + border-radius: 0 !important; + font-weight: bold; +} + +.tabs-view-menu .ui.menu .item { + color: #554535; + font-weight: bold; +} + +.mobile-nav-icon { + position: absolute; + top: 5px; + right: 5px; + cursor: pointer; + fill: white !important; +} + +/* media queries */ + +@media screen and (max-width: 1400px) { + .sticky-tabs { + top: 150px; + } +} +@media screen and (max-width: 1200px) { + .modern-tabs { + background-color: white; + } +} + +@media screen and (max-width: 1300px) { + .sticky-tabs { + top: 125px; + } +} + +@media screen and (max-width: 767px) { + .sticky-tabs { + top: 79px; + } + + .mobile-authenticated-sticky { + top: 101px; + } +} diff --git a/src/components/manage/Widgets/ObjectListInlineWidget.jsx b/src/components/manage/Widgets/ObjectListInlineWidget.jsx index 5d6646f..2d42a72 100644 --- a/src/components/manage/Widgets/ObjectListInlineWidget.jsx +++ b/src/components/manage/Widgets/ObjectListInlineWidget.jsx @@ -1,4 +1,4 @@ -import { Accordion, Button, Segment, Modal } from 'semantic-ui-react'; +import { Accordion, Button, Segment, Modal, Grid } from 'semantic-ui-react'; import React, { useState } from 'react'; import { Icon as VoltoIcon, FormFieldWrapper } from '@plone/volto/components'; diff --git a/src/components/theme/CatalogueViews/AppHead.jsx b/src/components/theme/CatalogueViews/AppHead.jsx index 090221f..a22a08b 100644 --- a/src/components/theme/CatalogueViews/AppHead.jsx +++ b/src/components/theme/CatalogueViews/AppHead.jsx @@ -3,7 +3,9 @@ * @module components/theme/App/App */ -import { Component } from 'react'; +import React, { Component } from 'react'; + +import { Footer } from '@plone/volto/components'; class App extends Component { render() { diff --git a/src/components/theme/CatalogueViews/AppHeader.jsx b/src/components/theme/CatalogueViews/AppHeader.jsx index fac83d3..2d20e5b 100644 --- a/src/components/theme/CatalogueViews/AppHeader.jsx +++ b/src/components/theme/CatalogueViews/AppHeader.jsx @@ -3,27 +3,27 @@ * @module components/theme/App/App */ -import React, { Component, Fragment } from 'react'; -import PropTypes from 'prop-types'; -import { connect } from 'react-redux'; -import { compose } from 'redux'; -import { asyncConnect } from 'redux-connect'; -import loadable from '@loadable/component'; +import React, { Component, Fragment } from "react"; +import PropTypes from "prop-types"; +import { connect } from "react-redux"; +import { compose } from "redux"; +import { asyncConnect } from "redux-connect"; +import loadable from "@loadable/component"; -import { Header } from '@plone/volto/components'; -import { BodyClass, getBaseUrl, getView } from '@plone/volto/helpers'; +import { Header } from "@plone/volto/components"; +import { BodyClass, getBaseUrl, getView } from "@plone/volto/helpers"; import { getContent, getNavigation, getTypes, getWorkflow, purgeMessages, -} from '@plone/volto/actions'; +} from "@plone/volto/actions"; import { getFrontpageSlides, getDefaultHeaderImage, -} from '@eeacms/volto-forests-theme/actions'; -import { getPortlets } from '@eeacms/volto-addons-forest/actions'; +} from "@eeacms/volto-forests-theme/actions"; +import { getPortlets } from "@eeacms/volto-addons-forest/actions"; class App extends Component { static propTypes = { @@ -50,7 +50,7 @@ class App extends Component { componentDidMount() { // this.props.getDefaultHeaderImage(); if (__CLIENT__ && process.env.SENTRY_DSN) { - const Raven = loadable(() => import('raven-js')); + const Raven = loadable(() => import("raven-js")); Raven.config(process.env.SENTRY_DSN).install(); } @@ -89,7 +89,7 @@ class App extends Component { componentDidCatch(error, info) { this.setState({ hasError: true, error, errorInfo: info }); if (__CLIENT__ && process.env.SENTRY_DSN) { - const Raven = loadable(() => import('raven-js')); + const Raven = loadable(() => import("raven-js")); Raven.captureException(error, { extra: info }); } } @@ -122,68 +122,68 @@ class App extends Component { export const __test__ = connect( (state, props) => ({ pathname: props.location.pathname }), - { purgeMessages }, + { purgeMessages } )(App); export default compose( asyncConnect([ { - key: 'content', + key: "content", promise: ({ location, store: { dispatch } }) => dispatch(getContent(getBaseUrl(location.pathname))), }, { - key: 'frontpage_slides', + key: "frontpage_slides", promise: ({ store: { dispatch } }) => __SERVER__ && dispatch(getFrontpageSlides()), }, { - key: 'defaultHeaderImage', + key: "defaultHeaderImage", promise: ({ store: { dispatch } }) => __SERVER__ && dispatch(getDefaultHeaderImage()), }, { - key: 'navigation', + key: "navigation", promise: ({ location, store: { dispatch } }) => __SERVER__ && dispatch(getNavigation(getBaseUrl(location.pathname))), }, { - key: 'types', + key: "types", promise: ({ location, store: { dispatch } }) => __SERVER__ && dispatch(getTypes(getBaseUrl(location.pathname))), }, { - key: 'workflow', + key: "workflow", promise: ({ location, store: { dispatch } }) => __SERVER__ && dispatch(getWorkflow(getBaseUrl(location.pathname))), }, { - key: 'portlets', + key: "portlets", promise: ({ location, store: { dispatch } }) => __SERVER__ && dispatch(getPortlets(getBaseUrl(location.pathname))), }, { - key: 'portlets_left', + key: "portlets_left", promise: ({ location, store: { dispatch } }) => __SERVER__ && dispatch( - getPortlets(getBaseUrl(location.pathname), 'plone.leftcolumn'), + getPortlets(getBaseUrl(location.pathname), "plone.leftcolumn") ), }, { - key: 'portlets_right', + key: "portlets_right", promise: ({ location, store: { dispatch } }) => __SERVER__ && dispatch( - getPortlets(getBaseUrl(location.pathname), 'plone.rightcolumn'), + getPortlets(getBaseUrl(location.pathname), "plone.rightcolumn") ), }, { - key: 'portlets_footer', + key: "portlets_footer", promise: ({ location, store: { dispatch } }) => __SERVER__ && dispatch( - getPortlets(getBaseUrl(location.pathname), 'plone.footerportlets'), + getPortlets(getBaseUrl(location.pathname), "plone.footerportlets") ), }, ]), @@ -200,6 +200,6 @@ export default compose( // loadingContent: state.content?.get, // search: state.search, }), - { purgeMessages }, - ), + { purgeMessages } + ) )(App); diff --git a/src/components/theme/CountryPageView/CountryPageView.jsx b/src/components/theme/CountryPageView/CountryPageView.jsx index c84b3a3..0820dd4 100644 --- a/src/components/theme/CountryPageView/CountryPageView.jsx +++ b/src/components/theme/CountryPageView/CountryPageView.jsx @@ -1,6 +1,6 @@ /* eslint-disable jsx-a11y/anchor-is-valid */ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; +import React, { Component } from "react"; +import PropTypes from "prop-types"; import { ResponsiveContainer, @@ -13,26 +13,42 @@ import { CartesianGrid, Tooltip, // Legend, -} from 'recharts'; +} from "recharts"; -import { Container, Image } from 'semantic-ui-react'; -import { map } from 'lodash'; -import { connect } from 'react-redux'; +import { Helmet } from "@plone/volto/helpers"; +import { Container, Image } from "semantic-ui-react"; +import { map } from "lodash"; +import { connect } from "react-redux"; // import { Link } from 'react-router-dom'; import { // setFolderHeader, setFolderTabs, getParentFolderData, -} from '@eeacms/volto-forests-theme/actions'; +} from "@eeacms/volto-forests-theme/actions"; -import config from '@plone/volto/registry'; +import config from "@plone/volto/registry"; import { getBlocksFieldname, getBlocksLayoutFieldname, hasBlocksData, -} from '@plone/volto/helpers'; +} from "@plone/volto/helpers"; + +const numberToWord = { + 1: "one", + 2: "two", + 3: "three", + 4: "four", + 5: "five", + 6: "six", + 7: "seven", + 8: "eight", + 9: "nine", + 10: "ten", + 11: "eleven", + 12: "twelve", +}; const mapDispatchToProps = { // setFolderHeader, @@ -41,19 +57,19 @@ const mapDispatchToProps = { }; const data = [ - { name: '01', uv: 31, Species: 9 }, - { name: '04', uv: 22, Species: 18 }, - { name: '07', uv: 2, Species: 38 }, - { name: '10', uv: 24, Species: 16 }, - { name: '18', uv: 21, Species: 19 }, + { name: "01", uv: 31, Species: 9 }, + { name: "04", uv: 22, Species: 18 }, + { name: "07", uv: 2, Species: 38 }, + { name: "10", uv: 24, Species: 16 }, + { name: "18", uv: 21, Species: 19 }, ]; const coverage = [ - { name: '01', uv: 5, pv: 8, amt: 12 }, - { name: '04', uv: 7, pv: 13, amt: 3 }, - { name: '07', uv: 6, pv: 15, amt: 19 }, - { name: '10', uv: 3, pv: 12, amt: 8 }, - { name: '18', uv: 5, pv: 15, amt: 9 }, + { name: "01", uv: 5, pv: 8, amt: 12 }, + { name: "04", uv: 7, pv: 13, amt: 3 }, + { name: "07", uv: 6, pv: 15, amt: 19 }, + { name: "10", uv: 3, pv: 12, amt: 8 }, + { name: "18", uv: 5, pv: 15, amt: 9 }, ]; class StackedBarChart extends Component { @@ -134,8 +150,8 @@ class CountryPageView extends Component { url: PropTypes.string, image: PropTypes.object, image_caption: PropTypes.string, - '@type': PropTypes.string, - }), + "@type": PropTypes.string, + }) ), }).isRequired, }; @@ -156,26 +172,26 @@ class CountryPageView extends Component { if ( JSON.stringify(nextProps.parent) !== JSON.stringify(this.props.parent) ) { - // const title = nextProps.parent.title; - // const description = nextProps.parent.description; - // const image = - // nextProps.parent.items && - // nextProps.parent.items.find((c) => c['@type'] === 'Image'); - // const url = image && image.image.download; - // const inCountryFolder = true; + const title = nextProps.parent.title; + const description = nextProps.parent.description; + const image = + nextProps.parent.items && + nextProps.parent.items.find((c) => c["@type"] === "Image"); + const url = image && image.image.download; + const inCountryFolder = true; // this.props.setFolderHeader({ title, description, url, inCountryFolder }); - const pathArr = nextProps.location.pathname.split('/'); + const pathArr = nextProps.location.pathname.split("/"); pathArr.length = 3; - const path = pathArr.join('/'); + const path = pathArr.join("/"); const tabsItems = nextProps.parent.items .map((i) => { return { url: `${path}/${i.id}`, title: i.title, - '@type': i['@type'], + "@type": i["@type"], }; }) - .filter((i) => i.title !== 'folder_info'); + .filter((i) => i.title !== "folder_info"); this.props.setFolderTabs(tabsItems); } } @@ -184,15 +200,15 @@ class CountryPageView extends Component { const content = this.props.content; const blocksFieldname = getBlocksFieldname(content); const blocksLayoutFieldname = getBlocksLayoutFieldname(content); - // { - // /*if (!this.tabs) { - // const pathArr = this.props.location.pathname.split('/'); - // pathArr.length = 3; - // const path = pathArr.join('/'); - // this.props.getParentFolderData(path); - // } - // */ - // } + { + /*if (!this.tabs) { + const pathArr = this.props.location.pathname.split('/'); + pathArr.length = 3; + const path = pathArr.join('/'); + this.props.getParentFolderData(path); + } + */ + } return hasBlocksData(content) ? (
@@ -353,7 +369,6 @@ class CountryPageView extends Component {