Skip to content

Commit 68f5adc

Browse files
authored
Merge pull request #9765 from scratchfoundation/integration-branch-ux-12.2024
Integration branch ux 12.2024
2 parents 18eaaa0 + dcf17db commit 68f5adc

31 files changed

+1496
-45
lines changed
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
@import "../../css/colors.css";
2+
3+
.debug-modal-overlay {
4+
position: fixed;
5+
top: 0;
6+
left: 0;
7+
right: 0;
8+
bottom: 0;
9+
background-color: 'transparent';
10+
display: flex;
11+
justify-content: center;
12+
align-items: center;
13+
z-index: 510;
14+
}
15+
16+
.debug-modal-container {
17+
background: white;
18+
border-radius: 8px;
19+
width: 1000px;
20+
max-height: 90%;
21+
display: flex;
22+
flex-direction: column;
23+
position: relative;
24+
overflow-x: visible;
25+
box-shadow: 0 4px 4px 0 $ui-black-transparent-10;
26+
outline: none;
27+
28+
.modal-header {
29+
display: flex;
30+
border-radius: 8px 8px 0 0;
31+
justify-content: space-between;
32+
align-items: center;
33+
padding: 8px;
34+
padding-left: 12px;
35+
padding-right: 12px;
36+
background-color: $ui-green-2;
37+
}
38+
39+
.header-title {
40+
display: flex;
41+
gap: 8px;
42+
align-items: center;
43+
font-size: 1rem;
44+
line-height: 1.25rem;
45+
font-weight: 700;
46+
color: white;
47+
}
48+
.debug-icon {
49+
height: 22px;
50+
width: 22px;
51+
}
52+
53+
.hidden {
54+
display: none;
55+
}
56+
57+
.close-button {
58+
display: flex;
59+
background: none;
60+
border: none;
61+
cursor: pointer;
62+
width: 32px;
63+
height: 32px;
64+
}
65+
66+
.modal-content {
67+
display: flex;
68+
width: 100%;
69+
flex-grow: 1;
70+
overflow-y: scroll;
71+
}
72+
73+
.modal-content::-webkit-scrollbar-track {
74+
background: transparent;
75+
}
76+
77+
.modal-content::-webkit-scrollbar {
78+
width: 8px;
79+
}
80+
81+
.previousIcon {
82+
position: absolute;
83+
cursor: pointer;
84+
top: 50%;
85+
}
86+
87+
.nextIcon {
88+
position: absolute;
89+
cursor: pointer;
90+
right: -24px;
91+
top: 50%;
92+
}
93+
94+
.topic-list {
95+
width: 30%;
96+
border-right: 1px solid $ui-green;;
97+
}
98+
99+
.topic-item {
100+
display: flex;
101+
gap: 8px;
102+
align-items: center;
103+
padding: 8px;
104+
padding-left: 12px;
105+
font-size: 1rem;
106+
line-height: 1.5rem;
107+
color: $ui-green;;
108+
cursor: pointer;
109+
}
110+
111+
.topic-item.active {
112+
background-color: #D1FAEE;
113+
font-weight: bold;
114+
}
115+
116+
.info-container {
117+
flex-direction: column;
118+
width: 70%;
119+
display: flex;
120+
padding: 20px;
121+
color: $text-primary;
122+
}
123+
124+
.text-container {
125+
flex: 1;
126+
margin-left: 70px;
127+
}
128+
129+
.title-text {
130+
font-size: 24px;
131+
line-height: 32px;
132+
font-weight: 700;
133+
}
134+
135+
.description {
136+
font-size: 16px;
137+
line-height: 28px;
138+
}
139+
140+
.imageContainer {
141+
display: flex;
142+
justify-content: center;
143+
align-items: center;
144+
padding: 10px;
145+
margin-top: 10px;
146+
}
147+
148+
.topicImage {
149+
max-width: 100%;
150+
max-height: 100%;
151+
object-fit: contain; /* Ensures image scales proportionally */
152+
}
153+
154+
.navigation-buttons {
155+
margin-top: 20px;
156+
}
157+
158+
button {
159+
margin: 5px;
160+
}
161+
}
162+
Lines changed: 174 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
import React, {useState, useCallback, useEffect} from 'react';
2+
import {defineMessages, FormattedMessage} from 'react-intl';
3+
import PropTypes from 'prop-types';
4+
import ReactModal from 'react-modal';
5+
import classNames from 'classnames';
6+
import {sections} from './sections/sections';
7+
import GA4 from '../../lib/analytics';
8+
9+
import styles from './debug-modal.css';
10+
import debugIcon from './icons/icon--debug.svg';
11+
import debugIconInverted from './icons/icon--debug-inverted.svg';
12+
import closeIcon from './icons/icon--close.svg';
13+
import prevIcon from './icons/icon--prev.svg';
14+
import nextIcon from './icons/icon--next.svg';
15+
16+
const messages = defineMessages({
17+
title: {
18+
id: 'gui.debugModal.title',
19+
defaultMessage: 'Debugging | Getting Unstuck',
20+
description: 'title for the debugging modal'
21+
}
22+
});
23+
24+
const logTopicChange = topicIndex => {
25+
GA4.event({
26+
category: 'change_topic_debug_modal',
27+
label: sections[topicIndex].id
28+
});
29+
};
30+
31+
const DebugModal = ({isOpen, onClose = () => {}}) => {
32+
const [selectedTopicIndex, setSelectedTopicIndex] = useState(0);
33+
34+
// Preload images
35+
useEffect(() => {
36+
sections.forEach(section => {
37+
new Image().src = section.image;
38+
});
39+
}, []);
40+
41+
const handleNext = useCallback(() => {
42+
if (selectedTopicIndex < sections.length - 1) {
43+
setSelectedTopicIndex(selectedTopicIndex + 1);
44+
logTopicChange(selectedTopicIndex + 1);
45+
}
46+
}, [selectedTopicIndex, setSelectedTopicIndex]);
47+
48+
const handlePrevious = useCallback(() => {
49+
if (selectedTopicIndex > 0) {
50+
setSelectedTopicIndex(selectedTopicIndex - 1);
51+
logTopicChange(selectedTopicIndex - 1);
52+
}
53+
}, [selectedTopicIndex, setSelectedTopicIndex]);
54+
55+
const handleTopicSelect = useCallback(index => {
56+
setSelectedTopicIndex(index);
57+
logTopicChange(index);
58+
}, [setSelectedTopicIndex]);
59+
60+
const handleClose = useCallback(() => {
61+
GA4.event({
62+
category: 'close_debug_modal'
63+
});
64+
onClose();
65+
}, [onClose]);
66+
67+
useEffect(() => {
68+
if (isOpen) {
69+
GA4.event({
70+
category: 'open_debug_modal',
71+
label: sections[selectedTopicIndex].id
72+
});
73+
}
74+
}, [isOpen]);
75+
76+
if (!isOpen) return null;
77+
78+
return (
79+
<ReactModal
80+
isOpen={isOpen}
81+
onRequestClose={handleClose}
82+
className={styles.debugModalContainer}
83+
overlayClassName={styles.debugModalOverlay}
84+
>
85+
<div className={styles.modalHeader}>
86+
<div className={styles.headerTitle}>
87+
<img
88+
className={styles.debugIcon}
89+
src={debugIcon}
90+
/>
91+
<FormattedMessage
92+
{...messages.title}
93+
/>
94+
</div>
95+
<button
96+
className={styles.closeButton}
97+
onClick={handleClose}
98+
>
99+
<img
100+
className={styles.closeIcon}
101+
src={closeIcon}
102+
/>
103+
</button>
104+
</div>
105+
<div className={styles.modalContent} >
106+
<div className={styles.topicList}>
107+
{sections.map((section, index) => (
108+
<div
109+
key={index}
110+
className={classNames(styles.topicItem, {
111+
[styles.active]: selectedTopicIndex === index
112+
})}
113+
// eslint-disable-next-line react/jsx-no-bind
114+
onClick={() => handleTopicSelect(index)}
115+
>
116+
<div className={styles.debugIcon}>
117+
<img
118+
className={classNames({
119+
[styles.hidden]: selectedTopicIndex !== index
120+
})}
121+
src={debugIconInverted}
122+
/>
123+
</div>
124+
<FormattedMessage
125+
{...(section.sectionTitle ?? section.title)}
126+
/>
127+
</div>
128+
))}
129+
</div>
130+
<div className={styles.infoContainer}>
131+
<div className={styles.textContainer}>
132+
<div className={styles.titleText}>
133+
<FormattedMessage
134+
{...sections[selectedTopicIndex].title}
135+
/>
136+
</div>
137+
<div className={styles.description}>{sections[selectedTopicIndex].description}</div>
138+
</div>
139+
<div className={styles.imageContainer}>
140+
<img
141+
src={sections[selectedTopicIndex].image}
142+
className={styles.topicImage}
143+
/>
144+
</div>
145+
<div className={styles.navigationButtons}>
146+
<img
147+
src={prevIcon}
148+
alt="Previous"
149+
onClick={handlePrevious}
150+
className={classNames(styles.previousIcon, {
151+
[styles.hidden]: selectedTopicIndex === 0
152+
})}
153+
/>
154+
<img
155+
src={nextIcon}
156+
alt="Next"
157+
onClick={handleNext}
158+
className={classNames(styles.nextIcon, {
159+
[styles.hidden]: selectedTopicIndex === sections.length - 1
160+
})}
161+
/>
162+
</div>
163+
</div>
164+
</div>
165+
</ReactModal>
166+
);
167+
};
168+
169+
DebugModal.propTypes = {
170+
isOpen: PropTypes.bool,
171+
onClose: PropTypes.func
172+
};
173+
174+
export default DebugModal;
Lines changed: 14 additions & 0 deletions
Loading

0 commit comments

Comments
 (0)