@@ -452,24 +234,26 @@ export class VerticalDiagram extends React.PureComponent { // eslint-disable-lin
const fwId = isNumber(fw.get('id')) ? parseInt(fw.get('id'), 10) : fw.get('id');
return (
1}>
- {this.renderButton({
- path: ROUTES.RECOMMENDATIONS,
- query: frameworks.size > 1 && {
+ 1 ? {
arg: 'fwx',
value: fwId,
replace: true,
- },
- paletteDefault: 'recommendations',
- paletteHover: 'recommendationsHover',
- stateButton: `buttonRecs_${fwId}`,
- icon: `recommendations_${fwId}`,
- type: `recommendations_${fwId}`,
- count: recommendationCountByFw.get(fwId),
- draftCount: recommendationDraftCountByFw.get(fwId),
- multiple: frameworks.size > 1,
- onPageLink,
- intl,
- })}
+ } : null}
+ paletteDefault="recommendations"
+ paletteHover="recommendationsHover"
+ icon={`recommendations_${fwId}`}
+ type={`recommendations_${fwId}`}
+ count={recommendationCountByFw.get(fwId)}
+ draftCount={recommendationDraftCountByFw.get(fwId)}
+ multiple={frameworks.size > 1}
+ onPageLink={onPageLink}
+ intl={intl}
+ ref={(node) => {
+ this.setItemRef(node, `buttonRecs_${fwId}`);
+ }}
+ />
);
}
@@ -482,17 +266,19 @@ export class VerticalDiagram extends React.PureComponent { // eslint-disable-lin
- {this.renderButton({
- path: ROUTES.MEASURES,
- paletteDefault: 'measures',
- paletteHover: 'measuresHover',
- stateButton: 'buttonMeasures',
- icon: 'measures',
- type: 'measures',
- count: measureCount,
- draftCount: measureDraftCount,
- intl,
- })}
+ {
+ this.setItemRef(node, 'buttonMeasures');
+ }}
+ />
@@ -502,17 +288,19 @@ export class VerticalDiagram extends React.PureComponent { // eslint-disable-lin
- {this.renderButton({
- path: ROUTES.INDICATORS,
- paletteDefault: 'indicators',
- paletteHover: 'indicatorsHover',
- stateButton: 'buttonIndicators',
- icon: 'indicators',
- type: 'indicators',
- count: indicatorCount,
- draftCount: indicatorDraftCount,
- intl,
- })}
+ {
+ this.setItemRef(node, 'buttonIndicators');
+ }}
+ />
diff --git a/app/containers/Overview/VerticalDiagramButton.js b/app/containers/Overview/VerticalDiagramButton.js
new file mode 100644
index 000000000..ccc75c7f3
--- /dev/null
+++ b/app/containers/Overview/VerticalDiagramButton.js
@@ -0,0 +1,141 @@
+/*
+ *
+ * Overview
+ *
+ */
+import React from 'react';
+import PropTypes from 'prop-types';
+import { FormattedMessage } from 'react-intl';
+import { palette } from 'styled-theme';
+
+import styled from 'styled-components';
+
+// components
+import Button from 'components/buttons/Button';
+import Icon from 'components/Icon';
+
+// relative
+import appMessages from 'containers/App/messages';
+import messages from './messages';
+
+const DiagramButton = styled((p) =>
)`
+ background-color: ${(props) => palette(props.paletteDefault, 0)};
+ color: white;
+ padding: ${({ draft }) => draft ? '0.4em 0.5em 0.75em' : '0.6em 0.5em'};
+ box-shadow: 0px 0px 5px 0px rgba(0,0,0,0.2);
+ font-size: 0.7em;
+ border-radius: 15px;
+ max-width: ${({ multiple }) => multiple ? '70px' : 'none'};
+ min-width: 0;
+ &:hover {
+ background-color: ${(props) => palette(props.paletteHover, 0)};
+ }
+ @media (min-width: ${(props) => props.theme.breakpoints.small}) {
+ font-size: 1em;
+ padding: ${({ draft }) => draft ? '0.4em 0.5em 0.4em' : '0.6em 0.5em'};
+ max-width: ${({ multiple }) => multiple ? '140px' : 'none'};
+ min-width: ${({ multiple }) => multiple ? '120px' : 'none'};
+ box-shadow: 0px 0px 10px 0px rgba(0,0,0,0.2);
+ }
+ @media (min-width: ${(props) => props.theme.breakpoints.medium}) {
+ font-size: 1.1em;
+ min-width: ${({ multiple }) => multiple ? 'none' : '180px'};
+ }
+ @media (min-width: ${(props) => props.theme.breakpoints.large}) {
+ font-weight: bold;
+ max-width: none;
+ min-width: 200px;
+ padding: ${({ draft }) => draft ? '0.6em 1em 0.2em' : '0.8em 1em'};
+ }
+ @media print {
+ font-size: ${(props) => props.theme.sizes.print.default};
+ box-shadow: none;
+ border: 1px solid ${palette('light', 3)};
+ min-width: none;
+ width: 130px;
+ height: 90px;
+ }
+`;
+
+const DiagramButtonIcon = styled.div`
+ padding-bottom: 5px;
+`;
+
+const DraftEntities = styled.div`
+ display: none;
+ @media (min-width: ${(props) => props.theme.breakpoints.small}) {
+ display: block;
+ font-size: 0.8em;
+ font-weight: normal;
+ }
+ @media print {
+ font-size: ${(props) => props.theme.sizes.print.smaller};
+ }
+`;
+
+const VerticalDiagramButton = React.forwardRef((props, ref) => {
+ const {
+ path,
+ query,
+ paletteDefault,
+ paletteHover,
+ icon,
+ type,
+ count,
+ draftCount,
+ multiple,
+ onPageLink,
+ intl,
+ } = props;
+ return (
+
+
onPageLink(path, query)}
+ paletteDefault={paletteDefault}
+ paletteHover={paletteHover}
+ draft={draftCount > 0}
+ multiple={multiple}
+ title={intl.formatMessage(
+ messages.buttons.title,
+ { label: `${count || 0} ${intl.formatMessage(appMessages.entities[type][count !== 1 ? 'plural' : 'single'])}` },
+ )}
+ >
+
+
+
+
+ {`${count || 0} ${intl.formatMessage(appMessages.entities[type][count !== 1 ? 'plural' : 'single'])}`}
+
+ {draftCount > 0 && (
+
+
+
+ )}
+
+
+ );
+});
+
+VerticalDiagramButton.propTypes = {
+ path: PropTypes.string,
+ query: PropTypes.object,
+ paletteDefault: PropTypes.string,
+ paletteHover: PropTypes.string,
+ icon: PropTypes.string,
+ type: PropTypes.string,
+ count: PropTypes.number,
+ draftCount: PropTypes.number,
+ multiple: PropTypes.bool,
+ onPageLink: PropTypes.func,
+ intl: PropTypes.object.isRequired,
+};
+
+export default VerticalDiagramButton;
diff --git a/app/containers/Overview/VerticalDiagramSVG.js b/app/containers/Overview/VerticalDiagramSVG.js
new file mode 100644
index 000000000..5ff496481
--- /dev/null
+++ b/app/containers/Overview/VerticalDiagramSVG.js
@@ -0,0 +1,277 @@
+/*
+ *
+ * Overview
+ *
+ */
+import React from 'react';
+import PropTypes from 'prop-types';
+import { PathLine } from 'react-svg-pathline';
+import { palette } from 'styled-theme';
+
+import styled from 'styled-components';
+
+const RADIUS = 6;
+
+const DiagramSvg = styled.svg``;
+const DiagramSvgWrapper = styled.div`
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ bottom: 0;
+ @media print {
+ display: none;
+ }
+`;
+
+const PathLineCustom = styled(PathLine)`
+ stroke: ${palette('dark', 2)};
+ stroke-width: 0.5px;
+ fill: none;
+`;
+const PathLineArrow = styled(PathLine)`
+ fill: ${palette('dark', 2)};
+`;
+const SectionLabel = styled.div`
+ color: ${palette('text', 1)};
+ font-size: ${(props) => props.theme.sizes.text.small};
+ margin-top: 5px;
+ position: absolute;
+ left: 0;
+ top: 0;
+ @media print {
+ font-size: ${(props) => props.theme.sizes.print.small};
+ }
+`;
+
+const roundRect = (rect) => ({
+ right: Math.floor(rect.right),
+ left: Math.floor(rect.left),
+ top: Math.floor(rect.top),
+ bottom: Math.floor(rect.bottom),
+})
+
+const getConnectionPoint = (node, nodeReference, side = 'bottom') => {
+ const boundingRect = roundRect(node.getBoundingClientRect());
+ const boundingRectReference = roundRect(nodeReference.getBoundingClientRect());
+ if (side === 'right' || side === 'left') {
+ return ({
+ x: side === 'right'
+ ? (boundingRect.right - boundingRectReference.left)
+ : (boundingRect.left - boundingRectReference.left),
+ y: (boundingRect.top - boundingRectReference.top)
+ + (((boundingRect.bottom - boundingRectReference.top) - (boundingRect.top - boundingRectReference.top)) / 2),
+ });
+ }
+
+ const ret = ({
+ x: (boundingRect.left - boundingRectReference.left)
+ + (((boundingRect.right - boundingRectReference.left) - (boundingRect.left - boundingRectReference.left)) / 2),
+ y: side === 'bottom'
+ ? (boundingRect.bottom - boundingRectReference.top)
+ : (boundingRect.top - boundingRectReference.top),
+ });
+ return ret;
+};
+
+const getConnectionPath = (start, end) => [
+ { x: start.x, y: start.y + 5 },
+ { x: end.x, y: end.y - 5 },
+];
+
+const getCurvedConnectionPath = (
+ direction = 'vertical',
+ start,
+ end,
+ curve = 0.2,
+ offset,
+) => {
+ if (direction === 'right') {
+ return [
+ { x: start.x + 5, y: start.y },
+ { x: Math.max(start.x, end.x) + 25, y: start.y },
+ { x: Math.max(start.x, end.x) + 25, y: end.y },
+ { x: end.x + 5, y: end.y },
+ ];
+ }
+ if (offset) {
+ return [
+ { x: start.x + 12, y: start.y + 5 },
+ { x: start.x + 12, y: (start.y + 5) + ((end.y - start.y - 10) * curve) },
+ { x: end.x, y: (start.y + 5) + ((end.y - start.y - 10) * curve) },
+ { x: end.x, y: end.y - 5 },
+ ];
+ }
+ if (Math.abs(start.x - end.x) < RADIUS * 2) {
+ return getConnectionPath(
+ {...start, x: end.x},
+ end,
+ );
+ }
+ return [
+ { x: start.x, y: start.y + 5 },
+ { x: start.x, y: (start.y + 5) + ((end.y - start.y - 10) * curve) },
+ { x: end.x, y: (start.y + 5) + ((end.y - start.y - 10) * curve) },
+ { x: end.x, y: end.y - 5 },
+ ];
+};
+
+const getConnectionPathArrow = (connectionPath, direction = 'bottom') => {
+ const point = connectionPath[connectionPath.length - 1];
+ if (direction === 'left') {
+ return [
+ point,
+ { x: point.x + 5, y: point.y + 5 },
+ { x: point.x + 5, y: point.y - 5 },
+ point,
+ ];
+ }
+ return [
+ point,
+ { x: point.x - 5, y: point.y - 5 },
+ { x: point.x + 5, y: point.y - 5 },
+ point,
+ ];
+};
+
+const connectRecommendationsMeasures = (itemRefs, fwId) => getCurvedConnectionPath(
+ 'vertical',
+ getConnectionPoint(itemRefs[`buttonRecs_${fwId}`], itemRefs.diagram, 'bottom'),
+ getConnectionPoint(itemRefs.buttonMeasures, itemRefs.diagram, 'top'),
+ 0.25,
+);
+
+const connectRecommendationsIndicators = (
+ itemRefs,
+ direction = 'vertical',
+ fwId,
+ offset,
+) => getCurvedConnectionPath(
+ direction,
+ getConnectionPoint(
+ itemRefs[`buttonRecs_${fwId}`],
+ itemRefs.diagram,
+ direction === 'vertical' ? 'bottom' : direction,
+ ),
+ getConnectionPoint(
+ itemRefs.buttonIndicators,
+ itemRefs.diagram,
+ direction === 'vertical' ? 'top' : direction,
+ ),
+ 0.9, // curve
+ offset,
+);
+
+const connectMeasuresIndicators = (itemRefs) => getConnectionPath(
+ getConnectionPoint(itemRefs.buttonMeasures, itemRefs.diagram, 'bottom'),
+ getConnectionPoint(itemRefs.buttonIndicators, itemRefs.diagram, 'top'),
+);
+
+const VerticalDiagramSVG = ({ frameworks, itemRefs, version }) => {
+ return (
+
+ {itemRefs.diagram && (
+
+ {frameworks && frameworks.valueSeq().map((fw) => {
+ const fwId = fw.get('id');
+ return fw.getIn(['attributes', 'has_indicators'])
+ && itemRefs[`buttonRecs_${fwId}`]
+ && itemRefs.buttonIndicators
+ && (
+
+ );
+ })}
+ {frameworks && frameworks.valueSeq().map((fw) => {
+ const fwId = fw.get('id');
+ return fw.getIn(['attributes', 'has_indicators'])
+ && itemRefs[`buttonRecs_${fwId}`]
+ && itemRefs.buttonIndicators
+ && frameworks.size === 1
+ && (
+
+ );
+ })}
+ {frameworks && frameworks.valueSeq().map((fw) => {
+ const fwId = fw.get('id');
+ return itemRefs[`buttonRecs_${fwId}`]
+ && itemRefs.buttonMeasures
+ && (
+ 1 ? RADIUS : 0}
+ points={connectRecommendationsMeasures(itemRefs, fwId)}
+ />
+ );
+ })}
+ {frameworks && frameworks.valueSeq().map((fw) => {
+ const fwId = fw.get('id');
+ return fw.getIn(['attributes', 'has_measures'])
+ && itemRefs[`buttonRecs_${fwId}`]
+ && itemRefs.buttonMeasures
+ && (
+
+ );
+ })}
+ { itemRefs.buttonIndicators && itemRefs.buttonMeasures && (
+
+ )}
+ { itemRefs.buttonIndicators && itemRefs.buttonMeasures && (
+
+ )}
+
+ )}
+
+ );
+};
+
+VerticalDiagramSVG.propTypes = {
+ frameworks: PropTypes.object,
+ itemRefs: PropTypes.object,
+ version: PropTypes.number,
+};
+
+export default VerticalDiagramSVG;
diff --git a/app/containers/Overview/index.js b/app/containers/Overview/index.js
index 6ab4c0abc..c7ff2cc77 100644
--- a/app/containers/Overview/index.js
+++ b/app/containers/Overview/index.js
@@ -10,12 +10,14 @@ import HelmetCanonical from 'components/HelmetCanonical';
import { FormattedMessage, injectIntl } from 'react-intl';
import styled, { withTheme } from 'styled-components';
+import { palette } from 'styled-theme';
// containers
import { loadEntitiesIfNeeded, updatePath } from 'containers/App/actions';
import {
selectFWTaxonomiesSorted,
selectReady,
+ selectFrameworks,
selectActiveFrameworks,
selectCurrentFrameworkId,
} from 'containers/App/selectors';
@@ -55,9 +57,9 @@ const ViewContainer = styled(Container)`
`;
const AboutLink = styled(A)`
- color: #ba5d03;
+ color: ${palette('primary', 1)};
&:hover {
- color: #ba5d03;
+ color: ${palette('primary', 0)};
text-decoration: underline;
}
`;
@@ -126,6 +128,7 @@ export class Overview extends React.PureComponent { // eslint-disable-line react
onTaxonomyLink,
taxonomies,
frameworks,
+ allFrameworks,
frameworkId,
onPageLink,
intl,
@@ -179,7 +182,7 @@ export class Overview extends React.PureComponent { // eslint-disable-line react
{!dataReady &&