Skip to content

Commit a5959bd

Browse files
authored
Merge pull request #3322 from processing/about-redesign
About Page Redesign
2 parents a4ddf9b + 4abc254 commit a5959bd

File tree

12 files changed

+515
-361
lines changed

12 files changed

+515
-361
lines changed

Diff for: client/images/heart.svg

+8
Loading

Diff for: client/modules/About/About.styles.js

+227
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
import styled from 'styled-components';
2+
import { remSize, prop } from '../../theme';
3+
4+
export const AboutPageContent = styled.div`
5+
margin: ${remSize(42)} ${remSize(295)};
6+
7+
@media (max-width: 1279px) {
8+
margin: ${remSize(20)};
9+
width: 95%;
10+
overflow: hidden auto;
11+
flex-direction: column;
12+
}
13+
`;
14+
15+
export const Intro = styled.div`
16+
& h1 {
17+
font-size: ${remSize(32)};
18+
font-weight: 700;
19+
}
20+
21+
& a {
22+
padding: ${remSize(12)};
23+
border: ${remSize(1)} solid ${prop('primaryTextColor')};
24+
border-radius: ${remSize(24)};
25+
display: flex;
26+
align-items: center;
27+
width: ${remSize(110)};
28+
justify-content: space-evenly;
29+
30+
&:hover {
31+
color: ${prop('Button.primary.default.background')};
32+
background-color: ${prop('Button.primary.hover.background')};
33+
border-color: ${prop('Button.primary.hover.border')};
34+
text-decoration: none;
35+
36+
& svg {
37+
& path {
38+
fill: ${prop('Button.primary.default.background')};
39+
}
40+
}
41+
}
42+
}
43+
`;
44+
45+
export const IntroHeadline = styled.div`
46+
display: flex;
47+
align-items: center;
48+
49+
& div {
50+
height: 100%;
51+
align-items: center;
52+
font-weight: 550;
53+
font-size: ${remSize(24)};
54+
margin: ${remSize(24)};
55+
}
56+
57+
& svg {
58+
& path {
59+
fill: ${prop('logoColor')};
60+
}
61+
}
62+
63+
@media (max-width: 769px) {
64+
flex-direction: column;
65+
align-items: start;
66+
67+
& div {
68+
margin: ${remSize(24)} 0;
69+
}
70+
}
71+
`;
72+
73+
export const IntroDescription = styled.div`
74+
line-height: ${remSize(27)};
75+
font-size: ${remSize(16)};
76+
margin: ${remSize(24)} 0;
77+
78+
p {
79+
margin-bottom: ${remSize(24)};
80+
}
81+
`;
82+
83+
export const Section = styled.div`
84+
margin: ${remSize(50)} 0;
85+
86+
& h2 {
87+
font-size: ${remSize(24)};
88+
padding-bottom: ${remSize(30)};
89+
font-weight: 600;
90+
}
91+
92+
@media (max-width: 769px) {
93+
display: grid;
94+
}
95+
`;
96+
97+
export const SectionContainer = styled.div`
98+
display: flex;
99+
justify-content: row;
100+
padding-top: 0;
101+
font-size: ${remSize(16)};
102+
width: 100%;
103+
flex-wrap: wrap;
104+
105+
@media (max-width: 769px) {
106+
display: grid;
107+
}
108+
`;
109+
110+
export const SectionItem = styled.div`
111+
width: 33%;
112+
display: flex;
113+
line-height: ${remSize(19.5)};
114+
font-size: ${remSize(14)};
115+
padding: 0 ${remSize(30)} ${remSize(30)} 0;
116+
117+
& p {
118+
margin-top: ${remSize(7)};
119+
}
120+
121+
& a {
122+
font-weight: 700;
123+
font-size: ${remSize(16)};
124+
125+
&:hover {
126+
text-decoration: underline;
127+
}
128+
}
129+
130+
& svg {
131+
padding-right: ${remSize(8)};
132+
width: ${remSize(30)};
133+
height: ${remSize(20)};
134+
135+
& path {
136+
fill: ${prop('logoColor')};
137+
stroke: ${prop('logoColor')};
138+
}
139+
}
140+
141+
@media (max-width: 1279px) {
142+
width: 50%;
143+
}
144+
145+
@media (max-width: 769px) {
146+
width: 100%;
147+
}
148+
`;
149+
150+
export const Contact = styled.div`
151+
margin-bottom: ${remSize(50)};
152+
153+
& h2 {
154+
font-size: ${remSize(24)};
155+
font-weight: 600;
156+
}
157+
158+
& div {
159+
display: flex;
160+
width: 100%;
161+
margin: ${remSize(20)} 0;
162+
font-size: ${remSize(16)};
163+
}
164+
`;
165+
166+
export const ContactTitle = styled.p`
167+
width: 50%;
168+
169+
@media (max-width: 769px) {
170+
width: 30%;
171+
}
172+
`;
173+
174+
export const ContactHandles = styled.p`
175+
width: 50%;
176+
177+
& a {
178+
color: ${prop('logoColor')};
179+
180+
&:hover {
181+
text-decoration: underline;
182+
}
183+
}
184+
185+
@media (max-width: 769px) {
186+
width: 70%;
187+
}
188+
`;
189+
190+
export const Footer = styled.div`
191+
border-top: 0.1rem dashed;
192+
padding: 0 ${remSize(20)} ${remSize(70)} 0;
193+
width: 100%;
194+
font-size: ${remSize(16)};
195+
196+
& div {
197+
display: flex;
198+
flex-wrap: wrap;
199+
width: 100%;
200+
}
201+
202+
& a {
203+
margin: ${remSize(20)} 9.5% 0 0;
204+
color: ${prop('logoColor')};
205+
206+
&:hover {
207+
text-decoration: underline;
208+
}
209+
}
210+
211+
& p {
212+
padding: ${remSize(20)} 9.5% 0 0;
213+
}
214+
215+
@media (max-width: 770px) {
216+
flex-direction: column;
217+
padding: 0 ${remSize(20)};
218+
}
219+
220+
@media (max-width: 550px) {
221+
padding-left: 0;
222+
223+
& div {
224+
display: grid;
225+
}
226+
}
227+
`;

Diff for: client/modules/About/pages/About.jsx

+158
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
import React from 'react';
2+
import PropTypes from 'prop-types';
3+
import { useSelector } from 'react-redux';
4+
import { Helmet } from 'react-helmet';
5+
import { useTranslation } from 'react-i18next';
6+
import { Link } from 'react-router-dom';
7+
8+
import {
9+
AboutPageContent,
10+
Intro,
11+
IntroHeadline,
12+
IntroDescription,
13+
Section,
14+
SectionContainer,
15+
SectionItem,
16+
Contact,
17+
ContactTitle,
18+
ContactHandles,
19+
Footer
20+
} from '../About.styles';
21+
22+
import { ContactSectionLinks, AboutSectionInfo } from '../statics/aboutData';
23+
import Nav from '../../IDE/components/Header/Nav';
24+
import RootPage from '../../../components/RootPage';
25+
import packageData from '../../../../package.json';
26+
27+
import HeartIcon from '../../../images/heart.svg';
28+
import AsteriskIcon from '../../../images/p5-asterisk.svg';
29+
import LogoIcon from '../../../images/p5js-square-logo.svg';
30+
31+
const AboutSection = ({ section, t }) => (
32+
<Section>
33+
<h2>{t(section.header)}</h2>
34+
<SectionContainer>
35+
{section.items.map((item) => (
36+
<SectionItem key={item.url}>
37+
<AsteriskIcon aria-hidden="true" focusable="false" />
38+
<div>
39+
<a href={item.url} target="_blank" rel="noopener noreferrer">
40+
{t(item.title)}
41+
</a>
42+
<p>{t(item.description)}</p>
43+
</div>
44+
</SectionItem>
45+
))}
46+
</SectionContainer>
47+
</Section>
48+
);
49+
50+
const About = () => {
51+
const { t } = useTranslation();
52+
53+
const p5version = useSelector((state) => {
54+
const index = state.files.find((file) => file.name === 'index.html');
55+
return index?.content.match(/\/p5\.js\/([\d.]+)\//)?.[1];
56+
});
57+
58+
return (
59+
<RootPage>
60+
<Helmet>
61+
<title> {t('About.TitleHelmet')} </title>
62+
</Helmet>
63+
64+
<Nav layout="dashboard" />
65+
66+
<AboutPageContent>
67+
<Intro>
68+
<h1>{t('About.Title')}</h1>
69+
<IntroHeadline>
70+
<LogoIcon
71+
role="img"
72+
aria-label={t('Common.p5logoARIA')}
73+
focusable="false"
74+
/>
75+
<div>
76+
<p>{t('About.Headline')}</p>
77+
</div>
78+
</IntroHeadline>
79+
<IntroDescription>
80+
<p>{t('About.IntroDescription1')}</p>
81+
<p>{t('About.IntroDescription2')}</p>
82+
</IntroDescription>
83+
<a
84+
href="https://p5js.org/donate/"
85+
target="_blank"
86+
rel="noopener noreferrer"
87+
>
88+
<HeartIcon aria-hidden="true" focusable="false" />
89+
{t('About.Donate')}
90+
</a>
91+
</Intro>
92+
93+
{AboutSectionInfo.map((section) => (
94+
<AboutSection key={t(section.header)} section={section} t={t} />
95+
))}
96+
97+
<Contact>
98+
<h2>{t('Contact')}</h2>
99+
<div>
100+
<ContactTitle>{t('About.Email')}</ContactTitle>
101+
<ContactHandles>
102+
<a
103+
href={t('About.EmailAddress')}
104+
target="_blank"
105+
rel="noopener noreferrer"
106+
>
107+
{t('About.EmailAddress')}
108+
</a>
109+
</ContactHandles>
110+
</div>
111+
<div>
112+
<ContactTitle>{t('About.Socials')}</ContactTitle>
113+
<ContactHandles>
114+
{ContactSectionLinks.map((item, index, array) => (
115+
<React.Fragment key={item.href}>
116+
<a href={item.href} target="_blank" rel="noopener noreferrer">
117+
{t(item.label)}
118+
</a>
119+
{index < array.length - 1 && ', '}
120+
</React.Fragment>
121+
))}
122+
</ContactHandles>
123+
</div>
124+
</Contact>
125+
126+
<Footer>
127+
<div>
128+
<Link to="/privacy-policy">{t('About.PrivacyPolicy')}</Link>
129+
<Link to="/terms-of-use">{t('About.TermsOfUse')}</Link>
130+
<Link to="/code-of-conduct">{t('About.CodeOfConduct')}</Link>
131+
</div>
132+
<p>
133+
{t('About.WebEditor')}: <span>v{packageData?.version}</span>
134+
</p>
135+
<p>
136+
p5.js: <span>v{p5version}</span>
137+
</p>
138+
</Footer>
139+
</AboutPageContent>
140+
</RootPage>
141+
);
142+
};
143+
144+
AboutSection.propTypes = {
145+
section: PropTypes.shape({
146+
header: PropTypes.string.isRequired,
147+
items: PropTypes.arrayOf(
148+
PropTypes.shape({
149+
url: PropTypes.string.isRequired,
150+
title: PropTypes.string.isRequired,
151+
description: PropTypes.string.isRequired
152+
})
153+
).isRequired
154+
}).isRequired,
155+
t: PropTypes.func.isRequired
156+
};
157+
158+
export default About;

0 commit comments

Comments
 (0)