diff --git a/app/assets/images/flag/big-principle.svg b/app/assets/images/flag/big-principle.svg index 0bbbdab..0929a31 100644 --- a/app/assets/images/flag/big-principle.svg +++ b/app/assets/images/flag/big-principle.svg @@ -1,30 +1,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/flag/principle.svg b/app/assets/images/flag/principle.svg index 0bbbdab..0929a31 100644 --- a/app/assets/images/flag/principle.svg +++ b/app/assets/images/flag/principle.svg @@ -1,30 +1,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/flag/relatedtools-methodologies.svg b/app/assets/images/flag/relatedtools-methodologies.svg new file mode 100755 index 0000000..2937e23 --- /dev/null +++ b/app/assets/images/flag/relatedtools-methodologies.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/flag/relatedtools-principles.svg b/app/assets/images/flag/relatedtools-principles.svg new file mode 100755 index 0000000..49ec321 --- /dev/null +++ b/app/assets/images/flag/relatedtools-principles.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/flag/relatedtools-stories.svg b/app/assets/images/flag/relatedtools-stories.svg new file mode 100755 index 0000000..25a52e2 --- /dev/null +++ b/app/assets/images/flag/relatedtools-stories.svg @@ -0,0 +1,46 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/flag/relatedtools-tactics.svg b/app/assets/images/flag/relatedtools-tactics.svg new file mode 100755 index 0000000..ade4720 --- /dev/null +++ b/app/assets/images/flag/relatedtools-tactics.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/flag/relatedtools-theories.svg b/app/assets/images/flag/relatedtools-theories.svg new file mode 100755 index 0000000..1f33d31 --- /dev/null +++ b/app/assets/images/flag/relatedtools-theories.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/icons/add-tool.old.svg b/app/assets/images/icons/add-tool.old.svg new file mode 100644 index 0000000..3e9318b --- /dev/null +++ b/app/assets/images/icons/add-tool.old.svg @@ -0,0 +1,58 @@ + + + + + + diff --git a/app/assets/images/icons/add-tool.svg b/app/assets/images/icons/add-tool.svg old mode 100644 new mode 100755 index 3e9318b..263e130 --- a/app/assets/images/icons/add-tool.svg +++ b/app/assets/images/icons/add-tool.svg @@ -1,58 +1,110 @@ - - + + + + + + + + + + diff --git a/app/assets/images/icons/bell.svg b/app/assets/images/icons/bell.svg new file mode 100755 index 0000000..e253e20 --- /dev/null +++ b/app/assets/images/icons/bell.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + diff --git a/app/assets/images/icons/clear.svg b/app/assets/images/icons/clear.svg new file mode 100755 index 0000000..5e5bb7e --- /dev/null +++ b/app/assets/images/icons/clear.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/icons/my-tools.old.svg b/app/assets/images/icons/my-tools.old.svg new file mode 100644 index 0000000..1d152be --- /dev/null +++ b/app/assets/images/icons/my-tools.old.svg @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/app/assets/images/icons/my-tools.svg b/app/assets/images/icons/my-tools.svg old mode 100644 new mode 100755 index 1d152be..b841d70 --- a/app/assets/images/icons/my-tools.svg +++ b/app/assets/images/icons/my-tools.svg @@ -1,14 +1,16 @@ - - - - - - + + + + + + + + + + + + diff --git a/app/assets/images/icons/remove-small.old.svg b/app/assets/images/icons/remove-small.old.svg new file mode 100644 index 0000000..eaca3a4 --- /dev/null +++ b/app/assets/images/icons/remove-small.old.svg @@ -0,0 +1,3 @@ + + + diff --git a/app/assets/images/icons/remove-small.svg b/app/assets/images/icons/remove-small.svg old mode 100644 new mode 100755 index eaca3a4..e9b5ae4 --- a/app/assets/images/icons/remove-small.svg +++ b/app/assets/images/icons/remove-small.svg @@ -1,3 +1,20 @@ - - + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/icons/remove-tool.old.svg b/app/assets/images/icons/remove-tool.old.svg new file mode 100644 index 0000000..4ec4fd1 --- /dev/null +++ b/app/assets/images/icons/remove-tool.old.svg @@ -0,0 +1,53 @@ + + + + + + + + + diff --git a/app/assets/images/icons/remove-tool.svg b/app/assets/images/icons/remove-tool.svg old mode 100644 new mode 100755 index 4ec4fd1..a33e103 --- a/app/assets/images/icons/remove-tool.svg +++ b/app/assets/images/icons/remove-tool.svg @@ -1,53 +1,92 @@ - - - - + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/icons/search.svg b/app/assets/images/icons/search.svg new file mode 100755 index 0000000..ca30b31 --- /dev/null +++ b/app/assets/images/icons/search.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/icons/stories-whyitfailed.svg b/app/assets/images/icons/stories-whyitfailed.svg new file mode 100755 index 0000000..c913252 --- /dev/null +++ b/app/assets/images/icons/stories-whyitfailed.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/icons/stories-whyitworked.svg b/app/assets/images/icons/stories-whyitworked.svg new file mode 100755 index 0000000..54ee4b3 --- /dev/null +++ b/app/assets/images/icons/stories-whyitworked.svg @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/icons/view_block.svg b/app/assets/images/icons/view_block.svg index 8337f90..9a8d2e1 100644 --- a/app/assets/images/icons/view_block.svg +++ b/app/assets/images/icons/view_block.svg @@ -1 +1 @@ -image/svg+xml +image/svg+xml diff --git a/app/assets/images/icons/view_list.svg b/app/assets/images/icons/view_list.svg index 57dc2fa..76e589c 100644 --- a/app/assets/images/icons/view_list.svg +++ b/app/assets/images/icons/view_list.svg @@ -1,4 +1,4 @@ - + diff --git a/app/assets/images/type/principle-icon.svg b/app/assets/images/type/principle-icon.svg index ffac786..81c3463 100644 --- a/app/assets/images/type/principle-icon.svg +++ b/app/assets/images/type/principle-icon.svg @@ -4,7 +4,7 @@ - - + + diff --git a/app/assets/images/type/principle-small.svg b/app/assets/images/type/principle-small.svg index a490c58..af6f095 100644 --- a/app/assets/images/type/principle-small.svg +++ b/app/assets/images/type/principle-small.svg @@ -6,18 +6,18 @@ - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/app/assets/images/type/principle.svg b/app/assets/images/type/principle.svg index d36a489..0898ff5 100644 --- a/app/assets/images/type/principle.svg +++ b/app/assets/images/type/principle.svg @@ -2,24 +2,24 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/type/principles-option.svg b/app/assets/images/type/principles-option.svg index d36a489..0898ff5 100644 --- a/app/assets/images/type/principles-option.svg +++ b/app/assets/images/type/principles-option.svg @@ -2,24 +2,24 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + diff --git a/app/assets/images/type/principles-optionflag.svg b/app/assets/images/type/principles-optionflag.svg index 0bbbdab..0929a31 100644 --- a/app/assets/images/type/principles-optionflag.svg +++ b/app/assets/images/type/principles-optionflag.svg @@ -1,30 +1,30 @@ - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/components/AboutPage/AboutSection.js b/app/components/AboutPage/AboutSection.js index 87905f8..40578d1 100644 --- a/app/components/AboutPage/AboutSection.js +++ b/app/components/AboutPage/AboutSection.js @@ -12,7 +12,7 @@ h2 { letter-spacing: 0; font-family: 'Avenir', 'Kaff', sans-serif; font-weight: 800; - margin-top: 40px; + margin-top: 90px; padding: 15px 20px; text-align: ${p=>p.lang==='ar'?'right':'left'}; position: relative; @@ -25,7 +25,14 @@ h2 { border-right: ${p=>p.hideHeader ? '0px solid' : '1px solid'}; width: 1PX; bottom: -65px; - ${p=>p.lang==='ar'?'right':'left'}: 50%; + ${p=>p.lang==='ar'?'right':'left'}: ${p=>{ + if (!p.position) return '50%'; + switch(p.position % 3) { + case 0: return '50%'; + case 1: return '67%'; + case 2: return '83%'; + } + }}; } } diff --git a/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkIntro.js b/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkIntro.js index 6b738c0..93f4b20 100644 --- a/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkIntro.js +++ b/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkIntro.js @@ -5,4 +5,10 @@ export default styled(IntroText)` margin-${p=>p.theme.isArabic?'right':'left'}: 82%; width: 33%; padding: 0; + + @media(max-width: 1170px) { + width: 100%; + margin: 0; + transform: translateX(0); + } ` diff --git a/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkListItem.js b/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkListItem.js index 580f182..f7305f3 100644 --- a/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkListItem.js +++ b/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkListItem.js @@ -1,7 +1,8 @@ import styled from 'styled-components'; -export default styled.li`list-style: none; - width: ${props=>props.theme.itemWidth}; - margin-${p=>p.theme.isArabic?'left':'right'}: ${props=>props.theme.itemMargin}; +export default styled.li` + list-style: none; + width: 32%; + margin-${p=>p.theme.isArabic?'left':'right'}: 0.5%; display: inline-block; vertical-align: top; margin-bottom: 50px; @@ -32,4 +33,16 @@ export default styled.li`list-style: none; a { color: #828486; } - }`; + } + + @media(max-width: 1170px) { + width: 100%; + text-align: center; + p { + padding: 0; + } + h3 { + text-align: center; + } + } +`; diff --git a/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkSection.js b/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkSection.js index 192fa67..f2cb0b9 100644 --- a/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkSection.js +++ b/app/components/AboutPage/AdvisoryNetwork/AdvisoryNetworkSection.js @@ -6,5 +6,11 @@ export default styled(AboutSection)` &::after { ${p=>p.theme.isArabic?'right':'left'}: 83%; } + + @media(max-width: 1170px) { + &::after { + ${p=>p.theme.isArabic?'right':'left'}: 50%; + } + } } `; diff --git a/app/components/AboutPage/FAQ/FAQContent.js b/app/components/AboutPage/FAQ/FAQContent.js index 08f8766..a48267b 100644 --- a/app/components/AboutPage/FAQ/FAQContent.js +++ b/app/components/AboutPage/FAQ/FAQContent.js @@ -2,4 +2,7 @@ import ContentBlock from 'components/ContentBlock'; import styled from 'styled-components'; export default styled(ContentBlock)` padding-${p=>p.theme.isArabic?'right':'left'}: 100px; + @media(max-width: 1170px) { + padding: 0; + } `; diff --git a/app/components/AboutPage/FAQ/FAQListItem.js b/app/components/AboutPage/FAQ/FAQListItem.js index 3b40e1a..9a44cf4 100644 --- a/app/components/AboutPage/FAQ/FAQListItem.js +++ b/app/components/AboutPage/FAQ/FAQListItem.js @@ -5,5 +5,9 @@ export default styled.li`list-style: none; display: inline-block; vertical-align: top; margin-bottom: 34px; + + @media(max-width: 1170px) { + width: 100%; + } ` ; diff --git a/app/components/AboutPage/IntroText.js b/app/components/AboutPage/IntroText.js index 1bed4fa..15474a5 100644 --- a/app/components/AboutPage/IntroText.js +++ b/app/components/AboutPage/IntroText.js @@ -7,4 +7,11 @@ export default styled(ContentBlock)` transform: translateX(${p=>p.lang==='ar'?'50%':'-50%'}); padding: 0 40px; text-align: center; + + @media(max-width: 1170px) { + width: 100%; + text-align: center; + transform: none; + margin-left: auto; + } `; diff --git a/app/components/AboutPage/Partners/ImageContainer.js b/app/components/AboutPage/Partners/ImageContainer.js index 2539341..89d026f 100644 --- a/app/components/AboutPage/Partners/ImageContainer.js +++ b/app/components/AboutPage/Partners/ImageContainer.js @@ -2,4 +2,8 @@ import styled from 'styled-components'; export default styled.div` width: 65%; padding-bottom: 13px; + +@media(max-width: 1170px) { + display: inline-block; +} `; diff --git a/app/components/AboutPage/Partners/ListItem.js b/app/components/AboutPage/Partners/ListItem.js index 04aba49..9e13aca 100644 --- a/app/components/AboutPage/Partners/ListItem.js +++ b/app/components/AboutPage/Partners/ListItem.js @@ -22,4 +22,23 @@ export default styled.li`list-style: none; text-align: ${p=>p.lang==='ar'?'right':'left'}; font-size: 18px; padding-${p=>p.lang==='ar'?'right':'left'}: 10px; - }`; + } + + @media(max-width: 1170px) { + width: 100%; + text-align: center; + p { + padding: 0; + } + h3 { + text-align: center; + } + + h5 { + &::before { + left: 50%; + transform: translateX(-50%); + } + } + } + `; diff --git a/app/components/AboutPage/Process/ProcessListItem.js b/app/components/AboutPage/Process/ProcessListItem.js index b9cb88a..dc14e49 100644 --- a/app/components/AboutPage/Process/ProcessListItem.js +++ b/app/components/AboutPage/Process/ProcessListItem.js @@ -1,7 +1,7 @@ import styled from 'styled-components'; export default styled.li`list-style: none; - width: ${props=>props.theme.itemWidth}; - margin-${p=>p.lang==='ar'?'left':'right'}: ${props=>props.theme.itemMargin}; + width: 24%; + margin-${p=>p.lang==='ar'?'left':'right'}: ${props=>'0.5%'}; display: inline-block; vertical-align: top; margin-bottom: 50px; @@ -50,4 +50,17 @@ export default styled.li`list-style: none; line-height: 20px; } } + + @media(max-width: 1170px) { + width: 100%; + float: none; + + text-align: center; + .circledContainer { + display: inline-block; + &::after { + display: none; + } + } + } `; diff --git a/app/components/AboutPage/Team/TeamListItem.js b/app/components/AboutPage/Team/TeamListItem.js index fe60236..5b97caf 100644 --- a/app/components/AboutPage/Team/TeamListItem.js +++ b/app/components/AboutPage/Team/TeamListItem.js @@ -1,7 +1,7 @@ import styled from 'styled-components'; export default styled.li`list-style: none; - width: ${props=>props.theme.itemWidth}; - margin-right: ${props=>props.theme.itemMargin}; + width: 32%; + margin-${p=>p.theme.isArabic?'left':'right'}: 0.5%; display: inline-block; vertical-align: top; margin-bottom: 50px; @@ -26,4 +26,15 @@ export default styled.li`list-style: none; } p { padding-${p=>p.theme.isArabic?'left':'right'}: 30px; } + + @media(max-width: 1170px) { + width: 100%; + text-align: center; + p { + padding: 0; + } + h3 { + text-align: center; + } + } `; diff --git a/app/components/AboutPage/Values/SubListContentBlock.js b/app/components/AboutPage/Values/SubListContentBlock.js index 15a1ed3..c2c63cc 100644 --- a/app/components/AboutPage/Values/SubListContentBlock.js +++ b/app/components/AboutPage/Values/SubListContentBlock.js @@ -3,4 +3,8 @@ import styled from 'styled-components'; export default styled(ContentBlock)` padding-${p=>p.theme.isArabic?'right':'left'}: 100px !important; margin: 10px; + + @media(max-width: 1170px) { + padding-${p=>p.theme.isArabic?'right':'left'}: 0 !important; + } `; diff --git a/app/components/AuthorComponents/index.js b/app/components/Author/index.js similarity index 73% rename from app/components/AuthorComponents/index.js rename to app/components/Author/index.js index 45e379b..d987622 100644 --- a/app/components/AuthorComponents/index.js +++ b/app/components/Author/index.js @@ -23,9 +23,14 @@ AuthorComponents.propTypes = { }; export const AuthorContainer = styled.section` - margin-top: 10px; - margin-bottom: 30px; + padding-top: 36px; + margin-bottom: 54px; direction: ${p=>p.theme.isArabic?'rtl':'ltr'} !important; + display: flex; + + @media(max-width: 1170px) { + flex-wrap: wrap; + } `; export const AuthorImageArea = styled.div` @@ -35,8 +40,7 @@ export const AuthorImageArea = styled.div` `; export const AuthorImage = styled.span` width: 100%; - height: 0; - padding-bottom: 100%; + height: 100%; background-image: url(${props=>AUTHOR_BASE_IMAGE + props.image}) display: inline-block; @@ -55,13 +59,32 @@ export const AuthorName = styled(SmallHeaderBlock)` export const AuthorLink = styled(Link)` color: rgb(130, 132, 134); - display: block; - width: 100%; + display: inline-block; + width: 200px; + height: 170px; + min-width: 200px; + + @media(max-width: 1170px) { + width: 100%; + min-width: 100%; + } `; export const AuthorDesc = styled.div` - margin: 2px; + flex-grow: 1; text-align: ${p=>p.theme.isArabic?'right':'left'} !important; + display: inline-block; + padding-left: 28px; + + p { + margin: 0; + } + + @media(max-width: 1170px) { + width: 100%; + padding: 10px; + margin-top: 10px; + } `; export default AuthorComponents; diff --git a/app/components/AuthorComponents/tests/index.test.js b/app/components/Author/tests/index.test.js similarity index 100% rename from app/components/AuthorComponents/tests/index.test.js rename to app/components/Author/tests/index.test.js diff --git a/app/components/Body/index.js b/app/components/Body/index.js index 587b3a4..58650a7 100644 --- a/app/components/Body/index.js +++ b/app/components/Body/index.js @@ -8,11 +8,19 @@ import React from 'react'; import styled from 'styled-components'; export default styled.section` - margin-top: 90px; + padding-top: 217px; display: inline-block; - max-width:1100px; + max-width: 1170px; width: 100%; position: relative; left: ${(props) => props.showTools ? (props.lang==='ar' ? '230px' : '-230px') : '0'}; transition: left 0.3s ease; + + // Mobile + @media(max-width: 1170px) { + max-width: 100%; + padding-top: 120px; + left: 0 !important; + padding-bottom: 70px; + } `; diff --git a/app/components/CircledImage/index.js b/app/components/CircledImage/index.js index 4627e77..0518b73 100644 --- a/app/components/CircledImage/index.js +++ b/app/components/CircledImage/index.js @@ -18,7 +18,7 @@ const CircledContainer = styled.div` &::after { content: ' '; - width: 170px; + width: 189px; height: 1px; border-bottom: 2px solid; top: 50%; diff --git a/app/components/CollapsingSection/index.js b/app/components/CollapsingSection/index.js new file mode 100644 index 0000000..f0a5dd2 --- /dev/null +++ b/app/components/CollapsingSection/index.js @@ -0,0 +1,109 @@ +/** +* +* CollapsingSection +* +*/ + +import React from 'react'; +import styled from 'styled-components'; + +import ArrowIcon from 'assets/images/icons/arrow.svg'; +import Isvg from 'react-inlinesvg'; + +import LanguageThemeProvider from 'components/LanguageThemeProvider'; + +const Container = styled.div` + +`; + +const HeaderContainer = styled.div` + border-bottom: 2px solid black; +`; +const Header = styled.div` + display: inline-block; + padding-${p=>p.theme.isArabic?'left':'right'}: 20px; + width: 100%; +`; +const ArrowContainer = styled.span` + display: inline-block; + transition: transform 0.5s ease; + position: absolute; + + ${p=>{ + if (p.theme.isArabic) { + return ` + transform: ${p.showing ? 'rotate(270deg)' : 'rotate(360deg)'} ${p.showing ? 'translate(100%, 0%)' : 'translate(0, -50%)'}; + left: 20px; + `; + } else { + return ` + transform: ${p.showing ? 'rotate(270deg)' : 'rotate(180deg)'} ${p.showing ? 'translate(100%, 0%)' : 'translate(0, 50%)'}; + right: 20px; + ` + } + }} + + top: 50%; + svg { + width: 12px !important; + * { + fill: ${p=>!p.showing ? '#afafaf' : '#000000'}; + transition: fill 0.5s ease; + } + } +`; +const Content = styled.div` + max-height: ${p=>p.show?'5000px':'0'}; + overflow: hidden; + transition: max-height 0.7s ease; +`; + +const ActionButton = styled.button` + outline: none; + padding: 0; + cursor: pointer; + width: 100%; + padding-${p=>p.theme.isArabic?'left':'right'}: 20px; + position: relative; +`; + +class CollapsingSection extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function + constructor(props) { + super(); + this.state = { + showContent: props.isShown || false + } + } + + toggleContent() { + ("Hello WorldX"); + this.setState({showContent: !this.state.showContent} ); + } + + render() { + return ( + + + + this.props.onClick() : this.toggleContent.bind(this)}> +
{ this.props.header }
+ + + +
+
+ + {React.Children.toArray(this.props.children)} + +
+
+ ); + } +} + +CollapsingSection.propTypes = { + // header: React.PropTypes.object.required + onClick: React.PropTypes.func +}; + +export default CollapsingSection; diff --git a/app/components/CollapsingSection/tests/index.test.js b/app/components/CollapsingSection/tests/index.test.js new file mode 100644 index 0000000..3aa47ca --- /dev/null +++ b/app/components/CollapsingSection/tests/index.test.js @@ -0,0 +1,10 @@ +// import React from 'react'; +// import { shallow } from 'enzyme'; + +// import CollapsingSection from '../index'; + +describe('', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(false); + }); +}); diff --git a/app/components/CommonComponents/constants.js b/app/components/CommonComponents/constants.js index ba123a1..e004471 100644 --- a/app/components/CommonComponents/constants.js +++ b/app/components/CommonComponents/constants.js @@ -16,3 +16,4 @@ export const DEVELOPMENT_ENDPOINT = 'https://api-develop.beautifulrising.org/api export const MODULE_TYPE_FULL = 'full'; export const MODULE_TYPE_GALLERY = 'gallery'; export const MODULE_TYPE_UNTRANSLATED = 'untranslated'; +export const MODULE_TYPE_SNAPSHOT = 'snapshot'; diff --git a/app/components/CommonComponents/index.js b/app/components/CommonComponents/index.js index 408e236..7de1ca6 100644 --- a/app/components/CommonComponents/index.js +++ b/app/components/CommonComponents/index.js @@ -30,7 +30,7 @@ export const getToolTypeColor = (type) => { return "#ff9200"; case "principle": case "principles": - return "#166ce3"; + return "#0088ff"; case "theory": case "theories": return "#f93732"; diff --git a/app/components/ContentBlock/index.js b/app/components/ContentBlock/index.js index 4271530..6e79ecb 100644 --- a/app/components/ContentBlock/index.js +++ b/app/components/ContentBlock/index.js @@ -27,4 +27,8 @@ export default styled.div` }; font-family: Avenir, Kaff, sans-serif; + + p:last-child { + margin-bottom: 0; + } `;; diff --git a/app/components/ContinentIcon/index.js b/app/components/ContinentIcon/index.js index cbc7233..4eac2a1 100644 --- a/app/components/ContinentIcon/index.js +++ b/app/components/ContinentIcon/index.js @@ -12,6 +12,8 @@ import Isvg from 'react-inlinesvg'; import ContentBlock from 'components/ContentBlock'; import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import { WhereWhen } from 'components/ToolPage/Header'; + import messages from './messages'; import Africa from 'assets/images/regions/africa.svg'; import APOceania from 'assets/images/regions/asia-pacific-oceania.svg'; @@ -23,21 +25,30 @@ import NorthAmerica from 'assets/images/regions/north-america.svg'; const Content = styled.div` top: 0; - ${p=>p.lang==='ar'?'left':'right'}: 50px; text-align: ${p=>p.lang==='ar'?'left':'right'}; - position: absolute; + margin-bottom: 20px; + + @media(max-width: 1170px) { + display: inline-block; + + .where-when-desktop { display: none; } + } `; +const DesktopContent = styled.div` + display: block; + @media(max-width: 1170px) { + display: none; + } +`; const Continent = styled.div` svg { height: 40px; margin-top: 10px;} svg * { fill: #08eb8c; } -`; -const WhereWhen = styled.div` - font-weight: 800; - color: white; - text-transform: uppercase; + @media(max-width: 1170px) { + margin-${p=>p.lang==='ar' ? 'left' : 'right'}: 10px; + } `; class ContinentIcon extends React.PureComponent { @@ -60,18 +71,12 @@ class ContinentIcon extends React.PureComponent { if (this.props.type !== "story") return null; const lang = this.props.intl.locale; - const where = this.props.where !== undefined ? this.props.where : ''; - const when = this.props.when !== undefined ? this.props.when : ''; return ( - - - - {`${where} ${when}`} - - - - + + + + diff --git a/app/components/ContributePage/Content.js b/app/components/ContributePage/Content.js index 12e710a..7e0ce6b 100644 --- a/app/components/ContributePage/Content.js +++ b/app/components/ContributePage/Content.js @@ -2,4 +2,5 @@ import ContentBlock from 'components/ContentBlock'; import styled from 'styled-components' export default styled(ContentBlock)` padding: 10px 60px; + text-align: center; `; diff --git a/app/components/ContributePage/ContributeTypeContainer.js b/app/components/ContributePage/ContributeTypeContainer.js index b4045ee..829e275 100644 --- a/app/components/ContributePage/ContributeTypeContainer.js +++ b/app/components/ContributePage/ContributeTypeContainer.js @@ -1,4 +1,3 @@ import styled from 'styled-components' export default styled.div` - margin-top: 95px; `; diff --git a/app/components/ContributePage/Divider.js b/app/components/ContributePage/Divider.js index 9b89eea..e24e4e5 100644 --- a/app/components/ContributePage/Divider.js +++ b/app/components/ContributePage/Divider.js @@ -1,5 +1,8 @@ import styled from 'styled-components' export default styled.div` +height: 90px; +margin-bottom: 36px; +margin-top: 24px; &::after { content: ' ' display: inline-block; diff --git a/app/components/ContributePage/Subsubtitle.js b/app/components/ContributePage/Subsubtitle.js index dfbe64c..2b43751 100644 --- a/app/components/ContributePage/Subsubtitle.js +++ b/app/components/ContributePage/Subsubtitle.js @@ -1,7 +1,7 @@ import styled from 'styled-components' export default styled.h3` font-weight: 800; font-family: 'Avenir', 'Kaff', sans-serif; - font-size: 18px; + font-size: 19px; letter-spacing: 0; margin-top: 30px; margin-bottom: 0px; diff --git a/app/components/ContributePage/Subtitle.js b/app/components/ContributePage/Subtitle.js index 652d0be..2cabf38 100644 --- a/app/components/ContributePage/Subtitle.js +++ b/app/components/ContributePage/Subtitle.js @@ -2,8 +2,9 @@ import SmallHeaderBlock from 'components/SmallHeaderBlock'; import styled from 'styled-components' export default styled(SmallHeaderBlock)` border-bottom: 2px solid; - padding-bottom: 20px; + padding-bottom: 12px; margin-bottom: 40px; margin-left: 30px; margin-right: 30px; + text-align: center; `; diff --git a/app/components/ContributeType/Button.js b/app/components/ContributeType/Button.js index c1daaba..00cfccb 100644 --- a/app/components/ContributeType/Button.js +++ b/app/components/ContributeType/Button.js @@ -3,4 +3,10 @@ import styled from 'styled-components'; export default styled.button` outline: none; cursor: pointer; + + @media(max-width: 1170px) { + .isvg { + display: none; + } + } `; diff --git a/app/components/ContributeType/Content.js b/app/components/ContributeType/Content.js index 35bd9ba..a5c88fd 100644 --- a/app/components/ContributeType/Content.js +++ b/app/components/ContributeType/Content.js @@ -2,4 +2,8 @@ import styled from 'styled-components'; export default styled.div` display: ${props=>props.show?'block':'none'}; + + @media(max-width: 1170px) { + display: none; + } `; diff --git a/app/components/ContributeType/ExampleContainer.js b/app/components/ContributeType/ExampleContainer.js new file mode 100644 index 0000000..45f3ff4 --- /dev/null +++ b/app/components/ContributeType/ExampleContainer.js @@ -0,0 +1,15 @@ +import styled from 'styled-components'; + +export default styled.div` + display: flex; + + @media(max-width: 1170px) { + display: block; + text-align: center; + + & > div { + display: inline-block; + float: none; + } + } +`; diff --git a/app/components/ContributeType/Examples.js b/app/components/ContributeType/Examples.js index d8e1acc..10d17fb 100644 --- a/app/components/ContributeType/Examples.js +++ b/app/components/ContributeType/Examples.js @@ -1,4 +1,9 @@ import styled from 'styled-components'; export default styled.div` +&::after { + content: ' '; + display: block; + clear: both; +} `; diff --git a/app/components/ContributeType/Type.js b/app/components/ContributeType/Type.js index d3c3dc7..e7657df 100644 --- a/app/components/ContributeType/Type.js +++ b/app/components/ContributeType/Type.js @@ -6,6 +6,7 @@ export default styled.li` list-style: none; width: 18%; margin-right: 2%; + opacity: ${p=>p.isChosen?1:0.5}; &:last-child { margin-right: 0; } @@ -13,4 +14,11 @@ export default styled.li` svg { width: 100%; } + + @media(max-width: 1170px) { + width: auto; + padding: 0; + margin-bottom: 0; + display: inline-block; + } `; diff --git a/app/components/HeaderBlock/index.js b/app/components/HeaderBlock/index.js new file mode 100644 index 0000000..982020e --- /dev/null +++ b/app/components/HeaderBlock/index.js @@ -0,0 +1,12 @@ +/** +* +* HeaderBlock +* +*/ + +import React from 'react'; +import styled from 'styled-components'; + +export default styled.h2` + text-align: ${p=>p.theme.isArabic?'right':'left'} +`; diff --git a/app/components/Stage/tests/index.test.js b/app/components/HeaderBlock/tests/index.test.js similarity index 68% rename from app/components/Stage/tests/index.test.js rename to app/components/HeaderBlock/tests/index.test.js index 500242a..8c4e023 100644 --- a/app/components/Stage/tests/index.test.js +++ b/app/components/HeaderBlock/tests/index.test.js @@ -1,9 +1,9 @@ // import React from 'react'; // import { shallow } from 'enzyme'; -// import Stage from '../index'; +// import HeaderBlock from '../index'; -describe('', () => { +describe('', () => { it('Expect to have unit tests specified', () => { expect(true).toEqual(false); }); diff --git a/app/components/HomePage/BlockView/BlockContainer.js b/app/components/HomePage/BlockView/BlockContainer.js new file mode 100644 index 0000000..007af56 --- /dev/null +++ b/app/components/HomePage/BlockView/BlockContainer.js @@ -0,0 +1,19 @@ +import styled from 'styled-components'; +import {ToolContainer} from '../Tools'; + +export default styled(ToolContainer)` + background-image: ${props => props.background}; + background-size: cover; + background-position: center; + width: 270px; + height: 270px; + margin-${p=>p.lang==='ar'?'left':'right'}: ${p=>p.index%3===0?'0':'30px'}; + margin-bottom: 30px; + + + @media(max-width: 1170px) { + width: 350px; + height: 350px; + margin: 10px; + } +`; diff --git a/app/components/HomePage/BlockView/BlockSpiel.js b/app/components/HomePage/BlockView/BlockSpiel.js new file mode 100644 index 0000000..42a4b5f --- /dev/null +++ b/app/components/HomePage/BlockView/BlockSpiel.js @@ -0,0 +1,21 @@ +import styled from 'styled-components'; + +import ContentBlock from 'components/ContentBlock'; +import { getToolTypeColor } from 'components/CommonComponents'; + + +export default styled(ContentBlock)` + color: #FFFFFF; + position: absolute; + top: 40px; + left: 0; + padding: 0 10px; + font-weight: 400; + text-align: center; + + opacity: 0; + @media(min-width: 1170px) { + opacity: ${props=>props.show?(props.forceShow?'0':'1'):'0'}; + transition: opacity 0.2s; + } +`; diff --git a/app/components/HomePage/BlockView/BlockViewTitleArea.js b/app/components/HomePage/BlockView/BlockViewTitleArea.js new file mode 100644 index 0000000..bcce08a --- /dev/null +++ b/app/components/HomePage/BlockView/BlockViewTitleArea.js @@ -0,0 +1,15 @@ +import styled from 'styled-components'; + +export default styled.div` + position: absolute; + ${p=>p.theme.isArabic?'right':'left'}: 20px; + top: 40px; + padding-${p=>p.theme.isArabic?'left':'right'}: 10px; + z-index: 0; + opacity: 1; + + @media(min-width: 1170px) { + opacity: ${props=>props.show ? '1': (props.forceShow?'1':'0')}; + transition: opacity 0.2s; + } +`; diff --git a/app/components/HomePage/BlockView/BlockViewToolType.js b/app/components/HomePage/BlockView/BlockViewToolType.js new file mode 100644 index 0000000..f234472 --- /dev/null +++ b/app/components/HomePage/BlockView/BlockViewToolType.js @@ -0,0 +1,6 @@ +import { ToolType } from 'components/ToolsComponents'; +import styled from 'styled-components'; + +export default styled(ToolType)` + font-size: 32px; +`; diff --git a/app/components/HomePage/BlockView/BlockViewport.js b/app/components/HomePage/BlockView/BlockViewport.js new file mode 100644 index 0000000..48eac65 --- /dev/null +++ b/app/components/HomePage/BlockView/BlockViewport.js @@ -0,0 +1,17 @@ +import styled from 'styled-components'; +import {ToolViewport} from '../Tools'; + +const GRAYED = 'rgba(89,89,89,1)'; +const BLACKED = 'rgba(0,0,0,0.65)'; +export default styled(ToolViewport)` + + width: 100%; + height: 100%; + position: relative; + + background-color: ${BLACKED}; + @media(min-width: 1170px) { + background-color: ${p=>p.grayout&&!p.forceShow ? GRAYED : BLACKED }; + transition: background-color 0.3s ease; + } +`; diff --git a/app/components/HomePage/BlockView/index.js b/app/components/HomePage/BlockView/index.js new file mode 100644 index 0000000..87865ec --- /dev/null +++ b/app/components/HomePage/BlockView/index.js @@ -0,0 +1,13 @@ +import BlockViewTitleArea from './BlockViewTitleArea'; +import BlockContainer from './BlockContainer'; +import BlockViewport from './BlockViewport'; +import BlockSpiel from './BlockSpiel'; +import BlockViewToolType from './BlockViewToolType'; + +export { + BlockViewTitleArea, + BlockContainer, + BlockViewport, + BlockSpiel, + BlockViewToolType +} diff --git a/app/components/HomePage/Container.js b/app/components/HomePage/Container.js index 12aea35..7623676 100644 --- a/app/components/HomePage/Container.js +++ b/app/components/HomePage/Container.js @@ -1,12 +1,22 @@ import styled from 'styled-components'; export default styled.div` - // transition: padding-top 0.3s ease; - ${props=> { - if(!props.shorten) { - return `padding-top: ${props.full ? '490px' : props.isStory ? '440px' : '360px'};` - } else { - return `padding-top: ${props.full ? '290px' : props.isStory ? '240px' : '160px'};` - } - } - } -` +display: flex; + +&::after { + content: ' '; + clear: both; + display: block; +} +`; + +/* +// transition: padding-top 0.3s ease; +// ${props=> { +// if(!props.shorten) { +// return `padding-top: ${props.full ? '490px' : props.isStory ? '440px' : '360px'};` +// } else { +// return `padding-top: ${props.full ? '290px' : props.isStory ? '240px' : '160px'};` +// } +// } +// } +*/ diff --git a/app/components/HomePage/Layout/LeftSection.js b/app/components/HomePage/Layout/LeftSection.js new file mode 100644 index 0000000..6b9bc4f --- /dev/null +++ b/app/components/HomePage/Layout/LeftSection.js @@ -0,0 +1,16 @@ +import React from 'react'; +import styled from 'styled-components'; + +export default styled.section` + width: 300px; + min-width: 300px; + display: inline-block; + &::after { + clear: both; + } + + //mobile + @media(max-width: 1170px) { + display: none; + } +`; diff --git a/app/components/Stage/index.js b/app/components/HomePage/Layout/Stage.js similarity index 61% rename from app/components/Stage/index.js rename to app/components/HomePage/Layout/Stage.js index 33323ff..61d40ff 100644 --- a/app/components/Stage/index.js +++ b/app/components/HomePage/Layout/Stage.js @@ -7,13 +7,15 @@ import React from 'react'; import styled from 'styled-components'; export default styled.section` - width: 75%; - float: ${props=>props.lang==='ar' ? 'right' : 'left'}; - margin-${props=>props.lang==='ar' ? 'right' : 'left'}: 10px; + flex-grow: 1; text-align: ${props=>props.lang==='ar' ? 'right' : 'left'}; &:after { clear: both; } + + @media(max-width:600px) { + width: 100%; + } `; diff --git a/app/components/HomePage/Layout/index.js b/app/components/HomePage/Layout/index.js new file mode 100644 index 0000000..1f34341 --- /dev/null +++ b/app/components/HomePage/Layout/index.js @@ -0,0 +1,7 @@ +import Stage from './Stage'; +import LeftSection from './LeftSection'; + +export { + LeftSection, + Stage +}; diff --git a/app/components/HomePage/ListView/ListViewport.js b/app/components/HomePage/ListView/ListViewport.js new file mode 100644 index 0000000..1993106 --- /dev/null +++ b/app/components/HomePage/ListView/ListViewport.js @@ -0,0 +1,14 @@ +import {ToolViewport} from '../Tools'; +import styled from 'styled-components'; +export default styled(ToolViewport)` + background-color: none; + padding: 0; + padding-${props=>props.theme.isArabic?'left':'right'}: 0px; + padding-${props=>props.theme.isArabic?'right':'left'}: 0px; + + position: relative; + + h3 { + padding-top: 5px; + } +`; diff --git a/app/components/HomePage/ListView/index.js b/app/components/HomePage/ListView/index.js new file mode 100644 index 0000000..f5a328e --- /dev/null +++ b/app/components/HomePage/ListView/index.js @@ -0,0 +1,5 @@ +import ListViewport from './ListViewport'; + +export { + ListViewport +}; diff --git a/app/components/HomePage/MobileSectionHeader.js b/app/components/HomePage/MobileSectionHeader.js new file mode 100644 index 0000000..56ce078 --- /dev/null +++ b/app/components/HomePage/MobileSectionHeader.js @@ -0,0 +1,11 @@ +import styled from 'styled-components'; +import ContentBlock from 'components/ContentBlock'; +export default styled(ContentBlock)` + text-align: center; + width: 100%; + font-weight: 800; + text-transform: uppercase; + padding: 18px; + border-bottom: 2px solid; + margin-bottom: 32px; +`; diff --git a/app/components/HomePage/SearchResultsContainer.js b/app/components/HomePage/SearchResultsContainer.js index e017384..a5db79f 100644 --- a/app/components/HomePage/SearchResultsContainer.js +++ b/app/components/HomePage/SearchResultsContainer.js @@ -1,5 +1,5 @@ import styled from 'styled-components'; export default styled.div` - padding-${p=>p.theme.isArabic?'right':'left'}: 59px; + margin-top: 24px; color: #828486; `; diff --git a/app/components/HomePage/Tools/ToolContainer.js b/app/components/HomePage/Tools/ToolContainer.js new file mode 100644 index 0000000..3ddb976 --- /dev/null +++ b/app/components/HomePage/Tools/ToolContainer.js @@ -0,0 +1,5 @@ +import styled from 'styled-components'; +export default styled.div` + ${props=>props.lang==='ar' ? 'float: right' : 'float: left'}; + text-align: left; +`; diff --git a/app/components/HomePage/Tools/ToolViewport.js b/app/components/HomePage/Tools/ToolViewport.js new file mode 100644 index 0000000..59b9b48 --- /dev/null +++ b/app/components/HomePage/Tools/ToolViewport.js @@ -0,0 +1,5 @@ +import styled from 'styled-components'; +export default styled.div` + margin: 0; + padding: 0; +` diff --git a/app/components/HomePage/Tools/index.js b/app/components/HomePage/Tools/index.js new file mode 100644 index 0000000..98e0a00 --- /dev/null +++ b/app/components/HomePage/Tools/index.js @@ -0,0 +1,6 @@ +import ToolContainer from './ToolContainer'; +import ToolViewport from './ToolViewport'; +export { + ToolContainer, + ToolViewport +}; diff --git a/app/components/IconButton/index.js b/app/components/IconButton/index.js index 84cb831..af50ad6 100644 --- a/app/components/IconButton/index.js +++ b/app/components/IconButton/index.js @@ -12,5 +12,6 @@ export default styled.button` text-align: center; width: ${props => props.width || "20px" }; cursor: pointer; - font-family: 'Avenir', 'Kaff' + font-family: 'Avenir', 'Kaff'; + padding: 0; `; diff --git a/app/components/ImageSlideshow/index.js b/app/components/ImageSlideshow/index.js new file mode 100644 index 0000000..ea077b3 --- /dev/null +++ b/app/components/ImageSlideshow/index.js @@ -0,0 +1,131 @@ +/* + * + * ImageSlideshow + * + */ + +import React, { PropTypes } from 'react'; +import { connect } from 'react-redux'; +import styled from 'styled-components'; + + +const IMAGE_CONTAINER={ + width: '100%', + height: '100%', + backgroundSize: 'contain', + backgroundPosition: 'center center', + position: 'absolute', + top: 0, + left: 0, + transition: 'opacity 0.4s ease' +}; + +const BUTTON = { + top: '50%', + position: 'absolute', + transform: 'translate(0, -50%)', + cursor: 'pointer' +} +const PREVIOUS_BUTTON = { + left: 0, + ...BUTTON +}; + +const NEXT_BUTTON = { + right: 0, + ...BUTTON +}; + +export class ImageSlideshow extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function + + constructor(props) { + super(props); + this.state = { + chosen: 0 + } + } + + renderImages() { + if (!this.props.images) return null; + + return this.props.images.map((image, index)=>( +
+
+ )); + } + + onPrevious() { + if (this.state.chosen > 0) { + this.setState({ chosen: this.state.chosen - 1 }); + } + } + + onNext() { + if (this.state.chosen < this.props.images.length - 1) { + this.setState({ chosen: this.state.chosen + 1 }); + } + } + + renderNextButton() { + if (this.state.chosen == this.props.images.length - 1) return null; + return this.props.nextButton || this.renderDefaultNextButton(); + } + + renderDefaultNextButton() { + return (
NEXT
); + } + + + renderPreviousButton() { + if (this.state.chosen == 0) return null; + return this.props.previousButton || this.renderDefaultPreviousButton(); + } + + renderDefaultPreviousButton() { + return (
PREVIOUS
); + } + + render() { + return ( +
+ {this.renderImages()} +
+ { this.renderPreviousButton() } +
+
+ { this.renderNextButton() } +
+
+ ); + } +} + +ImageSlideshow.propTypes = { + dispatch: PropTypes.func.isRequired, +}; + + +function mapDispatchToProps(dispatch) { + return { + dispatch, + }; +} + +export default connect(null, mapDispatchToProps)(ImageSlideshow); diff --git a/app/components/ImageSlideshow/tests/index.test.js b/app/components/ImageSlideshow/tests/index.test.js new file mode 100644 index 0000000..91a0c2a --- /dev/null +++ b/app/components/ImageSlideshow/tests/index.test.js @@ -0,0 +1,10 @@ +// import React from 'react'; +// import { shallow } from 'enzyme'; + +// import { ImageSlideshow } from '../index'; + +describe('', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(false); + }); +}); diff --git a/app/components/LanguageThemeProvider/index.js b/app/components/LanguageThemeProvider/index.js index 2cf8aaf..5b102d3 100644 --- a/app/components/LanguageThemeProvider/index.js +++ b/app/components/LanguageThemeProvider/index.js @@ -11,6 +11,8 @@ import { injectIntl } from 'react-intl'; const Container = styled.div` height: inherit; width: 100%; + + direction: ${p=>p.theme.isArabic ? 'rtl':'ltr'}; `; class LanguageThemeProvider extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function render() { diff --git a/app/components/LatinThemeProvider/index.js b/app/components/LatinThemeProvider/index.js index 64233a1..77ad176 100644 --- a/app/components/LatinThemeProvider/index.js +++ b/app/components/LatinThemeProvider/index.js @@ -10,6 +10,7 @@ import styled, { ThemeProvider } from 'styled-components'; const Container = styled.div` height: inherit; width: 100%; + direction: ltr; `; class LatinThemeProvider extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function render() { diff --git a/app/components/Logo/index.js b/app/components/Logo/index.js index 61fffc2..e0d0b06 100644 --- a/app/components/Logo/index.js +++ b/app/components/Logo/index.js @@ -15,8 +15,16 @@ const Title = styled.h1` position: absolute; background-color: ${props=>props.withBg ? 'white' : 'transparent'}; top: ${props=> props.top || '0' }; - ${props=>props.lang==='ar'?'right':'left'}: ${props=>props.left || '100px'}; + left: 50%; margin: 0; + transform: translate(-50%, 0); + + @media(max-width: 1170px) { + top: ${props=> props.top || '-15px' }; + img { + width: 170px; + } + } `; class Logo extends React.Component { diff --git a/app/components/Menu/MenuArea.js b/app/components/Menu/MenuArea.js index ffefb36..bae2c51 100644 --- a/app/components/Menu/MenuArea.js +++ b/app/components/Menu/MenuArea.js @@ -1,14 +1,29 @@ import styled from 'styled-components'; export default styled.div` +width: 1170px; text-align: ${props=>props.lang==='ar'?'right':'left'}; +direction: ${p=>p.lang==='ar'?'rtl':'ltr'}; +display: inline-block; &::before { + // content: ' '; + // position: absolute; + // top: 67px; + // left: ${props=>props.lang==='ar'?'3px':'115px'}; + // background-color: white; + // z-index: 0; + // width: 182px; + // height: 20px; +} + +&::after { content: ' '; - position: absolute; - top: 67px; - left: ${props=>props.lang==='ar'?'3px':'115px'}; - background-color: white; - z-index: 0; - width: 182px; - height: 20px; + display: block; + clear: both; +} + +// Mobile +@media(max-width: 1170px) { + max-width: 100%; + width: 100%; } `; diff --git a/app/components/Menu/MenuViewport.js b/app/components/Menu/MenuViewport.js new file mode 100644 index 0000000..5df6875 --- /dev/null +++ b/app/components/Menu/MenuViewport.js @@ -0,0 +1,10 @@ +import styled from 'styled-components'; + +export default styled.div` + display: flex; + width: 100%; + + @media(max-width: 1170px) { + display: block; + } +`; diff --git a/app/components/MenuBlock/index.js b/app/components/MenuBlock/index.js index 66cf06d..5d3a112 100644 --- a/app/components/MenuBlock/index.js +++ b/app/components/MenuBlock/index.js @@ -8,5 +8,19 @@ import styled from 'styled-components'; import ContentBlock from 'components/ContentBlock'; export default styled(ContentBlock)` padding: 20px; - border-bottom: 2px solid black; + border-${p=>p.isArabic?'left':'right'}: ${p=>p.last?'none':'2px solid black'}; + width: 20%; + display: inline-block; + vertical-align: top; + align-items: stretch; + text-align: ${p=>p.isArabic?'right':'left'}; + + @media(max-width: 1170px) { + width: 100%; + border: none; + + text-align: center; + border-bottom: 2px solid black; + + } `; diff --git a/app/components/MenuContactUs/EmailLink.js b/app/components/MenuContactUs/EmailLink.js index fb10fc6..871f86e 100644 --- a/app/components/MenuContactUs/EmailLink.js +++ b/app/components/MenuContactUs/EmailLink.js @@ -3,5 +3,6 @@ import styled from 'styled-components'; export default styled(MenuLink)` text-transform: none; - font-weight: none; + font-weight: normal !important; + font-size: 12px; `; diff --git a/app/components/MenuContactUs/FormContainer.js b/app/components/MenuContactUs/FormContainer.js index 4d0db60..570bf2d 100644 --- a/app/components/MenuContactUs/FormContainer.js +++ b/app/components/MenuContactUs/FormContainer.js @@ -2,7 +2,7 @@ import ContentBlock from 'components/ContentBlock'; import styled from 'styled-components'; export default styled(ContentBlock)` - border: 1px solid; + border: 2px solid black; padding: 8px; &::after { content: ''; @@ -10,19 +10,28 @@ export default styled(ContentBlock)` clear: both; } - input[type=email] { - outline: none; - padding: 2px; - float: ${p=>p.theme.isArabic?'right':'left'}; - text-align: ${p=>p.theme.isArabic?'right':'left'}; - } - button { - outline: none; - text-align: ${p=>p.theme.isArabic?'left':'right'}; - float: ${p=>p.theme.isArabic?'right':'left'}; - text-transform: uppercase; - text-decoration: underline; - font-weight: bold; - color: #828486; + form { + display: flex; + + div { + flex-grow: 1; + display: inline-block; + input[type=email] { + outline: none; + padding: 2px; + text-align: ${p=>p.theme.isArabic?'right':'left'}; + width: 100%; + } + } + button { + outline: none; + text-align: ${p=>p.theme.isArabic?'left':'right'}; + text-transform: uppercase; + text-decoration: underline; + font-weight: bold; + color: #828486; + padding: 0; + } } + `; diff --git a/app/components/MenuLink/index.js b/app/components/MenuLink/index.js index 177fb48..310eb26 100644 --- a/app/components/MenuLink/index.js +++ b/app/components/MenuLink/index.js @@ -8,15 +8,20 @@ import React from 'react'; import styled from 'styled-components'; import { Link } from 'react-router'; + +// This considers the p.to to be relative and not absolute. +// TODO: Make it so that the link allows for absolute export default styled(Link)` - text-decoration: underline; + text-decoration: ${p=>p.to === window.location.pathname ? "none" : "underline"} ;; font-weight: bold; text-transform: uppercase; - color: #828486; + color: ${p=>p.to === window.location.pathname ? "black" : "#828486"} ; display: block; padding-bottom: 0px; - margin-bottom: 12px; + margin-bottom: 20px; margin-top: 0; padding-top: 0; + font-size: 12px; + `; diff --git a/app/components/MenuSubtitle/index.js b/app/components/MenuSubtitle/index.js index 8981789..7134a56 100644 --- a/app/components/MenuSubtitle/index.js +++ b/app/components/MenuSubtitle/index.js @@ -12,4 +12,5 @@ color: #959595; font-style: italic; text-transform: none; font-size: 13px; +margin-bottom: 20px; `; diff --git a/app/components/MenuTitle/index.js b/app/components/MenuTitle/index.js index e864392..d9eb505 100644 --- a/app/components/MenuTitle/index.js +++ b/app/components/MenuTitle/index.js @@ -7,5 +7,5 @@ import styled from 'styled-components'; export default styled.h3` - margin: 10px 0 20px; + margin: 10px 0 24px; `; diff --git a/app/components/OtherResources/index.js b/app/components/OtherResources/index.js index 25c8288..cfb4bf9 100644 --- a/app/components/OtherResources/index.js +++ b/app/components/OtherResources/index.js @@ -21,10 +21,15 @@ const ResourceTypeList = styled.ul` const ResourceType = styled.li` list-style: none; position:relative; + + margin-top: 36px; `; const ResourceList = styled.ul` padding-left: 70px; + @media(max-width: 1170px) { + padding: 0; + } `; const Resource = styled.li` list-style: none; @@ -38,11 +43,19 @@ const Resource = styled.li` p { font-style: italic; } + + @media(max-width: 1170px) { + width: 100%; + padding: 0; + margin-top :10px; + p { margin: 0;} + } `; const ResourceContainer =styled.div``; const Header =styled(SmallHeaderBlock)` position: relative; + margin-bottom: 36px; &::before { position: absolute; content: ""; diff --git a/app/components/PlatformsPage/Container.js b/app/components/PlatformsPage/Container.js index dae867b..54979f8 100644 --- a/app/components/PlatformsPage/Container.js +++ b/app/components/PlatformsPage/Container.js @@ -1,5 +1,5 @@ import styled from 'styled-components'; export default styled.div` margin-top: 30px; - ${props=>props.lang==='ar'?'padding-right':'padding-left'}: 96px; + margin-bottom: 70px; `; diff --git a/app/components/PlatformsPage/ImageContent.js b/app/components/PlatformsPage/ImageContent.js index f08a41a..cf93cee 100644 --- a/app/components/PlatformsPage/ImageContent.js +++ b/app/components/PlatformsPage/ImageContent.js @@ -4,5 +4,11 @@ export default styled.div` float: ${props=>props.lang==='ar'?'right':'left'}; height: 400px; display: inline-block; - margin-top: 130px; + + @media(max-width: 1170px) { + width: 100%; + float: none; + padding: 10px; + height: 65vmin; + } `; diff --git a/app/components/PlatformsPage/Subtitle.js b/app/components/PlatformsPage/Subtitle.js index efb9d4e..8670513 100644 --- a/app/components/PlatformsPage/Subtitle.js +++ b/app/components/PlatformsPage/Subtitle.js @@ -4,5 +4,6 @@ export default styled.h3` font-family: 'Avenir', 'Kaff', sans-serif; font-size: 16px; letter-spacing: 0px; - margin-bottom: 5px; + margin-bottom: 10px; + margin-top: 10px; `; diff --git a/app/components/PlatformsPage/TextContent.js b/app/components/PlatformsPage/TextContent.js index db5e679..b68205f 100644 --- a/app/components/PlatformsPage/TextContent.js +++ b/app/components/PlatformsPage/TextContent.js @@ -6,4 +6,10 @@ export default styled.div` * { text-align: ${props=>props.lang==='ar'?'right':'left'}; } + + @media(max-width: 1170px) { + width: 100%; + float: none; + padding: 10px; + } `; diff --git a/app/components/PlatformsPage/Viewport.js b/app/components/PlatformsPage/Viewport.js index 88d0f76..4abea5a 100644 --- a/app/components/PlatformsPage/Viewport.js +++ b/app/components/PlatformsPage/Viewport.js @@ -1,5 +1,6 @@ import styled from 'styled-components'; export default styled.div` + width: 100%; display: inline-block; position: relative; `; diff --git a/app/components/RealWorldItem/index.js b/app/components/RealWorldItem/index.js index 6cf6cc0..82f7ea5 100644 --- a/app/components/RealWorldItem/index.js +++ b/app/components/RealWorldItem/index.js @@ -67,14 +67,19 @@ const Example = styled.div` position: relative; z-index: 100; font-size: 12px; - width: 342px; + width: 100%; + max-width: 342px; border: 2px solid black; ${props=> { if(props.pos % 2 == 1) { return ` margin-top: -22px; - margin-left: 90px; + left: calc(100% - 322px); + @media(max-width: 1170px) { + left: -22px; + // left: auto; + } ` } else { @@ -87,10 +92,11 @@ const Example = styled.div` }} `; const ExampleTitle = styled.h5` - line-height: 1; + margin: 0; padding: 0; font-size: 14px; + line-height: 22px; font-weight: 800; font-family: 'Avenir', sans-serif; letter-spacing: 0; a { @@ -99,10 +105,13 @@ const ExampleTitle = styled.h5` text-transform: uppercase; } `; -const ExampleDescription = styled.div` +const ExampleDescription = styled(ContentBlock)` font-style: italic; margin: 5px 0 0; padding: 0; + font-size: 12px; + line-height: 18px; + `; class RealWorldItem extends React.PureComponent { @@ -132,11 +141,9 @@ class RealWorldItem extends React.PureComponent { - - + {this.props.description} - - + diff --git a/app/components/RegionOptions/Container.js b/app/components/RegionOptions/Container.js index d0c6dee..416c909 100644 --- a/app/components/RegionOptions/Container.js +++ b/app/components/RegionOptions/Container.js @@ -1,4 +1,5 @@ import styled from 'styled-components'; export default styled.section` display: ${props=>props.inline?'inline-block':'block'}; + padding-bottom: 40px; `; diff --git a/app/components/RegionOptions/Disabled.js b/app/components/RegionOptions/Disabled.js index 7778f04..1157641 100644 --- a/app/components/RegionOptions/Disabled.js +++ b/app/components/RegionOptions/Disabled.js @@ -1,6 +1,8 @@ import styled from 'styled-components'; export default styled.span` + margin-right: 5px; svg, svg * { + width: 40px !important; fill: #dfdfdf !important; } `; diff --git a/app/components/RegionOptions/Region.js b/app/components/RegionOptions/Region.js index 93862c1..596b98b 100644 --- a/app/components/RegionOptions/Region.js +++ b/app/components/RegionOptions/Region.js @@ -1,4 +1,7 @@ import styled from 'styled-components'; export default styled.li` display: inline-block; + &:first-child { + margin-${p=>{("XXX", p.lang); return p.lang==='ar'?'left':'right'}}: 26px; + } `; diff --git a/app/components/RegionOptions/RegionLink.js b/app/components/RegionOptions/RegionLink.js index 39459b7..340a3ba 100644 --- a/app/components/RegionOptions/RegionLink.js +++ b/app/components/RegionOptions/RegionLink.js @@ -2,7 +2,30 @@ import styled from 'styled-components'; import { Link } from 'react-router'; export default styled(Link)` + text-transform: uppercase; + font-weight: 600; + font-size: 14px; + margin-right: 5px; + position: relative; + text-decoration: none; + color: ${p=>p.selected?'black':'#848383'}; + svg, svg * { + width: 40px !important; fill: ${props => props.selected ? 'black' : '#828486'} } + + &::after { + display: ${props => props.selected ? 'block' : 'none'}; + content: ' '; + height: 40px; + border: solid; + width: 0px !important; + position: absolute; + right: 50%; + bottom: -70px; + border-width: 0 1px 0 0; + transform: translate(-50%,0); + border-color: black; + } `; diff --git a/app/components/RegionOptions/Subheader.js b/app/components/RegionOptions/Subheader.js index db9d23c..3f48c9d 100644 --- a/app/components/RegionOptions/Subheader.js +++ b/app/components/RegionOptions/Subheader.js @@ -1,20 +1,20 @@ import styled from 'styled-components'; -export default styled.h3` - width: 50%; +export default styled.p` padding: 2px; - border: solid; - border-width: 0 0 2px; position: relative; display: ${props=> !props.show ? 'none' : 'block'}; + text-transform: uppercase; + font-weight: 600; + letter-spacing: 1px; - &::after { - content: ' '; - height: 40px; - border: solid; - width: 0px !important; - position: absolute; - ${p=>p.lang==='ar'?'left':'right'}: 30px; - bottom: -20px; - border-width: 0 1px 0 0; - } + // &::after { + // content: ' '; + // height: 40px; + // border: solid; + // width: 0px !important; + // position: absolute; + // ${p=>p.lang==='ar'?'left':'right'}: 30px; + // bottom: -20px; + // border-width: 0 1px 0 0; + // } `; diff --git a/app/components/SelectedTool/SelectedToolCommandItem.js b/app/components/SelectedTool/SelectedToolCommandItem.js index 7b63355..06d3bb9 100644 --- a/app/components/SelectedTool/SelectedToolCommandItem.js +++ b/app/components/SelectedTool/SelectedToolCommandItem.js @@ -7,7 +7,7 @@ export default styled.li` button { text-transform: uppercase; font-weight: bold; } color: #959595; svg * { - fill: #959595; + // fill: #959595; } .shareArea { diff --git a/app/components/SelectedTool/SelectedToolTitle.js b/app/components/SelectedTool/SelectedToolTitle.js index 1bf407a..223c993 100644 --- a/app/components/SelectedTool/SelectedToolTitle.js +++ b/app/components/SelectedTool/SelectedToolTitle.js @@ -9,11 +9,9 @@ export default styled.h3` color: black; text-decoration: none; } - &::after { + &::before { content: url(${props => props.flag }); - position: absolute; - transform: scale(.75) translate(-10px,-5px); - box-sizing: border-box; + display: block; } `; diff --git a/app/components/ShareButton/Button.js b/app/components/ShareButton/Button.js index 0e5ed93..5782738 100644 --- a/app/components/ShareButton/Button.js +++ b/app/components/ShareButton/Button.js @@ -6,8 +6,8 @@ export default styled.button` padding: 2px; text-transform: uppercase; span svg { - width: 20px; - height: 20px; + width: ${p=>p.svgSquare || '30px'}; + height: ${p=>p.svgSquare || '30px'}; * { fill: white ; diff --git a/app/components/ShareButton/MailButton.js b/app/components/ShareButton/MailButton.js index d56039d..63cde63 100644 --- a/app/components/ShareButton/MailButton.js +++ b/app/components/ShareButton/MailButton.js @@ -3,7 +3,7 @@ export default styled.a` outline: none; padding: 0; margin: 0; cursor: pointer; - padding: 5px; + padding: ${p=>p.padding || '5px'}; span svg { width: 20px; height: 20px; diff --git a/app/components/ShareButton/ShareArea.js b/app/components/ShareButton/ShareArea.js index 87de776..2d9b906 100644 --- a/app/components/ShareButton/ShareArea.js +++ b/app/components/ShareButton/ShareArea.js @@ -1,15 +1,31 @@ import styled from 'styled-components'; export default styled.div ` position: absolute; - width: 100px; - ${props=>props.lang==='ar' ? 'right' : 'left'}: 100%; + // display: ${props=>props.show?'block':'none'}; opacity: ${p=>p.show?1:0}; visibility: ${p=>p.show?'visible':'hidden'}; transition: opacity 0.2s ease; + ${p=>p.orientation&&p.orientation==='vertical'?'':'width:100px;'} + ${p=> { - a, button { + if (p.orientation && p.orientation === 'vertical') { + return ` + top: 130%; + left: 0; + `; + } else { + return ` + ${p.lang==='ar' ? 'right' : 'left'}: 100%; + `; + } + + }} + a, button { + } + button { + ${p=>p.orientation&&p.orientation==='vertical'?'display:block;':'display:inline-block;'} } `; diff --git a/app/components/SubmitRealWorldExample/Form.js b/app/components/SubmitRealWorldExample/Form.js index ea3b346..93f88f8 100644 --- a/app/components/SubmitRealWorldExample/Form.js +++ b/app/components/SubmitRealWorldExample/Form.js @@ -8,6 +8,10 @@ export default styled.form` text-align: ${props=>props.theme.lang === 'ar' ? 'right' : 'left'}; width: 100%; padding: 5px; + + &::placeholder { + font-size: 12px; + } } textarea { diff --git a/app/components/SubmitRealWorldExample/Header.js b/app/components/SubmitRealWorldExample/Header.js index 86f84cf..0c690e6 100644 --- a/app/components/SubmitRealWorldExample/Header.js +++ b/app/components/SubmitRealWorldExample/Header.js @@ -3,4 +3,5 @@ import SmallHeaderBlock from 'components/SmallHeaderBlock'; export default styled(SmallHeaderBlock)` margin: 0; margin-bottom: 5px; + margin-top: 36px; `; diff --git a/app/components/SubmitResource/Form.js b/app/components/SubmitResource/Form.js new file mode 100644 index 0000000..ea3b346 --- /dev/null +++ b/app/components/SubmitResource/Form.js @@ -0,0 +1,31 @@ +import styled from 'styled-components'; +export default styled.form` + margin-top: 36ppx; + border: 2px solid; + text-align: ${props=>props.theme.lang === 'ar' ? 'left' : 'right'}; + input { + border-bottom: 2px solid; + text-align: ${props=>props.theme.lang === 'ar' ? 'right' : 'left'}; + width: 100%; + padding: 5px; + } + + textarea { + width: 100%; + padding: 5px; + resize: none; + height: 50px; + outline: none; + } + + button { + outline: none; + cursor: pointer; + width: 70px; + text-transform: uppercase; + text-decoration: underline; + font-weight: bold; + color: #828486; + margin: 5px; + } +`; diff --git a/app/components/SubmitResource/Header.js b/app/components/SubmitResource/Header.js new file mode 100644 index 0000000..014a252 --- /dev/null +++ b/app/components/SubmitResource/Header.js @@ -0,0 +1,10 @@ +import styled from 'styled-components'; +import SmallHeaderBlock from 'components/SmallHeaderBlock'; +export default styled(SmallHeaderBlock)` + margin: 0; + margin-bottom: 5px; + text-align: center; + p { + margin: 0; + } +`; diff --git a/app/components/SubmitResource/TextArea.js b/app/components/SubmitResource/TextArea.js new file mode 100644 index 0000000..37fd753 --- /dev/null +++ b/app/components/SubmitResource/TextArea.js @@ -0,0 +1,5 @@ +import styled from 'styled-components'; +export default styled.textarea` + font-size: 14px; + line-height: 22px; +`; diff --git a/app/components/SubmitResource/TextInput.js b/app/components/SubmitResource/TextInput.js new file mode 100644 index 0000000..255df33 --- /dev/null +++ b/app/components/SubmitResource/TextInput.js @@ -0,0 +1,5 @@ +import styled from 'styled-components'; +export default styled.input` +font-size: 14px; +line-height: 22px; +`; diff --git a/app/components/Tags/ClearButtonContainer.js b/app/components/Tags/ClearButtonContainer.js index a91078b..d263930 100644 --- a/app/components/Tags/ClearButtonContainer.js +++ b/app/components/Tags/ClearButtonContainer.js @@ -1,9 +1,13 @@ import styled from 'styled-components'; export default styled.div` + position: absolute; + top: 0; + ${p=>p.theme.isArabic ? 'right': 'left'}: -44px; text-align: center; - padding-top: 20px; color: #828486; button { + cursor: pointer; + outline: none; padding-right: 0; padding-left: 0; } diff --git a/app/components/Tags/TagBlock.js b/app/components/Tags/TagBlock.js index ba36eb7..748515d 100644 --- a/app/components/Tags/TagBlock.js +++ b/app/components/Tags/TagBlock.js @@ -1,5 +1,6 @@ import ContentBlock from 'components/ContentBlock'; import styled from 'styled-components'; export default styled(ContentBlock)` + position: relative; text-align: ${props=>props.align || 'center'}` ; diff --git a/app/components/Tags/TagListItem.js b/app/components/Tags/TagListItem.js index 2a3d8a9..e062788 100644 --- a/app/components/Tags/TagListItem.js +++ b/app/components/Tags/TagListItem.js @@ -16,5 +16,14 @@ export default styled.li` a { text-decoration: ${props=>props.selected ? 'normal' : 'underline'}; color: ${props=>props.selected ? 'black' : '#828486'}; + + ${ p=>{ + if(p.selected) { + return ` + margin-left: -5px; + margin-right: -4px; + ` + } + }}; } `; diff --git a/app/components/ToolKeyItems/KeyItemListItem.js b/app/components/ToolKeyItems/KeyItemListItem.js index bb057ca..0485c93 100644 --- a/app/components/ToolKeyItems/KeyItemListItem.js +++ b/app/components/ToolKeyItems/KeyItemListItem.js @@ -1,4 +1,8 @@ import styled from 'styled-components'; export default styled.div` - margin: 10px 0; + margin: 36px 0 0; + + &:first-child { + margin-top: 0; + } `; diff --git a/app/components/ToolPage/Header/CTA.js b/app/components/ToolPage/Header/CTA.js new file mode 100644 index 0000000..a75e138 --- /dev/null +++ b/app/components/ToolPage/Header/CTA.js @@ -0,0 +1,7 @@ +import styled from 'styled-components'; + +export default styled.span` + font-size: ${p=>p.theme.ar?'16px':'14px'}; + font-family: 'Avenir', 'Kaff'; + font-weight: 800; +`; diff --git a/app/components/ToolPage/Header/Caption.js b/app/components/ToolPage/Header/Caption.js new file mode 100644 index 0000000..6899ea5 --- /dev/null +++ b/app/components/ToolPage/Header/Caption.js @@ -0,0 +1,15 @@ +import styled from 'styled-components'; +export default styled.div` + position: absolute; + bottom: 10px; + color: white; + padding-${props=>props.theme.lang==='ar'?'left':'right'}: 50px; + font-size: 14px; + display: ${props=>props.show ? 'block' : 'none'}; + + a { color: white; } + + @media(max-width: 1170px) { + display: none; + } +`; diff --git a/app/components/ToolPage/Header/Container.js b/app/components/ToolPage/Header/Container.js new file mode 100644 index 0000000..26fc343 --- /dev/null +++ b/app/components/ToolPage/Header/Container.js @@ -0,0 +1,8 @@ +import styled from 'styled-components'; +export default styled.section` + width: 100%; + height: 100%; + background-image: url(${props=>props.backgroundImage}) + background-size: cover; + background-position: center center; +`; diff --git a/app/components/ToolPage/Header/Content.js b/app/components/ToolPage/Header/Content.js new file mode 100644 index 0000000..9e8b67e --- /dev/null +++ b/app/components/ToolPage/Header/Content.js @@ -0,0 +1,13 @@ +import styled from 'styled-components'; + +export default styled.div` + position: absolute; + z-index: 100; + width: calc(100% - 90px); + height: 100%; + padding-top: 50px; + + @media(max-width: 1170px) { + padding-top: 26px; + } +`; diff --git a/app/components/ToolPage/Header/ContentViewport.js b/app/components/ToolPage/Header/ContentViewport.js new file mode 100644 index 0000000..ea6e619 --- /dev/null +++ b/app/components/ToolPage/Header/ContentViewport.js @@ -0,0 +1,7 @@ +import styled from 'styled-components'; + +export default styled.div` + width: 100%; + height: 100%; + position: relative; +`; diff --git a/app/components/ToolPage/Header/InteractiveContainer.js b/app/components/ToolPage/Header/InteractiveContainer.js new file mode 100644 index 0000000..f787f92 --- /dev/null +++ b/app/components/ToolPage/Header/InteractiveContainer.js @@ -0,0 +1,12 @@ +import styled from 'styled-components'; + +export default styled.div` + position: absolute; + top: 48px; + ${p=>p.lang==='ar'?'left':'right'}: 34px; + z-index: 200; + + @media(max-width: 1170px) { + display: none; + } +`; diff --git a/app/components/ToolPage/Header/InteractiveViewport.js b/app/components/ToolPage/Header/InteractiveViewport.js new file mode 100644 index 0000000..6de96a0 --- /dev/null +++ b/app/components/ToolPage/Header/InteractiveViewport.js @@ -0,0 +1,10 @@ +import styled from 'styled-components'; + +export default styled.div` + position: relative; + text-align: ${p=>p.theme.isArabic?'left':'right'}; + + @media(max-width: 1170px) { + text-align: ${p=>p.theme.isArabic?'right':'left'}; + } +`; diff --git a/app/components/ToolPage/Header/MobileInteractiveContainer.js b/app/components/ToolPage/Header/MobileInteractiveContainer.js new file mode 100644 index 0000000..bade984 --- /dev/null +++ b/app/components/ToolPage/Header/MobileInteractiveContainer.js @@ -0,0 +1,10 @@ +import styled from 'styled-components'; + +export default styled.div` + display: none; + + @media(max-width: 1170px) { + display: block; + zoom: 0.7; + } +`; diff --git a/app/components/ToolPage/Header/ShareContainer.js b/app/components/ToolPage/Header/ShareContainer.js new file mode 100644 index 0000000..5fa30e2 --- /dev/null +++ b/app/components/ToolPage/Header/ShareContainer.js @@ -0,0 +1,20 @@ +import styled from 'styled-components'; + +export default styled.div` + display: block; + margin-top: 11px; + svg * { + fill: white; + } + span.share-button { + margin-right: 10px; + } + color: white; + font-weight: 800; + + @media(max-width: 1170px) { + display: inline-block; + margin-top: 0; + margin-${p=>p.theme.isArabic?'right':'left'}: 5px; + } +`; diff --git a/app/components/ToolPage/Header/Title.js b/app/components/ToolPage/Header/Title.js new file mode 100644 index 0000000..c742b6b --- /dev/null +++ b/app/components/ToolPage/Header/Title.js @@ -0,0 +1,18 @@ +import styled from 'styled-components'; +import { ToolTitle } from 'components/ToolsComponents'; + +export default styled(ToolTitle)` + font-size: ${p=>p.theme.isArabic?'80px':'80px'}; + width: calc(100% - 80px); + letter-spacing: ${p=>p.theme.isArabic?'3px':'1px'}; + margin: 0 0 20px; + padding: 0; + line-height: ${p=>p.theme.isArabic?'95px':'70px'}; + + @media(max-width: 1170px) { + font-size: 30px; + line-height: ${p=>p.theme.isArabic?'28px':'28px'}; + margin-bottom: 12px; + width: 100%; + } +`; diff --git a/app/components/ToolPage/Header/ToolType.js b/app/components/ToolPage/Header/ToolType.js new file mode 100644 index 0000000..1d16ac8 --- /dev/null +++ b/app/components/ToolPage/Header/ToolType.js @@ -0,0 +1,20 @@ +import { ToolType } from 'components/ToolsComponents'; +import styled from 'styled-components'; + +export default styled(ToolType)` + font-size: ${p=>p.theme.isArabic?'50px':'40px'}; + margin-bottom: 20px; + padding: 0; + line-height: 36px; + + a { + color: inherit; + text-decoration: none; + } + + @media(max-width: 1170px) { + font-size: 21px; + line-height: 21px; + margin-bottom: 6px; + } +`; diff --git a/app/components/ToolPage/Header/Viewport.js b/app/components/ToolPage/Header/Viewport.js new file mode 100644 index 0000000..6ad3b99 --- /dev/null +++ b/app/components/ToolPage/Header/Viewport.js @@ -0,0 +1,14 @@ +import styled from 'styled-components'; +export default styled.div` + width: 100%; + height: 100%; + position: relative; + background-color: rgba(0,0,0,0.5); + text-align: ${props=>props.theme.lang === 'ar' ? 'right' : 'left'}; + padding-${props=>props.theme.lang==='ar'?'right':'left'}: 90px; + overflow: ${props=>props.showOverflow?'visible':'hidden'}; + + @media(max-width: 1170px) { + padding-${props=>props.theme.lang==='ar'?'right':'left'}: 42px; + } +`; diff --git a/app/components/ToolPage/Header/WhereWhen.js b/app/components/ToolPage/Header/WhereWhen.js new file mode 100644 index 0000000..e529dfa --- /dev/null +++ b/app/components/ToolPage/Header/WhereWhen.js @@ -0,0 +1,42 @@ +import styled from 'styled-components'; +import React from 'react'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import ContentBlock from 'components/ContentBlock'; + +const WhereWhenContainer = styled.div` + font-weight: 800; + color: white; + text-transform: uppercase; +`; + +const WhereWhenContent = styled(ContentBlock)` + + @media(max-width: 1170px) { + font-size: 8px; + line-height: 8px; + } +`; + +function WhereWhen(props) { + + const where = props.where !== undefined ? props.where : ''; + const when = props.when !== undefined ? props.when : ''; + + return ( + + + + {`${where} ${when}`} + + + + ) +} + + +WhereWhen.propTypes = { + where: React.PropTypes.string, + when: React.PropTypes.string, +}; + +export default WhereWhen; diff --git a/app/components/ToolPage/Header/index.js b/app/components/ToolPage/Header/index.js new file mode 100644 index 0000000..fda2ef5 --- /dev/null +++ b/app/components/ToolPage/Header/index.js @@ -0,0 +1,36 @@ +import styled from 'styled-components'; +import Caption from './Caption'; +import Container from './Container'; +import Content from './Content'; +import ContentViewport from './ContentViewport'; +import CTA from './CTA'; +import ShareContainer from './ShareContainer'; +import Title from './Title'; +import ToolType from './ToolType'; +import Viewport from './Viewport'; + +import InteractiveViewport from './InteractiveViewport'; +import InteractiveContainer from './InteractiveContainer'; +import WhereWhen from './WhereWhen'; +import MobileInteractiveContainer from './MobileInteractiveContainer'; + +export default styled.section` + width: 100%; + height: 430px; + + @media(max-width: 1170px) { + height: 245px; + } +`;; + +export { + Caption, Container, + Content, ContentViewport, + CTA, ShareContainer, + Title, ToolType, + Viewport, + + MobileInteractiveContainer, + WhereWhen, + InteractiveViewport, InteractiveContainer +}; diff --git a/app/components/ToolPage/Main/ByLine.js b/app/components/ToolPage/Main/ByLine.js new file mode 100644 index 0000000..e1138ba --- /dev/null +++ b/app/components/ToolPage/Main/ByLine.js @@ -0,0 +1,6 @@ +import styled from 'styled-components'; + +export default styled.div` + font-weight: 800; + text-transform: uppercase; +`; diff --git a/app/components/ToolPage/Main/CollapsingContent.js b/app/components/ToolPage/Main/CollapsingContent.js new file mode 100644 index 0000000..c7d7524 --- /dev/null +++ b/app/components/ToolPage/Main/CollapsingContent.js @@ -0,0 +1,6 @@ +import ContentContainer from './ContentContainer'; +import styled from 'styled-components'; + +export default styled(ContentContainer)` + padding-${p=>p.theme.isArabic?'right':'left'}: 16px; +`; diff --git a/app/components/ToolPage/Main/CollapsingHeader.js b/app/components/ToolPage/Main/CollapsingHeader.js new file mode 100644 index 0000000..bc6c2fc --- /dev/null +++ b/app/components/ToolPage/Main/CollapsingHeader.js @@ -0,0 +1,13 @@ +import styled from 'styled-components'; + +export default styled.h5` + font-size: ${p=>p.theme.isArabic ? '16px' : '18px'}; + text-transform: uppercase; + font-weight: bold; + font-family: 'Avenir', 'Kaff', 'sans-serif'; + margin: 0; + text-align: ${p=>p.theme.isArabic?'right':'left'}; + padding-top: 32px; + padding-bottom: 31px; + padding-${p=>p.theme.isArabic?'right':'left'}: 16px; +`; diff --git a/app/components/ToolPage/Main/Container.js b/app/components/ToolPage/Main/Container.js new file mode 100644 index 0000000..92c1fb2 --- /dev/null +++ b/app/components/ToolPage/Main/Container.js @@ -0,0 +1,13 @@ +import styled from 'styled-components'; + +export default styled.div` + flex-grow: 1; + padding: ${p=>p.theme.isArabic?'0 86px 0 136px':'0 136px 0 86px'}; + padding-top: 48px; + + @media(max-width: 1170px) { + flex-wrap: wrap; + padding: 32px; + padding-${p=>p.theme.isArabic?'left':'right'}: 20px; + } +`; diff --git a/app/components/ToolPage/Main/ContentContainer.js b/app/components/ToolPage/Main/ContentContainer.js new file mode 100644 index 0000000..6709a4f --- /dev/null +++ b/app/components/ToolPage/Main/ContentContainer.js @@ -0,0 +1,16 @@ +import styled from 'styled-components'; + +export default styled.article` + display: block; + width: 100%; + * { + p img { + width: 100%; + } + } + &::after { + display: block; + content: ' '; + clear: both; + } +`; diff --git a/app/components/ToolPage/Main/Epigraph.js b/app/components/ToolPage/Main/Epigraph.js new file mode 100644 index 0000000..4053ebe --- /dev/null +++ b/app/components/ToolPage/Main/Epigraph.js @@ -0,0 +1,15 @@ +import styled from 'styled-components'; + +export default styled.div` + padding-left: 15px; + text-align: ${p=>p.ar?'right':'left'}; + & p:last-child { + color: gray; + } + + p { + margin: 0; + } + + margin: 36px 0; +`; diff --git a/app/components/ToolPage/Main/PullQuote.js b/app/components/ToolPage/Main/PullQuote.js new file mode 100644 index 0000000..ea65dbb --- /dev/null +++ b/app/components/ToolPage/Main/PullQuote.js @@ -0,0 +1,29 @@ +import styled from 'styled-components'; + +export default styled.blockquote` + float: ${p=>p.theme.isArabic?'right':'left'}; + padding: 0; + margin: 20px 0; + + line-height: 30px; + max-width: 230px; + width: 230px; + padding: 10px 0; + margin-right: 40px; + p, div, span { + font-family: 'Paint Hand', 'Massira Spray', serif; + display: inline; + } + + text-transform: uppercase; + position: relative; + + font-size: 20px; + + @media(max-width: 1170px) { + width: 100%; + max-width: 100%; + padding: 0 30px; + text-align: center; + } +`; diff --git a/app/components/ToolPage/Main/ShortContentContainer.js b/app/components/ToolPage/Main/ShortContentContainer.js new file mode 100644 index 0000000..6998c37 --- /dev/null +++ b/app/components/ToolPage/Main/ShortContentContainer.js @@ -0,0 +1,7 @@ +import styled from 'styled-components'; + +export default styled.div` + p img { + width: 100% !important; + } +`; diff --git a/app/components/ToolPage/Main/ShowContentButton.js b/app/components/ToolPage/Main/ShowContentButton.js new file mode 100644 index 0000000..5ecae3b --- /dev/null +++ b/app/components/ToolPage/Main/ShowContentButton.js @@ -0,0 +1,7 @@ +import { BorderedButton } from 'components/CommonComponents'; +import styled from 'styled-components'; + +export default styled(BorderedButton)` + margin-top: 36px; + padding: 7px 30px 6px; +`; diff --git a/app/components/ToolPage/Main/index.js b/app/components/ToolPage/Main/index.js new file mode 100644 index 0000000..a37a56f --- /dev/null +++ b/app/components/ToolPage/Main/index.js @@ -0,0 +1,15 @@ +import Container from './Container'; +import ContentContainer from './ContentContainer'; +import PullQuote from './PullQuote'; +import Epigraph from './Epigraph'; +import ShowContentButton from './ShowContentButton'; +import ByLine from './ByLine'; +import CollapsingHeader from './CollapsingHeader'; +import CollapsingContent from './CollapsingContent'; +import ShortContentContainer from './ShortContentContainer'; + +export default Container; + +export { ContentContainer, Epigraph, PullQuote, + ShowContentButton, ByLine, CollapsingHeader, + CollapsingContent, ShortContentContainer }; diff --git a/app/components/ToolPage/RelatedTools/Container.js b/app/components/ToolPage/RelatedTools/Container.js new file mode 100644 index 0000000..9f949c9 --- /dev/null +++ b/app/components/ToolPage/RelatedTools/Container.js @@ -0,0 +1,4 @@ +import styled from 'styled-components'; +export default styled.div` + text-align: ${p=>p.lang==='ar' ? 'right' : 'left'}; +`; diff --git a/app/components/ToolPage/RelatedTools/List.js b/app/components/ToolPage/RelatedTools/List.js new file mode 100644 index 0000000..95d9cbe --- /dev/null +++ b/app/components/ToolPage/RelatedTools/List.js @@ -0,0 +1,6 @@ +import styled from 'styled-components'; +export default styled.ul` + padding: 0; + margin: 0; + margin-${p=>p.lang==='ar'?'right':'left'}: 18px; +`; diff --git a/app/components/ToolPage/RelatedTools/ListItem.js b/app/components/ToolPage/RelatedTools/ListItem.js new file mode 100644 index 0000000..414e3ab --- /dev/null +++ b/app/components/ToolPage/RelatedTools/ListItem.js @@ -0,0 +1,8 @@ +import styled from 'styled-components'; +export default styled.li` + list-style: none; + text-transform: uppercase; + font-weight: bold; + margin-bottom: 12px; + font-size: 14px; +`; diff --git a/app/components/ToolPage/RelatedTools/ToolLink.js b/app/components/ToolPage/RelatedTools/ToolLink.js new file mode 100644 index 0000000..652a91e --- /dev/null +++ b/app/components/ToolPage/RelatedTools/ToolLink.js @@ -0,0 +1,7 @@ +import { Link } from 'react-router'; +import styled from 'styled-components'; + +export default styled(Link)` + color: black; + text-decoration: underline; +`; diff --git a/app/components/ToolPage/RelatedTools/index.js b/app/components/ToolPage/RelatedTools/index.js new file mode 100644 index 0000000..2f0b59d --- /dev/null +++ b/app/components/ToolPage/RelatedTools/index.js @@ -0,0 +1,6 @@ +import Container from './Container'; +import List from './List'; +import ListItem from './ListItem'; +import ToolLink from './ToolLink'; + +export { Container, List, ListItem, ToolLink }; diff --git a/app/components/ToolPage/Sidebar/BigHeader.js b/app/components/ToolPage/Sidebar/BigHeader.js new file mode 100644 index 0000000..5cd734c --- /dev/null +++ b/app/components/ToolPage/Sidebar/BigHeader.js @@ -0,0 +1,6 @@ +import Header from './Header'; +import styled from 'styled-components'; +export default styled(Header)` + font-size: ${p=>p.theme.isArabic?'30px':'40px'}; + padding-${p=>p.theme.isArabic?'right':'left'}: 52px; +`; diff --git a/app/components/ToolPage/Sidebar/Container.js b/app/components/ToolPage/Sidebar/Container.js new file mode 100644 index 0000000..4f637f5 --- /dev/null +++ b/app/components/ToolPage/Sidebar/Container.js @@ -0,0 +1,11 @@ +import styled from 'styled-components'; + +export default styled.div` + padding-top: 49px; + width: 370px; + min-width: 370px; + + @media(max-width: 1170px) { + display: none; + } +`; diff --git a/app/components/ToolPage/Sidebar/Header.js b/app/components/ToolPage/Sidebar/Header.js new file mode 100644 index 0000000..c1ff4dc --- /dev/null +++ b/app/components/ToolPage/Sidebar/Header.js @@ -0,0 +1,11 @@ +import styled from 'styled-components'; +export default styled.h3` + font-size: ${p=>p.theme.lang==='ar'?'30px':'30px'}; + text-transform: uppercase; + position: relative; + margin: 0; + border-bottom: 2px solid; + padding-bottom: 0; + + text-align: ${p=>p.theme.isArabic?'right':'left'}; +`; diff --git a/app/components/ToolPage/Sidebar/RelatedHeader.js b/app/components/ToolPage/Sidebar/RelatedHeader.js new file mode 100644 index 0000000..afdbb2e --- /dev/null +++ b/app/components/ToolPage/Sidebar/RelatedHeader.js @@ -0,0 +1,8 @@ +import Header from './Header'; +import styled from 'styled-components'; + +export default styled(Header)` + border-bottom: none; + margin-top: 36px; + margin-bottom: 16px; +` diff --git a/app/components/ToolPage/Sidebar/SidebarContent.js b/app/components/ToolPage/Sidebar/SidebarContent.js new file mode 100644 index 0000000..43fca68 --- /dev/null +++ b/app/components/ToolPage/Sidebar/SidebarContent.js @@ -0,0 +1,5 @@ +import styled from 'styled-components'; + +export default styled.div` + padding-bottom: 42px; +`; diff --git a/app/components/ToolPage/Sidebar/WhyItIcon.js b/app/components/ToolPage/Sidebar/WhyItIcon.js new file mode 100644 index 0000000..26493eb --- /dev/null +++ b/app/components/ToolPage/Sidebar/WhyItIcon.js @@ -0,0 +1,7 @@ +import styled from 'styled-components'; + +export default styled.div` + position: absolute; + ${p=>p.theme.isArabic?'right':'left'}: 0; + top: -1px; +`; diff --git a/app/components/ToolPage/Sidebar/index.js b/app/components/ToolPage/Sidebar/index.js new file mode 100644 index 0000000..61bc3b2 --- /dev/null +++ b/app/components/ToolPage/Sidebar/index.js @@ -0,0 +1,9 @@ +import Container from './Container'; +import SidebarContent from './SidebarContent'; +import Header from './Header'; +import RelatedHeader from './RelatedHeader'; +import WhyItIcon from './WhyItIcon'; +import BigHeader from './BigHeader'; +export default Container; + +export { SidebarContent, Header, RelatedHeader, WhyItIcon, BigHeader }; diff --git a/app/components/ToolPage/Snapshot/Button.js b/app/components/ToolPage/Snapshot/Button.js new file mode 100644 index 0000000..1027bbf --- /dev/null +++ b/app/components/ToolPage/Snapshot/Button.js @@ -0,0 +1,19 @@ +import styled from 'styled-components'; + +export default styled.button` + cursor: pointer; + outline: none; + position: relative; + display: inline-block; + margin: 0; + padding: 0; + + color: black; + text-decoration: underline; + + text-transform: uppercase; + + font-weight: bold; + + text-align: ${p=>p.isArabic?'right':'left'}; +`; diff --git a/app/components/ToolPage/Snapshot/Container.js b/app/components/ToolPage/Snapshot/Container.js new file mode 100644 index 0000000..8f21a9f --- /dev/null +++ b/app/components/ToolPage/Snapshot/Container.js @@ -0,0 +1,10 @@ +import styled from 'styled-components'; + +export default styled.div` + + width: 100%; + height: 100%; + position: relative; + background-color: white; + +`; diff --git a/app/components/ToolPage/Snapshot/OverlayText.js b/app/components/ToolPage/Snapshot/OverlayText.js new file mode 100644 index 0000000..153262c --- /dev/null +++ b/app/components/ToolPage/Snapshot/OverlayText.js @@ -0,0 +1,28 @@ +import styled from 'styled-components'; +import ContentBlock from 'components/ContentBlock'; + +export default styled.div` + width: 100%; + height: 136px; + position: absolute; + bottom: 0; + left: 0; + + background-color: white; + padding: 44px 60px 10px; + font-weight: bold; + font-size: 20px; + z-index: 700; + a { color: #828487; } + + * { + margin: 0; + } + &::before { + content: '*'; + position: absolute; + ${p=>p.theme.isArabic?'right':'left'}: 45px; + font-size: 26px; + top: 40px; + } +` diff --git a/app/components/ToolPage/Snapshot/SnapshotText.js b/app/components/ToolPage/Snapshot/SnapshotText.js new file mode 100644 index 0000000..37d9d83 --- /dev/null +++ b/app/components/ToolPage/Snapshot/SnapshotText.js @@ -0,0 +1,12 @@ +import styled from 'styled-components'; +import ContentBlock from 'components/ContentBlock'; + +export default styled(ContentBlock) ` + font-size: ${p=>p.theme.isArabic?'14px':'16px'}; + line-height: ${p=>p.theme.isArabic?'23px':'22px'}; + font-weight: bold; + color: white; + max-width: 480px; + display: inline-block; + margin-top: 36px; +` diff --git a/app/components/ToolPage/Snapshot/Title.js b/app/components/ToolPage/Snapshot/Title.js new file mode 100644 index 0000000..a59858c --- /dev/null +++ b/app/components/ToolPage/Snapshot/Title.js @@ -0,0 +1,8 @@ +import styled from 'styled-components'; +import Title from 'components/ToolPage/Header/Title'; + +export default styled(Title)` + margin: 0; + width: 100%; + padding-${p=>p.theme.isArabic?'left':'right'}: 20px; +`; diff --git a/app/components/ToolPage/Snapshot/Viewport.js b/app/components/ToolPage/Snapshot/Viewport.js new file mode 100644 index 0000000..1c499a7 --- /dev/null +++ b/app/components/ToolPage/Snapshot/Viewport.js @@ -0,0 +1,6 @@ +import { Viewport } from 'components/ToolPage/Header'; +import styled from 'styled-components'; + +export default styled(Viewport)` + padding-${p=>p.theme.isArabic?'right':'left'}: 60px; +`; diff --git a/app/components/ToolPage/Snapshot/index.js b/app/components/ToolPage/Snapshot/index.js new file mode 100644 index 0000000..bdcf3a1 --- /dev/null +++ b/app/components/ToolPage/Snapshot/index.js @@ -0,0 +1,8 @@ +import Button from './Button'; +import Container from './Container'; +import SnapshotText from './SnapshotText'; +import Viewport from './Viewport'; +import OverlayText from './OverlayText'; +import Title from './Title'; + +export { Button, SnapshotText, Viewport, OverlayText, Title, Container}; diff --git a/app/components/ToolPage/Stage.js b/app/components/ToolPage/Stage.js new file mode 100644 index 0000000..256acba --- /dev/null +++ b/app/components/ToolPage/Stage.js @@ -0,0 +1,14 @@ +import styled from 'styled-components'; +export default styled.section` + width: 100%; + display: flex; + &::after { + content: ' '; + clear: both; + display: block; + } + + @media(max-width: 1170px) { + display: block; + } +`; diff --git a/app/components/ToolPage/index.js b/app/components/ToolPage/index.js new file mode 100644 index 0000000..e69de29 diff --git a/app/components/ToolTypeAllFull/Row.js b/app/components/ToolTypeAllFull/Row.js index 89f3e50..8692a4e 100644 --- a/app/components/ToolTypeAllFull/Row.js +++ b/app/components/ToolTypeAllFull/Row.js @@ -2,9 +2,8 @@ import styled from 'styled-components'; export default styled.div` text-align: center; - &:first-child { - margin-bottom: 22px; - } + margin-bottom: 38px; + &::after { content: ' '; clear: both; diff --git a/app/components/ToolTypeAllFull/ToolType.js b/app/components/ToolTypeAllFull/ToolType.js index bb2970c..aef2eb2 100644 --- a/app/components/ToolTypeAllFull/ToolType.js +++ b/app/components/ToolTypeAllFull/ToolType.js @@ -20,4 +20,8 @@ export default styled(Link)` vertical-align: top; } + @media(max-width: 1170px) { + width: 100%; + text-align: center; + } `; diff --git a/app/components/ToolsComponents/index.js b/app/components/ToolsComponents/index.js index a79f6f5..732c9f2 100644 --- a/app/components/ToolsComponents/index.js +++ b/app/components/ToolsComponents/index.js @@ -26,7 +26,7 @@ export const getToolTypeColor = (type) => { case TYPE_TACTICS: return "#ff9200"; case TYPE_PRINCIPLES: - return "#166ce3"; + return "#0088ff"; case TYPE_THEORIES: return "#f93732"; case TYPE_METHODOLOGIES: @@ -83,7 +83,6 @@ export const ToolsButton = styled.button` export const ToolsListMenu = styled.ul` padding: 0; padding: 10px 0 10px; - border-bottom: 2px solid black; margin: 0; display: ${props=>props.show?'block':'none'}; @@ -100,7 +99,7 @@ export const ToolsListMenuItem = styled.li` export const ToolType = styled.h3` margin: 0; - font-size: ${p=>p.ar?'35px':'20px'}; + font-size: ${p=>p.ar?'32px':'20px'}; letter-spacing: ${p=>p.ar?'3px':'0'}; text-align: ${p=>p.theme.isArabic?'right':'left'}; padding-top: 20px; @@ -113,7 +112,7 @@ export const ToolTitle = styled.h1` letter-spacing: 1px; font-weight: normal; margin: 0; - margin-bottom: ${p=>p.theme.isArabic?'5px':'0'}; + margin-bottom: 26px; text-align: ${p=>p.theme.isArabic?'right':'left'}; font-size: ${p=>p.theme.isArabic?'30px':'30px'}; line-height: 1; @@ -129,7 +128,7 @@ margin: 0; `; export const ToolsListItem = styled.li` list-style: none; - margin: 10px 10px 20px; + margin: 10px 10px 30px; border-top: 2px solid; &:first-child { @@ -143,12 +142,21 @@ export const ToolsMenu = styled.ul` height: 100%; margin: 0; padding: 20px 0; - border: solid black; - border-width: ${props=>props.theme.lang === 'ar' ? '0 0 0 2px' : '0 2px 0 0'}; + // border: solid black; + // border-width: ${props=>props.theme.lang === 'ar' ? '0 0 0 2px' : '0 2px 0 0'}; + @media(max-width: 1170px) { + display: flex; + padding: 0; + width: 100%; + border: none; + } `; export const ToolsMenuItem = styled.li` list-style: none; - margin: 10px 0 20px; + margin: 10px 0; + + margin-bottom: ${p=> p.marginBottom || '20px'}; + .isvg { &::after { content: ' '; @@ -156,6 +164,10 @@ export const ToolsMenuItem = styled.li` clear: both; } } + + @media(max-width: 1170px) { + flex-grow: 1; + } `; export const ToolsListContainer = styled.div``; @@ -167,99 +179,56 @@ export const ToolsContainer = styled.div` position: fixed; width: ${(props) => props.showTools ? '350px' : '75px' }; - height: calc(100vh - 170px); + height: calc(100vh - 220px) border: 2px solid black; - top: 93px; + // top: 217px; + + bottom: 0; + border-width: ${props=>props.lang == 'ar' ? '2px 2px 0 0' : '2px 0 0 2px'}; - ${props=>props.theme.lang == 'ar' ? 'left: 50%' : 'right: 50%;'} - transform: translateX(${(props) => props.showTools ? - (props=>props.theme.lang == 'ar' ? '-685px' : '685px') : - (props=>props.theme.lang == 'ar' ? '-640px' : '640px') }); + ${props=>props.lang == 'ar' ? 'left: 0;' : 'right: 0;'} transition: transform 0.3s ease, width 0.3s ease; overflow-x: hidden; overflow-y: hidden; - `; + + //mobile + @media(max-width: 1170px) { + position: fixed; + bottom: 0; + top: auto; + left: 0; + width: 100vw; + height: 70px; + background-color: white; + z-index: 600; + + border-width: 2px; + } +`; export const ToolContainer = styled.div` ${props=>props.lang==='ar' ? 'float: right' : 'float: left'}; - margin-right: 10px; - margin-bottom: 10px; text-align: left; `; -export const ToolViewport = styled.div` - margin: 0; - padding: 0; -` -// Block View -export const BlockContainer = styled(ToolContainer)` - background-image: ${props => props.background}; - background-size: cover; - background-position: center; - width: 250px; - height: 250px; - margin: 10px; - margin-${p=>p.lang==='ar'?'right':'left'}: 17px; - margin-${p=>p.lang==='ar'?'left':'right'}: 2px; - margin-bottom: 10px; - margin-top: 10px; -`; -export const BlockViewport = styled(ToolViewport)` - background-color: rgba(0,0,0,0.5); - padding: 10px; - width: 100%; - height: 100%; - position: relative; -`; -export const BlockSpiel = styled(ContentBlock)` - color: ${props=>getToolTypeColor(props.type)}; - position: absolute; - top: 0; - left: 0; - padding: 10px; - font-weight: 800; - opacity: ${props=>props.show?(props.forceShow?'0':'1'):'0'}; - transition: opacity 0.2s; -`; -export const BlockViewTitleArea = styled.div` - position: absolute; - left: 10px; - padding-right: 10px; - z-index: 100; - width: calc(100% - 10px); - opacity: ${props=>props.show ? '1': (props.forceShow?'1':'0')}; - transition: opacity 0.2s; -`; export const BlockAddRem = styled.div` text-align: ${p=>p.theme.isArabic?'right':'left'}; `; //List View export const ListContainer = styled(ToolContainer)` - width: 48%; - height: 190px; + width: 370px; text-align: left; -`; - -export const ListViewport = styled(ToolViewport)` - background-color: none; - padding: 0 10px 0 50px; - position: relative; - - &::before{ - content: ' '; - width: 53px; - height: 1px; - border-bottom: 2px solid; - position: absolute; - top: 0px; - ${p=>p.theme.isArabic?'right: 9px;':'left: 50px;'}; - } + margin-${p=>p.lang==='ar'?'left':'right'}: ${p=>p.index%2==0?'0':'130px'}; + padding-bottom: 40px; - h3 { - padding-top: 5px; + @media(max-width: 1170px) { + margin: 0; + width: 100%; + padding: 20px; } `; + export const ListSpiel = styled(ContentBlock)` margin: 0; `; diff --git a/app/components/ToolsPageComponents/index.js b/app/components/ToolsPageComponents/index.js index b61e237..3ee7aea 100644 --- a/app/components/ToolsPageComponents/index.js +++ b/app/components/ToolsPageComponents/index.js @@ -176,7 +176,7 @@ export const ToolMainContent = styled(ContentBlock)` `; export const ToolLearnMoreContent = styled(ToolMainContent)` - margin-top: 72px; + margin-top: 36px; `; export const ToolMainContentHeader = styled(CommonLeftHeader)` diff --git a/app/components/ToolsPotentialRisk/Container.js b/app/components/ToolsPotentialRisk/Container.js index 232ae70..d1f23ed 100644 --- a/app/components/ToolsPotentialRisk/Container.js +++ b/app/components/ToolsPotentialRisk/Container.js @@ -1,4 +1,6 @@ import styled from 'styled-components'; -export default styled.div` +import SidebarContent from 'components/ToolPage/Sidebar/SidebarContent'; + +export default styled(SidebarContent)` text-align: ${props=>props.theme.lang === 'ar' ? 'right' : 'left'}; `; diff --git a/app/components/ToolsPotentialRisk/Header.js b/app/components/ToolsPotentialRisk/Header.js index b22b9c7..6f29ddb 100644 --- a/app/components/ToolsPotentialRisk/Header.js +++ b/app/components/ToolsPotentialRisk/Header.js @@ -1,13 +1,12 @@ import styled from 'styled-components'; -export default styled.h3` - font-size: ${p=>p.theme.lang==='ar'?'30px':'40px'}; - text-transform: uppercase; - position: relative; - margin: 0; - padding-${p=>p.theme.lang==='ar'?'right':'left'}: 46px; +import { Header } from 'components/ToolPage/Sidebar'; +export default styled(Header)` + + font-size: ${p=>p.theme.lang==='ar'?'40px':'40px'}; + padding-${p=>p.theme.lang==='ar'?'right':'left'}: 52px; .isvg.loaded { position: absolute; - top: ${p=>p.theme.lang==='ar'?'0':'6px'}; + top: ${p=>p.theme.lang==='ar'?'8px':'8px'}; ${p=>p.theme.lang==='ar'?'right':'left'}: 0; } * { @@ -15,6 +14,4 @@ export default styled.h3` vertical-align: middle; display: inline-block; } - border-bottom: 5px solid; - padding-bottom: 0; `; diff --git a/app/components/ToolsRelatedTool/index.js b/app/components/ToolsRelatedTool/index.js index b205fc6..a816d92 100644 --- a/app/components/ToolsRelatedTool/index.js +++ b/app/components/ToolsRelatedTool/index.js @@ -18,29 +18,31 @@ const Viewport = styled.div``; const List = styled.ul` padding: 0; -margin: 0 0 0 23px; +margin: 0; +margin-${p=>p.lang==='ar'?'right':'left'}: 18px; `; const ListItem = styled.li` - list-style: square; + list-style: none; text-transform: uppercase; font-weight: bold; - margin-bottom: 5px; + margin-bottom: 12px; font-size: 14px; `; const ToolLink = styled(Link)` - color: ${props => getToolTypeColor(props.type)}; + color: black; + text-decoration: underline; `; function ToolsRelatedTool(props) { return ( - + {props.relatedTools.map(item => ( - {props.dict.getIn([item, 'title'])} + {props.dict.getIn([item, 'title'])} )) } diff --git a/app/components/TypeFlag/index.js b/app/components/TypeFlag/index.js index 92cb9b9..bb463c4 100644 --- a/app/components/TypeFlag/index.js +++ b/app/components/TypeFlag/index.js @@ -24,18 +24,25 @@ import BigTheoryFlag from 'assets/images/flag/big-theory.svg'; const FlagContainer = styled.div` position: absolute; ${props=>props.lang === 'ar' ? 'right' : 'left'}: -200px; - top: 125px; + top: 50px; svg circle, svg line, svg polyline { stroke: ${props=>getToolTypeColor(props.type)}; } + + @media(max-width: 1170px) { + position: absolute; + left: -220px; + top: 35px; + zoom: 0.75; + } `; const FlagViewport = styled.div` position: relative; width: 264px; - height: 182px; + height: 100px; overflow: hidden; `; const Flag = styled(Isvg)` @@ -60,6 +67,7 @@ export class TypeFlag extends React.PureComponent { this.setState({ showTooltip: false }); } render() { + //iF there's only one truth here, we show big flag. const oneTruth = [this.props.isTactic, this.props.isMethodology, this.props.isPrinciple, this.props.isTheory].filter(item=>item).length == 1; diff --git a/app/components/TypeOverlay/index.js b/app/components/TypeOverlay/index.js index 04cde75..bd42f32 100644 --- a/app/components/TypeOverlay/index.js +++ b/app/components/TypeOverlay/index.js @@ -55,7 +55,7 @@ const Flag = styled(Isvg)` function TypeOverlay(props) { const getTypeImage = (type) => { - + switch(type) { case 'tactic': return BigTacticFlag; case 'methodology': return BigMethodologyFlag; @@ -64,7 +64,7 @@ function TypeOverlay(props) { } } //iF there's only one truth here, we show big flag. - + return ( @@ -73,11 +73,7 @@ function TypeOverlay(props) { } TypeOverlay.propTypes = { - type: PropTypes.string.isRequired, - isMethodology: PropTypes.bool, - isPrinciple: PropTypes.bool, - isTactic: PropTypes.bool, - isTheory: PropTypes.bool + type: PropTypes.string.isRequired }; export default TypeOverlay; diff --git a/app/components/WhatsHappeningComponents/index.js b/app/components/WhatsHappeningComponents/index.js new file mode 100644 index 0000000..227fc1f --- /dev/null +++ b/app/components/WhatsHappeningComponents/index.js @@ -0,0 +1,22 @@ +/** +* +* WhatsHappeningComponents +* +*/ + +import React from 'react'; +// import styled from 'styled-components'; + + +function WhatsHappeningComponents() { + return ( +
+
+ ); +} + +WhatsHappeningComponents.propTypes = { + +}; + +export default WhatsHappeningComponents; diff --git a/app/components/WhatsHappeningComponents/tests/index.test.js b/app/components/WhatsHappeningComponents/tests/index.test.js new file mode 100644 index 0000000..1dfd39d --- /dev/null +++ b/app/components/WhatsHappeningComponents/tests/index.test.js @@ -0,0 +1,10 @@ +// import React from 'react'; +// import { shallow } from 'enzyme'; + +// import WhatsHappeningComponents from '../index'; + +describe('', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(false); + }); +}); diff --git a/app/containers/AboutMenu/constants.js b/app/containers/AboutMenu/constants.js index 4ea1edd..11abb0c 100644 --- a/app/containers/AboutMenu/constants.js +++ b/app/containers/AboutMenu/constants.js @@ -28,10 +28,10 @@ export const ABOUT_MENU = [ to: "/about/team", text: KEY_TEAM }, - { - to: "/about/beautiful-trouble-and-action-aid", - text: KEY_BTAA - }, + // { + // to: "/about/beautiful-trouble-and-action-aid", + // text: KEY_BTAA + // }, { to: "/about/partners", text: KEY_PARTNERS diff --git a/app/containers/AboutMenu/index.js b/app/containers/AboutMenu/index.js index e449456..3a7f7b0 100644 --- a/app/containers/AboutMenu/index.js +++ b/app/containers/AboutMenu/index.js @@ -22,25 +22,25 @@ function AboutMenu(props) { const { locale } = props.intl; return ( - - - - - - - { - ABOUT_MENU.map(item => ( + + + + + + + { + ABOUT_MENU.map(item => ( - - - - - - )) - } - + + + + + + )) + } + + - ); } diff --git a/app/containers/AboutPage/FAQ.js b/app/containers/AboutPage/FAQ.js index 048a881..65c703d 100644 --- a/app/containers/AboutPage/FAQ.js +++ b/app/containers/AboutPage/FAQ.js @@ -29,10 +29,11 @@ export class FAQ extends React.Component { ) } render() { + if (!this.props.questions ) return null; const {locale}=this.props.intl; return ( - + { this.props.hideHeader ? null : this.renderHeader()} { this.props.questions === undefined ? null : this.props.questions.map((item, ind) => { diff --git a/app/containers/AboutPage/OurAdvisoryNetwork.js b/app/containers/AboutPage/OurAdvisoryNetwork.js index b2e59a3..e41f06a 100644 --- a/app/containers/AboutPage/OurAdvisoryNetwork.js +++ b/app/containers/AboutPage/OurAdvisoryNetwork.js @@ -21,6 +21,12 @@ import AdvisoryNetworkIntro from 'components/AboutPage/AdvisoryNetwork/AdvisoryN import messages from './messages'; +const AdvisoryNetworkList = styled.ul` +@media(max-width: 1170px) { + padding: 0; +} +`; + export class OurAdvisoryNetwork extends React.Component { renderHeader() { return ( @@ -45,7 +51,7 @@ export class OurAdvisoryNetwork extends React.Component { -
    + { this.props.advisoryNetwork.map((item, ind) => ( @@ -56,7 +62,7 @@ export class OurAdvisoryNetwork extends React.Component { ))} -
+
diff --git a/app/containers/AboutPage/OurProcess.js b/app/containers/AboutPage/OurProcess.js index d0be1a7..2a5546f 100644 --- a/app/containers/AboutPage/OurProcess.js +++ b/app/containers/AboutPage/OurProcess.js @@ -32,6 +32,13 @@ const WORKSHOPS = ['myanmar', 'jordan', 'zimbabwe', 'bangladesh', 'uganda', 'mex const [STEPS, SUBHEADING, WORKSHOP] = [0, 1, 2]; +const Subheader = styled.h4`margin-top: 18px;` +const Header = styled.h3`margin-top: 24px;` +const ProcessList = styled.ul` +@media(max-width: 1170px) { + padding: 0; +} +`; class OurProcess extends React.Component { renderProjects() { @@ -43,12 +50,12 @@ class OurProcess extends React.Component { if (!groups) return null; return ( -
    + {groups.map((item,ind) => { return( -

    {item.get('name')}

    + {item.get('name')}
      {item.get('participants') ? @@ -59,7 +66,7 @@ class OurProcess extends React.Component { )} )} -
+ ) } @@ -78,17 +85,17 @@ class OurProcess extends React.Component { // processes[0] is the list return ( -
    + {processes[STEPS].value.map(item=>( -

    {item.title}

    +
    {item.title}
    ))} -
+
) } @@ -108,11 +115,11 @@ class OurProcess extends React.Component { } render() { + if (!this.props.processes) return null; const {locale} = this.props.intl; - return ( - + { this.props.hideHeader ? null : this.renderHeader() } { this.renderProcess() } {this.renderParticipants() } diff --git a/app/containers/AboutPage/OurTeam.js b/app/containers/AboutPage/OurTeam.js index 53a845c..81694c1 100644 --- a/app/containers/AboutPage/OurTeam.js +++ b/app/containers/AboutPage/OurTeam.js @@ -20,6 +20,11 @@ import TeamListItem from 'components/AboutPage/Team/TeamListItem'; import TeamImage from 'components/AboutPage/Team/TeamImage'; import TeamName from 'components/AboutPage/Team/TeamName'; +const TeamList = styled.ul` + @media(max-width: 1170px) { + padding: 0; + } +`; export class OurTeam extends React.Component { renderHeader() { return( @@ -29,13 +34,13 @@ export class OurTeam extends React.Component { ); } render() { + if (!this.props.teamMembers) return null; const {locale}=this.props.intl; return ( - + { this.props.hideHeader ? null : this.renderHeader() } - -
    + { !this.props.teamMembers ? null : this.props.teamMembers.map((item, ind) => { const teamMember = this.props.allData.get(item); return ( @@ -49,8 +54,7 @@ export class OurTeam extends React.Component { ); })} -
-
+
); diff --git a/app/containers/AboutPage/OurValues.js b/app/containers/AboutPage/OurValues.js index 87a57b8..e4b608b 100644 --- a/app/containers/AboutPage/OurValues.js +++ b/app/containers/AboutPage/OurValues.js @@ -21,6 +21,12 @@ const List = styled.ul` padding-left: 0; `; +const OurValuesList = styled.ul` + @media(max-width: 1170px) { + padding: 0; + } +`; + import ListItem from 'components/AboutPage/Values/ListItem'; import Count from 'components/AboutPage/Values/Count'; import SubListItem from 'components/AboutPage/Values/SubListItem'; @@ -41,7 +47,7 @@ export class OurValues extends React.Component { const lang = this.props.intl.locale return ( - + { this.props.hideHeader ? null : this.renderHeader() } { this.props.ourValues.map((item, ind) => @@ -49,7 +55,7 @@ export class OurValues extends React.Component { switch(item.get('type')) { case 'introduction': return null; case 'values': return ( -
    + { item.get('value').map((subitem, subindex) => ( {subindex + 1} @@ -59,25 +65,25 @@ export class OurValues extends React.Component { )) } -
+ ); case 'disclaimer': return ( -
    + {item.get('value')} -
+ ); case 'disclaimer-text': return ( -
    + -

    +

    -
+ ); } } diff --git a/app/containers/AboutPage/Partners.js b/app/containers/AboutPage/Partners.js index 6cc3946..3e9f1ff 100644 --- a/app/containers/AboutPage/Partners.js +++ b/app/containers/AboutPage/Partners.js @@ -21,6 +21,8 @@ import Team from 'components/AboutPage/Partners/Team'; import messages from './messages'; +const List = styled.ul` +padding: 0`; class Partners extends React.Component { renderHeader() { const lang = this.props.intl.locale; @@ -31,12 +33,14 @@ class Partners extends React.Component { ); } render() { + if (!this.props.networkPartners) return null; + const lang = this.props.intl.locale; return ( - + { this.props.hideHeader ? null : this.renderHeader() } - +
); diff --git a/app/containers/AboutPage/TheToolbox.js b/app/containers/AboutPage/TheToolbox.js index 35bcb51..bfd2a44 100644 --- a/app/containers/AboutPage/TheToolbox.js +++ b/app/containers/AboutPage/TheToolbox.js @@ -18,6 +18,27 @@ import VisibilitySensor from 'react-visibility-sensor'; import messages from './messages'; +const ToolTypeContainer = styled.div` + + + position: relative; + + ${p=>{ + if (p.notClickable) { + return ` + &::after { + content: ' '; + top: 0; + left: 0; + position: absolute; + width: 100%; + height: 100%; + background-color: rgba(0,0,0,0); + } + ` + } + }} +`; export class TheToolbox extends React.Component { renderHeader() { @@ -40,7 +61,9 @@ export class TheToolbox extends React.Component { - + + +
); diff --git a/app/containers/AboutPage/index.js b/app/containers/AboutPage/index.js index fa6891d..0c9c11e 100644 --- a/app/containers/AboutPage/index.js +++ b/app/containers/AboutPage/index.js @@ -53,7 +53,7 @@ export class AboutPage extends React.PureComponent { // eslint-disable-line reac // The delay is so that the receiveProps and didMount // will not go against eachother componentDidMount() { - if (this.props.aboutData) { + if (this.props.aboutData.size === 0) { this.props.onPageLoad(); } @@ -69,10 +69,13 @@ export class AboutPage extends React.PureComponent { // eslint-disable-line reac const reference = browserHistory.getCurrentLocation().pathname; const targetNode = ReactDOM.findDOMNode(this.refs[reference]); - if (targetNode && this.state.activateAnchor) { - this.setState({ activateAnchor : false, currentPath: reference, currentOffset: targetNode.offsetTop }); + if (targetNode && + // this.state.activateAnchor && + this.props.params.section !== nextProps.params.section + ) { + // this.setState({ activateAnchor : false, currentPath: reference, currentOffset: targetNode.offsetTop }); window.scrollTo(0, targetNode.offsetTop); - setTimeout(() => { this.setState({ activateAnchor: true }); }, 100); + // setTimeout(() => { this.setState({ activateAnchor: true }); }, 100); } } @@ -178,12 +181,12 @@ export class AboutPage extends React.PureComponent { // eslint-disable-line reac teamMembers={this.props.aboutData.getIn(['about', 'team-members'])} allData={this.props.aboutData} /> - + />*/} state.get('global'); const selectTools = (state) => state.get('tools'); const selectLanguage = (state) => state.get('language'); const selectTranslatableStaticText = (state) => state.get('translatableStaticText'); +const selectWhatsHappening = (state) => state.get('whatsHappening'); +const makeSelectWhatsHappening = () => createSelector( + [selectWhatsHappening], + (whatsHappeningData) => whatsHappeningData.get('data') +) const makeSelectLanguage = () => createSelector( [selectLanguage], (languageState) => languageState.get('locale') @@ -167,6 +172,7 @@ export { makeSelectLanguage, makeSelectExamples, makeSelectSlugged, - makeSelectStaticText + makeSelectStaticText, + makeSelectWhatsHappening // makeSelectToolView, }; diff --git a/app/containers/Author/index.js b/app/containers/Author/index.js index 398e81f..febac8c 100644 --- a/app/containers/Author/index.js +++ b/app/containers/Author/index.js @@ -9,7 +9,7 @@ import Markdown from 'react-remarkable'; import { connect } from 'react-redux'; import { createStructuredSelector } from 'reselect'; import {AuthorContainer, AuthorImageArea, AuthorLink, - AuthorImage, AuthorName, AuthorDesc} from 'components/AuthorComponents'; + AuthorImage, AuthorName, AuthorDesc} from 'components/Author'; import ContentBlock from 'components/ContentBlock'; import LanguageThemeProvider from 'components/LanguageThemeProvider'; import LatinThemeProvider from 'components/LatinThemeProvider'; @@ -29,13 +29,13 @@ export class Author extends React.PureComponent { // eslint-disable-line react/p return ( - - - - + + + + {/* {firstName} {latterName} - + */} diff --git a/app/containers/ContactUs/index.js b/app/containers/ContactUs/index.js index ef585f5..9c59d0b 100644 --- a/app/containers/ContactUs/index.js +++ b/app/containers/ContactUs/index.js @@ -10,6 +10,7 @@ import { Link } from 'react-router'; import Isvg from 'react-inlinesvg'; import TwitterIcon from 'assets/images/icons/twitter.svg'; import FacebookIcon from 'assets/images/icons/facebook.svg'; +import MenuBlock from 'components/MenuBlock'; import { connect } from 'react-redux'; import { FormattedMessage, injectIntl } from 'react-intl'; @@ -18,10 +19,10 @@ import makeSelectContactUs from './selectors'; import messages from './messages'; import { sendSubscription } from './actions'; +import {Counter} from 'containers/WhatsHappening'; import TranslatableStaticText from 'containers/TranslatableStaticText'; import MenuLink from 'components/MenuLink'; -import MenuBlock from 'components/MenuBlock'; import MenuList from 'components/MenuList'; import MenuListItem from 'components/MenuListItem'; import MenuTitle from 'components/MenuTitle'; @@ -35,6 +36,14 @@ import SubscribeCTA from 'components/MenuContactUs/SubscribeCTA'; import LanguageThemeProvider from 'components/LanguageThemeProvider'; import staticText from './staticText'; +const CounterContainer = styled.div` + display: inline-block; + vertical-align: top; + position: relative; + top: 11px; + right: -4px; +`; + export class ContactUs extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function constructor(props) { super(props); @@ -53,16 +62,18 @@ export class ContactUs extends React.PureComponent { // eslint-disable-line reac renderForm() { const {locale} = this.props.intl; return ( - - -
- - -
-
-
+ + +
+
+ +
+ +
+
+
); } @@ -78,11 +89,22 @@ export class ContactUs extends React.PureComponent { // eslint-disable-line reac const { locale } = this.props.intl; return ( - - + + + + + + + + + + + + + info@beautifulrising.org
@@ -97,8 +119,9 @@ export class ContactUs extends React.PureComponent { // eslint-disable-line reac
{ !this.props.ContactUs.complete ? this.renderForm() : this.renderResponse() } +
-
+ ); } } diff --git a/app/containers/ContactUs/staticText.js b/app/containers/ContactUs/staticText.js index e7ed12e..9a18ea7 100644 --- a/app/containers/ContactUs/staticText.js +++ b/app/containers/ContactUs/staticText.js @@ -10,5 +10,9 @@ export default { submit: { id: "menu.submit", defaultMessage: "Submit" + }, + whatsHappening: { + id: "menu.whats-happening", + defaultMessage: "What's Happening" } } diff --git a/app/containers/ContributeMenu/index.js b/app/containers/ContributeMenu/index.js index a268280..757e42e 100644 --- a/app/containers/ContributeMenu/index.js +++ b/app/containers/ContributeMenu/index.js @@ -6,6 +6,7 @@ import React from 'react'; +import { injectIntl } from 'react-intl'; import TranslatableStaticText from 'containers/TranslatableStaticText'; import LanguageThemeProvider from 'components/LanguageThemeProvider'; import MenuLink from 'components/MenuLink'; @@ -16,21 +17,24 @@ import MenuTitle from 'components/MenuTitle'; import staticText from './staticText'; function ContributeMenu(props) { + const { locale } = props.intl; return ( - - - - - - - - - - - - + + + + + + + + + + + + + + - + ); } @@ -38,4 +42,4 @@ ContributeMenu.propTypes = { }; -export default ContributeMenu; +export default injectIntl(ContributeMenu); diff --git a/app/containers/ContributeType/index.js b/app/containers/ContributeType/index.js index 6fba638..d8a7d83 100644 --- a/app/containers/ContributeType/index.js +++ b/app/containers/ContributeType/index.js @@ -7,10 +7,11 @@ import React from 'react'; import styled from 'styled-components'; import { FormattedMessage, injectIntl } from 'react-intl'; +import { Link } from 'react-router'; import Isvg from 'react-inlinesvg'; import Markdown from 'react-remarkable'; -import TranslatableStaticText from 'containers/TranslatableStaticText'; +import TranslatableStaticText, { injectStaticText } from 'containers/TranslatableStaticText'; import LanguageThemeProvider from 'components/LanguageThemeProvider'; import ContentBlock from 'components/ContentBlock'; @@ -26,6 +27,7 @@ import Subtitle from 'components/ContributeType/Subtitle'; import Type from 'components/ContributeType/Type'; import TypeList from 'components/ContributeType/TypeList'; import TypeName from 'components/ContributeType/TypeName'; +import ExampleContainer from 'components/ContributeType/ExampleContainer'; import StoryIcon from 'assets/images/type/stories.svg'; import TacticIcon from 'assets/images/type/tactics.svg'; @@ -37,6 +39,15 @@ import messages from './messages'; import keys from './constants'; import staticText from './staticText'; +const MobileContent = styled(Content)` + display: none; + padding: 0 20px 20px; + @media(max-width: 1170px) { + width: 100%; + display: ${p=>p.show?'block':'none'}; + * {text-align: center !important;} + } +`; class ContributeType extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function constructor(props) { @@ -54,14 +65,14 @@ class ContributeType extends React.PureComponent { // eslint-disable-line react/ } render() { - const { formatMessage } = this.props.intl; + const { buildMessage } = this.props.translatable; return (
{DATA.map((item, index) => ( - +
@@ -103,31 +133,36 @@ const DATA = [ type: 'story', icon: StoryIcon, label: (), - description: () + description: (), + form: staticText.storyForm }, { type: 'tactic', icon: TacticIcon, label: (), - description: () + description: (), + form: staticText.tacticForm }, { type: 'principle', icon: PrincipleIcon, label: (), - description: () + description: (), + form: staticText.principleForm }, { type: 'theory', icon: TheoryIcon, label: (), - description: () + description: (), + form: staticText.theoryForm }, { type: 'methodology', icon: MethodologyIcon, label: (), - description: () + description: (), + form: staticText.methodologyForm }, ]; @@ -136,4 +171,4 @@ ContributeType.propTypes = { }; -export default injectIntl(ContributeType); +export default injectStaticText(ContributeType); diff --git a/app/containers/ContributeType/staticText.js b/app/containers/ContributeType/staticText.js index f37045f..4df3430 100644 --- a/app/containers/ContributeType/staticText.js +++ b/app/containers/ContributeType/staticText.js @@ -38,5 +38,29 @@ export default { shortDefinitionStory: { id: 'definitions.story-short', defaultMessage: 'Accounts of memorable actions and campaigns, analysing what worked, or didn’t, and why.' + }, + goToForm: { + id: 'module.form', + defaultMessage: 'Go To Form' + }, + storyForm: { + id: 'forms.story', + defaultMessage: "https://docs.google.com/forms/d/e/1FAIpQLSeC_EdxoO7owVnL8fjSERZlychwMhDOR-7rI1SDtpL4ijZgkg/viewform", + }, + tacticForm: { + id: 'forms.tactic', + defaultMessage: "https://docs.google.com/forms/d/e/1FAIpQLSeC_EdxoO7owVnL8fjSERZlychwMhDOR-7rI1SDtpL4ijZgkg/viewform", + }, + methodologyForm: { + id: 'forms.methodology', + defaultMessage: "https://docs.google.com/forms/d/e/1FAIpQLSeC_EdxoO7owVnL8fjSERZlychwMhDOR-7rI1SDtpL4ijZgkg/viewform" + }, + principleForm: { + id: 'forms.principle', + defaultMessage: "https://docs.google.com/forms/d/e/1FAIpQLSeC_EdxoO7owVnL8fjSERZlychwMhDOR-7rI1SDtpL4ijZgkg/viewform" + }, + theoryForm: { + id: 'forms.theory', + defaultMessage: 'https://docs.google.com/forms/d/e/1FAIpQLSeC_EdxoO7owVnL8fjSERZlychwMhDOR-7rI1SDtpL4ijZgkg/viewform' } }; diff --git a/app/containers/Footer/index.js b/app/containers/Footer/index.js index 2dbd1f0..8deb40b 100644 --- a/app/containers/Footer/index.js +++ b/app/containers/Footer/index.js @@ -20,7 +20,7 @@ const Container = styled.section` padding: 10px; text-align: center; border-top: 2px solid black; -margin-top: 50px; +margin-top: 72px; margin-left: 20px; margin-right: 20px; &::before { @@ -30,7 +30,14 @@ margin-right: 20px; } `; -const Viewport = styled.div`margin-${p=>p.isArabic?'right':'left'}: 16%; width: 66%;`; +const Viewport = styled.div` + margin-${p=>p.isArabic?'right':'left'}: 16%; width: 66%; + + @media(max-width: 1170px) { + width: 100%; + margin: 0; + } +`; const Content = styled.div` p { diff --git a/app/containers/Header/index.js b/app/containers/Header/index.js index 5622a89..b69beab 100644 --- a/app/containers/Header/index.js +++ b/app/containers/Header/index.js @@ -12,23 +12,35 @@ import ModalMenu from 'containers/ModalMenu'; import Link from 'components/Link'; import { injectIntl } from 'react-intl'; import messages from './messages'; - +import { Bell as WhatsHappeningBell} from 'containers/WhatsHappening'; +import { MobileLanguageChanger } from 'containers/LanguageChanger'; const Viewport = styled.div` position: relative; - width: 1110px; + width: 1170px; text-align: left; display: inline-block; + // Mobile + @media(max-width: 1170px) { + max-width: 100%; + } `; const PageHeader = styled.header` position: fixed; + // position: absolute; width: 100%; background-color: white; - height: 92px; + height: 115px; overflow: visible; - padding: 0 20px 0px; + padding: 0; z-index: 300; text-align: center; + + @media(max-width: 1170px) { + padding: 0; + // position: relative; + z-index: 400; + } `; const ModalMenuArea = styled(ModalMenu)` @@ -41,6 +53,18 @@ const ModalMenuArea = styled(ModalMenu)` } `; +const BellArea = styled.div` + position: absolute; + ${p=>p.theme.ar=='ar'?'left':'right'}: 0; + top: 27px; + + @media(max-width: 1170px) { + position: absolute; + ${p=>p.theme.ar=='ar'?'left':'right'}: 15px; + top: 25px; + } +`; + class Header extends React.Component { render() { @@ -52,6 +76,10 @@ class Header extends React.Component { + + + +
diff --git a/app/containers/HomePage/BlockViewItem.js b/app/containers/HomePage/BlockViewItem.js index a07d816..c9f918e 100644 --- a/app/containers/HomePage/BlockViewItem.js +++ b/app/containers/HomePage/BlockViewItem.js @@ -12,8 +12,13 @@ import TranslatableStaticText from 'containers/TranslatableStaticText'; import Link from 'components/Link'; import AdderRemover from 'containers/Tools/AdderRemover'; -import {ToolType, ToolTitle, BlockContainer, - BlockViewport, BlockSpiel, BlockAddRem, BlockViewTitleArea} from 'components/ToolsComponents'; +import {ToolTitle, BlockAddRem} from 'components/ToolsComponents'; + +import { BlockViewTitleArea, + BlockContainer, + BlockViewport, + BlockSpiel, + BlockViewToolType } from 'components/HomePage/BlockView'; import LanguageThemeProvider from 'components/LanguageThemeProvider'; import RegionIcon from 'components/RegionIcon'; @@ -54,20 +59,22 @@ class BlockViewItem extends React.Component { return ( - + - + - + {this.props.title} diff --git a/app/containers/HomePage/Header.js b/app/containers/HomePage/Header.js index 92a2b85..22dba65 100644 --- a/app/containers/HomePage/Header.js +++ b/app/containers/HomePage/Header.js @@ -6,22 +6,31 @@ import React from 'react'; import styled from 'styled-components'; +import Isvg from 'react-inlinesvg'; import { injectIntl } from 'react-intl'; import ToolTypeArea from 'containers/ToolTypeArea'; + import SearchField from 'containers/SearchField'; +import ToolsViewOptions from 'containers/ToolsViewOptions'; +import ToolsSortOptions from 'containers/ToolsSortOptions'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import {TextButton} from 'components/CommonComponents'; +import IconButton from 'components/IconButton'; +import ArrowIcon from 'assets/images/icons/arrow.svg'; +import TypeDetails from 'containers/TypeDetails'; import Link from 'components/Link'; -import messages from './messages'; + +import TagArea from './TagArea'; +import staticText from './staticText'; const HeaderContainer = styled.div` - width: 1080px; - position: fixed; - background-color: white; - z-index: 200; - top: 92px; + width: 100%; + margin-top: 10px; &::before { position: absolute; @@ -34,14 +43,133 @@ const HeaderContainer = styled.div` } `; -function Header(props) { - const lang = props.intl.locale; - return ( - - - - - ); +const FilterSection = styled.ul` + width: 100%; + padding-bottom: 5px; + border-bottom: 2px solid black; + padding-${p=>p.theme.isArabic?'right':'left'}: 0px; + display: flex; + list-style: none; + margin: 0; + + @media(max-width: 1170px) { + flex-wrap: wrap; + + &::after { + content: ' '; + border: 1px solid white; + position: absolute; + right: 0; + top: 0; + height: 68px; + } + } +`; + +const FilterItem = styled.li` + display: inline-block; + list-style: none; + position: relative; + padding-left: ${p=>p.sidePadding || 0}; + padding-right: ${p=>p.sidePadding || 0}; + position: relative; + + ${p=>{ + if (p.last) { + return p.theme.isArabic?'padding-left:0;':'padding-right:0'; + } else { return null; } + }} + &::after { + content: ' '; + border-${p=>p.theme.isArabic?'left':'right'}: 2px solid; + position: absolute; + height: 12px; + ${p=>p.theme.isArabic?'left':'right'}: 0px; + top: 7px; + } + + &:last-child { + padding-${p=>p.theme.isArabic?'left':'right'}: 0; + &::after { border-${p=>p.theme.isArabic?'left':'right'}: none; } + } +`; + +const TagShownIcon = styled.div` + display: inline-block; + ${p=>{ + if(p.theme.isArabic) { + return `transform: ${p.selected?'rotate(270deg)':'rotate(360deg)'};` + } else { + return `transform: ${p.selected?'rotate(270deg)':'rotate(180deg)'};`; + } + }} + margin-${p=>p.theme.isArabic?'right':'left'}: 12px; + margin-top: -5px; + transition: transform 0.5s ease; + + svg { width: 10px !important; } + svg * { + fill: ${p=>p.selected?'black':'#ACACAC'}; + transition: fill 0.5s ease; + } +`; + +class Header extends React.PureComponent { + + constructor() { + super(); + + this.state = { + isTagsAreaShown: false + } + } + + toggleTagArea() { + this.setState({isTagsAreaShown: !this.state.isTagsAreaShown }); + } + + hideTagArea() { + this.setState({isTagsAreaShown: false }); + } + + showTagArea(){ + this.setState({isTagsAreaShown: true }); + } + render() { + const lang = this.props.intl.locale; + const showTypeDetails=this.props.params.filter==="type"; + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); + } + } Header.propTypes = { diff --git a/app/containers/HomePage/ListViewItem.js b/app/containers/HomePage/ListViewItem.js index 4747040..ca055f7 100644 --- a/app/containers/HomePage/ListViewItem.js +++ b/app/containers/HomePage/ListViewItem.js @@ -10,7 +10,9 @@ import LanguageThemeProvider from 'components/LanguageThemeProvider'; import { injectIntl } from 'react-intl'; import Link from 'components/Link'; import AdderRemover from 'containers/Tools/AdderRemover'; -import {ToolType, ToolTitle, ListContainer, ListViewport, ListSpiel} from 'components/ToolsComponents'; +import {ToolType, ToolTitle, ListContainer, ListSpiel} from 'components/ToolsComponents'; +import { ListViewport } from 'components/HomePage/ListView'; + import { BR_IMAGE_PREFIX } from 'containers/Tools/constants'; import TranslatableStaticText from 'containers/TranslatableStaticText'; @@ -22,7 +24,7 @@ class ListViewItem extends React.Component { const { locale } = this.props.intl; return ( - + diff --git a/app/containers/HomePage/MobileHeader.js b/app/containers/HomePage/MobileHeader.js new file mode 100644 index 0000000..d912f25 --- /dev/null +++ b/app/containers/HomePage/MobileHeader.js @@ -0,0 +1,308 @@ +/** +* +* ToolListItem +* +*/ + +import React from 'react'; +import styled from 'styled-components'; +import Isvg from 'react-inlinesvg'; + +import { injectIntl } from 'react-intl'; + +import ToolTypeAll from 'containers/ToolTypeAll'; + +import SearchField from 'containers/SearchField'; +import ToolsViewOptions from 'containers/ToolsViewOptions'; +import ToolsSortOptions from 'containers/ToolsSortOptions'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import {TextButton} from 'components/CommonComponents'; +import IconButton from 'components/IconButton'; +import MobileSectionHeader from 'components/HomePage/MobileSectionHeader'; +import ArrowIcon from 'assets/images/icons/arrow.svg'; + +import TypeDetails from 'containers/TypeDetails'; +import Link from 'components/Link'; +import Modal from 'react-modal'; + +import TagArea from './TagArea'; +import staticText from './staticText'; + +const MobileHeaderContainer = styled.div` + width: 100%; + margin-top: 10px; + + padding-right: 15px; + padding-left: 15px; + + &::before { + position: absolute; + content: ' '; + width: 240px; + height: 4px; + background-color: white; + ${props=>props.theme.lang==='ar' ? (props.showTools?'right: 326px':'right: 96px') : (props.showTools?'left: 325px':'left: 95px')}; + transition: left 0.3s ease, right 0.3s ease; + } +`; + +const FilterSection = styled.ul` + width: 100%; + padding-bottom: 5px; + border-bottom: 2px solid black; + padding-${p=>p.theme.isArabic?'right':'left'}: 0px; + display: flex; + list-style: none; + margin: 0; + + @media(max-width: 1170px) { + flex-wrap: wrap; + + &::after { + content: ' '; + border: 1px solid white; + position: absolute; + right: 0; + top: 0; + height: 68px; + } + + &:first-child { + border-bottom: 0; + } + } +`; + +const SingleFilterSection = styled(FilterSection)` + padding-top: 12px; + padding-bottom: 12px; + border-bottom: 0; +`; + +const FilterItem = styled.li` + display: inline-block; + list-style: none; + position: relative; + padding-left: ${p=>p.sidePadding || 0}; + padding-right: ${p=>p.sidePadding || 0}; + position: relative; + text-align: ${p=>p.theme.isArabic?'right': 'left'}; + + ${p=>{ + if (p.last) { + return p.theme.isArabic?'padding-left:0;':'padding-right:0'; + } else { return null; } + }} + + &::after { + content: ' '; + border-${p=>p.theme.isArabic?'left':'right'}: 2px solid; + position: absolute; + height: 12px; + ${p=>p.theme.isArabic?'left':'right'}: 0px; + top: 7px; + } + + &:first-child { + flex-grow: 1; + } + &:last-child { + padding-${p=>p.theme.isArabic?'left':'right'}: 0; + width: 110px; + text-align: center; + &::after { border-${p=>p.theme.isArabic?'left':'right'}: none; } + } +`; + +const TagShownIcon = styled.div` + display: inline-block; + ${p=>{ + if(p.theme.isArabic) { + return `transform: ${p.selected?'rotate(270deg)':'rotate(360deg)'};` + } else { + return `transform: ${p.selected?'rotate(270deg)':'rotate(180deg)'};`; + } + }} + margin-${p=>p.theme.isArabic?'right':'left'}: 12px; + margin-top: -5px; + transition: transform 0.5s ease; + + svg { width: 10px !important; } + svg * { + fill: ${p=>p.selected?'black':'#ACACAC'}; + transition: fill 0.5s ease; + } +`; + +//For modalIsOpen +const customStyles = { + overlay: { + backgroundColor: 'rgba(149, 149, 149, 0.75)', + zIndex: 900 + }, + content : { + position: 'absolute', + right: 'auto', + left: 'auto', + bottom: 'auto', + border: '0px none', + background: 'rgb(255, 255, 255)', + overflow: 'visible', + outline: 'none', + padding: '15px', + width: '100%', + height: 'calc(100% - 115px)', + zIndex: '600', + top: '115px' + } +}; + +const ApplyButton = styled.button` + outline: none; + display: none; + position: absolute; + bottom: 0; + left: 0; + width: 100%; + font-size: 15px; + padding: 18px; + text-transform: uppercase; + font-weight: 800; + border: 2px solid black; + @media(max-width: 1170px) { + display: block; + } +`; + + +class MobileHeader extends React.PureComponent { + + constructor() { + super(); + + this.state = { + isTagsAreaShown: false, + isTypeAreaShown: false + } + } + + toggleTagArea() { + this.setState({isTagsAreaShown: !this.state.isTagsAreaShown }); + } + + hideTagArea() { + this.setState({isTagsAreaShown: false }); + } + + showTagArea(){ + this.setState({isTagsAreaShown: true }); + } + + toggleTypeArea() { + this.setState({isTypeAreaShown: !this.state.isTypeAreaShown }); + } + + hideTypeArea() { + this.setState({isTypeAreaShown: false }); + } + + showTypeArea(){ + this.setState({isTypeAreaShown: true }); + } + + componentWillReceiveProps(nextProps) { + } + + renderMobileTags() { + const lang = this.props.intl.locale; + return ( + + + + + + ) + } + renderTypeButton() { + const lang = this.props.intl.locale; + return ( + + + + + + ) + } + render() { + const lang = this.props.intl.locale; + const showTypeDetails=this.props.params.filter==="type"; + return ( + + + + + + + + { this.renderMobileTags() } + + + + + + + + + + + + + {this.renderTypeButton() } + + + + + + {/* MODAL FOR TAGS */} + + + + + {}}/> + + + + + + {/* MODAL FOR TYPES */} + + + + + + + + + + + ); + } + +} + +MobileHeader.propTypes = { + +}; + +export default injectIntl(MobileHeader); diff --git a/app/containers/HomePage/TagArea.js b/app/containers/HomePage/TagArea.js new file mode 100644 index 0000000..0edfd40 --- /dev/null +++ b/app/containers/HomePage/TagArea.js @@ -0,0 +1,54 @@ +import React from 'react'; + +import styled from 'styled-components'; +import Isvg from 'react-inlinesvg'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import CloseIcon from 'assets/images/icons/close.svg'; +import Tags from 'containers/Tags'; + +import staticText from './staticText'; + +const Container = styled.div` + width: 100%; + overflow: hidden; + border-bottom: 2px solid black; + padding: 0px 44px 15px; + padding-bottom: ${p=>p.show?15:0}; + position: relative; + border-bottom: ${p=>p.show?'2px solid black':0}; + max-height: ${p=>p.show?'100vh':0}; + transition: max-height 0.8s ease, border-bottom 0.8s ease, padding-bottom 0.4s ease; + + @media(max-width: 1170px) { + height: 100%; + border-bottom: 0; + z-index: 700px; + padding: 0px 40px 15px; + } +`; +const CloseButton = styled.button` + outline: none; + position: absolute; + cursor: pointer; + top: 0; + left: 0; + + svg { + width: 15px !important; + height: 15px !important; + } +`; + + +class TagArea extends React.PureComponent { + + render() { + return ( + + + + ); + } +} + +export default TagArea; diff --git a/app/containers/HomePage/ToolList.js b/app/containers/HomePage/ToolList.js index 8b3225d..fec954f 100644 --- a/app/containers/HomePage/ToolList.js +++ b/app/containers/HomePage/ToolList.js @@ -8,9 +8,17 @@ import React from 'react'; import styled from 'styled-components'; export default styled.div` - ::after { + margin-top: 36px; + display: flex; + flex-wrap: wrap; + align-items: stretch; + &::after { content: ' '; clear: both; display: block; } + + @media(max-width: 1170px) { + justify-content: center; + } `; diff --git a/app/containers/HomePage/index.js b/app/containers/HomePage/index.js index b5d4246..77f5170 100644 --- a/app/containers/HomePage/index.js +++ b/app/containers/HomePage/index.js @@ -10,7 +10,7 @@ import Helmet from 'react-helmet'; import { push } from 'react-router-redux'; import { createStructuredSelector } from 'reselect'; - +import styled from 'styled-components'; import TranslatableStaticText from 'containers/TranslatableStaticText'; import Tags from 'containers/Tags'; import ContentBlock from 'components/ContentBlock'; @@ -25,14 +25,15 @@ import { makeSelectToolById, import ToolsViewOptions from 'containers/ToolsViewOptions'; import ToolsSortOptions from 'containers/ToolsSortOptions'; +import ToolTypeArea from 'containers/ToolTypeArea'; + +import { LeftSection, + Stage } from 'components/HomePage/Layout'; -import LeftSection from 'components/LeftSection'; import ClearButton from 'components/ClearButton'; import { LeftHeader, LeftContainer } from 'components/HomePage'; -import Stage from 'components/Stage'; - import { loadData } from '../App/actions'; import makeSelectHomePage, { makeSelectSearchFieldValue, makeSelectToolView, makeSelectAllTools, isToolsShown, makeSortedTools, makeSelectLanguage } from './selectors'; @@ -43,30 +44,30 @@ import ToolList from './ToolList'; import BlockViewItem from './BlockViewItem'; import ListViewItem from './ListViewItem'; import Header from './Header'; +import MobileHeader from './MobileHeader'; import staticText from './staticText'; const TOP=0,MIDDLE=1,BOTTOM=2; +const HeaderContainer = styled.div` + display: block; + @media(max-width: 1170px) { + display: none; + } +`; +const MobileHeaderContainer = styled.div` + display: none; + @media(max-width: 1170px) { + display: block; + } +`; export class HomePage extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function constructor(props) { super(props); - this.windowEvent = this.handleScroll.bind(this); - this.state = { - scrollY: 0 - } } - componentWillMount() { - window.addEventListener('scroll', this.windowEvent, false); - } - componentWillUnmount() { - window.removeEventListener('scroll', this.windowEvent, false); - } - handleScroll() { - this.setState({ scrollY: window.scrollY }); - } componentDidMount() { if (!this.props.tools) { @@ -77,7 +78,7 @@ export class HomePage extends React.PureComponent { // eslint-disable-line react getViewMode() { if (this.props.params.label !== undefined && this.props.params.label !== '' && - this.props.params.filter === 'search') { + (this.props.params.filter === 'search' || this.props.params.filter == 'tag') ) { return ListViewItem; } @@ -93,18 +94,15 @@ export class HomePage extends React.PureComponent { // eslint-disable-line react if (!this.props.params.filter || this.props.params.filter !== 'search' || !this.props.params.label) return; return ( - - + + - - - - - + + ); } getDirection() { @@ -126,53 +124,38 @@ export class HomePage extends React.PureComponent { // eslint-disable-line react const lang = this.props.language; const ListItem = this.getViewMode(); - return ( + + +; return ( 10} > -
- - - - - - - - - - - - - - - - - - - - - - + + +
+ + + + {this.getSearchResultsHeader()} { this.props.sorted ? this.props.sorted.map((tool, index) => { return ( ) diff --git a/app/containers/HomePage/sagas.js b/app/containers/HomePage/sagas.js index 8f564f7..1b66846 100644 --- a/app/containers/HomePage/sagas.js +++ b/app/containers/HomePage/sagas.js @@ -3,15 +3,17 @@ import { LOCATION_CHANGE } from 'react-router-redux'; import { take, call, put, select, cancel, takeLatest } from 'redux-saga/effects'; import { LOAD_DATA, LANGUAGE_CHANGE_RELOAD_DATA } from 'containers/App/constants'; import { CHANGE_LOCALE } from 'containers/LanguageProvider/constants'; -import { dataLoaded, dataLoadingError } from 'containers/App/actions'; +import { loadData, dataLoaded, dataLoadingError } from 'containers/App/actions'; import request, { getEndpoint } from 'utils/request'; export const getLanguage = (state) => state.get('language'); -export function* getData(lang) { +export function* getData() { + + let language = yield select(getLanguage); + const chosenLanguage = language !== undefined ? language.get('locale') : 'en'; + const requestURL = getEndpoint(chosenLanguage); - const requestURL = getEndpoint(lang); - try { const data = yield call(request, requestURL); @@ -29,11 +31,21 @@ export function* beautifulRisingData() { // By using `takeLatest` only the result of the latest API call is applied. // It returns task descriptor (just like fork) so we can continue execution - let language = yield select(getLanguage); - const chosenLanguage = language !== undefined ? language.get('locale') : 'en'; - const watcher = yield takeLatest(LOAD_DATA, getData, chosenLanguage); - yield take(CHANGE_LOCALE, LOCATION_CHANGE); + + const watcher = yield takeLatest(LOAD_DATA, getData); + + yield take(LOCATION_CHANGE); + yield cancel(watcher); + +} + +export function* changeLanguage() { + // Watches for LOAD_REPOS actions and calls getRepos when one comes in. + // By using `takeLatest` only the result of the latest API call is applied. + // It returns task descriptor (just like fork) so we can continue execution + + const watcher = yield takeLatest(CHANGE_LOCALE, getData); } // export function* langaugeChangeData() { @@ -50,4 +62,5 @@ export function* beautifulRisingData() { // All sagas to be loaded export default [ beautifulRisingData, + changeLanguage ]; diff --git a/app/containers/HomePage/selectors.js b/app/containers/HomePage/selectors.js index e42b5cd..96c9fa8 100644 --- a/app/containers/HomePage/selectors.js +++ b/app/containers/HomePage/selectors.js @@ -1,6 +1,6 @@ import { createSelector } from 'reselect'; import { TAG_FILTER, TYPE_FILTER, SEARCH_FILTER } from './constants'; -import { MODULE_TYPE_UNTRANSLATED, MODULE_TYPE_FULL, MODULE_TYPE_GALLERY } from 'components/CommonComponents/constants'; +import { MODULE_TYPE_UNTRANSLATED, MODULE_TYPE_FULL, MODULE_TYPE_SNAPSHOT, MODULE_TYPE_GALLERY } from 'components/CommonComponents/constants'; import { SORT_NEWEST, SORT_ALPHABETICAL } from 'containers/ToolsSortOptions/constants'; import {slugify} from 'utils/tags'; @@ -38,6 +38,11 @@ const selectHomePageDomain = () => (state) => state.get('homePage'); || item['module-type-effective'] === MODULE_TYPE_FULL; } +const isSearchItem = (item, lang) => { + return item['module-type-effective'] === MODULE_TYPE_GALLERY + || item['module-type-effective'] === MODULE_TYPE_FULL + || item['module-type-effective'] === MODULE_TYPE_SNAPSHOT; +} const selectToolsDomain = (state) => state.get('tools'); @@ -105,7 +110,7 @@ const makeSelectSearchFieldValue = createSelector( return label ? data.filter( item => { const searchBase = searchIndices.map(key => item[key]).join(' ').toLowerCase(); - return item['module-type-effective'] !== MODULE_TYPE_UNTRANSLATED && searchBase.search(label.toLowerCase()) >= 0 + return isSearchItem(item, lang) && item['module-type-effective'] !== MODULE_TYPE_UNTRANSLATED && searchBase.search(label.toLowerCase()) >= 0 } ) : data.filter(item => isFullTool(item, lang)); diff --git a/app/containers/HomePage/staticText.js b/app/containers/HomePage/staticText.js index cc0d76e..e6de65a 100644 --- a/app/containers/HomePage/staticText.js +++ b/app/containers/HomePage/staticText.js @@ -42,5 +42,13 @@ export default { searchResults: { id: 'list.results', defaultMessage: 'Search results for “{{query}}” ({{count}}) results found' + }, + apply: { + id: 'list.apply', + defaultMessage: 'Apply' + }, + toolTypeButton: { + id: 'list.type-button', + defaultMessage: 'filter by tool type' } } diff --git a/app/containers/LanguageChanger/MobileLanguageChanger.js b/app/containers/LanguageChanger/MobileLanguageChanger.js new file mode 100644 index 0000000..edf1d16 --- /dev/null +++ b/app/containers/LanguageChanger/MobileLanguageChanger.js @@ -0,0 +1,228 @@ +/* + * + * LanguageChanger + * + */ + +import React, { PropTypes } from 'react'; +import Modal from 'react-modal'; +import Isvg from 'react-inlinesvg'; + +import ArrowIcon from 'assets/images/icons/arrow.svg'; +import { push } from 'react-router'; +import { connect } from 'react-redux'; +import { changeLocale } from 'containers/LanguageProvider/actions'; +import { loadLanguage } from 'containers/TranslatableStaticText/actions'; +import { createStructuredSelector } from 'reselect'; +import styled from 'styled-components'; +import { injectIntl } from 'react-intl'; +import { makeSelectLanguage } from 'containers/App/selectors'; +import { loadData, langChangeReloadData } from '../App/actions'; + + +const customStyles = { + overlay: { + backgroundColor: 'rgba(149, 149, 149, 0.75)', + zIndex: 800 + }, + content : { + position: 'absolute', + right: 'auto', + left: 'auto', + top: '140px', + bottom: 'auto', + border: '0px none', + background: 'none', + overflow: 'visible', + outline: 'none', + padding: '0px', + width: '100%', + textAlign: 'center' + } +}; + +const Container = styled.div` + display: none; + position: fixed; + z-index: ${p=>p.zIndex?p.zIndex:500}; + ${p=>p.lang==='ar'?'left':'right'}: 5px; + top: 13px; + + @media(max-width: 1170px) { + display: block; + } +`; +const Viewport = styled.div``; +const Button = styled.button` + outline: none; + cursor: pointer; + text-transform: uppercase; + font-weight: 800; font-family: 'Avenir', 'Kaff', sans-serif; + color: ${props=>props.selected ? 'black' : '#828486'}; + text-decoration: ${props=>props.selected ? 'none' : 'underline'}; + font-size: 14px; + padding: 0 13px; + position: relative; +`; + +const LanguageChooser = styled(Button)` + width: 50px; + height: 50px; + margin-bottom: 10px; + + span { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + z-index: 100; + } + + &::after { + content: ' '; + width: 50px; + height: 50px; + background-color: white; + position: absolute; + border-radius: 50%; + border: 2px solid black; + top: 0; + left: 0; + } +`; + +const List = styled.ul` + margin: 0; + padding: 0; +`; + +const Item = styled.li` + list-style: none; + display: block; +`; + +const ArrowSvg = styled(Isvg)` + transform: rotate(270deg); + display: inline-block; + top: 0px; + position: relative; + + svg { + width: 10px; + height: 10px; + } + + svg * { + fill: black; + } +`; + +export class MobileLanguageChanger extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function + + constructor(props) { + super(); + + this.state = { + modalIsOpen: false + }; + + this.handleClick = this.handleClick.bind(this) + this.openModal = this.openModal.bind(this); + this.afterOpenModal = this.afterOpenModal.bind(this); + this.closeModal = this.closeModal.bind(this); + } + + toggleModal() { + this.setState({modalIsOpen: !this.state.modalIsOpen}); + } + + openModal() { + this.setState({modalIsOpen: true}); + } + + afterOpenModal() { + // references are now sync'd and can be accessed. + } + + closeModal() { + this.setState({modalIsOpen: false}); + } + + handleClick(language) { + + + if (this.props.intl.locale !== language) { + + this.props.handleChangeLocale(language); + this.props.handleChangeLocationSignal(); + // this.setState({modalIsOpen: false}); + } + } + + render() { + const lang = this.props.intl.locale; + return ( + + + + + + + this.handleClick('ar')} selected={lang === 'ar'} value={'ar'}> + AR + + + + this.handleClick('en')} selected={lang === 'en'} value={'en'}> + EN + + + + this.handleClick('es')} selected={lang === 'es'} value={'es'}> + ES + + + + + + + ); + } +} + +MobileLanguageChanger.propTypes = { + dispatch: PropTypes.func.isRequired, +}; + + +const mapStateToProps = createStructuredSelector({ + language: makeSelectLanguage() +}); + +function mapDispatchToProps(dispatch) { + return { + dispatch, + handleChangeLocale: (locale) => { + dispatch(changeLocale(locale)) + ; + }, + handleChangeLocationSignal: () => { + dispatch(loadData()); + }, + handleLoadLanguage: () => { + dispatch(loadLanguage()); + } + + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(MobileLanguageChanger)); diff --git a/app/containers/LanguageChanger/index.js b/app/containers/LanguageChanger/index.js index 28cdf66..afc12be 100644 --- a/app/containers/LanguageChanger/index.js +++ b/app/containers/LanguageChanger/index.js @@ -15,21 +15,29 @@ import { injectIntl } from 'react-intl'; import { makeSelectLanguage } from 'containers/App/selectors'; import { loadData, langChangeReloadData } from '../App/actions'; +import MobileLanguageChanger from './MobileLanguageChanger'; + const Container = styled.div` position: fixed; ${props=>props.lang==='ar'?'left: 50%': 'right:50%'} - top: 10px; + top: 45px; z-index: ${p=>p.zIndex?p.zIndex:500}; transform: ${props=>props.lang==='ar'?'translate(-530px,0)':'translate(530px,0)'}; + + // Mobile + @media(max-width: 1170px) { + display: none; + } `; const Viewport = styled.div``; const Button = styled.button` outline: none; cursor: pointer; font-weight: 800; font-family: 'Avenir', 'Kaff', sans-serif; - color: ${props=>props.selected ? 'black' : '#828486'}; + color: ${props=>props.selected ? 'black !important' : '#828486'}; text-decoration: ${props=>props.selected ? 'none' : 'underline'}; font-size: 14px; + padding: 0 13px; `; const List = styled.ul` @@ -49,7 +57,7 @@ const Item = styled.li` export class LanguageChanger extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function handleClick(e) { if (this.props.intl.locale !== e.target.value) { - + this.props.handleChangeLocale(e.target.value); this.props.handleChangeLocationSignal(); } @@ -57,18 +65,19 @@ export class LanguageChanger extends React.PureComponent { // eslint-disable-lin render() { const lang = this.props.intl.locale; + (this.props.changerClass); return ( - + - + - + - + @@ -104,3 +113,4 @@ function mapDispatchToProps(dispatch) { } export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(LanguageChanger)); +export { MobileLanguageChanger }; diff --git a/app/containers/Menu/index.js b/app/containers/Menu/index.js index 1461870..5ee0142 100644 --- a/app/containers/Menu/index.js +++ b/app/containers/Menu/index.js @@ -19,22 +19,26 @@ import staticText from './staticText'; import MenuArea from 'components/Menu/MenuArea'; import Home from 'components/Menu/Home'; +import MenuViewport from 'components/Menu/MenuViewport'; function Menu(props) { const lang = props.intl.locale; + return ( - - { window.location.pathname.match(/^\/(type|tag|search)|^\/$/) ? null : - ( - - ) - } - - - - - + + + {/* window.location.pathname.match(/^\/(type|tag|search)|^\/$/) ? null : + ( + + ) + */} + + + + + + ); } diff --git a/app/containers/ModalMenu/index.js b/app/containers/ModalMenu/index.js index 6bb33c1..dc090d4 100644 --- a/app/containers/ModalMenu/index.js +++ b/app/containers/ModalMenu/index.js @@ -12,28 +12,31 @@ import { injectIntl } from 'react-intl'; import MenuIcon from 'assets/images/icons/menu.svg'; import CloseIcon from 'assets/images/icons/close.svg'; import styled from 'styled-components'; - +import { MobileLanguageChanger } from 'containers/LanguageChanger'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; import TranslatableStaticText from 'containers/TranslatableStaticText'; import staticText from './staticText'; +import { Bell as WhatsHappeningBell} from 'containers/WhatsHappening'; const customStyles = { overlay: { backgroundColor: 'rgba(149, 149, 149, 0.75)', - zIndex: 600 + zIndex: 1100 }, content : { - top : '0px', - left : '50%', - right : 'auto', - bottom : 'auto', - transform : 'translate(-570px, 0)', - padding: '0', - border: 'none', - width: '300px', - height: '100%', - borderBottom: 'none', - borderWidth: 0, + position: 'absolute', + right: 'auto', + left: 'auto', + top: '0px', + bottom: 'auto', + border: '0px none', + background: 'rgb(255, 255, 255)', overflow: 'visible', + outline: 'none', + padding: '0px', + width: '100%', + textAlign: 'center', + zIndex: '900' } }; @@ -43,6 +46,12 @@ const Button = styled.button` position: absolute; ${props=>props.lang==='ar'?'right':'left'}: -1px; top: 10px; + + //mobile + @media(max-width: 1170px) { + ${props=>props.lang==='ar'?'right':'left'}: 0px; + top: 0px; + } `; const MenuText = styled.span`{ @@ -52,30 +61,68 @@ const MenuText = styled.span`{ margin-top: 2px; }`; -const CloseBox = styled.div`{ - position: absolute; - padding: 10px; - top: 0; - left: 0; +const CloseBox = styled.div` text-align: ${props=>props.lang==='ar'?'right':'left'}; - width: 100%; - border: 2px solid; - background-color: white; -}`; + padding: 35px 0; + top: 0; + width: 1170px; + display: inline-block; + height: 122px; + position: relative; -const MenuContainer= styled.div`{ - border: 2px solid; - padding: 75px 0px 20px; + // Mobile + @media(max-width: 1170px) { + width: 100%; + padding: 20px 0; + } +`; + +const MenuContainer= styled.div` + border: solid black; + border-width: 2px 2px 0; + // padding: 0 0px 20px; overflow: auto; - height: 100vh; -}`; -const CloseButton = styled.button`{ + width: 100%; + text-align: center; -}`; + &::after { + display: block; + content: ' '; + clear: both; + } + +`; +const CloseButton = styled.button` + +`; -const Viewport = styled.div`{ +const Viewport = styled.div` position: relative; -}`; +`; + +const MenuSection = styled.section` + width: 100%; + border-bottom: 2px solid black; +`; +const MenuHeaderSection = styled(MenuSection)``; +const MenuBodySection = styled(MenuSection)` + @media(max-width: 1170px) { + overflow: auto; + height: calc(100vh - 124px); + } +`; + +const BellArea = styled.div` + position: absolute; + ${p=>p.theme.isArabic?'left':'right'}: -5px; + top: 42px; + + @media(max-width: 1170px) { + ${p=>p.theme.isArabic?'left':'right'}: 13px; + top: 26px; + } +`; + export class ModalMenu extends React.Component { constructor() { @@ -105,6 +152,7 @@ export class ModalMenu extends React.Component { render() { const lang = this.props.intl.locale; + return ( + - ) } diff --git a/app/containers/OnboardingContent/index.js b/app/containers/OnboardingContent/index.js index 564cec3..2ce2399 100644 --- a/app/containers/OnboardingContent/index.js +++ b/app/containers/OnboardingContent/index.js @@ -16,6 +16,8 @@ import { Map } from 'immutable'; import { connect } from 'react-redux'; import ContentBlock from 'components/ContentBlock'; import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import { loadData } from 'containers/App/actions'; + import FAQ from 'containers/AboutPage/FAQ'; import TheToolbox from 'containers/AboutPage/TheToolbox'; @@ -46,17 +48,20 @@ const Header = styled.h2` padding-bottom: 15px; margin-bottom: 0; position:relative; + padding-top: 9px; &::after { content: ' '; position: absolute; - height: 80px; + height: 110px; border-right: 1px solid; width: 1PX; bottom: -65px; left: ${p=>p.leftLine || '50%'}; opacity: ${p=>p.showLine?'1':'0'}; transition: opacity 0.3s ease; + + @media(max-width: 1170px) { display: none; } } `; const Content = styled.div` @@ -71,13 +76,17 @@ const Button = styled.button` const List = styled.ul` padding: 0; margin: 20px 50px; + + @media(max-width: 1170px) { + margin: 5px; + } `; const CloseButton = styled(Button)` background: white; padding: 0; position: absolute; - ${p=>p.lang==='ar'?'left':'right'}: -27px; - top: 27px; + ${p=>p.lang==='ar'?'right':'left'}: -27px; + top: -27px; `; const OnboardedButton = styled(Button)` font-weight: 800; font-family: 'Avenir', 'Kaff', sans-serif; @@ -104,6 +113,15 @@ const ListItem = styled.li` h2 { font-size: 20px; } + button span.isvg { + position: absolute; + ${p=>p.lang==='ar'?'left':'right'}: 20px; + + @media(max-width: 1170px) { + top: 50%; + transform: translateY(-50%); + } + } button svg { transition: transform 0.4s ease; width: 10px; @@ -123,6 +141,15 @@ const ListItem = styled.li` } }}; } + + @media(max-width: 1170px) { + h2 { + font-size: 14px; + padding: 10px 0; + + padding-${p=>p.lang==='ar'?'left':'right'}: 30px; + } + } `; const HeaderArea = styled.div` @@ -130,7 +157,7 @@ const HeaderArea = styled.div` background-repeat: no-repeat; background-size: cover; background-color: rgba(0,0,0,0.6); - + background-position: center center; color: white; `; @@ -146,14 +173,23 @@ const LogoArea = styled.div` const SubTitle = styled.h2` margin: 0; `; -const Spiel = styled.div` - width: 42%; +const Spiel = styled(ContentBlock)` + margin: 0 28%; + text-align: center; + + @media(max-width: 1170px) { + margin: 0; + } `; const Overlay = styled.div` width: 100%; height: 100%; background-color: rgba(0,0,0,0.6); padding: 120px 39px 30px; + + @media(max-width: 1170px) { + padding: 120px 0 10px; + } `; class OnboardingContent extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function @@ -164,6 +200,11 @@ class OnboardingContent extends React.PureComponent { // eslint-disable-line rea }; } + componentDidMount(){ + if (this.props.aboutData.size === 0) { + this.props.onPageLoad(); + } + } handleClick(key) { if (this.state.chosen == key) { this.setState({ chosen: null }); @@ -191,19 +232,18 @@ class OnboardingContent extends React.PureComponent { // eslint-disable-line rea - + {/* {about.getIn(['modal','dismiss'])} + */} - + {/* {about.getIn(['modal','welcome'])} - + */} - - {about.getIn(['modal','introduction'])} - + {about.getIn(['modal','introduction'])} @@ -231,29 +271,41 @@ class OnboardingContent extends React.PureComponent { // eslint-disable-line rea ); } + renderData() { if (this.props.aboutData.size == 0 || !this.props.aboutData || this.props.aboutData == undefined) return null; const about = this.props.aboutData.get('about'); const misc = this.props.aboutData.getIn(['about', 'misc']); - return [ + const shownItems = this.props.aboutData.getIn(['about', 'modal-items-shown']); + const data = [ { + slug: 'whats-inside', title: misc.get('whats-inside'), content: }, { + slug: 'process', title: misc.get('process'), - content: + content: }, { + slug: 'values', title: misc.get('values'), content: }, { + slug: 'advisory-network', left: '80%', title: misc.get('advisory-network'), content: }, { + slug: 'team', title: misc.get('team'), content: }, { - title: misc.get('beautiful-trouble-and-action-aid'), - content: - }, - { + slug: 'partners', title: misc.get('partners'), content: }, { + slug: 'faq', title: misc.get('faq'), content: }, ]; + + return data.filter(item => shownItems.contains(item.slug)); } } @@ -309,6 +359,9 @@ function mapDispatchToProps(dispatch) { dispatch, onOnboard: (evt) => { dispatch(onboardUser()); + }, + onPageLoad: (evt) => { + dispatch(loadData()); } }; } diff --git a/app/containers/OnboardingModal/index.js b/app/containers/OnboardingModal/index.js index 489118b..77fca35 100644 --- a/app/containers/OnboardingModal/index.js +++ b/app/containers/OnboardingModal/index.js @@ -12,24 +12,24 @@ import OnboardingContent from 'containers/OnboardingContent'; import MenuIcon from 'assets/images/icons/menu.svg'; import CloseIcon from 'assets/images/icons/close.svg'; import styled from 'styled-components'; -import LanguageChanger from 'containers/LanguageChanger'; +import LanguageChanger, { MobileLanguageChanger } from 'containers/LanguageChanger'; const customStyles = (lang) => { return { overlay: { backgroundColor: 'hsla(0,0%,58%,.75)', - zIndex: 600, + zIndex: 3000, overflow: 'auto', }, content : { direction: `${lang==='ar' ? 'rtl':'ltr'}`, textAlign: `${lang==='ar' ? 'right':'left'}`, - top : '57px', + top : '75px', left : `${lang==='ar' ? 'auto':'50%'}`, right : `${lang==='ar' ? '50%':'auto'}`, bottom : 'auto', transform : `${lang==='ar' ? 'translate(50%,0)':'translate(-50%,0)'}`, padding: '0', - width: '1100px', + width: '960px', // minHeight: '80vh', overflow: 'visible', borderRadius: 0, @@ -103,14 +103,12 @@ export class OnboardingModal extends React.Component { this.setState({modalIsOpen: false}); } - renderLanguageChanger() { - return (); - } render() { const lang = this.props.intl.locale; return ( - {this.renderLanguageChanger()} + + + this.recaptcha = ref } + sitekey={ RECAPTCHA_SITE_KEY } + onResolved={this.handleRecaptcha.bind(this)} + /> + + ); + } + + render() { + const {buildMessage} = this.props.translatable; + return ( + + + +
+ +
+ { this.props.realWorldEx.complete ? this.renderComplete() : this.renderForm() } +
+
+ ); + } +} + +SubmitResource.propTypes = { + dispatch: PropTypes.func.isRequired +}; + +const mapStateToProps = createStructuredSelector({ + realWorldEx: makeSelectSubmitResource(), +}); + +function mapDispatchToProps(dispatch) { + return { + dispatch, + onFormSubmit: (captchaResponse, values) => { + if (evt !== undefined && evt.preventDefault) evt.preventDefault(); + dispatch(submitResource({...values, captcha: captchaResponse})); + } + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(injectStaticText(SubmitResource)); diff --git a/app/containers/SubmitResource/reducer.js b/app/containers/SubmitResource/reducer.js new file mode 100644 index 0000000..2c36782 --- /dev/null +++ b/app/containers/SubmitResource/reducer.js @@ -0,0 +1,54 @@ +/* + * + * SubmitRealWorldExample reducer + * + */ + +import { fromJS } from 'immutable'; +import { + DEFAULT_ACTION, + SUBMIT_RESOURCE, + SUBMISSION_COMPLETE, + SUBMISSION_ERROR, +} from './constants'; + +const initialState = fromJS({ + url: null, + title: null, + description: null, + documentLink: null, + documentTitle: null, + captcha: null, + submitting: false, + error: false, + complete: false +}); + +function submitResourceReducer(state = initialState, action) { + switch (action.type) { + case DEFAULT_ACTION: + return state; + case SUBMIT_RESOURCE: + return state + .set('url', action.data.url) + .set('title', action.data.title) + .set('description', action.data.description) + .set('captcha', action.data.captcha) + .set('documentTitle', action.data.documentTitle) + .set('documentLink', action.data.documentLink) + .set('submitting', true) + .set('error', false) + .set('complete', false); + case SUBMISSION_COMPLETE: + return initialState; + case SUBMISSION_ERROR: + return state + .set('complete', true) + .set('submitting', false) + .set('error', true); + default: + return state; + } +} + +export default submitResourceReducer; diff --git a/app/containers/SubmitResource/sagas.js b/app/containers/SubmitResource/sagas.js new file mode 100644 index 0000000..a7e3f0f --- /dev/null +++ b/app/containers/SubmitResource/sagas.js @@ -0,0 +1,49 @@ +import { take, call, put, select, takeLatest } from 'redux-saga/effects'; + +import { SUBMIT_RESOURCE, SUBMISSION_COMPLETE, SUBMISSION_ERROR } from './constants'; +import { successfulSubmission, submissionError } from './actions'; +// Individual exports for testing + +import request from 'utils/request'; + +export const getSubmitResource = (state) => state.get('submitResource'); + +export function* submitResource() { + const submitResource = yield select(getSubmitResource); + const url = submitResource.get('url'); + const title = submitResource.get('title'); + const description = submitResource.get('description'); + const captcha = submitResource.get('captcha'); + const documentLink = submitResource.get('documentLink'); + const documentTitle = submitResource.get('documentTitle'); + + try { + const requestUrl = `https://api.beautifulrising.org/intake/resource`; + yield put(request(requrestUrl, { + method: "POST", + header: { + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ + 'g-recaptcha-response': captcha, + 'document_title': documentTitle, + 'document_link': document_link, + 'title': title, + 'link': url, + 'description': description + }) + })); + + yield put(successfulSubmission()); + } catch(e) { + yield call(put, submissionError(e)) + } +} +export function* listenForSubmissions() { + const action = yield takeLatest(SUBMIT_RESOURCE, submitResource); +} + +// All sagas to be loaded +export default [ + listenForSubmissions, +]; diff --git a/app/containers/SubmitResource/selectors.js b/app/containers/SubmitResource/selectors.js new file mode 100644 index 0000000..3c59686 --- /dev/null +++ b/app/containers/SubmitResource/selectors.js @@ -0,0 +1,25 @@ +import { createSelector } from 'reselect'; + +/** + * Direct selector to the submitRealWorldExample state domain + */ +const makeSelectSubmitResourceDomain = () => (state) => state.get('submitResource'); + +/** + * Other specific selectors + */ + + +/** + * Default selector used by SubmitRealWorldExample + */ + +const makeSelectSubmitResource = () => createSelector( + makeSelectSubmitResourceDomain(), + (substate) => substate.toJS() +); + +export default makeSelectSubmitResource; +export { + makeSelectSubmitResourceDomain, +}; diff --git a/app/containers/SubmitResource/staticText.js b/app/containers/SubmitResource/staticText.js new file mode 100644 index 0000000..9028c68 --- /dev/null +++ b/app/containers/SubmitResource/staticText.js @@ -0,0 +1,22 @@ +export default { + header: { + id: 'submit-resource.header', + defaultMessage: 'do you use a helpful resource\n\nthat’s not listed here?\n\nadd it below', + }, + url: { + id: 'submit-resource.link-placeholder', + defaultMessage: 'www.urlofresource.com' + }, + title: { + id: 'submit-resource.title-placeholder', + defaultMessage: 'Give a short title for your example' + }, + description: { + id: 'submit-resource.brief-description-placeholder', + defaultMessage: 'A brief description (150 characters)' + }, + submit: { + id: 'submit-resource.submit', + defaultMessage: 'Submit' + } +} diff --git a/app/containers/SubmitResource/tests/actions.test.js b/app/containers/SubmitResource/tests/actions.test.js new file mode 100644 index 0000000..c1bdd9a --- /dev/null +++ b/app/containers/SubmitResource/tests/actions.test.js @@ -0,0 +1,18 @@ + +import { + defaultAction, +} from '../actions'; +import { + DEFAULT_ACTION, +} from '../constants'; + +describe('SubmitRealWorldExample actions', () => { + describe('Default Action', () => { + it('has a type of DEFAULT_ACTION', () => { + const expected = { + type: DEFAULT_ACTION, + }; + expect(defaultAction()).toEqual(expected); + }); + }); +}); diff --git a/app/containers/SubmitResource/tests/index.test.js b/app/containers/SubmitResource/tests/index.test.js new file mode 100644 index 0000000..b30d396 --- /dev/null +++ b/app/containers/SubmitResource/tests/index.test.js @@ -0,0 +1,10 @@ +// import React from 'react'; +// import { shallow } from 'enzyme'; + +// import { SubmitRealWorldExample } from '../index'; + +describe('', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(false); + }); +}); diff --git a/app/containers/SubmitResource/tests/reducer.test.js b/app/containers/SubmitResource/tests/reducer.test.js new file mode 100644 index 0000000..682e843 --- /dev/null +++ b/app/containers/SubmitResource/tests/reducer.test.js @@ -0,0 +1,9 @@ + +import { fromJS } from 'immutable'; +import submitRealWorldExampleReducer from '../reducer'; + +describe('submitRealWorldExampleReducer', () => { + it('returns the initial state', () => { + expect(submitRealWorldExampleReducer(undefined, {})).toEqual(fromJS({})); + }); +}); diff --git a/app/containers/SubmitResource/tests/sagas.test.js b/app/containers/SubmitResource/tests/sagas.test.js new file mode 100644 index 0000000..6dd4d4e --- /dev/null +++ b/app/containers/SubmitResource/tests/sagas.test.js @@ -0,0 +1,15 @@ +/** + * Test sagas + */ + +/* eslint-disable redux-saga/yield-effects */ +// import { take, call, put, select } from 'redux-saga/effects'; +// import { defaultSaga } from '../sagas'; + +// const generator = defaultSaga(); + +describe('defaultSaga Saga', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(false); + }); +}); diff --git a/app/containers/SubmitResource/tests/selectors.test.js b/app/containers/SubmitResource/tests/selectors.test.js new file mode 100644 index 0000000..4a577cc --- /dev/null +++ b/app/containers/SubmitResource/tests/selectors.test.js @@ -0,0 +1,10 @@ +// import { fromJS } from 'immutable'; +// import { makeSelectSubmitRealWorldExampleDomain } from '../selectors'; + +// const selector = makeSelectSubmitRealWorldExampleDomain(); + +describe('makeSelectSubmitRealWorldExampleDomain', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(false); + }); +}); diff --git a/app/containers/Tags/index.js b/app/containers/Tags/index.js index d127c01..434287c 100644 --- a/app/containers/Tags/index.js +++ b/app/containers/Tags/index.js @@ -8,9 +8,12 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; import { injectIntl } from 'react-intl'; import { createStructuredSelector } from 'reselect'; +import Isvg from 'react-inlinesvg'; import { makeSelectAllTags } from 'containers/App/selectors'; import { push } from 'react-router-redux'; +import ClearIcon from 'assets/images/icons/clear.svg'; + import TranslatableStaticText from 'containers/TranslatableStaticText'; import ContentBlock from 'components/ContentBlock'; import LanguageThemeProvider from 'components/LanguageThemeProvider'; @@ -20,7 +23,6 @@ import MenuTitle from 'components/MenuTitle'; import MenuList from 'components/MenuList'; import MenuListItem from 'components/MenuListItem'; import Link from 'components/Link'; -import ClearButton from 'components/ClearButton'; import {slugify} from 'utils/tags' @@ -48,9 +50,9 @@ export class Tags extends React.PureComponent { // eslint-disable-line react/pre return ( - - - + ); diff --git a/app/containers/ToolKeyItems/index.js b/app/containers/ToolKeyItems/index.js index a4c9fe5..0c36092 100644 --- a/app/containers/ToolKeyItems/index.js +++ b/app/containers/ToolKeyItems/index.js @@ -25,6 +25,10 @@ import staticText from './staticText'; class ToolKeyItems extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function + constructor(props) { + super(); + } + generateKeyItems(list, type) { if (!list || list === undefined || list.length == 0) return null; const { locale } = this.props.intl; @@ -58,14 +62,24 @@ class ToolKeyItems extends React.PureComponent { // eslint-disable-line react/pr render() { + const keyTactics=this.props['key-modules'] ? this.props['key-modules']['key-tactics'] : []; + const keyPrinciples=this.props['key-modules'] ? this.props['key-modules']['key-principles'] : []; + const keyTheories=this.props['key-modules'] ? this.props['key-modules']['key-theories'] : []; + const keyMethodologies=this.props['key-modules'] ? this.props['key-modules']['key-methodologies'] : []; + + const showTactics = this.props.showIfUntranslated('key-tactics'); + const showPrinciples = this.props.showIfUntranslated('key-principles'); + const showTheories = this.props.showIfUntranslated('key-theories'); + const showMethodologies = this.props.showIfUntranslated('key-methodologies'); + return (
- {this.props.showTactics ? this.generateKeyItems(this.props.keyTactics, this.props.keyTactics&&this.props.keyTactics.length > 1 ? "tactics" : "tactic") : null} - {this.props.showPrinciples ? this.generateKeyItems(this.props.keyPrinciples, this.props.keyPrinciples&&this.props.keyPrinciples.length > 1 ? "principles" : "principle") : null} - {this.props.showTheories ? this.generateKeyItems(this.props.keyTheories, this.props.keyTheories&&this.props.keyTheories.length > 1 ? "theories" : "theory") : null} - {this.props.showMethodologies ? this.generateKeyItems(this.props.keyMethodologies, this.props.keyMethodologies&&this.props.keyMethodologies.length > 1 ? "methodologies" : "methodology") : null} + {showTactics ? this.generateKeyItems(keyTactics, keyTactics&&keyTactics.length > 1 ? "tactics" : "tactic") : null} + {showPrinciples ? this.generateKeyItems(keyPrinciples, keyPrinciples&&keyPrinciples.length > 1 ? "principles" : "principle") : null} + {showTheories ? this.generateKeyItems(keyTheories, keyTheories&&keyTheories.length > 1 ? "theories" : "theory") : null} + {showMethodologies ? this.generateKeyItems(keyMethodologies, keyMethodologies&&keyMethodologies.length > 1 ? "methodologies" : "methodology") : null}
diff --git a/app/containers/ToolPage/Header/InteractiveArea.js b/app/containers/ToolPage/Header/InteractiveArea.js new file mode 100644 index 0000000..05d3a5f --- /dev/null +++ b/app/containers/ToolPage/Header/InteractiveArea.js @@ -0,0 +1,46 @@ +import React, { PropTypes } from 'react'; +import { injectIntl } from 'react-intl'; +import Isvg from 'react-inlinesvg'; + +import AdderRemover from 'containers/Tools/AdderRemover'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import ShareButton from 'containers/ShareButton'; +import ContentBlock from 'components/ContentBlock'; +import ContinentIcon from 'components/ContinentIcon'; + +import ShareIcon from 'assets/images/icons/share-small.svg'; + +import {CTA, ShareContainer, + InteractiveViewport, InteractiveContainer} from 'components/ToolPage/Header'; + +class InteractiveArea extends React.PureComponent { + constructor() { + super(); + } + render() { + const { locale } = this.props.intl; + return ( + + + + + + + + + + + + + + + + + + ) + } +} + +export default injectIntl(InteractiveArea); diff --git a/app/containers/ToolPage/Header/MobileInteractiveArea.js b/app/containers/ToolPage/Header/MobileInteractiveArea.js new file mode 100644 index 0000000..6f5c11b --- /dev/null +++ b/app/containers/ToolPage/Header/MobileInteractiveArea.js @@ -0,0 +1,46 @@ +import React, { PropTypes } from 'react'; +import { injectIntl } from 'react-intl'; +import Isvg from 'react-inlinesvg'; + +import AdderRemover from 'containers/Tools/AdderRemover'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import ShareButton from 'containers/ShareButton'; +import ContentBlock from 'components/ContentBlock'; +import ContinentIcon from 'components/ContinentIcon'; + +import ShareIcon from 'assets/images/icons/share-small.svg'; + +import {CTA, ShareContainer, + InteractiveViewport, MobileInteractiveContainer} from 'components/ToolPage/Header'; + +class MobileInteractiveArea extends React.PureComponent { + constructor() { + super(); + } + render() { + const { locale } = this.props.intl; + return ( + + + + + + + + + + + + + + + + + + ) + } +} + +export default injectIntl(MobileInteractiveArea); diff --git a/app/containers/ToolPage/Header/index.js b/app/containers/ToolPage/Header/index.js new file mode 100644 index 0000000..319ac23 --- /dev/null +++ b/app/containers/ToolPage/Header/index.js @@ -0,0 +1,119 @@ +import React, { PropTypes } from 'react'; +import { Link } from 'react-router'; +import { connect } from 'react-redux'; +import { injectIntl } from 'react-intl'; +import { createStructuredSelector } from 'reselect'; +import Markdown from 'react-markdown'; +import Isvg from 'react-inlinesvg'; +import styled, {ThemeProvider} from 'styled-components'; + +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import ContentBlock from 'components/ContentBlock'; + +import { + Caption, Container, + Content, ContentViewport, + Title, ToolType, + Viewport, +} from 'components/ToolPage/Header'; + +import { BR_IMAGE_PREFIX } from 'containers/Tools/constants'; +import { RouterLink } from 'utils/markdown'; +import ShareIcon from 'assets/images/icons/share-small.svg'; +import ShareButton from 'containers/ShareButton'; +import TypeFlag from 'components/TypeFlag'; +import TypeOverlay from 'components/TypeOverlay'; + +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import staticText from '../staticText'; + +import InteractiveArea from './InteractiveArea'; +import MobileInteractiveArea from './MobileInteractiveArea'; +import WhereWhen from 'components/ToolPage/Header/WhereWhen'; + +const MobileWhenWhereContainer = styled.div` + position: absolute; + left: 0; + top: -15px; + display: none; + + @media(max-width: 1170px) { + display: block; + } +`; +export class Header extends React.PureComponent { + constructor() { + super(); + } + + isType(type, key) { + return this.props.type === type || + (this.props[key] && this.props[key].length > 0); + } + + getBanner() { + if(this.props['module-type-effective'] === 'snapshot') { + return (); + } else if ( ['full', 'gallery'].includes(this.props['module-type-effective'])) { + return ( + ); + } + } + + render() { + + return ( + + + + + + + + + + + + + + + + {this.props.title} + + + + + + + + { this.getBanner() } + + + + ); + } +} + +Header.propTypes = { + dispatch: PropTypes.func.isRequired, +}; + + +function mapDispatchToProps(dispatch) { + return { + dispatch + } +} + +export default connect(null, mapDispatchToProps)(injectIntl(Header)); diff --git a/app/containers/ToolPage/MainStage/ByLine.js b/app/containers/ToolPage/MainStage/ByLine.js new file mode 100644 index 0000000..0d48371 --- /dev/null +++ b/app/containers/ToolPage/MainStage/ByLine.js @@ -0,0 +1,23 @@ +import React from 'react'; +import styled from 'styled-components'; +import { injectIntl } from 'react-intl'; +import Markdown from 'react-remarkable'; +import ContentBlock from 'components/ContentBlock'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import {ByLine as ByLineContainer, ContentContainer} from 'components/ToolPage/Main'; +import staticText from '../staticText'; + +function ByLine(props) { + return ( + + + + + + + + ) +} + +export default ByLine; diff --git a/app/containers/ToolPage/MainStage/ContributedBy.js b/app/containers/ToolPage/MainStage/ContributedBy.js new file mode 100644 index 0000000..309969a --- /dev/null +++ b/app/containers/ToolPage/MainStage/ContributedBy.js @@ -0,0 +1,106 @@ +import React, { PropTypes } from 'react'; +import { connect } from 'react-redux'; +import { injectIntl } from 'react-intl'; +import { createStructuredSelector } from 'reselect'; +import styled from 'styled-components'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import { CollapsingHeader, ContentContainer, CollapsingContent } from 'components/ToolPage/Main'; +import CollapsingSection from 'components/CollapsingSection'; +import ContentBlock from 'components/ContentBlock'; +import AskTheContributor from 'containers/AskTheContributor'; +import CouldBeYou from 'components/CouldBeYou'; +import Author from 'containers/Author'; +import makeSelectToolPage from '../selectors'; +import { setChosenSection } from '../actions'; +import { CONTRIBUTED_BY } from '../constants'; +import staticText from '../staticText'; + + +const FirstCollapsingHeader = styled(CollapsingHeader)` + @media(max-width: 1170px) { + margin-top: 0; + } +`; + +class ContributedBy extends React.PureComponent { + + constructor(props) { + super(); + } + + renderAskContributors() { + return () + } + + renderAuthors() { + return this.props.authors.map(item=>); + } + + handleClick() { + + // Set it to null if the same CONTRIBUTED_BY + if (this.props.ToolPage.chosenSection === CONTRIBUTED_BY) { + this.props.handleSectionClick(null); + } else { + this.props.handleSectionClick(CONTRIBUTED_BY); + } + + } + + render() { + if (!this.props.authors || this.props.authors.length == 0) { + return null; + } + + const authors = this.renderAuthors(); + const askTheAuthors = this.renderAskContributors(); + + return ( + + + + + + + )} + + shouldOpen={ + this.props.ToolPage.expandAll || + this.props.ToolPage.chosenSection === CONTRIBUTED_BY + } + > + + {authors} + {askTheAuthors} + + + + + + ) + } + +} + +const mapStateToProps = createStructuredSelector({ + ToolPage: makeSelectToolPage() +}); + +function mapDispatchToProps(dispatch) { + return { + handleSectionClick: (chosenSection) => { + dispatch(setChosenSection(chosenSection)); + } + }; +} + + +export default connect(mapStateToProps, mapDispatchToProps)(ContributedBy); diff --git a/app/containers/ToolPage/MainStage/Epigraph.js b/app/containers/ToolPage/MainStage/Epigraph.js new file mode 100644 index 0000000..2a95b68 --- /dev/null +++ b/app/containers/ToolPage/MainStage/Epigraph.js @@ -0,0 +1,34 @@ +import React from 'react'; +import styled from 'styled-components'; +import { injectIntl } from 'react-intl'; +import Markdown from 'react-remarkable'; +import ContentBlock from 'components/ContentBlock'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import {Epigraph as EpigraphContainer, ContentContainer} from 'components/ToolPage/Main'; + +function Epigraph(props) { + const { locale } = props.intl; + const content = props.epigraphs ? + props.epigraphs.map(item => { + const text = item.replace(/—/g, '\r\n\r\n––'); + + return ( + + + + ); + }) : + null; + + return ( + + + + {content} + + + + ) +} + +export default injectIntl(Epigraph); diff --git a/app/containers/ToolPage/MainStage/FullContent.js b/app/containers/ToolPage/MainStage/FullContent.js new file mode 100644 index 0000000..108d2be --- /dev/null +++ b/app/containers/ToolPage/MainStage/FullContent.js @@ -0,0 +1,62 @@ +import React from 'react'; +import Markdown from 'react-markdown'; +import {injectIntl} from 'react-intl'; + +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import ContentBlock from 'components/ContentBlock'; +import Epigraph from './Epigraph'; +import Origins from './Origins' +import { RouterLink } from 'utils/markdown'; +import { ContentContainer, PullQuote } from 'components/ToolPage/Main'; + +class FullContent extends React.PureComponent { + + renderWithPullQuote(content) { + const {locale} = this.props.intl; + const count = 1 + ((Math.random() * 100) % 2); + const split = content.split('\n').filter(item => item !== ""); + let contents = split.map((item, ind) => { return () }); + let pullQuote = + contents.splice(count, 0, ("{pullQuote}")); + + return ( +
+ { contents } +
+ ); + } + generateContent(content) { + if (this.props['pull-quote'] !== '') { + return this.renderWithPullQuote(content); + } else { + + } + } + render() { + if (!this.props['full-write-up']) return null; + + const imageReplaced = this.props['full-write-up'].replace(/\(([^()]*?)\.jpg\)/g,"(https://www.beautifulrising.org/$1.jpg)"); + + const content = this.generateContent(imageReplaced); + + return( + + + + + + { content } + + + + ); + } + +} + +export default injectIntl(FullContent); diff --git a/app/containers/ToolPage/MainStage/LearnMore.js b/app/containers/ToolPage/MainStage/LearnMore.js new file mode 100644 index 0000000..cebebc3 --- /dev/null +++ b/app/containers/ToolPage/MainStage/LearnMore.js @@ -0,0 +1,93 @@ +/* + * + * ToolPage + * + */ + +import React, { PropTypes } from 'react'; +import { connect } from 'react-redux'; +import { createStructuredSelector } from 'reselect'; +import LatinThemeProvider from 'components/LatinThemeProvider'; +import AdderRemover from 'containers/Tools/AdderRemover'; +import { LearnMoreList, ToolMainContent, ToolLearnMoreContent, ToolMainContentHeader } from 'components/ToolsPageComponents'; +import ToolLearnMoreItem from 'containers/ToolPage/ToolLearnMoreItem'; + +import { CollapsingHeader, ContentContainer, CollapsingContent } from 'components/ToolPage/Main'; +import CollapsingSection from 'components/CollapsingSection'; + +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import staticText from '../staticText'; + +import makeSelectToolPage from '../selectors'; +import { setChosenSection } from '../actions'; +import { LEARN_MORE } from '../constants'; + +// import { makeSelectToolById } from 'containers/Tool/selectors'; + +class LearnMore extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function + + constructor() { + super(); + } + + handleClick() { + + // Set it to null if the same LEARN_MORE + if (this.props.ToolPage.chosenSection === LEARN_MORE) { + this.props.handleSectionClick(null); + } else { + this.props.handleSectionClick(LEARN_MORE); + } + + } + + render() { + if (!this.props['learn-more'] || + this.props['learn-more'] === undefined || + this.props['learn-more'].length === 0) { + return null; + } + + return ( + + + + )} + + onClick={this.handleClick.bind(this)} + shouldOpen={ + this.props.ToolPage.expandAll || + this.props.ToolPage.chosenSection === LEARN_MORE + } + > + + + + + {this.props['learn-more'].map(item=>)} + + + + + + ); + } + +} + +const mapStateToProps = createStructuredSelector({ + ToolPage: makeSelectToolPage() +}); + +function mapDispatchToProps(dispatch) { + return { + handleSectionClick: (chosenSection) => { + dispatch(setChosenSection(chosenSection)); + } + }; +} + + +export default connect(mapStateToProps, mapDispatchToProps)(LearnMore); diff --git a/app/containers/ToolPage/MainStage/MainContent.js b/app/containers/ToolPage/MainStage/MainContent.js new file mode 100644 index 0000000..911cf99 --- /dev/null +++ b/app/containers/ToolPage/MainStage/MainContent.js @@ -0,0 +1,88 @@ +import React, { PropTypes } from 'react'; +import Markdown from 'react-markdown'; +import { createStructuredSelector } from 'reselect'; +import { connect } from 'react-redux'; + +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import ContentBlock from 'components/ContentBlock'; +import { ContentContainer, ShowContentButton } from 'components/ToolPage/Main'; +import ShortContent from './ShortContent'; +import FullContent from './FullContent'; + +import { PROP_FULL_WRITE_UP, PROP_SHORT_WRITE_UP } from '../constants'; + +import makeSelectToolPage from '../selectors'; +import {setExpandAll} from '../actions'; + +import staticText from '../staticText'; + +class MainContent extends React.PureComponent { + + constructor(props) { + super(props); + } + + componentWillReceiveProps(nextProps) { + } + + generateContent(){ + if (this.props.ToolPage.expandAll) { + return (); + } else { + return () + } + } + + handleShowClick() { + this.props.handleMoreLessClick(!this.props.ToolPage.expandAll); + } + + render() { + + // IF long writeup is translated + if( this.props.showIfUntranslated(PROP_FULL_WRITE_UP) + && this.props['full-write-up'] ) { + + const mainContent = this.generateContent(); + const buttonText = this.props.ToolPage.expandAll + ? () + : (); + + return ( + + {mainContent} + + + {buttonText} + + + + ); + } + + // IF Short writeup is also not translated + if ( + !this.props.showIfUntranslated(PROP_SHORT_WRITE_UP) + ) { return null; } + + // IF short writeup is translated + return ( + + ); + } +} + +const mapStateToProps = createStructuredSelector({ + ToolPage: makeSelectToolPage() +}); + +function mapDispatchToProps(dispatch) { + return { + handleMoreLessClick: (isExpandAll) => { + dispatch(setExpandAll(isExpandAll)); + } + }; +} + + +export default connect(mapStateToProps, mapDispatchToProps)(MainContent); diff --git a/app/containers/ToolPage/MainStage/Origins.js b/app/containers/ToolPage/MainStage/Origins.js new file mode 100644 index 0000000..91979d0 --- /dev/null +++ b/app/containers/ToolPage/MainStage/Origins.js @@ -0,0 +1,32 @@ +import React from 'react'; +import styled from 'styled-components'; +import { injectIntl } from 'react-intl'; +import Markdown from 'react-remarkable'; +import ContentBlock from 'components/ContentBlock'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import {ContentContainer} from 'components/ToolPage/Main'; +import { injectStaticText } from 'containers/TranslatableStaticText'; +import staticText from '../staticText'; + +const OriginsContent = styled(ContentBlock)` + +`; + +function Origins(props) { + const { locale } = props.intl; + const { buildMessage } = props.translatable; + + const originsText = buildMessage(staticText.origins); + + return ( + + + + + + + + ) +} + +export default injectStaticText(injectIntl(Origins)); diff --git a/app/containers/ToolPage/MainStage/RealWorld.js b/app/containers/ToolPage/MainStage/RealWorld.js new file mode 100644 index 0000000..f1685a1 --- /dev/null +++ b/app/containers/ToolPage/MainStage/RealWorld.js @@ -0,0 +1,115 @@ +/* + * + * ToolPage + * + */ + +import React, { PropTypes } from 'react'; +import { connect } from 'react-redux'; +import { injectIntl } from 'react-intl'; +import { createStructuredSelector } from 'reselect'; +import Isvg from 'react-inlinesvg'; +import styled, { ThemeProvider } from 'styled-components'; + +import { RealWorldIcon } from 'components/ToolsComponents'; +import LatinThemeProvider from 'components/LatinThemeProvider'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import { LearnMoreList, ToolMainContent, + ToolMainContentHeader, RealWorldContainer, + RealWorldHeader, RealWorldToggle, RealWorldItems } from 'components/ToolsPageComponents'; +import SubmitRealWorldExample from 'containers/SubmitRealWorldExample'; +import RealWorldItem from 'components/RealWorldItem'; + +import RealWorldIconImage from 'assets/images/icons/real-world.svg'; +import ArrowIcon from 'assets/images/icons/arrow.svg'; + +import { CollapsingHeader, ContentContainer, CollapsingContent } from 'components/ToolPage/Main'; +import CollapsingSection from 'components/CollapsingSection'; +import ContentBlock from 'components/ContentBlock'; + +// import { makeSelectToolById } from 'containers/Tool/selectors'; + +import TranslatableStaticText from 'containers/TranslatableStaticText'; + +import makeSelectToolPage from '../selectors'; +import { setChosenSection } from '../actions'; +import { REAL_WORLD_EXAMPLE } from '../constants'; + +import staticText from '../staticText'; + +class RealWorld extends React.Component { // eslint-disable-line react/prefer-stateless-function + + constructor(props) { + super(props); + this.state = { + isCollapsed: true + } + } + generateRealWorldList() { + + if (!this.props['real-world-examples'] + || this.props['real-world-examples'].length == 0) + return null; + + return ( +
+ {this.props['real-world-examples'].map((item, index)=>())} +
+ ) + + } + + handleClick() { + + // Set it to null if the same REAL_WORLD_EXAMPLE + if (this.props.ToolPage.chosenSection === REAL_WORLD_EXAMPLE) { + this.props.handleSectionClick(null); + } else { + this.props.handleSectionClick(REAL_WORLD_EXAMPLE); + } + + } + + render() { + (this.props.ToolPage); + return ( + + + + )}> + + + + {this.generateRealWorldList()} + + + + + + + ); + } +} + +const mapStateToProps = createStructuredSelector({ + ToolPage: makeSelectToolPage() +}); + +function mapDispatchToProps(dispatch) { + return { + handleSectionClick: (chosenSection) => { + dispatch(setChosenSection(chosenSection)); + } + }; +} + + +export default connect(mapStateToProps, mapDispatchToProps)(RealWorld); diff --git a/app/containers/ToolPage/MainStage/ShortContent.js b/app/containers/ToolPage/MainStage/ShortContent.js new file mode 100644 index 0000000..910db4f --- /dev/null +++ b/app/containers/ToolPage/MainStage/ShortContent.js @@ -0,0 +1,23 @@ +import React, { PropTypes } from 'react'; +import Markdown from 'react-markdown'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import ContentBlock from 'components/ContentBlock'; +import { RouterLink } from 'utils/markdown'; +import { PROP_SHORT_WRITE_UP } from '../constants'; +import {ShortContentContainer} from 'components/ToolPage/Main' + +export default function(props) { + if (!props[PROP_SHORT_WRITE_UP] ) return null; + return( + + + + + + + + ); +} diff --git a/app/containers/ToolPage/MainStage/Untranslated.js b/app/containers/ToolPage/MainStage/Untranslated.js new file mode 100644 index 0000000..e857d4c --- /dev/null +++ b/app/containers/ToolPage/MainStage/Untranslated.js @@ -0,0 +1,45 @@ +/* + * + * ToolPage + * + */ + +import React, { PropTypes } from 'react'; +import { connect } from 'react-redux'; +import { createStructuredSelector } from 'reselect'; +import Markdown from 'react-markdown'; +import styled from 'styled-components'; + +import { injectStaticText } from 'containers/TranslatableStaticText'; +import { ContentContainer } from 'components/ToolPage/Main' +import ContentBlock from 'components/ContentBlock'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import {MODULE_TYPE_UNTRANSLATED} from 'components/CommonComponents/constants'; + +import staticText from '../staticText'; + +function Untranslated(props) { // eslint-disable-line react/prefer-stateless-function + + const { buildMessage } = props.translatable; + const origLink = `/${props.lang}/tool/${props.slug}`; + const message = buildMessage(staticText.translationNeeded, { + link: origLink, + form: buildMessage(staticText.needsTranslationForm) + }) + + if (props['module-type-effective'] !== MODULE_TYPE_UNTRANSLATED) return null; + + return ( + + + + + + + + ); +} + +export default injectStaticText(Untranslated); diff --git a/app/containers/ToolPage/MainStage/index.js b/app/containers/ToolPage/MainStage/index.js new file mode 100644 index 0000000..c8a92b9 --- /dev/null +++ b/app/containers/ToolPage/MainStage/index.js @@ -0,0 +1,84 @@ +import React, { PropTypes } from 'react'; +import Markdown from 'react-markdown'; +import { Link } from 'react-router'; +import { connect } from 'react-redux'; +import { createStructuredSelector } from 'reselect'; +import styled from 'styled-components'; +import { makeSelectAllToolsWithSlugIndex } from 'containers/App/selectors'; + +import { RouterLink } from 'utils/markdown'; + +import ToolKeyItems from 'containers/ToolKeyItems'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import staticText from '../staticText'; + +import Untranslated from './Untranslated'; +import MainContent from './MainContent'; +import ByLine from './ByLine'; +import ContributedBy from './ContributedBy'; +import RealWorld from './RealWorld'; +import LearnMore from './LearnMore'; +import WhyItWorked from '../Sidebar/WhyItWorked'; +import WhyItFailed from '../Sidebar/WhyItFailed'; +import PotentialRisk from '../Sidebar/PotentialRisk'; +import RelatedTools from '../Sidebar/RelatedTools'; +import Tags from '../Sidebar/Tags'; +import Training from '../Sidebar/Training'; + +const MobileContent = styled.div` + display: none; + @media(max-width: 1170px) { + display: block; + } +`; + +const ContentSeparation = styled.div` + height: 72px; +`; +class MainStage extends React.PureComponent { + constructor(props) { + super(); + } + + render() { + return ( + + + + + + + + + + + + + + {/* Show RealWorld example only on non-stories*/} + {this.props.type !== "story" ? : null} + + + + + + + + + + ); + } +} + +const mapStateToProps = createStructuredSelector({ + toolsList: makeSelectAllToolsWithSlugIndex() +}); + +function mapDispatchToProps(dispatch) { + return { + dispatch + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(MainStage); diff --git a/app/containers/ToolPage/Sidebar/PotentialRisk.js b/app/containers/ToolPage/Sidebar/PotentialRisk.js new file mode 100644 index 0000000..518360e --- /dev/null +++ b/app/containers/ToolPage/Sidebar/PotentialRisk.js @@ -0,0 +1,120 @@ +import React from 'react'; +import styled, { ThemeProvider } from 'styled-components'; +import Markdown from 'react-markdown'; +import { injectIntl } from 'react-intl'; + +import { RouterLink } from 'utils/markdown'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; + +import {createStructuredSelector} from 'reselect'; +import { connect } from 'react-redux'; +import { CollapsingHeader, ContentContainer, CollapsingContent } from 'components/ToolPage/Main'; +import CollapsingSection from 'components/CollapsingSection'; + +import { PotentialRiskIcon } from 'components/ToolsComponents'; +import PotentialRiskIconImage from 'assets/images/icons/potential-risk.svg'; + +import ContentBlock from 'components/ContentBlock'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import Container from 'components/ToolsPotentialRisk/Container'; +import HeaderName from 'components/ToolsPotentialRisk/HeaderName'; +import Header from 'components/ToolsPotentialRisk/Header'; +import staticText from '../staticText'; +import SidebarContent from 'components/ToolPage/Sidebar/SidebarContent'; + +import makeSelectToolPage from '../selectors'; +import { setChosenSection } from '../actions'; +import { POTENTIAL_RISK, PROP_POTENTIAL_RISK } from '../constants'; + +class PotentialRisk extends React.PureComponent { + + constructor() { + super() + } + + handleClick() { + // Set it to null if the same LEARN_MORE + if (this.props.ToolPage.chosenSection === POTENTIAL_RISK) { + this.props.handleSectionClick(null); + } else { + this.props.handleSectionClick(POTENTIAL_RISK); + } + } + + renderCollapsible() { + return ( + + + + )} + + onClick={this.handleClick.bind(this)} + shouldOpen={ + this.props.ToolPage.expandAll || + this.props.ToolPage.chosenSection === POTENTIAL_RISK + } + > + + + + + + + + + ); + } + renderSidebar() { + const lang = this.props.intl.locale; + return ( + + +
+
+ + + + +
+ + + +
+
+
+ ); + } + + render() { + if( !this.props.showIfUntranslated(PROP_POTENTIAL_RISK) ) { + return null; + } + + if (!this.props.content || this.props.content.trim().length == 0) return null; + + return this.props.collapsible ? this.renderCollapsible() : this.renderSidebar(); + } + +} + +PotentialRisk.propTypes = { + content: React.PropTypes.string, + type: React.PropTypes.string.isRequired +}; + +const mapStateToProps = createStructuredSelector({ + ToolPage: makeSelectToolPage() +}); + +function mapDispatchToProps(dispatch) { + return { + handleSectionClick: (chosenSection) => { + dispatch(setChosenSection(chosenSection)); + } + }; +} + + +export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(PotentialRisk)); diff --git a/app/containers/ToolPage/Sidebar/RelatedTools.js b/app/containers/ToolPage/Sidebar/RelatedTools.js new file mode 100644 index 0000000..b156727 --- /dev/null +++ b/app/containers/ToolPage/Sidebar/RelatedTools.js @@ -0,0 +1,133 @@ +import React from 'react'; +import styled, { ThemeProvider } from 'styled-components'; +import Markdown from 'react-markdown'; +import { injectIntl } from 'react-intl'; +import Isvg from 'react-inlinesvg'; + +import { RouterLink } from 'utils/markdown'; + +import {createStructuredSelector} from 'reselect'; +import { connect } from 'react-redux'; +import { CollapsingHeader, ContentContainer, CollapsingContent } from 'components/ToolPage/Main'; +import CollapsingSection from 'components/CollapsingSection'; + +import MethodologiesFlag from 'assets/images/flag/relatedtools-methodologies.svg'; +import PrinciplesFlag from 'assets/images/flag/relatedtools-principles.svg'; +import StoriesFlag from 'assets/images/flag/relatedtools-stories.svg'; +import TacticsFlag from 'assets/images/flag/relatedtools-tactics.svg'; +import TheoriesFlag from 'assets/images/flag/relatedtools-theories.svg'; + +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import ContentBlock from 'components/ContentBlock'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import { Header, + SidebarContent, + RelatedHeader} from 'components/ToolPage/Sidebar'; + +import RelatedToolsList from './RelatedToolsList'; + +import staticText from '../staticText'; + +import makeSelectToolPage from '../selectors'; +import { setChosenSection } from '../actions'; +import { RELATED_TOOLS } from '../constants'; + +class RelatedTools extends React.PureComponent { + constructor(props) { + super(); + } + + handleClick() { + // Set it to null if the same LEARN_MORE + if (this.props.ToolPage.chosenSection === RELATED_TOOLS) { + this.props.handleSectionClick(null); + } else { + this.props.handleSectionClick(RELATED_TOOLS); + } + } + + renderRelated(FlagImage, typeKey) { + + if (!this.props[typeKey] || this.props[typeKey].length == 0) return null; + return ( + + + + + + + ); + } + + renderCollapsible() { + return ( + + + + )} + + onClick={this.handleClick.bind(this)} + shouldOpen={ + this.props.ToolPage.expandAll || + this.props.ToolPage.chosenSection === RELATED_TOOLS + } + > + + + + {this.renderRelated(TacticsFlag, "tactics")} + {this.renderRelated(PrinciplesFlag, "principles")} + {this.renderRelated(TheoriesFlag, "theories")} + {this.renderRelated(MethodologiesFlag, "methodologies")} + {this.renderRelated(StoriesFlag, "stories")} + + + + + ); + } + + renderSidebar() { + return ( + + +
+ +
+ {this.renderRelated(TacticsFlag, "tactics")} + {this.renderRelated(PrinciplesFlag, "principles")} + {this.renderRelated(TheoriesFlag, "theories")} + {this.renderRelated(MethodologiesFlag, "methodologies")} + {this.renderRelated(StoriesFlag, "stories")} +
+
+ ); + } + + render() { + + return this.props.collapsible ? this.renderCollapsible() : this.renderSidebar(); + + } +} + +RelatedTools.propTypes = { +}; + + +const mapStateToProps = createStructuredSelector({ + ToolPage: makeSelectToolPage() +}); + +function mapDispatchToProps(dispatch) { + return { + handleSectionClick: (chosenSection) => { + dispatch(setChosenSection(chosenSection)); + } + }; +} + + +export default connect(mapStateToProps, mapDispatchToProps)(RelatedTools); diff --git a/app/containers/ToolPage/Sidebar/RelatedToolsList.js b/app/containers/ToolPage/Sidebar/RelatedToolsList.js new file mode 100644 index 0000000..1bd7368 --- /dev/null +++ b/app/containers/ToolPage/Sidebar/RelatedToolsList.js @@ -0,0 +1,49 @@ +/** +* +* ToolsRelatedTool +* +*/ + +import React from 'react'; +import styled from 'styled-components'; +import { Link } from 'react-router'; +import { injectIntl } from 'react-intl'; +import { getToolTypeColor } from 'components/CommonComponents'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import { Container, List, ListItem, ToolLink } from 'components/ToolPage/RelatedTools'; +import Snapshot from 'containers/ToolPage/Snapshot'; + +function RelatedToolsList(props) { + return ( + + + + + { + props.relatedTools.map(item => { + + if (props.dict.getIn([item, 'module-type-effective']) === 'snapshot' ) { + return ( + + {props.dict.getIn([item, 'title'])} + + ) + } + + return ( + + {props.dict.getIn([item, 'title'])} + + ); + }) + } + + + + ); +} + +RelatedToolsList.propTypes = { +}; + +export default injectIntl(RelatedToolsList); diff --git a/app/containers/ToolPage/Sidebar/Tags.js b/app/containers/ToolPage/Sidebar/Tags.js new file mode 100644 index 0000000..5f6b91d --- /dev/null +++ b/app/containers/ToolPage/Sidebar/Tags.js @@ -0,0 +1,109 @@ +import React from 'react'; +import styled, { ThemeProvider } from 'styled-components'; +import Markdown from 'react-markdown'; +import { injectIntl } from 'react-intl'; + +import { RouterLink } from 'utils/markdown'; + +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import ContentBlock from 'components/ContentBlock'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import {Header, SidebarContent} from 'components/ToolPage/Sidebar'; +import TagsContent from 'containers/Tags'; + +import {createStructuredSelector} from 'reselect'; +import { connect } from 'react-redux'; +import { CollapsingHeader, ContentContainer, CollapsingContent } from 'components/ToolPage/Main'; +import CollapsingSection from 'components/CollapsingSection'; + +import staticText from '../staticText'; + +import makeSelectToolPage from '../selectors'; +import { setChosenSection } from '../actions'; +import { TAGS } from '../constants'; + +class Tags extends React.PureComponent { + constructor(props) { + super(); + } + + renderSidebar() { + const lang = this.props.intl.locale; + return ( + + +
+ +
+ item.toLowerCase()) : null} + /> +
+
+ ); + } + + handleClick() { + // Set it to null if the same LEARN_MORE + if (this.props.ToolPage.chosenSection === TAGS) { + this.props.handleSectionClick(null); + } else { + this.props.handleSectionClick(TAGS); + } + } + + renderCollapsible() { + const lang = this.props.intl.locale; + return ( + + + + )} + + onClick={this.handleClick.bind(this)} + shouldOpen={ + this.props.ToolPage.expandAll || + this.props.ToolPage.chosenSection === TAGS + } + > + + + item.toLowerCase()) : null} + /> + + + + ); + } + + render() { + return this.props.collapsible ? this.renderCollapsible() : this.renderSidebar(); + } +} + +Tags.propTypes = { + content: React.PropTypes.string, + type: React.PropTypes.string.isRequired +}; + +const mapStateToProps = createStructuredSelector({ + ToolPage: makeSelectToolPage() +}); + +function mapDispatchToProps(dispatch) { + return { + handleSectionClick: (chosenSection) => { + dispatch(setChosenSection(chosenSection)); + } + }; +} + + +export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(Tags)); diff --git a/app/containers/ToolPage/Sidebar/Training.js b/app/containers/ToolPage/Sidebar/Training.js new file mode 100644 index 0000000..10b766a --- /dev/null +++ b/app/containers/ToolPage/Sidebar/Training.js @@ -0,0 +1,112 @@ +import React from 'react'; +import styled, { ThemeProvider } from 'styled-components'; +import Markdown from 'react-markdown'; +import { injectIntl } from 'react-intl'; + +import { RouterLink } from 'utils/markdown'; + +import {createStructuredSelector} from 'reselect'; +import { connect } from 'react-redux'; +import { CollapsingHeader, ContentContainer, CollapsingContent } from 'components/ToolPage/Main'; +import CollapsingSection from 'components/CollapsingSection'; + +import TranslatableStaticText, { injectStaticText } from 'containers/TranslatableStaticText'; +import ContentBlock from 'components/ContentBlock'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import {Header, SidebarContent} from 'components/ToolPage/Sidebar'; + +import staticText from '../staticText'; + +import makeSelectToolPage from '../selectors'; +import { setChosenSection } from '../actions'; +import { TRAINING } from '../constants'; + +class Training extends React.PureComponent { + constructor(props) { + super(); + } + + handleClick() { + // Set it to null if the same LEARN_MORE + if (this.props.ToolPage.chosenSection === TRAINING) { + this.props.handleSectionClick(null); + } else { + this.props.handleSectionClick(TRAINING); + } + } + + renderCollapsible() { + const lang = this.props.intl.locale; + const {buildMessage} = this.props.translatable; + const formLink = buildMessage(staticText.trainingForm); + const requestMarkdown = buildMessage(staticText.trainingRequest, {form: formLink}); + + return ( + + + + )} + + onClick={this.handleClick.bind(this)} + shouldOpen={ + this.props.ToolPage.expandAll || + this.props.ToolPage.chosenSection === TRAINING + } + > + + + + + + + + + ); + } + + renderSidebar() { + const lang = this.props.intl.locale; + const {buildMessage} = this.props.translatable; + const formLink = buildMessage(staticText.trainingForm); + const requestMarkdown = buildMessage(staticText.trainingRequest, {form: formLink}); + + return ( + + +
+ +
+ + + +
+
+ ); + } + render() { + return this.props.collapsible ? this.renderCollapsible() : this.renderSidebar() + } +} + +const mapStateToProps = createStructuredSelector({ + ToolPage: makeSelectToolPage() +}); + +function mapDispatchToProps(dispatch) { + return { + handleSectionClick: (chosenSection) => { + dispatch(setChosenSection(chosenSection)); + } + }; +} + + +export default connect(mapStateToProps, mapDispatchToProps)(injectStaticText(injectIntl(Training))); diff --git a/app/containers/ToolPage/Sidebar/WhyItFailed.js b/app/containers/ToolPage/Sidebar/WhyItFailed.js new file mode 100644 index 0000000..36a43ce --- /dev/null +++ b/app/containers/ToolPage/Sidebar/WhyItFailed.js @@ -0,0 +1,119 @@ +import React from 'react'; +import styled, { ThemeProvider } from 'styled-components'; +import Markdown from 'react-markdown'; +import { injectIntl } from 'react-intl'; +import Isvg from 'react-inlinesvg'; + +import { RouterLink } from 'utils/markdown'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; + +import {createStructuredSelector} from 'reselect'; +import { connect } from 'react-redux'; +import { CollapsingHeader, ContentContainer, CollapsingContent } from 'components/ToolPage/Main'; +import CollapsingSection from 'components/CollapsingSection'; + + +import { PotentialRiskIcon } from 'components/ToolsComponents'; +import WhyItFailedIcon from 'assets/images/icons/stories-whyitfailed.svg'; + +import ContentBlock from 'components/ContentBlock'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import { BigHeader, + SidebarContent, + RelatedHeader, + WhyItIcon} from 'components/ToolPage/Sidebar'; + +import staticText from '../staticText'; + +import makeSelectToolPage from '../selectors'; +import { setChosenSection } from '../actions'; +import { WHY_IT_FAILED, PROP_WHY_IT_FAILED } from '../constants'; + + +class WhyItFailed extends React.PureComponent { + + constructor() { + super(); + } + + handleClick() { + // Set it to null if the same LEARN_MORE + if (this.props.ToolPage.chosenSection === WHY_IT_FAILED) { + this.props.handleSectionClick(null); + } else { + this.props.handleSectionClick(WHY_IT_FAILED); + } + } + renderCollapsible() { + return ( + + + + )} + + onClick={this.handleClick.bind(this)} + shouldOpen={ + this.props.ToolPage.expandAll || + this.props.ToolPage.chosenSection === WHY_IT_FAILED + } + > + + + + + + + + + ); + } + + renderSidebar() { + return ( + + + + + + + + + + + + + + ); + } + + render() { + if( !this.props.showIfUntranslated(PROP_WHY_IT_FAILED) ) { + return null; + } + + if (!this.props.text || this.props.text.trim().length == 0) return null; + return this.props.collapsible ? this.renderCollapsible() : this.renderSidebar(); + } +} + +WhyItFailed.propTypes = { + content: React.PropTypes.string, + type: React.PropTypes.string.isRequired +}; + +const mapStateToProps = createStructuredSelector({ + ToolPage: makeSelectToolPage() +}); + +function mapDispatchToProps(dispatch) { + return { + handleSectionClick: (chosenSection) => { + dispatch(setChosenSection(chosenSection)); + } + }; +} + + +export default connect(mapStateToProps, mapDispatchToProps)(WhyItFailed); diff --git a/app/containers/ToolPage/Sidebar/WhyItWorked.js b/app/containers/ToolPage/Sidebar/WhyItWorked.js new file mode 100644 index 0000000..e1094ca --- /dev/null +++ b/app/containers/ToolPage/Sidebar/WhyItWorked.js @@ -0,0 +1,120 @@ +import React from 'react'; +import styled, { ThemeProvider } from 'styled-components'; +import Markdown from 'react-markdown'; +import { injectIntl } from 'react-intl'; +import Isvg from 'react-inlinesvg'; +import { RouterLink } from 'utils/markdown'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; + +import {createStructuredSelector} from 'reselect'; +import { connect } from 'react-redux'; +import { CollapsingHeader, ContentContainer, CollapsingContent } from 'components/ToolPage/Main'; +import CollapsingSection from 'components/CollapsingSection'; + +import { PotentialRiskIcon } from 'components/ToolsComponents'; +import WhyItWorkedIcon from 'assets/images/icons/stories-whyitworked.svg'; + +import ContentBlock from 'components/ContentBlock'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; + +import { BigHeader, + SidebarContent, + RelatedHeader, + WhyItIcon} from 'components/ToolPage/Sidebar'; + + +import staticText from '../staticText'; + +import makeSelectToolPage from '../selectors'; +import { setChosenSection } from '../actions'; +import { WHY_IT_WORKED, PROP_WHY_IT_WORKED } from '../constants'; + +class WhyItWorked extends React.PureComponent { + + constructor() { + super(); + } + + handleClick() { + // Set it to null if the same LEARN_MORE + if (this.props.ToolPage.chosenSection === WHY_IT_WORKED) { + this.props.handleSectionClick(null); + } else { + this.props.handleSectionClick(WHY_IT_WORKED); + } + } + + renderSidebar() { + return ( + + + + + + + + + + + + + + ); + } + + renderCollapsible() { + return ( + + + + )} + + onClick={this.handleClick.bind(this)} + shouldOpen={ + this.props.ToolPage.expandAll || + this.props.ToolPage.chosenSection === WHY_IT_WORKED + } + > + + + + + + + + + ); + } + + render() { + if( !this.props.showIfUntranslated(PROP_WHY_IT_WORKED) ) { + return null; + } + + if (!this.props.text || this.props.text.trim().length == 0) return null; + return this.props.collapsible ? this.renderCollapsible() : this.renderSidebar() + } + +} + +WhyItWorked.propTypes = { + content: React.PropTypes.string, + type: React.PropTypes.string.isRequired +}; + +const mapStateToProps = createStructuredSelector({ + ToolPage: makeSelectToolPage() +}); + +function mapDispatchToProps(dispatch) { + return { + handleSectionClick: (chosenSection) => { + dispatch(setChosenSection(chosenSection)); + } + }; +} + + +export default connect(mapStateToProps, mapDispatchToProps)(WhyItWorked); diff --git a/app/containers/ToolPage/Sidebar/index.js b/app/containers/ToolPage/Sidebar/index.js new file mode 100644 index 0000000..b599dc6 --- /dev/null +++ b/app/containers/ToolPage/Sidebar/index.js @@ -0,0 +1,51 @@ +import React, { PropTypes } from 'react'; +import Markdown from 'react-markdown'; +import { Link } from 'react-router'; +import { connect } from 'react-redux'; +import { createStructuredSelector } from 'reselect'; +import { RouterLink } from 'utils/markdown'; +import { makeSelectAllToolsWithSlugIndex } from 'containers/App/selectors'; + +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import staticText from '../staticText'; + +import { ContentContainer } from 'components/ToolPage/Main'; + +import PotentialRisk from './PotentialRisk'; +import RelatedTools from './RelatedTools'; +import Tags from './Tags'; +import Training from './Training'; +import WhyItWorked from './WhyItWorked'; +import WhyItFailed from './WhyItFailed'; + +class Sidebar extends React.PureComponent { + constructor(props) { + super(); + } + + render() { + return ( + + + + + + + + + ); + } +} + +const mapStateToProps = createStructuredSelector({ + toolsList: makeSelectAllToolsWithSlugIndex() +}); + +function mapDispatchToProps(dispatch) { + return { + dispatch + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(Sidebar); diff --git a/app/containers/ToolPage/Snapshot/SnapshotContent.js b/app/containers/ToolPage/Snapshot/SnapshotContent.js new file mode 100644 index 0000000..b789d5c --- /dev/null +++ b/app/containers/ToolPage/Snapshot/SnapshotContent.js @@ -0,0 +1,84 @@ +import React, { PropTypes } from 'react'; +import { Link } from 'react-router'; +import { connect } from 'react-redux'; +import { injectIntl } from 'react-intl'; +import { createStructuredSelector } from 'reselect'; +import Markdown from 'react-markdown'; +import Isvg from 'react-inlinesvg'; +import styled, {ThemeProvider} from 'styled-components'; +import { RouterLink } from 'utils/markdown'; + +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import ContentBlock from 'components/ContentBlock'; + +import { + Caption, Container, + Content, ContentViewport, + ToolType +} from 'components/ToolPage/Header'; + +import { SnapshotText, Viewport, OverlayText, Title } from 'components/ToolPage/Snapshot'; + +import { BR_IMAGE_PREFIX } from 'containers/Tools/constants'; +import TypeOverlay from 'components/TypeOverlay'; + +import TranslatableStaticText, { injectStaticText } from 'containers/TranslatableStaticText'; +import staticText from '../staticText'; + +export class SnapshotContent extends React.PureComponent { + constructor() { + super(); + } + + isType(type, key) { + return this.props.type === type || + (this.props[key] && this.props[key].length > 0); + } + + render() { + + const { buildMessage } = this.props.translatable; + const callToAction = buildMessage(staticText.expandingToolbox, { link: this.props['bt-link'] }); + + return ( + + + + + + + + + + + + {this.props.title} + + + {this.props.snapshot} + + + + + + + + + + + ); + } +} + +SnapshotContent.propTypes = { + dispatch: PropTypes.func.isRequired, +}; + + +function mapDispatchToProps(dispatch) { + return { + dispatch + } +} + +export default connect(null, mapDispatchToProps)(injectStaticText(injectIntl(SnapshotContent))); diff --git a/app/containers/ToolPage/Snapshot/index.js b/app/containers/ToolPage/Snapshot/index.js new file mode 100644 index 0000000..9e222af --- /dev/null +++ b/app/containers/ToolPage/Snapshot/index.js @@ -0,0 +1,115 @@ +import React from 'react'; +import Modal from 'react-modal'; +import { injectIntl } from 'react-intl'; +import Isvg from 'react-inlinesvg'; + +import CloseIcon from 'assets/images/icons/close.svg'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import { Container as SnapshotContainer, Button } from 'components/ToolPage/Snapshot'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import SnapshotContent from './SnapshotContent'; +import staticText from '../staticText'; + +import styled from 'styled-components'; + +const customStyles = { + overlay: { + backgroundColor: 'rgba(149, 149, 149, 0.75)', + zIndex: 600 + }, + content : { + position: 'absolute', + left: '50%', + top: '50%', + transform: 'translate(-50%, -50%)', + borderRadius: '0', + width: '1035px', + height: '533px', + bottom: 'auto', + border: '2px solid', + background: 'rgb(255, 255, 255)', + overflow: 'visible', + outline: 'none', + padding: '0px', + textAlign: 'center' + } +}; + +const CloseBox = styled.div` + ${p=>p.theme.isArabic?'right':'left'}: -32px; + + position: absolute; + background-color: white; + z-index: 700; + top: -22px; + display: inline-block; +`; +const CloseButton = styled.button` + outline: none; + padding: 0; +`; + + +export class Snapshot extends React.Component { + constructor() { + super(); + + this.state = { + modalIsOpen: false + }; + + this.openModal = this.openModal.bind(this); + this.afterOpenModal = this.afterOpenModal.bind(this); + this.closeModal = this.closeModal.bind(this); + } + + + openModal() { + this.setState({modalIsOpen: true}); + } + + afterOpenModal() { + // references are now sync'd and can be accessed. + } + + closeModal() { + this.setState({modalIsOpen: false}); + } + + render() { + const lang = this.props.intl.locale; + + return ( +
+ + + + + + + + + + + + + +
+ ); + } + +} + +Snapshot.propTypes = { + +}; + +export default injectIntl(Snapshot); diff --git a/app/containers/ToolPage/ToolLearnMore.js b/app/containers/ToolPage/ToolLearnMore.js index c363cfd..634134f 100644 --- a/app/containers/ToolPage/ToolLearnMore.js +++ b/app/containers/ToolPage/ToolLearnMore.js @@ -10,7 +10,7 @@ import { createStructuredSelector } from 'reselect'; import LatinThemeProvider from 'components/LatinThemeProvider'; import AdderRemover from 'containers/Tools/AdderRemover'; import { LearnMoreList, ToolMainContent, ToolLearnMoreContent, ToolMainContentHeader } from 'components/ToolsPageComponents'; -import ToolLearnMoreItem from './ToolLearnMoreItem'; +import ToolLearnMoreItem from 'containers/ToolPage/ToolLearnMoreItem'; import TranslatableStaticText from 'containers/TranslatableStaticText'; import staticText from './staticText'; diff --git a/app/containers/ToolPage/ToolPageHeader.js b/app/containers/ToolPage/ToolPageHeader.js index 2c45ab3..08c12be 100644 --- a/app/containers/ToolPage/ToolPageHeader.js +++ b/app/containers/ToolPage/ToolPageHeader.js @@ -12,6 +12,7 @@ import { createStructuredSelector } from 'reselect'; import Markdown from 'react-markdown'; import Isvg from 'react-inlinesvg'; import styled, {ThemeProvider} from 'styled-components'; +import ShareButton from 'containers/ShareButton'; import LanguageThemeProvider from 'components/LanguageThemeProvider'; import ContentBlock from 'components/ContentBlock'; @@ -25,7 +26,6 @@ import { ToolHeaderContainer, import { BR_IMAGE_PREFIX } from 'containers/Tools/constants'; import { RouterLink } from 'utils/markdown'; import ShareIcon from 'assets/images/icons/share-small.svg'; -import ShareButton from 'containers/ShareButton'; import TypeFlag from 'components/TypeFlag'; import TypeOverlay from 'components/TypeOverlay'; // import { makeSelectToolById } from 'containers/Tool/selectors'; @@ -101,10 +101,7 @@ export class ToolPageHeader extends React.PureComponent { // eslint-disable-line {this.props.title} )} removeText={()} /> diff --git a/app/containers/ToolPage/ToolPageMain.js b/app/containers/ToolPage/ToolPageMain.js index 19e1b29..ca1b941 100644 --- a/app/containers/ToolPage/ToolPageMain.js +++ b/app/containers/ToolPage/ToolPageMain.js @@ -105,7 +105,8 @@ export class ToolPageMain extends React.PureComponent { // eslint-disable-line r checkContentLength() { - if( this.props.showIfUntranslated(PROP_FULL_WRITE_UP) && this.props['full-write-up'] ) { + if( this.props.showIfUntranslated(PROP_FULL_WRITE_UP) + && this.props['full-write-up'] ) { return ( {this.generateContent()} diff --git a/app/containers/ToolPage/actions.js b/app/containers/ToolPage/actions.js index 58799ef..320e5b5 100644 --- a/app/containers/ToolPage/actions.js +++ b/app/containers/ToolPage/actions.js @@ -6,6 +6,9 @@ import { DEFAULT_ACTION, + RESET_TOOL_STATE, + SET_CHOSEN_SECTION, + SET_EXPAND_ALL } from './constants'; export function defaultAction() { @@ -13,3 +16,23 @@ export function defaultAction() { type: DEFAULT_ACTION, }; } + +export function setExpandAll(isExpandAll) { + return { + type: SET_EXPAND_ALL, + isExpandAll + } +} + +export function setChosenSection(chosenSection) { + return { + type: SET_CHOSEN_SECTION, + chosenSection + } +} + +export function resetToolState() { + return { + type: RESET_TOOL_STATE + } +} diff --git a/app/containers/ToolPage/constants.js b/app/containers/ToolPage/constants.js index 325cc16..60a0ac4 100644 --- a/app/containers/ToolPage/constants.js +++ b/app/containers/ToolPage/constants.js @@ -5,7 +5,24 @@ */ export const DEFAULT_ACTION = 'app/ToolPage/DEFAULT_ACTION'; +export const RESET_TOOL_STATE = 'app/ToolPage/RESET_TOOL_STATE'; +export const SET_CHOSEN_SECTION = 'app/ToolPage/SET_CHOSEN_SECTION'; +export const SET_EXPAND_ALL = 'app/ToolPage/SET_EXPAND_ALL'; +export const REAL_WORLD_EXAMPLE = 'app/ToolPage/Section/REAL_WORLD_EXAMPLE'; +export const CONTRIBUTED_BY = 'app/ToolPage/Section/CONTRIBUTED_BY'; +export const LEARN_MORE = 'app/ToolPage/Section/LEARN_MORE'; +export const WHY_IT_WORKED = 'app/ToolPage/Section/WHY_IT_WORKED'; +export const WHY_IT_FAILED = 'app/ToolPage/Section/WHY_IT_FAILED'; +export const POTENTIAL_RISK = 'app/ToolPage/Section/POTENTIAL_RISK'; +export const TAGS = 'app/ToolPage/Section/TAGS'; +export const TRAINING = 'app/ToolPage/Section/TRAINING'; +export const RELATED_TOOLS = 'app/ToolPage/Section/RELATED_TOOLS'; + + export const TYPE_PERSON = 'person'; export const PROP_FULL_WRITE_UP = 'full-write-up'; export const PROP_SHORT_WRITE_UP = 'short-write-up'; +export const PROP_WHY_IT_WORKED = 'why-it-worked'; +export const PROP_WHY_IT_FAILED = 'why-it-failed'; +export const PROP_POTENTIAL_RISK = 'potential-risk'; diff --git a/app/containers/ToolPage/index.js b/app/containers/ToolPage/index.js index 01bedc5..cec6d45 100644 --- a/app/containers/ToolPage/index.js +++ b/app/containers/ToolPage/index.js @@ -13,16 +13,24 @@ import { createStructuredSelector } from 'reselect'; import AdderRemover from 'containers/Tools/AdderRemover'; import { ToolInformation, ToolHeader } from 'components/ToolsPageComponents'; // import { makeSelectToolById } from 'containers/Tool/selectors'; +import HeaderContainer from 'components/ToolPage/Header'; +import StageContainer from 'components/ToolPage/Stage'; +import MainArea from 'components/ToolPage/Main'; +import SidebarContainer from 'components/ToolPage/Sidebar'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; import { loadData } from '../App/actions'; import { ThemeProvider } from 'styled-components'; import makeSelectToolPage, { makeSelectTool } from './selectors'; import messages from './messages'; -import ToolPageHeader from './ToolPageHeader'; +import Header from './Header'; import ToolPageLeft from './ToolPageLeft'; import ToolPageMain from './ToolPageMain'; import ToolPageRight from './ToolPageRight'; +import MainStage from './MainStage'; +import Sidebar from './Sidebar'; + import {BR_IMAGE_PREFIX} from 'containers/Tools/constants'; import { MODULE_TYPE_UNTRANSLATED } from 'components/CommonComponents/constants'; @@ -60,7 +68,7 @@ export class ToolPage extends React.PureComponent { // eslint-disable-line react if (!tool.document_id) return null; return ( - +
- - +
- - - - + + + - + + + - + /> + +
-
+ ); } } - +// +// +// +// //

{tool.type}

//

{tool['short-write-up']}

//

{this.props.toolData.getIn(['authors']).map(item => item.title)}

diff --git a/app/containers/ToolPage/reducer.js b/app/containers/ToolPage/reducer.js index 74797a2..ba323ea 100644 --- a/app/containers/ToolPage/reducer.js +++ b/app/containers/ToolPage/reducer.js @@ -7,14 +7,29 @@ import { fromJS } from 'immutable'; import { DEFAULT_ACTION, + REAL_WORLD_EXAMPLE, + CONTRIBUTED_BY, + LEARN_MORE, + SET_CHOSEN_SECTION, + RESET_TOOL_STATE, + SET_EXPAND_ALL } from './constants'; -const initialState = fromJS({}); +const initialState = fromJS({ + expandAll: false, + chosenSection: REAL_WORLD_EXAMPLE, +}); function toolPageReducer(state = initialState, action) { switch (action.type) { case DEFAULT_ACTION: return state; + case RESET_TOOL_STATE: + return initialState; + case SET_CHOSEN_SECTION: + return state.set('chosenSection', action.chosenSection); + case SET_EXPAND_ALL: + return state.set('expandAll', action.isExpandAll); default: return state; } diff --git a/app/containers/ToolPage/sagas.js b/app/containers/ToolPage/sagas.js index 8e6bf46..1fb95bb 100644 --- a/app/containers/ToolPage/sagas.js +++ b/app/containers/ToolPage/sagas.js @@ -4,7 +4,7 @@ import { take, call, put, select, cancel, takeLatest } from 'redux-saga/effects' import { LOAD_DATA } from 'containers/App/constants'; import { CHANGE_LOCALE } from 'containers/LanguageProvider/constants'; import { dataLoaded, dataLoadingError } from 'containers/App/actions'; - +import { resetToolState } from 'containers/ToolPage/actions'; import request, { getEndpoint } from 'utils/request'; export const getLanguage = (state) => state.get('language'); @@ -23,24 +23,20 @@ export function* getToolsData(lang) { } } -// Individual exports for testing -export function* toolsData() { +export function* resetState() { + yield put(resetToolState()); +} - // Watches for LOAD_REPOS actions and calls getRepos when one comes in. - // By using `takeLatest` only the result of the latest API call is applied. - // It returns task descriptor (just like fork) so we can continue execution - let language = yield select(getLanguage); - const chosenLanguage = language !== undefined ? language.get('locale') : 'en'; +// Individual exports for testing +export function* checkLocaleChange() { - const watcher = yield takeLatest(LOAD_DATA, getToolsData, chosenLanguage); + yield put(resetToolState()); + yield take(LOCATION_CHANGE); - // Suspend execution until location changes - yield take(CHANGE_LOCALE, LOCATION_CHANGE); - yield cancel(watcher); } // All sagas to be loaded export default [ - toolsData, + checkLocaleChange, ]; diff --git a/app/containers/ToolPage/staticText.js b/app/containers/ToolPage/staticText.js index d516ec3..5765f4a 100644 --- a/app/containers/ToolPage/staticText.js +++ b/app/containers/ToolPage/staticText.js @@ -15,17 +15,29 @@ export default { id: 'module.read-more', defaultMessage: 'Read More', }, + more: { + id: 'module.more', + defaultMessage: 'More', + }, + less: { + id: 'module.less', + defaultMessage: 'Less', + }, learnMore: { id: 'module.learn-more', defaultMessage: 'Learn More', }, + realWorldHeader: { + id: 'module.real-world-header', + defaultMessage: 'Real-world Examples' + }, realWorldExamplesOf: { id: 'module.real-world', defaultMessage: 'Real world examples of “{{title}}”', }, contributedByHeader: { - id: 'module.contributed-by', - defaultMessage: 'Contributed By' + id: 'module.about-contributor', + defaultMessage: 'About the contributer' }, share: { @@ -94,5 +106,38 @@ export default { needsTranslationForm: { id: 'module.needs-translation-form', defaultMessage: 'https://docs.google.com/forms/d/e/1FAIpQLSdNIM8BZK8PBPRaMwcHe8vQPaq82xtsPkloav5qNAzDeEwHHA/viewform' + }, + byLine: { + id: 'module.by-line', + defaultMessage: 'By {{byline}}' + }, + potentialRiskHeader: { + id: 'module.potential-risks', + defaultMessage: 'Potential Risks', + }, + trainingRequest: { + id: 'module.training-request', + defaultMessage: 'You can also [request]({{form}}) a Beautiful Rising training' + }, + trainingForm: { + id: 'forms.training', + defaultMessage: 'https://docs.google.com/forms/d/e/1FAIpQLSfbN0Qb5P2ORCHYl4UPEdA-01I-ixPP9TRjEFv5c05HGguwrA/viewform' + }, + whyItFailedHeader: { + id: 'module.why-it-failed', + defaultMessage: 'Why it Failed', + }, + whyItWorkedHeader: { + id: 'module.why-it-worked', + defaultMessage: 'Why it Worked', + }, + expandingToolbox: { + id: 'module.expanding-toolbox', + defaultMessage: 'This is an ever-expanding toolbox. You’re welcome to [read more]({{link}}) this tool. ' + }, + + origins: { + id: 'module.origins', + defaultMessage: 'Origins' } } diff --git a/app/containers/ToolTypeAll/index.js b/app/containers/ToolTypeAll/index.js new file mode 100644 index 0000000..e9cac6b --- /dev/null +++ b/app/containers/ToolTypeAll/index.js @@ -0,0 +1,151 @@ +/** +* +* ToolTypeAllPartial +* +*/ + +import React from 'react'; +import styled from 'styled-components'; +import {Link} from 'react-router'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; + +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import staticText from '../ToolTypeArea/staticText'; +import ContentBlock from 'components/ContentBlock'; + +import Isvg from 'react-inlinesvg'; +import MethodologyIcon from 'assets/images/type/methodologies-option.svg'; +import PrincipleIcon from 'assets/images/type/principles-option.svg'; +import StoryIcon from 'assets/images/type/stories-option.svg'; +import TacticIcon from 'assets/images/type/tactics-option.svg'; +import TheoryIcon from 'assets/images/type/theories-option.svg'; + +const Container = styled.section` + display: ${props=>props.show ? 'block' : 'none'}; +`; +const Viewport = styled.div``; +const Row = styled.div` + text-align: center; +`; +const ToolType = styled(Link)` + width: 19%; + margin-${p=>p.theme.isArabic?'left':'right'}: 0.5%; + display: block; + height: auto + text-align: ${p=>p.theme.isArabic?'right':'left'}; + vertical-align: top; + text-transform: uppercase; + color: black; + text-decoration: none; + + * { + vertical-align: top; + } + + opacity: ${p=>p.selected?1:0.5}; + + svg { + width: 166px; + } + margin-bottom: 20px; + + @media(max-width: 1170px) { + text-align: center; + width: 100%; + .isvg { + display: none; + } + } +`; +const BigHead = styled.h2`margin:0`; +const Head = styled.h3` + margin: 0; + font-size: ${p=>p.selected?'40px':'30px'}; + white-space: nowrap; +`; +const Desc = styled.p` + margin: 0; + + ::after { + content: ' '; + clear: both; + display: block; + } +` + +const ToolDesc = styled(ContentBlock)` + display: ${p=>p.show?'block':'none'}; + width: 200px; + text-transform: none; + margin-top: 36px; + padding-${p=>p.theme.isArabic?'left':'right'}: 30px; + margin-bottom: 70px; + + @media(max-width: 1170px) { + display: none; + } +`; + +function ToolTypeAll(props) { + + const {label, filter} = props.params; + const isSelected = (type)=> label === type && filter === 'type'; + + return ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +} + +ToolTypeAll.propTypes = { + +}; + +export default ToolTypeAll; diff --git a/app/containers/ToolTypeAll/messages.js b/app/containers/ToolTypeAll/messages.js new file mode 100644 index 0000000..4542428 --- /dev/null +++ b/app/containers/ToolTypeAll/messages.js @@ -0,0 +1,13 @@ +/* + * ToolTypeAllPartial Messages + * + * This contains all the text for the ToolTypeAllPartial component. + */ +import { defineMessages } from 'react-intl'; + +export default defineMessages({ + header: { + id: 'app.components.ToolTypeAllPartial.header', + defaultMessage: 'This is the ToolTypeAllPartial component !', + }, +}); diff --git a/app/containers/ToolTypeAll/tests/index.test.js b/app/containers/ToolTypeAll/tests/index.test.js new file mode 100644 index 0000000..357066b --- /dev/null +++ b/app/containers/ToolTypeAll/tests/index.test.js @@ -0,0 +1,10 @@ +// import React from 'react'; +// import { shallow } from 'enzyme'; + +// import ToolTypeAllPartial from '../index'; + +describe('', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(false); + }); +}); diff --git a/app/containers/ToolTypeAllFull/index.js b/app/containers/ToolTypeAllFull/index.js index d85c8af..7a409f4 100644 --- a/app/containers/ToolTypeAllFull/index.js +++ b/app/containers/ToolTypeAllFull/index.js @@ -48,52 +48,115 @@ function ToolTypeAllFull(props) { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + +
); } +/** + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +*/ + ToolTypeAllFull.propTypes = { }; diff --git a/app/containers/ToolTypeArea/index.js b/app/containers/ToolTypeArea/index.js index 4a3b24e..64f23b9 100644 --- a/app/containers/ToolTypeArea/index.js +++ b/app/containers/ToolTypeArea/index.js @@ -9,6 +9,7 @@ import styled from 'styled-components'; import Isvg from 'react-inlinesvg'; +import ToolTypeAll from 'containers/ToolTypeAll'; import ToolTypeAllFull from 'containers/ToolTypeAllFull'; import ToolTypeAllPartial from 'containers/ToolTypeAllPartial'; import ToolTypeSelectedFull from 'containers/ToolTypeSelectedFull'; @@ -29,9 +30,7 @@ import messages from './messages'; */ const AllContainer = styled.div` - border: solid black; - border-width: 0 2px 2px; - padding: 20px 60px; + // margin-top: 65px; text-align: ${props=>props.lang === 'ar' ? 'right' : 'left'}; `; @@ -50,52 +49,59 @@ class ToolTypeArea extends React.Component { // eslint-disable-line react/prefer constructor(props) { super(props); - this.windowEvent = this.handleScroll.bind(this); + // this.windowEvent = this.handleScroll.bind(this); this.state = { scrollY: 0 } } componentWillMount() { - const func = this.handleScroll.bind(this); - window.addEventListener('scroll', this.windowEvent, false); + // const func = this.handleScroll.bind(this); + // window.addEventListener('scroll', this.windowEvent, false); } componentWillUnmount() { - const func = this.handleScroll.bind(this); - window.removeEventListener('scroll', this.windowEvent, false); + // const func = this.handleScroll.bind(this); + // window.removeEventListener('scroll', this.windowEvent, false); // window.addEventListener('scroll', this.handleScroll.bind(this), true); } handleScroll() { - this.setState({ scrollY: window.scrollY }); + // this.setState({ scrollY: window.scrollY }); } render() { const onTop = this.state.scrollY < 10; - if (this.props.filter !== 'type' || !this.props.label || this.props.label === undefined) { - //All - return ( - - - - - - - - ); - } else { - //Selected - return ( -
- - - - - -
- ); - } + + return ( + + + + ); + + // if (this.props.filter !== 'type' || !this.props.label || this.props.label === undefined) { + // //All + // return ( + // + // + // + // + // + // + // + // ); + // } else { + // //Selected + // return ( + //
+ // + // + // + // + // + //
+ // ); + // } } } diff --git a/app/containers/Tools/AdderRemover.js b/app/containers/Tools/AdderRemover.js index ef37423..0e383be 100644 --- a/app/containers/Tools/AdderRemover.js +++ b/app/containers/Tools/AdderRemover.js @@ -22,6 +22,7 @@ import { Link } from 'react-router'; import { ToolsButton, ToolsListMenu, ToolsListMenuItem, ToolsList, ToolsListItem } from 'components/ToolsComponents'; +import { getToolTypeColor } from 'components/CommonComponents'; import { removeTool, addTool } from './actions'; const CallToAction = styled.span` @@ -30,10 +31,22 @@ const CallToAction = styled.span` font-weight: 800; font-size: ${p=>p.ar?'16px':'14px'}; line-height: 22px; - padding-top: 12px; display: inline-block; `; +const CallToRemoveAction = styled(CallToAction) ` + svg circle { + ${p=>p.type ? `stroke: ${getToolTypeColor(p.type)};` : ''} + fill: transparent; + } + + svg path { + fill: ${p=>p.type ? `${getToolTypeColor(p.type)}` : 'transparent'}; + } + margin-left: -10px; + margin-top: -10px; +` + export class AdderRemover extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function onButtonClick(evt) { @@ -48,9 +61,9 @@ export class AdderRemover extends React.PureComponent { // eslint-disable-line r buildRemove() { return ( - - { this.props.removeText || ""} - + + { this.props.removeText || ""} + ) } diff --git a/app/containers/Tools/SelectedTool.js b/app/containers/Tools/SelectedTool.js index f2ef9e9..ed2c0cd 100644 --- a/app/containers/Tools/SelectedTool.js +++ b/app/containers/Tools/SelectedTool.js @@ -40,6 +40,14 @@ import AdderRemover from './AdderRemover'; import makeSelectTools from './selectors'; import staticText from './staticText'; +const RemoveIconContainer = styled.span` + svg circle { + fill: transparent; + } + svg path { + fill: #B3B3B3; + } +`; export class SelectedTool extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function getFlag() { @@ -53,14 +61,14 @@ export class SelectedTool extends React.PureComponent { // eslint-disable-line r } render() { - const flag = this.getFlag(); + const Flag = this.getFlag(); const tool = this.props.allData.get(this.props.slug); const lang = this.props.intl.locale; if (!tool) return null; return ( - + {tool.get('title')} @@ -71,7 +79,9 @@ export class SelectedTool extends React.PureComponent { // eslint-disable-line r - + + + diff --git a/app/containers/Tools/ToolsArea.js b/app/containers/Tools/ToolsArea.js index 0e7e776..a611558 100644 --- a/app/containers/Tools/ToolsArea.js +++ b/app/containers/Tools/ToolsArea.js @@ -44,13 +44,23 @@ import staticText from './staticText'; export const ToolsListContainer = styled.div` width: calc(100% - 73px); float: ${props=>props.lang === 'ar' ? 'right' : 'left'}; - direction: float: ${props=>props.lang === 'ar' ? 'rtl' : 'ltr'}; + direction: ${props=>props.lang === 'ar' ? 'rtl' : 'ltr'}; height: 100%; display: ${props=>props.show ? 'block' : 'none'}; + ${props=>props.lang === 'ar' ? 'border-right' : 'border-left'}: 2px solid; & > div > * { direction: ${props=>props.lang === 'ar' ? 'rtl' : 'ltr'}; text-align: ${props=>props.lang === 'ar' ? 'right' : 'left'}; } + + @media(max-width: 1170px) { + display: block; + width: 100%; + float: none; + + border: 2px solid; + border-width: 2px 2px 0; + } `; const Container = styled.div` diff --git a/app/containers/Tools/actions.js b/app/containers/Tools/actions.js index 6ac1154..72c52fb 100644 --- a/app/containers/Tools/actions.js +++ b/app/containers/Tools/actions.js @@ -11,7 +11,8 @@ import { DEFAULT_ACTION, SET_VIEW_TYPE, NEW_USER_TOOL_ONBOARDING, - TOOL_ONBOARDING_FINISHED + TOOL_ONBOARDING_FINISHED, + SET_MOBILE_SHOW_TOOLS } from './constants'; export function setShowTools(showTools) { @@ -21,6 +22,13 @@ export function setShowTools(showTools) { } } +export function setMobileShowTools(mobileShowTools) { + return { + type: SET_MOBILE_SHOW_TOOLS, + data: mobileShowTools + } +} + export function setViewType(viewType) { return { type: SET_VIEW_TYPE, diff --git a/app/containers/Tools/constants.js b/app/containers/Tools/constants.js index 780cf74..cf11ccf 100644 --- a/app/containers/Tools/constants.js +++ b/app/containers/Tools/constants.js @@ -6,6 +6,7 @@ export const DEFAULT_ACTION = 'app/Tools/DEFAULT_ACTION'; export const SET_SHOW_TOOLS = 'app/Tools/SET_SHOW_TOOLS'; +export const SET_MOBILE_SHOW_TOOLS = 'app/Tools/SET_MOBILE_SHOW_TOOLS'; export const ADD_TOOL = 'app/Tools/ADD_TOOL'; export const REMOVE_TOOL = 'app/Tools/REMOVE_TOOL'; export const BR_IMAGE_PREFIX = 'https://beautifulrising.org/assets/content/medium-'; diff --git a/app/containers/Tools/index.js b/app/containers/Tools/index.js index 1744d4b..56f4329 100644 --- a/app/containers/Tools/index.js +++ b/app/containers/Tools/index.js @@ -9,6 +9,7 @@ import { connect } from 'react-redux'; import { injectIntl } from 'react-intl'; import { createStructuredSelector } from 'reselect'; import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import Modal from 'react-modal'; import styled from 'styled-components'; import Isvg from 'react-inlinesvg'; @@ -32,7 +33,7 @@ import { ThemeProvider } from 'styled-components'; import ToolsArea from './ToolsArea'; import makeSelectTools, {makeSelectLanguage} from './selectors'; import messages from './messages'; -import { setShowTools, setViewType } from './actions'; +import { setShowTools, setViewType, setMobileShowTools } from './actions'; import TranslatableStaticText from 'containers/TranslatableStaticText'; import staticText from './staticText'; @@ -40,7 +41,7 @@ import staticText from './staticText'; const ToolsOpenerCloser = styled.div``; const ToolsMenuContainer = styled.div` -height: 100%; + height: 100%; `; const ToolsViewType = styled(ToolsButton)` @@ -52,6 +53,21 @@ const ToolsViewType = styled(ToolsButton)` } `; +const DesktopContent = styled.div` + display: block; + height: 100%; + @media(max-width: 1170px) { + display: none; + } +`; + +const MobileContent = styled.div` + display: none; + @media(max-width: 1170px) { + display: block; + } +`; + const MyToolsButton = styled(ToolsViewType)` ${props=> { @@ -68,17 +84,60 @@ const MyToolsButton = styled(ToolsViewType)` // return `animation-play-state: paused;`; } }} +`; +const ToolTitle = styled.span` + color: black; `; + +//For modalIsOpen +const customStyles = { + overlay: { + backgroundColor: 'rgba(149, 149, 149, 0.75)', + zIndex: 590 + }, + content : { + position: 'absolute', + right: 'auto', + left: 'auto', + top: '0px', + bottom: 'auto', + border: '0px none', + background: 'rgb(255, 255, 255)', + overflow: 'visible', + outline: 'none', + padding: '0px', + width: '100%', + textAlign: 'center', + height: 'calc(100% - 70px) !important', + zIndex: '1000' + } +}; export class Tools extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function constructor(props) { super(props); this.state = { chosen: NEWS_FEED, //myTools - isFirstTime: false + isFirstTime: false, + modalIsOpen: false } + + this.closeModal = this.closeModal.bind(this); } + + closeModal() { + this.setState({modalIsOpen: false}); + } + + openModal() { + this.setState({modalIsOpen: true}); + } + + afterOpenModal() { + // references are now sync'd and can be accessed. + } + onToggleClick(chosen = null) { if (chosen !== null) { this.props.setShowTools(true); @@ -95,66 +154,151 @@ export class Tools extends React.PureComponent { // eslint-disable-line react/pr } } + onMobileToggleClick(chosen = null) { + if (chosen !== null) { + this.props.handleSetMobileShowTools(true); + } else { + this.props.handleSetMobileShowTools(!this.props.Tools.mobileShow); + } + + if (this.props.Tools.mobileShow && chosen === this.props.Tools.viewType) { + this.props.handleSetMobileShowTools(false); + } + + if ( chosen !== null) { + this.props.setViewType(chosen); + } + } + + componentWillReceiveProps(nextProps) { // if(Object.keys(this.props.Tools.selectedTools).length === 0 && Object.keys(nextProps.Tools.selectedTools).length === 1 ) { this.setState({ isFirstTime: true }); - } else { this.setState({ isFirstTime: false }); - } } + renderMobileContent() { + const {locale} = this.props.intl; + return ( + + + + { + this.onMobileToggleClick(NEWS_FEED); + this.openModal(); + }} + chosen={this.props.Tools.viewType === NEWS_FEED} + toShow={this.props.Tools.mobileShow} + > + + + + + + + + { + this.onMobileToggleClick(MY_TOOLS); + this.openModal(); + }} + chosen={this.props.Tools.viewType === MY_TOOLS} + toShow={this.props.Tools.mobileShow || this.props.Tools.onboardShow} + firstTime={this.props.Tools.onboardShow} + className={this.props.Tools.onboardShow ? 'animate' : ''} + > + + + + + + + + + + + + ) + } - render() { + renderDesktopContent() { const {locale} = this.props.intl; return ( - - - - - - this.onToggleClick(null)} - rotate={true} - toShow={this.props.Tools.show || this.props.Tools.onboardShow} - lang={this.props.language} + + + + + this.onToggleClick(null)} + rotate={true} + toShow={this.props.Tools.show || this.props.Tools.onboardShow} + lang={this.props.language} + > + + + + + this.onToggleClick(NEWS_FEED)} + chosen={this.props.Tools.viewType === NEWS_FEED} + toShow={this.props.Tools.show} > - - - - - this.onToggleClick(NEWS_FEED)} - chosen={this.props.Tools.viewType === NEWS_FEED} - toShow={this.props.Tools.show} - > - + + - - - - this.onToggleClick(MY_TOOLS)} - chosen={this.props.Tools.viewType === MY_TOOLS} - toShow={this.props.Tools.show || this.props.Tools.onboardShow} - firstTime={this.props.Tools.onboardShow} - className={this.props.Tools.onboardShow ? 'animate' : ''} - > - + + + + + this.onToggleClick(MY_TOOLS)} + chosen={this.props.Tools.viewType === MY_TOOLS} + toShow={this.props.Tools.show || this.props.Tools.onboardShow} + firstTime={this.props.Tools.onboardShow} + className={this.props.Tools.onboardShow ? 'animate' : ''} + > + + - - - - - - - + + + + + + + + ); + } + + render() { + const {locale} = this.props.intl; + + return ( + + + {this.renderMobileContent()} + + + {this.renderDesktopContent()} + + ); } } @@ -176,6 +320,9 @@ function mapDispatchToProps(dispatch) { }, setViewType: (viewType) => { dispatch(setViewType(viewType)); + }, + handleSetMobileShowTools: (show) => { + dispatch(setMobileShowTools(show)); } }; } diff --git a/app/containers/Tools/reducer.js b/app/containers/Tools/reducer.js index fcf71e1..3c4b1e1 100644 --- a/app/containers/Tools/reducer.js +++ b/app/containers/Tools/reducer.js @@ -13,12 +13,14 @@ import { SET_VIEW_TYPE, NEWS_FEED, NEW_USER_TOOL_ONBOARDING, - TOOL_ONBOARDING_FINISHED + TOOL_ONBOARDING_FINISHED, + SET_MOBILE_SHOW_TOOLS } from './constants'; const initialState = fromJS({ show: false, onboardShow: false, + mobileShow: false, selectedTools: {}, viewType: NEWS_FEED }); @@ -28,6 +30,8 @@ function toolsReducer(state = initialState, action) { switch (action.type) { case SET_SHOW_TOOLS: return state.set('show', action.data); + case SET_MOBILE_SHOW_TOOLS: + return state.set('mobileShow', action.data); case ADD_TOOL: return state .setIn(['selectedTools', action.slug], action.data); diff --git a/app/containers/Tools/sagas.js b/app/containers/Tools/sagas.js index 0c06a09..6928dd3 100644 --- a/app/containers/Tools/sagas.js +++ b/app/containers/Tools/sagas.js @@ -1,13 +1,14 @@ import { LOCATION_CHANGE } from 'react-router-redux'; import {takeLatest, take, call, put, select } from 'redux-saga/effects'; import { delay } from 'redux-saga'; -import { setShowTools , setViewType, showToolsForOnboarding, hideToolsAfterOnboarded} from './actions' +import { setShowTools , setMobileShowTools, setViewType, showToolsForOnboarding, hideToolsAfterOnboarded} from './actions' import { ADD_TOOL, MY_TOOLS } from './constants'; export const getTools = (state) => state.get('tools'); export function* closeToolsList() { yield put(setShowTools(false)); + yield put(setMobileShowTools(false)); } // This will hide the tools area the page diff --git a/app/containers/ToolsSortOptions/index.js b/app/containers/ToolsSortOptions/index.js index 1041519..c1297c9 100644 --- a/app/containers/ToolsSortOptions/index.js +++ b/app/containers/ToolsSortOptions/index.js @@ -8,32 +8,42 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; import { injectIntl } from 'react-intl'; import { createStructuredSelector } from 'reselect'; + +import styled from 'styled-components'; + import makeSelectToolsSortOptions from './selectors'; import { changeSortOption } from './actions'; import { SORT_NEWEST, SORT_ALPHABETICAL } from './constants'; import {TextButton} from 'components/CommonComponents'; - import IconButton from 'components/IconButton'; import TranslatableStaticText from 'containers/TranslatableStaticText'; import staticText from './staticText'; +const Container = styled.div` + display: inline-block; + width: auto; +`; +const SortButton = styled(IconButton)` + margin-${p=>p.isArabic?'right':'left'}: ${p=>p.last?'24px':'0'}; +` + export class ToolsSortOptions extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function render() { const { locale } = this.props.intl; return ( -
- + + - - + + - -
+ +
); } } diff --git a/app/containers/ToolsViewOptions/index.js b/app/containers/ToolsViewOptions/index.js index d9a461d..19c3212 100644 --- a/app/containers/ToolsViewOptions/index.js +++ b/app/containers/ToolsViewOptions/index.js @@ -7,6 +7,7 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; import { createStructuredSelector } from 'reselect'; +import { injectIntl} from 'react-intl'; import makeSelectToolView, { isListView, isBlockView } from './selectors'; import styled from 'styled-components'; @@ -21,21 +22,26 @@ import IconButton from 'components/IconButton'; import { LIST_VIEW, BLOCK_VIEW } from './constants' import { changeToolView } from './actions'; +const Container = styled.div` + display: inline-block; +`; // import { makeSelectToolView } from './selectors'; -import messages from './messages'; - +const ViewOption = styled(IconButton)` + margin-${p=>p.isArabic?'right':'left'}: ${p=>p.last?'24px':'0'}; +` export class ToolsViewOptions extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function render() { + const { locale } = this.props.intl; return ( -
- + + - - + + - -
+ + ); } } @@ -61,4 +67,4 @@ function mapDispatchToProps(dispatch) { }; } -export default connect(mapStateToProps, mapDispatchToProps)(ToolsViewOptions); +export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(ToolsViewOptions)); diff --git a/app/containers/TrainingMenu/index.js b/app/containers/TrainingMenu/index.js index b2e743c..f401775 100644 --- a/app/containers/TrainingMenu/index.js +++ b/app/containers/TrainingMenu/index.js @@ -22,9 +22,11 @@ import staticText from './staticText'; function TrainingMenu(props) { + const {locale} = props.intl; return ( - - + + + @@ -38,8 +40,8 @@ function TrainingMenu(props) { + - ); } diff --git a/app/containers/TrainingPage/index.js b/app/containers/TrainingPage/index.js index 39d4931..207b79b 100644 --- a/app/containers/TrainingPage/index.js +++ b/app/containers/TrainingPage/index.js @@ -19,6 +19,8 @@ import LanguageThemeProvider from 'components/LanguageThemeProvider'; import ContentBlock from 'components/ContentBlock'; import TrainingBanner from 'assets/images/about/training.jpg'; import OtherResources from 'components/OtherResources'; +import SubmitResource from 'containers/SubmitResource'; +import CollapsingSection from 'components/CollapsingSection'; import { loadData } from 'containers/App/actions'; //For listening @@ -40,6 +42,13 @@ const MenuArea = styled.div` border-${props=>props.lang==='ar'?'left':'right'}: 2px solid; position: relative; + @media(max-width: 1170px) { + width: 100%; + float: none; + padding: 0; + border: none; + } + `; const Header = styled.h1`text-align: center font-size: 48px; @@ -48,11 +57,17 @@ const Heading = styled.h2` line-height: 40px; text-align: ${props=>props.lang==='ar'?'right':'left'}; `; -const Lead = styled.div``; +const Lead = styled.div` + margin-bottom: 36px; +`; const MenuList = styled.ul` padding: 0; margin: 0; + +@media(max-width: 1170px) { + display: none; +} `; const LinkItem = styled.li` text-align: ${props=>props.lang==='ar'?'right':'left'}; @@ -72,13 +87,13 @@ const LinkItem = styled.li` display: ${props => props.isSelected ? 'block' : 'none'}; content: '______'; position: absolute; - ${props=>props.lang==='ar'?'right':'left'}: 350px; + ${props=>props.lang==='ar'?'left':'right'}: -105px; top: 25%; transform: translate(0,-50%); } `; const Button = styled.button` - text-align: ${props=>props.lang==='ar'?'right':'left'}; + text-align: ${props=>props.lang==='ar'?'right':'left'} !important; outline: none; cursor: pointer; @@ -87,39 +102,91 @@ const Button = styled.button` font-weight: bold; font-weight: 800; font-family: 'Avenir', 'Kaff', sans-serif; margin-bottom: 18px; - font-size: 16px; + font-size: ${props=>props.lang==='ar'?'13px':'14px;'}; line-height: 22px; + padding-${props=>props.lang==='ar'?'right':'left'}: 0; + + @media(max-width: 1170px) { + margin-bottom: 0; + margin: 0; + padding: 10px 0; + width: 100%; + } +`; +const Banner = styled.img` + display: block; + @media(max-width: 1170px) { + display: none; + } +`; + +const MobileBanner = styled.img` + display: none; + @media(max-width: 1170px) { + display: block; + width: 100%; + } `; -const Banner = styled.img``; +const MobileTrainingList = styled.div` +display: none; +@media(max-width: 1170px) { + display: block; + width: 100%; +}`; const ContentArea = styled.div` width: 60%; float: ${props=>props.lang==='ar'?'right':'left'}; padding-${props=>props.lang==='ar'?'right':'left'}: 100px; + + @media(max-width: 1170px) { + display: none; + } `; const Content = styled.div` display: ${props => props.isVisible ? 'block' : 'none'} !important; padding-${props=>props.lang==='ar'?'left':'right'}: 170px; margin-top: 40px; + + @media(max-width: 1170px) { + display: block !important; + padding-right: 0; + margin-top: 0; + margin-bottom: 60px; + } `; const TrainingArea =styled.div` - padding-bottom: 40px; border-bottom: 2px solid; margin-left: 20px; margin-right: 20px; + padding-bottom: 72px; &::after { content: ' '; clear: both; display: block; } + + @media(max-width: 1170px) { + padding-bottom: 20px; + } `; + +const OtherResourcesHeading = styled(Heading)` + padding-top: 36px +`; + const OtherResourcesArea = styled.div` margin-left: 20px; margin-right: 20px; `; + +const SubmitResourcesArea = styled.div` + margin-top: 72px; + text-align: center; +`; export class TrainingPage extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function constructor(props) { @@ -129,11 +196,32 @@ export class TrainingPage extends React.PureComponent { // eslint-disable-line r } } + // The delay is so that the receiveProps and didMount + // will not go against eachother componentDidMount() { if (!this.props.data.size || !this.props.data || this.props.data === undefined) { this.props.onPageLoad(); } + const reference = browserHistory.getCurrentLocation().pathname; + const targetNode = ReactDOM.findDOMNode(this.refs[reference]); + if (targetNode) { + window.scrollTo(0, targetNode.offsetTop); + } + } + + componentWillReceiveProps(nextProps) { + const reference = browserHistory.getCurrentLocation().pathname; + const targetNode = ReactDOM.findDOMNode(this.refs[reference]); + + if (targetNode && + // this.state.activateAnchor && + this.props.params.section !== nextProps.params.section + ) { + // this.setState({ activateAnchor : false, currentPath: reference, currentOffset: targetNode.offsetTop }); + window.scrollTo(0, targetNode.offsetTop); + // setTimeout(() => { this.setState({ activateAnchor: true }); }, 100); + } } handleClick(clicked) { @@ -158,19 +246,42 @@ export class TrainingPage extends React.PureComponent { // eslint-disable-line r { name: 'description', content: 'Description of TrainingPage' }, ]} /> - +
+ {trouble.get('heading')} + + + {trouble.get('content').map((item, ind) => { + return ( + this.handleClick(ind)}> + {item.get('heading')} + + ) + } + shouldOpen={ind === this.state.selected} + > + + + + + ) + })} + + {trouble.get('content').map((item, ind) => { return ( @@ -197,12 +308,16 @@ export class TrainingPage extends React.PureComponent { // eslint-disable-line r - - + + - + + + + +
diff --git a/app/containers/TranslatableStaticText/index.js b/app/containers/TranslatableStaticText/index.js index faa0390..b9bcef7 100644 --- a/app/containers/TranslatableStaticText/index.js +++ b/app/containers/TranslatableStaticText/index.js @@ -8,9 +8,10 @@ import React, { PropTypes } from 'react'; import { connect } from 'react-redux'; import { createStructuredSelector } from 'reselect'; import makeSelectTranslatableStaticText from './selectors'; - +import styled from 'styled-components'; import { loadLanguage } from './actions'; +const SpanItem = styled.span``; export class TranslatableStaticText extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function constructor() { @@ -50,6 +51,7 @@ export class TranslatableStaticText extends React.PureComponent { // eslint-disa } buildMessage({id, defaultMessage}, values) { + if (!id || id === undefined ) { return null; } const template = this.getStaticMessage({id, defaultMessage}); const extrapolate = this.build(template, values); return extrapolate; @@ -60,7 +62,7 @@ export class TranslatableStaticText extends React.PureComponent { // eslint-disa const message = this.buildMessage({...this.props}, this.props.values); return ( - {message} + {message} ); } } @@ -107,6 +109,7 @@ const injectStaticText = (WrappedComponent) => { if (values) { let splits = message.split(/({{.*?}})/); const regex = new RegExp("{{\s*(.*?)\s*}}", "gi"); + return splits.map(item => { var match; if (match = regex.exec(item)) { @@ -114,7 +117,7 @@ const injectStaticText = (WrappedComponent) => { } else { return item; } - }) + }).join(''); // var compiled = _.template(message); // return compiled(values); } @@ -123,7 +126,7 @@ const injectStaticText = (WrappedComponent) => { } buildMessage({id, defaultMessage}, values) { - + if (!id || id === undefined ) { return null; } const template = this.getStaticMessage({id, defaultMessage}); const extrapolate = this.build(template, values); diff --git a/app/containers/TypeDetails/index.js b/app/containers/TypeDetails/index.js new file mode 100644 index 0000000..611a6eb --- /dev/null +++ b/app/containers/TypeDetails/index.js @@ -0,0 +1,180 @@ +/** +* +* ToolTypeSelectedFull +* +*/ + +import React from 'react'; +import styled from 'styled-components'; +import {Link} from 'react-router'; +import { injectIntl } from 'react-intl'; +import Isvg from 'react-inlinesvg'; + +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import MethodologyIcon from 'assets/images/type/methodologies-optionflag.svg'; +import PrincipleIcon from 'assets/images/type/principles-optionflag.svg'; +import StoryIcon from 'assets/images/type/stories-optionflag.svg'; +import TacticIcon from 'assets/images/type/tactics-optionflag.svg'; +import TheoryIcon from 'assets/images/type/theories-optionflag.svg'; + +import ContentBlock from 'components/ContentBlock'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; + +import RegionOptions from 'containers/RegionOptions'; + +import staticText from 'containers/ToolTypeArea/staticText'; + +const Container = styled.section` + display: ${props=>props.show ? 'block' : 'none'}; + margin-top: 42px; + +`; +const Viewport = styled.div` +&::after { + content: ' '; + clear: both; + display: block; +} +`; + +const Column = styled.div` + text-align: center; + width: ${props=>props.width} + float: ${p=>p.theme.isArabic?'right':'left'}; + position: relative; + + &::after { + content: ' '; + position: absolute; + top: 0; + ${p=>p.theme.isArabic?'left':'right'}: 0; + width: 100%; + height: 100%; + max-height: 160px; + opacity: 0.3; + z-index: -1; + background-position: ${p=>p.theme.isArabic?'left':'right'} top; + background-repeat: no-repeat; + background-size: ${ + props=>{ + switch(props.bg) { + case 'theory' : + case 'methodology': return 'cover'; + default: return 'contain'; + } + } + }; + background-image: url(${ + props=>{ + switch(props.bg) { + case 'tactic' : return TacticIcon; + case 'principle' : return PrincipleIcon; + case 'story': return StoryIcon; + case 'theory': return TheoryIcon; + case 'methodology': return MethodologyIcon; + } + } + }); + } + + @media(max-width: 1170px) { + width: 100%; + display: block; + text-align: center; + + & > div { text-align: center; } + } +`; +const ToolType = styled(Link)` + margin-${p=>p.theme.isArabic ?'left':'right'}: 0.5%; + display: block; + text-align: ${p=>p.theme.isArabic ?'right':'left'}; + vertical-align: top; + opacity: ${p=>p.selected?'0':'1'}; + color: #828486; + text-transform: uppercase; + font-weight: bold; + margin-bottom: 15px; + font-size: 14px; + + * { + vertical-align: top; + } +`; +const Head = styled.h1` + margin: 0; +`; +const Desc = styled.p` + margin: 0; + + &::after { + content: ' '; + clear: both; + display: block; + } +` + +const Flag = styled.span` + display: ${props=>props.selected ? 'block' : 'none'}; + position: absolute; + width: 100%; + opacity: .4; + top: 0; + z-index: -1; + + .isvg { + width: 100%; + overflow-y: visible; + max-height: 160px; + display: inline-block; + + svg { + width: 100%; + height: auto; + } + } +`; + +const TypeName = styled.h1` + text-align: ${p=>p.theme.isArabic?'left':'right'}; + margin-top: 20px; + text-transform: uppercase; + margin-${p=>p.theme.isArabic?'left':'right'}: 10px; +`; + +const Description = styled(ContentBlock)` + padding: 10px 0; +`; + +// +// +// +// +// + +function TypeDetails(props) { + + if (props.filter === undefined) { + return null; + } + return ( + + + + + + + + { props.label === 'story' ? : null} + + + + + ); +} + +TypeDetails.propTypes = { + +}; + +export default TypeDetails; diff --git a/app/containers/TypeDetails/messages.js b/app/containers/TypeDetails/messages.js new file mode 100644 index 0000000..9c1687f --- /dev/null +++ b/app/containers/TypeDetails/messages.js @@ -0,0 +1,13 @@ +/* + * ToolTypeSelectedFull Messages + * + * This contains all the text for the ToolTypeSelectedFull component. + */ +import { defineMessages } from 'react-intl'; + +export default defineMessages({ + header: { + id: 'app.components.ToolTypeSelectedFull.header', + defaultMessage: 'This is the ToolTypeSelectedFull component !', + }, +}); diff --git a/app/containers/TypeDetails/tests/index.test.js b/app/containers/TypeDetails/tests/index.test.js new file mode 100644 index 0000000..36ec07b --- /dev/null +++ b/app/containers/TypeDetails/tests/index.test.js @@ -0,0 +1,10 @@ +// import React from 'react'; +// import { shallow } from 'enzyme'; + +// import ToolTypeSelectedFull from '../index'; + +describe('', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(false); + }); +}); diff --git a/app/containers/WhatsHappening/Bell.js b/app/containers/WhatsHappening/Bell.js new file mode 100644 index 0000000..da30bcf --- /dev/null +++ b/app/containers/WhatsHappening/Bell.js @@ -0,0 +1,61 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { Link } from 'react-router'; +import { injectIntl } from 'react-intl'; +import Isvg from 'react-inlinesvg'; +import { createStructuredSelector } from 'reselect'; +import styled from 'styled-components'; + +import makeSelectWhatsHappening from './selectors'; +import BellIcon from 'assets/images/icons/bell.svg'; +import Counter from './Counter'; + +const CounterContainer = styled.div` + position: absolute + top: 5px; + ${p=>p.lang==='ar'?'right':'left'}: 7px; + +`; +const BellContainer = styled.div` + display: inline-block; +`; +const Viewport = styled.div` + width: 100%; + height: 100%; + position: relative; +`; +class Bell extends React.PureComponent { + + constructor(props) { + super(); + } + + render() { + const { locale } = this.props.intl; + return( + + + this.props.onClick()}> + + + + + + + + ); + } +} + +const mapStateToProps = createStructuredSelector({ + WhatsHappening: makeSelectWhatsHappening(), +}); + +function mapDispatchToProps(dispatch) { + return { + dispatch + } +} + + +export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(Bell)); diff --git a/app/containers/WhatsHappening/Counter.js b/app/containers/WhatsHappening/Counter.js new file mode 100644 index 0000000..b1b95d8 --- /dev/null +++ b/app/containers/WhatsHappening/Counter.js @@ -0,0 +1,80 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import { Link } from 'react-router'; +import { injectIntl } from 'react-intl'; +import Isvg from 'react-inlinesvg'; +import makeSelectWhatsHappening from './selectors'; +import BellIcon from 'assets/images/icons/bell.svg'; +import { createStructuredSelector } from 'reselect'; +import styled from 'styled-components'; + +const CounterArea = styled.div` + color: white; + text-align: center; + width: 20px; + font-size: 12px; + position: relative; + + span { + z-index: 100; + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%,-50%); + font-weight: 800; + } + + &::after { + content: ' '; + position: absolute; + top: 50%; + left: 50%; + z-index: 50; + width: 100%; + padding-bottom: 100%; + background: black; + border-radius: 50%; + transform: translate(-50%, -50%); + } + +`; + +class Counter extends React.PureComponent { + + constructor(props) { + super(); + } + + render() { + + + const { data, lastViewed } = this.props.WhatsHappening; + const { locale } = this.props.intl; + if (!data || data === undefined) return null; + + const unseenCount = data.filter(item=> { + const dateTime = new Date(item.date); + return dateTime > lastViewed; + }); + + + if (unseenCount.length == 0) return null; + + return ( + {unseenCount.length} + ) + } +} + +const mapStateToProps = createStructuredSelector({ + WhatsHappening: makeSelectWhatsHappening(), +}); + +function mapDispatchToProps(dispatch) { + return { + dispatch + } +} + + +export default connect(mapStateToProps, mapDispatchToProps)(injectIntl(Counter)); diff --git a/app/containers/WhatsHappening/Post.js b/app/containers/WhatsHappening/Post.js new file mode 100644 index 0000000..69de682 --- /dev/null +++ b/app/containers/WhatsHappening/Post.js @@ -0,0 +1,190 @@ +import React, { PropTypes } from 'react'; +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import LatinThemeProvider from 'components/LatinThemeProvider' +import Markdown from 'react-markdown'; +import { RouterLink } from 'utils/markdown'; +import { createStructuredSelector } from 'reselect'; +import { connect } from 'react-redux'; +import BlockViewItem from 'containers/HomePage/BlockViewItem'; +import ImageSlideshow from 'components/ImageSlideshow'; +import styled from 'styled-components'; +import ContentBlock from 'components/ContentBlock'; +import HeaderBlock from 'components/HeaderBlock'; +import Isvg from 'react-inlinesvg'; +import ArrowIcon from 'assets/images/icons/arrow.svg'; + +const Container = styled.div` + display: flex + margin-top: 95px; + + @media(max-width: 1170px) { + display: block; + margin-top: 15px; + } +`; +const ContentArea = styled.div` + width: 490px; + min-width: 490px; + display: inline-block; + border-${p=>p.theme.isArabic?'left':'right'}: 2px solid; + align-items: stretch; + position: relative; + padding: 70px; + + &::after { + content: ' '; + position: absolute; + width: 50px; + ${p=>p.theme.isArabic?'left':'right'}: -25px; + height: 0; + border-top: 2px solid; + top: ${p=>p.twig + 10}%; + } + + @media(max-width: 1170px) { + display: block; + width: 100%; + min-width: 100%; + border: none; + padding: 40px; + + &::after { + border: none; + } + } +`; +const FeatureArea = styled.div` + flex-grow: 1; + align-items: stretch; + display: inline-block; + padding-${p=>p.theme.isArabic?'right':'left'}: 80px; + padding-top: 45px; + padding-bottom: 70px; + + @media(max-width: 1170px) { + display: block; + width: 100%; + min-width: 100%; + padding: 10px; + text-align: center; + + & > div { + float: none; + margin: 0; + display: inline-block; + margin-bottom: 20px; + } + } +`; + +const DateContent = styled(ContentBlock)` + font-style: italic; + font-weight: 12px; +`; +const Title = styled(HeaderBlock)` + font-size: 40px; + line-height: 44px; +`; +const FeatureImage = styled.img`width: 100%`; +const BEAUTIFULRISING_URL = `//www.beautifulrising.org/`; + +const PreviousButton = styled.div` + display: inline-block; + opacity: 0.7; +`; +const NextButton = styled.div` + display: inline-block; + transform: rotate(180deg); + opacity: 0.7; +` + +class Post extends React.PureComponent { + + constructor(props) { + super(); + } + + renderSlideshow() { + return ( + BEAUTIFULRISING_URL + item) + } + previousButton={()} + nextButton={()} + /> + ) + } + + renderImage() { + return ( + )} + nextButton={()} + /> + ) + } + + renderTools() { + + return this.props.tools.map((item, index) => { + if (!this.props.toolsData[item] || this.props.toolsData[item] === undefined) return null; + return ( + + )}) + } + renderFeatureArea() { + + if (this.props.slideshow) { + return ( + + {this.renderSlideshow()} + + ); + } + + if (this.props.image) { + return ( + + {this.renderImage()} + + ); + } + + if (this.props.tools) { + return ( + + {this.renderTools()} + + ) + } + } + render() { + + return( + + + + + {this.props.date} + {this.props.title} + + + + + + { this.renderFeatureArea() } + + + ) + } +} + +export default Post; diff --git a/app/containers/WhatsHappening/actions.js b/app/containers/WhatsHappening/actions.js new file mode 100644 index 0000000..a6ed8dd --- /dev/null +++ b/app/containers/WhatsHappening/actions.js @@ -0,0 +1,47 @@ +/* + * + * TranslatableStaticText actions + * + */ + +import { + DEFAULT_ACTION, + LOAD_WHATSHAPPENING, + LOADING_WHATSHAPPENING_COMPLETE, + LOADING_WHATSHAPPENING_ERROR, + UPDATE_WHATSHAPPENING_LASTVIEWED +} from './constants'; + +export function defaultAction() { + return { + type: DEFAULT_ACTION, + }; +} + +export function loadWhatsHappening() { + + return { + type: LOAD_WHATSHAPPENING + }; +} + +export function loadingWhatsHappeningComplete(data) { + return { + type: LOADING_WHATSHAPPENING_COMPLETE, + data + }; +} + +export function loadingWhatsHappeningError(err) { + return { + type: LOADING_WHATSHAPPENING_ERROR, + error: err + }; +} + +export function updateLastViewed(lastViewed = new Date()) { + return { + type: UPDATE_WHATSHAPPENING_LASTVIEWED, + lastViewed + } +} diff --git a/app/containers/WhatsHappening/constants.js b/app/containers/WhatsHappening/constants.js new file mode 100644 index 0000000..0823cee --- /dev/null +++ b/app/containers/WhatsHappening/constants.js @@ -0,0 +1,11 @@ +/* + * + * WhatsHappening constants + * + */ + +export const DEFAULT_ACTION = 'app/WhatsHappening/DEFAULT_ACTION'; +export const LOAD_WHATSHAPPENING = 'app/WhatsHappening/DEFAULT_ACTION'; +export const LOADING_WHATSHAPPENING_COMPLETE = 'app/WhatsHappening/LOADING_WHATSHAPPENING_COMPLETE'; +export const LOADING_WHATSHAPPENING_ERROR = 'app/WhatsHappening/LOADING_WHATSHAPPENING_ERROR'; +export const UPDATE_WHATSHAPPENING_LASTVIEWED = 'app/WhatsHappening/UPDATE_WHATSHAPPENING_LASTVIEWED'; diff --git a/app/containers/WhatsHappening/index.js b/app/containers/WhatsHappening/index.js new file mode 100644 index 0000000..b7cb2d6 --- /dev/null +++ b/app/containers/WhatsHappening/index.js @@ -0,0 +1,171 @@ +/* + * + * WhatsHappening + * + */ + +import React, { PropTypes } from 'react'; +import { connect } from 'react-redux'; +import Helmet from 'react-helmet'; +import styled from 'styled-components'; +import { Link } from 'react-router'; +import { createStructuredSelector } from 'reselect'; + +import LanguageThemeProvider from 'components/LanguageThemeProvider'; +import TranslatableStaticText from 'containers/TranslatableStaticText'; +import { loadData } from 'containers/App/actions'; + +import makeSelectWhatsHappening, { makeSelectToolsAsSlug } from './selectors'; +import { updateLastViewed } from './actions'; +import staticText from './staticText' +import Post from './Post'; +import Bell from './Bell'; +import Counter from './Counter'; + +const PostList = styled.ul`margin: 0; padding: 0;`; +const PostListItem = styled.li`list-style: none;`; +const POST_PER_PAGE = 3; + +const PaginationArea = styled.div` + width: 100%; + padding: 20px 0; + &::after { + content:' '; + clear: both; + display: block; + } +`; +const WhatHappeningButton = styled(Link)` + color: #828487; + text-decoration: underline; + display: ${p=>p.toShow?'block':'none'}; + text-transform: uppercase; + font-size: 14px; + font-weight: 600; +`; + +const NextButton = styled(WhatHappeningButton)` + float: right; +`; + +const PreviousButton = styled(WhatHappeningButton)` + float: left; +`; + +export class WhatsHappening extends React.PureComponent { // eslint-disable-line react/prefer-stateless-function + constructor(props) { + super(); + + this.state = { isLast: false }; + } + + componentDidMount() { + this.props.handlePageLoaded(); + + if (this.props.toolsData.size === 0 ) { + + this.props.onPageLoad(); + } + } + handleEarlyPage() { + this.setState({ isLast: false }); + } + + handleLastPage() { + this.setState({ isLast: true }); + } + + componentWillReceiveProps(nextProps) { + + if (this.props !== undefined && this.props.location !== undefined + && this.props.location.query !== undefined + && this.props.location.query.page != nextProps.location.query.page) { + const pageCount = nextProps.location.query.page; + if((POST_PER_PAGE * pageCount) + POST_PER_PAGE <= this.props.WhatsHappening.data.length ) { + this.setState({ isLast: false }); + } else { + this.setState({ isLast: true }) + } + } + + } + + renderPostList(page = 0) { + //Filter out the ones that are after the lastUpdate date + if (!this.props.WhatsHappening.data) return null; + + let targetDataSet = null; + + if((POST_PER_PAGE * page) + POST_PER_PAGE + 1 <= this.props.WhatsHappening.data.length ) { + targetDataSet = this.props.WhatsHappening.data.slice(POST_PER_PAGE * page, POST_PER_PAGE * page + POST_PER_PAGE); + } else { + + targetDataSet = this.props.WhatsHappening.data.slice(POST_PER_PAGE * page, this.props.WhatsHappening.data.length - 1); + } + + + // + // const itemsToShow = this.props.WhatsHappening.data.filter(item => !this.props.WhatsHappening.lastViewed || new Date(item.date) < this.props.WhatsHappening.lastViewed) + return targetDataSet.map((item, index) => + + + ) + } + + render() { + + const pageFocus = this.props.location.query.page ? parseInt(this.props.location.query.page) : 1; + const postList = this.renderPostList(pageFocus - 1); + + + // + return ( + + +

+ +

+ + {postList} + + + + 1}>Previous Page + Next Button + +
+ ); + } +} + +WhatsHappening.propTypes = { + dispatch: PropTypes.func.isRequired, +}; + +const mapStateToProps = createStructuredSelector({ + WhatsHappening: makeSelectWhatsHappening(), + toolsData: makeSelectToolsAsSlug() +}); + +function mapDispatchToProps(dispatch) { + return { + dispatch, + handlePageLoaded: () =>{ + dispatch(updateLastViewed()); + }, + handleShowClick: () => { + dispatch(updateLastViewed()); + }, + onPageLoad: (evt) => { + dispatch(loadData()); + } + }; +} + +export default connect(mapStateToProps, mapDispatchToProps)(WhatsHappening); +export { Bell, Counter }; diff --git a/app/containers/WhatsHappening/reducer.js b/app/containers/WhatsHappening/reducer.js new file mode 100644 index 0000000..d2e4e62 --- /dev/null +++ b/app/containers/WhatsHappening/reducer.js @@ -0,0 +1,55 @@ +/* + * + * WhatsHappening reducer + * + */ + +import { fromJS } from 'immutable'; +import { + DEFAULT_ACTION, + LOAD_WHATSHAPPENING, + LOADING_WHATSHAPPENING_COMPLETE, + LOADING_WHATSHAPPENING_ERROR, + UPDATE_WHATSHAPPENING_LASTVIEWED +} from './constants'; + +const initialState = fromJS({ + data: null, + loading: false, + complete: false, + error: false, + lastViewed: null +}); + +function whatsHappeningReducer(state = initialState, action) { + switch (action.type) { + case DEFAULT_ACTION: + return state; + + case LOAD_WHATSHAPPENING: + + return state + .set('loading', true) + .set('complete', false) + .set('error', false); + case LOADING_WHATSHAPPENING_COMPLETE: + + return state.set('data', action.data) + .set('complete', true) + .set('loading', false) + .set('error', false) + + case LOADING_WHATSHAPPENING_ERROR: + + return state.set('data', null) + .set('loading', false) + .set('complete', false) + .set('error', action.error); + case UPDATE_WHATSHAPPENING_LASTVIEWED: + return state.set('lastViewed', action.lastViewed); + default: + return state; + } +} + +export default whatsHappeningReducer; diff --git a/app/containers/WhatsHappening/sagas.js b/app/containers/WhatsHappening/sagas.js new file mode 100644 index 0000000..c8fece9 --- /dev/null +++ b/app/containers/WhatsHappening/sagas.js @@ -0,0 +1,108 @@ +import { take, race, call, cancel, put, select,takeLatest } from 'redux-saga/effects'; +import { LOAD_WHATSHAPPENING, + LOADING_WHATSHAPPENING_COMPLETE, + LOADING_WHATSHAPPENING_ERROR + } from './constants'; + + import { CHANGE_LOCALE } from 'containers/LanguageProvider/constants'; +import { loadWhatsHappening, loadingWhatsHappeningComplete, loadingWhatsHappeningError } from './actions'; +// Individual exports for testing +import request from 'utils/request'; + +export const getLanguage = (state) => state.get('language'); +export const getWhatsHappening = (state) => state.get('whatsHappening'); + +let timeoutHandler = null; +// Utility function to delay effects +function delay(millis) { + + const promise = new Promise(resolve => { + if (timeoutHandler) { + clearTimeout(timeoutHandler); + } + + timeoutHandler = setTimeout(() => resolve(true), millis) + }); + return promise; +} + +// Fetch data every 20 seconds +function* pollData() { + try { + yield call(delay, 10000); + yield put(loadWhatsHappening()); + } catch (error) { + // cancellation error -- can handle this if you wish + return; + } +} + +// Wait for successful response, then fire another request +// Cancel polling if user logs out +function* watchPollData() { + while (true) { + yield take(LOADING_WHATSHAPPENING_COMPLETE); + yield race([ + call(pollData) + ]); + } +} + +export function* retrieveWhatsHappening() { + // getContactUs.get(email); + + const language = yield select(getLanguage); + + + const requestURL = `https://api.beautifulrising.org/api/v1/posts?lang=${language.get('locale')}&orderby=timestamp&reverse=true&limit=100`; + + try { + const data = yield call(request, requestURL); + + + /** LOADING AREA **/ + yield put(loadingWhatsHappeningComplete(data)); + + + } catch (err) { + yield call(put, loadingWhatsHappeningError(err)); + + } +} +export function* initialLoadingCall() { + // See example in containers/HomePage/sagas.js + + + const action = yield takeLatest(LOAD_WHATSHAPPENING, retrieveWhatsHappening); + + // yield take(CHANGE_LOCALE); + // + // yield cancel(action); + // // const sel = yield select('email'); + // yield (); +} +export function* handleLanguageChange() { + + yield put(loadWhatsHappening()); + +} + +export function* languageChanged() { + + const action = yield takeLatest(CHANGE_LOCALE, handleLanguageChange); + + // yield take(CHANGE_LOCALE); +} + +// All sagas to be loaded +// export default [ +// languageChanged, +// initialLoadingCall +// ]; + +// Daemonize tasks in parallel +export default [ + watchPollData, + languageChanged, + initialLoadingCall +] diff --git a/app/containers/WhatsHappening/selectors.js b/app/containers/WhatsHappening/selectors.js new file mode 100644 index 0000000..599483d --- /dev/null +++ b/app/containers/WhatsHappening/selectors.js @@ -0,0 +1,47 @@ +import { createSelector } from 'reselect'; +import Immutable, { OrderedSet, Map, List } from 'immutable'; + +/** + * Direct selector to the whatsHappening state domain + */ +const selectWhatsHappeningDomain = () => (state) => state.get('whatsHappening'); +const selectGlobal = () => (state) => state.get('global'); + +/** + * Other specific selectors + */ + const indexBy = (iterable, searchKey) => { + if (iterable) { + const reduced = iterable.reduce( + (lookup, item) => lookup.set(item.get(searchKey), item), + Map() + ); + + return reduced.toJS(); + } + + return Map(); + } + +/** + * Default selector used by WhatsHappening + */ + + const makeSelectToolsAsSlug = () => createSelector( + selectGlobal(), + (globalState) => { + + return indexBy(Immutable.fromJS(globalState.getIn(['appData', 'information'])), 'slug'); + } + ); + +const makeSelectWhatsHappening = () => createSelector( + selectWhatsHappeningDomain(), + (substate) => substate.toJS() +); + +export default makeSelectWhatsHappening; +export { + selectWhatsHappeningDomain, + makeSelectToolsAsSlug +}; diff --git a/app/containers/WhatsHappening/staticText.js b/app/containers/WhatsHappening/staticText.js new file mode 100644 index 0000000..03dcfea --- /dev/null +++ b/app/containers/WhatsHappening/staticText.js @@ -0,0 +1,6 @@ +export default { + whatsHappeningHeader: { + id: 'whats-happening.header', + defaultMessage: 'What\'s Happening', + } +}; diff --git a/app/containers/WhatsHappening/tests/actions.test.js b/app/containers/WhatsHappening/tests/actions.test.js new file mode 100644 index 0000000..2351713 --- /dev/null +++ b/app/containers/WhatsHappening/tests/actions.test.js @@ -0,0 +1,18 @@ + +import { + defaultAction, +} from '../actions'; +import { + DEFAULT_ACTION, +} from '../constants'; + +describe('WhatsHappening actions', () => { + describe('Default Action', () => { + it('has a type of DEFAULT_ACTION', () => { + const expected = { + type: DEFAULT_ACTION, + }; + expect(defaultAction()).toEqual(expected); + }); + }); +}); diff --git a/app/containers/WhatsHappening/tests/index.test.js b/app/containers/WhatsHappening/tests/index.test.js new file mode 100644 index 0000000..ca0ac03 --- /dev/null +++ b/app/containers/WhatsHappening/tests/index.test.js @@ -0,0 +1,10 @@ +// import React from 'react'; +// import { shallow } from 'enzyme'; + +// import { WhatsHappening } from '../index'; + +describe('', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(false); + }); +}); diff --git a/app/containers/WhatsHappening/tests/reducer.test.js b/app/containers/WhatsHappening/tests/reducer.test.js new file mode 100644 index 0000000..740f66a --- /dev/null +++ b/app/containers/WhatsHappening/tests/reducer.test.js @@ -0,0 +1,9 @@ + +import { fromJS } from 'immutable'; +import whatsHappeningReducer from '../reducer'; + +describe('whatsHappeningReducer', () => { + it('returns the initial state', () => { + expect(whatsHappeningReducer(undefined, {})).toEqual(fromJS({})); + }); +}); diff --git a/app/containers/WhatsHappening/tests/sagas.test.js b/app/containers/WhatsHappening/tests/sagas.test.js new file mode 100644 index 0000000..6dd4d4e --- /dev/null +++ b/app/containers/WhatsHappening/tests/sagas.test.js @@ -0,0 +1,15 @@ +/** + * Test sagas + */ + +/* eslint-disable redux-saga/yield-effects */ +// import { take, call, put, select } from 'redux-saga/effects'; +// import { defaultSaga } from '../sagas'; + +// const generator = defaultSaga(); + +describe('defaultSaga Saga', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(false); + }); +}); diff --git a/app/containers/WhatsHappening/tests/selectors.test.js b/app/containers/WhatsHappening/tests/selectors.test.js new file mode 100644 index 0000000..344eabe --- /dev/null +++ b/app/containers/WhatsHappening/tests/selectors.test.js @@ -0,0 +1,10 @@ +// import { fromJS } from 'immutable'; +// import { makeSelectWhatsHappeningDomain } from '../selectors'; + +// const selector = makeSelectWhatsHappeningDomain(); + +describe('makeSelectWhatsHappeningDomain', () => { + it('Expect to have unit tests specified', () => { + expect(true).toEqual(false); + }); +}); diff --git a/app/global-styles.js b/app/global-styles.js index cf96365..0b6f204 100644 --- a/app/global-styles.js +++ b/app/global-styles.js @@ -36,6 +36,12 @@ injectGlobal` src: url(${AvenirBlack}); } + @font-face { + font-family: 'Avenir Black'; + font-weight: 800; + src: url(${AvenirBlack}); + } + @font-face { font-family: 'KnockOut'; src: url(${KnockOut}); @@ -97,7 +103,9 @@ injectGlobal` font-family: 'Avenir', 'Kaff', 'Helvetica Neue', Helvetica, Arial, sans-serif; } - + input[type=text]::placeholder, textarea::placeholder { + font-size: 12px; + } h1 { font-size: 50px; @@ -112,6 +120,7 @@ injectGlobal` letter-spacing: 1px; } + h1,h2,h3,h4,h5 { margin: 0; padding: 0; } body.fontLoaded { font-family: 'Avenir', 'Kaff', 'Helvetica Neue', Helvetica, Arial, sans-serif; } @@ -125,11 +134,62 @@ injectGlobal` .ReactModal__Body--open { overflow-y: hidden; overflow: hidden; + + .onboarding-language-changer { + button { color: white; } + } } .ReactModal__Overlay--after-open { + position: absolute; + left: 0; top: 0; + height: 100%; + width: 100% !important; + .circledContainer::after { - width: 138px !important; + width: 157px !important; } } + [aria-label=MenuModal] { + @media(max-width: 1170px) { + z-index: 1100 !important; + } + } + + [aria-label=Onboarding] { + @media(max-width: 1170px) { + width: calc(100% - 75px) !important; + } + } + [aria-label=ToolsModal] { + display: none; + @media(max-width: 1170px) { + display: block; + width: 100% !important; + height: calc(100% - 70px) !important; + + & > div { height: 100%; } + } + } + + .MenuModalOverlay { + + @media(max-width: 1170px) { + z-index: 1100; + + & > div { + z-index: 1100; + } + } + } + + .ToolModalOverlay { + display: none; + @media(max-width: 1170px) { + display: block; + } + } + + .ReactModalPortal { + } `; diff --git a/app/reducers.js b/app/reducers.js index 62afc88..7bddc0a 100644 --- a/app/reducers.js +++ b/app/reducers.js @@ -17,12 +17,15 @@ import searchFieldReducer from 'containers/SearchField/reducer'; import toolsReducer from 'containers/Tools/reducer'; import contactUsReducer from 'containers/ContactUs/reducer'; import submitRealWorldExampleReducer from 'containers/SubmitRealWorldExample/reducer'; +import submitResourceReducer from 'containers/SubmitResource/reducer'; import emailToolsReducer from 'containers/EmailTools/reducer'; +import toolPageReducer from 'containers/ToolPage/reducer'; import newsFeedReducer from 'containers/NewsFeed/reducer'; import submitNewsFeedReducer from 'containers/SubmitNewsFeed/reducer'; import askTheContributorReducer from 'containers/AskTheContributor/reducer'; import onboardingModalReducer from 'containers/OnboardingModal/reducer'; import translatableStaticTextReducer from 'containers/TranslatableStaticText/reducer'; +import whatsHappeningReducer from 'containers/WhatsHappening/reducer'; /* * routeReducer * @@ -64,14 +67,17 @@ export default function createReducer(asyncReducers) { toolsView: toolsViewOptionsReducer, toolsSort: toolsSortOptionsReducer, tools: toolsReducer, + toolPage: toolPageReducer, contactUs: contactUsReducer, submitRealWorldExample: submitRealWorldExampleReducer, + submitResource: submitResourceReducer, emailTools: emailToolsReducer, newsFeed: newsFeedReducer, submitNewsFeed: submitNewsFeedReducer, askTheContributor: askTheContributorReducer, onboardingModal: onboardingModalReducer, translatableStaticText: translatableStaticTextReducer, + whatsHappening: whatsHappeningReducer, ...asyncReducers, }); } diff --git a/app/routes.js b/app/routes.js index b82aa08..3301e78 100644 --- a/app/routes.js +++ b/app/routes.js @@ -9,6 +9,8 @@ import NewsFeed from 'containers/NewsFeed/sagas'; import Tools from 'containers/Tools/sagas'; import TranslatableStaticText from 'containers/TranslatableStaticText/sagas'; import SubmitNewsFeed from 'containers/SubmitNewsFeed/sagas'; +import HomePage from 'containers/HomePage/sagas'; +import WhatsHappening from 'containers/WhatsHappening/sagas'; import {changeLocale} from 'containers/LanguageProvider/actions'; const errorLoading = (err) => { console.error('Dynamic page loading failed', err); // eslint-disable-line no-console @@ -23,9 +25,14 @@ export default function createRoutes(store) { const { injectReducer, injectSagas } = getAsyncInjectors(store); // eslint-disable-line no-unused-vars injectSagas(ContactUs); + injectSagas(WhatsHappening); + //enable email everywhere injectSagas(EmailTools); + //for HomePage + injectSagas(HomePage); + //get news feed injectSagas(NewsFeed); @@ -42,7 +49,6 @@ export default function createRoutes(store) { const getHomePageComponent = (nextState, cb) => { const importModules = Promise.all([ import('containers/HomePage/reducer'), - import('containers/HomePage/sagas'), // import('containers/SearchField/sagas'), import('containers/HomePage'), import('containers/ToolsViewOptions/reducer'), @@ -51,10 +57,9 @@ export default function createRoutes(store) { const renderRoute = loadModule(cb); - importModules.then(([reducer, sagas, /*searchSagas,*/ component, + importModules.then(([reducer, /*searchSagas,*/ component, toolsViewOptionsReducer, toolsSortOptionsReducer]) => { injectReducer('homePage', reducer.default); - injectSagas(sagas.default); // injectSagas(searchSagas.default); injectReducer('toolsView', toolsViewOptionsReducer.default); @@ -72,9 +77,30 @@ export default function createRoutes(store) { name: 'homePage', getComponent: getHomePageComponent, }, + { + path: '/whats-happening', + name: 'whats-happening', + ignoreScrollBehavior: true, //for useScroll + getComponent(nextState, cb) { + + const importModules = Promise.all([ + import('containers/WhatsHappening'), + ]); + + const renderRoute = loadModule(cb); + + importModules.then(([component]) => { + renderRoute(component); + }); + + importModules.catch(errorLoading); + + }, + }, { path: '/tool(/:label)*', name: 'tool', + scrollToTop: true, getComponent(nextState, cb) { const importModules = Promise.all([ @@ -87,9 +113,9 @@ export default function createRoutes(store) { const renderRoute = loadModule(cb); - importModules.then(([reducer, sagas, worldExampleSagas, askContributor, component]) => { + importModules.then(([reducer, toolPageSagas, worldExampleSagas, askContributor, component]) => { injectReducer('tool', reducer.default); - injectSagas(sagas.default); + injectSagas(toolPageSagas.default); injectSagas(worldExampleSagas.default); injectSagas(askContributor.default); renderRoute(component); @@ -106,14 +132,12 @@ export default function createRoutes(store) { getComponent(nextState, cb) { const importModules = Promise.all([ - import('containers/AboutPage/sagas'), import('containers/AboutPage'), ]); const renderRoute = loadModule(cb); - importModules.then(([sagas, component]) => { - injectSagas(sagas.default); + importModules.then(([component]) => { renderRoute(component); }); @@ -128,14 +152,12 @@ export default function createRoutes(store) { getComponent(nextState, cb) { const importModules = Promise.all([ - import('containers/AboutPage/sagas'), import('containers/ContributePage'), ]); const renderRoute = loadModule(cb); - importModules.then(([sagas, component]) => { - injectSagas(sagas.default); + importModules.then(([component]) => { renderRoute(component); }); @@ -150,13 +172,11 @@ export default function createRoutes(store) { getComponent(nextState, cb) { const importModules = Promise.all([ - import('containers/AboutPage/sagas'), import('containers/TrainingPage'), ]); const renderRoute = loadModule(cb); - importModules.then(([sagas, component]) => { - injectSagas(sagas.default); + importModules.then(([component]) => { renderRoute(component); }); importModules.catch(errorLoading); @@ -169,13 +189,11 @@ export default function createRoutes(store) { getComponent(nextState, cb) { const importModules = Promise.all([ - import('containers/AboutPage/sagas'), import('containers/PlatformsPage'), ]); const renderRoute = loadModule(cb); - importModules.then(([sagas, component]) => { - injectSagas(sagas.default); + importModules.then(([component]) => { renderRoute(component); }); importModules.catch(errorLoading); diff --git a/app/translations/en.json b/app/translations/en.json index 90a5f80..4ef7cf7 100644 --- a/app/translations/en.json +++ b/app/translations/en.json @@ -67,7 +67,7 @@ "app.components.PlatformsPageComponents.how": "How to use it", "app.components.PlatformsPageComponents.pdfHeader": "PDF", "app.components.PlatformsPageComponents.what": "What It is", - "app.components.RegionOptions.header": "Region", + "app.components.RegionOptions.header": "Filter by Region", "app.components.SelectedToolComponents.header": "This is the SelectedToolComponents component !", "app.components.ShareButton.emailMessage": "Checkout this awesome tool from BeautifulRising.org {url}", "app.components.ShareButton.emailSubject": "Read about \"{title}\" at BeautifulRising.org", diff --git a/package.json b/package.json index dac9f8a..108cac4 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,16 @@ { - "name": "react-boilerplate", - "version": "3.4.0", - "description": "A highly scalable, offline-first foundation with the best DX and a focus on performance and best practices", + "name": "beautiful-rising", + "version": "3.1.0", + "description": "Beautiful Rising harnesses the insights of changemakers worldwide to help make our movements more strategic, creative and effective.", "repository": { "type": "git", - "url": "git://github.com/react-boilerplate/react-boilerplate.git" + "url": "git://github.com/BeautifulTrouble/beautifulrising-client.git" }, "engines": { "npm": ">=3", "node": ">=5" }, - "author": "Max Stoiber", + "author": "Rapi Castillo, Adrian Carpenter", "license": "MIT", "scripts": { "analyze:clean": "rimraf stats.json",