From f2adf68789d35b29c44acf971d1b4c9f294dfb9b Mon Sep 17 00:00:00 2001 From: Kaloyan Manolov Date: Fri, 1 Nov 2024 11:06:55 +0200 Subject: [PATCH 1/6] feat: uepr-38: debug modal changes --- src/components/debug-modal/debug-modal.css | 149 +++++++++ src/components/debug-modal/debug-modal.jsx | 167 ++++++++++ .../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 | 144 +++++++++ src/components/gui/gui.jsx | 13 +- src/components/menu-bar/menu-bar.css | 8 +- src/components/menu-bar/menu-bar.jsx | 27 +- src/containers/gui.jsx | 7 +- src/css/colors.css | 3 + src/lib/analytics.js | 40 --- src/playground/index.ejs | 15 + src/reducers/modals.js | 10 + webpack.config.js | 52 ++- 31 files changed, 1506 insertions(+), 56 deletions(-) create mode 100644 src/components/debug-modal/debug-modal.css create mode 100644 src/components/debug-modal/debug-modal.jsx create mode 100644 src/components/debug-modal/icons/icon--add-sound-checkpoints.svg create mode 100644 src/components/debug-modal/icons/icon--ask-for-help.svg create mode 100644 src/components/debug-modal/icons/icon--break-it-down.svg create mode 100644 src/components/debug-modal/icons/icon--check-code-sequence.svg create mode 100644 src/components/debug-modal/icons/icon--check-the-values.svg create mode 100644 src/components/debug-modal/icons/icon--close.svg create mode 100644 src/components/debug-modal/icons/icon--comment-your-code.svg create mode 100644 src/components/debug-modal/icons/icon--debug-inverted.svg create mode 100644 src/components/debug-modal/icons/icon--debug.svg create mode 100644 src/components/debug-modal/icons/icon--next.svg create mode 100644 src/components/debug-modal/icons/icon--prev.svg create mode 100644 src/components/debug-modal/icons/icon--read-aloud.svg create mode 100644 src/components/debug-modal/icons/icon--slow-it-down.svg create mode 100644 src/components/debug-modal/icons/icon--take-a-break.svg create mode 100644 src/components/debug-modal/icons/icon--think-about-block-options.svg create mode 100644 src/components/debug-modal/icons/icon--timing-and-parallelism.svg create mode 100644 src/components/debug-modal/icons/icon--tinker-with-block-order.svg create mode 100644 src/components/debug-modal/icons/icon--to-loop-or-not.svg create mode 100644 src/components/debug-modal/sections/messages.ts create mode 100644 src/components/debug-modal/sections/sections.jsx diff --git a/src/components/debug-modal/debug-modal.css b/src/components/debug-modal/debug-modal.css new file mode 100644 index 00000000000..53138acb0a4 --- /dev/null +++ b/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/src/components/debug-modal/debug-modal.jsx b/src/components/debug-modal/debug-modal.jsx new file mode 100644 index 00000000000..924556daac4 --- /dev/null +++ b/src/components/debug-modal/debug-modal.jsx @@ -0,0 +1,167 @@ +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'; +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 logTopicChange = topicIndex => { + GA4.event({ + category: 'change_topic_debug_modal', + label: sections[topicIndex].id + }); +}; + +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) { + GA4.event({ + category: 'open_debug_modal', + label: sections[selectedTopicIndex].id + }); + } + }, [isOpen]); + + 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/src/components/debug-modal/icons/icon--add-sound-checkpoints.svg b/src/components/debug-modal/icons/icon--add-sound-checkpoints.svg new file mode 100644 index 00000000000..4b6f65bfe0d --- /dev/null +++ b/src/components/debug-modal/icons/icon--add-sound-checkpoints.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--ask-for-help.svg b/src/components/debug-modal/icons/icon--ask-for-help.svg new file mode 100644 index 00000000000..1f59b547318 --- /dev/null +++ b/src/components/debug-modal/icons/icon--ask-for-help.svg @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--break-it-down.svg b/src/components/debug-modal/icons/icon--break-it-down.svg new file mode 100644 index 00000000000..7d1d104223a --- /dev/null +++ b/src/components/debug-modal/icons/icon--break-it-down.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--check-code-sequence.svg b/src/components/debug-modal/icons/icon--check-code-sequence.svg new file mode 100644 index 00000000000..f458487e175 --- /dev/null +++ b/src/components/debug-modal/icons/icon--check-code-sequence.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--check-the-values.svg b/src/components/debug-modal/icons/icon--check-the-values.svg new file mode 100644 index 00000000000..9918a57b896 --- /dev/null +++ b/src/components/debug-modal/icons/icon--check-the-values.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--close.svg b/src/components/debug-modal/icons/icon--close.svg new file mode 100644 index 00000000000..e12cf933df8 --- /dev/null +++ b/src/components/debug-modal/icons/icon--close.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/components/debug-modal/icons/icon--comment-your-code.svg b/src/components/debug-modal/icons/icon--comment-your-code.svg new file mode 100644 index 00000000000..6f2acd9bd9c --- /dev/null +++ b/src/components/debug-modal/icons/icon--comment-your-code.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--debug-inverted.svg b/src/components/debug-modal/icons/icon--debug-inverted.svg new file mode 100644 index 00000000000..1c9a1d4ab48 --- /dev/null +++ b/src/components/debug-modal/icons/icon--debug-inverted.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/debug-modal/icons/icon--debug.svg b/src/components/debug-modal/icons/icon--debug.svg new file mode 100644 index 00000000000..6d192179918 --- /dev/null +++ b/src/components/debug-modal/icons/icon--debug.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/debug-modal/icons/icon--next.svg b/src/components/debug-modal/icons/icon--next.svg new file mode 100644 index 00000000000..f2a10ae158c --- /dev/null +++ b/src/components/debug-modal/icons/icon--next.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--prev.svg b/src/components/debug-modal/icons/icon--prev.svg new file mode 100644 index 00000000000..ddf932d0308 --- /dev/null +++ b/src/components/debug-modal/icons/icon--prev.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--read-aloud.svg b/src/components/debug-modal/icons/icon--read-aloud.svg new file mode 100644 index 00000000000..e6a98660701 --- /dev/null +++ b/src/components/debug-modal/icons/icon--read-aloud.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--slow-it-down.svg b/src/components/debug-modal/icons/icon--slow-it-down.svg new file mode 100644 index 00000000000..e5c04a9af6b --- /dev/null +++ b/src/components/debug-modal/icons/icon--slow-it-down.svg @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--take-a-break.svg b/src/components/debug-modal/icons/icon--take-a-break.svg new file mode 100644 index 00000000000..37b973b88ff --- /dev/null +++ b/src/components/debug-modal/icons/icon--take-a-break.svg @@ -0,0 +1,100 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--think-about-block-options.svg b/src/components/debug-modal/icons/icon--think-about-block-options.svg new file mode 100644 index 00000000000..1896cdddd88 --- /dev/null +++ b/src/components/debug-modal/icons/icon--think-about-block-options.svg @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--timing-and-parallelism.svg b/src/components/debug-modal/icons/icon--timing-and-parallelism.svg new file mode 100644 index 00000000000..fbbf09c3381 --- /dev/null +++ b/src/components/debug-modal/icons/icon--timing-and-parallelism.svg @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--tinker-with-block-order.svg b/src/components/debug-modal/icons/icon--tinker-with-block-order.svg new file mode 100644 index 00000000000..406ab56427d --- /dev/null +++ b/src/components/debug-modal/icons/icon--tinker-with-block-order.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/icons/icon--to-loop-or-not.svg b/src/components/debug-modal/icons/icon--to-loop-or-not.svg new file mode 100644 index 00000000000..25787b6bcb2 --- /dev/null +++ b/src/components/debug-modal/icons/icon--to-loop-or-not.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/components/debug-modal/sections/messages.ts b/src/components/debug-modal/sections/messages.ts new file mode 100644 index 00000000000..72c2acdc0e9 --- /dev/null +++ b/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/src/components/debug-modal/sections/sections.jsx b/src/components/debug-modal/sections/sections.jsx new file mode 100644 index 00000000000..6b1290c67d8 --- /dev/null +++ b/src/components/debug-modal/sections/sections.jsx @@ -0,0 +1,144 @@ +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 = [ + { + id: 'readAloud', + title: messages.readAloudTitle, + description:
+

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

+

+

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

+

+

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

+

+

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

+ +

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

+

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

+

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

+

+

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

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

+

+

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

+

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

+

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

+

+
, + image: askForHelp + } +]; diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index f48e5a6ec33..fe87173f551 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -7,8 +7,8 @@ import {connect} from 'react-redux'; import MediaQuery from 'react-responsive'; import {Tab, Tabs, TabList, TabPanel} from 'react-tabs'; import tabStyles from 'react-tabs/style/react-tabs.css'; -import VM from 'scratch-vm'; -import Renderer from 'scratch-render'; +import VM from '@scratch/scratch-vm'; +import Renderer from '@scratch/scratch-render'; import Blocks from '../../containers/blocks.jsx'; import CostumeTab from '../../containers/costume-tab.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/src/containers/gui.jsx b/src/containers/gui.jsx index 2da5c156000..7c7d2b1b533 100644 --- a/src/containers/gui.jsx +++ b/src/containers/gui.jsx @@ -3,7 +3,7 @@ import React from 'react'; import {compose} from 'redux'; import {connect} from 'react-redux'; import ReactModal from 'react-modal'; -import VM from 'scratch-vm'; +import VM from '@scratch/scratch-vm'; import {injectIntl, intlShape} from 'react-intl'; import ErrorBoundaryHOC from '../lib/error-boundary-hoc.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/src/css/colors.css b/src/css/colors.css index d5ae6f1a682..058c078a102 100644 --- a/src/css/colors.css +++ b/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/src/lib/analytics.js b/src/lib/analytics.js index d4892d75f03..e0f1d986e7d 100644 --- a/src/lib/analytics.js +++ b/src/lib/analytics.js @@ -2,46 +2,6 @@ // We now use GTM, so we could use `react-gtm-module`, but it doesn't support GTM environments (GTM_ENV_AUTH). // So we use the GTM snippets directly. -const GTM_ID = (process.env.GTM_ID || window.GTM_ID); -const GTM_ENV_AUTH = (process.env.GTM_ENV_AUTH || window.GTM_ENV_AUTH || ''); - -/** - * Build the HTML snippets to load GTM. - * Call this ONLY if GTM_ID is a valid Tag Manager ID. GTM_ENV_AUTH should be valid or an empty string. - * The content of the snippets is taken from the GTM web interface. We should check there periodically for changes. - * @returns {object} an object the GTM snippets. - * @property {string} script The snippet to load GTM when JavaScript is enabled. Add this to the element. - * @property {string} noscript The snippet to load GTM when JavaScript is disabled. Add this to the element. - */ -const makeGtmSnippets = () => ({ - script: - ` - - `, - noscript: - ` - - ` -}); - -if (GTM_ID) { - // load GTM - const snippets = makeGtmSnippets(); - - const noscript = document.createElement('noscript'); - noscript.innerHTML = snippets.noscript; - - const script = document.createElement('script'); - script.innerHTML = snippets.script; - - document.head.insertBefore(script, document.head.firstChild); - document.body.insertBefore(noscript, document.body.firstChild); -} /** * Report analytics to GA4 using an interface similar to the 'react-ga' module we were using for UA. diff --git a/src/playground/index.ejs b/src/playground/index.ejs index b789b004866..abbd5d8b024 100644 --- a/src/playground/index.ejs +++ b/src/playground/index.ejs @@ -1,6 +1,16 @@ + <% if (htmlWebpackPlugin.options.gtm_id) { %> + + + + <% } %> @@ -8,5 +18,10 @@ <%= htmlWebpackPlugin.options.title %> + <% if (htmlWebpackPlugin.options.gtm_id) { %> + + + + <% } %> diff --git a/src/reducers/modals.js b/src/reducers/modals.js index 2e69bf8ba75..5bec3699a1e 100644 --- a/src/reducers/modals.js +++ b/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, diff --git a/webpack.config.js b/webpack.config.js index 6813de1187f..5676e5e6c68 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -9,10 +9,23 @@ const ScratchWebpackConfigBuilder = require('scratch-webpack-configuration'); // const STATIC_PATH = process.env.STATIC_PATH || '/static'; +const commonHtmlWebpackPluginOptions = { + // Google Tag Manager ID + // Looks like 'GTM-XXXXXXX' + gtm_id: process.env.GTM_ID || '', + + // Google Tag Manager env & auth info for alterative GTM environments + // Looks like '>m_auth=0123456789abcdefghijklm>m_preview=env-00>m_cookies_win=x' + // Taken from the middle of: GTM -> Admin -> Environments -> (environment) -> Get Snippet + // Blank for production + gtm_env_auth: process.env.GTM_ENV_AUTH || '' +}; + const baseConfig = new ScratchWebpackConfigBuilder( { rootPath: path.resolve(__dirname), enableReact: true, + enableTs: true, shouldSplitChunks: false }) .setTarget('browserslist') @@ -22,7 +35,10 @@ const baseConfig = new ScratchWebpackConfigBuilder( library: { name: 'GUI', type: 'umd2' - } + }, + // Do not clean the JS files before building as we have two outputs to the same + // dist directory (the regular and the standalone version) + clean: false }, resolve: { fallback: { @@ -45,11 +61,11 @@ const baseConfig = new ScratchWebpackConfigBuilder( .addPlugin(new CopyWebpackPlugin({ patterns: [ { - from: 'node_modules/scratch-blocks/media', + from: '../../node_modules/scratch-blocks/media', to: 'static/blocks-media/default' }, { - from: 'node_modules/scratch-blocks/media', + from: '../../node_modules/scratch-blocks/media', to: 'static/blocks-media/high-contrast' }, { @@ -60,7 +76,7 @@ const baseConfig = new ScratchWebpackConfigBuilder( force: true }, { - context: 'node_modules/scratch-vm/dist/web', + context: '../../node_modules/@scratch/scratch-vm/dist/web', from: 'extension-worker.{js,js.map}', noErrorOnMissing: true } @@ -75,12 +91,13 @@ if (!process.env.CI) { const distConfig = baseConfig.clone() .merge({ entry: { - 'scratch-gui': path.join(__dirname, 'src/index.js') + 'scratch-gui': path.join(__dirname, 'src/index.ts') }, output: { path: path.resolve(__dirname, 'dist') } }) + .addExternals(['react', 'react-dom', 'redux', 'react-redux']) .addPlugin( new CopyWebpackPlugin({ patterns: [ @@ -93,6 +110,17 @@ const distConfig = baseConfig.clone() }) ); +// build the shipping library in `dist/` bundled with react, react-dom, redux, etc. +const distStandaloneConfig = baseConfig.clone() + .merge({ + entry: { + 'scratch-gui-standalone': path.join(__dirname, 'src/index-standalone.tsx') + }, + output: { + path: path.resolve(__dirname, 'dist') + } + }); + // build the examples and debugging tools in `build/` const buildConfig = baseConfig.clone() .enableDevServer(process.env.PORT || 8601) @@ -104,27 +132,37 @@ const buildConfig = baseConfig.clone() player: './src/playground/player.jsx' }, output: { - path: path.resolve(__dirname, 'build') + path: path.resolve(__dirname, 'build'), + + // This output is loaded using a file:// scheme from the local file system. + // Having `publicPath: '/'` (the default) means the `gui.js` file in `build/index.html` + // would be looked for at the root of the filesystem, which is incorrect. + // Hence, we're resetting the public path to be relative. + publicPath: '' } }) .addPlugin(new HtmlWebpackPlugin({ + ...commonHtmlWebpackPluginOptions, chunks: ['gui'], template: 'src/playground/index.ejs', title: 'Scratch 3.0 GUI' })) .addPlugin(new HtmlWebpackPlugin({ + ...commonHtmlWebpackPluginOptions, chunks: ['blocksonly'], filename: 'blocks-only.html', template: 'src/playground/index.ejs', title: 'Scratch 3.0 GUI: Blocks Only Example' })) .addPlugin(new HtmlWebpackPlugin({ + ...commonHtmlWebpackPluginOptions, chunks: ['compatibilitytesting'], filename: 'compatibility-testing.html', template: 'src/playground/index.ejs', title: 'Scratch 3.0 GUI: Compatibility Testing' })) .addPlugin(new HtmlWebpackPlugin({ + ...commonHtmlWebpackPluginOptions, chunks: ['player'], filename: 'player.html', template: 'src/playground/index.ejs', @@ -151,5 +189,5 @@ const buildConfig = baseConfig.clone() const buildDist = process.env.NODE_ENV === 'production' || process.env.BUILD_MODE === 'dist'; module.exports = buildDist ? - [buildConfig.get(), distConfig.get()] : + [buildConfig.get(), distStandaloneConfig.get(), distConfig.get()] : buildConfig.get(); From f56149337c2ebe2525199ddd1d390fdf73f145c6 Mon Sep 17 00:00:00 2001 From: Kaloyan Manolov Date: Fri, 1 Nov 2024 11:17:43 +0200 Subject: [PATCH 2/6] fix: uepr-38: fix imports --- src/components/gui/gui.jsx | 4 ++-- src/components/menu-bar/menu-bar.jsx | 2 +- src/containers/gui.jsx | 2 +- webpack.config.js | 36 ++++++---------------------- 4 files changed, 11 insertions(+), 33 deletions(-) diff --git a/src/components/gui/gui.jsx b/src/components/gui/gui.jsx index fe87173f551..f2d0a8e8f73 100644 --- a/src/components/gui/gui.jsx +++ b/src/components/gui/gui.jsx @@ -7,8 +7,8 @@ import {connect} from 'react-redux'; import MediaQuery from 'react-responsive'; import {Tab, Tabs, TabList, TabPanel} from 'react-tabs'; import tabStyles from 'react-tabs/style/react-tabs.css'; -import VM from '@scratch/scratch-vm'; -import Renderer from '@scratch/scratch-render'; +import VM from 'scratch-vm'; +import Renderer from 'scratch-render'; import Blocks from '../../containers/blocks.jsx'; import CostumeTab from '../../containers/costume-tab.jsx'; diff --git a/src/components/menu-bar/menu-bar.jsx b/src/components/menu-bar/menu-bar.jsx index 2f59fd2f6dc..0fc148a2242 100644 --- a/src/components/menu-bar/menu-bar.jsx +++ b/src/components/menu-bar/menu-bar.jsx @@ -7,7 +7,7 @@ import bindAll from 'lodash.bindall'; import bowser from 'bowser'; import React from 'react'; -import VM from '@scratch/scratch-vm'; +import VM from 'scratch-vm'; import Box from '../box/box.jsx'; import Button from '../button/button.jsx'; diff --git a/src/containers/gui.jsx b/src/containers/gui.jsx index 7c7d2b1b533..b585f9d0155 100644 --- a/src/containers/gui.jsx +++ b/src/containers/gui.jsx @@ -3,7 +3,7 @@ import React from 'react'; import {compose} from 'redux'; import {connect} from 'react-redux'; import ReactModal from 'react-modal'; -import VM from '@scratch/scratch-vm'; +import VM from 'scratch-vm'; import {injectIntl, intlShape} from 'react-intl'; import ErrorBoundaryHOC from '../lib/error-boundary-hoc.jsx'; diff --git a/webpack.config.js b/webpack.config.js index 5676e5e6c68..1414bd5148c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -25,7 +25,6 @@ const baseConfig = new ScratchWebpackConfigBuilder( { rootPath: path.resolve(__dirname), enableReact: true, - enableTs: true, shouldSplitChunks: false }) .setTarget('browserslist') @@ -35,10 +34,7 @@ const baseConfig = new ScratchWebpackConfigBuilder( library: { name: 'GUI', type: 'umd2' - }, - // Do not clean the JS files before building as we have two outputs to the same - // dist directory (the regular and the standalone version) - clean: false + } }, resolve: { fallback: { @@ -61,11 +57,11 @@ const baseConfig = new ScratchWebpackConfigBuilder( .addPlugin(new CopyWebpackPlugin({ patterns: [ { - from: '../../node_modules/scratch-blocks/media', + from: 'node_modules/scratch-blocks/media', to: 'static/blocks-media/default' }, { - from: '../../node_modules/scratch-blocks/media', + from: 'node_modules/scratch-blocks/media', to: 'static/blocks-media/high-contrast' }, { @@ -76,7 +72,7 @@ const baseConfig = new ScratchWebpackConfigBuilder( force: true }, { - context: '../../node_modules/@scratch/scratch-vm/dist/web', + context: 'node_modules/scratch-vm/dist/web', from: 'extension-worker.{js,js.map}', noErrorOnMissing: true } @@ -91,13 +87,12 @@ if (!process.env.CI) { const distConfig = baseConfig.clone() .merge({ entry: { - 'scratch-gui': path.join(__dirname, 'src/index.ts') + 'scratch-gui': path.join(__dirname, 'src/index.js') }, output: { path: path.resolve(__dirname, 'dist') } }) - .addExternals(['react', 'react-dom', 'redux', 'react-redux']) .addPlugin( new CopyWebpackPlugin({ patterns: [ @@ -110,17 +105,6 @@ const distConfig = baseConfig.clone() }) ); -// build the shipping library in `dist/` bundled with react, react-dom, redux, etc. -const distStandaloneConfig = baseConfig.clone() - .merge({ - entry: { - 'scratch-gui-standalone': path.join(__dirname, 'src/index-standalone.tsx') - }, - output: { - path: path.resolve(__dirname, 'dist') - } - }); - // build the examples and debugging tools in `build/` const buildConfig = baseConfig.clone() .enableDevServer(process.env.PORT || 8601) @@ -132,13 +116,7 @@ const buildConfig = baseConfig.clone() player: './src/playground/player.jsx' }, output: { - path: path.resolve(__dirname, 'build'), - - // This output is loaded using a file:// scheme from the local file system. - // Having `publicPath: '/'` (the default) means the `gui.js` file in `build/index.html` - // would be looked for at the root of the filesystem, which is incorrect. - // Hence, we're resetting the public path to be relative. - publicPath: '' + path: path.resolve(__dirname, 'build') } }) .addPlugin(new HtmlWebpackPlugin({ @@ -189,5 +167,5 @@ const buildConfig = baseConfig.clone() const buildDist = process.env.NODE_ENV === 'production' || process.env.BUILD_MODE === 'dist'; module.exports = buildDist ? - [buildConfig.get(), distStandaloneConfig.get(), distConfig.get()] : + [buildConfig.get(), distConfig.get()] : buildConfig.get(); From 703907f92cb5b1076b8f4bc445369c2dd7843dd8 Mon Sep 17 00:00:00 2001 From: Kaloyan Manolov Date: Tue, 19 Nov 2024 12:55:54 +0200 Subject: [PATCH 3/6] fix: uepr-38: debug modal description and image preload --- src/components/debug-modal/debug-modal.jsx | 7 +++++++ src/components/debug-modal/sections/sections.jsx | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/components/debug-modal/debug-modal.jsx b/src/components/debug-modal/debug-modal.jsx index 924556daac4..65edf630cb4 100644 --- a/src/components/debug-modal/debug-modal.jsx +++ b/src/components/debug-modal/debug-modal.jsx @@ -31,6 +31,13 @@ const logTopicChange = topicIndex => { const DebugModal = ({isOpen, onClose = () => {}}) => { const [selectedTopicIndex, setSelectedTopicIndex] = useState(0); + // Preload images + useEffect(() => { + sections.forEach(section => { + new Image().src = section.image; + }); + }, []); + const handleNext = useCallback(() => { if (selectedTopicIndex < sections.length - 1) { setSelectedTopicIndex(selectedTopicIndex + 1); diff --git a/src/components/debug-modal/sections/sections.jsx b/src/components/debug-modal/sections/sections.jsx index 6b1290c67d8..6295ddbabfd 100644 --- a/src/components/debug-modal/sections/sections.jsx +++ b/src/components/debug-modal/sections/sections.jsx @@ -102,7 +102,7 @@ export const sections = [ description:

    -
  • +
, From 3c7f15354a93f9da2369e5cc927ca8ecc26e9426 Mon Sep 17 00:00:00 2001 From: Kaloyan Manolov Date: Mon, 2 Dec 2024 12:03:47 +0200 Subject: [PATCH 4/6] fix: uepr-38: style updates --- src/components/debug-modal/debug-modal.css | 258 +++++++++++---------- src/components/debug-modal/debug-modal.jsx | 8 +- 2 files changed, 138 insertions(+), 128 deletions(-) diff --git a/src/components/debug-modal/debug-modal.css b/src/components/debug-modal/debug-modal.css index 53138acb0a4..e765c65d485 100644 --- a/src/components/debug-modal/debug-modal.css +++ b/src/components/debug-modal/debug-modal.css @@ -1,6 +1,6 @@ @import "../../css/colors.css"; -.modal-overlay { +.debug-modal-overlay { position: fixed; top: 0; left: 0; @@ -13,7 +13,7 @@ z-index: 510; } -.modal-container { +.debug-modal-container { background: white; border-radius: 8px; width: 1000px; @@ -23,127 +23,137 @@ position: relative; overflow-x: visible; box-shadow: 0 4px 4px 0 $ui-black-transparent-10; + outline: none; + + .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; + } + + .modal-content::-webkit-scrollbar-track { + background: transparent; + } + + .modal-content::-webkit-scrollbar { + width: 8px; + } + + .previousIcon { + position: absolute; + cursor: pointer; + top: 50%; + } + + .nextIcon { + position: absolute; + cursor: pointer; + right: -26px; + 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; + } } -.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/src/components/debug-modal/debug-modal.jsx b/src/components/debug-modal/debug-modal.jsx index 65edf630cb4..e79a6195fec 100644 --- a/src/components/debug-modal/debug-modal.jsx +++ b/src/components/debug-modal/debug-modal.jsx @@ -79,8 +79,8 @@ const DebugModal = ({isOpen, onClose = () => {}}) => {
@@ -147,7 +147,7 @@ const DebugModal = ({isOpen, onClose = () => {}}) => { src={prevIcon} alt="Previous" onClick={handlePrevious} - className={classNames(styles.navigationIcon, styles.previousIcon, { + className={classNames(styles.previousIcon, { [styles.hidden]: selectedTopicIndex === 0 })} /> @@ -155,7 +155,7 @@ const DebugModal = ({isOpen, onClose = () => {}}) => { src={nextIcon} alt="Next" onClick={handleNext} - className={classNames(styles.navigationIcon, styles.nextIcon, { + className={classNames(styles.nextIcon, { [styles.hidden]: selectedTopicIndex === sections.length - 1 })} /> From 23980392afcb760361f0412d5d199214f8c72ad3 Mon Sep 17 00:00:00 2001 From: Kaloyan Manolov Date: Mon, 2 Dec 2024 13:37:45 +0200 Subject: [PATCH 5/6] Return tutorials-button class --- src/components/menu-bar/menu-bar.jsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/components/menu-bar/menu-bar.jsx b/src/components/menu-bar/menu-bar.jsx index 0fc148a2242..9ad60de4d4d 100644 --- a/src/components/menu-bar/menu-bar.jsx +++ b/src/components/menu-bar/menu-bar.jsx @@ -696,7 +696,9 @@ class MenuBar extends React.Component {
Date: Mon, 2 Dec 2024 13:49:36 +0200 Subject: [PATCH 6/6] fix: uepr-38: style fixes --- src/components/debug-modal/debug-modal.css | 11 +++++++---- src/css/colors.css | 1 + 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/components/debug-modal/debug-modal.css b/src/components/debug-modal/debug-modal.css index e765c65d485..1125bf45860 100644 --- a/src/components/debug-modal/debug-modal.css +++ b/src/components/debug-modal/debug-modal.css @@ -30,8 +30,10 @@ border-radius: 8px 8px 0 0; justify-content: space-between; align-items: center; - padding: 10px; - background-color: $ui-green; + padding: 8px; + padding-left: 12px; + padding-right: 12px; + background-color: $ui-green-2; } .header-title { @@ -85,7 +87,7 @@ .nextIcon { position: absolute; cursor: pointer; - right: -26px; + right: -24px; top: 50%; } @@ -98,7 +100,8 @@ display: flex; gap: 8px; align-items: center; - padding: 10px; + padding: 8px; + padding-left: 12px; font-size: 1rem; line-height: 1.5rem; color: $ui-green;; diff --git a/src/css/colors.css b/src/css/colors.css index 058c078a102..538d4e8d032 100644 --- a/src/css/colors.css +++ b/src/css/colors.css @@ -13,6 +13,7 @@ $ui-black-transparent: hsla(0, 0%, 0%, 0.15); /* 15% transparent version of blac $ui-black-transparent-10: hsla(0, 0%, 0%, 0.10); /* 10% transparent version of black */ $ui-green: hsla(163, 85%, 35%, 1); /* #0DA57A */ +$ui-green-2: hsla(163, 85%, 40%, 1); /* #0FBD8C */ $text-primary: hsla(225, 15%, 40%, 1); /* #575E75 */ $text-primary-transparent: hsla(225, 15%, 40%, 0.75);