Skip to content

Commit 771ad2b

Browse files
Polish sandbox info (codesandbox#3369)
* Fix width of textarea with count * remove noPadding in favor of css= * fix alignment of editable title+description * add hover+focus states for input elements * remove padding from stats + club author and stats together * deduplicate codesandbox black theme * Add link component * fix foreground color in theme * fix focus state for input * fix focus state for swtich * fix privacy setting for pro users * convert text to link * fix outline for color picker button * fix text + switch component * link avatar * use link for pro link * make description muted * disable underline from workbench.css * sigh use important coz old design uses workbench * handle patrons without subscription * turns out my profile is busted, not subscriptionSince * oops sorry missed that * fix types Co-authored-by: Sara Vieira <[email protected]>
1 parent a7d3b89 commit 771ad2b

File tree

16 files changed

+159
-62
lines changed

16 files changed

+159
-62
lines changed

packages/app/src/app/overmind/effects/vscode/initializers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ export function initializeCustomTheme() {
124124

125125
installCustomTheme(
126126
'codesandbox-black-0.0.1',
127-
'CodeSandbox Black',
127+
'CodeSandbox Black.',
128128
JSON.stringify(codeSandboxBlackTheme)
129129
);
130130
}

packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/ProjectInfo/Description.tsx

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,35 @@ import React, {
66
useState,
77
} from 'react';
88
import styled from 'styled-components';
9+
import css from '@styled-system/css';
910
import { useOvermind } from 'app/overmind';
10-
import { Textarea, SidebarRow, Text, FormField } from '@codesandbox/components';
11+
import {
12+
Element,
13+
Textarea,
14+
SidebarRow,
15+
Text,
16+
FormField,
17+
} from '@codesandbox/components';
1118
import { PenIcon } from './icons';
1219

1320
const DescriptionTrimmed = styled(Text)`
1421
display: -webkit-box;
1522
-webkit-line-clamp: 3;
1623
-webkit-box-orient: vertical;
24+
flex-wrap: wrap;
25+
word-break: break-word;
1726
overflow: hidden;
1827
`;
1928

2029
const Icon = styled(PenIcon)`
2130
cursor: pointer;
22-
display: none;
31+
opacity: 0;
2332
`;
2433

25-
const SandboxDescription = styled(SidebarRow)<{ empty: boolean }>`
26-
font-style: ${props => (props.empty ? 'normal' : 'italic')};
27-
flex-wrap: wrap;
28-
word-break: break-all;
34+
const SandboxDescription = styled(SidebarRow)`
2935
:hover {
3036
svg {
31-
display: block;
37+
opacity: 1;
3238
}
3339
}
3440
`;
@@ -68,10 +74,10 @@ export const Description: FunctionComponent<Props> = ({ editable }) => {
6874

6975
return editing ? (
7076
<FormField
71-
noPadding
7277
direction="vertical"
7378
label="Sandbox Description"
7479
hideLabel
80+
css={css({ paddingX: 0 })}
7581
>
7682
<Textarea
7783
onBlur={() => {
@@ -88,11 +94,15 @@ export const Description: FunctionComponent<Props> = ({ editable }) => {
8894
/>
8995
</FormField>
9096
) : (
91-
<SandboxDescription gap={4} empty={Boolean(description)}>
92-
<DescriptionTrimmed>
93-
{description || (editable ? 'No description, create one!' : '')}
97+
<SandboxDescription>
98+
<DescriptionTrimmed variant="muted">
99+
{description || (editable ? 'No description, create one!' : null)}
100+
{editable && (
101+
<Element as="span" marginX={2}>
102+
<Icon onClick={() => setEditing(true)} />
103+
</Element>
104+
)}
94105
</DescriptionTrimmed>
95-
{editable && <Icon onClick={() => setEditing(true)} />}
96106
</SandboxDescription>
97107
);
98108
};

packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/ProjectInfo/Privacy.tsx

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import React from 'react';
2-
import { Collapsible, Text, Stack, Select } from '@codesandbox/components';
2+
import {
3+
Collapsible,
4+
Text,
5+
Link,
6+
Stack,
7+
Select,
8+
} from '@codesandbox/components';
39
import { useOvermind } from 'app/overmind';
410
import { css } from '@styled-system/css';
511
import { GlobeIcon } from './icons';
@@ -11,15 +17,17 @@ export const Privacy = () => {
1117
},
1218
state: {
1319
editor: { currentSandbox },
14-
isPatron,
20+
user,
1521
},
1622
} = useOvermind();
1723

24+
const isPaidUser = user?.subscription;
25+
1826
return (
1927
<Collapsible title="Privacy" defaultOpen>
2028
<Stack direction="vertical" gap={4} css={css({ paddingX: 3 })}>
2129
<Select
22-
disabled={!isPatron}
30+
disabled={!isPaidUser}
2331
icon={GlobeIcon}
2432
onChange={({ target: { value } }) =>
2533
sandboxPrivacyChanged({
@@ -30,18 +38,15 @@ export const Privacy = () => {
3038
value={currentSandbox.privacy}
3139
>
3240
<option value={0}>Public</option>
33-
34-
{isPatron && (
35-
<option value={1}>Unlisted (only available by url)</option>
36-
)}
37-
38-
{isPatron && <option value={2}>Private</option>}
41+
<option value={1}>Unlisted (only available by url)</option>
42+
<option value={2}>Private</option>
3943
</Select>
40-
{!isPatron ? (
44+
{isPaidUser ? (
4145
<Text variant="muted" size={2}>
42-
You an change privacy of a sandbox as a Pro.
43-
<br />
44-
Become a Pro.
46+
You an change privacy of a sandbox as a Pro.{' '}
47+
<Link href="/pro" css={{ textDecoration: 'underline !important' }}>
48+
Become a Pro
49+
</Link>
4550
</Text>
4651
) : null}
4752
</Stack>

packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/ProjectInfo/TemplateConfig.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,14 @@ const PickColor = styled(PopoverDisclosure)`
2525
${({ theme, color }) => css`
2626
width: ${theme.space[5]}px;
2727
height: ${theme.space[4]}px;
28-
border: 1px solid inherit;
28+
border: 1px solid ${color};
2929
background: ${color};
3030
border-radius: ${theme.radii.small}px;
31+
&:focus {
32+
// need to use !important to override styles from
33+
// workbench-theme.css, not proud :/
34+
outline: none !important;
35+
}
3136
`}
3237
`;
3338

packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/ProjectInfo/Title.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { useOvermind } from 'app/overmind';
66

77
import { Text, Input, SidebarRow, FormField } from '@codesandbox/components';
88
import styled from 'styled-components';
9+
import css from '@styled-system/css';
910
import { PenIcon } from './icons';
1011

1112
const Icon = styled(PenIcon)`
@@ -64,7 +65,7 @@ export const Title = ({ editable }) => {
6465
};
6566

6667
return editing ? (
67-
<FormField label="Sandbox Name" hideLabel>
68+
<FormField label="Sandbox Name" hideLabel css={css({ paddingX: 0 })}>
6869
<Input
6970
onBlur={onBlur}
7071
onChange={onChange}
@@ -78,7 +79,7 @@ export const Title = ({ editable }) => {
7879
/>
7980
</FormField>
8081
) : (
81-
<SandboxNameWrapper gap={4}>
82+
<SandboxNameWrapper gap={2}>
8283
<Text>{getSandboxName(currentSandbox)}</Text>
8384
{editable && <Icon onClick={edit} />}
8485
</SandboxNameWrapper>

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

Lines changed: 41 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,22 @@ import {
33
Element,
44
Collapsible,
55
Text,
6+
Link,
7+
Label,
68
Avatar,
79
Stack,
810
List,
911
ListItem,
1012
Switch,
1113
Stats,
1214
} from '@codesandbox/components';
15+
1316
import { getSandboxName } from '@codesandbox/common/lib/utils/get-sandbox-name';
17+
import {
18+
sandboxUrl,
19+
profileUrl,
20+
} from '@codesandbox/common/lib/utils/url-generator';
21+
import getTemplateDefinition from '@codesandbox/common/lib/templates';
1422
import { useOvermind } from 'app/overmind';
1523

1624
import { css } from '@styled-system/css';
@@ -19,8 +27,6 @@ import { Description } from './Description';
1927
import { Privacy } from './Privacy';
2028
import { Config } from './Config';
2129

22-
const Link = props => <Text variant="muted" {...props} />;
23-
2430
export const ProjectInfo = () => {
2531
const {
2632
actions: {
@@ -54,45 +60,56 @@ export const ProjectInfo = () => {
5460
return frozenUpdated({ frozen: !isFrozen });
5561
};
5662

63+
const isForked = forkedFromSandbox || forkedTemplateSandbox;
64+
const { url: templateUrl } = getTemplateDefinition(template);
65+
5766
return (
5867
<>
5968
<Collapsible title="Sandbox Info" defaultOpen>
6069
<Stack direction="vertical" gap={6}>
61-
<Element css={css({ paddingX: 2 })}>
70+
<Element as="section" css={css({ paddingX: 2 })}>
6271
<Title editable />
6372
<Description editable />
6473
</Element>
65-
{author ? (
66-
<Stack
67-
gap={2}
68-
align="center"
69-
marginBottom={4}
70-
css={css({ paddingX: 2 })}
71-
>
72-
<Avatar user={author} /> <Text>{author.username}</Text>
73-
</Stack>
74-
) : null}
75-
<Stats sandbox={currentSandbox} />
74+
75+
<Element as="section" css={css({ paddingX: 2 })}>
76+
{author ? (
77+
<Link href={profileUrl(author.username)}>
78+
<Stack gap={2} align="center" marginBottom={4}>
79+
<Avatar user={author} /> <Text>{author.username}</Text>
80+
</Stack>
81+
</Link>
82+
) : null}
83+
<Stats sandbox={currentSandbox} />
84+
</Element>
85+
7686
<List>
7787
<ListItem justify="space-between">
78-
<Text as="label" htmlFor="frozen">
79-
Frozen
80-
</Text>
88+
<Label htmlFor="frozen">Frozen</Label>
8189
<Switch
8290
id="frozen"
8391
onChange={updateFrozenState}
8492
on={customTemplate ? sessionFrozen : isFrozen}
8593
/>
8694
</ListItem>
87-
<ListItem justify="space-between">
88-
<Text> {forkedTemplateSandbox ? 'Template' : 'Forked From'}</Text>
89-
<Link>
90-
{getSandboxName(forkedFromSandbox || forkedTemplateSandbox)}
91-
</Link>
92-
</ListItem>
95+
{isForked ? (
96+
<ListItem justify="space-between">
97+
<Text>
98+
{forkedTemplateSandbox ? 'Template' : 'Forked From'}
99+
</Text>
100+
<Link
101+
href={sandboxUrl(forkedFromSandbox || forkedTemplateSandbox)}
102+
target="_blank"
103+
>
104+
{getSandboxName(forkedFromSandbox || forkedTemplateSandbox)}
105+
</Link>
106+
</ListItem>
107+
) : null}
93108
<ListItem justify="space-between">
94109
<Text>Environment</Text>
95-
<Link>{template}</Link>
110+
<Link href={templateUrl} target="_blank">
111+
{template}
112+
</Link>
96113
</ListItem>
97114
</List>
98115
</Stack>

packages/common/src/themes/codesandbox-black.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const colors = {
1414
contrastActiveBorder: null,
1515
errorForeground: tokens.reds[500],
1616
focusBorder: tokens.grays[600],
17-
foreground: tokens.grays[300],
17+
foreground: tokens.grays[200],
1818
activityBar: {
1919
background: tokens.grays[700],
2020
border: tokens.grays[600],
@@ -137,7 +137,7 @@ const colors = {
137137
placeholderForeground: tokens.grays[300],
138138
},
139139
inputOption: {
140-
activeBorder: tokens.blues[300],
140+
activeBorder: tokens.grays[300],
141141
},
142142
inputValidation: {
143143
infoForeground: null,
@@ -212,7 +212,7 @@ const colors = {
212212
background: tokens.grays[700],
213213
hoverBackground: tokens.green,
214214
border: tokens.grays[600],
215-
foreground: tokens.grays[300],
215+
foreground: tokens.grays[200],
216216
},
217217
sideBarSectionHeader: {
218218
background: tokens.grays[700],

packages/components/src/components/FormField/index.tsx

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ interface IFormFieldProps {
1414
// for this purpose, we visually hide the label but still keep in the
1515
// elements tree.
1616
hideLabel?: boolean;
17-
noPadding?: boolean;
1817
direction?: 'horizontal' | 'vertical';
1918
}
2019

@@ -23,7 +22,6 @@ export const FormField: React.FC<IFormFieldProps> = ({
2322
id,
2423
hideLabel = false,
2524
direction = 'horizontal',
26-
noPadding,
2725
...props
2826
}) => {
2927
const inputId = useId(id);
@@ -42,7 +40,7 @@ export const FormField: React.FC<IFormFieldProps> = ({
4240
direction="horizontal"
4341
justify="space-between"
4442
align="center"
45-
css={{ height: 8, paddingX: noPadding ? 0 : 2 }}
43+
css={{ height: 8, paddingX: 2 }}
4644
{...props}
4745
>
4846
<LabelWrapper>
@@ -59,7 +57,7 @@ export const FormField: React.FC<IFormFieldProps> = ({
5957
return (
6058
<Element
6159
css={{
62-
paddingX: noPadding ? 0 : 2,
60+
paddingX: 2,
6361
}}
6462
{...props}
6563
>

packages/components/src/components/Input/index.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,16 @@ export const Input = styled(Element).attrs({ as: 'input' })(
2121
'::-webkit-input-placeholder': placeholderStyles,
2222
'::-ms-input-placeholder': placeholderStyles,
2323
'::placeholder': placeholderStyles,
24+
25+
':hover, :focus': {
26+
borderColor: 'inputOption.activeBorder',
27+
// need to use !important to override styles from
28+
// workbench-theme.css, not proud :/
29+
outline: 'none !important',
30+
},
31+
':disabled': {
32+
opacity: 0.4,
33+
borderColor: 'input.border', // (default border)
34+
},
2435
})
2536
);

0 commit comments

Comments
 (0)