vzcode 0.20.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{index-0053b846.css → index-1547f7b8.css} +1 -1
- package/dist/assets/{index-12dbf516.js → index-37015623.js} +48 -48
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/src/client/App.tsx +4 -0
- package/src/client/CodeEditor/json1PresenceBroadcast.js +2 -0
- package/src/client/CodeEditor/json1PresenceDisplay.js +45 -1
- package/src/client/PresenceNotifications/index.tsx +128 -0
- package/src/client/PresenceNotifications/style.scss +17 -0
- package/src/client/Settings.tsx +11 -1
- package/src/client/Sidebar/FileListing.tsx +1 -0
package/dist/index.html
CHANGED
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
href="https://unpkg.com/bootstrap@5.3.0/dist/css/bootstrap.min.css"
|
|
29
29
|
rel="stylesheet"
|
|
30
30
|
/>
|
|
31
|
-
<script type="module" crossorigin src="/assets/index-
|
|
32
|
-
<link rel="stylesheet" href="/assets/index-
|
|
31
|
+
<script type="module" crossorigin src="/assets/index-37015623.js"></script>
|
|
32
|
+
<link rel="stylesheet" href="/assets/index-1547f7b8.css">
|
|
33
33
|
</head>
|
|
34
34
|
<body>
|
|
35
35
|
<div id="root"></div>
|
package/package.json
CHANGED
package/src/client/App.tsx
CHANGED
|
@@ -28,6 +28,7 @@ import { usePrettier } from './usePrettier';
|
|
|
28
28
|
import PrettierWorker from './usePrettier/worker?worker';
|
|
29
29
|
import { SplitPaneResizeProvider } from './SplitPaneResizeContext';
|
|
30
30
|
import { Resizer } from './Resizer';
|
|
31
|
+
import { PresenceNotifications } from './PresenceNotifications';
|
|
31
32
|
import './style.scss';
|
|
32
33
|
|
|
33
34
|
// Instantiate the Prettier worker.
|
|
@@ -307,6 +308,9 @@ function App() {
|
|
|
307
308
|
editorCache={editorCache}
|
|
308
309
|
/>
|
|
309
310
|
) : null}
|
|
311
|
+
<PresenceNotifications
|
|
312
|
+
docPresence={docPresence}
|
|
313
|
+
/>
|
|
310
314
|
</div>
|
|
311
315
|
<Resizer />
|
|
312
316
|
</div>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { EditorView } from 'codemirror';
|
|
2
|
+
import { username } from '../Settings.tsx';
|
|
2
3
|
|
|
3
4
|
// Deals with broadcasting changes in cursor location and selection.
|
|
4
5
|
export const json1PresenceBroadcast = ({
|
|
@@ -22,6 +23,7 @@ export const json1PresenceBroadcast = ({
|
|
|
22
23
|
const presence = {
|
|
23
24
|
start: [...path, from],
|
|
24
25
|
end: [...path, to],
|
|
26
|
+
username: username,
|
|
25
27
|
};
|
|
26
28
|
|
|
27
29
|
// Broadcast presence to remote clients!
|
|
@@ -32,13 +32,16 @@ export const json1PresenceDisplay = ({
|
|
|
32
32
|
// Receive remote presence changes.
|
|
33
33
|
docPresence.on('receive', (id, presence) => {
|
|
34
34
|
// If presence === null, the user has disconnected / exited
|
|
35
|
+
// notification(presence);
|
|
36
|
+
// console.log('docPresence in presenceDisplay:',docPresence);
|
|
37
|
+
// console.log('presence in presenceDisplay:', presence);
|
|
38
|
+
|
|
35
39
|
// We also check if the presence is for the current file or not.
|
|
36
40
|
if (presence && pathMatches(path, presence)) {
|
|
37
41
|
presenceState[id] = presence;
|
|
38
42
|
} else {
|
|
39
43
|
delete presenceState[id];
|
|
40
44
|
}
|
|
41
|
-
|
|
42
45
|
// Update decorations to reflect new presence state.
|
|
43
46
|
// TODO consider mutating this rather than recomputing it on each change.
|
|
44
47
|
this.decorations = Decoration.set(
|
|
@@ -99,6 +102,47 @@ export const json1PresenceDisplay = ({
|
|
|
99
102
|
presenceTheme,
|
|
100
103
|
];
|
|
101
104
|
|
|
105
|
+
// const notification = (presence) => {
|
|
106
|
+
// const notif = document.createElement('div');
|
|
107
|
+
// notif.className = 'notification-presence';
|
|
108
|
+
// if (presence === null){
|
|
109
|
+
// notif.textContent = 'User asdfgasdfgasdfg left the collaboration session.';
|
|
110
|
+
// notif.style.display = 'block';
|
|
111
|
+
// }
|
|
112
|
+
// // The following causes the popup to show every time the remote cursor moves
|
|
113
|
+
// // to a different location on the file and not when the user first joins
|
|
114
|
+
// // else {
|
|
115
|
+
// // notif.textContent = presence + 'joined the collaboration session.';
|
|
116
|
+
// // notif.style.display = 'block';
|
|
117
|
+
// // }
|
|
118
|
+
// document.body.appendChild(notif);
|
|
119
|
+
|
|
120
|
+
// const notifStyle = document.createElement('style');
|
|
121
|
+
// notifStyle.innerText = `
|
|
122
|
+
// .notification-presence {
|
|
123
|
+
// position: fixed;
|
|
124
|
+
// display: none;
|
|
125
|
+
// bottom: 20px;
|
|
126
|
+
// right: 20px;
|
|
127
|
+
// max-width: 300px;
|
|
128
|
+
// overflow-x: hidden;
|
|
129
|
+
// white-space: nowrap;
|
|
130
|
+
// background-color: rgb(54, 65, 89);
|
|
131
|
+
// color: rgb(154, 160, 172);
|
|
132
|
+
// padding: 15px;
|
|
133
|
+
// }
|
|
134
|
+
// .notification-presence:hover {
|
|
135
|
+
// overflow-x: auto;
|
|
136
|
+
// }`;
|
|
137
|
+
// document.head.appendChild(notifStyle);
|
|
138
|
+
|
|
139
|
+
// setTimeout(() => {
|
|
140
|
+
// notif.style.display = 'none';
|
|
141
|
+
// }, 10000);
|
|
142
|
+
|
|
143
|
+
// return notif;
|
|
144
|
+
// };
|
|
145
|
+
|
|
102
146
|
const presenceAnnotation = Annotation.define();
|
|
103
147
|
|
|
104
148
|
// Checks that the path of this file
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react';
|
|
2
|
+
import './style.scss';
|
|
3
|
+
|
|
4
|
+
// A presence notification is a message that is displayed when a user joins or leaves a session.
|
|
5
|
+
// It has the following properties:
|
|
6
|
+
// - `user` is the username of the user who joined or left the session.
|
|
7
|
+
// - `join` is a boolean value that indicates whether the user joined or left the session.
|
|
8
|
+
// - `true` means user has joined the session.
|
|
9
|
+
// - `false` means user has left the session.
|
|
10
|
+
type PresenceNotification = {
|
|
11
|
+
user: string;
|
|
12
|
+
join: boolean;
|
|
13
|
+
presenceId: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const PresenceNotifications = ({
|
|
17
|
+
docPresence,
|
|
18
|
+
}: {
|
|
19
|
+
docPresence?: any;
|
|
20
|
+
}) => {
|
|
21
|
+
const [presenceNotifications, setPresenceNotifications] =
|
|
22
|
+
useState<Array<PresenceNotification>>([]);
|
|
23
|
+
|
|
24
|
+
// // console.log('docPresence:', docPresence);
|
|
25
|
+
// const [visible, setVisible] = useState(true);
|
|
26
|
+
// const [user, setUser] = useState('');
|
|
27
|
+
|
|
28
|
+
// // `true` means user has joined the session.
|
|
29
|
+
// // `false` means user has left the session.
|
|
30
|
+
// const [join, setJoin] = useState<boolean>(true);
|
|
31
|
+
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
// console.log('useEffect triggered.');
|
|
34
|
+
if (docPresence) {
|
|
35
|
+
// See https://share.github.io/sharedb/presence
|
|
36
|
+
docPresence.on('receive', (presenceId, update) => {
|
|
37
|
+
// TODO figure out how to get username from `presenceId`.
|
|
38
|
+
const user = 'someone';
|
|
39
|
+
|
|
40
|
+
// `true` means user has joined the session.
|
|
41
|
+
// `false` means user has left the session.
|
|
42
|
+
const join = update === null;
|
|
43
|
+
|
|
44
|
+
// Add an entry to the presence notifications array.
|
|
45
|
+
setPresenceNotifications((prev) => [
|
|
46
|
+
...prev,
|
|
47
|
+
{ user, join, presenceId },
|
|
48
|
+
]);
|
|
49
|
+
|
|
50
|
+
// Remove it after 5 seconds.
|
|
51
|
+
setTimeout(() => {
|
|
52
|
+
setPresenceNotifications((prev) =>
|
|
53
|
+
prev.filter(
|
|
54
|
+
(notification) =>
|
|
55
|
+
notification.presenceId !== presenceId,
|
|
56
|
+
),
|
|
57
|
+
);
|
|
58
|
+
}, 5000);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
// console.log('inside if of useEffect.');
|
|
62
|
+
// docPresence.on('receive', (presence) => {
|
|
63
|
+
// console.log('presence', presence);
|
|
64
|
+
|
|
65
|
+
// // Add an entry to the presence notifications array.
|
|
66
|
+
// setPresenceNotifications((prev) => [
|
|
67
|
+
// ...prev,
|
|
68
|
+
// { user: presence.username, join: presence === null },
|
|
69
|
+
// ]);
|
|
70
|
+
|
|
71
|
+
// console.log('receive triggered.');
|
|
72
|
+
// if (presence === null) {
|
|
73
|
+
// setJoin(false);
|
|
74
|
+
// }
|
|
75
|
+
// const { username } = presence;
|
|
76
|
+
// setUser(username);
|
|
77
|
+
// });
|
|
78
|
+
|
|
79
|
+
// const timer = setTimeout(() => {
|
|
80
|
+
// setVisible(false);
|
|
81
|
+
// }, 10000);
|
|
82
|
+
return () => {
|
|
83
|
+
// clearTimeout(timer);
|
|
84
|
+
};
|
|
85
|
+
} else {
|
|
86
|
+
// setVisible(false);
|
|
87
|
+
}
|
|
88
|
+
}, [docPresence]);
|
|
89
|
+
|
|
90
|
+
console.log(
|
|
91
|
+
'presenceNotifications',
|
|
92
|
+
presenceNotifications,
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return presenceNotifications.length > 0 ? (
|
|
96
|
+
<div className="vz-notification">
|
|
97
|
+
{presenceNotifications.map((notification) => {
|
|
98
|
+
const { user, join } = notification;
|
|
99
|
+
return (
|
|
100
|
+
<div
|
|
101
|
+
key={notification.presenceId}
|
|
102
|
+
className="vz-notification-item"
|
|
103
|
+
>
|
|
104
|
+
{join
|
|
105
|
+
? `${user} has joined the session.`
|
|
106
|
+
: `${user} has left the session.`}
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
})}
|
|
110
|
+
</div>
|
|
111
|
+
) : null;
|
|
112
|
+
// return null;
|
|
113
|
+
|
|
114
|
+
// return (
|
|
115
|
+
// <Modal
|
|
116
|
+
// className="vz-notification"
|
|
117
|
+
// show={visible}
|
|
118
|
+
// onHide={() => setVisible(false)}
|
|
119
|
+
// animation={false}
|
|
120
|
+
// >
|
|
121
|
+
// <Modal.Body>
|
|
122
|
+
// {join
|
|
123
|
+
// ? `${user} has joined the session.`
|
|
124
|
+
// : `${user} has left the session.`}
|
|
125
|
+
// </Modal.Body>
|
|
126
|
+
// </Modal>
|
|
127
|
+
// );
|
|
128
|
+
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
.vz-notification {
|
|
2
|
+
position: fixed;
|
|
3
|
+
display: flex;
|
|
4
|
+
flex-direction: column;
|
|
5
|
+
gap: 10px;
|
|
6
|
+
bottom: 20px;
|
|
7
|
+
right: 20px;
|
|
8
|
+
|
|
9
|
+
color: rgb(154, 160, 172);
|
|
10
|
+
padding: 15px;
|
|
11
|
+
|
|
12
|
+
.vz-notification-item {
|
|
13
|
+
background-color: rgb(54, 65, 89);
|
|
14
|
+
padding: 5px;
|
|
15
|
+
border-radius: 5px;
|
|
16
|
+
}
|
|
17
|
+
}
|
package/src/client/Settings.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useCallback } from 'react';
|
|
1
|
+
import { useCallback, useRef } from 'react';
|
|
2
2
|
import { Button, Modal, Form } from './bootstrap';
|
|
3
3
|
import Select from 'react-select';
|
|
4
4
|
import {
|
|
@@ -14,6 +14,8 @@ const saveTimes = [
|
|
|
14
14
|
{ value: 30, label: '30 seconds' },
|
|
15
15
|
];
|
|
16
16
|
|
|
17
|
+
export let username = 'Anonymous';
|
|
18
|
+
|
|
17
19
|
export const Settings = ({
|
|
18
20
|
show,
|
|
19
21
|
onClose,
|
|
@@ -43,6 +45,12 @@ export const Settings = ({
|
|
|
43
45
|
[],
|
|
44
46
|
);
|
|
45
47
|
|
|
48
|
+
const usernameRef = useRef<HTMLInputElement>(null);
|
|
49
|
+
const handleUsernameChange = () => {
|
|
50
|
+
const usernameValue = usernameRef.current?.value;
|
|
51
|
+
username = usernameValue;
|
|
52
|
+
};
|
|
53
|
+
|
|
46
54
|
return show ? (
|
|
47
55
|
<Modal
|
|
48
56
|
className="vz-settings"
|
|
@@ -58,6 +66,8 @@ export const Settings = ({
|
|
|
58
66
|
<Form.Label>Username</Form.Label>
|
|
59
67
|
<Form.Control
|
|
60
68
|
type="text"
|
|
69
|
+
ref={usernameRef}
|
|
70
|
+
onChange={handleUsernameChange}
|
|
61
71
|
placeholder="Enter username"
|
|
62
72
|
/>
|
|
63
73
|
<Form.Text className="text-muted">
|