Skip to content

Commit c936f66

Browse files
feat: implement collaborative code editor with real-time cursor tracking and output components
1 parent 31904ed commit c936f66

3 files changed

Lines changed: 33 additions & 36 deletions

File tree

client/src/components/Editor.jsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ const Editor = ({ socketRef, roomId, onCodeChange, onEditorClick, language }) =>
2626
if (onEditorClick) onEditorClick();
2727
});
2828

29-
editor.onDidChangeModelContent((event) => {
29+
editor.onDidChangeModelContent(() => {
3030
if (isRemoteUpdate.current) return;
3131
const code = editor.getValue();
3232
const cursor = editor.getPosition();
@@ -113,7 +113,7 @@ const Editor = ({ socketRef, roomId, onCodeChange, onEditorClick, language }) =>
113113
}
114114

115115
// Re-apply cursors
116-
Object.entries(lastCursorPositionRef.current).forEach(([socketId, { cursor, username }]) => {
116+
Object.entries(lastCursorPositionRef.current).forEach(([socketId, { cursor }]) => {
117117
if (!userColors.current[socketId]) return;
118118

119119
const model = editorRef.current.getModel();
@@ -228,7 +228,7 @@ const Editor = ({ socketRef, roomId, onCodeChange, onEditorClick, language }) =>
228228
socket.off(ACTIONS.DISCONNECTED);
229229
}
230230
};
231-
}, [socketRef.current]);
231+
}, [socketRef, roomId, onCodeChange, onEditorClick]);
232232

233233
return (
234234
<div style={{ height: '100%', width: '100%' }}>

client/src/components/Output.jsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ const Output = ({ editorRef, language, isRemoteTyping }) => {
6767
};
6868

6969
// Piston API helper
70-
export const executeCode = async (language, sourceCode) => {
70+
const executeCode = async (language, sourceCode) => {
7171
// Map moniker to Piston language
7272
const LANGUAGE_VERSIONS = {
7373
javascript: "18.15.0",

client/src/pages/EditorPage.jsx

Lines changed: 29 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ const EditorPage = () => {
3030
// But we need the language too. For now hardcode or add selector.
3131
const [language, setLanguage] = useState("javascript");
3232
const languageRef = useRef("javascript");
33-
const [socketInitialized, setSocketInitialized] = useState(false);
33+
// const [socketInitialized, setSocketInitialized] = useState(false);
3434
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
3535
const [isLangOpen, setIsLangOpen] = useState(false);
3636
const [isAboutOpen, setIsAboutOpen] = useState(false);
@@ -81,13 +81,11 @@ const EditorPage = () => {
8181
useEffect(() => {
8282
const init = () => {
8383
socketRef.current = initSocket();
84-
socketRef.current.on("connect_error", (err) => handleErrors(err));
85-
86-
function handleErrors(e) {
87-
console.log("socket error", e);
84+
socketRef.current.on("connect_error", (err) => {
85+
console.log("socket error", err);
8886
toast.error("Socket connection failed, try again later.");
8987
setIsClientsLoading(false);
90-
}
88+
});
9189

9290
socketRef.current.emit(ACTIONS.JOIN, {
9391
roomId,
@@ -113,7 +111,6 @@ const EditorPage = () => {
113111
if (socketId !== socketRef.current.id) {
114112
setIsRemoteTyping(true);
115113

116-
// Optional: Reset after 3 seconds of inactivity if they don't click
117114
if (remoteTypingTimeoutRef.current)
118115
clearTimeout(remoteTypingTimeoutRef.current);
119116
remoteTypingTimeoutRef.current = setTimeout(() => {
@@ -136,18 +133,21 @@ const EditorPage = () => {
136133
});
137134
});
138135

139-
setSocketInitialized(true);
136+
// setSocketInitialized(true);
140137
};
141-
init();
138+
if (location.state?.username) {
139+
init();
140+
}
142141
return () => {
143142
if (socketRef.current) {
144143
socketRef.current.disconnect();
145144
socketRef.current.off(ACTIONS.JOINED);
146145
socketRef.current.off(ACTIONS.DISCONNECTED);
147146
socketRef.current.off(ACTIONS.LANGUAGE_CHANGE);
147+
socketRef.current.off(ACTIONS.CODE_CHANGE);
148148
}
149149
};
150-
}, []);
150+
}, [roomId, location.state?.username]);
151151

152152
async function copyRoomId() {
153153
try {
@@ -169,37 +169,25 @@ const EditorPage = () => {
169169
clearTimeout(remoteTypingTimeoutRef.current);
170170
};
171171

172-
if (!location.state) {
173-
return <Navigate to="/" state={{roomId}} />;
174-
}
175-
176-
// Filter for unique usernames to display
177-
const uniqueClients = Array.from(new Set(clients.map((c) => c.username))).map(
178-
(username) => clients.find((c) => c.username === username),
179-
);
180-
181-
const [outputWidth, setOutputWidth] = useState(300);
182-
const isDragging = useRef(false);
183-
184-
const startResizing = (mouseDownEvent) => {
172+
const startResizing = () => {
185173
isDragging.current = true;
186174
};
187175

188176
const stopResizing = () => {
189177
isDragging.current = false;
190178
};
191179

192-
const resize = (mouseMoveEvent) => {
193-
if (isDragging.current) {
194-
// Calculate new width from the right edge of the screen
195-
const newWidth = window.innerWidth - mouseMoveEvent.clientX;
196-
if (newWidth > 100 && newWidth < window.innerWidth * 0.8) {
197-
setOutputWidth(newWidth);
180+
useEffect(() => {
181+
const resize = (mouseMoveEvent) => {
182+
if (isDragging.current) {
183+
// Calculate new width from the right edge of the screen
184+
const newWidth = window.innerWidth - mouseMoveEvent.clientX;
185+
if (newWidth > 100 && newWidth < window.innerWidth * 0.8) {
186+
setOutputWidth(newWidth);
187+
}
198188
}
199-
}
200-
};
189+
};
201190

202-
useEffect(() => {
203191
window.addEventListener("mousemove", resize);
204192
window.addEventListener("mouseup", stopResizing);
205193
return () => {
@@ -208,6 +196,15 @@ const EditorPage = () => {
208196
};
209197
}, []);
210198

199+
if (!location.state) {
200+
return <Navigate to="/" state={{roomId}} />;
201+
}
202+
203+
// Filter for unique usernames to display
204+
const uniqueClients = Array.from(new Set(clients.map((c) => c.username))).map(
205+
(username) => clients.find((c) => c.username === username),
206+
);
207+
211208
return (
212209
<div className="mainWrap">
213210
<div className="aside">

0 commit comments

Comments
 (0)