diff --git a/.all-contributorsrc b/.all-contributorsrc
index a5552987393..20e00e95303 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -1198,6 +1198,15 @@
"contributions": [
"code"
]
+ },
+ {
+ "login": "twhite96",
+ "name": "Tiffany White",
+ "avatar_url": "https://avatars0.githubusercontent.com/u/7698292?v=4",
+ "profile": "https://tiffanywhite.dev",
+ "contributions": [
+ "code"
+ ]
}
],
"repoType": "github",
diff --git a/.eslintrc b/.eslintrc
index d27202d75a7..58efef9ccb5 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -16,6 +16,7 @@
"__DEV__": true
},
"rules": {
+ "linebreak-style": 0,
"react/jsx-filename-extension": 0,
"react/sort-comp": 0,
"import/no-extraneous-dependencies": 0,
diff --git a/README.md b/README.md
index d140b7e0146..7fb78758b86 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-# [CodeSandbox](https://codesandbox.io) [](https://spectrum.chat/codesandbox) [](#contributors) [](https://circleci.com/gh/codesandbox/codesandbox-client) [](https://www.browserstack.com/automate/public-build/cVJuczlJWUtqWXhIbFN1ZjVQekF4NzNsd3phNEZRaGlWU0pHYVVkdGRFWT0tLXFtTVhaOWRySmN0ZG5QVDNDQ0g5Z0E9PQ==--79fe3eae4f149a400d396c9b12d3988f685785cf) [](http://makeapullrequest.com) [](http://www.firsttimersonly.com/)
+# [CodeSandbox](https://codesandbox.io) [](https://spectrum.chat/codesandbox) [](#contributors) [](https://circleci.com/gh/codesandbox/codesandbox-client) [](https://www.browserstack.com/automate/public-build/cVJuczlJWUtqWXhIbFN1ZjVQekF4NzNsd3phNEZRaGlWU0pHYVVkdGRFWT0tLXFtTVhaOWRySmN0ZG5QVDNDQ0g5Z0E9PQ==--79fe3eae4f149a400d396c9b12d3988f685785cf) [](http://makeapullrequest.com) [](http://www.firsttimersonly.com/)
[](#backers) [](#sponsors)
@@ -60,7 +60,7 @@ Thanks goes to these wonderful people
| [The Gitter Badger ](https://gitter.im) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=gitter-badger "Code") | [Tim Whitbeck ](https://github.com/twhitbeck) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=twhitbeck "Code") | [Wei Zhu ](http://twitter.com/yesmeck) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=yesmeck "Code") | [Wil Wilsman ](http://wilwilsman.com) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=wwilsman "Code") | [abnessor aka findoff ](https://codepen.io/findoff/) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=findoff "Code") | [cottom ](http://jerry-i.github.io) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=jerry-i "Code") | [gitname ](https://github.com/gitname) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=gitname "Code") |
| [Bruce Xu ](http://www.xulingming.cn) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=jackdon "Code") | [jess ](http://jessachandler.com) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=monkeywithacupcake "Code") | [Juliette PrΓ©tot ](https://juliette.sh) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=juliettepretot "Code") | [Victoria Bergquist ](https://twitter.com/vicbergquist) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=vicbergquist "Code") [π](https://github.com/codesandbox/codesandbox-client/commits?author=vicbergquist "Documentation") | [Samrith Shankar ](https://github.com/samrith-s) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=samrith-s "Code") | [Mahendra Hirapra ](https://github.com/tinahir) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=tinahir "Code") | [Rabin Gaire ](http://rabingaire.com.np) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=rabingaire "Code") |
| [Neville Mehta ](https://twitter.com/ask_neville) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=nm123github "Code") | [Vasiliy ](https://github.com/Yeti-or) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=Yeti-or "Code") | [Romain Lanz ](https://slynova.io) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=RomainLanz "Code") | [LiBe ](http://libe.toile-libre.org) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=libetl "Code") | [Jeremy Bolding ](http://thecodechef.github.io) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=thecodechef "Code") | [Evan Bacon ](https://twitter.com/baconbrix) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=EvanBacon "Code") | [MichaΓ«l De Boey ](https://michaeldeboey.be) [π](https://github.com/codesandbox/codesandbox-client/issues?q=author%3AMichaelDeBoey "Bug reports") [π»](https://github.com/codesandbox/codesandbox-client/commits?author=MichaelDeBoey "Code") [π](https://github.com/codesandbox/codesandbox-client/commits?author=MichaelDeBoey "Documentation") [π](#infra-MichaelDeBoey "Infrastructure (Hosting, Build-Tools, etc)") [π§](#tool-MichaelDeBoey "Tools") |
-| [gabeeden ](https://github.com/gabeeden) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=gabeeden "Code") |
+| [gabeeden ](https://github.com/gabeeden) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=gabeeden "Code") | [Tiffany White ](https://tiffanywhite.dev) [π»](https://github.com/codesandbox/codesandbox-client/commits?author=twhite96 "Code") |
diff --git a/packages/app/package.json b/packages/app/package.json
index f76d81f0ad2..00c70c25f06 100644
--- a/packages/app/package.json
+++ b/packages/app/package.json
@@ -200,6 +200,7 @@
"memoize-one": "^4.0.0",
"mobx": "^4.0.0",
"mobx-react": "^5.2.3",
+ "mobx-react-lite": "^1.3.2",
"mobx-state-tree": "^3.3.0",
"moment": "^2.18.1",
"monaco-editor-textmate": "^2.0.0",
diff --git a/packages/app/public/apple-touch-icon-152x152.png b/packages/app/public/apple-touch-icon-152x152.png
new file mode 100644
index 00000000000..14f5ec6a7b0
Binary files /dev/null and b/packages/app/public/apple-touch-icon-152x152.png differ
diff --git a/packages/app/public/apple-touch-icon-180x180.png b/packages/app/public/apple-touch-icon-180x180.png
new file mode 100644
index 00000000000..84b5142613c
Binary files /dev/null and b/packages/app/public/apple-touch-icon-180x180.png differ
diff --git a/packages/app/public/apple-touch-icon.png b/packages/app/public/apple-touch-icon.png
new file mode 100644
index 00000000000..84b5142613c
Binary files /dev/null and b/packages/app/public/apple-touch-icon.png differ
diff --git a/packages/app/public/manifest.json b/packages/app/public/manifest.json
index e6c1f166f0a..9ddd3303471 100644
--- a/packages/app/public/manifest.json
+++ b/packages/app/public/manifest.json
@@ -31,6 +31,21 @@
"src": "codesandbox-1024.png",
"type": "image/png",
"sizes": "1024x1024"
+ },
+ {
+ "src": "apple-touch-icon",
+ "type": "image/png",
+ "sizes": "57x57"
+ },
+ {
+ "src": "apple-touch-icon-152x152",
+ "type": "image/png",
+ "sizes": "152x152"
+ },
+ {
+ "src": "apple-touch-icon-180x180.png",
+ "type": "image/png",
+ "sizes": "180x180"
}
],
"description": "An online editor tailored for web applications",
diff --git a/packages/app/src/app/hooks/index.ts b/packages/app/src/app/hooks/index.ts
new file mode 100644
index 00000000000..2e88ceda96b
--- /dev/null
+++ b/packages/app/src/app/hooks/index.ts
@@ -0,0 +1,2 @@
+export { useInterval } from './useInterval';
+export { useScript } from './useScript';
diff --git a/packages/app/src/app/hooks/useInterval.ts b/packages/app/src/app/hooks/useInterval.ts
new file mode 100644
index 00000000000..0c96767ac2e
--- /dev/null
+++ b/packages/app/src/app/hooks/useInterval.ts
@@ -0,0 +1,21 @@
+// Based on https://overreacted.io/making-setinterval-declarative-with-react-hooks/
+import { useEffect, useRef } from 'react';
+
+export const useInterval = (callback = () => {}, delay: number) => {
+ const savedCallback: { current: any } = useRef();
+
+ useEffect(() => {
+ savedCallback.current = callback;
+ }, [callback]);
+
+ useEffect(() => {
+ function tick() {
+ savedCallback.current();
+ }
+ if (delay !== null) {
+ const id = setInterval(tick, delay);
+ return () => clearInterval(id);
+ }
+ return undefined;
+ }, [delay]);
+};
diff --git a/packages/app/src/app/hooks/useScript.ts b/packages/app/src/app/hooks/useScript.ts
new file mode 100644
index 00000000000..06ddd94e59c
--- /dev/null
+++ b/packages/app/src/app/hooks/useScript.ts
@@ -0,0 +1,60 @@
+// Based on https://usehooks.com/useScript/
+import { useState, useEffect } from 'react';
+
+const cachedScripts = [];
+
+export const useScript = (src: string) => {
+ const [state, setState] = useState({
+ loaded: false,
+ error: false,
+ });
+
+ useEffect(() => {
+ if (cachedScripts.includes(src)) {
+ setState({
+ loaded: true,
+ error: false,
+ });
+ } else {
+ cachedScripts.push(src);
+
+ const script = document.createElement('script');
+ script.src = src;
+ script.async = true;
+
+ const onScriptLoad = () => {
+ setState({
+ loaded: true,
+ error: false,
+ });
+ };
+
+ const onScriptError = () => {
+ const index = cachedScripts.indexOf(src);
+
+ if (index >= 0) cachedScripts.splice(index, 1);
+
+ script.remove();
+
+ setState({
+ loaded: true,
+ error: true,
+ });
+ };
+
+ script.addEventListener('load', onScriptLoad);
+ script.addEventListener('error', onScriptError);
+
+ document.body.appendChild(script);
+
+ return () => {
+ script.removeEventListener('load', onScriptLoad);
+ script.removeEventListener('error', onScriptError);
+ };
+ }
+
+ return undefined;
+ }, [src]);
+
+ return [state.loaded, state.error];
+};
diff --git a/packages/app/src/app/index.js b/packages/app/src/app/index.js
index 8663b25b58c..0d0fbadf7ee 100644
--- a/packages/app/src/app/index.js
+++ b/packages/app/src/app/index.js
@@ -10,7 +10,7 @@ import {
logError,
} from '@codesandbox/common/lib/utils/analytics';
import '@codesandbox/common/lib/global.css';
-
+import { Signals, Store } from 'app/store';
import history from 'app/utils/history';
import { client } from 'app/graphql/client';
import registerServiceWorker from '@codesandbox/common/lib/registerServiceWorker';
@@ -119,16 +119,21 @@ function boot() {
});
try {
+ const { signals, store } = controller.provide();
render(
-
-
-
-
-
-
-
-
- ,
+
+
+
+
+
+
+
+
+
+
+
+
+ ,
rootEl
);
} catch (e) {
diff --git a/packages/app/src/app/pages/Dashboard/Sidebar/index.js b/packages/app/src/app/pages/Dashboard/Sidebar/index.js
index fce06bc819e..db0110761ae 100644
--- a/packages/app/src/app/pages/Dashboard/Sidebar/index.js
+++ b/packages/app/src/app/pages/Dashboard/Sidebar/index.js
@@ -18,7 +18,7 @@ import { TEAMS_QUERY } from '../queries';
class Sidebar extends React.Component {
handleSearchFocus = () => {
- history.push('/dashboard/search');
+ history.push('/dashboard/search', { from: 'sandboxSearchFocused' });
};
handleSearchChange = e => {
diff --git a/packages/app/src/app/pages/Dashboard/index.js b/packages/app/src/app/pages/Dashboard/index.js
index 59db9432f75..6c1ad8061af 100644
--- a/packages/app/src/app/pages/Dashboard/index.js
+++ b/packages/app/src/app/pages/Dashboard/index.js
@@ -52,7 +52,11 @@ class Dashboard extends React.Component {
} = this.props;
const { showSidebar } = this.state;
- history.listen(() => {
+ history.listen(({ state }) => {
+ if (Boolean(state) && state.from === 'sandboxSearchFocused') {
+ return;
+ }
+
this.onRouteChange();
});
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/Advertisement.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/Advertisement.tsx
new file mode 100644
index 00000000000..3e1341d699f
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/Advertisement.tsx
@@ -0,0 +1,13 @@
+import React from 'react';
+import { useScript } from 'app/hooks';
+import { Container } from './elements';
+
+export const Advertisement = () => {
+ useScript(`https://codefund.app/properties/24/funder.js`);
+
+ return (
+
+
+
+ );
+};
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/CodeFund.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/CodeFund.js
deleted file mode 100644
index 277f17e5e78..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/CodeFund.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import React from 'react';
-import styled from 'styled-components';
-
-const Container = styled.div`
- .cf-text {
- color: ${props =>
- props.theme.light
- ? `rgba(0, 0, 0, 0.8)`
- : `rgba(255, 255, 255, 0.8)`} !important;
- }
-`;
-
-const CODEFUND_LINK = 'https://codefund.app/properties/24/funder.js';
-let loaded = false;
-
-export default class CodeFund extends React.PureComponent {
- componentDidMount() {
- if (!loaded) {
- loaded = true;
-
- const script = document.createElement('script');
- script.setAttribute('src', CODEFUND_LINK);
- script.async = 'true';
- script.setAttribute('id', 'external-js');
- document.head.appendChild(script);
- }
- }
-
- render() {
- return (
-
-
-
- );
- }
-}
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/elements.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/elements.js
deleted file mode 100644
index e277af51698..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/elements.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import styled from 'styled-components';
-
-export const Container = styled.div`
- padding: 1rem;
- border-top: 1px solid rgba(0, 0, 0, 0.3);
-
- .carbon-text {
- text-decoration: none !important;
- color: rgba(255, 255, 255, 0.9) !important;
- }
-
- .carbon-wrap {
- font-size: 0.875rem;
-
- img {
- display: block;
- margin-bottom: 0.5rem;
- }
- }
-
- .carbon-poweredby {
- display: block;
- margin-top: 0.5rem;
-
- font-size: 0.75rem;
- text-decoration: none !important;
- color: rgba(255, 255, 255, 0.6) !important;
- }
-`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/elements.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/elements.ts
new file mode 100644
index 00000000000..a094e7742b9
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/elements.ts
@@ -0,0 +1,9 @@
+import styled, { css } from 'styled-components';
+
+export const Container = styled.div`
+ ${({ theme }) => css`
+ color: ${theme.light
+ ? css`rgba(0, 0, 0, 0.8)`
+ : css`rgba(255, 255, 255, 0.8)`} !important;
+ `};
+`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/index.js
deleted file mode 100644
index e385b45f41b..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/index.js
+++ /dev/null
@@ -1,5 +0,0 @@
-import React from 'react';
-
-import CodeFund from './CodeFund';
-
-export default () => ;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/index.ts
new file mode 100644
index 00000000000..10de49bbfd1
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Advertisement/index.ts
@@ -0,0 +1 @@
+export { Advertisement } from './Advertisement';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/ConnectionNotice.tsx
similarity index 61%
rename from packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/index.js
rename to packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/ConnectionNotice.tsx
index 8d1d51701f7..cf70782abb6 100644
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/index.js
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/ConnectionNotice.tsx
@@ -1,11 +1,13 @@
import React from 'react';
-import { inject, observer } from 'mobx-react';
-
+import { observer } from 'mobx-react-lite';
+import { useStore } from 'app/store';
import { Container } from './elements';
-function ConnectionNotice({ store }) {
+export const ConnectionNotice = observer(() => {
+ const { connected } = useStore();
+
return (
- !store.connected && (
+ !connected && (
You{"'"}re not connected to the internet. You can still edit, but you
cannot save. We recommend using the {"'"}Download{"'"} function to keep
@@ -13,6 +15,4 @@ function ConnectionNotice({ store }) {
)
);
-}
-
-export default inject('store')(observer(ConnectionNotice));
+});
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/elements.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/elements.js
deleted file mode 100644
index fbbae7ce7dd..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/elements.js
+++ /dev/null
@@ -1,8 +0,0 @@
-import styled from 'styled-components';
-
-export const Container = styled.div`
- color: ${props => props.theme.red};
- background-color: ${props => props.theme.redBackground};
- padding: 1rem;
- font-size: 0.75rem;
-`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/elements.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/elements.ts
new file mode 100644
index 00000000000..895269a659a
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/elements.ts
@@ -0,0 +1,10 @@
+import styled, { css } from 'styled-components';
+
+export const Container = styled.div`
+ ${({ theme }) => css`
+ color: ${theme.red};
+ background-color: ${theme.redBackground};
+ padding: 1rem;
+ font-size: 0.75rem;
+ `}
+`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/index.ts
new file mode 100644
index 00000000000..912664f02ae
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/ConnectionNotice/index.ts
@@ -0,0 +1 @@
+export { ConnectionNotice } from './ConnectionNotice';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/CreateRepo/elements.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/CreateRepo/elements.js
deleted file mode 100644
index c6f83c5e137..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/CreateRepo/elements.js
+++ /dev/null
@@ -1,7 +0,0 @@
-import styled from 'styled-components';
-
-export const Error = styled.div`
- margin: 1rem;
- color: ${({ theme }) => theme.red};
- font-size: 0.875rem;
-`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/CreateRepo/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/CreateRepo/index.js
deleted file mode 100644
index 182cc300612..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/CreateRepo/index.js
+++ /dev/null
@@ -1,53 +0,0 @@
-import React from 'react';
-import { inject, observer } from 'mobx-react';
-
-import Margin from '@codesandbox/common/lib/components/spacing/Margin';
-import Input from '@codesandbox/common/lib/components/Input';
-import { Button } from '@codesandbox/common/lib/components/Button';
-
-import { WorkspaceSubtitle, WorkspaceInputContainer } from '../elements';
-
-import { Error } from './elements';
-
-class CreateRepo extends React.Component {
- updateRepoTitle = e => {
- this.props.signals.git.repoTitleChanged({ title: e.target.value });
- };
-
- createRepo = () => {
- this.props.signals.git.createRepoClicked();
- };
-
- render() {
- const { store, style } = this.props;
- const modulesNotSaved = !store.editor.isAllModulesSynced;
- const repoTitle = store.git.repoTitle;
- const error = store.git.error;
-
- return (
-
- {modulesNotSaved && (
- Save your files first before exporting.
- )}
- {error && {error} }
-
- Repository Name
-
-
-
-
-
- Create Repository
-
-
-
- );
- }
-}
-
-export default inject('signals', 'store')(observer(CreateRepo));
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/Changes/elements.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/Changes/elements.js
deleted file mode 100644
index e91a9a72960..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/Changes/elements.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import styled, { css } from 'styled-components';
-import { EntryContainer } from '../../elements';
-
-export const ChangeContainer = styled.div`
- &:last-child {
- border-bottom: none;
- }
-`;
-
-export const Entry = styled(EntryContainer)`
- display: flex;
- align-items: center;
- line-height: 1;
- color: ${props => props.theme.vscodeTheme.colors['editor.foreground']};
- ${({ hideColor }) =>
- hideColor &&
- css`
- background-color: transparent;
- padding-left: 0;
- `};
-
- svg {
- color: ${({ color }) => color};
- margin-right: 0.5rem;
- }
-`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/Changes/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/Changes/index.js
deleted file mode 100644
index 3bf5899981d..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/Changes/index.js
+++ /dev/null
@@ -1,66 +0,0 @@
-import React from 'react';
-
-import theme from '@codesandbox/common/lib/theme';
-
-import AddedIcon from 'react-icons/lib/go/diff-added';
-import ModifiedIcon from 'react-icons/lib/go/diff-modified';
-import RemovedIcon from 'react-icons/lib/go/diff-removed';
-
-import Tooltip from '@codesandbox/common/lib/components/Tooltip';
-
-import { ChangeContainer, Entry } from './elements';
-
-function Changes({ changes, color, Icon, title, hideColor }) {
- return (
-
- {changes.sort().map(change => (
-
-
-
-
-
- {change}
-
-
- ))}
-
- );
-}
-
-export function Added({ changes, hideColor }) {
- return (
-
- );
-}
-
-export function Modified({ changes, hideColor }) {
- return (
-
- );
-}
-
-export function Deleted({ changes, hideColor }) {
- return (
-
- );
-}
-
-export default Changes;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/TotalChanges/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/TotalChanges/index.js
deleted file mode 100644
index 5b5610464b0..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/TotalChanges/index.js
+++ /dev/null
@@ -1,14 +0,0 @@
-import React from 'react';
-import { Added, Modified, Deleted } from '../Changes';
-
-function TotalChanges({ gitChanges, hideColor }) {
- return (
-
- );
-}
-
-export default TotalChanges;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/elements.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/elements.js
deleted file mode 100644
index 489a2414f24..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/elements.js
+++ /dev/null
@@ -1,21 +0,0 @@
-import styled from 'styled-components';
-
-export const Container = styled.div`
- color: ${props =>
- props.theme.light ? 'rgba(0, 0, 0, 0.8)' : 'rgba(255, 255, 255, 0.8)'};
-`;
-
-export const Buttons = styled.div`
- display: flex;
- margin: 1rem 0.125rem;
-
- button {
- margin: 0 0.875rem;
- }
-`;
-
-export const ErrorMessage = styled.div`
- color: ${({ theme }) => theme.red};
- margin: 1rem;
- font-size: 0.875rem;
-`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/index.js
deleted file mode 100644
index 18a5d421103..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/Git/index.js
+++ /dev/null
@@ -1,153 +0,0 @@
-import React from 'react';
-import { inject, observer } from 'mobx-react';
-
-import Margin from '@codesandbox/common/lib/components/spacing/Margin';
-import GithubBadge from '@codesandbox/common/lib/components/GithubBadge';
-import { githubRepoUrl } from '@codesandbox/common/lib/utils/url-generator';
-import { Button } from '@codesandbox/common/lib/components/Button';
-import Notice from '@codesandbox/common/lib/components/Notice';
-import Input, { TextArea } from '@codesandbox/common/lib/components/Input';
-
-import TotalChanges from './TotalChanges';
-import { WorkspaceSubtitle, WorkspaceInputContainer } from '../elements';
-
-import { Container, Buttons, ErrorMessage } from './elements';
-
-function hasWriteAccess(rights: 'none' | 'read' | 'write' | 'admin') {
- return rights === 'write' || rights === 'admin';
-}
-
-class Git extends React.Component {
- componentDidMount() {
- this.props.signals.git.gitMounted();
- }
- createCommit = () => {
- this.props.signals.git.createCommitClicked();
- };
-
- createPR = () => {
- this.props.signals.git.createPrClicked();
- };
-
- changeSubject = event => {
- this.props.signals.git.subjectChanged({
- subject: event.target.value,
- });
- };
-
- changeDescription = event => {
- this.props.signals.git.descriptionChanged({
- description: event.target.value,
- });
- };
-
- render() {
- const { store } = this.props;
- const gitChanges = store.git.originalGitChanges;
- const originalGit = store.editor.currentSandbox.originalGit;
- const modulesNotSaved = !store.editor.isAllModulesSynced;
- const changeCount = gitChanges
- ? gitChanges.added.length +
- gitChanges.modified.length +
- gitChanges.deleted.length
- : 0;
-
- return (
-
- beta
- GitHub Repository
-
-
-
-
-
- Changes ({gitChanges ? changeCount : '...'})
-
- {!store.git.isFetching && gitChanges ? (
-
-
-
- {changeCount > 0 ? (
-
- Commit Info
- {modulesNotSaved && (
-
- You need to save all modules before you can commit
-
- )}
- 72 ? `#F27777` : `#556362`,
- textAlign: 'right',
- }}
- >
- {`${store.git.subject.length}/72`}
-
-
-
-
-
-
-
-
- {hasWriteAccess(gitChanges.rights) && (
-
- Commit
-
- )}
-
- Open PR
-
-
-
- ) : (
-
-
- There are no changes
-
-
- )}
-
- ) : (
-
- Fetching changes...
-
- )}
-
-
- );
- }
-}
-
-export default inject('signals', 'store')(observer(Git));
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/SSEDownNotice.tsx
similarity index 87%
rename from packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/index.js
rename to packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/SSEDownNotice.tsx
index c2724312670..0632013d7c9 100644
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/index.js
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/SSEDownNotice.tsx
@@ -1,10 +1,11 @@
import React from 'react';
-import { observer, inject } from 'mobx-react';
+import { observer } from 'mobx-react-lite';
import getTemplate from '@codesandbox/common/lib/templates';
-
+import { useStore } from 'app/store';
import { Container } from './elements';
-const ConnectionNotice = ({ store }) => {
+export const SSEDownNotice = observer(() => {
+ const store = useStore();
const templateDef = getTemplate(store.editor.currentSandbox.template);
if (!templateDef.isServer) {
return null;
@@ -46,6 +47,4 @@ const ConnectionNotice = ({ store }) => {
);
-};
-
-export default inject('store')(observer(ConnectionNotice));
+});
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/elements.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/elements.js
deleted file mode 100644
index 3e6eb777998..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/elements.js
+++ /dev/null
@@ -1,10 +0,0 @@
-import styled from 'styled-components';
-
-export const Container = styled.div`
- color: rgba(255, 255, 255, 0.9);
- background-color: ${props => props.theme.secondary};
- padding: 1rem;
- font-size: 0.8rem;
- font-weight: 500;
- line-height: 1.4;
-`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/elements.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/elements.ts
new file mode 100644
index 00000000000..d92979aff26
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/elements.ts
@@ -0,0 +1,12 @@
+import styled, { css } from 'styled-components';
+
+export const Container = styled.div`
+ ${({ theme }) => css`
+ color: rgba(255, 255, 255, 0.9);
+ background-color: ${theme.secondary};
+ padding: 1rem;
+ font-size: 0.8rem;
+ font-weight: 500;
+ line-height: 1.4;
+ `}
+`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/index.ts
new file mode 100644
index 00000000000..7024f287a70
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/SSEDownNotice/index.ts
@@ -0,0 +1 @@
+export { SSEDownNotice } from './SSEDownNotice';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/index.js
index 4ee0245f7ed..13a21738f76 100644
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/index.js
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/index.js
@@ -8,19 +8,19 @@ import SocialInfo from 'app/components/SocialInfo';
import Files from './items/Files';
import ProjectInfo from './items/ProjectInfo';
-import GitHub from './items/GitHub';
+import { GitHub } from './items/GitHub';
import Server from './items/Server';
-import Live from './items/Live';
-import More from './items/More';
-import Deployment from './items/Deployment';
+import { Live } from './items/Live';
+import { More } from './items/More';
+import { Deployment } from './items/Deployment';
import ConfigurationFiles from './items/ConfigurationFiles';
-import NotOwnedSandboxInfo from './items/NotOwnedSandboxInfo';
+import { NotOwnedSandboxInfo } from './items/NotOwnedSandboxInfo';
-import ConnectionNotice from './ConnectionNotice';
-import Advertisement from './Advertisement';
+import { ConnectionNotice } from './ConnectionNotice';
+import { Advertisement } from './Advertisement';
import WorkspaceItem from './WorkspaceItem';
import Chat from './Chat';
-import SSEDownNotice from './SSEDownNotice';
+import { SSEDownNotice } from './SSEDownNotice';
import {
Container,
@@ -29,7 +29,7 @@ import {
VersionContainer,
} from './elements';
-const idToItem = {
+const workspaceTabs = {
project: ProjectInfo,
'project-summary': NotOwnedSandboxInfo,
files: Files,
@@ -45,15 +45,15 @@ function Workspace({ store }) {
const sandbox = store.editor.currentSandbox;
const preferences = store.preferences;
- const currentItem = store.workspace.openedWorkspaceItem;
+ const activeTab = store.workspace.openedWorkspaceItem;
- if (!currentItem) {
+ if (!activeTab) {
return null;
}
- const Component = idToItem[currentItem];
+ const Component = workspaceTabs[activeTab];
- const item = getWorkspaceItems(store).find(i => i.id === currentItem);
+ const item = getWorkspaceItems(store).find(i => i.id === activeTab);
return (
{item && !item.hasCustomHeader && {item.name} }
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Deployment.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Deployment.tsx
new file mode 100644
index 00000000000..8ca195e4a4d
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Deployment.tsx
@@ -0,0 +1,23 @@
+import React, { useEffect } from 'react';
+import { useSignals } from 'app/store';
+import { Description } from '../../elements';
+import { Zeit } from './Zeit';
+import { Netlify } from './Netlify';
+
+export const Deployment = () => {
+ const {
+ deployment: { getDeploys },
+ } = useSignals();
+ useEffect(() => getDeploys(), []); // eslint-disable-line
+
+ return (
+
+
+ You can deploy a production version of your sandbox using one our
+ supported providers.
+
+
+
+
+ );
+};
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Elements.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Elements.js
deleted file mode 100644
index c73e8a26046..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Elements.js
+++ /dev/null
@@ -1,129 +0,0 @@
-import styled, { css } from 'styled-components';
-
-const mapColorToState = (state, theme) => {
- const STARTING = ['DEPLOYING', 'BUILDING', 'INITIALIZING'];
- const ERROR = ['DEPLOYMENT_ERROR', 'BUILD_ERROR', 'ERROR'];
- const STARTED = ['BOOTED', 'READY'];
-
- if (STARTING.includes(state)) return '#fccb7e';
- if (ERROR.includes(state)) return theme.red;
- if (STARTED.includes(state)) return theme.green;
- if (state === 'FROZEN') return theme.blue;
-
- return theme.gray;
-};
-
-export const State = styled.span`
- align-items: center;
- display: flex;
- text-transform: capitalize;
- margin-bottom: 0.5rem;
-
- &:before {
- content: '';
- display: block;
- width: 10px;
- height: 10px;
- border-radius: 50%;
- margin-right: 0.5rem;
- background: ${props => mapColorToState(props.state, props.theme)};
- }
-`;
-
-export const Deploys = styled.ul`
- list-style: none;
- padding: 0;
- margin-top: 1rem;
- flex-direction: column;
- font-size: 0.875rem;
- margin: 0 0.25rem;
-`;
-
-export const Deploy = styled.li`
- display: flex;
- margin-bottom: 1.5rem;
- flex-direction: column;
-`;
-
-export const Name = styled.span`
- font-weight: 600;
- color: ${props =>
- props.theme.light || props.light
- ? 'rgba(0, 0, 0, 0.8)'
- : 'rgba(255, 255, 255, 0.8)'};
- font-size: 1rem;
- margin-top: 0;
- vertical-align: middle;
-
- span {
- color: ${props =>
- props.theme.light || props.light
- ? props.theme.background3.darken(0.5)
- : props.theme.background3.lighten(0.5)};
- font-size: 12px;
- margin-left: 0.5rem;
- }
-`;
-
-export const Link = styled.a`
- padding: 0.25rem 0.4rem;
- background-color: ${props => props.theme.secondary};
- text-decoration: none;
- border: none;
- font-size: 0.75rem;
- color: white;
- border-radius: 2px;
- font-weight: 600;
- margin-top: 0.75rem;
- display: flex;
- align-items: center;
- flex-grow: 0;
- max-width: 50%;
-
- svg {
- margin-right: 10px;
- }
-
- ${props =>
- props.disabled &&
- css`
- background: ${props.theme.gray};
- pointer-events: none;
- `};
-
- &:disabled {
- background: ${props => props.theme.gray};
- }
-`;
-
-export const Action = Link.withComponent('button');
-
-export const ButtonContainer = styled.section`
- display: flex;
- > *:not(:last-child) {
- margin-right: 0.5rem;
- }
-`;
-
-export const DeploysWrapper = styled.div`
- background: rgb(0, 0, 0);
- border-radius: 4px;
- font-size: 0.875rem;
- color: rgba(255, 255, 255, 0.8);
- padding: 0.75rem 1rem;
- padding: 0.75rem 0rem;
- border-top-right-radius: 0;
- border-top-left-radius: 0;
- margin: 0.5rem 0.75rem;
- margin-top: 0;
-`;
-
-export const Wrapper = styled.div`
- opacity: 1;
- ${props =>
- props.loading &&
- css`
- opacity: 0.5;
- pointer-events: none;
- `};
-`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Netlify.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Netlify.js
deleted file mode 100644
index c3deb20da64..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Netlify.js
+++ /dev/null
@@ -1,206 +0,0 @@
-import React, { Component } from 'react';
-import { inject, observer } from 'mobx-react';
-
-import LinkIcon from 'react-icons/lib/fa/external-link';
-import Cogs from 'react-icons/lib/fa/cogs';
-import LightningIcon from 'react-icons/lib/md/flash-on';
-import NetlifyLogo from 'app/components/NetlifyLogo';
-import DeploymentIntegration from 'app/components/DeploymentIntegration';
-import getTemplate from '@codesandbox/common/lib/templates';
-import { Button } from '@codesandbox/common/lib/components/Button';
-import { resolveDirectory } from '@codesandbox/common/lib/sandbox/modules';
-import getNetlifyConfig from 'app/utils/getNetlifyConfig';
-import { WorkspaceInputContainer, WorkspaceSubtitle } from '../../elements';
-import {
- Deploys,
- Deploy,
- Name,
- Link,
- DeploysWrapper,
- Wrapper,
- ButtonContainer,
-} from './Elements';
-
-const getFunctionDir = sandbox => {
- try {
- return resolveDirectory(
- getNetlifyConfig(sandbox).functions,
- sandbox.modules,
- sandbox.directories
- );
- } catch (e) {
- return [];
- }
-};
-
-class NetlifyDeployment extends Component {
- state = { show: false };
-
- toggleNetlify = () =>
- this.setState(state => ({
- show: !state.show,
- }));
-
- componentDidMount() {
- this.props.signals.deployment.getNetlifyDeploys();
- }
-
- render() {
- const {
- store: { deployment, editor },
- signals,
- } = this.props;
-
- const template = getTemplate(editor.currentSandbox.template);
- const { show } = this.state;
- const functionDirectory = getFunctionDir(editor.currentSandbox);
-
- const functions = editor.currentSandbox.modules.filter(
- m => m.directoryShortid === functionDirectory.shortid
- );
- return (
- template.netlify !== false && (
-
-
- this.toggleNetlify()}
- color="#fff"
- light
- Icon={NetlifyLogo}
- name="netlify"
- beta
- deploy={() => signals.deployment.deployWithNetlify()}
- >
- Deploy your sandbox site on{' '}
-
- Netlify
-
-
-
- {deployment.netlifySite && show ? (
-
- Sandbox Site
-
-
-
- {deployment.netlifySite.name}
- {!deployment.building && Building
}
- {functions.length ? (
- <>
-
- Functions
-
-
- {functions.map(file => (
-
-
- {file.title.split('.js')[0]}
-
- ))}
-
- >
- ) : null}
-
-
- Actions
-
-
-
- {deployment.building ? (
- <>
- Building...
- >
- ) : (
- <>
- Visit
- >
- )}
-
-
- {deployment.netlifyClaimUrl ? (
-
- Claim Site
-
- ) : null}
-
- {deployment.netlifyLogs ? (
-
- signals.modalOpened({
- modal: 'netlifyLogs',
- })
- }
- >
- View Logs
-
- ) : null}
-
-
-
-
- ) : null}
-
- )
- );
- }
-}
-export default inject('signals', 'store')(observer(NetlifyDeployment));
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Netlify.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Netlify.tsx
new file mode 100644
index 00000000000..8f7e167d98b
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Netlify.tsx
@@ -0,0 +1,192 @@
+import React, { useEffect, useState } from 'react';
+import { observer } from 'mobx-react-lite';
+import LinkIcon from 'react-icons/lib/fa/external-link';
+import Cogs from 'react-icons/lib/fa/cogs';
+import LightningIcon from 'react-icons/lib/md/flash-on';
+import getTemplate from '@codesandbox/common/lib/templates';
+import { Button } from '@codesandbox/common/lib/components/Button';
+import { resolveDirectory } from '@codesandbox/common/lib/sandbox/modules';
+import NetlifyLogo from 'app/components/NetlifyLogo';
+import DeploymentIntegration from 'app/components/DeploymentIntegration';
+import getNetlifyConfig from 'app/utils/getNetlifyConfig';
+import { useSignals, useStore } from 'app/store';
+import { WorkspaceInputContainer, WorkspaceSubtitle } from '../../elements';
+import {
+ Deploys,
+ Deploy,
+ Name,
+ Link,
+ DeploysWrapper,
+ Wrapper,
+ ButtonContainer,
+} from './elements';
+
+const getFunctionDir = sandbox => {
+ try {
+ return resolveDirectory(
+ getNetlifyConfig(sandbox).functions,
+ sandbox.modules,
+ sandbox.directories
+ );
+ } catch (e) {
+ return [];
+ }
+};
+
+export const Netlify = observer(() => {
+ const {
+ deployment: { getNetlifyDeploys, deployWithNetlify },
+ modalOpened,
+ } = useSignals();
+ const { deployment, editor } = useStore();
+ const [isVisible, setVisibility] = useState(false);
+
+ useEffect(() => getNetlifyDeploys(), []); // eslint-disable-line
+
+ const template = getTemplate(editor.currentSandbox.template);
+ const functionDirectory = getFunctionDir(editor.currentSandbox);
+
+ const functions = editor.currentSandbox.modules.filter(
+ m => m.directoryShortid === functionDirectory.shortid
+ );
+
+ return (
+ template.netlify !== false && (
+
+
+ setVisibility(!isVisible)}
+ color="#fff"
+ light
+ Icon={NetlifyLogo}
+ name="netlify"
+ beta
+ deploy={() => deployWithNetlify()}
+ >
+ Deploy your sandbox site on{' '}
+
+ Netlify
+
+
+
+ {deployment.netlifySite && isVisible ? (
+
+ Sandbox Site
+
+
+
+ {deployment.netlifySite.name}
+ {!deployment.building && Building
}
+ {functions.length ? (
+ <>
+
+ Functions
+
+
+ {functions.map(file => (
+
+
+ {file.title.split('.js')[0]}
+
+ ))}
+
+ >
+ ) : null}
+
+
+ Actions
+
+
+
+ {deployment.building ? (
+ <>
+ Building...
+ >
+ ) : (
+ <>
+ Visit
+ >
+ )}
+
+
+ {deployment.netlifyClaimUrl ? (
+
+ Claim Site
+
+ ) : null}
+
+ {deployment.netlifyLogs ? (
+
+ modalOpened({
+ modal: 'netlifyLogs',
+ })
+ }
+ >
+ View Logs
+
+ ) : null}
+
+
+
+
+ ) : null}
+
+ )
+ );
+});
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Zeit.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Zeit.js
deleted file mode 100644
index a347be1f6d4..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Zeit.js
+++ /dev/null
@@ -1,144 +0,0 @@
-import React, { Fragment, Component } from 'react';
-import { inject, observer } from 'mobx-react';
-import TrashIcon from 'react-icons/lib/fa/trash';
-import LinkIcon from 'react-icons/lib/fa/external-link';
-import distanceInWordsToNow from 'date-fns/distance_in_words_to_now';
-import NowLogo from 'app/components/NowLogo';
-import DeploymentIntegration from 'app/components/DeploymentIntegration';
-import ZeitIntegration from '../../../../../common/ZeitIntegration';
-import { WorkspaceInputContainer, WorkspaceSubtitle } from '../../elements';
-import {
- Deploys,
- Wrapper,
- Deploy,
- State,
- Name,
- Link,
- Action,
- ButtonContainer,
- DeploysWrapper,
-} from './Elements';
-
-class ZeitDeployment extends Component {
- state = { show: false };
-
- toggleZeit = () =>
- this.setState(state => ({
- show: !state.show,
- }));
-
- render() {
- const {
- signals,
- store: { user, deployment },
- } = this.props;
-
- const { show } = this.state;
- return user.integrations.zeit ? (
-
-
- this.toggleZeit()}
- color="#000000"
- Icon={NowLogo}
- name="Now"
- deploy={() => signals.deployment.deploySandboxClicked()}
- >
- Deploy your sandbox on{' '}
-
- ZEIT Now
-
-
-
- {deployment.sandboxDeploys.length && show ? (
-
- Sandbox Deploys
-
-
- {deployment.sandboxDeploys.map(deploy => (
-
-
- {deploy.name}
- ({distanceInWordsToNow(deploy.created)} ago)
-
-
- {deploy.state.toLowerCase()}
-
- {deploy.alias.length ? (
-
- Aliased to{' '}
- {deploy.alias.map(a => (
-
- {a.alias}
-
- ))}
-
- ) : null}
-
-
- Visit
-
- {
- signals.deployment.setDeploymentToDelete({
- id: deploy.uid,
- });
- signals.modalOpened({
- modal: 'deleteDeployment',
- });
- }}
- >
- {deployment[`${deploy.uid}Deleting`] ? (
- 'Deleting'
- ) : (
-
- Delete
-
- )}
-
- {deployment.hasAlias && deploy.state === 'READY' ? (
- {
- signals.deployment.aliasDeployment({
- id: deploy.uid,
- });
- }}
- >
- {deploy.alias.length ? 'Aliased' : 'Alias'}
-
- ) : null}
-
-
- ))}
-
-
-
- ) : null}
-
- ) : (
-
-
-
- );
- }
-}
-export default inject('signals', 'store')(observer(ZeitDeployment));
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Zeit.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Zeit.tsx
new file mode 100644
index 00000000000..16f5b5af89b
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/Zeit.tsx
@@ -0,0 +1,132 @@
+import React, { useState } from 'react';
+import { observer } from 'mobx-react-lite';
+import TrashIcon from 'react-icons/lib/fa/trash';
+import LinkIcon from 'react-icons/lib/fa/external-link';
+import distanceInWordsToNow from 'date-fns/distance_in_words_to_now';
+import NowLogo from 'app/components/NowLogo';
+import DeploymentIntegration from 'app/components/DeploymentIntegration';
+import { useSignals, useStore } from 'app/store';
+import ZeitIntegration from 'app/pages/common/ZeitIntegration';
+import { WorkspaceInputContainer, WorkspaceSubtitle } from '../../elements';
+import {
+ Deploys,
+ Wrapper,
+ Deploy,
+ State,
+ Name,
+ Link,
+ Action,
+ ButtonContainer,
+ DeploysWrapper,
+} from './elements';
+
+export const Zeit = observer(() => {
+ const {
+ deployment: {
+ deploySandboxClicked,
+ setDeploymentToDelete,
+ aliasDeployment,
+ },
+ modalOpened,
+ } = useSignals();
+ const { user, deployment } = useStore();
+ const [isVisible, setVisibility] = useState(false);
+
+ return user.integrations.zeit ? (
+
+
+ setVisibility(!isVisible)}
+ color="#000000"
+ Icon={NowLogo}
+ name="Now"
+ deploy={() => deploySandboxClicked()}
+ >
+ Deploy your sandbox on{' '}
+
+ ZEIT Now
+
+
+
+ {deployment.sandboxDeploys.length && isVisible ? (
+
+ Sandbox Deploys
+
+
+ {deployment.sandboxDeploys.map(deploy => (
+
+
+ {deploy.name}
+ ({distanceInWordsToNow(deploy.created)} ago)
+
+
+ {deploy.state.toLowerCase()}
+
+ {deploy.alias.length ? (
+
+ Aliased to{' '}
+ {deploy.alias.map(a => (
+
+ {a.alias}
+
+ ))}
+
+ ) : null}
+
+
+ Visit
+
+ {
+ setDeploymentToDelete({ id: deploy.uid });
+ modalOpened({ modal: 'deleteDeployment' });
+ }}
+ >
+ {deployment[`${deploy.uid}Deleting`] ? (
+ 'Deleting'
+ ) : (
+ <>
+ Delete
+ >
+ )}
+
+ {deployment.hasAlias && deploy.state === 'READY' ? (
+ aliasDeployment({ id: deploy.uid })}
+ >
+ {deploy.alias.length ? 'Aliased' : 'Alias'}
+
+ ) : null}
+
+
+ ))}
+
+
+
+ ) : null}
+
+ ) : (
+
+
+
+ );
+});
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/elements.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/elements.ts
new file mode 100644
index 00000000000..0ea8e6a0af7
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/elements.ts
@@ -0,0 +1,133 @@
+import styled, { css } from 'styled-components';
+
+const mapColorToState = (state: string, theme: any) => {
+ const STARTING = ['DEPLOYING', 'BUILDING', 'INITIALIZING'];
+ const ERROR = ['DEPLOYMENT_ERROR', 'BUILD_ERROR', 'ERROR'];
+ const STARTED = ['BOOTED', 'READY'];
+
+ if (STARTING.includes(state)) return '#fccb7e';
+ if (ERROR.includes(state)) return theme.red;
+ if (STARTED.includes(state)) return theme.green;
+ if (state === 'FROZEN') return theme.blue;
+
+ return theme.gray;
+};
+
+export const State = styled.span`
+ ${({ state, theme }: { state: string; theme: any }) => css`
+ align-items: center;
+ display: flex;
+ text-transform: capitalize;
+ margin-bottom: 0.5rem;
+
+ &:before {
+ content: '';
+ display: block;
+ width: 10px;
+ height: 10px;
+ border-radius: 50%;
+ margin-right: 0.5rem;
+ background: ${mapColorToState(state, theme)};
+ }
+ `}
+`;
+
+export const Deploys = styled.ul`
+ list-style: none;
+ padding: 0;
+ margin-top: 1rem;
+ flex-direction: column;
+ font-size: 0.875rem;
+ margin: 0 0.25rem;
+`;
+
+export const Deploy = styled.li`
+ display: flex;
+ margin-bottom: 1.5rem;
+ flex-direction: column;
+`;
+
+export const Name = styled.span`
+ ${({ light, theme }: { light: boolean; theme: any }) => css`
+ font-weight: 600;
+ color: ${theme.light || light
+ ? css`rgba(0, 0, 0, 0.8)`
+ : css`rgba(255, 255, 255, 0.8)`};
+ font-size: 1rem;
+ margin-top: 0;
+ vertical-align: middle;
+
+ span {
+ color: ${theme.light || light
+ ? theme.background3.darken(0.5)
+ : theme.background3.lighten(0.5)};
+ font-size: 12px;
+ margin-left: 0.5rem;
+ }
+ `}
+`;
+
+export const Link = styled.a`
+ ${({ disabled, theme }: { disabled: boolean; theme: any }) => css`
+ padding: 0.25rem 0.4rem;
+ background-color: ${theme.secondary};
+ text-decoration: none;
+ border: none;
+ font-size: 0.75rem;
+ color: white;
+ border-radius: 2px;
+ font-weight: 600;
+ margin-top: 0.75rem;
+ display: flex;
+ align-items: center;
+ flex-grow: 0;
+ max-width: 50%;
+
+ svg {
+ margin-right: 10px;
+ }
+
+ ${disabled &&
+ css`
+ background: ${theme.gray};
+ pointer-events: none;
+ `};
+
+ &:disabled {
+ background: ${theme.gray};
+ }
+ `}
+`;
+
+export const Action = Link.withComponent('button');
+
+export const ButtonContainer = styled.section`
+ display: flex;
+ > *:not(:last-child) {
+ margin-right: 0.5rem;
+ }
+`;
+
+export const DeploysWrapper = styled.div`
+ background: rgb(0, 0, 0);
+ border-radius: 4px;
+ font-size: 0.875rem;
+ color: rgba(255, 255, 255, 0.8);
+ padding: 0.75rem 1rem;
+ padding: 0.75rem 0rem;
+ border-top-right-radius: 0;
+ border-top-left-radius: 0;
+ margin: 0.5rem 0.75rem;
+ margin-top: 0;
+`;
+
+export const Wrapper = styled.div`
+ ${({ loading }: { loading: boolean }) => css`
+ opacity: 1;
+ ${loading &&
+ css`
+ opacity: 0.5;
+ pointer-events: none;
+ `};
+ `}
+`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/index.js
deleted file mode 100644
index 62830469d8a..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/index.js
+++ /dev/null
@@ -1,26 +0,0 @@
-import React, { Component } from 'react';
-import { inject, observer } from 'mobx-react';
-import { Description } from '../../elements';
-import ZeitDeployments from './Zeit';
-import NetlifyDeployments from './Netlify';
-
-class Deployment extends Component {
- componentDidMount = () => {
- this.props.signals.deployment.getDeploys();
- };
-
- render() {
- return (
-
-
- You can deploy a production version of your sandbox using one our
- supported providers.
-
-
-
-
- );
- }
-}
-
-export default inject('signals', 'store')(observer(Deployment));
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/index.ts
new file mode 100644
index 00000000000..74dc9ac5cad
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/index.ts
@@ -0,0 +1 @@
+export { Deployment } from './Deployment';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/CreateRepo/CreateRepo.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/CreateRepo/CreateRepo.tsx
new file mode 100644
index 00000000000..dc61470c959
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/CreateRepo/CreateRepo.tsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import { observer } from 'mobx-react-lite';
+import Margin from '@codesandbox/common/lib/components/spacing/Margin';
+import Input from '@codesandbox/common/lib/components/Input';
+import { Button } from '@codesandbox/common/lib/components/Button';
+import { useSignals, useStore } from 'app/store';
+import {
+ WorkspaceSubtitle,
+ WorkspaceInputContainer,
+} from 'app/pages/Sandbox/Editor/Workspace/elements';
+import { Error } from './elements';
+
+export const CreateRepo = observer(
+ ({ style }: { style: React.CSSProperties }) => {
+ const {
+ git: { repoTitleChanged, createRepoClicked },
+ } = useSignals();
+ const {
+ editor: { isAllModulesSynced },
+ git: { repoTitle, error },
+ } = useStore();
+
+ const updateRepoTitle = (e: React.ChangeEvent) =>
+ repoTitleChanged({ title: e.target.value });
+ const createRepo = () => createRepoClicked();
+
+ return (
+
+ {!isAllModulesSynced && (
+ Save your files first before exporting.
+ )}
+ {error && {error} }
+
+ Repository Name
+
+
+
+
+
+ Create Repository
+
+
+
+ );
+ }
+);
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/CreateRepo/elements.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/CreateRepo/elements.ts
new file mode 100644
index 00000000000..78f472db7d4
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/CreateRepo/elements.ts
@@ -0,0 +1,9 @@
+import styled, { css } from 'styled-components';
+
+export const Error = styled.div`
+ ${({ theme }) => css`
+ margin: 1rem;
+ color: ${theme.red};
+ font-size: 0.875rem;
+ `}
+`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/CreateRepo/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/CreateRepo/index.ts
new file mode 100644
index 00000000000..02f41f8b49d
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/CreateRepo/index.ts
@@ -0,0 +1 @@
+export { CreateRepo } from './CreateRepo';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Added.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Added.tsx
new file mode 100644
index 00000000000..878832e2aa1
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Added.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import AddedIcon from 'react-icons/lib/go/diff-added';
+import theme from '@codesandbox/common/lib/theme';
+import { Changes } from './Changes';
+
+export const Added = ({ changes, hideColor }) => (
+
+);
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Changes.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Changes.tsx
new file mode 100644
index 00000000000..6c1e889dcb5
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Changes.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import Tooltip from '@codesandbox/common/lib/components/Tooltip';
+import { ChangeContainer, Entry } from './elements';
+
+export const Changes = ({ changes, color, Icon, title, hideColor }) => (
+ <>
+ {changes.sort().map(change => (
+
+
+
+
+
+ {change}
+
+
+ ))}
+ >
+);
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Deleted.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Deleted.tsx
new file mode 100644
index 00000000000..ac6dca83487
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Deleted.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import RemovedIcon from 'react-icons/lib/go/diff-removed';
+import theme from '@codesandbox/common/lib/theme';
+import { Changes } from './Changes';
+
+export const Deleted = ({ changes, hideColor }) => (
+
+);
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Modified.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Modified.tsx
new file mode 100644
index 00000000000..6222dfc409c
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/Modified.tsx
@@ -0,0 +1,14 @@
+import React from 'react';
+import ModifiedIcon from 'react-icons/lib/go/diff-modified';
+import theme from '@codesandbox/common/lib/theme';
+import { Changes } from './Changes';
+
+export const Modified = ({ changes, hideColor }) => (
+
+);
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/elements.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/elements.ts
new file mode 100644
index 00000000000..9f88251bb49
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/elements.ts
@@ -0,0 +1,35 @@
+import styled, { css } from 'styled-components';
+import { EntryContainer } from '../../../../elements';
+
+export const ChangeContainer = styled.div`
+ &:last-child {
+ border-bottom: none;
+ }
+`;
+
+export const Entry = styled(EntryContainer)`
+ ${({
+ color,
+ hideColor,
+ theme,
+ }: {
+ color: string;
+ hideColor: boolean;
+ theme: any;
+ }) => css`
+ display: flex;
+ align-items: center;
+ line-height: 1;
+ color: ${theme.vscodeTheme.colors['editor.foreground']};
+ ${hideColor &&
+ css`
+ background-color: transparent;
+ padding-left: 0;
+ `};
+
+ svg {
+ color: ${color};
+ margin-right: 0.5rem;
+ }
+ `}
+`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/index.ts
new file mode 100644
index 00000000000..781a6ed49ff
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Changes/index.ts
@@ -0,0 +1,3 @@
+export { Added } from './Added';
+export { Deleted } from './Deleted';
+export { Modified } from './Modified';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Git.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Git.tsx
new file mode 100644
index 00000000000..3cc2875f9a2
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/Git.tsx
@@ -0,0 +1,145 @@
+import React, { useEffect } from 'react';
+import { observer } from 'mobx-react-lite';
+import Margin from '@codesandbox/common/lib/components/spacing/Margin';
+import GithubBadge from '@codesandbox/common/lib/components/GithubBadge';
+import { githubRepoUrl } from '@codesandbox/common/lib/utils/url-generator';
+import { Button } from '@codesandbox/common/lib/components/Button';
+import Notice from '@codesandbox/common/lib/components/Notice';
+import Input, { TextArea } from '@codesandbox/common/lib/components/Input';
+import { useSignals, useStore } from 'app/store';
+import { WorkspaceSubtitle, WorkspaceInputContainer } from '../../../elements';
+import { TotalChanges } from './TotalChanges';
+import { Container, Buttons, ErrorMessage, NoChanges } from './elements';
+
+function hasWriteAccess(rights: 'none' | 'read' | 'write' | 'admin') {
+ return rights === 'write' || rights === 'admin';
+}
+
+export const Git = observer(() => {
+ const {
+ git: {
+ gitMounted,
+ createCommitClicked,
+ createPrClicked,
+ subjectChanged,
+ descriptionChanged,
+ },
+ } = useSignals();
+ const {
+ git: { originalGitChanges: gitChanges, isFetching, subject, description },
+ editor: {
+ currentSandbox: { originalGit },
+ isAllModulesSynced,
+ },
+ } = useStore();
+
+ useEffect(() => {
+ gitMounted();
+ }, []); // eslint-disable-line
+
+ const createCommit = () => createCommitClicked();
+ const createPR = () => createPrClicked();
+ const changeSubject = (e: React.ChangeEvent) =>
+ subjectChanged({
+ subject: e.target.value,
+ });
+ const changeDescription = (e: React.ChangeEvent) =>
+ descriptionChanged({
+ description: e.target.value,
+ });
+
+ const modulesNotSaved = !isAllModulesSynced;
+ const changeCount = gitChanges
+ ? gitChanges.added.length +
+ gitChanges.modified.length +
+ gitChanges.deleted.length
+ : 0;
+
+ return (
+
+ beta
+ GitHub Repository
+
+
+
+
+
+ Changes ({gitChanges ? changeCount : '...'})
+
+ {!isFetching && gitChanges ? (
+
+
+
+ {changeCount > 0 ? (
+
+ Commit Info
+ {modulesNotSaved && (
+
+ You need to save all modules before you can commit
+
+ )}
+ 72 ? `#F27777` : `#556362`,
+ textAlign: 'right',
+ }}
+ >
+ {`${subject.length}/72`}
+
+
+
+
+
+
+
+
+ {hasWriteAccess(gitChanges.rights) && (
+
+ Commit
+
+ )}
+
+ Open PR
+
+
+
+ ) : (
+
+ There are no changes
+
+ )}
+
+ ) : (
+
+ Fetching changes...
+
+ )}
+
+
+ );
+});
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/TotalChanges/TotalChanges.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/TotalChanges/TotalChanges.tsx
new file mode 100644
index 00000000000..4c13deb5638
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/TotalChanges/TotalChanges.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+import { Added, Modified, Deleted } from '../Changes';
+
+export const TotalChanges = ({
+ gitChanges,
+ hideColor,
+}: {
+ gitChanges: any;
+ hideColor?: boolean;
+}) => (
+ <>
+
+
+
+ >
+);
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/TotalChanges/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/TotalChanges/index.ts
new file mode 100644
index 00000000000..86e49204854
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/TotalChanges/index.ts
@@ -0,0 +1 @@
+export { TotalChanges } from './TotalChanges';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/elements.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/elements.ts
new file mode 100644
index 00000000000..ab39dbb1e91
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/elements.ts
@@ -0,0 +1,31 @@
+import styled, { css } from 'styled-components';
+
+export const Container = styled.div`
+ ${({ theme }) => css`
+ color: ${theme.light
+ ? css`rgba(0, 0, 0, 0.8)`
+ : css`rgba(255, 255, 255, 0.8)`};
+ `}
+`;
+
+export const Buttons = styled.div`
+ display: flex;
+ margin: 1rem 0.125rem;
+
+ button {
+ margin: 0 0.875rem;
+ }
+`;
+
+export const ErrorMessage = styled.div`
+ ${({ theme }) => css`
+ color: ${theme.red};
+ margin: 1rem;
+ font-size: 0.875rem;
+ `}
+`;
+
+export const NoChanges = styled.em`
+ color: rgba(255, 255, 255, 0.6);
+ font-size: 0.875rem;
+`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/index.ts
new file mode 100644
index 00000000000..4fb4233f432
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/Git/index.ts
@@ -0,0 +1 @@
+export { Git } from './Git';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/GitHub.tsx
similarity index 55%
rename from packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/index.js
rename to packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/GitHub.tsx
index e0fc769819f..a1f9aa6e095 100644
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/index.js
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/GitHub.tsx
@@ -1,22 +1,26 @@
import React from 'react';
-import { inject, observer } from 'mobx-react';
-
-import GithubIntegration from '../../../../../common/GithubIntegration';
+import { observer } from 'mobx-react-lite';
+import GithubIntegration from 'app/pages/common/GithubIntegration';
+import { useStore } from 'app/store';
import WorkspaceItem from '../../WorkspaceItem';
-import Git from '../../Git';
-import CreateRepo from '../../CreateRepo';
import { Description } from '../../elements';
+import { Git } from './Git';
+import { CreateRepo } from './CreateRepo';
-const GitHub = ({ store }) => {
- const sandbox = store.editor.currentSandbox;
-
- const hasOriginalGitSource = sandbox.originalGit;
+export const GitHub = observer(() => {
+ const {
+ editor: {
+ currentSandbox: { originalGit },
+ },
+ user: {
+ integrations: { github },
+ },
+ } = useStore();
- return store.user.integrations.github ? ( // eslint-disable-line
- hasOriginalGitSource ? (
+ return github ? ( // eslint-disable-line
+ originalGit ? (
<>
-
@@ -28,7 +32,7 @@ const GitHub = ({ store }) => {
>
)
) : (
-
+ <>
You can create commits and open pull requests if you add GitHub to your
integrations.
@@ -37,8 +41,6 @@ const GitHub = ({ store }) => {
-
+ >
);
-};
-
-export default inject('signals', 'store')(observer(GitHub));
+});
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/index.ts
new file mode 100644
index 00000000000..e3e2db9dafe
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/GitHub/index.ts
@@ -0,0 +1 @@
+export { GitHub } from './GitHub';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/Countdown.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/Countdown.js
deleted file mode 100644
index 443c342be07..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/Countdown.js
+++ /dev/null
@@ -1,48 +0,0 @@
-import React from 'react';
-
-const pad = t => {
- if (`${t}`.length === 1) {
- return `0${t}`;
- }
-
- return `${t}`;
-};
-
-export default class Countdown extends React.PureComponent {
- componentDidMount() {
- this.timer = setTimeout(this.tick, 1000);
- }
-
- tick = () => {
- this.forceUpdate();
-
- this.timer = setTimeout(this.tick, 1000);
- };
-
- componentWillUnmount() {
- clearTimeout(this.timer);
- }
-
- getTimes = () => {
- const delta = Date.now() - this.props.time;
-
- const hours = Math.floor(delta / 1000 / 60 / 60);
- const minutes = Math.floor((delta - hours * 1000 * 60 * 60) / 1000 / 60);
- const seconds = Math.floor(
- (delta - hours * 1000 * 60 * 60 - minutes * 1000 * 60) / 1000
- );
-
- return { hours: pad(hours), minutes: pad(minutes), seconds: pad(seconds) };
- };
-
- render() {
- const { hours, minutes, seconds } = this.getTimes();
-
- return (
-
- {hours > 0 && `${hours}:`}
- {minutes}:{seconds}
-
- );
- }
-}
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/Live.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/Live.tsx
new file mode 100644
index 00000000000..394e36b3127
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/Live.tsx
@@ -0,0 +1,56 @@
+import React from 'react';
+import { observer } from 'mobx-react-lite';
+import { useSignals, useStore } from 'app/store';
+import { LiveInfo } from './LiveInfo';
+import { LiveButton } from './LiveButton';
+import {
+ Description,
+ WorkspaceInputContainer,
+ WorkspaceSubtitle,
+ ErrorDescription,
+} from '../../elements';
+
+export const Live = observer(() => {
+ const signals = useSignals();
+ const store = useStore();
+ const hasUnsyncedModules = !store.editor.isAllModulesSynced;
+
+ return (
+
+ {store.live.isLive ? (
+
+ ) : (
+ <>
+
+ Invite others to live edit this sandbox with you. We
+ {"'"}
+ re doing it live!
+
+ <>
+ Create live room
+
+ To invite others you need to generate a URL that others can join.
+
+
+ {hasUnsyncedModules && (
+
+ Save all your files before going live
+
+ )}
+
+ {
+ signals.live.createLiveClicked({
+ sandboxId: store.editor.currentId,
+ });
+ }}
+ isLoading={store.live.isLoading}
+ disable={hasUnsyncedModules}
+ />
+
+ >
+ >
+ )}
+
+ );
+});
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton.js
deleted file mode 100644
index e769c1a57ba..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton.js
+++ /dev/null
@@ -1,120 +0,0 @@
-import React from 'react';
-import styled, { css } from 'styled-components';
-
-import RecordIcon from 'react-icons/lib/md/fiber-manual-record';
-
-const styles = css`
- display: flex;
- align-items: center;
- justify-content: center;
-
- outline: none;
- border: none;
- padding: 0.5rem;
-
- background-color: #fd2439b8;
-
- width: 100%;
- color: white;
- border-radius: 4px;
- font-weight: 800;
-
- border: 2px solid #fd2439b8;
-`;
-
-const Button = styled.button`
- transition: 0.3s ease all;
- ${styles};
- cursor: pointer;
-
- svg {
- margin-right: 0.25rem;
- }
-
- ${props =>
- props.disable
- ? css`
- pointer-events: none;
- background-color: rgba(0, 0, 0, 0.3);
- border-color: rgba(0, 0, 0, 0.2);
- color: rgba(255, 255, 255, 0.7);
- `
- : css`
- &:hover {
- background-color: #fd2439fa;
- }
- `};
-`;
-
-const LoadingDiv = styled.div`
- ${styles};
-`;
-
-const AnimatedRecordIcon = styled(RecordIcon)`
- transition: 0.3s ease opacity;
-`;
-
-export default class LiveButton extends React.PureComponent {
- state = {
- hovering: false,
- showIcon: true,
- };
-
- timer: ?number;
-
- componentDidUpdate() {
- if (this.state.hovering && !this.timer) {
- this.timer = setInterval(() => {
- this.setState({ showIcon: !this.state.showIcon });
- }, 1000);
- } else if (!this.state.hovering && this.timer) {
- clearInterval(this.timer);
- this.timer = null;
-
- // eslint-disable-next-line
- this.setState({ showIcon: true });
- }
- }
-
- componentWillUnmount() {
- clearInterval(this.timer);
- }
-
- startHovering = () => {
- this.setState({ hovering: true });
- };
-
- stopHovering = () => {
- this.setState({ hovering: false });
- };
-
- render() {
- const {
- onClick,
- isLoading,
- disable,
- showIcon = true,
- message = 'Go Live',
- } = this.props;
-
- if (isLoading) {
- return Creating Session ;
- }
-
- return (
-
- {showIcon && (
-
- )}{' '}
- {message}
-
- );
- }
-}
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton/LiveButton.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton/LiveButton.tsx
new file mode 100644
index 00000000000..5c6d0ad4e2d
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton/LiveButton.tsx
@@ -0,0 +1,47 @@
+import React, { useState } from 'react';
+import { useInterval } from 'app/hooks';
+import { Button, LoadingDiv, AnimatedRecordIcon } from './elements';
+
+export const LiveButton = ({
+ onClick,
+ isLoading,
+ disable,
+ icon = true,
+ message = 'Go Live',
+}) => {
+ const [hovering, setHovering] = useState(false);
+ const [showIcon, setShowIcon] = useState(icon);
+
+ useInterval(
+ () => {
+ if (hovering) {
+ setShowIcon(!showIcon);
+ }
+ },
+ hovering ? 1000 : null
+ );
+
+ if (!hovering && !showIcon) {
+ setShowIcon(true);
+ }
+
+ const startHovering = () => setHovering(true);
+ const stopHovering = () => setHovering(false);
+
+ if (isLoading) {
+ return Creating Session ;
+ }
+
+ return (
+
+ {/*
+ // @ts-ignore */}
+ {icon && } {message}
+
+ );
+};
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton/elements.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton/elements.ts
new file mode 100644
index 00000000000..7c081bf29d6
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton/elements.ts
@@ -0,0 +1,57 @@
+import styled, { css } from 'styled-components';
+import RecordIcon from 'react-icons/lib/md/fiber-manual-record';
+
+const styles = css`
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ outline: none;
+ border: none;
+ padding: 0.5rem;
+ background-color: #fd2439b8;
+ width: 100%;
+ color: white;
+ border-radius: 4px;
+ font-weight: 800;
+ border: 2px solid #fd2439b8;
+`;
+
+interface Button extends HTMLButtonElement {
+ disable?: boolean;
+}
+
+export const Button = styled.button`
+ ${({ disable }) => css`
+ transition: 0.3s ease all;
+ ${styles};
+ cursor: pointer;
+
+ svg {
+ margin-right: 0.25rem;
+ }
+
+ ${disable
+ ? css`
+ pointer-events: none;
+ background-color: rgba(0, 0, 0, 0.3);
+ border-color: rgba(0, 0, 0, 0.2);
+ color: rgba(255, 255, 255, 0.7);
+ `
+ : css`
+ &:hover {
+ background-color: #fd2439fa;
+ }
+ `};
+ `}
+`;
+
+export const LoadingDiv = styled.div`
+ ${styles};
+`;
+
+export const AnimatedRecordIcon = styled(RecordIcon)`
+ ${({ opacity = 1 }) => css`
+ opacity: ${opacity};
+ transition: 0.3s ease opacity;
+ `}
+`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton/index.ts
new file mode 100644
index 00000000000..ff524c90831
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveButton/index.ts
@@ -0,0 +1 @@
+export { LiveButton } from './LiveButton';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo.js
deleted file mode 100644
index 12d2d7c0ba1..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo.js
+++ /dev/null
@@ -1,459 +0,0 @@
-import React from 'react';
-import styled from 'styled-components';
-import { inject, observer } from 'mobx-react';
-import { sortBy } from 'lodash-es';
-
-import RecordIcon from 'react-icons/lib/md/fiber-manual-record';
-import Input from '@codesandbox/common/lib/components/Input';
-import Margin from '@codesandbox/common/lib/components/spacing/Margin';
-import delay from '@codesandbox/common/lib/utils/animation/delay-effect';
-import Switch from '@codesandbox/common/lib/components/Switch';
-
-import Tooltip from '@codesandbox/common/lib/components/Tooltip';
-
-import AddIcon from 'react-icons/lib/md/add';
-import RemoveIcon from 'react-icons/lib/md/remove';
-import FollowIcon from 'react-icons/lib/io/eye';
-import UnFollowIcon from 'react-icons/lib/io/eye-disabled';
-
-import User from './User';
-import Countdown from './Countdown';
-import LiveButton from './LiveButton';
-
-import { Description, WorkspaceInputContainer } from '../../elements';
-
-const Container = styled.div`
- ${delay()};
- color: ${props =>
- props.theme.light ? 'rgba(0, 0, 0, 0.7)' : 'rgba(255, 255, 255, 0.7)'};
- box-sizing: border-box;
-`;
-
-const Title = styled.div`
- color: #fd2439fa;
- font-weight: 800;
- display: flex;
- align-items: center;
- vertical-align: middle;
-
- padding: 0.5rem 1rem;
- padding-top: 0;
-
- svg {
- margin-right: 0.25rem;
- }
-`;
-
-const StyledInput = styled(Input)`
- width: calc(100% - 1.5rem);
- margin: 0 0.75rem;
- font-size: 0.875rem;
-`;
-
-const SubTitle = styled.div`
- text-transform: uppercase;
- font-weight: 700;
- color: rgba(255, 255, 255, 0.5);
-
- padding-left: 1rem;
- font-size: 0.875rem;
-`;
-
-const Users = styled.div`
- padding: 0.25rem 1rem;
- padding-top: 0;
- color: ${props =>
- props.theme.light ? 'rgba(0, 0, 0, 0.8)' : 'rgba(255, 255, 255, 0.8)'};
-`;
-
-const ModeSelect = styled.div`
- position: relative;
- margin: 0.5rem 1rem;
-`;
-
-const Mode = styled.button`
- display: block;
- text-align: left;
- transition: 0.3s ease opacity;
- padding: 0.5rem 1rem;
- color: white;
- border-radius: 4px;
- width: 100%;
- font-size: 1rem;
-
- font-weight: 600;
- border: none;
- outline: none;
- background-color: transparent;
- cursor: ${props => (props.onClick ? 'pointer' : 'inherit')};
- color: white;
- opacity: ${props => (props.selected ? 1 : 0.6)};
- margin: 0.25rem 0;
-
- z-index: 3;
-
- ${props =>
- props.onClick &&
- `
- &:hover {
- opacity: 1;
- }`};
-`;
-
-const ModeDetails = styled.div`
- font-size: 0.75rem;
- color: ${props =>
- props.theme.light ? 'rgba(0, 0, 0, 0.7)' : 'rgba(255, 255, 255, 0.7)'};
- margin-top: 0.25rem;
-`;
-
-const ModeSelector = styled.div`
- transition: 0.3s ease transform;
- position: absolute;
- left: 0;
- right: 0;
- top: 0;
- height: 48px;
-
- border: 2px solid rgba(253, 36, 57, 0.6);
- background-color: rgba(253, 36, 57, 0.6);
- border-radius: 4px;
- z-index: -1;
-
- transform: translateY(${props => props.i * 55}px);
-`;
-
-const PreferencesContainer = styled.div`
- margin: 1rem;
- display: flex;
-`;
-
-const Preference = styled.div`
- flex: 1;
- font-weight: 400;
- color: ${props =>
- props.theme.light ? 'rgba(0, 0, 0, 0.8)' : 'rgba(255, 255, 255, 0.8)'};
- align-items: center;
- justify-content: center;
- font-size: 0.875rem;
-`;
-
-const IconContainer = styled.div`
- transition: 0.3s ease color;
- color: ${props =>
- props.theme.light ? 'rgba(0, 0, 0, 0.8)' : 'rgba(255, 255, 255, 0.8)'};
- cursor: pointer;
-
- &:hover {
- color: white;
- }
-`;
-
-class LiveInfo extends React.Component {
- select = e => {
- e.target.select();
- };
-
- render() {
- const {
- roomInfo,
- isOwner,
- isTeam,
- ownerIds,
- setMode,
- addEditor,
- removeEditor,
- currentUserId,
- reconnecting,
- onSessionCloseClicked,
- notificationsHidden,
- toggleNotificationsHidden,
- chatEnabled,
- toggleChatEnabled,
- setFollowing,
- followingUserId,
- } = this.props;
-
- const owners = roomInfo.users.filter(u => ownerIds.indexOf(u.id) > -1);
-
- const editors = sortBy(
- roomInfo.users.filter(
- u =>
- roomInfo.editorIds.indexOf(u.id) > -1 && ownerIds.indexOf(u.id) === -1
- ),
- 'username'
- );
- const otherUsers = sortBy(
- roomInfo.users.filter(
- u =>
- ownerIds.indexOf(u.id) === -1 &&
- roomInfo.editorIds.indexOf(u.id) === -1
- ),
- 'username'
- );
-
- const liveMessage = (() => {
- if (isTeam) {
- return 'Your team is live!';
- }
-
- if (isOwner) {
- return "You've gone live!";
- }
-
- return 'You are live!';
- })();
-
- return (
-
-
-
- {reconnecting ? (
- 'Reconnecting...'
- ) : (
-
- {liveMessage}
-
- )}
-
-
- {roomInfo.startTime != null && (
-
- )}
-
-
-
- Share this link with others to invite them to the session:
-
-
-
- {isOwner && !isTeam && (
-
-
-
- )}
-
-
- Preferences
-
- {isOwner && (
-
- Chat enabled
-
-
- )}
-
- Hide notifications
-
-
-
-
-
- Live Mode
-
-
- setMode({ mode: 'open' }) : undefined}
- selected={roomInfo.mode === 'open'}
- >
- Open
- Everyone can edit
-
- setMode({ mode: 'classroom' }) : undefined
- }
- selected={roomInfo.mode === 'classroom'}
- >
- Classroom
- Take control over who can edit
-
-
-
-
- {owners && (
-
- Owners
-
- {owners.map(owner => (
-
- {followingUserId === owner.id ? (
-
- setFollowing({ liveUserId: null })}
- />
-
- ) : (
-
-
- setFollowing({ liveUserId: owner.id })
- }
- />
-
- )}
-
- )
- }
- />
- ))}
-
-
- )}
-
- {editors.length > 0 && roomInfo.mode === 'classroom' && (
-
- Editors
-
- {editors.map(user => (
-
- {user.id !== currentUserId && (
-
- {followingUserId === user.id ? (
-
-
- setFollowing({ liveUserId: null })
- }
- />
-
- ) : (
-
-
- setFollowing({ liveUserId: user.id })
- }
- />
-
- )}
-
- )}
- {isOwner && roomInfo.mode === 'classroom' && (
-
-
-
- removeEditor({ liveUserId: user.id })
- }
- />
-
-
- )}
-
- }
- />
- ))}
-
-
- )}
-
-
- Users
-
-
- {otherUsers.length ? (
- otherUsers.map(user => (
-
- {roomInfo.mode !== 'classroom' &&
- user.id !== currentUserId && (
-
- {followingUserId === user.id ? (
-
-
- setFollowing({ liveUserId: null })
- }
- />
-
- ) : (
-
-
- setFollowing({ liveUserId: user.id })
- }
- />
-
- )}
-
- )}
- {isOwner && roomInfo.mode === 'classroom' && (
-
-
- addEditor({ liveUserId: user.id })}
- />
-
-
- )}
-
- }
- />
- ))
- ) : (
-
- No other users in session, invite them!
-
- )}
-
-
-
- );
- }
-}
-
-export default inject('store')(observer(LiveInfo));
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/LiveInfo.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/LiveInfo.tsx
new file mode 100644
index 00000000000..7e8d1414c87
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/LiveInfo.tsx
@@ -0,0 +1,323 @@
+import React from 'react';
+import { observer } from 'mobx-react-lite';
+import { sortBy } from 'lodash-es';
+import RecordIcon from 'react-icons/lib/md/fiber-manual-record';
+import AddIcon from 'react-icons/lib/md/add';
+import RemoveIcon from 'react-icons/lib/md/remove';
+import FollowIcon from 'react-icons/lib/io/eye';
+import UnFollowIcon from 'react-icons/lib/io/eye-disabled';
+import Margin from '@codesandbox/common/lib/components/spacing/Margin';
+import Switch from '@codesandbox/common/lib/components/Switch';
+import Tooltip from '@codesandbox/common/lib/components/Tooltip';
+import { useSignals, useStore } from 'app/store';
+import { Description, WorkspaceInputContainer } from '../../../elements';
+import { LiveButton } from '../LiveButton';
+import { SessionTimer } from './SessionTimer';
+import { User } from './User';
+import {
+ Container,
+ Title,
+ ConnectionStatus,
+ StyledInput,
+ SubTitle,
+ Users,
+ ModeSelect,
+ Mode,
+ ModeDetails,
+ ModeSelector,
+ PreferencesContainer,
+ Preference,
+ IconContainer,
+ NoUsers,
+} from './elements';
+
+export const LiveInfo = observer(() => {
+ const {
+ live: {
+ onModeChanged,
+ onAddEditorClicked,
+ onChatEnabledChange,
+ onRemoveEditorClicked,
+ onSessionCloseClicked,
+ onToggleNotificationsHidden,
+ onFollow,
+ },
+ } = useSignals();
+ const {
+ live: {
+ isOwner,
+ isTeam,
+ roomInfo: {
+ chatEnabled,
+ users,
+ ownerIds,
+ editorIds,
+ startTime,
+ roomId,
+ mode,
+ },
+ liveUserId,
+ reconnecting,
+ notificationsHidden,
+ followingUserId,
+ },
+ } = useStore();
+
+ const toggleChatEnabled = () => {
+ onChatEnabledChange({
+ enabled: !chatEnabled,
+ });
+ };
+
+ const owners = users.filter(u => ownerIds.indexOf(u.id) > -1);
+
+ const editors = sortBy(
+ users.filter(
+ u => editorIds.indexOf(u.id) > -1 && ownerIds.indexOf(u.id) === -1
+ ),
+ 'username'
+ );
+ const otherUsers = sortBy(
+ users.filter(
+ u => ownerIds.indexOf(u.id) === -1 && editorIds.indexOf(u.id) === -1
+ ),
+ 'username'
+ );
+
+ const liveMessage = (() => {
+ if (isTeam) {
+ return 'Your team is live!';
+ }
+
+ if (isOwner) {
+ return "You've gone live!";
+ }
+
+ return 'You are live!';
+ })();
+
+ return (
+
+
+
+ {reconnecting ? (
+ 'Reconnecting...'
+ ) : (
+ <>
+ {liveMessage}
+ >
+ )}
+
+ {startTime != null && }
+
+
+ Share this link with others to invite them to the session:
+
+ {
+ e.target.select();
+ }}
+ value={`https://codesandbox.io/live/${roomId}`}
+ />
+
+ {isOwner && !isTeam && (
+
+
+
+ )}
+
+
+ Preferences
+
+ {isOwner && (
+
+ Chat enabled
+
+
+ )}
+
+ Hide notifications
+
+
+
+
+
+ Live Mode
+
+
+ onModeChanged({ mode: 'open' }) : undefined
+ }
+ selected={mode === 'open'}
+ >
+ Open
+ Everyone can edit
+
+ onModeChanged({ mode: 'classroom' }) : undefined
+ }
+ selected={mode === 'classroom'}
+ >
+ Classroom
+ Take control over who can edit
+
+
+
+
+ {owners && (
+
+ Owners
+
+ {owners.map(owner => (
+
+ {followingUserId === owner.id ? (
+
+ onFollow({ liveUserId: null })}
+ />
+
+ ) : (
+
+ onFollow({ liveUserId: owner.id })}
+ />
+
+ )}
+
+ )
+ }
+ />
+ ))}
+
+
+ )}
+
+ {editors.length > 0 && mode === 'classroom' && (
+
+ Editors
+
+ {editors.map(user => (
+
+ {user.id !== liveUserId && (
+
+ {followingUserId === user.id ? (
+
+ onFollow({ liveUserId: null })}
+ />
+
+ ) : (
+
+ onFollow({ liveUserId: user.id })}
+ />
+
+ )}
+
+ )}
+ {isOwner && mode === 'classroom' && (
+
+
+
+ onRemoveEditorClicked({ liveUserId: user.id })
+ }
+ />
+
+
+ )}
+ >
+ }
+ />
+ ))}
+
+
+ )}
+
+
+ Users
+
+
+ {otherUsers.length ? (
+ otherUsers.map(user => (
+
+ {mode !== 'classroom' && user.id !== liveUserId && (
+
+ {followingUserId === user.id ? (
+
+ onFollow({ liveUserId: null })}
+ />
+
+ ) : (
+
+ onFollow({ liveUserId: user.id })}
+ />
+
+ )}
+
+ )}
+ {isOwner && mode === 'classroom' && (
+
+
+
+ onAddEditorClicked({ liveUserId: user.id })
+ }
+ />
+
+
+ )}
+ >
+ }
+ />
+ ))
+ ) : (
+ No other users in session, invite them!
+ )}
+
+
+
+ );
+});
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/SessionTimer.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/SessionTimer.tsx
new file mode 100644
index 00000000000..cdc780d7bf8
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/SessionTimer.tsx
@@ -0,0 +1,28 @@
+import React, { useState } from 'react';
+import { useInterval } from 'app/hooks';
+
+export const SessionTimer = ({ startTime }) => {
+ const [elapsed, setElapsed] = useState(`00:00`);
+
+ const pad = (val: number) => (`${val}`.length === 1 ? `0${val}` : `${val}`);
+
+ const getTimes = () => {
+ const delta = Date.now() - startTime;
+
+ const hours = Math.floor(delta / 1000 / 60 / 60);
+ const minutes = Math.floor((delta - hours * 1000 * 60 * 60) / 1000 / 60);
+ const seconds = Math.floor(
+ (delta - hours * 1000 * 60 * 60 - minutes * 1000 * 60) / 1000
+ );
+
+ return { hours: pad(hours), minutes: pad(minutes), seconds: pad(seconds) };
+ };
+
+ const { hours, minutes, seconds } = getTimes();
+
+ useInterval(() => {
+ setElapsed(`${Number(hours) > 0 ? `${hours}:` : ``}${minutes}:${seconds}`);
+ }, 1000);
+
+ return <>{elapsed}>;
+};
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/User/User.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/User/User.tsx
new file mode 100644
index 00000000000..2013535dc9b
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/User/User.tsx
@@ -0,0 +1,29 @@
+import React from 'react';
+import { UserContainer, ProfileImage, UserName, Status } from './elements';
+
+export const User = ({ user, type, sideView, users, currentUserId }) => {
+ const metaData = users.find(u => u.id === user.id);
+ const [r, g, b] = metaData ? metaData.color : [0, 0, 0];
+
+ const isCurrentUser = user.id === currentUserId;
+
+ return (
+
+
+
+ {user.username}
+ {type && (
+
+ {type}
+ {isCurrentUser && ' (you)'}
+
+ )}
+
+ {sideView}
+
+ );
+};
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/User/elements.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/User/elements.ts
new file mode 100644
index 00000000000..ae944734d5a
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/User/elements.ts
@@ -0,0 +1,43 @@
+import styled, { css } from 'styled-components';
+import delay from '@codesandbox/common/lib/utils/animation/delay-effect';
+
+export const Status = styled.div`
+ font-size: 0.75rem;
+ color: rgba(255, 255, 255, 0.6);
+`;
+
+export const UserContainer = styled.div`
+ ${({ isCurrentUser, theme }: { isCurrentUser: boolean; theme: any }) => css`
+ ${delay()};
+ display: flex;
+ align-items: center;
+ margin: 0.5rem 0;
+ color: ${theme.light
+ ? css`rgba(0, 0, 0, 0.8)`
+ : css`rgba(255, 255, 255, 0.8)`};
+ ${isCurrentUser &&
+ css`
+ color: white;
+ `};
+
+ &:first-child {
+ margin-top: 0;
+ }
+ `}
+`;
+
+export const ProfileImage = styled.img`
+ ${({ borderColor }: { borderColor: string }) => css`
+ width: 26px;
+ height: 26px;
+ border-radius: 2px;
+ border-left: 2px solid ${borderColor};
+
+ margin-right: 0.5rem;
+ `}
+`;
+
+export const UserName = styled.div`
+ font-weight: 600;
+ font-size: 0.875rem;
+`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/User/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/User/index.ts
new file mode 100644
index 00000000000..403fc945c19
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/User/index.ts
@@ -0,0 +1 @@
+export { User } from './User';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/elements.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/elements.ts
new file mode 100644
index 00000000000..1d788913f46
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/elements.ts
@@ -0,0 +1,166 @@
+import styled, { css } from 'styled-components';
+import Input from '@codesandbox/common/lib/components/Input';
+import delay from '@codesandbox/common/lib/utils/animation/delay-effect';
+
+interface Theme {
+ theme: {
+ light: boolean;
+ };
+}
+
+export const Container = styled.div`
+ ${({ theme }: Theme) => css`
+ ${delay()};
+ color: ${theme.light
+ ? css`rgba(0, 0, 0, 0.7)`
+ : css`rgba(255, 255, 255, 0.7)`};
+ box-sizing: border-box;
+ `}
+`;
+
+export const Title = styled.div`
+ color: #fd2439fa;
+ font-weight: 800;
+ display: flex;
+ align-items: center;
+ vertical-align: middle;
+ padding: 0.5rem 1rem;
+ padding-top: 0;
+
+ svg {
+ margin-right: 0.25rem;
+ }
+`;
+
+export const ConnectionStatus = styled.div`
+ display: flex;
+ flex: 1;
+ align-items: center;
+ font-size: 1rem;
+`;
+
+export const StyledInput = styled(Input)`
+ width: calc(100% - 1.5rem);
+ margin: 0 0.75rem;
+ font-size: 0.875rem;
+`;
+
+export const SubTitle = styled.div`
+ text-transform: uppercase;
+ font-weight: 700;
+ color: rgba(255, 255, 255, 0.5);
+ padding-left: 1rem;
+ font-size: 0.875rem;
+`;
+
+export const Users = styled.div`
+ ${({ theme }: Theme) => css`
+ padding: 0.25rem 1rem;
+ padding-top: 0;
+ color: ${theme.light
+ ? css`rgba(0, 0, 0, 0.8)`
+ : css`rgba(255, 255, 255, 0.8)`};
+ `}
+`;
+
+export const ModeSelect = styled.div`
+ position: relative;
+ margin: 0.5rem 1rem;
+`;
+
+export const Mode = styled.button`
+ ${({ onClick, selected }: { onClick: any; selected: boolean }) => css`
+ display: block;
+ text-align: left;
+ transition: 0.3s ease opacity;
+ padding: 0.5rem 1rem;
+ color: white;
+ border-radius: 4px;
+ width: 100%;
+ font-size: 1rem;
+
+ font-weight: 600;
+ border: none;
+ outline: none;
+ background-color: transparent;
+ cursor: ${onClick ? 'pointer' : 'inherit'};
+ color: white;
+ opacity: ${selected ? 1 : 0.6};
+ margin: 0.25rem 0;
+
+ z-index: 3;
+
+ ${onClick &&
+ `
+ &:hover {
+ opacity: 1;
+ }`};
+ `}
+`;
+
+export const ModeDetails = styled.div`
+ ${({ theme }: Theme) => css`
+ font-size: 0.75rem;
+ color: ${theme.light
+ ? css`rgba(0, 0, 0, 0.7)`
+ : css`rgba(255, 255, 255, 0.7)`};
+ margin-top: 0.25rem;
+ `}
+`;
+
+export const ModeSelector = styled.div`
+ ${({ i }: { i: number }) => css`
+ transition: 0.3s ease transform;
+ position: absolute;
+ left: 0;
+ right: 0;
+ top: 0;
+ height: 48px;
+
+ border: 2px solid rgba(253, 36, 57, 0.6);
+ background-color: rgba(253, 36, 57, 0.6);
+ border-radius: 4px;
+ z-index: -1;
+
+ transform: translateY(${i * 55}px);
+ `}
+`;
+
+export const PreferencesContainer = styled.div`
+ margin: 1rem;
+ display: flex;
+`;
+
+export const Preference = styled.div`
+ ${({ theme }: Theme) => css`
+ flex: 1;
+ font-weight: 400;
+ color: ${theme.light
+ ? css`rgba(0, 0, 0, 0.8)`
+ : css`rgba(255, 255, 255, 0.8)`};
+ align-items: center;
+ justify-content: center;
+ font-size: 0.875rem;
+ `}
+`;
+
+export const IconContainer = styled.div`
+ ${({ theme }: Theme) => css`
+ transition: 0.3s ease color;
+ color: ${theme.light
+ ? css`rgba(0, 0, 0, 0.8)`
+ : css`rgba(255, 255, 255, 0.8)`};
+ cursor: pointer;
+
+ &:hover {
+ color: white;
+ }
+ `}
+`;
+
+export const NoUsers = styled.div`
+ margin-top: 0.25rem;
+ color: rgba(255, 255, 255, 0.8);
+ font-size: 0.875rem;
+ font-weight: 600;
+`;
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/index.ts
new file mode 100644
index 00000000000..4903353342c
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/LiveInfo/index.ts
@@ -0,0 +1 @@
+export { LiveInfo } from './LiveInfo';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/User.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/User.js
deleted file mode 100644
index 2e20de7eedb..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/User.js
+++ /dev/null
@@ -1,76 +0,0 @@
-import React from 'react';
-import styled from 'styled-components';
-import { observer } from 'mobx-react';
-
-import delay from '@codesandbox/common/lib/utils/animation/delay-effect';
-
-const Status = styled.div`
- font-size: 0.75rem;
- color: rgba(255, 255, 255, 0.6);
-`;
-
-const UserContainer = styled.div`
- ${delay()};
- display: flex;
- align-items: center;
- margin: 0.5rem 0;
- color: ${props =>
- props.theme.light ? 'rgba(0, 0, 0, 0.8)' : 'rgba(255, 255, 255, 0.8)'};
- ${props =>
- props.isCurrentUser &&
- `
- color: white;
- `};
-
- &:first-child {
- margin-top: 0;
- }
-`;
-
-const ProfileImage = styled.img`
- width: 26px;
- height: 26px;
- border-radius: 2px;
- border-left: 2px solid ${({ borderColor }) => borderColor};
-
- margin-right: 0.5rem;
-`;
-
-const UserName = styled.div`
- font-weight: 600;
- font-size: 0.875rem;
-`;
-
-// eslint-disable-next-line
-class User extends React.Component {
- render() {
- const { user, type, sideView, roomInfo, currentUserId } = this.props;
-
- const metaData = roomInfo.users.find(u => u.id === user.id);
- const [r, g, b] = metaData ? metaData.color : [0, 0, 0];
-
- const isCurrentUser = user.id === currentUserId;
-
- return (
-
-
-
- {user.username}
- {type && (
-
- {type}
- {isCurrentUser && ' (you)'}
-
- )}
-
- {sideView}
-
- );
- }
-}
-
-export default observer(User);
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/index.js
deleted file mode 100644
index b2d69c82543..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/index.js
+++ /dev/null
@@ -1,79 +0,0 @@
-import React from 'react';
-import { inject, observer } from 'mobx-react';
-
-import LiveInfo from './LiveInfo';
-import LiveButton from './LiveButton';
-
-import {
- Description,
- WorkspaceInputContainer,
- WorkspaceSubtitle,
- ErrorDescription,
-} from '../../elements';
-
-const Live = ({ signals, store }) => {
- const hasUnsyncedModules = !store.editor.isAllModulesSynced;
-
- return (
-
- {store.live.isLive ? (
- {
- signals.live.onChatEnabledChange({
- enabled: !store.live.roomInfo.chatEnabled,
- });
- }}
- setFollowing={signals.live.onFollow}
- followingUserId={store.live.followingUserId}
- />
- ) : (
-
-
- Invite others to live edit this sandbox with you. We
- {"'"}
- re doing it live!
-
-
-
- Create live room
-
- To invite others you need to generate a URL that others can join.
-
-
- {hasUnsyncedModules && (
-
- Save all your files before going live
-
- )}
-
- {
- signals.live.createLiveClicked({
- sandboxId: store.editor.currentId,
- });
- }}
- isLoading={store.live.isLoading}
- disable={hasUnsyncedModules}
- />
-
-
-
- )}
-
- );
-};
-
-export default inject('signals', 'store')(observer(Live));
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/index.ts
new file mode 100644
index 00000000000..c5cc09c5182
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Live/index.ts
@@ -0,0 +1 @@
+export { Live } from './Live';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/More/More.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/More/More.tsx
new file mode 100644
index 00000000000..f872fccf066
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/More/More.tsx
@@ -0,0 +1,47 @@
+import React, { useEffect } from 'react';
+import { observer } from 'mobx-react-lite';
+import ProgressButton from '@codesandbox/common/lib/components/ProgressButton';
+import Margin from '@codesandbox/common/lib/components/spacing/Margin';
+import track from '@codesandbox/common/lib/utils/analytics';
+import SignInButton from 'app/pages/common/SignInButton';
+import { useSignals, useStore } from 'app/store';
+import { Description } from '../../elements';
+
+const NOT_OWNED_MESSAGE = `Fork this sandbox to make deployments, commit to GitHub, create live sessions with others and more!`;
+const NOT_SIGNED_IN_MESSAGE = `Sign in to be able to organize your sandboxes with a dashboard, make deployments, collaborate live with others, make commits to GitHub and more!`;
+
+export const More = observer(() => {
+ const {
+ editor: { forkSandboxClicked },
+ } = useSignals();
+ const {
+ editor: {
+ isForkingSandbox,
+ currentSandbox: { owned },
+ },
+ } = useStore();
+
+ useEffect(() => track('Workspace - More Opened'), []);
+
+ const message = !owned ? NOT_OWNED_MESSAGE : NOT_SIGNED_IN_MESSAGE;
+
+ return (
+
+
{message}
+
+ {!owned ? (
+ forkSandboxClicked()}
+ >
+ {isForkingSandbox ? 'Forking Sandbox...' : 'Fork Sandbox'}
+
+ ) : (
+
+ )}
+
+
+ );
+});
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/More/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/More/index.ts
new file mode 100644
index 00000000000..785e8957ccd
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/More/index.ts
@@ -0,0 +1 @@
+export { More } from './More';
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/More/index.tsx b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/More/index.tsx
deleted file mode 100644
index 9bf6373979b..00000000000
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/More/index.tsx
+++ /dev/null
@@ -1,55 +0,0 @@
-import React from 'react';
-import { inject, observer } from 'mobx-react';
-
-import ProgressButton from '@codesandbox/common/lib/components/ProgressButton';
-import SignInButton from 'app/pages/common/SignInButton';
-import Margin from '@codesandbox/common/lib/components/spacing/Margin';
-import track from '@codesandbox/common/lib/utils/analytics';
-
-import { Description } from '../../elements';
-
-type Props = {
- store: any;
- signals: any;
-};
-
-const NOT_OWNED_MESSAGE = `Fork this sandbox to make deployments, commit to GitHub, create live sessions with others and more!`;
-const NOT_SIGNED_IN_MESSAGE = `Sign in to be able to organize your sandboxes with a dashboard, make deployments, collaborate live with others, make commits to GitHub and more!`;
-
-class More extends React.Component {
- componentDidMount() {
- track('Workspace - More Opened');
- }
-
- forkSandbox = () => {
- this.props.signals.editor.forkSandboxClicked();
- };
-
- render() {
- const { owned } = this.props.store.editor.currentSandbox;
- const { isForkingSandbox } = this.props.store.editor;
- const message = !owned ? NOT_OWNED_MESSAGE : NOT_SIGNED_IN_MESSAGE;
-
- return (
-
-
{message}
-
- {!owned ? (
-
- {isForkingSandbox ? 'Forking Sandbox...' : 'Fork Sandbox'}
-
- ) : (
-
- )}
-
-
- );
- }
-}
-
-export default inject('store', 'signals')(observer(More));
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/NotOwnedSandboxInfo/index.js b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/NotOwnedSandboxInfo/NotOwnedSandboxInfo.tsx
similarity index 94%
rename from packages/app/src/app/pages/Sandbox/Editor/Workspace/items/NotOwnedSandboxInfo/index.js
rename to packages/app/src/app/pages/Sandbox/Editor/Workspace/items/NotOwnedSandboxInfo/NotOwnedSandboxInfo.tsx
index 0630991fe68..992a3f6c135 100644
--- a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/NotOwnedSandboxInfo/index.js
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/NotOwnedSandboxInfo/NotOwnedSandboxInfo.tsx
@@ -1,11 +1,10 @@
import React, { useState } from 'react';
-
import Project from '../../Project';
import Files from '../../Files';
import Dependencies from '../../Dependencies';
import WorkspaceItem from '../../WorkspaceItem';
-export default () => {
+export const NotOwnedSandboxInfo = () => {
const [editActions, setEditActions] = useState(null);
return (
diff --git a/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/NotOwnedSandboxInfo/index.ts b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/NotOwnedSandboxInfo/index.ts
new file mode 100644
index 00000000000..00a8c69652d
--- /dev/null
+++ b/packages/app/src/app/pages/Sandbox/Editor/Workspace/items/NotOwnedSandboxInfo/index.ts
@@ -0,0 +1 @@
+export { NotOwnedSandboxInfo } from './NotOwnedSandboxInfo';
diff --git a/packages/app/src/app/store/index.js b/packages/app/src/app/store/index.js
index 81c79b802af..702474e235d 100644
--- a/packages/app/src/app/store/index.js
+++ b/packages/app/src/app/store/index.js
@@ -1,3 +1,4 @@
+import { createContext, useContext } from 'react';
import { Module } from 'cerebral';
import HttpProvider from '@cerebral/http';
@@ -39,6 +40,12 @@ import live from './modules/live';
import dashboard from './modules/dashboard';
import userNotifications from './modules/user-notifications';
+export const Signals = createContext();
+export const Store = createContext();
+
+export const useSignals = () => useContext(Signals);
+export const useStore = () => useContext(Store);
+
export default Module({
model,
state: {
diff --git a/packages/app/src/sandbox/eval/loaders/eval.js b/packages/app/src/sandbox/eval/loaders/eval.js
index f4f6ad68c5a..f0f03e1651d 100644
--- a/packages/app/src/sandbox/eval/loaders/eval.js
+++ b/packages/app/src/sandbox/eval/loaders/eval.js
@@ -15,6 +15,8 @@ const requestFrame = (() => {
};
})();
+const hasGlobalDeclaration = /^const global/m;
+
/* eslint-disable no-unused-vars */
export default function(
code: string,
@@ -32,14 +34,24 @@ export default function(
const allGlobals = {
require,
- module: asUMD ? undefined : module,
- exports: asUMD ? undefined : exports,
+ module,
+ exports,
process,
setImmediate: requestFrame,
- global: asUMD ? undefined : global,
+ global,
...globals,
};
+ if (asUMD) {
+ delete allGlobals.module;
+ delete allGlobals.exports;
+ delete allGlobals.global;
+ }
+
+ if (hasGlobalDeclaration.test(code)) {
+ delete allGlobals.global;
+ }
+
const allGlobalKeys = Object.keys(allGlobals);
const globalsCode = allGlobalKeys.length ? allGlobalKeys.join(', ') : '';
const globalsValues = allGlobalKeys.map(k => allGlobals[k]);
diff --git a/packages/common/src/utils/analytics.ts b/packages/common/src/utils/analytics.ts
index aee08c2fc1c..a967a702973 100644
--- a/packages/common/src/utils/analytics.ts
+++ b/packages/common/src/utils/analytics.ts
@@ -124,6 +124,9 @@ const isAllowedEvent = (eventName, secondArg) => {
if (secondArg.id.startsWith('cursor')) {
return false;
}
+ if (secondArg.id === 'deleteLeft') {
+ return false;
+ }
}
return true;
} catch (e) {
diff --git a/packages/homepage/src/components/Cube.js b/packages/homepage/src/components/Cube.js
index 6ee45cff0f9..2dda34d919e 100644
--- a/packages/homepage/src/components/Cube.js
+++ b/packages/homepage/src/components/Cube.js
@@ -45,73 +45,74 @@ const Side = styled.div`
transform: ${({ rotate }) => rotate} translateZ(${({ size }) => size / 2}px);
`;
+const isSafari =
+ typeof navigator !== 'undefined' &&
+ /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
+const SHADOW_SIZE = isSafari ? 100 : 150;
+
type Props = {
- size: number,
className: string,
- noAnimation: ?boolean,
- speed: number,
color: string,
+ noAnimation: ?boolean,
offset: number,
+ size: number,
+ speed: number,
};
+const GlowCube = ({
+ className,
+ color = 'rgba(242,119,119,0.5)',
+ id,
+ noAnimation,
+ offset = 0,
+ ref,
+ size = 150,
+ speed = 1,
+}: Props) => (
+
+
+
-const isSafari =
- typeof navigator !== 'undefined' &&
- /^((?!chrome|android).)*safari/i.test(navigator.userAgent);
-const SHADOW_SIZE = isSafari ? 100 : 150;
+
-export default class GlowCube extends React.PureComponent {
- render() {
- const {
- size = 150,
- color = 'rgba(242,119,119,0.5)',
- speed = 1,
- offset = 0,
- noAnimation,
- className,
- ref,
- id,
- } = this.props;
- return (
-
-
-
-
-
-
-
-
-
-
- );
- }
-}
+
+
+
+
+
+
+
+
+
+);
+
+export default GlowCube;
diff --git a/yarn.lock b/yarn.lock
index 23347ca6299..c6c47b1db3f 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -16740,6 +16740,11 @@ mkdirp@0.5.1, mkdirp@0.5.x, mkdirp@0.x.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdir
dependencies:
minimist "0.0.8"
+mobx-react-lite@^1.3.2:
+ version "1.3.2"
+ resolved "https://registry.yarnpkg.com/mobx-react-lite/-/mobx-react-lite-1.3.2.tgz#4366048b5d283d12a82053367638b5d79281951f"
+ integrity sha512-D8VZEsxSxMNYDJmw2SgUXVAgpOlVYmp3hBCusoe+LuBDYUqyn2K3RPrMEF0rIzYJAvqpyv7YRrH8I3eBsPPx1A==
+
mobx-react@^5.2.3:
version "5.4.3"
resolved "https://registry.yarnpkg.com/mobx-react/-/mobx-react-5.4.3.tgz#6709b7dd89670c40e9815914ac2ca49cc02bfb47"