Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions packages/app/src/app/overmind/namespaces/editor/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import {
} from '@codesandbox/common/lib/types';
import { getTextOperation } from '@codesandbox/common/lib/utils/diff';
import { COMMENTS } from '@codesandbox/common/lib/utils/feature-flags';
import { hasPermission } from '@codesandbox/common/lib/utils/permission';
import { convertTypeToStatus } from '@codesandbox/common/lib/utils/notifications';
import { NotificationStatus } from '@codesandbox/notifications';
import { hasPermission } from '@codesandbox/common/lib/utils/permission';
import { signInPageUrl } from '@codesandbox/common/lib/utils/url-generator';
import { NotificationStatus } from '@codesandbox/notifications';
import {
Authorization,
CollaboratorFragment,
Expand Down Expand Up @@ -472,6 +472,8 @@ export const moduleSelected: Action<
> = ({ actions, effects, state }, { id, path }) => {
effects.analytics.track('Open File');

state.editor.hasLoadedInitialModule = true;

const sandbox = state.editor.currentSandbox;

if (!sandbox) {
Expand Down
2 changes: 2 additions & 0 deletions packages/app/src/app/overmind/namespaces/editor/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,11 @@ type State = {
selectedCommentsFilter: CommentsFilterOption;
currentCommentId: string | null;
currentComment: Derive<State, Comment | null>;
hasLoadedInitialModule: boolean;
};

export const state: State = {
hasLoadedInitialModule: false,
comments: {},
currentCommentId: null, // '5e5961e0c277a40fef1e391b',
currentComment: ({ comments, currentSandbox, currentCommentId }) => {
Expand Down
73 changes: 73 additions & 0 deletions packages/app/src/app/pages/Sandbox/Editor/Skeleton/elements.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import styled, { css, keyframes } from 'styled-components';

const pulse = keyframes`
0% { background-position: 100% 50%; }
100% { background-position: -100% 50%; }
`;

export const SkeletonTextBlock = styled.div(
props => css`
height: 16px;
width: 200px;
animation: ${pulse} 2s linear infinite;
background: linear-gradient(
90deg,
${props.theme.colors?.sideBar.border + '80'} 0%,
${props.theme.colors?.sideBar.border + '80'} 40%,
${props.theme.colors?.sideBar.border + 'd6'} 50%,
${props.theme.colors?.sideBar.border + '80'} 60%,
${props.theme.colors?.sideBar.border + '80'} 100%
);
background-size: 200% 200%;
`
);

export const SkeletonWrapper = styled.div`
position: absolute;
font-family: Inter, sans-serif;
opacity: 1;
transition: opacity 0.5s ease-out;
background-color: ${props =>
props.theme.colors?.editor?.background || 'black'};
width: 100%;
height: 100%;
display: flex;
top: 0;
left: 0;
z-index: 10;
`;

export const SkeletonExplorer = styled.div`
flex: 0 0 272px;
border-right: 1px solid
${props => props.theme.colors?.sideBar.border || 'rgba(0, 0, 0, 0.5)'};
background-color: ${props =>
props.theme.colors?.sideBar.background || 'rgba(0, 0, 0, 0.5)'};
color: ${props => props.theme.colors?.sideBar.foreground || '#ffffff'} + '80';
`;

export const SkeletonEditor = styled.div`
flex: 1;
border-right: 1px solid
${props => props.theme.colors?.sideBar.border || 'rgba(0, 0, 0, 0.5)'};
`;
export const SkeletonEditorTop = styled.div`
height: 34px;
border-bottom: 1px solid
${props => props.theme.colors?.sideBar.border || 'rgba(0, 0, 0, 0.5)'};
`;
export const SkeletonDevtools = styled.div`
flex: 1;
`;
export const SkeletonDevtoolsTop = styled.div`
height: 34px;
`;
export const SkeletonDevtoolsNavigator = styled.div`
height: 34px;
border-bottom: 1px solid
${props => props.theme.colors?.sideBar.border || 'rgba(0, 0, 0, 0.5)'};
`;
export const SkeletonDevtoolsIframe = styled.div`
height: 100%;
background-color: #fff;
`;
114 changes: 114 additions & 0 deletions packages/app/src/app/pages/Sandbox/Editor/Skeleton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import Navigator from '@codesandbox/common/lib/components/Preview/Navigator';
import { Collapsible, List, ListItem, Stack } from '@codesandbox/components';
import css from '@styled-system/css';
import React from 'react';

import {
SkeletonDevtools,
SkeletonDevtoolsIframe,
SkeletonDevtoolsNavigator,
SkeletonDevtoolsTop,
SkeletonEditor,
SkeletonEditorTop,
SkeletonExplorer,
SkeletonTextBlock,
SkeletonWrapper,
} from './elements';

export const ContentSkeleton = ({ style }) => (
<SkeletonWrapper style={style}>
<SkeletonExplorer>
<SkeletonExplorerContents />
</SkeletonExplorer>
<SkeletonEditor>
<SkeletonEditorTop />
</SkeletonEditor>
<SkeletonDevtools>
<SkeletonDevtoolsTop />
<SkeletonDevtoolsNavigator>
<Navigator
url=""
onChange={() => {}}
onConfirm={() => {}}
onRefresh={() => {}}
isProjectView
/>
</SkeletonDevtoolsNavigator>
<SkeletonDevtoolsIframe />
</SkeletonDevtools>
</SkeletonWrapper>
);

const SkeletonExplorerContents = () => (
<>
<Collapsible title="Files" defaultOpen>
<List>
<File type="folder" />
<File type="folder" />
<File type="file" nested />
<File type="file" nested />
<File type="file" nested />
<File type="file" />
</List>
</Collapsible>
<Collapsible title="Dependencies" defaultOpen>
<List css={{ marginBottom: '32px' }}>
<Dependency />
<Dependency />
<Dependency />
</List>
</Collapsible>
<Collapsible title="External resources" />
</>
);

export const File = props => (
<ListItem
justify="space-between"
align="center"
css={{
minHeight: '28px',
paddingLeft: `calc(${props.nested ? 2 : 1}rem - 2px)`,
}}
{...props}
>
<Stack gap={2} align="center" css={css({ color: 'sideBar.border' })}>
<span style={{ opacity: 0.5 }}>{icons[props.type]}</span>{' '}
<SkeletonTextBlock />
</Stack>
</ListItem>
);

const Dependency = () => (
<ListItem justify="space-between">
<SkeletonTextBlock />
</ListItem>
);

const icons = {
folder: (
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M6.86667 2L8.33333 3.46667H14.2C15 3.46667 15.6667 4.13333 15.6667 4.93333V12.4C15.6667 13.2 15 13.8667 14.2 13.8667H2.46667C1.66667 14 1 13.3333 1 12.5333V3.46667C1 2.66667 1.66667 2 2.46667 2H6.86667Z"
fill="currentColor"
/>
</svg>
),
file: (
<svg
width="12"
height="12"
viewBox="0 0 12 12"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<rect width="12" height="12" rx="2" fill="currentColor" />
</svg>
),
};
54 changes: 0 additions & 54 deletions packages/app/src/app/pages/Sandbox/Editor/elements.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,57 +14,3 @@ export const Container = styled.div`
background-clip: padding-box;
}
`;

export const SkeletonWrapper = styled.div`
position: absolute;
transition: opacity 0.5s ease-out;
opacity: 1;
background-color: ${props =>
props.theme.colors?.editor?.background || 'black'};
width: 100%;
height: 100%;
display: flex;
top: 0;
left: 0;
z-index: 10;
`;

export const SkeletonExplorer = styled.div`
flex: 0 0 272px;
border-right: 1px solid
${props => props.theme.colors?.sideBar.border || 'rgba(0, 0, 0, 0.5)'};
background-color: ${props =>
props.theme.colors?.sideBar.background || 'rgba(0, 0, 0, 0.5)'};
`;
export const SkeletonExplorerTop = styled.div`
height: 35px;
border-bottom: 1px solid
${props =>
props.theme.vscodeTheme.colors.editorGroupHeader?.tabsBackground ||
'rgba(0, 0, 0, 0.5)'};
`;
export const SkeletonEditor = styled.div`
flex: 1;
border-right: 1px solid
${props => props.theme.colors?.sideBar.border || 'rgba(0, 0, 0, 0.5)'};
`;
export const SkeletonEditorTop = styled.div`
height: 35px;
border-bottom: 1px solid
${props => props.theme.colors?.sideBar.border || 'rgba(0, 0, 0, 0.5)'};
`;
export const SkeletonDevtools = styled.div`
flex: 1;
`;
export const SkeletonDevtoolsTop = styled.div`
height: 35px;
`;
export const SkeletonDevtoolsNavigator = styled.div`
height: 35px;
border-bottom: 1px solid
${props => props.theme.colors?.sideBar.border || 'rgba(0, 0, 0, 0.5)'};
`;
export const SkeletonDevtoolsIframe = styled.div`
height: 100%;
background-color: #fff;
`;
79 changes: 26 additions & 53 deletions packages/app/src/app/pages/Sandbox/Editor/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import Fullscreen from '@codesandbox/common/lib/components/flex/Fullscreen';
import Navigator from '@codesandbox/common/lib/components/Preview/Navigator';
import getTemplateDefinition from '@codesandbox/common/lib/templates';
import codesandbox from '@codesandbox/common/lib/themes/codesandbox.json';
import { REDESIGNED_SIDEBAR } from '@codesandbox/common/lib/utils/feature-flags';
Expand All @@ -11,23 +10,13 @@ import SplitPane from 'react-split-pane';
import styled, { ThemeProvider } from 'styled-components';

import Content from './Content';
import {
Container,
SkeletonDevtools,
SkeletonDevtoolsIframe,
SkeletonDevtoolsNavigator,
SkeletonDevtoolsTop,
SkeletonEditor,
SkeletonEditorTop,
SkeletonExplorer,
SkeletonExplorerTop,
SkeletonWrapper,
} from './elements';
import { Container } from './elements';
import ForkFrozenSandboxModal from './ForkFrozenSandboxModal';
import { Header } from './Header';
import { Header as HeaderOld } from './HeaderOld';
import { Navigation } from './Navigation';
import { Navigation as NavigationOld } from './NavigationOld';
import { ContentSkeleton } from './Skeleton';
import getVSCodeTheme from './utils/get-vscode-theme';
import { Workspace } from './Workspace';

Expand All @@ -39,41 +28,8 @@ const StatusBar = styled.div`
}
`;

const ContentSkeleton = ({ style, onTransitionEnd }) => {
React.useEffect(() => {
// In case we started already with opacity 0
if (style.opacity === 0) {
onTransitionEnd();
}
}, [onTransitionEnd, style.opacity]); // eslint-disable-line we don't want to check style on purpose

return (
<SkeletonWrapper style={style} onTransitionEnd={onTransitionEnd}>
<SkeletonExplorer>
<SkeletonExplorerTop />
</SkeletonExplorer>
<SkeletonEditor>
<SkeletonEditorTop />
</SkeletonEditor>
<SkeletonDevtools>
<SkeletonDevtoolsTop />
<SkeletonDevtoolsNavigator>
<Navigator
url=""
onChange={() => {}}
onConfirm={() => {}}
onRefresh={() => {}}
isProjectView
/>
</SkeletonDevtoolsNavigator>
<SkeletonDevtoolsIframe />
</SkeletonDevtools>
</SkeletonWrapper>
);
};

const ContentSplit = () => {
const { state, actions, effects } = useOvermind();
const { state, actions, effects, reaction } = useOvermind();
const statusbarEl = useRef(null);
const [showSkeleton, setShowSkeleton] = useState(true);
const [localState, setLocalState] = useState({
Expand All @@ -84,6 +40,20 @@ const ContentSplit = () => {
customVSCodeTheme: null,
});

useEffect(() => {
let timeout;
const dispose = reaction(
reactionState => reactionState.editor.hasLoadedInitialModule,
() => {
timeout = setTimeout(() => setShowSkeleton(false), 500);
}
);
return () => {
dispose();
clearTimeout(timeout);
};
}, [reaction]);

useEffect(() => {
async function loadTheme() {
const vsCodeTheme = state.preferences.settings.customVSCodeTheme;
Expand Down Expand Up @@ -201,12 +171,15 @@ const ContentSplit = () => {
{showSkeleton ? (
<NewThemeProvider theme={localState.theme.vscodeTheme}>
<ContentSkeleton
style={{
opacity: state.editor.isLoading ? 1 : 0,
}}
onTransitionEnd={() => {
setShowSkeleton(false);
}}
style={
state.editor.hasLoadedInitialModule
? {
opacity: 0,
}
: {
opacity: 1,
}
}
/>
</NewThemeProvider>
) : null}
Expand Down