Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

About Page Redesign #3322

Merged
merged 21 commits into from
Jan 17, 2025
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