Skip to content

Commit 55948a2

Browse files
authored
Dashboard: List view (codesandbox#4077)
1 parent d4d6050 commit 55948a2

File tree

13 files changed

+393
-429
lines changed

13 files changed

+393
-429
lines changed

packages/app/src/app/pages/NewDashboard/Components/SandboxCard/Menu.tsx renamed to packages/app/src/app/pages/NewDashboard/Components/Sandbox/Menu.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,24 +25,24 @@ export const MenuOptions = ({ sandbox, isTemplate, onRename }) => {
2525
<Menu.List>
2626
<Menu.Item
2727
onSelect={() => {
28-
history.push(getFolderUrl(sandbox.collection.path));
28+
history.push(url);
2929
}}
3030
>
31-
Show in Folder
31+
Open sandbox
3232
</Menu.Item>
3333
<Menu.Item
3434
onSelect={() => {
35-
history.push(url);
35+
window.open(`https://codesandbox.io${url}`, '_blank');
3636
}}
3737
>
38-
Open sandbox
38+
Open sandbox in new tab
3939
</Menu.Item>
4040
<Menu.Item
4141
onSelect={() => {
42-
window.open(`https://codesandbox.io${url}`, '_blank');
42+
history.push(getFolderUrl(sandbox.collection.path));
4343
}}
4444
>
45-
Open sandbox in new tab
45+
Show in Folder
4646
</Menu.Item>
4747
<Menu.Divider />
4848
<Menu.Item
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
import React from 'react';
2+
import { Link as RouterLink } from 'react-router-dom';
3+
import {
4+
Stack,
5+
Element,
6+
Text,
7+
Link,
8+
Stats,
9+
Input,
10+
SkeletonText,
11+
isMenuClicked,
12+
} from '@codesandbox/components';
13+
import css from '@styled-system/css';
14+
import { MenuOptions } from './Menu';
15+
16+
export const SandboxCard = ({
17+
sandbox,
18+
isTemplate = false,
19+
sandboxTitle,
20+
newTitle,
21+
url,
22+
edit,
23+
inputRef,
24+
onChange,
25+
onKeyDown,
26+
onSubmit,
27+
onBlur,
28+
enterEditing,
29+
...props
30+
}) => (
31+
<Link
32+
as={RouterLink}
33+
to={url}
34+
onClick={event => {
35+
if (edit || isMenuClicked(event)) event.preventDefault();
36+
}}
37+
>
38+
<Stack
39+
direction="vertical"
40+
gap={2}
41+
css={css({
42+
width: '100%',
43+
height: 240,
44+
border: '1px solid',
45+
borderColor: 'grays.600',
46+
borderRadius: 'medium',
47+
overflow: 'hidden',
48+
transition: 'all ease-in-out',
49+
transitionDuration: theme => theme.speeds[4],
50+
':hover, :focus, :focus-within': {
51+
cursor: edit ? 'normal' : 'pointer',
52+
boxShadow: theme => '0 4px 16px 0 ' + theme.colors.grays[900],
53+
},
54+
})}
55+
{...props}
56+
>
57+
<Element
58+
as="div"
59+
css={css({
60+
height: 160,
61+
backgroundColor: 'grays.600',
62+
backgroundImage: `url(${sandbox.screenshotUrl})`,
63+
backgroundSize: 'cover',
64+
backgroundPosition: 'center center',
65+
backgroundRepeat: 'no-repeat',
66+
})}
67+
/>
68+
<Stack justify="space-between" align="center" marginLeft={4}>
69+
{edit ? (
70+
<form onSubmit={onSubmit}>
71+
<Input
72+
value={newTitle}
73+
ref={inputRef}
74+
onChange={onChange}
75+
onKeyDown={onKeyDown}
76+
onBlur={onBlur}
77+
/>
78+
</form>
79+
) : (
80+
<Text size={3} weight="medium">
81+
{sandboxTitle}
82+
</Text>
83+
)}
84+
<MenuOptions
85+
sandbox={sandbox}
86+
isTemplate={isTemplate}
87+
onRename={enterEditing}
88+
/>
89+
</Stack>
90+
<Stack marginX={4}>
91+
<Stats
92+
css={css({ fontSize: 2 })}
93+
sandbox={{
94+
viewCount: kFormatter(sandbox.viewCount),
95+
likeCount: kFormatter(sandbox.likeCount),
96+
forkCount: kFormatter(sandbox.forkCount),
97+
}}
98+
/>
99+
</Stack>
100+
</Stack>
101+
</Link>
102+
);
103+
104+
const kFormatter = (num: number): string => {
105+
if (num > 999999) {
106+
return (num / 1000000).toFixed(1) + 'M';
107+
}
108+
109+
if (num > 999) {
110+
return (num / 1000).toFixed(1) + 'K';
111+
}
112+
113+
return num.toString();
114+
};
115+
116+
export const SkeletonCard = () => (
117+
<Stack
118+
direction="vertical"
119+
gap={4}
120+
css={css({
121+
width: '100%',
122+
height: 240,
123+
border: '1px solid',
124+
borderColor: 'grays.600',
125+
borderRadius: 'medium',
126+
overflow: 'hidden',
127+
transition: 'all ease-in-out',
128+
transitionDuration: theme => theme.speeds[4],
129+
})}
130+
>
131+
<SkeletonText css={{ width: '100%', height: 160 }} />
132+
<Stack direction="vertical" gap={2} marginX={4}>
133+
<SkeletonText css={{ width: 120 }} />
134+
<SkeletonText css={{ width: 180 }} />
135+
</Stack>
136+
</Stack>
137+
);
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import React from 'react';
2+
import { Link as RouterLink } from 'react-router-dom';
3+
import formatDistanceToNow from 'date-fns/formatDistanceToNow';
4+
import {
5+
Stack,
6+
Element,
7+
Text,
8+
Input,
9+
Link,
10+
ListAction,
11+
SkeletonText,
12+
isMenuClicked,
13+
} from '@codesandbox/components';
14+
import css from '@styled-system/css';
15+
import { MenuOptions } from './Menu';
16+
17+
export const SandboxListItem = ({
18+
sandbox,
19+
isTemplate = false,
20+
sandboxTitle,
21+
newTitle,
22+
url,
23+
edit,
24+
inputRef,
25+
onChange,
26+
onKeyDown,
27+
onSubmit,
28+
onBlur,
29+
enterEditing,
30+
...props
31+
}) => (
32+
<ListAction css={css({ paddingX: 0 })}>
33+
<Link
34+
as={RouterLink}
35+
to={url}
36+
onClick={event => {
37+
if (edit || isMenuClicked(event)) event.preventDefault();
38+
}}
39+
style={{ width: '100%' }}
40+
>
41+
<Stack
42+
gap={2}
43+
align="center"
44+
paddingX={2}
45+
justify="space-between"
46+
css={css({
47+
height: 64,
48+
borderBottom: '1px solid',
49+
borderBottomColor: 'grays.600',
50+
overflow: 'hidden',
51+
})}
52+
{...props}
53+
>
54+
<Stack gap={4} align="center">
55+
<Element
56+
as="div"
57+
css={css({
58+
borderRadius: 'small',
59+
height: 32,
60+
width: 32,
61+
backgroundImage: `url(${sandbox.screenshotUrl})`,
62+
backgroundSize: 'cover',
63+
backgroundPosition: 'center center',
64+
backgroundRepeat: 'no-repeat',
65+
})}
66+
/>
67+
<Element style={{ width: 150 }}>
68+
{edit ? (
69+
<form onSubmit={onSubmit}>
70+
<Input
71+
value={newTitle}
72+
ref={inputRef}
73+
onChange={onChange}
74+
onKeyDown={onKeyDown}
75+
onBlur={onBlur}
76+
/>
77+
</form>
78+
) : (
79+
<Text size={3} weight="medium">
80+
{sandboxTitle}
81+
</Text>
82+
)}
83+
</Element>
84+
</Stack>
85+
{sandbox.removedAt ? (
86+
<Text size={3} variant="muted" block style={{ width: 180 }}>
87+
Deleted {formatDistanceToNow(new Date(sandbox.removedAt))} ago
88+
</Text>
89+
) : (
90+
<Text size={3} variant="muted" block style={{ width: 180 }}>
91+
Updated {formatDistanceToNow(new Date(sandbox.updatedAt))} ago
92+
</Text>
93+
)}
94+
<MenuOptions
95+
sandbox={sandbox}
96+
isTemplate={isTemplate}
97+
onRename={enterEditing}
98+
/>
99+
</Stack>
100+
</Link>
101+
</ListAction>
102+
);
103+
104+
export const SkeletonListItem = () => (
105+
<Stack
106+
paddingX={2}
107+
align="center"
108+
justify="space-between"
109+
css={css({
110+
height: 64,
111+
paddingX: 2,
112+
borderBottom: '1px solid',
113+
borderBottomColor: 'grays.600',
114+
})}
115+
>
116+
<Stack align="center" gap={4}>
117+
<SkeletonText css={{ height: 32, width: 32 }} />
118+
<SkeletonText css={{ width: 120 }} />
119+
</Stack>
120+
<SkeletonText css={{ width: 120 }} />
121+
<SkeletonText
122+
css={{
123+
width: 26,
124+
/* keep menu for justify, but hide it from user */
125+
opacity: 0,
126+
}}
127+
/>
128+
</Stack>
129+
);

0 commit comments

Comments
 (0)