diff --git a/src/containers/gui.jsx b/src/containers/gui.jsx
index 9935b3a7e25..025a739661e 100644
--- a/src/containers/gui.jsx
+++ b/src/containers/gui.jsx
@@ -36,6 +36,7 @@ import vmManagerHOC from '../lib/vm-manager-hoc.jsx';
import cloudManagerHOC from '../lib/cloud-manager-hoc.jsx';
import GUIComponent from '../components/gui/gui.jsx';
+import {setIsScratchDesktop} from '../lib/isScratchDesktop.js';
const messages = defineMessages({
defaultProjectTitle: {
@@ -47,6 +48,7 @@ const messages = defineMessages({
class GUI extends React.Component {
componentDidMount () {
+ setIsScratchDesktop(this.props.isScratchDesktop);
this.setReduxTitle(this.props.projectTitle);
this.props.onStorageInit(storage);
}
@@ -78,6 +80,7 @@ class GUI extends React.Component {
cloudHost,
error,
isError,
+ isScratchDesktop,
isShowingProject,
onStorageInit,
onUpdateProjectId,
@@ -113,6 +116,7 @@ GUI.propTypes = {
intl: intlShape,
isError: PropTypes.bool,
isLoading: PropTypes.bool,
+ isScratchDesktop: PropTypes.bool,
isShowingProject: PropTypes.bool,
loadingStateVisible: PropTypes.bool,
onSeeCommunity: PropTypes.func,
@@ -128,6 +132,7 @@ GUI.propTypes = {
};
GUI.defaultProps = {
+ isScratchDesktop: false,
onStorageInit: storageInstance => storageInstance.addOfficialScratchWebStores(),
onUpdateProjectId: () => {}
};
diff --git a/src/containers/tips-library.jsx b/src/containers/tips-library.jsx
index 5727e19d120..3c85ce99e39 100644
--- a/src/containers/tips-library.jsx
+++ b/src/containers/tips-library.jsx
@@ -7,6 +7,8 @@ import decksLibraryContent from '../lib/libraries/decks/index.jsx';
import tutorialTags from '../lib/libraries/tutorial-tags';
import analytics from '../lib/analytics';
+import {notScratchDesktop} from '../lib/isScratchDesktop';
+
import LibraryComponent from '../components/library/library.jsx';
import {connect} from 'react-redux';
@@ -56,16 +58,21 @@ class TipsLibrary extends React.PureComponent {
});
}
render () {
- const decksLibraryThumbnailData = Object.keys(decksLibraryContent).map(id => ({
- rawURL: decksLibraryContent[id].img,
- id: id,
- name: decksLibraryContent[id].name,
- featured: true,
- tags: decksLibraryContent[id].tags,
- urlId: decksLibraryContent[id].urlId,
- requiredProjectId: decksLibraryContent[id].requiredProjectId,
- hidden: decksLibraryContent[id].hidden || false
- }));
+ const decksLibraryThumbnailData = Object.keys(decksLibraryContent)
+ .filter(id =>
+ // Scratch Desktop doesn't want tutorials with `requiredProjectId`
+ notScratchDesktop() || !decksLibraryContent[id].hasOwnProperty('requiredProjectId')
+ )
+ .map(id => ({
+ rawURL: decksLibraryContent[id].img,
+ id: id,
+ name: decksLibraryContent[id].name,
+ featured: true,
+ tags: decksLibraryContent[id].tags,
+ urlId: decksLibraryContent[id].urlId,
+ requiredProjectId: decksLibraryContent[id].requiredProjectId,
+ hidden: decksLibraryContent[id].hidden || false
+ }));
if (!this.props.visible) return null;
return (
diff --git a/src/lib/isScratchDesktop.js b/src/lib/isScratchDesktop.js
new file mode 100644
index 00000000000..e159e385263
--- /dev/null
+++ b/src/lib/isScratchDesktop.js
@@ -0,0 +1,35 @@
+/**
+ * Internal stored state. Not valid until after at least one call to `setIsScratchDesktop()`.
+ * @type {boolean}
+ */
+let _isScratchDesktop; // undefined = not ready yet
+
+/**
+ * Tell the `isScratchDesktop()` whether or not the GUI is running under Scratch Desktop.
+ * @param {boolean} value - the new value which `isScratchDesktop()` should return in the future.
+ */
+const setIsScratchDesktop = function (value) {
+ _isScratchDesktop = value;
+};
+
+/**
+ * @returns {boolean} - true if it seems like the GUI is running under Scratch Desktop; false otherwise.
+ * If `setIsScratchDesktop()` has not yet been called, this can return `undefined`.
+ */
+const isScratchDesktop = function () {
+ return _isScratchDesktop;
+};
+
+/**
+ * @returns {boolean} - false if it seems like the GUI is running under Scratch Desktop; true otherwise.
+ */
+const notScratchDesktop = function () {
+ return !isScratchDesktop();
+};
+
+export default isScratchDesktop;
+export {
+ isScratchDesktop,
+ notScratchDesktop,
+ setIsScratchDesktop
+};
diff --git a/src/playground/render-gui.jsx b/src/playground/render-gui.jsx
index f3acac2eefd..3ae35e4d303 100644
--- a/src/playground/render-gui.jsx
+++ b/src/playground/render-gui.jsx
@@ -32,19 +32,38 @@ export default appTarget => {
const backpackHostMatches = window.location.href.match(/[?&]backpack_host=([^&]*)&?/);
const backpackHost = backpackHostMatches ? backpackHostMatches[1] : null;
+ const scratchDesktopMatches = window.location.href.match(/[?&]isScratchDesktop=([^&]+)/);
+ let simulateScratchDesktop;
+ if (scratchDesktopMatches) {
+ try {
+ // parse 'true' into `true`, 'false' into `false`, etc.
+ simulateScratchDesktop = JSON.parse(scratchDesktopMatches[1]);
+ } catch {
+ // it's not JSON so just use the string
+ // note that a typo like "falsy" will be treated as true
+ simulateScratchDesktop = scratchDesktopMatches[1];
+ }
+ }
+
if (process.env.NODE_ENV === 'production' && typeof window === 'object') {
// Warn before navigating away
window.onbeforeunload = () => true;
}
ReactDOM.render(
- ,
+ // important: this is checking whether `simulateScratchDesktop` is truthy, not just defined!
+ simulateScratchDesktop ?
+ :
+ ,
appTarget);
};