Skip to content

Commit f474586

Browse files
committed
feat: add ability to hide sounds and costumes
1 parent fb4ff71 commit f474586

5 files changed

Lines changed: 899 additions & 60 deletions

File tree

packages/scratch-gui/src/components/gui/gui.jsx

Lines changed: 70 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ const GUIComponent = props => {
189189
onTelemetryModalOptOut,
190190
onUpdateProjectThumbnail,
191191
showComingSoon,
192+
showCostumesTab,
193+
showSoundsTab,
192194
showTutorials,
193195
soundsTabVisible,
194196
stageSizeMode,
@@ -423,46 +425,50 @@ const GUIComponent = props => {
423425
id="gui.gui.codeTab"
424426
/>
425427
</Tab>
426-
<Tab
427-
className={tabClassNames.tab}
428-
onClick={onActivateCostumesTab}
429-
role="tab"
430-
tabIndex="0"
431-
>
432-
<img
433-
draggable={false}
434-
src={costumesIcon}
435-
/>
436-
{targetIsStage ? (
437-
<FormattedMessage
438-
defaultMessage="Backdrops"
439-
description="Button to get to the backdrops panel"
440-
id="gui.gui.backdropsTab"
428+
{showCostumesTab !== false && (
429+
<Tab
430+
className={tabClassNames.tab}
431+
onClick={onActivateCostumesTab}
432+
role="tab"
433+
tabIndex="0"
434+
>
435+
<img
436+
draggable={false}
437+
src={costumesIcon}
438+
/>
439+
{targetIsStage ? (
440+
<FormattedMessage
441+
defaultMessage="Backdrops"
442+
description="Button to get to the backdrops panel"
443+
id="gui.gui.backdropsTab"
444+
/>
445+
) : (
446+
<FormattedMessage
447+
defaultMessage="Costumes"
448+
description="Button to get to the costumes panel"
449+
id="gui.gui.costumesTab"
450+
/>
451+
)}
452+
</Tab>
453+
)}
454+
{showSoundsTab !== false && (
455+
<Tab
456+
className={tabClassNames.tab}
457+
onClick={onActivateSoundsTab}
458+
role="tab"
459+
tabIndex="0"
460+
>
461+
<img
462+
draggable={false}
463+
src={soundsIcon}
441464
/>
442-
) : (
443465
<FormattedMessage
444-
defaultMessage="Costumes"
445-
description="Button to get to the costumes panel"
446-
id="gui.gui.costumesTab"
466+
defaultMessage="Sounds"
467+
description="Button to get to the sounds panel"
468+
id="gui.gui.soundsTab"
447469
/>
448-
)}
449-
</Tab>
450-
<Tab
451-
className={tabClassNames.tab}
452-
onClick={onActivateSoundsTab}
453-
role="tab"
454-
tabIndex="0"
455-
>
456-
<img
457-
draggable={false}
458-
src={soundsIcon}
459-
/>
460-
<FormattedMessage
461-
defaultMessage="Sounds"
462-
description="Button to get to the sounds panel"
463-
id="gui.gui.soundsTab"
464-
/>
465-
</Tab>
470+
</Tab>
471+
)}
466472
</TabList>
467473
</Box>
468474
<TabPanel
@@ -499,30 +505,34 @@ const GUIComponent = props => {
499505
<Watermark />
500506
</Box>
501507
</TabPanel>
502-
<TabPanel
503-
className={tabClassNames.tabPanel}
504-
role="tabpanel"
505-
>
506-
{costumesTabVisible ? <CostumeTab
507-
ariaLabel={targetIsStage ? intl.formatMessage(ariaMessages.backdropsPanel) :
508-
intl.formatMessage(ariaMessages.costumesPanel)}
509-
ariaRole="region"
510-
vm={vm}
511-
onNewLibraryBackdropClick={onNewLibraryBackdropClick}
512-
onNewLibraryCostumeClick={onNewLibraryCostumeClick}
513-
/> : null}
514-
</TabPanel>
515-
<TabPanel
516-
className={tabClassNames.tabPanel}
517-
role="tabpanel"
518-
>
519-
{soundsTabVisible ?
520-
<SoundTab
521-
ariaLabel={intl.formatMessage(ariaMessages.soundsPanel)}
508+
{showCostumesTab !== false && (
509+
<TabPanel
510+
className={tabClassNames.tabPanel}
511+
role="tabpanel"
512+
>
513+
{costumesTabVisible ? <CostumeTab
514+
ariaLabel={targetIsStage ? intl.formatMessage(ariaMessages.backdropsPanel) :
515+
intl.formatMessage(ariaMessages.costumesPanel)}
522516
ariaRole="region"
523517
vm={vm}
518+
onNewLibraryBackdropClick={onNewLibraryBackdropClick}
519+
onNewLibraryCostumeClick={onNewLibraryCostumeClick}
524520
/> : null}
525-
</TabPanel>
521+
</TabPanel>
522+
)}
523+
{showSoundsTab !== false && (
524+
<TabPanel
525+
className={tabClassNames.tabPanel}
526+
role="tabpanel"
527+
>
528+
{soundsTabVisible ?
529+
<SoundTab
530+
ariaLabel={intl.formatMessage(ariaMessages.soundsPanel)}
531+
ariaRole="region"
532+
vm={vm}
533+
/> : null}
534+
</TabPanel>
535+
)}
526536
</Tabs>
527537
</Box>
528538

@@ -638,6 +648,8 @@ GUIComponent.propTypes = {
638648
renderLogin: PropTypes.func,
639649
setTheme: PropTypes.func.isRequired,
640650
showComingSoon: PropTypes.bool,
651+
showCostumesTab: PropTypes.bool,
652+
showSoundsTab: PropTypes.bool,
641653
showTutorials: PropTypes.bool,
642654
showNewFeatureCallouts: PropTypes.bool,
643655
soundsTabVisible: PropTypes.bool,

packages/scratch-gui/src/lib/project-file-hoc.jsx

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,36 @@ const ProjectFileHOC = function (WrappedComponent) {
3434
}
3535
componentDidMount () {
3636
const queryParams = queryString.parse(location.search);
37-
if (queryParams.project) {
37+
if (queryParams.projectJson) {
38+
// Decode base64-encoded project JSON from URL
39+
try {
40+
const json = decodeURIComponent(atob(queryParams.projectJson));
41+
const projectFile = JSON.parse(json);
42+
if (!projectFile.title || typeof projectFile.title !== 'string') {
43+
throw new Error('Project file must have a "title" string field');
44+
}
45+
this.props.onSetProjectFile(projectFile);
46+
if (projectFile.sb3 && this.props.vm) {
47+
this.loadSb3(projectFile.sb3);
48+
}
49+
if (projectFile.steps && projectFile.steps.length > 0) {
50+
const deck = {
51+
name: projectFile.title,
52+
img: projectFile.steps[0].image || '',
53+
steps: projectFile.steps.map(step => ({
54+
title: step.title,
55+
text: step.text || null,
56+
image: step.image || null,
57+
video: step.video || null
58+
}))
59+
};
60+
this.props.onSetExternalDeck(EXTERNAL_DECK_ID, deck);
61+
}
62+
} catch (error) {
63+
log.error('Failed to parse projectJson from URL:', error);
64+
this.props.onSetProjectFileError(error.message);
65+
}
66+
} else if (queryParams.project) {
3867
const url = queryParams.project;
3968
this.setState({projectFileUrl: url});
4069
if (url.endsWith('.sb3')) {
@@ -129,6 +158,14 @@ const ProjectFileHOC = function (WrappedComponent) {
129158
if (projectFile.ui && projectFile.ui.allowExtensions === false) {
130159
componentProps.allowExtensions = false;
131160
}
161+
162+
// Hide costumes/sounds tabs if configured
163+
if (projectFile.ui && projectFile.ui.showCostumesTab === false) {
164+
componentProps.showCostumesTab = false;
165+
}
166+
if (projectFile.ui && projectFile.ui.showSoundsTab === false) {
167+
componentProps.showSoundsTab = false;
168+
}
132169
}
133170

134171
return (

0 commit comments

Comments
 (0)