Skip to content

Commit c7e8d16

Browse files
authored
more things (codesandbox#3859)
* more things * Revert schema.graphql
1 parent 9ddba5c commit c7e8d16

File tree

10 files changed

+315
-59
lines changed

10 files changed

+315
-59
lines changed

packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/Comments/AddComment.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ export const AddComment: React.FC<Props> = ({ onSubmit }) => {
2121
// Form elements submit on Enter, except Textarea :)
2222
const submitOnEnter = event => {
2323
if (event.keyCode === ENTER && !event.shiftKey) {
24+
event.preventDefault();
2425
submit(event);
2526
}
2627
};

packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/Comments/Comment.tsx

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,17 +74,6 @@ export const Comment = React.memo<{
7474
itemScope
7575
itemType="http://schema.org/Comment"
7676
>
77-
<Link
78-
variant="muted"
79-
css={css({
80-
paddingBottom: 2,
81-
display: 'block',
82-
})}
83-
>
84-
{comment.references[0]
85-
? comment.references[0].metadata.path
86-
: 'General'}
87-
</Link>
8877
<Stack align="flex-start" justify="space-between" marginBottom={4}>
8978
<AvatarBlock comment={comment} />
9079
<Stack align="center">
@@ -126,6 +115,26 @@ export const Comment = React.memo<{
126115
</Menu>
127116
</Stack>
128117
</Stack>
118+
{comment.references[0] && (
119+
<Link
120+
variant="muted"
121+
css={css({
122+
marginTop: -2,
123+
opacity: 0.6,
124+
paddingBottom: 2,
125+
display: 'block',
126+
transition: 'all ease',
127+
transitionDuration: theme => theme.speeds[1],
128+
129+
':hover': {
130+
opacity: 1,
131+
color: 'sidebar.foreground',
132+
},
133+
})}
134+
>
135+
{comment.references[0].metadata.path}
136+
</Link>
137+
)}
129138
<Element
130139
as="p"
131140
marginY={0}

packages/app/src/app/pages/Sandbox/Editor/Workspace/screens/Comments/Dialog/Markdown/Code.tsx

Lines changed: 55 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -2,50 +2,61 @@ import React from 'react';
22
import Highlight, { defaultProps } from 'prism-react-renderer';
33
import { Element } from '@codesandbox/components';
44
import css from '@styled-system/css';
5-
import nightOwlLight from 'prism-react-renderer/themes/nightOwlLight';
6-
7-
import nightOwl from 'prism-react-renderer/themes/nightOwl';
5+
import { useOvermind } from 'app/overmind';
86
import { withTheme } from 'styled-components';
7+
import { makeTheme } from './makeTheme/index';
8+
9+
export const Code = withTheme(({ value, language, theme }) => {
10+
const { state } = useOvermind();
911

10-
export const Code = withTheme(({ value, language, theme }) => (
11-
<>
12-
{value ? (
13-
<Highlight
14-
{...defaultProps}
15-
code={value}
16-
language={language || 'js'}
17-
theme={theme.vscodeTheme.type === 'dark' ? nightOwl : nightOwlLight}
18-
>
19-
{({ className, style, tokens, getLineProps, getTokenProps }) => (
20-
<Element
21-
as="pre"
22-
paddingX={4}
23-
paddingY={2}
24-
marginY={2}
25-
className={className}
26-
style={style}
27-
css={css({
28-
fontSize: 3,
29-
whiteSpace: 'pre-wrap',
30-
maxHeight: 400,
31-
overflow: 'scroll',
32-
fontFamily: "'dm', menlo, monospace",
12+
const defaultLanguage = () => {
13+
const template = state.editor.currentSandbox.template;
14+
if (template === 'create-react-app') {
15+
return 'jsx';
16+
}
17+
return 'js';
18+
};
19+
return (
20+
<>
21+
{value ? (
22+
<Highlight
23+
{...defaultProps}
24+
code={value}
25+
language={language || defaultLanguage()}
26+
// @ts-ignore
27+
theme={makeTheme(theme.vscodeTheme)}
28+
>
29+
{({ className, style, tokens, getLineProps, getTokenProps }) => (
30+
<Element
31+
as="pre"
32+
paddingX={4}
33+
paddingY={2}
34+
marginY={2}
35+
className={className}
36+
style={style}
37+
css={css({
38+
fontSize: 3,
39+
whiteSpace: 'pre-wrap',
40+
maxHeight: 400,
41+
overflow: 'scroll',
42+
fontFamily: "'dm', menlo, monospace",
3343

34-
'*': {
35-
wordBreak: 'break-all',
36-
},
37-
})}
38-
>
39-
{tokens.map((line, i) => (
40-
<Element {...getLineProps({ line, key: i })}>
41-
{line.map((token, key) => (
42-
<Element as="span" {...getTokenProps({ token, key })} />
43-
))}
44-
</Element>
45-
))}
46-
</Element>
47-
)}
48-
</Highlight>
49-
) : null}
50-
</>
51-
));
44+
'*': {
45+
wordBreak: 'break-all',
46+
},
47+
})}
48+
>
49+
{tokens.map((line, i) => (
50+
<Element {...getLineProps({ line, key: i })}>
51+
{line.map((token, key) => (
52+
<Element as="span" {...getTokenProps({ token, key })} />
53+
))}
54+
</Element>
55+
))}
56+
</Element>
57+
)}
58+
</Highlight>
59+
) : null}
60+
</>
61+
);
62+
});
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { mapScope } from './scopeMapper';
2+
import { getScoreForScope } from './scopeScore';
3+
import { transformSettings } from './transformSettings';
4+
import { minify } from './minify';
5+
6+
export const collectAllSettings = tokenColors => {
7+
const output = {};
8+
9+
tokenColors.forEach(({ scope, settings }) => {
10+
// We only care about colouring here
11+
if (!settings.foreground && !settings.fontStyle) {
12+
return;
13+
}
14+
15+
const normScope = typeof scope === 'string' ? [scope] : scope;
16+
// Return when no input scopes are present
17+
if (!normScope || !normScope.length) {
18+
return;
19+
}
20+
21+
normScope.forEach(scopeName => {
22+
const mappedScope = mapScope(scopeName);
23+
// Return when no mapping scope has been returned
24+
if (!mappedScope) {
25+
return;
26+
}
27+
28+
if (output[mappedScope] === undefined) {
29+
output[mappedScope] = [];
30+
}
31+
32+
output[mappedScope].push({
33+
scope: scopeName,
34+
settings,
35+
});
36+
});
37+
});
38+
39+
const styles = Object.keys(output).map(mappedScope => {
40+
const matchesArr = output[mappedScope];
41+
42+
// Get score for each match
43+
const scored = matchesArr.map(match => {
44+
const score = getScoreForScope(match.scope, mappedScope);
45+
46+
return {
47+
score,
48+
scope: mappedScope,
49+
settings: transformSettings(match.settings),
50+
};
51+
});
52+
53+
// Sort by score asc
54+
const sorted = scored.sort((a, b) => b.score - a.score);
55+
56+
// Return highest-scored one
57+
return sorted[0];
58+
});
59+
60+
const themeStyles = minify(styles);
61+
62+
return {
63+
styles: themeStyles,
64+
};
65+
};
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { collectAllSettings } from './collectStyles';
2+
3+
export const makeTheme = theme => {
4+
const prismTheme = collectAllSettings(theme.tokenColors);
5+
6+
const json = {
7+
plain: {
8+
color: theme.colors['editor.foreground'],
9+
backgroundColor: theme.colors['editor.background'],
10+
},
11+
...prismTheme,
12+
};
13+
14+
return json;
15+
};
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import isEqual from 'lodash-es/isEqual';
2+
3+
export const minify = styles => {
4+
const output = [];
5+
6+
styles.forEach(style => {
7+
const item = output.find(x => isEqual(style.settings, x.style));
8+
9+
if (!item) {
10+
output.push({
11+
types: [style.scope],
12+
style: style.settings,
13+
});
14+
} else {
15+
item.types.push(style.scope);
16+
}
17+
});
18+
19+
return output;
20+
};
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
const scopeMap = {
2+
comment: 'comment',
3+
punctuation: 'punctuation',
4+
string: 'string',
5+
variable: 'variable',
6+
constant: 'constant',
7+
header: 'prolog',
8+
'support.function.magic': 'constant',
9+
'support.variable': 'constant',
10+
'entity.name.type.namespace': 'namespace',
11+
'keyword.operator': 'operator',
12+
'constant.numeric': 'number',
13+
'constant.character.numeric': 'number',
14+
'support.type.vendor.property-name': 'property',
15+
'support.type.property-name': 'property',
16+
'meta.property-list': 'property',
17+
'entity.name.tag': 'tag',
18+
'entity.name.function': 'function',
19+
'entity.name.class': 'class-name',
20+
'entity.name.tag.doctype': 'doctype',
21+
'meta.selector': 'selector',
22+
'entity.other.attribute-name': 'attr-name',
23+
'meta.attribute-selector': 'attr-name',
24+
'constant.other': 'constant',
25+
'constant.other.symbol': 'symbol',
26+
'constant.language.boolean': 'boolean',
27+
'constant.character': 'char',
28+
'meta.tag.html': 'tag',
29+
'meta.tag.js': 'tag',
30+
'support.function': 'builtin',
31+
'variable.other.constant': 'builtin',
32+
'constant.language': 'builtin',
33+
'keyword.control': 'keyword',
34+
'keyword.other': 'keyword',
35+
'variable.parameter.url': 'url',
36+
'meta.at-rule': 'at-rule',
37+
'source.css.scss': 'at-rule',
38+
'markup.inserted': 'inserted',
39+
'markup.deleted': 'deleted',
40+
'markup.changed': 'changed',
41+
};
42+
43+
export const mapScope = scope => {
44+
// If the scope includes a whitespace, it's a specific
45+
// type that we don't support
46+
if (scope.includes(' ')) {
47+
return undefined;
48+
}
49+
50+
const scopeAccess = scope.split('.');
51+
52+
for (let i = scopeAccess.length; i >= 0; i--) {
53+
const searchScope = scopeAccess.slice(0, i).join('.');
54+
const outputScope = scopeMap[searchScope];
55+
if (outputScope !== undefined) {
56+
return outputScope;
57+
}
58+
}
59+
60+
return undefined;
61+
};
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
const scorePerScope = {
2+
builtin: ['variable.other.constant', 'constant.language'],
3+
punctuation: ['punctuation.accessor'],
4+
tag: ['meta.tag.html', 'entity.name.tag'],
5+
};
6+
7+
// The higher the better
8+
const score = [
9+
// These are sure matches
10+
'markup', // diffs
11+
'comment',
12+
'punctuation',
13+
'string',
14+
'variable',
15+
16+
// These are more "meta" scopes
17+
'meta', // good guesses
18+
'entity',
19+
'constant',
20+
'support',
21+
'variable',
22+
];
23+
24+
const baseScoreSize = score.length;
25+
26+
export const getScoreForScope = (scope, mappedScope) => {
27+
// Get scores for specific mapped scopes first
28+
const scoreForMapped = scorePerScope[mappedScope];
29+
if (scoreForMapped) {
30+
// If the scope is in the specific mapped scope we add the baseScoreSize to this
31+
// score
32+
const mappedIndex = scoreForMapped.findIndex(x => scope.startsWith(x));
33+
if (mappedIndex !== -1) {
34+
return baseScoreSize + (scoreForMapped.length - mappedIndex);
35+
}
36+
}
37+
38+
const parentScope = scope.split('.')[0];
39+
const index = score.indexOf(parentScope);
40+
41+
if (index === -1) {
42+
// Otherwise it's a negative score based on length
43+
return -1 * scope.length;
44+
}
45+
46+
// If it's found we return the score from the main `score` arr
47+
return baseScoreSize - index;
48+
};
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
type Output = {
2+
color?: string;
3+
backgroundColor?: string;
4+
fontStyle?: string;
5+
};
6+
7+
export const transformSettings = settings => {
8+
const output: Output = {};
9+
10+
if (settings.foreground) {
11+
output.color = settings.foreground.toString();
12+
}
13+
14+
if (settings.background) {
15+
output.backgroundColor = settings.background.toString();
16+
}
17+
18+
if (settings.fontStyle === 'italic') {
19+
output.fontStyle = 'italic';
20+
}
21+
22+
return output;
23+
};

0 commit comments

Comments
 (0)