diff --git a/.browserslistrc b/.browserslistrc index 84c253cc..0e6d135c 100644 --- a/.browserslistrc +++ b/.browserslistrc @@ -1,4 +1,5 @@ -> 1% +> 0.5% +last 2 versions not dead not ie <= 11 not op_mini all diff --git a/src/app/MainRouter.jsx b/src/app/MainRouter.jsx index 66ddb125..4538fea9 100644 --- a/src/app/MainRouter.jsx +++ b/src/app/MainRouter.jsx @@ -6,7 +6,6 @@ import loadable from '@loadable/component'; import { Layout } from 'antd'; import { ConnectedRouter } from 'connected-react-router'; import { Alert, Spin } from '~/adapters/antd'; -import { selectPreference } from '~/features/ui/uiSlice'; import { getNetworkName, useSwitchToChainFromUrl } from '~/features/web3'; import { getCounterPartyChainId, isSupportedChain, isSupportedSideChain } from '~/features/web3/supportedChains'; import Web3ErrorAlert from '~/features/web3/Web3ErrorAlert'; @@ -31,8 +30,6 @@ const TranslationRequest = loadable(() => import('~/pages/TranslationRequest'), const TranslationDetails = loadable(() => import('~/pages/TranslationDetails'), { fallback }); export default function MainRouter() { - const defaultPage = useSelector(selectPreference('page.default')); - return ( @@ -55,7 +52,7 @@ export default function MainRouter() { - + diff --git a/src/assets/gifs/pricing.gif b/src/assets/gifs/pricing.gif new file mode 100644 index 00000000..e76765b0 Binary files /dev/null and b/src/assets/gifs/pricing.gif differ diff --git a/src/assets/images/avatar-linguo-bot-512.png b/src/assets/images/avatar-linguo-bot-512.png index 111beb34..bff6fc93 100644 Binary files a/src/assets/images/avatar-linguo-bot-512.png and b/src/assets/images/avatar-linguo-bot-512.png differ diff --git a/src/assets/images/avatar-linguo-bot.svg b/src/assets/images/avatar-linguo-bot.svg index 11977ac4..7a956557 100644 --- a/src/assets/images/avatar-linguo-bot.svg +++ b/src/assets/images/avatar-linguo-bot.svg @@ -1,172 +1,111 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +linguo new diff --git a/src/assets/images/background-symbols.png b/src/assets/images/background-symbols.png new file mode 100644 index 00000000..1fefcc80 Binary files /dev/null and b/src/assets/images/background-symbols.png differ diff --git a/src/assets/images/hex-community.svg b/src/assets/images/hex-community.svg new file mode 100644 index 00000000..eac72fb1 --- /dev/null +++ b/src/assets/images/hex-community.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/hex-global.svg b/src/assets/images/hex-global.svg new file mode 100644 index 00000000..d6fa2776 --- /dev/null +++ b/src/assets/images/hex-global.svg @@ -0,0 +1,33 @@ + + + + + + + + + + + + + diff --git a/src/assets/images/hex-uptrend.svg b/src/assets/images/hex-uptrend.svg new file mode 100644 index 00000000..66ec141a --- /dev/null +++ b/src/assets/images/hex-uptrend.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + diff --git a/src/assets/images/icon-arrow.svg b/src/assets/images/icon-arrow.svg new file mode 100644 index 00000000..d35d16fd --- /dev/null +++ b/src/assets/images/icon-arrow.svg @@ -0,0 +1,6 @@ + + + diff --git a/src/assets/images/icon-check-circle.svg b/src/assets/images/icon-check-circle.svg new file mode 100644 index 00000000..dfcb24c9 --- /dev/null +++ b/src/assets/images/icon-check-circle.svg @@ -0,0 +1,7 @@ + + + diff --git a/src/assets/images/landing-requester.png b/src/assets/images/landing-requester.png new file mode 100644 index 00000000..5b8e5a58 Binary files /dev/null and b/src/assets/images/landing-requester.png differ diff --git a/src/assets/images/landing-translators.png b/src/assets/images/landing-translators.png new file mode 100644 index 00000000..ed5223de Binary files /dev/null and b/src/assets/images/landing-translators.png differ diff --git a/src/assets/images/logo-linguo-homepage.svg b/src/assets/images/logo-linguo-homepage.svg new file mode 100644 index 00000000..4fbf50a6 --- /dev/null +++ b/src/assets/images/logo-linguo-homepage.svg @@ -0,0 +1,132 @@ +linguo new vertical diff --git a/src/assets/images/logo-linguo-white.svg b/src/assets/images/logo-linguo-white.svg index dcde5f54..632146b5 100644 --- a/src/assets/images/logo-linguo-white.svg +++ b/src/assets/images/logo-linguo-white.svg @@ -1,204 +1,141 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +linguo new white diff --git a/src/assets/images/logo-secured-by-kleros.svg b/src/assets/images/logo-secured-by-kleros.svg new file mode 100644 index 00000000..de8a609e --- /dev/null +++ b/src/assets/images/logo-secured-by-kleros.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + diff --git a/src/features/ui/theme.js b/src/features/ui/theme.js index 977bd7c3..a8682ffd 100644 --- a/src/features/ui/theme.js +++ b/src/features/ui/theme.js @@ -5,6 +5,7 @@ export default { light: '#4A4A4A', lighter: '#8C8C8C', inverted: '#FFFFFF', + secondary: '#999999', }, primary: { default: '#0043C5', @@ -58,6 +59,11 @@ export default { incomplete: '#6C6C6C', finished: '#0043C5', }, + landing: { + secondary: '#00AAFF', + lightBlue: '#F1FAFF', + lightBackground: '#FAFBFC', + }, }, fontSize: { xxl: '1.5rem', diff --git a/src/pages/Home.jsx b/src/pages/Home.jsx deleted file mode 100644 index 9a4dc635..00000000 --- a/src/pages/Home.jsx +++ /dev/null @@ -1,210 +0,0 @@ -import React from 'react'; -import { Titled } from 'react-titled'; -import { useDispatch, useSelector } from 'react-redux'; -import { Link } from 'react-router-dom'; -import { CheckOutlined, CloseOutlined } from '@ant-design/icons'; -import { Col, Layout, Row, Switch, Typography } from 'antd'; -import styled from 'styled-components'; -import * as r from '~/app/routes'; -import LinguoAvatar from '~/assets/images/avatar-linguo-bot.svg'; -import RequestTranslationAvatar from '~/assets/images/avatar-request-translation.svg'; -import ReviewTranslationsAvatar from '~/assets/images/avatar-task-awaiting-review.svg'; -import WorkAsATranslatorAvatar from '~/assets/images/avatar-work-as-a-translator.svg'; -import { selectPreference, setPreference } from '~/features/ui/uiSlice'; -import Button from '~/shared/Button'; -import Spacer from '~/shared/Spacer'; - -export default function Home() { - const dispatch = useDispatch(); - const defaultPage = useSelector(selectPreference('page.default')); - - const createClickHandler = page => checked => { - const value = checked ? page : null; - - dispatch( - setPreference({ - key: 'page.default', - value, - }) - ); - }; - - return ( - 'Linguo by Kleros'}> - - - - - - - Welcome! - - - - - - - My Translations - - - - - } - unCheckedChildren={} - checked={defaultPage === r.REQUESTER_DASHBOARD} - onClick={createClickHandler(r.REQUESTER_DASHBOARD)} - /> - Set as default page for Linguo - - - - - - - Work as a Translator - - - - - } - unCheckedChildren={} - checked={defaultPage === `${r.TRANSLATOR_DASHBOARD}?status=open`} - onClick={createClickHandler(`${r.TRANSLATOR_DASHBOARD}?status=open`)} - /> - Set as default page for Linguo - - - - - - - Review Translations - - - - - } - unCheckedChildren={} - checked={defaultPage === `${r.TRANSLATOR_DASHBOARD}?status=inReview&allTasks=true`} - onClick={createClickHandler(`${r.TRANSLATOR_DASHBOARD}?status=inReview&allTasks=true`)} - /> - Set as default page for Linguo - - - - - - - ); -} - -const StyledLayout = styled(Layout)` - margin: 4rem; - padding: 1rem 4rem 4rem; - max-width: 68rem; - background-color: ${props => props.theme.color.background.light}; - box-shadow: 0 2px 3px ${props => props.theme.color.shadow.default}; - border-radius: 3px; - align-self: stretch; - - @media (max-width: 575.98px) { - margin: 0; - box-shadow: none; - border-radius: 0; - } -`; - -const StyledPageHeader = styled.div` - display: flex; - justify-content: center; - position: relative; - ::before { - content: ''; - display: block; - width: 100%; - border-bottom: 1px solid ${props => props.theme.color.secondary.default}; - position: absolute; - z-index: 0; - top: 5.25rem; - } -`; - -const StyledLinguoAvatar = styled(LinguoAvatar)` - width: 9.25rem; - height: 9.25rem; - position: relative; - z-index: 1; -`; - -const StyledLayoutContent = styled(Layout.Content)``; - -const StyledRow = styled(Row)` - align-items: stretch; -`; - -const StyledTitle = styled(Typography.Title)` - && { - color: ${props => props.theme.color.secondary.default}; - font-size: ${props => props.theme.fontSize.xxl}; - font-weight: ${p => p.theme.fontWeight.semibold}; - text-align: center; - } -`; - -const StyledButton = styled(Button)` - && { - border: 0.3125rem solid ${props => props.theme.color.border.default}; - border-radius: 1.325rem; - font-size: ${props => props.theme.fontSize.xl}; - padding: 1rem; - - ::after, - ::before { - border-radius: 0; - } - - :hover, - :active, - :focus { - border: 0.3125rem solid ${props => props.theme.color.border.default}; - } - - > span { - display: flex; - flex-direction: column; - align-items: center; - height: 100%; - - svg { - width: 8rem; - margin-bottom: 1rem; - } - - .text { - margin-bottom: 1rem; - word-break: normal; - white-space: normal; - } - } - } -`; - -const StyledSwitchWrapper = styled.div` - display: flex; - justify-content: center; - align-items: center; - gap: 1rem; - color: ${p => p.theme.color.text.light}; - font-size: ${p => p.theme.fontSize.sm}; - font-weight: ${p => p.theme.fontWeight.regular}; - - .ant-switch-inner > .anticon { - display: none; - } -`; diff --git a/src/pages/Home/Hero.jsx b/src/pages/Home/Hero.jsx new file mode 100644 index 00000000..aa993aa8 --- /dev/null +++ b/src/pages/Home/Hero.jsx @@ -0,0 +1,132 @@ +import React from 'react'; +import { Typography } from 'antd'; +import styled, { css } from 'styled-components'; +import { Link } from 'react-router-dom'; +import * as r from '~/app/routes'; +import LogoLinguo from '~/assets/images/logo-linguo-homepage.svg'; +import SecuredByKleros from '~/assets/images/logo-secured-by-kleros.svg'; +import SymbolsBackground from '~/assets/images/background-symbols.png'; +import Button from '~/shared/Button'; +import { smallScreenStyle } from './smallScreenStyle'; + +const BUTTONS = [ + { + link: r.REQUESTER_DASHBOARD, + text: 'Request translation', + }, + { + link: `${r.TRANSLATOR_DASHBOARD}?status=open`, + text: 'Work as a translator', + }, + { + link: `${r.TRANSLATOR_DASHBOARD}?status=inReview&allTasks=true`, + text: 'Review translations', + }, +]; + +const Hero = () => ( + + + + The freelance translation platform for Web3 + Hire and make affordable and quality translations. + + {BUTTONS.map(({ text, link }) => ( + + + + ))} + + + + + + + +); + +const Container = styled.div` + background-color: ${props => props.theme.color.landing.lightBlue}; + width: 100%; + padding: 0 2rem; +`; + +const Layout = styled.div` + position: relative; + display: flex; + max-width: 74rem; + margin: 100px auto; + ${smallScreenStyle(css` + flex-direction: column; + align-items: center; + margin-bottom: 0px; + `)}; +`; + +const Symbols = styled.img` + position: absolute; + width: 100%; + bottom: -100px; + ${smallScreenStyle(css` + display: none; + `)}; +`; + +const TextContainer = styled.div` + flex-basis: 60%; + display: flex; + flex-direction: column; + justify-content: space-around; + align-items: flex-start; + ${smallScreenStyle(css` + gap: 1.5rem; + `)} +`; + +const ButtonContainer = styled.div` + display: flex; + gap: 1rem; + ${smallScreenStyle(css` + flex-wrap: wrap; + justify-content: center; + `)}; +`; + +const StyledLinguoLogo = styled(LogoLinguo)` + flex-basis: 40%; + z-index: 1; + ${smallScreenStyle(css` + max-width: 480px; + margin-bottom: 2rem; + `)}; +`; + +const StyledTitle = styled(Typography.Title)` + width: 75%; + ${smallScreenStyle(css` + width: 100%; + `)}; + && { + margin: 0px; + color: ${props => props.theme.color.primary.default}; + font-size: 3rem; + font-weight: ${p => p.theme.fontWeight.semibold}; + text-align: left; + } +`; + +const StyledSubtitle = styled(Typography.Title)` + && { + margin: 0px; + color: ${props => props.theme.color.secondary.default}; + font-size: ${props => props.theme.fontSize.xxl}; + font-weight: ${p => p.theme.fontWeight.semibold}; + text-align: left; + } +`; + +const StyledSecuredByKleros = styled(SecuredByKleros)` + height: 1.5rem; +`; + +export default Hero; diff --git a/src/pages/Home/Pricing.jsx b/src/pages/Home/Pricing.jsx new file mode 100644 index 00000000..1914df89 --- /dev/null +++ b/src/pages/Home/Pricing.jsx @@ -0,0 +1,102 @@ +import React from 'react'; +import styled, { css } from 'styled-components'; +import { smallScreenStyle } from './smallScreenStyle'; +import { Typography } from 'antd'; +import PricingAnimation from '~/assets/gifs/pricing.gif'; + +const USE_CASES = ['Technical', 'Blockchain', 'Data for Machine Learning', 'Articles']; + +const Pricing = () => ( + + + + How Pricing Works? + + Linguo relies on a dynamic auction mechanism to help both parties reach a price they consider fair. + Translation prices start at a set minimum price or $0 and keep increasing to the maximum price decided by the + requester. Translators can pick up the job when the price reaches a level they consider acceptable. + + + + + Specialized translations use cases: + + {USE_CASES.map(usecase => ( + + ))} + And More! + + + + +); + +const Container = styled.div` + width: 100%; + margin-top: 8rem; + padding: 0 2rem; +`; + +const Card = styled.div` + margin: 0 auto; + width: 100%; + max-width: 74rem; +`; + +const HowPricingWorksContainer = styled.div` + border-radius: 18px 18px 0 0; + background-color: ${props => props.theme.color.landing.secondary}; + padding: 3rem; + + > img { + ${smallScreenStyle(css` + display: none; + `)} + margin-top: 2rem; + width: 100%; + } +`; + +const StyledTitle = styled(Typography.Title)` + && { + text-align: left; + font-size: 3rem; + font-weight: ${p => p.theme.fontWeight.semibold}; + color: ${props => props.theme.color.text.inverted}; + } +`; + +const StyledBody = styled(Typography.Text)` + && { + text-align: left; + color: ${props => props.theme.color.text.inverted}; + } +`; + +const SpecializedTranslationsContainer = styled.div` + border-radius: 0 0 18px 18px; + background-color: ${props => props.theme.color.primary.default}; + padding: 3rem; +`; + +const LabelContainer = styled.div` + margin-top: 2rem; + display: flex; + flex-wrap: wrap; + gap: 0.5rem; +`; + +const Label = styled(Typography.Text)` + background-color: ${props => props.theme.color.landing.lightBlue}; + border-radius: 300px; + padding: 0.5rem 1rem; + color: ${props => props.theme.color.primary.default}; + text-align: center; +`; + +const LabelNoStyle = styled(Typography.Text)` + color: ${props => props.theme.color.text.inverted}; + padding: 0.5rem 1rem; +`; + +export default Pricing; diff --git a/src/pages/Home/Requesters.jsx b/src/pages/Home/Requesters.jsx new file mode 100644 index 00000000..c5dad20c --- /dev/null +++ b/src/pages/Home/Requesters.jsx @@ -0,0 +1,94 @@ +import React from 'react'; +import styled, { css } from 'styled-components'; +import { smallScreenStyle } from './smallScreenStyle'; +import * as r from '~/app/routes'; +import RequesterBackground from '~/assets/images/landing-requester.png'; +import AvatarRequestTranslation from '~/assets/images/avatar-request-translation.svg'; +import TitleWithIcon from './TitleWithIcon'; +import TextWithCheck from './TextWithCheck'; +import StartNowCard from './StartNowCard'; + +const SENTENCES = [ + 'Get documents translated without hassle.', + 'Upload your files and be notified when it is completed.', + 'Perfect quality translation, at a fair price each time.', + 'No need to know the languages you are translating to. Other translators check the quality of the translation for you.', + 'No need to know how much to pay for a translation. A reverse auction mechanism allows you to get the best price.', +]; + +const Requesters = () => ( + + + + + + + {SENTENCES.map(sentence => ( + + ))} + + + + + + + +); + +const Container = styled.div` + width: 100%; + margin-top: 8rem; + padding: 0 2rem; +`; + +const Layout = styled.div` + margin: 0 auto; + width: 100%; + max-width: 74rem; + display: flex; + flex-direction: column; + gap: 2rem; +`; + +const TextAndImageLayout = styled.div` + width: 100%; + display: flex; + border-radius: 18px; + overflow: hidden; + ${smallScreenStyle(css` + flex-direction: column; + `)} +`; + +const TextContainer = styled.div` + flex: 50%; + ${smallScreenStyle(css` + height: auto; + `)} + background-color: ${props => props.theme.color.primary.default}; + padding: 2rem; +`; + +const SentenceContainer = styled.div` + margin-top: 3.5rem; + display: flex; + flex-direction: column; + gap: 1.5rem; +`; + +const ImageContainer = styled.div` + flex: 50%; + min-height: 734px; + background-image: url(${RequesterBackground}); + background-position: 55% 30%; + background-size: cover; + ${smallScreenStyle(css` + min-height: 400px; + `)} +`; + +export default Requesters; diff --git a/src/pages/Home/Sash.jsx b/src/pages/Home/Sash.jsx new file mode 100644 index 00000000..30a4deb3 --- /dev/null +++ b/src/pages/Home/Sash.jsx @@ -0,0 +1,113 @@ +import React from 'react'; +import styled from 'styled-components'; +import t from 'prop-types'; +import { Typography } from 'antd'; +import HexUpTrend from '~/assets/images/hex-uptrend.svg'; +import HexGlobal from '~/assets/images/hex-global.svg'; +import HexCommunity from '~/assets/images/hex-community.svg'; +import Card from '~/shared/Card'; + +const CARDS = [ + { + title: 'Affordable', + text: 'An innovative mechanism ensuring fair prices for all parties.', + icon: HexUpTrend, + }, + { + title: 'Reliable', + text: + 'Translators can start working immediately after making a deposit. ' + + 'This gives them the incentive to only accept gigs they know they can ' + + 'complete on time.', + icon: HexGlobal, + }, + { + title: 'High Quality', + text: + 'Translations get reviewed by multiple people ensuring a high quality ' + + 'of output. Any disputes are efficiently resolved by Kleros.', + icon: HexCommunity, + }, +]; + +const Sash = () => ( + + Why Translate with Linguo? + + {CARDS.map(card => ( + + ))} + + +); + +const SashCard = ({ icon: Icon, title, text, className }) => ( + + + + {text} + + +); + +SashCard.propTypes = { + title: t.node.isRequired, + icon: t.func.isRequired, + text: t.string.isRequired, + className: t.node, +}; + +const Container = styled.div` + width: 100%; + margin-top: 8rem; + padding: 0 2rem; +`; + +const Layout = styled.div` + margin: 6rem auto 0px auto; + width: 100%; + max-width: 74rem; + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 1rem; +`; + +const StyledTitle = styled(Typography.Title)` + && { + margin: 0px; + color: ${props => props.theme.color.primary.default}; + font-size: 3rem; + font-weight: ${p => p.theme.fontWeight.semibold}; + text-align: center; + } +`; + +const StyledCard = styled(Card)` + width: 22rem; + border-radius: 18px; + box-shadow: 0 2px 3px rgb(0 0 0 / 15%); + .card-header { + border-radius: 18px 18px 0 0; + } + .card-header-title { + font-size: ${props => props.theme.fontSize.xxl}; + } +`; + +const SashCardLayout = styled.div` + display: flex; + flex-direction: column; + align-items: center; + padding: 1.5rem 0; + gap: 1.5rem; +`; + +const SashCardBody = styled(Typography.Text)` + && { + text-align: center; + color: ${props => props.theme.color.text.secondary}; + } +`; + +export default Sash; diff --git a/src/pages/Home/StartNowCard.jsx b/src/pages/Home/StartNowCard.jsx new file mode 100644 index 00000000..cef4525c --- /dev/null +++ b/src/pages/Home/StartNowCard.jsx @@ -0,0 +1,109 @@ +import React from 'react'; +import styled from 'styled-components'; +import t from 'prop-types'; +import LinguoLogo from '~/assets/images/avatar-linguo-bot.svg'; +import ArrowIcon from '~/assets/images/icon-arrow.svg'; +import { Typography } from 'antd'; +import Button from '~/shared/Button'; +import { Link } from 'react-router-dom'; + +const StartNowCard = ({ title, buttonText, buttonURL }) => ( + + + + +); + +StartNowCard.propTypes = { + title: t.string.isRequired, + buttonText: t.string.isRequired, + buttonURL: t.string.isRequired, +}; + +const Card = styled.div` + width: 100%; + display: flex; + flex-wrap: wrap; + justify-content: space-between; + align-items: center; + padding: 1rem 2rem; + gap: 1rem; + background-color: ${props => props.theme.color.landing.secondary}; + border-radius: 18px; + + .linguo-with-title { + display: flex; + flex-wrap: wrap; + align-items: center; + gap: 0.5rem; + > svg { + height: 3rem; + flex-shrink: 0; + } + } + .learn-more-and-button { + display: flex; + gap: 1.5rem; + align-items: center; + flex-wrap: wrap; + .learn-more-and-arrow { + display: flex; + gap: 0.25rem; + align-items: center; + > svg { + flex-shrink: 0; + width: 0.8rem; + } + } + } +`; + +const LinguoWithTitle = ({ title }) => ( + + + {title} + +); + +LinguoWithTitle.propTypes = { + title: t.string.isRequired, +}; + +const LearnMoreAndButton = ({ buttonText, buttonURL }) => ( + + + + Learn more + + + + + + + +); + +LearnMoreAndButton.propTypes = { + buttonText: t.string.isRequired, + buttonURL: t.string.isRequired, +}; + +const Title = styled(Typography.Title)` + && { + margin: 0px; + color: ${props => props.theme.color.text.inverted}; + font-size: ${props => props.theme.fontSize.xxl}; + font-weight: ${p => p.theme.fontWeight.bold}; + text-align: left; + } +`; + +const Text = styled(Typography.Text)` + && { + font-size: ${props => props.theme.fontSize.md}; + color: ${props => props.theme.color.text.inverted}; + weight: ${props => props.theme.fontWeight.regular}; + } +`; + +export default StartNowCard; diff --git a/src/pages/Home/TextWithCheck.jsx b/src/pages/Home/TextWithCheck.jsx new file mode 100644 index 00000000..2095ba73 --- /dev/null +++ b/src/pages/Home/TextWithCheck.jsx @@ -0,0 +1,37 @@ +import React from 'react'; +import styled from 'styled-components'; +import t from 'prop-types'; +import { Typography } from 'antd'; +import CheckIcon from '~/assets/images/icon-check-circle.svg'; + +const TitleWithIcon = ({ text, className }) => ( + + + {text} + +); + +TitleWithIcon.propTypes = { + text: t.string.isRequired, + className: t.string, +}; + +const Container = styled.div` + display: flex; + gap: 1rem; + align-items: center; + > svg { + fill: white; + height: 1.5rem; + flex-shrink: 0; + } +`; + +const StyledText = styled(Typography.Text)` + && { + font-size: ${props => props.theme.fontSize.xxl}; + color: ${props => props.theme.color.text.inverted}; + } +`; + +export default TitleWithIcon; diff --git a/src/pages/Home/TitleWithIcon.jsx b/src/pages/Home/TitleWithIcon.jsx new file mode 100644 index 00000000..7bc5e089 --- /dev/null +++ b/src/pages/Home/TitleWithIcon.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import styled, { css } from 'styled-components'; +import { smallScreenStyle } from './smallScreenStyle'; +import t from 'prop-types'; +import { Typography } from 'antd'; + +const TitleWithIcon = ({ title, icon: Icon }) => ( + + + {title} + +); + +TitleWithIcon.propTypes = { + title: t.string.isRequired, + icon: t.func.isRequired, + className: t.string, +}; + +const Container = styled.div` + display: flex; + gap: 1.5rem; + align-items: center; + > svg { + height: 5rem; + flex-shrink: 0; + } + ${smallScreenStyle(css` + flex-wrap: wrap; + justify-content: center; + `)} +`; + +const StyledTitle = styled(Typography.Title)` + && { + margin: 0; + font-size: 3rem; + font-weight: ${p => p.theme.fontWeight.semibold}; + color: ${props => props.theme.color.text.inverted}; + } +`; + +export default TitleWithIcon; diff --git a/src/pages/Home/Translators.jsx b/src/pages/Home/Translators.jsx new file mode 100644 index 00000000..90e8a978 --- /dev/null +++ b/src/pages/Home/Translators.jsx @@ -0,0 +1,198 @@ +import React from 'react'; +import t from 'prop-types'; +import styled, { css } from 'styled-components'; +import { Typography } from 'antd'; +import * as r from '~/app/routes'; +import { smallScreenStyle } from './smallScreenStyle'; +import TranslatorBackground from '~/assets/images/landing-translators.png'; +import AvatarTaskAssigned from '~/assets/images/avatar-task-assigned.svg'; +import TitleWithIcon from './TitleWithIcon'; +import TextWithCheck from './TextWithCheck'; +import StartNowCard from './StartNowCard'; + +const SENTENCES = [ + 'Earn by translating documents.', + "Earn by reviewing other people's tranlations.", + 'Flexibility to chose what you work on.', +]; + +const CARDS = [ + { + title: 'Start working immediately', + body: "Pick a request, pay the deposit and get started. No long tests, processes or interviews. You're in control.", + }, + { + title: 'No fees or hidden costs', + body: "You keep 100% of your work. Linguo doesn't take a cut.", + }, + { + title: 'Multiple ways to earn', + body: 'Use your skills to make translations yourself or review translations made by others.', + }, + { + title: 'Guaranteed payment', + body: 'Once your translation is accepted, you will automatically receive your payment.', + }, +]; + +const Translators = () => ( + + + + + + + {SENTENCES.map(sentence => ( + + ))} + + + + + + + {CARDS.map(card => ( + + ))} + + + + + +); + +const Card = ({ title, body }) => ( + + {title} + + {body} + +); + +Card.propTypes = { + title: t.string.isRequired, + body: t.string.isRequired, +}; + +const BlueCard = styled.div` + width: 18rem; + border-radius: 18px; + background-color: ${props => props.theme.color.primary.default}; + padding: 1rem 1.5rem; + + ${smallScreenStyle(css` + flex: 49%; + `)} +`; + +const CardTitle = styled(Typography.Title)` + && { + margin: 0px; + color: ${props => props.theme.color.text.inverted}; + font-size: 2rem; + font-weight: ${p => p.theme.fontWeight.semibold}; + text-align: left; + } +`; + +const CardBody = styled(Typography.Text)` + && { + text-align: left; + font-size: ${props => props.theme.fontSize.xl}; + color: ${props => props.theme.color.text.inverted}; + } +`; + +const CardSeparator = styled.hr` + margin: 16px 0; + width: 30%; + height: 0px; + background-color: ${props => props.theme.color.landing.secondary}; + border-color: ${props => props.theme.color.landing.secondary}; + border-style: solid; + border-width: 3px; + border-radius: 300px; + margin-left: 0px; +`; + +const BottomSection = styled.div` + position: relative; + bottom: 6rem; + z-index: 2; + ${smallScreenStyle(css` + bottom: 1.75rem; + `)} +`; + +const CardContainer = styled.div` + display: flex; + justify-content: space-between; + margin-bottom: 2rem; + ${smallScreenStyle(css` + flex-wrap: wrap; + gap: 1rem; + `)} +`; + +const Container = styled.div` + width: 100%; + margin-top: 8rem; + padding: 0 2rem; +`; + +const Layout = styled.div` + margin: 0 auto; + width: 100%; + max-width: 74rem; +`; + +const ImageLayout = styled.div` + position: relative; + width: 100%; + border-radius: 18px; + overflow: hidden; +`; + +const TextContainer = styled.div` + position: relative; + z-index: 1; + height: 600px; + background-image: linear-gradient( + 99.71deg, + ${props => props.theme.color.primary.default} 0%, + rgba(0, 170, 255, 0) 67.49% + ); + padding: 2rem; + + ${smallScreenStyle(css` + min-height: 600px; + height: auto; + background-image: linear-gradient( + 128.74deg, + ${props => props.theme.color.primary.default} 37.29%, + rgba(0, 170, 255, 0) 98.43% + ); + `)} +`; + +const SentenceContainer = styled.div` + margin-top: 3.5rem; + display: flex; + flex-direction: column; + gap: 1.5rem; +`; + +const ImageContainer = styled.div` + position: absolute; + top: 0; + width: 100%; + height: 100%; + background-image: url(${TranslatorBackground}); + background-position: 65% 100%; +`; + +export default Translators; diff --git a/src/pages/Home/index.jsx b/src/pages/Home/index.jsx new file mode 100644 index 00000000..02693db1 --- /dev/null +++ b/src/pages/Home/index.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import styled from 'styled-components'; +import { Titled } from 'react-titled'; +import Hero from './Hero'; +import Sash from './Sash'; +import Pricing from './Pricing'; +import Requesters from './Requesters'; +import Translators from './Translators'; + +export default function Home() { + return ( + + + + + + + + + + ); +} + +const getTitle = () => 'Linguo by Kleros'; + +const Container = styled.div` + width: 100%; + background-color: ${props => props.theme.color.landing.lightBackground}; + display: flex; + flex-direction: column; + align-items: center; +`; diff --git a/src/pages/Home/smallScreenStyle.jsx b/src/pages/Home/smallScreenStyle.jsx new file mode 100644 index 00000000..7bd2e1be --- /dev/null +++ b/src/pages/Home/smallScreenStyle.jsx @@ -0,0 +1,7 @@ +import { css } from 'styled-components'; + +export const smallScreenStyle = style => css` + @media (max-width: 1250px) { + ${style} + } +`; diff --git a/src/shared/Menu.jsx b/src/shared/Menu.jsx index fe798e5e..2b02c0cb 100644 --- a/src/shared/Menu.jsx +++ b/src/shared/Menu.jsx @@ -37,6 +37,9 @@ export function MainMenu() { } const menuItems = [ + + Home + , Request Translations , @@ -47,7 +50,24 @@ const menuItems = [ search: 'status=open', }} > - Work as a Translator + Find work + + , + + + Tutorial + + , + + FAQ + , + + + Contact us , ]; diff --git a/src/shared/Navbar.jsx b/src/shared/Navbar.jsx index a4c02b0d..52410814 100644 --- a/src/shared/Navbar.jsx +++ b/src/shared/Navbar.jsx @@ -15,7 +15,6 @@ export default function Navbar() { - by Kleros