working basic live collab
This commit is contained in:
parent
a18bcf9c14
commit
17af48fe2c
3
backend/server/dist/index.js
vendored
3
backend/server/dist/index.js
vendored
@ -57,7 +57,8 @@ io.use((socket, next) => __awaiter(void 0, void 0, void 0, function* () {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const sandbox = dbUserJSON.sandbox.find((s) => s.id === sandboxId);
|
const sandbox = dbUserJSON.sandbox.find((s) => s.id === sandboxId);
|
||||||
if (!sandbox) {
|
const sharedSandboxes = dbUserJSON.usersToSandboxes.find((uts) => uts.sandboxId === sandboxId);
|
||||||
|
if (!sandbox && !sharedSandboxes) {
|
||||||
console.log("Invalid credentials.");
|
console.log("Invalid credentials.");
|
||||||
next(new Error("Invalid credentials."));
|
next(new Error("Invalid credentials."));
|
||||||
return;
|
return;
|
||||||
|
@ -63,8 +63,11 @@ io.use(async (socket, next) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const sandbox = dbUserJSON.sandbox.find((s) => s.id === sandboxId)
|
const sandbox = dbUserJSON.sandbox.find((s) => s.id === sandboxId)
|
||||||
|
const sharedSandboxes = dbUserJSON.usersToSandboxes.find(
|
||||||
|
(uts) => uts.sandboxId === sandboxId
|
||||||
|
)
|
||||||
|
|
||||||
if (!sandbox) {
|
if (!sandbox && !sharedSandboxes) {
|
||||||
console.log("Invalid credentials.")
|
console.log("Invalid credentials.")
|
||||||
next(new Error("Invalid credentials."))
|
next(new Error("Invalid credentials."))
|
||||||
return
|
return
|
||||||
|
@ -106,4 +106,39 @@
|
|||||||
padding: 2px 4px;
|
padding: 2px 4px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
margin-left: 56px;
|
margin-left: 56px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.yRemoteSelection {
|
||||||
|
opacity: 0.5;
|
||||||
|
background-color: var(--user-color);
|
||||||
|
margin-right: -1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cursor caret */
|
||||||
|
.yRemoteSelectionHead {
|
||||||
|
position: absolute;
|
||||||
|
box-sizing: border-box;
|
||||||
|
height: 100%;
|
||||||
|
border-left: 2px solid var(--user-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cursor name */
|
||||||
|
.yRemoteSelectionHead::after {
|
||||||
|
position: absolute;
|
||||||
|
top: -1.4em;
|
||||||
|
left: -2px;
|
||||||
|
padding: 2px 6px;
|
||||||
|
background: var(--user-color);
|
||||||
|
color: #fff;
|
||||||
|
border: 0;
|
||||||
|
border-radius: 6px;
|
||||||
|
border-bottom-left-radius: 0;
|
||||||
|
line-height: normal;
|
||||||
|
white-space: nowrap;
|
||||||
|
font-size: 14px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 600;
|
||||||
|
pointer-events: none;
|
||||||
|
user-select: none;
|
||||||
|
z-index: 1000;
|
||||||
}
|
}
|
@ -42,7 +42,6 @@ import { TFile, TFileData, TFolder, TTab } from "./sidebar/types"
|
|||||||
import { User } from "@/lib/types"
|
import { User } from "@/lib/types"
|
||||||
import { processFileType, validateName } from "@/lib/utils"
|
import { processFileType, validateName } from "@/lib/utils"
|
||||||
import { Cursors } from "./live/cursors"
|
import { Cursors } from "./live/cursors"
|
||||||
import { Avatars } from "./live/avatars"
|
|
||||||
|
|
||||||
export default function CodeEditor({
|
export default function CodeEditor({
|
||||||
userData,
|
userData,
|
||||||
@ -271,26 +270,31 @@ export default function CodeEditor({
|
|||||||
})
|
})
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!editorRef.current) return
|
let yProvider: any
|
||||||
|
let yDoc: Y.Doc
|
||||||
|
let binding: MonacoBinding
|
||||||
|
|
||||||
const yDoc = new Y.Doc()
|
if (editorRef.current) {
|
||||||
const yText = yDoc.getText("monaco")
|
yDoc = new Y.Doc()
|
||||||
const yProvider: any = new LiveblocksProvider(room, yDoc)
|
const yText = yDoc.getText("monaco")
|
||||||
setProvider(yProvider)
|
yProvider = new LiveblocksProvider(room, yDoc)
|
||||||
|
setProvider(yProvider)
|
||||||
|
|
||||||
const binding = new MonacoBinding(
|
// Attach Yjs to Monaco
|
||||||
yText,
|
binding = new MonacoBinding(
|
||||||
editorRef.current.getModel() as monaco.editor.ITextModel,
|
yText,
|
||||||
new Set([editorRef.current]),
|
editorRef.current.getModel() as monaco.editor.ITextModel,
|
||||||
yProvider.awareness as Awareness
|
new Set([editorRef.current]),
|
||||||
)
|
yProvider.awareness as Awareness
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
yDoc.destroy()
|
yDoc?.destroy()
|
||||||
yProvider.destroy()
|
yProvider?.destroy()
|
||||||
binding.destroy()
|
binding?.destroy()
|
||||||
}
|
}
|
||||||
}, [editorRef, room])
|
}, [editorRef.current, room])
|
||||||
|
|
||||||
// connection/disconnection effect + resizeobserver
|
// connection/disconnection effect + resizeobserver
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -490,7 +494,6 @@ export default function CodeEditor({
|
|||||||
{tab.name}
|
{tab.name}
|
||||||
</Tab>
|
</Tab>
|
||||||
))}
|
))}
|
||||||
<Avatars />
|
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
ref={editorContainerRef}
|
ref={editorContainerRef}
|
||||||
|
@ -19,6 +19,7 @@ export function Cursors({ yProvider }: { yProvider: TypedLiveblocksProvider }) {
|
|||||||
|
|
||||||
// On changes, update `awarenessUsers`
|
// On changes, update `awarenessUsers`
|
||||||
function setUsers() {
|
function setUsers() {
|
||||||
|
console.log("SET USERS")
|
||||||
setAwarenessUsers(
|
setAwarenessUsers(
|
||||||
Array.from(yProvider.awareness.getStates()) as AwarenessList
|
Array.from(yProvider.awareness.getStates()) as AwarenessList
|
||||||
)
|
)
|
||||||
|
@ -10,6 +10,7 @@ import { Button } from "@/components/ui/button"
|
|||||||
import { useState } from "react"
|
import { useState } from "react"
|
||||||
import EditSandboxModal from "./edit"
|
import EditSandboxModal from "./edit"
|
||||||
import ShareSandboxModal from "./share"
|
import ShareSandboxModal from "./share"
|
||||||
|
import { Avatars } from "../live/avatars"
|
||||||
|
|
||||||
export default function Navbar({
|
export default function Navbar({
|
||||||
userData,
|
userData,
|
||||||
@ -58,6 +59,8 @@ export default function Navbar({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center space-x-4">
|
<div className="flex items-center space-x-4">
|
||||||
|
<Avatars />
|
||||||
|
|
||||||
<Button variant="outline" onClick={() => setIsShareOpen(true)}>
|
<Button variant="outline" onClick={() => setIsShareOpen(true)}>
|
||||||
<Users className="w-4 h-4 mr-2" />
|
<Users className="w-4 h-4 mr-2" />
|
||||||
Share
|
Share
|
||||||
|
Loading…
x
Reference in New Issue
Block a user