frontend/src/views/learn.js (368 lines of code) (raw):
import React, { useState } from 'react';
import { Link } from '@reach/router';
import Popup from 'reactjs-popup';
import { FormattedMessage } from 'react-intl';
import messages from './messages';
import { useSetTitleTag } from '../hooks/UseMetaTags';
import { TopBar } from '../components/header/topBar';
import {
PlayIcon,
CloseIcon,
PolygonIcon,
SelectProject,
SelectTask,
ValidationIcon,
HumanProcessingIcon,
WorldNodesIcon,
} from '../components/svgIcons';
import CommunityLogo from '../assets/img/icons/community.jpg';
import EmergencyMappingLogo from '../assets/img/icons/emergency-mapping.jpg';
import TechnicalLogo from '../assets/img/icons/technical.jpg';
import LearnOSMLogo from '../assets/img/learn-osm-logo.svg';
import QuickstartLogo from '../assets/img/info-logo.svg';
const LearnNav = ({ sections, section, setSection }) => {
useSetTitleTag('Learn');
return (
<div className="w-50 w-100-m">
<ul className="pa0 ma0 list bg-tan dib">
{sections.map((s) => (
<li
className={`f5 dib mh3 pt3 link pointer no-underline ${
section === s ? 'bb b--blue-dark bw1 pb1' : 'pb3'
}`}
onClick={() => setSection(s)}
key={s}
>
<FormattedMessage {...messages[s]} />
</li>
))}
</ul>
</div>
);
};
const Intro = ({ section, messagesObjs }) => (
<div className="w-100 cf">
<div className="w-100 cf">
<div className="w-30-ns w-100 fl">
<p className="barlow-condensed f2 ttu b fw6">
{<FormattedMessage {...messages[section]} />}
</p>
</div>
<div className="w-70-ns w-100 fr lh-copy f4">
<p className="b">{<FormattedMessage {...messages[messagesObjs.intro]} />}</p>
<p className="f5">{<FormattedMessage {...messages[messagesObjs.description]} />}</p>
</div>
</div>
</div>
);
const Steps = ({ items }) => (
<div className="w-100 cf relative">
{items.map((item, i) => (
<div className="w-third-ns w-100 fl pa2 z-2 bg-white" key={i}>
<div className="shadow-1 pa3">
{item.img}
<p className="blue-dark b f4 pt0">
<span className="mr1">{i + 1}.</span>
{item.titleLink ? (
<Link to={item.titleLink} className="link no-underline blue-dark">
<FormattedMessage {...messages[`${item.message}Title`]} />
</Link>
) : (
<FormattedMessage {...messages[`${item.message}Title`]} />
)}
</p>
<p className="blue-grey lh-title f5">
<FormattedMessage {...messages[`${item.message}Description`]} values={item.values} />
</p>
</div>
</div>
))}
<div style={{ height: '60%' }} className="w-100 bg-tan relative bottom--2 right--2 z-1 "></div>
</div>
);
const Manuals = ({ contents }) => (
<div className="mv3">
<h3 className="f2 ttu barlow-condensed fw6">
<FormattedMessage {...messages.learnManualsTitle} />
</h3>
<div className="w-100 cf">
{contents.map((content, i) => (
<div key={i} style={{ height: '20rem' }} className="w-25-l w-third-m w-100 fl ph2">
<div className="shadow-4">
<a
className="no-underline"
rel="noopener noreferrer"
target="_blank"
href={content.url}
>
<div
className="bg-tan w-100 tc h4"
style={{
background: `#f0efef url(${content.img}) no-repeat center`,
backgroundSize: '55%',
}}
></div>
<div className="pa3" style={{ height: '12rem' }}>
<p className="fw7 f4 mt0 blue-dark">
<FormattedMessage {...messages[`${content.message}Title`]} />
</p>
<p className="blue-grey lh-title f5">
<FormattedMessage {...messages[`${content.message}Description`]} />
</p>
</div>
</a>
</div>
</div>
))}
</div>
</div>
);
const Videos = ({ contents }) => {
const [activeVideo, setActiveVideo] = useState(null);
const iframeStyle = {
border: 0,
height: '100%',
left: 0,
position: 'absolute',
top: 0,
width: '100%',
};
return (
<div className="mv3">
<h3 className="f2 ttu barlow-condensed fw6">
<FormattedMessage {...messages.learnVideosTitle} />
</h3>
<div className="w-100 cf">
{contents.map((content, i) => {
return (
<div className="w-25-l w-third-m w-100 fl ph2" key={i}>
<div className="shadow-4 pointer" onClick={() => setActiveVideo(content)}>
<div
className="bg-tan w-100 tc h5-l h4"
style={{
background: `linear-gradient(rgba(0, 0, 0, 0.3) 100%, rgba(0, 0, 0, 0.3) 100%), url(https://img.youtube.com/vi/${content.youTubeId}/hqdefault.jpg) no-repeat center`,
backgroundSize: 'cover',
}}
>
<PlayIcon className="white pv5-l pv0 mv3" height="6rem" />
</div>
<div className="pa3 db" style={{ height: '8rem' }}>
<p className="fw7 f4 mt0 blue-dark">
<FormattedMessage {...messages[`${content.message}Title`]} />
</p>
<p className="blue-grey lh-title f5 db">
<FormattedMessage {...messages[`${content.message}Description`]} />
</p>
</div>
</div>
</div>
);
})}
</div>
{activeVideo && (
<Popup
modal
open
closeOnEscape={true}
closeOnDocumentClick={true}
onClose={() => setActiveVideo(null)}
className="video-popup"
>
{(close) => (
<div className="pa3 blue-dark">
<CloseIcon
className="fr pointer"
width="18px"
height="18px"
onClick={() => close()}
/>
<h3 className="mt0 f4">
<FormattedMessage {...messages[`${activeVideo.message}Title`]} />
</h3>
<div className="tc overflow-hidden relative" style={{ paddingTop: '56.25%' }}>
<iframe
title="videotutorial"
style={iframeStyle}
src={`https://www.youtube.com/embed/${activeVideo.youTubeId}?autoplay=1`}
frameBorder="0"
allow="accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen="allowFullScreen"
></iframe>
</div>
</div>
)}
</Popup>
)}
</div>
);
};
const LearnToManage = ({ section }) => {
const messagesObjs = {
intro: 'learnManageIntro',
description: 'learnManageDescription',
};
const items = [
{
message: 'learnManageStepJoin',
img: <img className="w-35" src={CommunityLogo} alt={'join a community'} />,
},
{
message: 'learnManageStepCreate',
img: <img className="w-35" src={EmergencyMappingLogo} alt={'create project'} />,
},
{
message: 'learnManageStepData',
img: <img className="w-35" src={TechnicalLogo} alt={'use the data'} />,
values: {
exportToolLink: (
<a className="link red fw5" href="https://export.hotosm.org/">
HOT Export Tool
</a>
),
overpassLink: (
<a className="link red fw5" href="https://dev.overpass-api.de/overpass-doc/en">
Overpass API
</a>
),
},
},
];
const tutorials = [
{
message: 'learnOSMTutorial',
url: 'https://learnosm.org/en/coordination/tm-admin/',
img: LearnOSMLogo,
},
];
return (
<div className="w-100">
<Intro section={section} messagesObjs={messagesObjs} />
<Steps items={items} />
<Manuals contents={tutorials} />
</div>
);
};
const LearnToValidate = ({ section }) => {
const messagesObjs = {
intro: 'learnValidateIntro',
description: 'learnValidateDescription',
};
const items = [
{ message: 'learnValidateStepIdentify', img: <ValidationIcon className="red" /> },
{
message: 'learnValidateStepBuild',
img: <HumanProcessingIcon className="red" />,
values: {
taggingLink: (
<a className="link red fw5" href="https://wiki.openstreetmap.org/wiki/Map_Features">
<FormattedMessage {...messages.osmTaggingSchema} />
</a>
),
},
},
{
message: 'learnValidateStepCollaborate',
img: <WorldNodesIcon className="red" />,
values: {
mailingListLink: (
<a className="link red fw5" href="https://wiki.openstreetmap.org/wiki/Mailing_lists">
<FormattedMessage {...messages.mailingLists} />
</a>
),
forumLink: (
<a className="link red fw5" href="https://forum.openstreetmap.org/">
<FormattedMessage {...messages.forum} />
</a>
),
},
},
];
const videos = [
{
message: 'learnValidateHowToVideo',
youTubeId: 'frVwlJn4tdI',
},
{
message: 'learnValidateTrainingVideo',
youTubeId: 'YQ18XfRM6d4',
},
];
return (
<div className="w-100">
<Intro section={section} messagesObjs={messagesObjs} />
<Steps items={items} />
<p className="w-60 lh-copy f5 left mb5">
{<FormattedMessage {...messages.learnValidateNote} />}
</p>
<Videos contents={videos} />
</div>
);
};
const LearnToMap = ({ section }) => {
const messagesObjs = {
intro: 'learnMapIntro',
description: 'learnMapDescription',
};
const items = [
{
message: 'learnMapStepSelectProject',
img: <SelectProject className="red" />,
titleLink: '/explore',
},
{ message: 'learnMapStepSelectTask', img: <SelectTask className="red" /> },
{ message: 'learnMapStepMapOSM', img: <PolygonIcon className="red" /> },
];
const tutorials = [
{
message: 'learnQuickStartTutorial',
url: 'learn/quickstart',
img: QuickstartLogo,
},
{
message: 'learnTMManualTutorial',
url: 'https://learnosm.org/en/coordination/tm-user/',
img: LearnOSMLogo,
},
{
message: 'learnOSMStepByStepTutorial',
url: 'https://learnosm.org/en/beginner/',
img: LearnOSMLogo,
},
];
const videos = [
{
message: 'learnSignUp',
youTubeId: 'wqQdDgjBOvY',
},
{
message: 'learnMapBuildings',
youTubeId: 'nswUcgMfKTM',
},
{
message: 'learnMapRoads',
youTubeId: 'NzZWur1YG1k',
},
];
return (
<div className="w-100 cf">
<Intro section={section} messagesObjs={messagesObjs} />
<Steps items={items} />
<Manuals contents={tutorials} />
<Videos contents={videos} />
</div>
);
};
const getSection = (section, sections) => {
switch (section) {
case sections[0]:
return <LearnToMap section={section} />;
case sections[1]:
return <LearnToValidate section={section} />;
case sections[2]:
return <LearnToManage section={section} />;
default:
return;
}
};
export const LearnPage = () => {
const sections = ['learnMapTitle', 'learnValidateTitle', 'learnManageTitle'];
const [section, setSection] = useState(sections[0]);
return (
<div className="pt180 pull-center blue-dark">
<TopBar pageName={<FormattedMessage {...messages.learn} />} />
<div className="ph6-l ph4-m ph2">
<LearnNav sections={sections} section={section} setSection={setSection} />
<div className="w-100 mt3">{getSection(section, sections)}</div>
</div>
</div>
);
};