Skip to content

Commit 74004ee

Browse files
authored
Show placeholder icons if not signed in or not owned sandbox (codesandbox#2164)
* Show placeholder icons if not signed in or not owned sandbox * Fix error message for deployments when not signed in * Move signals to own component * Remove store prop
1 parent be16eef commit 74004ee

File tree

12 files changed

+262
-122
lines changed

12 files changed

+262
-122
lines changed

packages/app/src/app/overmind/namespaces/workspace/internalActions.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { Action } from 'app/overmind';
2-
import getItems from './items';
32
import { Sandbox } from '@codesandbox/common/lib/types';
3+
import getItems from './items';
44

55
export const setWorkspace: Action<Sandbox> = ({ state }, sandbox) => {
66
state.workspace.project.title = sandbox.title || '';

packages/app/src/app/overmind/namespaces/workspace/items.ts

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,66 @@
11
import getTemplate from '@codesandbox/common/lib/templates';
22

3-
const PROJECT = {
3+
interface INavigationItem {
4+
id: string;
5+
name: string;
6+
hasCustomHeader?: boolean;
7+
defaultOpen?: boolean;
8+
}
9+
10+
const PROJECT: INavigationItem = {
411
id: 'project',
5-
name: 'Project Info',
12+
name: 'Sandbox Info',
13+
};
14+
15+
const PROJECT_TEMPLATE: INavigationItem = {
16+
...PROJECT,
17+
name: 'Template Info',
618
};
719

8-
const PROJECT_SUMMARY = {
20+
const PROJECT_SUMMARY: INavigationItem = {
921
id: 'project-summary',
1022
name: 'Sandbox Info',
1123
hasCustomHeader: true,
1224
};
1325

14-
const FILES = {
26+
const FILES: INavigationItem = {
1527
id: 'files',
1628
name: 'Explorer',
1729
hasCustomHeader: true,
1830
defaultOpen: true,
1931
};
2032

21-
const GITHUB = {
33+
const GITHUB: INavigationItem = {
2234
id: 'github',
2335
name: 'GitHub',
2436
};
2537

26-
const DEPLOYMENT = {
38+
const DEPLOYMENT: INavigationItem = {
2739
id: 'deploy',
2840
name: 'Deployment',
2941
};
3042

31-
const CONFIGURATION = {
43+
const CONFIGURATION: INavigationItem = {
3244
id: 'config',
3345
name: 'Configuration Files',
3446
};
3547

36-
const LIVE = {
48+
const LIVE: INavigationItem = {
3749
id: 'live',
3850
name: 'Live',
3951
};
4052

41-
const MORE = {
53+
const MORE: INavigationItem = {
4254
id: 'more',
4355
name: 'More',
4456
};
4557

46-
const SERVER = {
58+
const SERVER: INavigationItem = {
4759
id: 'server',
4860
name: 'Server Control Panel',
4961
};
5062

51-
export default function getItems(store) {
63+
export default function getItems(store): INavigationItem[] {
5264
if (
5365
store.live.isLive &&
5466
!(
@@ -66,7 +78,8 @@ export default function getItems(store) {
6678
return [PROJECT_SUMMARY, CONFIGURATION, MORE];
6779
}
6880

69-
const items = [PROJECT, FILES];
81+
const isCustomTemplate = !!store.editor.currentSandbox.customTemplate;
82+
const items = [isCustomTemplate ? PROJECT_TEMPLATE : PROJECT, FILES];
7083

7184
if (store.isLoggedIn && store.editor.currentSandbox) {
7285
const templateDef = getTemplate(store.editor.currentSandbox.template);

packages/app/src/app/pages/Sandbox/Editor/Navigation/Navigation.tsx

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,12 @@ import FilesIcon from '-!svg-react-loader!@codesandbox/common/lib/icons/file.svg
1414
import RocketIcon from '-!svg-react-loader!@codesandbox/common/lib/icons/rocket.svg';
1515
// @ts-ignore
1616
import ConfigurationIcon from '-!svg-react-loader!@codesandbox/common/lib/icons/cog.svg';
17-
import getWorkspaceItems from 'app/store/modules/workspace/items';
17+
import getWorkspaceItems, {
18+
getDisabledItems,
19+
INavigationItem,
20+
} from 'app/store/modules/workspace/items';
1821
import { useSignals, useStore } from 'app/store';
19-
import { Container, IconContainer } from './elements';
22+
import { Container, IconContainer, Separator } from './elements';
2023
import ServerIcon from './ServerIcon';
2124

2225
const IDS_TO_ICONS = {
@@ -31,6 +34,42 @@ const IDS_TO_ICONS = {
3134
server: ServerIcon,
3235
};
3336

37+
interface IconProps {
38+
item: INavigationItem;
39+
isDisabled?: boolean;
40+
}
41+
42+
const IconComponent = observer(({ item, isDisabled }: IconProps) => {
43+
const { id, name } = item;
44+
const store = useStore();
45+
const {
46+
workspace: { setWorkspaceHidden, setWorkspaceItem },
47+
} = useSignals();
48+
49+
const Icon = IDS_TO_ICONS[id];
50+
const selected =
51+
!store.workspace.workspaceHidden &&
52+
id === store.workspace.openedWorkspaceItem;
53+
return (
54+
<Tooltip key={id} placement="right" content={name}>
55+
<IconContainer
56+
isDisabled={isDisabled}
57+
selected={selected}
58+
onClick={() => {
59+
if (selected) {
60+
setWorkspaceHidden({ hidden: true });
61+
} else {
62+
setWorkspaceHidden({ hidden: false });
63+
setWorkspaceItem({ item: id });
64+
}
65+
}}
66+
>
67+
<Icon />
68+
</IconContainer>
69+
</Tooltip>
70+
);
71+
});
72+
3473
export const Navigation = observer(
3574
({
3675
topOffset,
@@ -39,39 +78,22 @@ export const Navigation = observer(
3978
topOffset: number;
4079
bottomOffset: number;
4180
}) => {
42-
const {
43-
workspace: { setWorkspaceHidden, setWorkspaceItem },
44-
} = useSignals();
4581
const store = useStore();
4682

83+
const shownItems = getWorkspaceItems(store);
84+
const disabledItems = getDisabledItems(store);
85+
4786
return (
4887
<Container topOffset={topOffset} bottomOffset={bottomOffset}>
49-
{getWorkspaceItems(store)
50-
.filter(w => !w.show || w.show(store))
51-
.map(item => {
52-
const { id, name } = item;
53-
const Icon = IDS_TO_ICONS[id];
54-
const selected =
55-
!store.workspace.workspaceHidden &&
56-
id === store.workspace.openedWorkspaceItem;
57-
return (
58-
<Tooltip key={id} placement="right" content={name}>
59-
<IconContainer
60-
selected={selected}
61-
onClick={() => {
62-
if (selected) {
63-
setWorkspaceHidden({ hidden: true });
64-
} else {
65-
setWorkspaceHidden({ hidden: false });
66-
setWorkspaceItem({ item: id });
67-
}
68-
}}
69-
>
70-
<Icon />
71-
</IconContainer>
72-
</Tooltip>
73-
);
74-
})}
88+
{shownItems.map(item => (
89+
<IconComponent key={item.id} item={item} />
90+
))}
91+
92+
<Separator />
93+
94+
{disabledItems.map(item => (
95+
<IconComponent key={item.id} item={item} isDisabled />
96+
))}
7597
</Container>
7698
);
7799
}

packages/app/src/app/pages/Sandbox/Editor/Navigation/elements.ts

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -27,26 +27,48 @@ export const Container = styled.div`
2727
`}
2828
`;
2929

30-
export const IconContainer = styled.div`
31-
${({ selected, theme }: { selected: boolean; theme: any }) => css`
32-
display: flex;
33-
justify-content: center;
34-
align-items: center;
35-
transition: 0.3s ease all;
36-
height: 3.5rem;
37-
width: 3.5rem;
38-
font-size: 1.875rem;
39-
color: ${theme[`activityBar.inactiveForeground`] ||
40-
css`rgba(255, 255, 255, 0.5)`};
41-
cursor: pointer;
30+
export const IconContainer = styled.div<{
31+
selected: boolean;
32+
isDisabled: boolean;
33+
}>`
34+
display: flex;
35+
justify-content: center;
36+
align-items: center;
37+
transition: 0.3s ease all;
38+
height: 3.5rem;
39+
width: 3.5rem;
40+
font-size: 1.875rem;
41+
color: ${props =>
42+
props.theme[`activityBar.inactiveForeground`] ||
43+
css`rgba(255, 255, 255, 0.5)`};
44+
cursor: pointer;
4245
43-
&:hover {
44-
color: ${theme[`activityBar.foreground`] || css`white`};
45-
}
46+
&:hover {
47+
color: ${props => props.theme[`activityBar.foreground`] || css`white`};
48+
}
4649
47-
${selected &&
48-
css`
49-
color: ${theme[`activityBar.foreground`] || css`white`};
50-
`};
51-
`}
50+
${props =>
51+
props.selected &&
52+
css`
53+
color: ${props.theme[`activityBar.foreground`] || css`white`};
54+
`};
55+
56+
${props =>
57+
props.isDisabled &&
58+
!props.selected &&
59+
css`
60+
opacity: 0.4;
61+
`}
62+
`;
63+
64+
export const Separator = styled.hr`
65+
width: calc(100% - 20px);
66+
height: 1px;
67+
background-color: ${props =>
68+
props.theme.light ? 'rgba(0, 0, 0, 0.2)' : 'rgba(255,255,255,0.1)'};
69+
70+
margin: 0.25rem 0;
71+
72+
outline: none;
73+
border: none;
5274
`;

packages/app/src/app/pages/Sandbox/Editor/Workspace/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ import { observer } from 'mobx-react-lite';
33
import React from 'react';
44
import SocialInfo from 'app/components/SocialInfo';
55
import { useStore } from 'app/store';
6-
import getWorkspaceItems from 'app/store/modules/workspace/items';
6+
import getWorkspaceItems, {
7+
getDisabledItems,
8+
} from 'app/store/modules/workspace/items';
79
import Files from './items/Files';
810
import { GitHub } from './items/GitHub';
911
import Server from './items/Server';
@@ -56,7 +58,9 @@ const Workspace = () => {
5658
}
5759

5860
const Component = workspaceTabs[activeTab];
59-
const item = getWorkspaceItems(store).find(({ id }) => id === activeTab);
61+
const item =
62+
getWorkspaceItems(store).find(({ id }) => id === activeTab) ||
63+
getDisabledItems(store).find(({ id }) => id === activeTab);
6064

6165
return (
6266
<Container>

packages/app/src/app/pages/Sandbox/Editor/Workspace/items/Deployment/index.js

Lines changed: 0 additions & 26 deletions
This file was deleted.
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
import React, { useEffect } from 'react';
2+
import { observer } from 'mobx-react-lite';
3+
4+
import { useStore, useSignals } from 'app/store';
5+
import { Description } from '../../elements';
6+
import ZeitDeployments from './Zeit';
7+
import NetlifyDeployments from './Netlify';
8+
import { More } from '../More';
9+
10+
const Deployment = observer(() => {
11+
const store = useStore();
12+
const signals = useSignals();
13+
14+
const showPlaceholder =
15+
!store.editor.currentSandbox.owned || !store.isLoggedIn;
16+
17+
useEffect(() => {
18+
if (!showPlaceholder) {
19+
signals.deployment.getDeploys();
20+
}
21+
}, [showPlaceholder, signals]);
22+
23+
if (showPlaceholder) {
24+
const message = store.isLoggedIn ? (
25+
<>
26+
You need to own this sandbox to deploy this sandbox to Netlify or ZEIT.{' '}
27+
<p>Fork this sandbox to make a deploy!</p>
28+
</>
29+
) : (
30+
<>You need to be signed in to deploy this sandbox to Netlify or ZEIT.</>
31+
);
32+
33+
return <More message={message} id="github" />;
34+
}
35+
36+
return (
37+
<div>
38+
<Description>
39+
You can deploy a production version of your sandbox using one our
40+
supported providers.
41+
</Description>
42+
<ZeitDeployments />
43+
<NetlifyDeployments />
44+
</div>
45+
);
46+
});
47+
48+
export default Deployment;

0 commit comments

Comments
 (0)