diff --git a/client/images/heart.svg b/client/images/heart.svg
new file mode 100644
index 0000000000..1dc62d2639
--- /dev/null
+++ b/client/images/heart.svg
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/client/modules/About/About.styles.js b/client/modules/About/About.styles.js
new file mode 100644
index 0000000000..59439addb4
--- /dev/null
+++ b/client/modules/About/About.styles.js
@@ -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;
+ }
+ }
+`;
diff --git a/client/modules/About/pages/About.jsx b/client/modules/About/pages/About.jsx
new file mode 100644
index 0000000000..39ef396192
--- /dev/null
+++ b/client/modules/About/pages/About.jsx
@@ -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 }) => (
+
+ {t(section.header)}
+
+ {section.items.map((item) => (
+
+
+
+
+ ))}
+
+
+);
+
+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 (
+
+
+ {t('About.TitleHelmet')}
+
+
+
+
+
+
+ {t('About.Title')}
+
+
+
+
{t('About.Headline')}
+
+
+
+ {t('About.IntroDescription1')}
+ {t('About.IntroDescription2')}
+
+
+
+ {t('About.Donate')}
+
+
+
+ {AboutSectionInfo.map((section) => (
+
+ ))}
+
+
+ {t('Contact')}
+
+
+
{t('About.Socials')}
+
+ {ContactSectionLinks.map((item, index, array) => (
+
+
+ {t(item.label)}
+
+ {index < array.length - 1 && ', '}
+
+ ))}
+
+
+
+
+
+
+
+ );
+};
+
+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;
diff --git a/client/modules/About/statics/aboutData.js b/client/modules/About/statics/aboutData.js
new file mode 100644
index 0000000000..b00583cd0c
--- /dev/null
+++ b/client/modules/About/statics/aboutData.js
@@ -0,0 +1,91 @@
+export const ContactSectionLinks = [
+ {
+ label: 'About.Github',
+ href: 'https://github.com/processing/p5.js-web-editor'
+ },
+ {
+ label: 'About.Instagram',
+ href: 'https://www.instagram.com/p5xjs'
+ },
+ {
+ label: 'About.Youtube',
+ href: 'https://www.youtube.com/@ProcessingFoundation'
+ },
+ { label: 'About.X', href: 'https://x.com/p5xjs' },
+ {
+ label: 'About.Discord',
+ href: 'https://discord.gg/SHQ8dH25r9'
+ },
+ {
+ label: 'About.Forum',
+ href: 'https://forum.processing.org/'
+ }
+];
+
+export const AboutSectionInfo = [
+ {
+ header: 'About.NewP5',
+ items: [
+ {
+ url: 'https://p5js.org/',
+ title: 'About.Home',
+ description: 'About.LinkDescriptions.Home'
+ },
+ {
+ url: 'https://p5js.org/examples/',
+ title: 'About.Examples',
+ description: 'About.LinkDescriptions.Examples'
+ },
+ {
+ url: '/code-of-conduct',
+ title: 'About.CodeOfConduct',
+ description: 'About.LinkDescriptions.CodeOfConduct'
+ }
+ ]
+ },
+ {
+ header: 'About.Resources',
+ items: [
+ {
+ url: 'https://p5js.org/libraries/',
+ title: 'About.Libraries',
+ description: 'About.LinkDescriptions.Libraries'
+ },
+ {
+ url: 'https://p5js.org/reference/',
+ title: 'About.Reference',
+ description: 'About.LinkDescriptions.Reference'
+ }
+ ]
+ },
+ {
+ header: 'About.GetInvolved',
+ items: [
+ {
+ url: 'https://p5js.org/donate/',
+ title: 'About.Donate',
+ description: 'About.LinkDescriptions.Donate'
+ },
+ {
+ url: 'https://github.com/processing/p5.js-web-editor',
+ title: 'About.Contribute',
+ description: 'About.LinkDescriptions.Contribute'
+ },
+ {
+ url: 'https://github.com/processing/p5.js-web-editor/issues/new',
+ title: 'About.Report',
+ description: 'About.LinkDescriptions.Report'
+ },
+ {
+ url: 'https://discourse.processing.org/',
+ title: 'About.ForumCTA',
+ description: 'About.LinkDescriptions.Forum'
+ },
+ {
+ url: 'https://discord.com/invite/SHQ8dH25r9',
+ title: 'About.DiscordCTA',
+ description: 'About.LinkDescriptions.Discord'
+ }
+ ]
+ }
+];
diff --git a/client/modules/IDE/components/About.jsx b/client/modules/IDE/components/About.jsx
deleted file mode 100644
index 25b9f54520..0000000000
--- a/client/modules/IDE/components/About.jsx
+++ /dev/null
@@ -1,234 +0,0 @@
-import React from 'react';
-import { useSelector } from 'react-redux';
-import { Helmet } from 'react-helmet';
-import { useTranslation } from 'react-i18next';
-import { Link } from 'react-router-dom';
-import SquareLogoIcon from '../../../images/p5js-square-logo.svg';
-// import PlayIcon from '../../../images/play.svg';
-import AsteriskIcon from '../../../images/p5-asterisk.svg';
-import packageData from '../../../../package.json';
-
-function About(props) {
- 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 (
-
-
- {t('About.TitleHelmet')}
-
-
-
-
-
- {t('About.WebEditor')}: v{packageData?.version}
-
-
- p5.js: v{p5version}
-
-
-
-
-
-
-
- );
-}
-
-export default About;
diff --git a/client/modules/IDE/components/About.stories.jsx b/client/modules/IDE/components/About.stories.jsx
deleted file mode 100644
index 97289f9bc8..0000000000
--- a/client/modules/IDE/components/About.stories.jsx
+++ /dev/null
@@ -1,8 +0,0 @@
-import About from './About';
-
-export default {
- title: 'IDE/About',
- component: About
-};
-
-export const Default = {};
diff --git a/client/modules/IDE/components/IDEOverlays.jsx b/client/modules/IDE/components/IDEOverlays.jsx
index 52b21a9e9e..8565c5bd56 100644
--- a/client/modules/IDE/components/IDEOverlays.jsx
+++ b/client/modules/IDE/components/IDEOverlays.jsx
@@ -9,7 +9,6 @@ import {
closeShareModal,
hideErrorModal
} from '../actions/ide';
-import About from './About';
import AddToCollectionList from './AddToCollectionList';
import ErrorModal from './ErrorModal';
import Feedback from './Feedback';
@@ -49,15 +48,6 @@ export default function IDEOverlays() {
)}
- {location.pathname === '/about' && (
-
-
-
- )}
{location.pathname === '/feedback' && (
-
+
diff --git a/client/styles/components/_about.scss b/client/styles/components/_about.scss
deleted file mode 100644
index c21939e6fe..0000000000
--- a/client/styles/components/_about.scss
+++ /dev/null
@@ -1,98 +0,0 @@
-@use "sass:math";
-
-.about__logo {
- @include themify() {
- & path {
- fill: getThemifyVariable('logo-color');
- }
- }
-}
-
-.about__content {
- display: flex;
- flex-direction: row;
- justify-content: space-between;
- flex-wrap: wrap;
- padding-top: #{math.div(17, $base-font-size)}rem;
- padding-right: #{math.div(78, $base-font-size)}rem;
- padding-bottom: #{math.div(20, $base-font-size)}rem;
- padding-left: #{math.div(20, $base-font-size)}rem;
- width: #{math.div(720, $base-font-size)}rem;
-}
-
-.about__content-column {
- display: flex;
- flex-direction: column;
- margin-left: 15px;
- margin-right: 15px;
-}
-
-@media (max-width: 768px) {
- .about__content {
- flex-direction: column;
- overflow-y: auto;
- overflow-x: hidden;
- width: 100%;
- margin-right: 15rem;
- }
-
- .about__footer {
- flex-direction: column;
- padding-left: #{math.div(20, $base-font-size)}rem;
- padding-right: #{math.div(20, $base-font-size)}rem;
- }
-}
-
-.about__content-column-title {
- font-size: #{math.div(21, $base-font-size)}rem;
- padding-left: #{math.div(17, $base-font-size)}rem;
-}
-
-.about__content-column-asterisk {
- padding-right: #{math.div(5, $base-font-size)}rem;
- @include themify() {
- & path {
- fill: getThemifyVariable('logo-color');
- stroke: getThemifyVariable('logo-color');
- }
- }
-}
-
-.about__content-column-list {
- @include themify() {
- padding-top: #{math.div(10, $base-font-size)}rem;
- font-size: #{math.div(16, $base-font-size)}rem;
- }
-}
-
-.about__version-info {
- @include themify() {
- padding-top: #{math.div(8, $base-font-size)}rem;
- font-size: #{math.div(16, $base-font-size)}rem;
- span {
- color: getThemifyVariable('logo-color');
- }
- &:first-child {
- padding-top: #{math.div(30, $base-font-size)}rem;
- }
- }
- // span {
- // @include themify() {
- // fill: getThemifyVariable('logo-color');
- // }
- // }
-}
-
-.about__footer {
- display: flex;
- justify-content: space-between;
- padding-top: #{math.div(18, $base-font-size)}rem;
- padding-right: #{math.div(20, $base-font-size)}rem;
- padding-bottom: #{math.div(21, $base-font-size)}rem;
- padding-left: #{math.div(20, $base-font-size)}rem;
- width: 100%;
-}
-
-.about__footer-list {
- padding-top: #{math.div(12, $base-font-size)}rem;
-}
diff --git a/client/styles/main.scss b/client/styles/main.scss
index 75cc236904..c82a2c3e8f 100644
--- a/client/styles/main.scss
+++ b/client/styles/main.scss
@@ -32,7 +32,6 @@
@import 'components/console';
@import 'components/resizer';
@import 'components/overlay';
-@import 'components/about';
@import 'components/forms';
@import 'components/toast';
@import 'components/timer';
diff --git a/translations/locales/en-US/translations.json b/translations/locales/en-US/translations.json
index 31a42c47af..697e5a2749 100644
--- a/translations/locales/en-US/translations.json
+++ b/translations/locales/en-US/translations.json
@@ -89,27 +89,47 @@
"About": {
"Title": "About",
"TitleHelmet": "p5.js Web Editor | About",
+ "Headline": "Create, share, and remix p5.js sketches with the p5.js Editor.",
"Contribute": "Contribute",
+ "IntroDescription1": "p5.js is a free, open-source JavaScript library for learning to code and make art. Using the p5.js Editor, you can create, share, and remix p5.js sketches without needing to download or configure anything.",
+ "IntroDescription2": "We believe software the tools to learn it, should be as open and inclusive as possible. You can support this work by making a donation to the Processing Foundation, the organization that supports p5.js. Your donation supports sofware development for p5.js, education resources like code examples and tutorials, fellowships, and community events.",
+ "Donate": "Donate",
"NewP5": "New to p5.js?",
- "Report": "Report a bug",
+ "Report": "Report a Bug",
"Learn": "Learn",
- "Twitter": "Twitter",
- "Home": "Home",
+ "X": "X",
+ "Home": "p5.js Home",
"Instagram": "Instagram",
"Discord": "Discord",
+ "DiscordCTA": "Join the Discord",
+ "Youtube": "Youtube",
+ "Github": "Github",
+ "GetInvolved": "Get Involved",
"WebEditor": "Web Editor",
"Resources": "Resources",
+ "Reference": "Reference",
"Libraries": "Libraries",
"Forum": "Forum",
+ "ForumCTA": "Join the Forum",
"Examples": "Examples",
- "Home": "Home",
- "Twitter": "Twitter",
- "Instagram": "Instagram",
- "Discord": "Discord",
"PrivacyPolicy": "Privacy Policy",
"TermsOfUse": "Terms of Use",
"CodeOfConduct": "Code of Conduct",
- "WebEditor": "Web Editor"
+ "Email": "Email",
+ "EmailAddress": "hello@p5js.org",
+ "Socials": "Socials",
+ "LinkDescriptions": {
+ "Home": "Learn more about p5.js and our community.",
+ "Examples": "Explore the possibilities of p5.js with short examples.",
+ "CodeOfConduct": "Read our Community State and Code of Conduct.",
+ "Libraries": "Expand the possibilities of p5.js with community-created libraries.",
+ "Reference": "Find easy expalantions for every piece of p5.js code.",
+ "Donate": "Support this work with a donation to the Processing Foundation.",
+ "Contribute": "Contribute to the open-source p5.js Editor on Github.",
+ "Report": "Report broken or incorrect behavior with the p5.js Editor.",
+ "Forum": "Expand the possibilities of p5.js with community-created libraries.",
+ "Discord": "Expand the possibilties of p5.js with community-created libraries."
+ }
},
"Toast": {
"OpenedNewSketch": "Opened new sketch.",