Skip to content

Commit 8ab6646

Browse files
replay changes from dialog branch (#3611)
* replay changes * fix ts Co-authored-by: Sara Vieira <hey@iamsaravieira.com>
1 parent 882f45e commit 8ab6646

File tree

14 files changed

+466
-21
lines changed

14 files changed

+466
-21
lines changed

packages/app/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
"posthtml": "^0.11.3",
179179
"posthtml-parser": "^0.4.1",
180180
"posthtml-render": "^1.1.0",
181+
"prism-react-renderer": "^1.0.2",
181182
"punycode": "^2.1.1",
182183
"qrcode.react": "^0.8.0",
183184
"qs": "^6.5.0",
@@ -200,6 +201,7 @@
200201
"react-inspector": "^2.2.0",
201202
"react-instantsearch": "^5.7.0",
202203
"react-loadable": "^3.3.1",
204+
"react-markdown": "^4.3.1",
203205
"react-media": "^1.9.2",
204206
"react-modal": "^3.6.1",
205207
"react-motion": "^0.5.0",

packages/app/src/app/overmind/effects/fakeGql/comments/mutations.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,30 @@ export const updateComment: Query<any, any> = gql`
5151
}
5252
}
5353
`;
54+
55+
export const reply: Query<any, any> = gql`
56+
mutation replyToComment(
57+
$id: String!
58+
$comment: String!
59+
$username: String!
60+
$metadata: String
61+
) {
62+
addReply(
63+
id: $id
64+
comment: $comment
65+
username: $username
66+
metadata: $metadata
67+
) {
68+
id
69+
replies {
70+
id
71+
content
72+
author {
73+
id
74+
avatarUrl
75+
username
76+
}
77+
}
78+
}
79+
}
80+
`;

packages/app/src/app/overmind/effects/fakeGql/comments/queries.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,11 @@ export const allComments: Query<CommentsResponse, CommentsVariables> = gql`
2424
}
2525
replies {
2626
id
27+
content
28+
author {
29+
avatarUrl
30+
username
31+
}
2732
}
2833
insertedAt
2934
updatedAt

packages/app/src/app/overmind/namespaces/editor/actions.ts

Lines changed: 59 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1399,7 +1399,11 @@ export const addComment: AsyncAction<{
13991399
comment: string;
14001400
sandboxId: string;
14011401
username: string;
1402-
}> = async ({ state, effects }, { sandboxId, comment, username }) => {
1402+
open?: boolean;
1403+
}> = async (
1404+
{ state, effects, actions },
1405+
{ sandboxId, comment, username, open }
1406+
) => {
14031407
if (!state.user) {
14041408
return;
14051409
}
@@ -1434,6 +1438,9 @@ export const addComment: AsyncAction<{
14341438

14351439
delete state.editor.comments[sandboxId][id];
14361440
state.editor.comments[sandboxId][newComment.id] = newComment;
1441+
if (open) {
1442+
actions.editor.getComment({ id: newComment.id, sandboxId });
1443+
}
14371444
} catch (error) {
14381445
effects.notificationToast.error(
14391446
'Unable to create your comment, please try again'
@@ -1536,3 +1543,54 @@ export const changeInvitationAuthorization: AsyncAction<{
15361543
}
15371544
}
15381545
};
1546+
1547+
export const addReply: AsyncAction<string> = async (
1548+
{ state, effects },
1549+
comment
1550+
) => {
1551+
const id = state.editor.currentCommentId;
1552+
1553+
if (
1554+
!state.editor.currentComment ||
1555+
!id ||
1556+
!state.user ||
1557+
!state.editor.currentSandbox
1558+
) {
1559+
return;
1560+
}
1561+
const sandboxId = state.editor.currentSandbox.id;
1562+
const fakeId = `${comment}-${state.user.username}`;
1563+
state.editor.comments[sandboxId][id] = {
1564+
...state.editor.currentComment,
1565+
// sorry
1566+
// @ts-ignore
1567+
replies: state.editor.currentComment.replies.concat({
1568+
id: fakeId,
1569+
content: comment,
1570+
author: {
1571+
id: state.user.id,
1572+
avatarUrl: state.user.avatarUrl,
1573+
username: state.user.username,
1574+
},
1575+
}),
1576+
};
1577+
1578+
try {
1579+
const { addReply: newReply } = await effects.fakeGql.mutations.reply({
1580+
id,
1581+
comment,
1582+
username: state.user.username,
1583+
});
1584+
state.editor.comments[sandboxId][id] = {
1585+
...state.editor.comments[sandboxId][id],
1586+
replies: state.editor.currentComment.replies
1587+
.filter(a => a.id !== fakeId)
1588+
.concat(newReply.replies[newReply.replies.length - 1]),
1589+
};
1590+
} catch (e) {
1591+
state.editor.comments[sandboxId][id] = {
1592+
...state.editor.comments[sandboxId][id],
1593+
replies: state.editor.currentComment.replies.filter(a => a.id !== fakeId),
1594+
};
1595+
}
1596+
};
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import React from 'react';
2+
import Highlight, { defaultProps } from 'prism-react-renderer';
3+
import { Element } from '@codesandbox/components';
4+
import nightOwlLight from 'prism-react-renderer/themes/nightOwlLight';
5+
6+
export const Code = props => (
7+
<>
8+
<Highlight
9+
{...defaultProps}
10+
code={props.value}
11+
language={props.language || 'js'}
12+
theme={nightOwlLight}
13+
>
14+
{({ className, style, tokens, getLineProps, getTokenProps }) => (
15+
<Element
16+
as="pre"
17+
paddingX={4}
18+
paddingY={2}
19+
marginY={2}
20+
className={className}
21+
style={style}
22+
>
23+
{tokens.map((line, i) => (
24+
<Element {...getLineProps({ line, key: i })}>
25+
{line.map((token, key) => (
26+
<Element as="span" {...getTokenProps({ token, key })} />
27+
))}
28+
</Element>
29+
))}
30+
</Element>
31+
)}
32+
</Highlight>
33+
</>
34+
);
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from 'react';
2+
import ReactMarkdown from 'react-markdown';
3+
import { Text, Element } from '@codesandbox/components';
4+
import { Code } from './Code';
5+
6+
export const Comment = ({ source }) => (
7+
<Element paddingX={4} paddingBottom={6}>
8+
<ReactMarkdown
9+
source={source}
10+
renderers={{
11+
text: ({ children }) => (
12+
<Text variant="muted" size={13}>
13+
{children}
14+
</Text>
15+
),
16+
heading: ({ children }) => (
17+
<Text variant="muted" size={13}>
18+
{children}
19+
</Text>
20+
),
21+
code: props => <Code {...props} />,
22+
}}
23+
/>
24+
</Element>
25+
);
Lines changed: 195 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,195 @@
1+
import React, { useState } from 'react';
2+
import ReactDOM from 'react-dom';
3+
import css from '@styled-system/css';
4+
import Draggable from 'react-draggable';
5+
import { ENTER } from '@codesandbox/common/lib/utils/keycodes';
6+
7+
import {
8+
Element,
9+
Stack,
10+
Avatar,
11+
Textarea,
12+
Text,
13+
IconButton,
14+
} from '@codesandbox/components';
15+
import { useOvermind } from 'app/overmind';
16+
import { Comment } from './Comment';
17+
18+
// // eslint-disable-next-line no-var
19+
// var markdown = `
20+
// I am a comment
21+
22+
// Here's that code block:
23+
24+
// \`\`\`js
25+
// const total = [1, 2, 3, 4, 5]
26+
// .map(num => num * 3)
27+
// .filter(num => num < 9)
28+
// .reduce((sum, num) => sum += num, 0)
29+
30+
// \`\`\`
31+
32+
// Neat, eh?`;
33+
34+
// const defaultComment = {
35+
// id: '5e59204cc277a40fef1e3916',
36+
// isResolved: false,
37+
// originalMessage: {
38+
// id: 'gier2bk769d03r',
39+
// content: markdown,
40+
// author: {
41+
// id: '740dca51-993d-4b0e-b8cb-0e46acada86b',
42+
// avatarUrl: 'https://avatars0.githubusercontent.com/u/1863771?v=4',
43+
// username: 'siddharthkp',
44+
// },
45+
// },
46+
// replies: [
47+
// {
48+
// id: 'a\n-SaraVieira',
49+
// content: 'A reply',
50+
// author: {
51+
// avatarUrl: 'https://avatars0.githubusercontent.com/u/1051509?v=4',
52+
// badges: [{ id: 'patron_2', name: 'Patron II', visible: true }],
53+
// curatorAt: '2018-11-25T18:51:34Z',
54+
// email: 'hey@iamsaravieira.com',
55+
// experiments: { containerLsp: null },
56+
// id: '8d35d7c1-eecb-4aad-87b0-c22d30d12081',
57+
// integrations: {
58+
// github: null,
59+
// zeit: { token: 'pqshnGwa4t3y7RxMzfHnoSW1' },
60+
// },
61+
// name: 'Sara Vieira',
62+
// sendSurvey: false,
63+
// subscription: {
64+
// amount: 10,
65+
// cancelAtPeriodEnd: false,
66+
// duration: 'monthly',
67+
// plan: 'patron',
68+
// since: '2018-03-01T16:00:18Z',
69+
// },
70+
// username: 'SaraVieira',
71+
// },
72+
// },
73+
// ],
74+
// insertedAt: '2020-02-28T14:14:36.859Z',
75+
// updatedAt: '2020-02-28T14:14:36.859Z',
76+
// };
77+
export const CommentDialog = props =>
78+
ReactDOM.createPortal(<Dialog {...props} />, document.body);
79+
80+
export const Dialog = props => {
81+
const { state, actions } = useOvermind();
82+
const [value, setValue] = useState('');
83+
const comment = state.editor.currentComment;
84+
const [position, setPosition] = React.useState({
85+
x: 200,
86+
y: 100,
87+
});
88+
89+
const closeDialog = () => actions.editor.selectComment(null);
90+
const onSubmit = () => {
91+
setValue('');
92+
if (comment) {
93+
actions.editor.addReply(value);
94+
} else {
95+
actions.editor.addComment({
96+
comment: value,
97+
sandboxId: state.editor.currentSandbox.id,
98+
username: state.user.username,
99+
open: true,
100+
});
101+
}
102+
};
103+
104+
const onDragStop = (_, data) => {
105+
setPosition({
106+
x: data.x,
107+
y: data.y,
108+
});
109+
};
110+
111+
return (
112+
<Draggable handle=".handle" position={position} onStop={onDragStop}>
113+
<Element
114+
css={css({
115+
position: 'absolute',
116+
zIndex: 2,
117+
backgroundColor: 'dialog.background',
118+
color: 'dialog.foreground',
119+
border: '1px solid',
120+
borderColor: 'dialog.border',
121+
borderRadius: 4,
122+
width: 420,
123+
height: 'auto',
124+
paddingBottom: 4,
125+
})}
126+
>
127+
<Stack direction="vertical">
128+
<Stack
129+
className="handle"
130+
justify="space-between"
131+
padding={2}
132+
paddingLeft={4}
133+
css={{ cursor: 'move' }}
134+
marginBottom={4}
135+
>
136+
<Stack align="center" gap={2}>
137+
<Avatar user={comment.originalMessage.author} />
138+
<Text size={3}>{comment.originalMessage.author.username}</Text>
139+
</Stack>
140+
141+
<Stack align="center">
142+
<IconButton
143+
name="cross"
144+
size={3}
145+
title="Close comment dialog"
146+
onClick={closeDialog}
147+
/>
148+
</Stack>
149+
</Stack>
150+
{comment && (
151+
<>
152+
<Comment source={comment.originalMessage.content} />
153+
{comment.replies.map(c => (
154+
<>
155+
<Element
156+
paddingX={4}
157+
paddingTop={6}
158+
css={css({
159+
borderTop: '1px solid',
160+
borderColor: 'sideBar.border',
161+
})}
162+
>
163+
<Stack align="center" gap={2}>
164+
<Avatar user={c.author} />
165+
<Text size={3}>{c.author.username}</Text>
166+
</Stack>
167+
</Element>
168+
<Comment source={c.content} />
169+
</>
170+
))}
171+
<Element
172+
paddingX={4}
173+
css={css({
174+
borderTop: '1px solid',
175+
borderColor: 'sideBar.border',
176+
})}
177+
>
178+
<Textarea
179+
autosize
180+
css={css({ minHeight: 8, overflow: 'hidden' })}
181+
value={value}
182+
onChange={e => setValue(e.target.value)}
183+
placeholder={comment ? 'Reply' : 'Write a comment...'}
184+
onKeyDown={event => {
185+
if (event.keyCode === ENTER && !event.shiftKey) onSubmit();
186+
}}
187+
/>
188+
</Element>
189+
</>
190+
)}
191+
</Stack>
192+
</Element>
193+
</Draggable>
194+
);
195+
};

0 commit comments

Comments
 (0)