Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions client/images/heart.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
227 changes: 227 additions & 0 deletions client/modules/About/About.styles.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
import styled from 'styled-components';
import { remSize, prop } from '../../theme';

export const AboutPageContent = styled.div`
margin: ${remSize(42)} ${remSize(295)};

@media (max-width: 1279px) {
margin: ${remSize(20)};
width: 95%;
overflow: hidden auto;
flex-direction: column;
}
`;

export const Intro = styled.div`
& h1 {
font-size: ${remSize(32)};
font-weight: 700;
}

& a {
padding: ${remSize(12)};
border: ${remSize(1)} solid ${prop('primaryTextColor')};
border-radius: ${remSize(24)};
display: flex;
align-items: center;
width: ${remSize(110)};
justify-content: space-evenly;

&:hover {
color: ${prop('Button.primary.default.background')};
background-color: ${prop('Button.primary.hover.background')};
border-color: ${prop('Button.primary.hover.border')};
text-decoration: none;

& svg {
& path {
fill: ${prop('Button.primary.default.background')};
}
}
}
}
`;

export const IntroHeadline = styled.div`
display: flex;
align-items: center;

& div {
height: 100%;
align-items: center;
font-weight: 550;
font-size: ${remSize(24)};
margin: ${remSize(24)};
}

& svg {
& path {
fill: ${prop('logoColor')};
}
}

@media (max-width: 769px) {
flex-direction: column;
align-items: start;

& div {
margin: ${remSize(24)} 0;
}
}
`;

export const IntroDescription = styled.div`
line-height: ${remSize(27)};
font-size: ${remSize(16)};
margin: ${remSize(24)} 0;

p {
margin-bottom: ${remSize(24)};
}
`;

export const Section = styled.div`
margin: ${remSize(50)} 0;

& h2 {
font-size: ${remSize(24)};
padding-bottom: ${remSize(30)};
font-weight: 600;
}

@media (max-width: 769px) {
display: grid;
}
`;

export const SectionContainer = styled.div`
display: flex;
justify-content: row;
padding-top: 0;
font-size: ${remSize(16)};
width: 100%;
flex-wrap: wrap;

@media (max-width: 769px) {
display: grid;
}
`;

export const SectionItem = styled.div`
width: 33%;
display: flex;
line-height: ${remSize(19.5)};
font-size: ${remSize(14)};
padding: 0 ${remSize(30)} ${remSize(30)} 0;

& p {
margin-top: ${remSize(7)};
}

& a {
font-weight: 700;
font-size: ${remSize(16)};

&:hover {
text-decoration: underline;
}
}

& svg {
padding-right: ${remSize(8)};
width: ${remSize(30)};
height: ${remSize(20)};

& path {
fill: ${prop('logoColor')};
stroke: ${prop('logoColor')};
}
}

@media (max-width: 1279px) {
width: 50%;
}

@media (max-width: 769px) {
width: 100%;
}
`;

export const Contact = styled.div`
margin-bottom: ${remSize(50)};

& h2 {
font-size: ${remSize(24)};
font-weight: 600;
}

& div {
display: flex;
width: 100%;
margin: ${remSize(20)} 0;
font-size: ${remSize(16)};
}
`;

export const ContactTitle = styled.p`
width: 50%;

@media (max-width: 769px) {
width: 30%;
}
`;

export const ContactHandles = styled.p`
width: 50%;

& a {
color: ${prop('logoColor')};

&:hover {
text-decoration: underline;
}
}

@media (max-width: 769px) {
width: 70%;
}
`;

export const Footer = styled.div`
border-top: 0.1rem dashed;
padding: 0 ${remSize(20)} ${remSize(70)} 0;
width: 100%;
font-size: ${remSize(16)};

& div {
display: flex;
flex-wrap: wrap;
width: 100%;
}

& a {
margin: ${remSize(20)} 9.5% 0 0;
color: ${prop('logoColor')};

&:hover {
text-decoration: underline;
}
}

& p {
padding: ${remSize(20)} 9.5% 0 0;
}

@media (max-width: 770px) {
flex-direction: column;
padding: 0 ${remSize(20)};
}

@media (max-width: 550px) {
padding-left: 0;

& div {
display: grid;
}
}
`;
158 changes: 158 additions & 0 deletions client/modules/About/pages/About.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { Helmet } from 'react-helmet';
import { useTranslation } from 'react-i18next';
import { Link } from 'react-router-dom';

import {
AboutPageContent,
Intro,
IntroHeadline,
IntroDescription,
Section,
SectionContainer,
SectionItem,
Contact,
ContactTitle,
ContactHandles,
Footer
} from '../About.styles';

import { ContactSectionLinks, AboutSectionInfo } from '../statics/aboutData';
import Nav from '../../IDE/components/Header/Nav';
import RootPage from '../../../components/RootPage';
import packageData from '../../../../package.json';

import HeartIcon from '../../../images/heart.svg';
import AsteriskIcon from '../../../images/p5-asterisk.svg';
import LogoIcon from '../../../images/p5js-square-logo.svg';

const AboutSection = ({ section, t }) => (
<Section>
<h2>{t(section.header)}</h2>
<SectionContainer>
{section.items.map((item) => (
<SectionItem key={item.url}>
<AsteriskIcon aria-hidden="true" focusable="false" />
<div>
<a href={item.url} target="_blank" rel="noopener noreferrer">
{t(item.title)}
</a>
<p>{t(item.description)}</p>
</div>
</SectionItem>
))}
</SectionContainer>
</Section>
);

const About = () => {
const { t } = useTranslation();

const p5version = useSelector((state) => {
const index = state.files.find((file) => file.name === 'index.html');
return index?.content.match(/\/p5\.js\/([\d.]+)\//)?.[1];
});

return (
<RootPage>
<Helmet>
<title> {t('About.TitleHelmet')} </title>
</Helmet>

<Nav layout="dashboard" />

<AboutPageContent>
<Intro>
<h1>{t('About.Title')}</h1>
<IntroHeadline>
<LogoIcon
role="img"
aria-label={t('Common.p5logoARIA')}
focusable="false"
/>
<div>
<p>{t('About.Headline')}</p>
</div>
</IntroHeadline>
<IntroDescription>
<p>{t('About.IntroDescription1')}</p>
<p>{t('About.IntroDescription2')}</p>
</IntroDescription>
<a
href="https://p5js.org/donate/"
target="_blank"
rel="noopener noreferrer"
>
<HeartIcon aria-hidden="true" focusable="false" />
{t('About.Donate')}
</a>
</Intro>

{AboutSectionInfo.map((section) => (
<AboutSection key={t(section.header)} section={section} t={t} />
))}

<Contact>
<h2>{t('Contact')}</h2>
<div>
<ContactTitle>{t('About.Email')}</ContactTitle>
<ContactHandles>
<a
href={t('About.EmailAddress')}
target="_blank"
rel="noopener noreferrer"
>
{t('About.EmailAddress')}
</a>
</ContactHandles>
</div>
<div>
<ContactTitle>{t('About.Socials')}</ContactTitle>
<ContactHandles>
{ContactSectionLinks.map((item, index, array) => (
<React.Fragment key={item.href}>
<a href={item.href} target="_blank" rel="noopener noreferrer">
{t(item.label)}
</a>
{index < array.length - 1 && ', '}
</React.Fragment>
))}
</ContactHandles>
</div>
</Contact>

<Footer>
<div>
<Link to="/privacy-policy">{t('About.PrivacyPolicy')}</Link>
<Link to="/terms-of-use">{t('About.TermsOfUse')}</Link>
<Link to="/code-of-conduct">{t('About.CodeOfConduct')}</Link>
</div>
<p>
{t('About.WebEditor')}: <span>v{packageData?.version}</span>
</p>
<p>
p5.js: <span>v{p5version}</span>
</p>
</Footer>
</AboutPageContent>
</RootPage>
);
};

AboutSection.propTypes = {
section: PropTypes.shape({
header: PropTypes.string.isRequired,
items: PropTypes.arrayOf(
PropTypes.shape({
url: PropTypes.string.isRequired,
title: PropTypes.string.isRequired,
description: PropTypes.string.isRequired
})
).isRequired
}).isRequired,
t: PropTypes.func.isRequired
};

export default About;
Loading
Loading