+ );
+};
+
+render(
+
+
+ ,
+ document.getElementById('app')
+);
diff --git a/src/views/guidelines/guidelines.scss b/src/views/guidelines/guidelines.scss
index 92566445d..6012cb20e 100644
--- a/src/views/guidelines/guidelines.scss
+++ b/src/views/guidelines/guidelines.scss
@@ -1,23 +1,215 @@
@import "../../colors";
@import "../../frameless";
-.guidelines {
- .guidelines-footer {
- margin-top: 1.5rem;
- text-align: center;
+#view {
+ padding: 0;
+}
+
+.guidelines-page {
+ header {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ background-color: $motion-blue-3;
+ background-image: url('/svgs/guidelines/header_sprinkles_left.svg'), url('/svgs/guidelines/header_sprinkles_right.svg');
+ background-position: left, right;
+ background-repeat: no-repeat;
+
+ padding: 6.25rem 0;
+
+ div {
+ color: $ui-white;
+ text-align: center;
+ font-family: "Helvetica Neue", "Helvetica", Arial, sans-serif;
+ width: 708px;
+ }
+
+ .title {
+ margin-bottom: 2.25rem;
+ font-size: 2.25rem;
+ font-weight: 700;
+ }
+
+ .header1, .header2 {
+ font-size: 1.5rem;
+ font-weight: 500;
+ }
+
+ .header1 {
+ margin-bottom: 1.5rem;
+ }
}
- dl {
- dt {
- margin-top: 1.5rem;
- }
- }
-}
-
-@media #{$medium-and-smaller}{
- .guidelines-footer {
- img {
- display: none;
+ .navigation {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ gap: 4.5rem;
+ margin: 6rem 15% 0 15%;
+ padding-bottom: 6rem;
+
+ border-bottom: 1px solid $active-gray;
+
+ .header3 {
+ font-size: 1.25rem;
+ font-weight: 400;
+ font-family: "Helvetica Neue", "Helvetica", Arial, sans-serif;
+ text-align: start;
+ }
+
+ .navigation-buttons {
+ display: grid;
+ grid-template-columns: repeat(2, 1fr);
+ grid-template-rows: repeat(3, 1fr);
+ grid-auto-flow: column;
+ column-gap: 2.25rem;
+ row-gap: 1rem;
+
+ a {
+ display: flex;
+ align-items: center;
+ gap: 1.875rem;
+
+ padding: 1rem 2rem;
+
+ font-size: 1.125rem;
+ font-weight: 500;
+ font-family: "Helvetica Neue", "Helvetica", Arial, sans-serif;
+ color: $header-gray;
+ text-align: start;
+ word-wrap: break-word;
+
+ border: 1px solid $box-shadow-light-gray;
+ border-radius: 10px;
+ transition: background 0.5s ease-in-out;
+ }
+
+ a:hover {
+ background-color: $ui-light-grayish-blue;
+ }
+ }
+ }
+
+ .guidelines {
+ display: flex;
+ flex-direction: column;
+ gap: 12rem;
+
+ margin: 6rem auto;
+
+ .guideline {
+ display: flex;
+ align-items: center;
+ gap: 4.5rem;
+ scroll-margin-top: 6rem;
+
+ div, p {
+ font-family: "Helvetica Neue", "Helvetica", Arial, sans-serif;
+ text-align: start;
+ }
+
+ .guideline-title {
+ font-size: 1.5rem;
+ font-weight: 500;
+ }
+
+ .first-paragraph {
+ font-size: 1.25rem;
+ font-weight: 400;
+ }
+
+ .second-paragraph {
+ font-size: 1rem;
+ font-weight: 400;
+ }
+
+ img {
+ width: $cols4;
+ }
+
+ a {
+ text-decoration: underline;
+ }
+ }
+
+ .content-first {
+ flex-direction: row;
+ }
+
+ .image-first {
+ flex-direction: row-reverse;
+ }
+ }
+
+ @media only screen and (max-width: 1024px) {
+ .guidelines {
+ .guideline {
+ flex-direction: column-reverse;
+ gap: 2.25rem;
+ margin: 0 10%;
+ }
+ }
+ }
+
+ @media only screen and (max-width: 768px) {
+ header {
+ background-image: unset;
+ padding: 6.25rem 10%;
+
+ div {
+ width: auto;
+ }
+ }
+ }
+
+ @media only screen and (max-width: 560px) {
+ header {
+ .title {
+ font-size: 2rem;
+ }
+
+ .header1, .header2 {
+ font-size: 1.25rem;
+ }
+ }
+
+ .navigation {
+ .navigation-buttons {
+ grid-template-columns: repeat(1, 1fr);
+ grid-template-rows: unset;
+ grid-auto-flow: unset;
+ }
+ }
+ }
+
+ @media only screen and (max-width: 360px) {
+ header {
+ .title {
+ font-size: 1.5rem;
+ }
+
+ .header1, .header2 {
+ font-size: 1rem;
+ }
+ }
+
+ .navigation {
+ .header3 {
+ font-size: 1rem;
+ }
+ }
+
+ .guidelines {
+ .guideline {
+ .guideline-title {
+ font-size: 1.25rem;
+ }
+
+ .first-paragraph {
+ font-size: 1.125rem;
+ }
+ }
}
}
}
diff --git a/src/views/guidelines/l10n.json b/src/views/guidelines/l10n.json
index 20e1ff0d0..4764f3ce8 100644
--- a/src/views/guidelines/l10n.json
+++ b/src/views/guidelines/l10n.json
@@ -1,19 +1,40 @@
{
- "guidelines.title": "Scratch Community Guidelines",
+ "guidelines.title": "The Purpose of Scratch Community",
"guidelines.header1": "Scratch is a friendly and welcoming community for everyone, where people create, share, and learn together.",
"guidelines.header2": "We welcome people of all ages, races, ethnicities, religions, abilities, sexual orientations, and gender identities.",
"guidelines.header3": "Help keep Scratch a welcoming, supportive, and creative space for all by following these Community Guidelines:",
"guidelines.respectheader": "Treat everyone with respect.",
- "guidelines.respectbody": "Scratchers have diverse backgrounds, interests, identities, and experiences. Everyone on Scratch is encouraged to share things that excite them and are important to them—we hope that you find ways to celebrate your own identity on Scratch, and allow others to do the same. It’s never OK to attack a person or group’s identity or to be unkind to someone about their background or interests.",
+ "guidelines.respectbody1": "Scratchers have diverse backgrounds, interests, identities, and experiences.",
+ "guidelines.respectbody2": "Everyone on Scratch is encouraged to share things that excite them and are important to them—we hope that you find ways to celebrate your own identity on Scratch, and allow others to do the same. It’s never OK to attack a person or group’s identity or to be unkind to someone about their background or interests.",
"guidelines.privacyheader": "Be safe: keep personal and contact information private.",
- "guidelines.privacybody": "For safety reasons, don't give out any information that could be used for private communication, in person or online. This includes sharing real last names, phone numbers, addresses, hometowns, school names, email addresses, usernames or links to social media sites, video chatting applications, or websites with private chat functionality.",
+ "guidelines.privacybody1": "For safety reasons, don't give out any information that could be used for private communication, in person or online.",
+ "guidelines.privacybody2": "This includes sharing real last names, phone numbers, addresses, hometowns, school names, email addresses, usernames or links to social media sites, video chatting applications, or websites with private chat functionality.",
"guidelines.helpfulheader": "Give helpful feedback.",
- "guidelines.helpfulbody": "Everyone on Scratch is learning. When commenting on a project, remember to say something you like about it, offer suggestions, and be kind, not critical. Please keep comments respectful and avoid spamming or posting chain mail. We encourage you to try new things, experiment, and learn from others.",
+ "guidelines.helpfulbody1": "Everyone on Scratch is learning.",
+ "guidelines.helpfulbody2": "When commenting on a project, remember to say something you like about it, offer suggestions, and be kind, not critical. Please keep comments respectful and avoid spamming or posting chain mail. We encourage you to try new things, experiment, and learn from others.",
"guidelines.remixheader": "Embrace remix culture.",
"guidelines.remixbody1": "Remixing is when you build upon someone else’s projects, code, ideas, images, or anything else they share on Scratch to make your own unique creation.",
"guidelines.remixbody2": "Remixing is a great way to collaborate and connect with other Scratchers. You are encouraged to use anything you find on Scratch in your own creations, as long as you provide credit to everyone whose work you used and make a meaningful change to it. And when you share something on Scratch, you are giving permission to all Scratchers to use your work in their creations, too.",
"guidelines.honestyheader": "Be honest.",
- "guidelines.honestybody": "It’s important to be honest and authentic when interacting with others on Scratch, and remember that there is a person behind every Scratch account. Spreading rumors, impersonating other Scratchers or celebrities, or pretending to be seriously ill is not respectful to the Scratch Community.",
+ "guidelines.honestybody1": "It’s important to be honest and authentic when interacting with others on Scratch, and remember that there is a person behind every Scratch account.",
+ "guidelines.honestybody2": "Spreading rumors, impersonating other Scratchers or celebrities, or pretending to be seriously ill is not respectful to the Scratch Community.",
"guidelines.friendlyheader": "Help keep the site friendly.",
- "guidelines.friendlybody": "It’s important to keep your creations and conversations friendly and appropriate for all ages. If you think something on Scratch is mean, insulting, too violent, or otherwise disruptive to the community, click “Report” to let us know about it. Please use the “Report” button rather than engaging in fights, spreading rumors about other people’s behavior, or otherwise responding to any inappropriate content. The Scratch Team will look at your report and take the appropriate action."
+ "guidelines.friendlybody1": "It’s important to keep your creations and conversations friendly and appropriate for all ages.",
+ "guidelines.friendlybody2": "If you think something on Scratch is mean, insulting, too violent, or otherwise disruptive to the community, click “Report” to let us know about it. Please use the “Report” button rather than engaging in fights, spreading rumors about other people’s behavior, or otherwise responding to any inappropriate content. The Scratch Team will look at your report and take the appropriate action.",
+ "guidelines.learnMoreheader": "Want to learn more?",
+ "guidelines.learnMorebody1": "Download the guide for more details!",
+ "guidelines.learnMorebody2": "Discover the limitless potential of the Scratch online community with our guides! These valuable resources are designed to help you navigate and thrive as a Scratcher, revealing everything from setting up your profile to connecting with like-minded individuals. Learn how to connect with others, share your unique creations, and find inspiration for your next project.",
+ "guidelines.respectButtonImageDescription": "A blue circle",
+ "guidelines.privacyButtonImageDescription": "A yellow circle",
+ "guidelines.helpfulButtonImageDescription": "A magenta circle",
+ "guidelines.remixButtonImageDescription": "A green circle",
+ "guidelines.honestyButtonImageDescription": "A purple circle",
+ "guidelines.friendlyButtonImageDescription": "A pink circle",
+ "guidelines.respectSectionImageDescription": "A graphic of two hands grasping each other in a handshake, with a pink heart above them.",
+ "guidelines.privacySectionImageDescription": "A graphic of a blue combination lock lock on a yellow background. Inside the lock is the shape of a head with a question mark printed on the face.",
+ "guidelines.helpfulSectionImageDescription": "A graphic of a piece of paper on top of a pink background. On the paper, there is a Scratch project with a white cat on a blue background. A pink pen with a heart on the cap is drawing a heart and a pencil is writing a comment.",
+ "guidelines.remixSectionImageDescription": "A graphic of the Scratch \"remix\" swirl on a green background. Two hands move orange, blue, and purple Scratch blocks around. A paintbrush paints a green streak.",
+ "guidelines.honestySectionImageDescription": "A graphic of a light blue compass on a purple background. There is a pink heart in the \"North\" position.",
+ "guidelines.friendlySectionImageDescription": "A graphic of 5 hands with different skin tones using their pointer and middle fingers to create a star on a pink background with a pink star and yellow star in the center.",
+ "guidelines.learnMoreSectionImageDescription": "A graphic of a box with a green arrow pointing inside of it with stars in the background."
}
diff --git a/src/views/ideas/ideas.jsx b/src/views/ideas/ideas.jsx
index a93579351..d9cfbc69a 100644
--- a/src/views/ideas/ideas.jsx
+++ b/src/views/ideas/ideas.jsx
@@ -1,284 +1,341 @@
-const bindAll = require('lodash.bindall');
const FormattedMessage = require('react-intl').FormattedMessage;
-const injectIntl = require('react-intl').injectIntl;
const React = require('react');
+const {useState, useCallback} = require('react');
const Button = require('../../components/forms/button.jsx');
const FlexRow = require('../../components/flex-row/flex-row.jsx');
-const MasonryGrid = require('../../components/masonrygrid/masonrygrid.jsx');
-const TitleBanner = require('../../components/title-banner/title-banner.jsx');
-const TTTModal = require('../../components/modal/ttt/modal.jsx');
-const TTTTile = require('../../components/ttt-tile/ttt-tile.jsx');
const Page = require('../../components/page/www/page.jsx');
-const intlShape = require('../../lib/intl-shape');
const render = require('../../lib/render.jsx');
-const Tiles = require('./ttt.json');
+const {useIntl} = require('react-intl');
+const {
+ YoutubeVideoModal
+} = require('../../components/youtube-video-modal/youtube-video-modal.jsx');
+const {YoutubePlaylistItem} = require('../../components/youtube-playlist-item/youtube-playlist-item.jsx');
+const {CardsModal} = require('../../components/cards-modal/cards-modal.jsx');
require('./ideas.scss');
-class Ideas extends React.Component {
- constructor (props) {
- super(props);
- bindAll(this, [
- 'handleShowTTTModal',
- 'handleHideTTTModal',
- 'renderTiles'
- ]);
- this.state = {
- currentTile: Tiles[0],
- TTTModalOpen: false
- };
+const tipsSectionData = [
+ {
+ tipImage: {
+ altTextId: 'ideas.gettingStartedImageDescription',
+ imageSrc: '/images/ideas/getting-started-illustration.svg'
+ },
+ button: {
+ href: '/projects/editor/?tutorial=getStarted',
+ buttonTextId: 'ideas.gettingStartedButtonText'
+ }
+ },
+ {
+ tipImage: {
+ altTextId: 'ideas.seeTutorialsLibraryImageDescription',
+ imageSrc: '/images/ideas/see-tutorials-library.png'
+ },
+ button: {
+ href: '/projects/editor/?tutorial=all',
+ buttonTextId: 'ideas.seeTutorialsLibraryButtonText'
+ }
+ },
+ {
+ tipImage: {
+ altTextId: 'ideas.starterProjectsImageDescription',
+ imageSrc: '/images/ideas/starter-projects-illustration.svg'
+ },
+ button: {
+ href: '/starter_projects',
+ buttonTextId: 'ideas.starterProjectsButton'
+ }
+ },
+ {
+ tipImage: {
+ altTextId: 'ideas.cardsIllustrationDescription',
+ imageSrc: '/images/ideas/cards-illustration.svg'
+ },
+ button: {
+ hrefId: 'cards.scratch-cards-allLink',
+ buttonImageSrc: '/images/ideas/download-icon.svg',
+ buttonTextId: 'ideas.codingCards'
+ }
}
- handleShowTTTModal (tile) {
- // expects translated tile
- this.setState({
- currentTile: tile,
- TTTModalOpen: true
- });
+];
+
+const physicalIdeasData = [
+ {
+ physicalIdeasImage: {
+ imageSrc: '/images/ideas/micro-bit.png',
+ imageClass: 'micro-bit'
+ },
+ physicalIdeasDescription: {
+ headerId: 'ideas.microBitHeader',
+ bodyId: 'ideas.microBitBody',
+ hrefId: 'cards.microbit-cardsLink',
+ buttonImageSrc: '/images/ideas/download-icon.svg',
+ buttonTextId: 'ideas.codingCards'
+ }
+ },
+ {
+ physicalIdeasImage: {
+ imageSrc: '/images/ideas/make-board.svg',
+ imageClass: 'makey-makey-img'
+ },
+ physicalIdeasDescription: {
+ headerId: 'ideas.makeyMakeyHeader',
+ bodyId: 'ideas.makeyMakeyBody',
+ hrefId: 'cards.makeymakey-cardsLink',
+ buttonImageSrc: '/images/ideas/download-icon.svg',
+ buttonTextId: 'ideas.codingCards'
+ }
}
- handleHideTTTModal () {
- this.setState({
- TTTModalOpen: false
- });
- }
- renderTiles () {
- return Tiles.map((tile, key) => {
- const translatedTile = {
- tutorialUrl: `/projects/editor/?tutorial=${tile.tutorialUrl}`,
- modalImage: tile.modalImage,
- modalImageDescription: this.props.intl.formatMessage({id: tile.modalImageDescription}),
- description: this.props.intl.formatMessage({id: tile.description}),
- guideUrl: this.props.intl.formatMessage({id: tile.guideUrl}),
- thumbImage: tile.thumbImage,
- thumbImageDescription: this.props.intl.formatMessage({id: tile.thumbImageDescription}),
- title: this.props.intl.formatMessage({id: tile.title}),
- cardsUrl: this.props.intl.formatMessage({id: tile.cardsUrl})
- };
- return (
- { // eslint-disable-line react/jsx-no-bind
- this.handleShowTTTModal(translatedTile);
- }}
- {...translatedTile}
+];
+
+const playlists = {
+ 'sprites-and-vectors': 'ideas.spritesAndVector',
+ 'tips-and-tricks': 'ideas.tipsAndTricks',
+ 'advanced-topics': 'ideas.advancedTopics'
+};
+
+const Ideas = () => {
+ const intl = useIntl();
+ const [youtubeVideoId, setYoutubeVideoId] = useState('');
+ const [isCardsModalOpen, setCardsModalOpen] = useState(false);
+
+ const onCloseVideoModal = useCallback(() => setYoutubeVideoId(''), [setYoutubeVideoId]);
+ const onSelectedVideo = useCallback(
+ videoId => setYoutubeVideoId(videoId),
+ [setYoutubeVideoId]
+ );
+
+ const onCardsModalOpen = useCallback(() => setCardsModalOpen(true), [isCardsModalOpen]);
+ const onCardsModalClose = useCallback(() => setCardsModalOpen(false), [isCardsModalOpen]);
+
+ return (
+