mini challenges grid on desktop
This commit is contained in:
parent
73e7ada0c3
commit
76bdb473e9
@ -1,20 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="theme-color" content="#000000" />
|
||||
<head>
|
||||
<meta charset="utf-8"/>
|
||||
<link rel="icon" href="%PUBLIC_URL%/favicon.ico"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||
<meta name="theme-color" content="#000000"/>
|
||||
<meta
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
name="description"
|
||||
content="Web site created using create-react-app"
|
||||
/>
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
|
||||
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png"/>
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is installed on a
|
||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json"/>
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
@ -24,20 +24,20 @@
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
<title>Gonito</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>You need to enable JavaScript to run this app.</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
||||
|
@ -4,7 +4,7 @@ import {Body, H3} from "../../utils/fonts";
|
||||
import styled from "styled-components";
|
||||
import IconLabel from "./IconLabel";
|
||||
import {Link} from "react-router-dom";
|
||||
import {CHALLENGE_PAGE} from "../../utils/globals";
|
||||
import {CHALLENGE_PAGE, MINI_DESCRIPTION_LENGTH} from "../../utils/globals";
|
||||
|
||||
const ChallengeStyle = styled(FlexColumn)`
|
||||
padding: 12px;
|
||||
@ -14,10 +14,6 @@ const ChallengeStyle = styled(FlexColumn)`
|
||||
position: relative;
|
||||
max-width: 420px;
|
||||
|
||||
p {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
* {
|
||||
cursor: pointer;
|
||||
}
|
||||
@ -26,12 +22,19 @@ const ChallengeStyle = styled(FlexColumn)`
|
||||
transform: scale(1.05);
|
||||
}
|
||||
|
||||
a {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
article {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
align-items: flex-start;
|
||||
|
||||
p {
|
||||
width: 80%;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: ${({theme}) => theme.overMobile}) {
|
||||
width: 360px;
|
||||
padding: 20px;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -54,43 +57,43 @@ const IconsGrid = styled(Grid)`
|
||||
`;
|
||||
|
||||
const MiniChallenge = (props) => {
|
||||
|
||||
const renderDescription = (description) => {
|
||||
if (description.length <= 200)
|
||||
if (description.length <= MINI_DESCRIPTION_LENGTH)
|
||||
return description;
|
||||
return `${description.slice(0, 100)}...`
|
||||
return `${description.slice(0, MINI_DESCRIPTION_LENGTH)}...`
|
||||
}
|
||||
|
||||
return (
|
||||
<ChallengeStyle as='article' alignmentX='flex-start'>
|
||||
<FlexRow margin='0 0 14px 0' gap='12px' width='100%' alignmentX='space-between'>
|
||||
<H3 as='h3' width='85%'>
|
||||
{props.title}
|
||||
</H3>
|
||||
<IconLabel type={props.type} size='30px'/>
|
||||
</FlexRow>
|
||||
<Line/>
|
||||
<Body as='p' margin='0 0 14px 0'>
|
||||
{props.description ? renderDescription(props.description) : 'xxx'}
|
||||
</Body>
|
||||
<IconsGrid>
|
||||
<IconLabel size='24px' gap='8px' type='metric'>
|
||||
{props.metric ? props.metric : 'xxx'}
|
||||
</IconLabel>
|
||||
<IconLabel size='24px' gap='8px' type='bestScore'>
|
||||
{props.bestScore ? props.bestScore : 'xxx'}
|
||||
</IconLabel>
|
||||
<IconLabel size='24px' gap='8px' type='deadline'>
|
||||
{props.deadline ? props.deadline.slice(0, 10) : 'xxx'}
|
||||
</IconLabel>
|
||||
<IconLabel size='24px' gap='8px' type='baseline'>
|
||||
{props.baseline ? props.baseline : 'xxx'}
|
||||
</IconLabel>
|
||||
{props.prize ? <IconLabel size='24px' gap='8px' type='prize'>
|
||||
{props.prize}
|
||||
</IconLabel> : ''}
|
||||
</IconsGrid>
|
||||
<Container as={Link} to={`${CHALLENGE_PAGE}/${props.name}`}/>
|
||||
<ChallengeStyle as={Link} to={`${CHALLENGE_PAGE}/${props.name}`}>
|
||||
<FlexColumn as='article'>
|
||||
<FlexRow margin='0 0 14px 0' gap='12px' width='100%' alignmentX='space-between'>
|
||||
<H3 as='h3' width='85%'>
|
||||
{props.title}
|
||||
</H3>
|
||||
{props.type ? <IconLabel type={props.type} size='30px'/> : 'xxx'}
|
||||
</FlexRow>
|
||||
<Line/>
|
||||
<Body as='p' margin='0 0 14px 0'>
|
||||
{props.description ? renderDescription(props.description) : 'xxx'}
|
||||
</Body>
|
||||
<IconsGrid>
|
||||
<IconLabel size='24px' gap='8px' type='metric'>
|
||||
{props.metric ? props.metric : 'xxx'}
|
||||
</IconLabel>
|
||||
<IconLabel size='24px' gap='8px' type='bestScore'>
|
||||
{props.bestScore ? props.bestScore : 'xxx'}
|
||||
</IconLabel>
|
||||
<IconLabel size='24px' gap='8px' type='deadline'>
|
||||
{props.deadline ? props.deadline.slice(0, 10) : 'xxx'}
|
||||
</IconLabel>
|
||||
<IconLabel size='24px' gap='8px' type='baseline'>
|
||||
{props.baseline ? props.baseline : 'xxx'}
|
||||
</IconLabel>
|
||||
{props.prize ? <IconLabel size='24px' gap='8px' type='prize'>
|
||||
{props.prize}
|
||||
</IconLabel> : ''}
|
||||
</IconsGrid>
|
||||
</FlexColumn>
|
||||
</ChallengeStyle>
|
||||
);
|
||||
}
|
||||
|
@ -5,26 +5,46 @@ import polygon from '../../assets/polygon.svg';
|
||||
import styled from "styled-components";
|
||||
import theme from "../../utils/theme";
|
||||
|
||||
const PagerStyle = styled(FlexRow)`
|
||||
gap: 14px;
|
||||
|
||||
@media (min-width: ${({theme}) => theme.overMobile}) {
|
||||
gap: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
const LeftArrow = styled(Svg)`
|
||||
background-color: ${({backgroundColor}) => backgroundColor};
|
||||
cursor: ${({backgroundColor}) => (backgroundColor === 'transparent') ? 'auto' : 'pointer'};
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
@media (min-width: ${({theme}) => theme.overMobile}) {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
`;
|
||||
|
||||
const RightArrow = styled(Svg)`
|
||||
display: ${({display}) => display};
|
||||
background-color: ${({backgroundColor}) => backgroundColor};
|
||||
transform: rotate(180deg);
|
||||
cursor: ${({backgroundColor}) => (backgroundColor === 'transparent') ? 'auto' : 'pointer'};
|
||||
width: 10px;
|
||||
height: 10px;
|
||||
@media (min-width: ${({theme}) => theme.overMobile}) {
|
||||
width: 12px;
|
||||
height: 12px;
|
||||
}
|
||||
`;
|
||||
|
||||
const Pager = (props) => {
|
||||
return (
|
||||
<FlexRow gap='14px'>
|
||||
<LeftArrow as='button' src={polygon} onClick={props.previousPage}
|
||||
<PagerStyle>
|
||||
<LeftArrow as='button' src={polygon} onClick={props.previousPage} size='cover'
|
||||
backgroundColor={(props.pageNr === 1) ? 'transparent' : theme.colors.dark}/>
|
||||
<CircleNumber number={props.pageNr}/>
|
||||
<RightArrow as='button' src={polygon} onClick={props.nextPage}
|
||||
<RightArrow as='button' src={polygon} onClick={props.nextPage} size='cover'
|
||||
backgroundColor={(props.pageNr === props.pages) ? 'transparent' : theme.colors.dark}/>
|
||||
</FlexRow>
|
||||
</PagerStyle>
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -19,6 +19,10 @@ const FooterStyle = styled(FlexRow)`
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@media (min-width: ${({theme}) => theme.overMobile}) {
|
||||
height: 72px;
|
||||
}
|
||||
`;
|
||||
|
||||
const Footer = () => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import {H1} from "../../utils/fonts";
|
||||
import {FlexColumn, Grid} from "../../utils/containers";
|
||||
import {FlexColumn} from "../../utils/containers";
|
||||
import Search from "../../components/elements/Search";
|
||||
import Pager from "../../components/elements/Pager";
|
||||
import {ELEMENTS_PER_PAGE} from "../../utils/globals";
|
||||
@ -8,6 +8,8 @@ import FiltersMenu from "../../components/elements/FiltersMenu";
|
||||
import _searchQueryHandler from "./_searchQueryHandler";
|
||||
import _challengesRequest from "./_challengesRequest";
|
||||
import _renderChallenges from "./_renderChallenges";
|
||||
import Media from "react-media";
|
||||
import theme from "../../utils/theme";
|
||||
|
||||
const Challenges = () => {
|
||||
const [pageNr, setPageNr] = React.useState(1);
|
||||
@ -74,29 +76,59 @@ const Challenges = () => {
|
||||
setFiltersMenu(newFiltersMenu);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<FiltersMenu translateX={filtersMenu ? '0' : '100vw'} opacity={filtersMenu ? '1' : '0'}
|
||||
toggleFiltersMenu={toggleFiltersMenu}
|
||||
sortByHandler={sortByHandler} statusHandler={statusHandler}
|
||||
challengeTypeHandler={challengeTypeHandler} commercialHandler={commercialHandler}
|
||||
sortBy={sortBy} status={status} challengeType={challengeType} commercial={commercial}/>
|
||||
const mobileRender = () => {
|
||||
return (
|
||||
<>
|
||||
<FiltersMenu translateX={filtersMenu ? '0' : '100vw'} opacity={filtersMenu ? '1' : '0'}
|
||||
toggleFiltersMenu={toggleFiltersMenu}
|
||||
sortByHandler={sortByHandler} statusHandler={statusHandler}
|
||||
challengeTypeHandler={challengeTypeHandler} commercialHandler={commercialHandler}
|
||||
sortBy={sortBy} status={status} challengeType={challengeType} commercial={commercial}/>
|
||||
<FlexColumn as='main' alignmentY='flex-start' width='100%'
|
||||
minHeight='100vh' padding='90px 0 32px 0'>
|
||||
<FlexColumn alignmentX='flex-start' width='80%'>
|
||||
<H1 as='h1' margin='0 0 20px 0'>
|
||||
Challenges
|
||||
</H1>
|
||||
<Search searchQueryHandler={searchQueryHandler} toggleFiltersMenu={toggleFiltersMenu}/>
|
||||
<FlexColumn width='100%'>
|
||||
{renderChallenges()}
|
||||
</FlexColumn>
|
||||
</FlexColumn>
|
||||
<Pager pageNr={pageNr} pages={calcPages()}
|
||||
nextPage={nextPage} previousPage={previousPage}/>
|
||||
</FlexColumn>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
const desktopRender = () => {
|
||||
return (
|
||||
<FlexColumn as='main' alignmentY='flex-start' width='100%'
|
||||
minHeight='100vh' padding='90px 0 32px 0'>
|
||||
<FlexColumn alignmentX='flex-start' width='80%'>
|
||||
<H1 as='h1' margin='0 0 20px 0'>
|
||||
minHeight='100vh' padding='112px 0 82px 0'>
|
||||
<FlexColumn alignmentX='flex-start'>
|
||||
<H1 as='h1' margin='0 0 32px 0'>
|
||||
Challenges
|
||||
</H1>
|
||||
<Search searchQueryHandler={searchQueryHandler} toggleFiltersMenu={toggleFiltersMenu}/>
|
||||
<FlexColumn width='100%'>
|
||||
<Grid margin='32px 0' gridGap='32px 0'>
|
||||
{renderChallenges()}
|
||||
</Grid>
|
||||
{renderChallenges()}
|
||||
</FlexColumn>
|
||||
</FlexColumn>
|
||||
<Pager pageNr={pageNr} pages={calcPages()}
|
||||
nextPage={nextPage} previousPage={previousPage}/>
|
||||
</FlexColumn>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Media query={theme.mobile}>
|
||||
{mobileRender()}
|
||||
</Media>
|
||||
<Media query={theme.desktop}>
|
||||
{desktopRender()}
|
||||
</Media>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
@ -1,18 +1,33 @@
|
||||
import {ELEMENTS_PER_PAGE} from "../../utils/globals";
|
||||
import MiniChallenge from "../../components/elements/MiniChallenge";
|
||||
import {Grid} from "../../utils/containers";
|
||||
import styled from "styled-components";
|
||||
|
||||
const ChallengesGrid = styled(Grid)`
|
||||
margin: 32px 0;
|
||||
grid-gap: 32px 0;
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
margin: 96px 0;
|
||||
grid-gap: 64px;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
}
|
||||
`;
|
||||
|
||||
const _renderChallenges = (pageNr, challenges) => {
|
||||
const n = (pageNr - 1) * ELEMENTS_PER_PAGE;
|
||||
return (
|
||||
challenges.slice(n, n + ELEMENTS_PER_PAGE).map((challenge, index) => {
|
||||
return (
|
||||
<MiniChallenge key={`challenge-${index}`} title={challenge.title} type={challenge.type}
|
||||
description={challenge.description} metric={challenge.mainMetric}
|
||||
bestScore={challenge.bestScore} baseline={challenge.baseline}
|
||||
prize={challenge.prize} deadline={challenge.deadline}
|
||||
name={challenge.name}/>
|
||||
);
|
||||
})
|
||||
<ChallengesGrid margin='32px 0' gridGap='32px 0'>
|
||||
{challenges.slice(n, n + ELEMENTS_PER_PAGE).map((challenge, index) => {
|
||||
return (
|
||||
<MiniChallenge key={`challenge-${index}`} title={challenge.title} type={challenge.type}
|
||||
description={challenge.description} metric={challenge.mainMetric}
|
||||
bestScore={challenge.bestScore} baseline={challenge.baseline}
|
||||
prize={challenge.prize} deadline={challenge.deadline}
|
||||
name={challenge.name}/>
|
||||
);
|
||||
})}
|
||||
</ChallengesGrid>
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
const ELEMENTS_PER_PAGE = 12;
|
||||
const MINI_DESCRIPTION_LENGTH = 70;
|
||||
const API = 'https://gonito.net/api';
|
||||
const CHALLENGES_PAGE = '/challenges';
|
||||
const CHALLENGE_PAGE = '/challenge';
|
||||
|
||||
export {ELEMENTS_PER_PAGE, API, CHALLENGES_PAGE, CHALLENGE_PAGE};
|
||||
export {ELEMENTS_PER_PAGE, API, CHALLENGES_PAGE, CHALLENGE_PAGE, MINI_DESCRIPTION_LENGTH};
|
Loading…
Reference in New Issue
Block a user