From 4afe3451f2a439e6a963efa8a2933e132589b5a8 Mon Sep 17 00:00:00 2001 From: Kaloyan Manolov Date: Mon, 28 Oct 2024 11:24:44 +0200 Subject: [PATCH 1/7] feat: uepr-38: implement debugging modal with text topics --- .../components/debug-modal/debug-modal.css | 149 +++++++++ .../components/debug-modal/debug-modal.jsx | 140 +++++++++ .../icons/icon--add-sound-checkpoints.svg | 14 + .../debug-modal/icons/icon--ask-for-help.svg | 82 +++++ .../debug-modal/icons/icon--break-it-down.svg | 44 +++ .../icons/icon--check-code-sequence.svg | 34 ++ .../icons/icon--check-the-values.svg | 20 ++ .../debug-modal/icons/icon--close.svg | 4 + .../icons/icon--comment-your-code.svg | 16 + .../icons/icon--debug-inverted.svg | 3 + .../debug-modal/icons/icon--debug.svg | 3 + .../debug-modal/icons/icon--next.svg | 18 ++ .../debug-modal/icons/icon--prev.svg | 18 ++ .../debug-modal/icons/icon--read-aloud.svg | 18 ++ .../debug-modal/icons/icon--slow-it-down.svg | 32 ++ .../debug-modal/icons/icon--take-a-break.svg | 100 ++++++ .../icons/icon--think-about-block-options.svg | 28 ++ .../icons/icon--timing-and-parallelism.svg | 69 ++++ .../icons/icon--tinker-with-block-order.svg | 29 ++ .../icons/icon--to-loop-or-not.svg | 99 ++++++ .../debug-modal/sections/messages.ts | 296 ++++++++++++++++++ .../debug-modal/sections/sections.jsx | 131 ++++++++ .../scratch-gui/src/components/gui/gui.jsx | 9 + .../src/components/menu-bar/menu-bar.css | 8 +- .../src/components/menu-bar/menu-bar.jsx | 25 +- packages/scratch-gui/src/containers/gui.jsx | 5 +- packages/scratch-gui/src/css/colors.css | 3 + packages/scratch-gui/src/reducers/modals.js | 10 + 28 files changed, 1402 insertions(+), 5 deletions(-) create mode 100644 packages/scratch-gui/src/components/debug-modal/debug-modal.css create mode 100644 packages/scratch-gui/src/components/debug-modal/debug-modal.jsx create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--add-sound-checkpoints.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--ask-for-help.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--break-it-down.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--check-code-sequence.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--check-the-values.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--close.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--comment-your-code.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--debug-inverted.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--debug.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--next.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--prev.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--read-aloud.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--slow-it-down.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--take-a-break.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--think-about-block-options.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--timing-and-parallelism.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--tinker-with-block-order.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/icons/icon--to-loop-or-not.svg create mode 100644 packages/scratch-gui/src/components/debug-modal/sections/messages.ts create mode 100644 packages/scratch-gui/src/components/debug-modal/sections/sections.jsx diff --git a/packages/scratch-gui/src/components/debug-modal/debug-modal.css b/packages/scratch-gui/src/components/debug-modal/debug-modal.css new file mode 100644 index 0000000000..53138acb0a --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/debug-modal.css @@ -0,0 +1,149 @@ +@import "../../css/colors.css"; + +.modal-overlay { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: 'transparent'; + display: flex; + justify-content: center; + align-items: center; + z-index: 510; +} + +.modal-container { + background: white; + border-radius: 8px; + width: 1000px; + max-height: 90%; + display: flex; + flex-direction: column; + position: relative; + overflow-x: visible; + box-shadow: 0 4px 4px 0 $ui-black-transparent-10; +} + +.modal-header { + display: flex; + border-radius: 8px 8px 0 0; + justify-content: space-between; + align-items: center; + padding: 10px; + background-color: $ui-green; +} + +.header-title { + display: flex; + gap: 8px; + align-items: center; + font-size: 1rem; + line-height: 1.25rem; + font-weight: 700; + color: white; +} +.debug-icon { + height: 22px; + width: 22px; +} + +.hidden { + display: none; +} + +.close-button { + display: flex; + background: none; + border: none; + cursor: pointer; + width: 32px; + height: 32px; +} + +.modal-content { + display: flex; + width: 100%; + flex-grow: 1; + overflow-y: scroll; +} + +.previousIcon { + position: absolute; + cursor: pointer; + top: 50%; +} + +.nextIcon { + position: absolute; + cursor: pointer; + right: -30px; + top: 50%; +} + +.topic-list { + width: 30%; + border-right: 1px solid $ui-green;; +} + +.topic-item { + display: flex; + gap: 8px; + align-items: center; + padding: 10px; + font-size: 1rem; + line-height: 1.5rem; + color: $ui-green;; + cursor: pointer; +} + +.topic-item.active { + background-color: #D1FAEE; + font-weight: bold; +} + +.info-container { + flex-direction: column; + width: 70%; + display: flex; + padding: 20px; + color: $text-primary; +} + +.text-container { + flex: 1; + margin-left: 70px; +} + +.title-text { + font-size: 24px; + line-height: 32px; + font-weight: 700; +} + +.description { + font-size: 16px; + line-height: 28px; +} + +.imageContainer { + display: flex; + justify-content: center; + align-items: center; + padding: 10px; + margin-top: 10px; +} + +.topicImage { + max-width: 100%; + max-height: 100%; + object-fit: contain; /* Ensures image scales proportionally */ +} + +.navigation-buttons { + margin-top: 20px; +} + +button { + margin: 5px; +} \ No newline at end of file diff --git a/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx b/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx new file mode 100644 index 0000000000..a77a49e514 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx @@ -0,0 +1,140 @@ +import React, {useState, useCallback} from 'react'; +import {defineMessages, FormattedMessage} from 'react-intl'; +import PropTypes from 'prop-types'; +import ReactModal from 'react-modal'; +import classNames from 'classnames'; +import {sections} from './sections/sections'; + +import styles from './debug-modal.css'; +import debugIcon from './icons/icon--debug.svg'; +import debugIconInverted from './icons/icon--debug-inverted.svg'; +import closeIcon from './icons/icon--close.svg'; +import prevIcon from './icons/icon--prev.svg'; +import nextIcon from './icons/icon--next.svg'; + +const messages = defineMessages({ + title: { + id: 'gui.debugModal.title', + defaultMessage: 'Debugging | Getting Unstuck', + description: 'title for the debugging modal' + } +}); + +const DebugModal = ({isOpen, onClose = () => {}}) => { + const [selectedTopicIndex, setSelectedTopicIndex] = useState(0); + + const handleNext = useCallback(() => { + if (selectedTopicIndex < sections.length - 1) { + setSelectedTopicIndex(selectedTopicIndex + 1); + } + }, [selectedTopicIndex, setSelectedTopicIndex]); + + const handlePrevious = useCallback(() => { + if (selectedTopicIndex > 0) { + setSelectedTopicIndex(selectedTopicIndex - 1); + } + }, [selectedTopicIndex, setSelectedTopicIndex]); + + const handleTopicSelect = useCallback(index => { + setSelectedTopicIndex(index); + }, [setSelectedTopicIndex]); + + if (!isOpen) return null; + + return ( + +
+
+ + +
+ +
+
+
+ {sections.map((section, index) => ( +
handleTopicSelect(index)} + > +
+ +
+ +
+ ))} +
+
+
+
+ +
+
{sections[selectedTopicIndex].description}
+
+
+ +
+
+ Previous + Next +
+
+
+
+ ); +}; + +DebugModal.propTypes = { + isOpen: PropTypes.bool, + onClose: PropTypes.func +}; + +export default DebugModal; diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--add-sound-checkpoints.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--add-sound-checkpoints.svg new file mode 100644 index 0000000000..4b6f65bfe0 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--add-sound-checkpoints.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--ask-for-help.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--ask-for-help.svg new file mode 100644 index 0000000000..1f59b54731 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--ask-for-help.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--break-it-down.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--break-it-down.svg new file mode 100644 index 0000000000..7d1d104223 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--break-it-down.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--check-code-sequence.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--check-code-sequence.svg new file mode 100644 index 0000000000..f458487e17 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--check-code-sequence.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--check-the-values.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--check-the-values.svg new file mode 100644 index 0000000000..9918a57b89 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--check-the-values.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--close.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--close.svg new file mode 100644 index 0000000000..e12cf933df --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--close.svg @@ -0,0 +1,4 @@ + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--comment-your-code.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--comment-your-code.svg new file mode 100644 index 0000000000..6f2acd9bd9 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--comment-your-code.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--debug-inverted.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--debug-inverted.svg new file mode 100644 index 0000000000..1c9a1d4ab4 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--debug-inverted.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--debug.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--debug.svg new file mode 100644 index 0000000000..6d19217991 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--debug.svg @@ -0,0 +1,3 @@ + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--next.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--next.svg new file mode 100644 index 0000000000..f2a10ae158 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--next.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--prev.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--prev.svg new file mode 100644 index 0000000000..ddf932d030 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--prev.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--read-aloud.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--read-aloud.svg new file mode 100644 index 0000000000..e6a9866070 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--read-aloud.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--slow-it-down.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--slow-it-down.svg new file mode 100644 index 0000000000..e5c04a9af6 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--slow-it-down.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--take-a-break.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--take-a-break.svg new file mode 100644 index 0000000000..37b973b88f --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--take-a-break.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--think-about-block-options.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--think-about-block-options.svg new file mode 100644 index 0000000000..1896cdddd8 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--think-about-block-options.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--timing-and-parallelism.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--timing-and-parallelism.svg new file mode 100644 index 0000000000..fbbf09c338 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--timing-and-parallelism.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--tinker-with-block-order.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--tinker-with-block-order.svg new file mode 100644 index 0000000000..406ab56427 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--tinker-with-block-order.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/icons/icon--to-loop-or-not.svg b/packages/scratch-gui/src/components/debug-modal/icons/icon--to-loop-or-not.svg new file mode 100644 index 0000000000..25787b6bcb --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/icons/icon--to-loop-or-not.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/scratch-gui/src/components/debug-modal/sections/messages.ts b/packages/scratch-gui/src/components/debug-modal/sections/messages.ts new file mode 100644 index 0000000000..72c2acdc0e --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/sections/messages.ts @@ -0,0 +1,296 @@ +import {defineMessages} from 'react-intl'; + +export const messages = defineMessages({ + readAloudTitle: { + id: 'gui.debugModal.readAloud.title', + defaultMessage: 'Read Aloud', + description: 'title for the "read aloud" section' + }, + readAloudDescription1: { + id: 'gui.debugModal.readAloud.description1', + defaultMessage: 'As you read your code aloud, think from the computer’s perspective.', + description: 'description for the "read aloud" section of the debug modal' + }, + readAloudDescription2: { + id: 'gui.debugModal.readAloud.description2', + defaultMessage: 'Are you including steps that aren’t there?', + description: 'description for the "read aloud" section of the debug modal' + }, + readAloudDescription3: { + id: 'gui.debugModal.readAloud.description3', + defaultMessage: 'Are your instructions clear?', + description: 'description for the "read aloud" section of the debug modal' + }, + readAloudDescription4: { + id: 'gui.debugModal.readAloud.description4', + defaultMessage: + 'If something needs to be reset each time the program has run, are those instructions included?', + description: 'description for the "read aloud" section of the debug modal' + }, + breakItDownTitle: { + id: 'gui.debugModal.breakItDown.title', + defaultMessage: 'Break It Down', + description: 'title for the "break it down" section' + }, + breakItDownDescription1: { + id: 'gui.debugModal.breakItDown.description1', + defaultMessage: + 'Separate the blocks into smaller chunks (or sequences), and click to see what each sequence does.', + description: 'description for the "break it down" section of the debug modal' + }, + breakItDownDescription2: { + id: 'gui.debugModal.breakItDown.description2', + defaultMessage: + 'Once the smaller sequences work as you expect, add them back into the main program.', + description: 'description for the "break it down" section of the debug modal' + }, + breakItDownDescription3: { + id: 'gui.debugModal.breakItDown.description3', + defaultMessage: 'The process is called decomposition.', + description: 'description for the "break it down" section of the debug modal' + }, + slowItDownTitle: { + id: 'gui.debugModal.slowItDown.title', + defaultMessage: 'Slow It Down', + description: 'title for the "slow it down" section' + }, + slowItDownDescription1: { + id: 'gui.debugModal.slowItDown.description1', + defaultMessage: + 'The computer runs your program so quickly it can be hard to follow with your eyes.', + description: 'description for the "slow it down" section of the debug modal' + }, + slowItDownDescription2: { + id: 'gui.debugModal.slowItDown.description2', + defaultMessage: + // eslint-disable-next-line max-len + 'Add temporary “wait” or “wait until” blocks to slow down the sequence. This gives you time to process if a piece worked or not.', + description: 'description for the "slow it down" section of the debug modal' + }, + slowItDownDescription3: { + id: 'gui.debugModal.slowItDown.description3', + defaultMessage: 'Remove these wait blocks once your code works.', + description: 'description for the "slow it down" section of the debug modal' + }, + addSoundCheckpointsTitle: { + id: 'gui.debugModal.addSoundCheckpoints.title', + defaultMessage: 'Add Sound Checkpoints', + description: 'title for the "add sound checkpoints" section' + }, + addSoundCheckpointsDescription1: { + id: 'gui.debugModal.addSoundCheckpoints.description1', + defaultMessage: + // eslint-disable-next-line max-len + 'Similar to the Slow It Down strategy, you can add different sounds with the “play until done” block at key points to test your sequence.', + description: 'description for the "add sound checkpoints" section of the debug modal' + }, + addSoundCheckpointsDescription2: { + id: 'gui.debugModal.addSoundCheckpoints.description2', + defaultMessage: + // eslint-disable-next-line max-len + 'If a sound doesn’t play, your bug may be before this block. If the sound plays, the bug is probably after this block.', + description: 'description for the "add sound checkpoints" section of the debug modal' + }, + addSoundCheckpointsDescription3: { + id: 'gui.debugModal.addSoundCheckpoints.description3', + defaultMessage: 'Remove the sounds once your code works.', + description: 'description for the "add sound checkpoints" section of the debug modal' + }, + tinkerWithBlockOrderTitle: { + id: 'gui.debugModal.tinkerWithBlockOrder.title', + defaultMessage: 'Tinker with Block Order', + description: 'title for the "tinker with block order" section' + }, + tinkerWithBlockOrderDescription1: { + id: 'gui.debugModal.tinkerWithBlockOrder.description1', + defaultMessage: 'Try adjusting the order/sequence of the blocks.', + description: 'description for the "tinker with block order" section of the debug modal' + }, + tinkerWithBlockOrderDescription2: { + id: 'gui.debugModal.tinkerWithBlockOrder.description2', + defaultMessage: 'What needs to happen first?', + description: 'description for the "tinker with block order" section of the debug modal' + }, + tinkerWithBlockOrderDescription3: { + id: 'gui.debugModal.tinkerWithBlockOrder.description3', + defaultMessage: 'What happens second?', + description: 'description for the "tinker with block order" section of the debug modal' + }, + tinkerWithBlockOrderDescription4: { + id: 'gui.debugModal.tinkerWithBlockOrder.description4', + defaultMessage: 'Do values or sprites need to reset before the next piece of code runs?', + description: 'description for the "tinker with block order" section of the debug modal' + }, + tinkerWithBlockOrderDescription5: { + id: 'gui.debugModal.tinkerWithBlockOrder.description5', + defaultMessage: + 'Try using blocks inside a loop or conditional statement, versus outside a loop or conditional statement.', + description: 'description for the "tinker with block order" section of the debug modal' + }, + toLoopOrNotTitle: { + id: 'gui.debugModal.toLoopOrNot.title', + defaultMessage: 'To Loop or Not to Loop', + description: 'title for the "tinker with block order" section' + }, + toLoopOrNotDescription1: { + id: 'gui.debugModal.toLoopOrNot.description1', + defaultMessage: + // eslint-disable-next-line max-len + 'If using Control blocks like "forever" and "repeat", check that all blocks inside a loop should be there, or if a block (like “wait”) is missing to reset the action or adjust the timing. Do you want your loop to run forever or for a certain number of times? Should something stop the looping?', + description: 'description for the "to loop or not to loop" section of the debug modal' + }, + toLoopOrNotDescription2: { + id: 'gui.debugModal.toLoopOrNot.description2', + defaultMessage: + // eslint-disable-next-line max-len + 'Perhaps you aren\'t using a loop when you should be? For instance, if you are using a conditional statement block like "if then," does the program only need to check if it is true or false once? Or does it need to check continuously, in which case, you would want to place your conditional statement inside a forever loop?', + description: 'description for the "to loop or not to loop" section of the debug modal' + }, + timingAndParallelismTitle: { + id: 'gui.debugModal.timingAndParallelism.title', + defaultMessage: 'Think About Timing & Parallelism', + description: 'title for the "think about timing and parallelism" section' + }, + timingAndParallelismSectionTitle: { + id: 'gui.debugModal.timingAndParallelism.sectionTitle', + defaultMessage: 'Timing & Parallelism', + description: 'title for the "think about timing and parallelism" sidebar section' + }, + timingAndParallelismDescription1: { + id: 'gui.debugModal.timingAndParallelism.description1', + defaultMessage: + // eslint-disable-next-line max-len + 'Do you have multiple events trying to run at the same time? If two sequences are programmed to start at the same time, you can get unpredictable behavior.', + description: 'description for the "think about timing and parallelism" section of the debug modal' + }, + timingAndParallelismDescription2: { + id: 'gui.debugModal.timingAndParallelism.description2', + defaultMessage: + // eslint-disable-next-line max-len + 'Add small waits, broadcasts, or user interaction (like clicking or pressing a key) to see if this affects the result.', + description: 'description for the "think about timing and parallelism" section of the debug modal' + }, + thinkAboutBlockOptionsTitle: { + id: 'gui.debugModal.thinkAboutBlockOptions.title', + defaultMessage: 'Think About Block Options', + description: 'title for the "think about block options" section' + }, + thinkAboutBlockOptionsDescription1: { + id: 'gui.debugModal.thinkAboutBlockOptions.description1', + defaultMessage: 'Is there a similar but different block you can use?', + description: 'description for the "think about block options" section of the debug modal' + }, + thinkAboutBlockOptionsDescription2: { + id: 'gui.debugModal.thinkAboutBlockOptions.description2', + defaultMessage: + // eslint-disable-next-line max-len + 'Some blocks look similar but can behave differently, such as “set” vs “change” or “play until done” vs “start.”', + description: 'description for the "think about block options" section of the debug modal' + }, + thinkAboutBlockOptionsDescription3: { + id: 'gui.debugModal.thinkAboutBlockOptions.description3', + defaultMessage: 'Try using a similar block in place of what you have, and see if this affects the result.', + description: 'description for the "think about block options" section of the debug modal' + }, + checkTheValuesTitle: { + id: 'gui.debugModal.checkTheValues.title', + defaultMessage: 'Check the Values', + description: 'title for the "check the value" section' + }, + checkTheValuesDescription1: { + id: 'gui.debugModal.checkTheValues.description1', + defaultMessage: + 'If you are using variables or reporter blocks, check the value at the moment the code sequence is run.', + description: 'description for the "check the values" section of the debug modal' + }, + checkTheValuesDescription2: { + id: 'gui.debugModal.checkTheValues.description2', + defaultMessage: 'Do/should all the sprites control a variable, or should only one sprite have control?', + description: 'description for the "check the values" section of the debug modal' + }, + checkTheValuesDescription3: { + id: 'gui.debugModal.checkTheValues.description3', + defaultMessage: 'Where is the value reset? Where is it changed?', + description: 'description for the "check the values" section of the debug modal' + }, + checkCodeSequenceTitle: { + id: 'gui.debugModal.checkCodeSequence.title', + defaultMessage: 'Check Code Sequence', + description: 'title for the "check code sequence" section' + }, + checkCodeSequenceDescription1: { + id: 'gui.debugModal.checkCodeSequence.description1', + defaultMessage: + 'Check that your code sequence is attached to the correct sprite or the backdrop, if appropriate.', + description: 'description for the "check code sequence" section of the debug modal' + }, + checkCodeSequenceDescription2: { + id: 'gui.debugModal.checkCodeSequence.description2', + defaultMessage: + // eslint-disable-next-line max-len + 'If you need to move your code to another sprite, click and drag it until you are hovering over the correct sprite. Release it once the sprite wiggles.', + description: 'description for the "check code sequence" section of the debug modal' + }, + checkCodeSequenceDescription3: { + id: 'gui.debugModal.checkCodeSequence.description3', + defaultMessage: + 'You can also use your Backpack (bottom of screen) to store and move your code or assets.', + description: 'description for the "check code sequence" section of the debug modal' + }, + commentYourCodeTitle: { + id: 'gui.debugModal.commentYourCode.title', + defaultMessage: 'Comment Your Code', + description: 'title for the "comment your code" section' + }, + commentYourCodeDescription1: { + id: 'gui.debugModal.commentYourCode.description1', + defaultMessage: + // eslint-disable-next-line max-len + 'Adding comments to your code can help others looking at your code to understand it. It can also help you remember how your code works when you come back to it later.', + description: 'description for the "comment your code" section of the debug modal' + }, + commentYourCodeDescription2: { + id: 'gui.debugModal.commentYourCode.description2', + defaultMessage: + // eslint-disable-next-line max-len + 'Right click on script area to “Add Comment.” Use everyday language to explain what a block, or small sequence of blocks, does.', + description: 'description for the "comment your code" section of the debug modal' + }, + takeABreakTitle: { + id: 'gui.debugModal.takeABreak.title', + defaultMessage: 'Take a Break, Step Away', + description: 'title for the "take a break" section' + }, + takeABreakDescription1: { + id: 'gui.debugModal.takeABreak.description1', + defaultMessage: + 'Sometimes, spending too much time focused on an issue can be counterproductive and frustrating.', + description: 'description for the "take a break, step away" section of the debug modal' + }, + takeABreakDescription2: { + id: 'gui.debugModal.takeABreak.description2', + defaultMessage: + // eslint-disable-next-line max-len + 'Take a break and step away from the screen to clear your mind. After some rest, focusing on something else, or getting some water, you can approach the problem with fresh eyes.', + description: 'description for the "take a break, step away" section of the debug modal' + }, + askForHelpTitle: { + id: 'gui.debugModal.askForHelp.title', + defaultMessage: 'Ask for Help', + description: 'title for the "ask for help" section' + }, + askForHelpDescription1: { + id: 'gui.debugModal.askForHelp.description1', + defaultMessage: + // eslint-disable-next-line max-len + 'If you are still stuck, you can ask for help from a peer. Try finding a debugging/help studio and share your project, asking for help in a comment or the project notes.', + description: 'description for the "ask for help" section of the debug modal' + }, + askForHelpDescription2: { + id: 'gui.debugModal.askForHelp.description2', + defaultMessage: + // eslint-disable-next-line max-len + 'Ask one to three people to try your code, as different people may have different perspectives or solutions!', + description: 'description for the "ask for help" section of the debug modal' + } +}); diff --git a/packages/scratch-gui/src/components/debug-modal/sections/sections.jsx b/packages/scratch-gui/src/components/debug-modal/sections/sections.jsx new file mode 100644 index 0000000000..c706b46756 --- /dev/null +++ b/packages/scratch-gui/src/components/debug-modal/sections/sections.jsx @@ -0,0 +1,131 @@ +import React from 'react'; +import {FormattedMessage} from 'react-intl'; +import {messages} from './messages.ts'; + +import addSoundCheckpoints from '../icons/icon--add-sound-checkpoints.svg'; +import askForHelp from '../icons/icon--ask-for-help.svg'; +import breakItDown from '../icons/icon--break-it-down.svg'; +import checkCodeSequence from '../icons/icon--check-code-sequence.svg'; +import checkTheValues from '../icons/icon--check-the-values.svg'; +import commentYourCode from '../icons/icon--comment-your-code.svg'; +import readAloud from '../icons/icon--read-aloud.svg'; +import slowItDown from '../icons/icon--slow-it-down.svg'; +import takeABreak from '../icons/icon--take-a-break.svg'; +import thinkAboutBlockOptions from '../icons/icon--think-about-block-options.svg'; +import timingAndParallelism from '../icons/icon--timing-and-parallelism.svg'; +import tinkerWithBlockOrder from '../icons/icon--tinker-with-block-order.svg'; +import toLoopOrNotToLoop from '../icons/icon--to-loop-or-not.svg'; + + +export const sections = [ + { + title: messages.readAloudTitle, + description:
+

+ +
, + image: readAloud + }, { + title: messages.breakItDownTitle, + description: (
+

+

+

+
), + image: breakItDown + }, { + title: messages.slowItDownTitle, + description: (
+

+

+

+
), + image: slowItDown + }, { + title: messages.addSoundCheckpointsTitle, + description: (
+

+

+

+
), + image: addSoundCheckpoints + }, { + title: messages.tinkerWithBlockOrderTitle, + description:
+

+ +

+
, + image: tinkerWithBlockOrder + }, { + title: messages.toLoopOrNotTitle, + description: (
+

+

+
), + image: toLoopOrNotToLoop + }, { + title: messages.timingAndParallelismTitle, + sectionTitle: messages.timingAndParallelismSectionTitle, + description: (
+

+

+
), + image: timingAndParallelism + }, { + title: messages.thinkAboutBlockOptionsTitle, + description: (
+

+

+

+
), + image: thinkAboutBlockOptions + }, { + title: messages.checkTheValuesTitle, + description:
+

+ +
, + image: checkTheValues + }, { + title: messages.checkCodeSequenceTitle, + description:
+

+

+

+
, + image: checkCodeSequence + }, { + title: messages.commentYourCodeTitle, + description:
+

+

+
, + image: commentYourCode + }, { + title: messages.takeABreakTitle, + description:
+

+

+
, + image: takeABreak + }, { + title: messages.askForHelpTitle, + description:
+

+

+
, + image: askForHelp + } +]; diff --git a/packages/scratch-gui/src/components/gui/gui.jsx b/packages/scratch-gui/src/components/gui/gui.jsx index cb7b4be34f..fe87173f55 100644 --- a/packages/scratch-gui/src/components/gui/gui.jsx +++ b/packages/scratch-gui/src/components/gui/gui.jsx @@ -40,6 +40,7 @@ import addExtensionIcon from './icon--extensions.svg'; import codeIcon from './icon--code.svg'; import costumesIcon from './icon--costumes.svg'; import soundsIcon from './icon--sounds.svg'; +import DebugModal from '../debug-modal/debug-modal.jsx'; const messages = defineMessages({ addExtension: { @@ -82,6 +83,7 @@ const GUIComponent = props => { connectionModalVisible, costumeLibraryVisible, costumesTabVisible, + debugModalVisible, enableCommunity, intl, isCreating, @@ -108,6 +110,7 @@ const GUIComponent = props => { onProjectTelemetryEvent, onRequestCloseBackdropLibrary, onRequestCloseCostumeLibrary, + onRequestCloseDebugModal, onRequestCloseTelemetryModal, onSeeCommunity, onShare, @@ -205,6 +208,10 @@ const GUIComponent = props => { onRequestClose={onRequestCloseCostumeLibrary} /> ) : null} + {} {backdropLibraryVisible ? (
+
+ + + + +
@@ -900,6 +919,7 @@ MenuBar.propTypes = { onLogOut: PropTypes.func, onOpenRegistration: PropTypes.func, onOpenTipLibrary: PropTypes.func, + onOpenDebugModal: PropTypes.func, onProjectTelemetryEvent: PropTypes.func, onRequestCloseAbout: PropTypes.func, onRequestCloseAccount: PropTypes.func, @@ -963,6 +983,7 @@ const mapStateToProps = (state, ownProps) => { const mapDispatchToProps = dispatch => ({ autoUpdateProject: () => dispatch(autoUpdateProject()), onOpenTipLibrary: () => dispatch(openTipsLibrary()), + onOpenDebugModal: () => dispatch(openDebugModal()), onClickAccount: () => dispatch(openAccountMenu()), onRequestCloseAccount: () => dispatch(closeAccountMenu()), onClickFile: () => dispatch(openFileMenu()), diff --git a/packages/scratch-gui/src/containers/gui.jsx b/packages/scratch-gui/src/containers/gui.jsx index 4a3502b849..7c7d2b1b53 100644 --- a/packages/scratch-gui/src/containers/gui.jsx +++ b/packages/scratch-gui/src/containers/gui.jsx @@ -22,7 +22,8 @@ import { closeCostumeLibrary, closeBackdropLibrary, closeTelemetryModal, - openExtensionLibrary + openExtensionLibrary, + closeDebugModal } from '../reducers/modals'; import FontLoaderHOC from '../lib/font-loader-hoc.jsx'; @@ -154,6 +155,7 @@ const mapStateToProps = state => { connectionModalVisible: state.scratchGui.modals.connectionModal, costumeLibraryVisible: state.scratchGui.modals.costumeLibrary, costumesTabVisible: state.scratchGui.editorTab.activeTabIndex === COSTUMES_TAB_INDEX, + debugModalVisible: state.scratchGui.modals.debugModal, error: state.scratchGui.projectState.error, isError: getIsError(loadingState), isFullScreen: state.scratchGui.mode.isFullScreen, @@ -180,6 +182,7 @@ const mapDispatchToProps = dispatch => ({ onActivateSoundsTab: () => dispatch(activateTab(SOUNDS_TAB_INDEX)), onRequestCloseBackdropLibrary: () => dispatch(closeBackdropLibrary()), onRequestCloseCostumeLibrary: () => dispatch(closeCostumeLibrary()), + onRequestCloseDebugModal: () => dispatch(closeDebugModal()), onRequestCloseTelemetryModal: () => dispatch(closeTelemetryModal()) }); diff --git a/packages/scratch-gui/src/css/colors.css b/packages/scratch-gui/src/css/colors.css index d5ae6f1a68..058c078a10 100644 --- a/packages/scratch-gui/src/css/colors.css +++ b/packages/scratch-gui/src/css/colors.css @@ -10,6 +10,9 @@ $ui-white-transparent: hsla(0, 100%, 100%, 0.25); /* 25% transparent version of $ui-transparent: hsla(0, 100%, 100%, 0); /* 25% transparent version of ui-white */ $ui-black-transparent: hsla(0, 0%, 0%, 0.15); /* 15% transparent version of black */ +$ui-black-transparent-10: hsla(0, 0%, 0%, 0.10); /* 10% transparent version of black */ + +$ui-green: hsla(163, 85%, 35%, 1); /* #0DA57A */ $text-primary: hsla(225, 15%, 40%, 1); /* #575E75 */ $text-primary-transparent: hsla(225, 15%, 40%, 0.75); diff --git a/packages/scratch-gui/src/reducers/modals.js b/packages/scratch-gui/src/reducers/modals.js index 2e69bf8ba7..5bec3699a1 100644 --- a/packages/scratch-gui/src/reducers/modals.js +++ b/packages/scratch-gui/src/reducers/modals.js @@ -3,6 +3,7 @@ const CLOSE_MODAL = 'scratch-gui/modals/CLOSE_MODAL'; const MODAL_BACKDROP_LIBRARY = 'backdropLibrary'; const MODAL_COSTUME_LIBRARY = 'costumeLibrary'; +const MODAL_DEBUG = 'debugModal'; const MODAL_EXTENSION_LIBRARY = 'extensionLibrary'; const MODAL_LOADING_PROJECT = 'loadingProject'; const MODAL_TELEMETRY = 'telemetryModal'; @@ -15,6 +16,7 @@ const MODAL_TIPS_LIBRARY = 'tipsLibrary'; const initialState = { [MODAL_BACKDROP_LIBRARY]: false, [MODAL_COSTUME_LIBRARY]: false, + [MODAL_DEBUG]: false, [MODAL_EXTENSION_LIBRARY]: false, [MODAL_LOADING_PROJECT]: false, [MODAL_TELEMETRY]: false, @@ -58,6 +60,9 @@ const openBackdropLibrary = function () { const openCostumeLibrary = function () { return openModal(MODAL_COSTUME_LIBRARY); }; +const openDebugModal = function () { + return openModal(MODAL_DEBUG); +}; const openExtensionLibrary = function () { return openModal(MODAL_EXTENSION_LIBRARY); }; @@ -88,6 +93,9 @@ const closeBackdropLibrary = function () { const closeCostumeLibrary = function () { return closeModal(MODAL_COSTUME_LIBRARY); }; +const closeDebugModal = function () { + return closeModal(MODAL_DEBUG); +}; const closeExtensionLibrary = function () { return closeModal(MODAL_EXTENSION_LIBRARY); }; @@ -117,6 +125,7 @@ export { initialState as modalsInitialState, openBackdropLibrary, openCostumeLibrary, + openDebugModal, openExtensionLibrary, openLoadingProject, openSoundLibrary, @@ -127,6 +136,7 @@ export { openConnectionModal, closeBackdropLibrary, closeCostumeLibrary, + closeDebugModal, closeExtensionLibrary, closeLoadingProject, closeSpriteLibrary, From 341acc3a0f9e71721d62cec8597eacdab209b877 Mon Sep 17 00:00:00 2001 From: Kaloyan Manolov Date: Mon, 28 Oct 2024 13:13:09 +0200 Subject: [PATCH 2/7] feat: uepr-80: Add analytics events --- .../components/debug-modal/debug-modal.jsx | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx b/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx index a77a49e514..f68f292bfe 100644 --- a/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx +++ b/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx @@ -1,9 +1,10 @@ -import React, {useState, useCallback} from 'react'; +import React, {useState, useCallback, useEffect} from 'react'; import {defineMessages, FormattedMessage} from 'react-intl'; import PropTypes from 'prop-types'; import ReactModal from 'react-modal'; import classNames from 'classnames'; import {sections} from './sections/sections'; +import GA4 from '../../lib/analytics'; import styles from './debug-modal.css'; import debugIcon from './icons/icon--debug.svg'; @@ -20,31 +21,57 @@ const messages = defineMessages({ } }); +const logTopicChange = topicIndex => { + GA4.event({ + category: 'change_topic_debug_modal', + label: topicIndex + }); +}; + const DebugModal = ({isOpen, onClose = () => {}}) => { const [selectedTopicIndex, setSelectedTopicIndex] = useState(0); const handleNext = useCallback(() => { if (selectedTopicIndex < sections.length - 1) { setSelectedTopicIndex(selectedTopicIndex + 1); + logTopicChange(selectedTopicIndex + 1); } }, [selectedTopicIndex, setSelectedTopicIndex]); const handlePrevious = useCallback(() => { if (selectedTopicIndex > 0) { setSelectedTopicIndex(selectedTopicIndex - 1); + logTopicChange(selectedTopicIndex - 1); } }, [selectedTopicIndex, setSelectedTopicIndex]); const handleTopicSelect = useCallback(index => { setSelectedTopicIndex(index); + logTopicChange(index); }, [setSelectedTopicIndex]); + const handleClose = useCallback(() => { + GA4.event({ + category: 'close_debug_modal' + }); + onClose(); + }, [onClose]); + + useEffect(() => { + if (isOpen) { + console.log('==opened debug modal'); + GA4.event({ + category: 'open_debug_modal' + }); + } + }, [isOpen]); + if (!isOpen) return null; return ( From 6c62fca8bfd1fae9de92107cdfc01e3dc350c629 Mon Sep 17 00:00:00 2001 From: Kaloyan Manolov Date: Mon, 28 Oct 2024 13:21:39 +0200 Subject: [PATCH 3/7] fix: uepr-80: remove console log --- packages/scratch-gui/src/components/debug-modal/debug-modal.jsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx b/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx index f68f292bfe..11395b2904 100644 --- a/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx +++ b/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx @@ -59,7 +59,6 @@ const DebugModal = ({isOpen, onClose = () => {}}) => { useEffect(() => { if (isOpen) { - console.log('==opened debug modal'); GA4.event({ category: 'open_debug_modal' }); From 5cfba7cb10510b5b9d72470477d47e09a799e2bd Mon Sep 17 00:00:00 2001 From: Kaloyan Manolov Date: Mon, 28 Oct 2024 16:47:31 +0200 Subject: [PATCH 4/7] fix: uepr-80: Fix GTM initialisation in gui --- .../components/debug-modal/debug-modal.jsx | 2 +- packages/scratch-gui/src/lib/analytics.js | 40 ------------------- packages/scratch-gui/src/playground/index.ejs | 15 +++++++ packages/scratch-gui/webpack.config.js | 11 ++++- 4 files changed, 26 insertions(+), 42 deletions(-) diff --git a/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx b/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx index 11395b2904..8ef64697af 100644 --- a/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx +++ b/packages/scratch-gui/src/components/debug-modal/debug-modal.jsx @@ -86,7 +86,7 @@ const DebugModal = ({isOpen, onClose = () => {}}) => {