diff --git a/docs/writing-docs/tutorials/control-options.md b/docs/writing-docs/tutorials/control-options.md
index ec2d9cbd62be..1511497d5778 100644
--- a/docs/writing-docs/tutorials/control-options.md
+++ b/docs/writing-docs/tutorials/control-options.md
@@ -54,6 +54,14 @@ You can highlight the differences in code between the current step hint and the
### @diffs true
```
+### Hide Toolbox
+
+For text-based tutorials, you can choose to hide the toolbox altogether. This is done by specifying **@hideToolbox** in the metadata. The default is ``false``.
+
+```
+### @hideToolbox true
+```
+
## Special blocks
### Templates
diff --git a/localtypings/pxtarget.d.ts b/localtypings/pxtarget.d.ts
index 1c8fd4b54e32..feb1d9700a61 100644
--- a/localtypings/pxtarget.d.ts
+++ b/localtypings/pxtarget.d.ts
@@ -1197,6 +1197,7 @@ declare namespace pxt.tutorial {
activities?: boolean; // tutorial consists of activities, then steps. uses `###` for steps
explicitHints?: boolean; // tutorial expects explicit hints in `#### ~ tutorialhint` format
flyoutOnly?: boolean; // no categories, display all blocks in flyout
+ hideToolbox?: boolean; // hide the toolbox in the tutorial
hideIteration?: boolean; // hide step control in tutorial
diffs?: boolean; // automatically diff snippets
noDiffs?: boolean; // don't automatically generated diffs
@@ -1347,4 +1348,4 @@ declare namespace pxt.auth {
type: "skillmap-completion";
sourceURL: string;
}
-}
\ No newline at end of file
+}
diff --git a/pxtlib/docsrender.ts b/pxtlib/docsrender.ts
index d65256642409..553d5f271671 100644
--- a/pxtlib/docsrender.ts
+++ b/pxtlib/docsrender.ts
@@ -24,6 +24,7 @@ namespace pxt.docs {
"activities": "",
"explicitHints": "",
"flyoutOnly": "",
+ "hideToolbox": "",
"hideIteration": "",
"codeStart": "",
"codeStop": "",
diff --git a/pxtlib/tutorial.ts b/pxtlib/tutorial.ts
index 80a2832c60ba..cc14761415bd 100644
--- a/pxtlib/tutorial.ts
+++ b/pxtlib/tutorial.ts
@@ -22,6 +22,12 @@ namespace pxt.tutorial {
simThemeJson
} = computeBodyMetadata(body);
+ // For python HOC, hide the toolbox (we don't support flyoutOnly mode).
+ if (pxt.BrowserUtils.useOldTutorialLayout() && language === "python" && metadata.flyoutOnly) {
+ metadata.flyoutOnly = false;
+ metadata.hideToolbox = true;
+ }
+
// noDiffs legacy
if (metadata.diffs === true // enabled in tutorial
|| (metadata.diffs !== false && metadata.noDiffs !== true // not disabled
@@ -406,7 +412,7 @@ ${code}
if (metadata.explicitHints !== undefined
&& pxt.appTarget.appTheme
&& pxt.appTarget.appTheme.tutorialExplicitHints)
- metadata.explicitHints = true;
+ metadata.explicitHints = true;
return { metadata, body };
}
diff --git a/theme/tutorial.less b/theme/tutorial.less
index 19885bb53008..bbeba42f0255 100644
--- a/theme/tutorial.less
+++ b/theme/tutorial.less
@@ -642,6 +642,10 @@ code.lang-filterblocks {
}
}
+.hideToolbox #headers #flyoutHeader {
+ display: none;
+}
+
/*******************************
Sidebar Tutorial
*******************************/
@@ -913,4 +917,4 @@ code.lang-filterblocks {
100% {
transform: rotate(0deg);
}
-}
\ No newline at end of file
+}
diff --git a/webapp/src/app.tsx b/webapp/src/app.tsx
index 67c79529c64c..a68c0cb127ac 100644
--- a/webapp/src/app.tsx
+++ b/webapp/src/app.tsx
@@ -5034,7 +5034,11 @@ export class ProjectView
} else {
const tc = document.getElementById("tutorialcard");
if (tc) {
- const flyoutOnly = this.state.editorState?.hasCategories === false || this.state.tutorialOptions?.metadata?.flyoutOnly;
+ const flyoutOnly =
+ this.state.editorState?.hasCategories === false
+ || this.state.tutorialOptions?.metadata?.flyoutOnly
+ || this.state.tutorialOptions?.metadata?.hideToolbox;
+
let headerHeight = 0;
if (flyoutOnly) {
const headers = document.getElementById("headers");
@@ -5257,7 +5261,9 @@ export class ProjectView
const inEditor = !!this.state.header && !inHome;
const { lightbox, greenScreen, accessibleBlocks } = this.state;
const hideTutorialIteration = inTutorial && tutorialOptions.metadata?.hideIteration;
- const flyoutOnly = this.state.editorState?.hasCategories === false || (inTutorial && tutorialOptions.metadata?.flyoutOnly);
+ const hideToolbox = inTutorial && tutorialOptions.metadata?.hideToolbox;
+ // flyoutOnly has become a de facto css class for styling tutorials (especially minecraft HOC), so keep it if hideToolbox is true, even if flyoutOnly is false.
+ const flyoutOnly = this.state.editorState?.hasCategories === false || (inTutorial && (tutorialOptions.metadata?.flyoutOnly || hideToolbox));
const { hideEditorToolbar, transparentEditorToolbar } = targetTheme;
const hideMenuBar = targetTheme.hideMenuBar || hideTutorialIteration || (isTabTutorial && pxt.appTarget.appTheme.embeddedTutorial) || pxt.shell.isTimeMachineEmbed();
const isHeadless = simOpts && simOpts.headless;
@@ -5308,6 +5314,7 @@ export class ProjectView
logoWide ? "logo-wide" : "",
isHeadless ? "headless" : "",
flyoutOnly ? "flyoutOnly" : "",
+ hideToolbox ? "hideToolbox" : "",
hideTutorialIteration ? "hideIteration" : "",
this.editor != this.blocksEditor ? "editorlang-text" : "",
this.editor == this.textEditor && this.state.errorListState,
@@ -5356,7 +5363,7 @@ export class ProjectView
{isSidebarTutorial && flyoutOnly && inTutorial &&