-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #37 from SuperViz/lab
Lab
- Loading branch information
Showing
75 changed files
with
3,695 additions
and
9,093 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
name: Yjs Provider - Publish Package | ||
on: | ||
push: | ||
branches: | ||
- lab | ||
- beta | ||
- main | ||
paths: | ||
- "packages/yjs/**" | ||
- "packages/semantic-release-version-file/**" | ||
- ".github/workflows/yjs.ci.yml" | ||
jobs: | ||
package: | ||
runs-on: ubuntu-latest | ||
strategy: | ||
matrix: | ||
node-version: [20] | ||
steps: | ||
- uses: actions/checkout@v4 | ||
- name: Install pnpm | ||
uses: pnpm/action-setup@v4 | ||
with: | ||
version: 9.10.0 | ||
- name: Use Node.js ${{ matrix.node-version }} | ||
uses: actions/setup-node@v4 | ||
with: | ||
node-version: ${{ matrix.node-version }} | ||
cache: "pnpm" | ||
- name: Install dependencies | ||
run: pnpm install --no-frozen-lockfile | ||
env: | ||
NPM_CONFIG_USERCONFIG: .npmrc.ci | ||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | ||
- run: git config --global user.name SuperViz | ||
- run: git config --global user.email ci@superviz.com | ||
- name: Publish npm package | ||
run: npm whoami && pnpm run semantic-release --filter=@superviz/yjs | ||
env: | ||
NPM_CONFIG_USERCONFIG: .npmrc.ci | ||
GITHUB_TOKEN: ${{ secrets.TOKEN_GITHUB }} | ||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }} | ||
slack: | ||
needs: package | ||
name: Slack Notification | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v2 | ||
- name: Slack Notification | ||
uses: rtCamp/action-slack-notify@v2 | ||
env: | ||
SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} | ||
SLACK_ICON: https://avatars.slack-edge.com/2020-11-18/1496892993975_af721d1c045bea2d5a46_48.png | ||
MSG_MINIMAL: true | ||
SLACK_USERNAME: Deploy yjs provider version ${{ github.ref_name }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,4 +8,5 @@ export { | |
MousePointers, | ||
ParticipantType, | ||
type LauncherFacade, | ||
type Participant, | ||
} from "@superviz/sdk"; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,207 @@ | ||
/* eslint-disable @typescript-eslint/no-explicit-any */ | ||
import { v4 as generateId } from "uuid"; | ||
|
||
import { getConfig } from "../config"; | ||
|
||
import * as Y from "yjs"; | ||
import { SuperVizYjsProvider } from "@superviz/yjs"; | ||
|
||
import { MonacoBinding } from "y-monaco"; | ||
import "../styles/yjs.css"; | ||
import { | ||
Room, | ||
type LauncherFacade, | ||
type Participant, | ||
WhoIsOnline, | ||
} from "../lib/sdk"; | ||
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; | ||
import Editor from "@monaco-editor/react"; | ||
|
||
const SUPERVIZ_KEY = getConfig<string>("keys.superviz"); | ||
const SUPERVIZ_ROOM_PREFIX = getConfig<string>("roomPrefix"); | ||
|
||
const componentName = "yjs-monaco-wio"; | ||
|
||
function setStyles( | ||
states: Map<number, Record<string, any>>, | ||
ids: Set<number> | ||
): number[] { | ||
const stylesheet = document.getElementById("sv-yjs-monaco"); | ||
let styles = ""; | ||
|
||
const idsList = []; | ||
for (const [id, state] of states) { | ||
if (ids.has(id) || !state.participant) continue; | ||
idsList.push(id); | ||
|
||
styles += ` | ||
.yRemoteSelection-${id}, | ||
.yRemoteSelectionHead-${id} { | ||
--presence-color: ${state.participant.slot.color}; | ||
} | ||
.yRemoteSelectionHead-${id}:after { | ||
content: "${state.participant.name}"; | ||
--sv-text-color: ${state.participant.slot.textColor}; | ||
} | ||
`; | ||
} | ||
|
||
stylesheet!.innerText = styles; | ||
|
||
return idsList; | ||
} | ||
|
||
export function YjsMonacoWio() { | ||
const ydoc = useMemo(() => new Y.Doc(), []); | ||
|
||
const [editor, setEditor] = useState<any>(null); | ||
const [localParticipant, setLocalParticipant] = | ||
useState<Partial<Participant>>(); | ||
const [ids, setIds] = useState(new Set<number>()); | ||
const [joinedRoom, setJoinedRoom] = useState(false); | ||
|
||
const room = useRef<LauncherFacade>(); | ||
const provider = useMemo<SuperVizYjsProvider>( | ||
() => new SuperVizYjsProvider(ydoc), | ||
[ydoc] | ||
); | ||
const wio = useRef<WhoIsOnline>(); | ||
const loaded = useRef(false); | ||
|
||
const initializeSuperViz = useCallback(async () => { | ||
if (loaded.current) return; | ||
loaded.current = true; | ||
|
||
const uuid = generateId(); | ||
|
||
room.current = await Room(SUPERVIZ_KEY, { | ||
roomId: `${SUPERVIZ_ROOM_PREFIX}-${componentName}`, | ||
participant: { | ||
name: "Participant", | ||
id: uuid, | ||
}, | ||
group: { | ||
name: SUPERVIZ_ROOM_PREFIX, | ||
id: SUPERVIZ_ROOM_PREFIX, | ||
}, | ||
environment: "dev", | ||
debug: true, | ||
}); | ||
|
||
wio.current = new WhoIsOnline(); | ||
|
||
room.current.subscribe("participant.updated", (data) => { | ||
if (!data.slot?.index) return; | ||
|
||
provider.awareness?.setLocalStateField("participant", { | ||
id: data.id, | ||
slot: data.slot, | ||
name: data.name, | ||
}); | ||
|
||
setLocalParticipant({ | ||
id: data.id, | ||
slot: data.slot, | ||
name: data.name, | ||
}); | ||
}); | ||
|
||
const style = document.createElement("style"); | ||
style.id = "sv-yjs-monaco"; | ||
document.head.appendChild(style); | ||
}, [provider.awareness]); | ||
|
||
useEffect(() => { | ||
initializeSuperViz(); | ||
|
||
return () => { | ||
room.current?.removeComponent(wio.current); | ||
room.current?.removeComponent(provider); | ||
room.current?.destroy(); | ||
}; | ||
}, []); | ||
|
||
const joinRoom = useCallback(() => { | ||
if (joinedRoom || !room.current) return; | ||
setJoinedRoom(true); | ||
|
||
if (localParticipant) { | ||
provider.awareness?.setLocalStateField("participant", localParticipant); | ||
} | ||
|
||
const updateStyles = () => { | ||
const states = provider.awareness?.getStates(); | ||
const idsList = setStyles(states, ids); | ||
|
||
setIds(new Set(idsList)); | ||
}; | ||
|
||
provider.on("connect", updateStyles); | ||
provider.awareness?.on("update", updateStyles); | ||
provider.awareness?.once("change", updateStyles); | ||
|
||
room.current.addComponent(provider); | ||
room.current.addComponent(wio.current); | ||
}, [room, joinedRoom, setIds, ids, localParticipant, provider]); | ||
|
||
const leaveRoom = useCallback(() => { | ||
if (!joinedRoom || !room.current) return; | ||
setJoinedRoom(false); | ||
|
||
setIds(new Set()); | ||
room.current.removeComponent(wio.current); | ||
room.current.removeComponent(provider); | ||
}, [room, joinedRoom, provider]); | ||
|
||
useEffect(() => { | ||
if (!provider || editor == null) return; | ||
|
||
const binding = new MonacoBinding( | ||
ydoc.getText("monaco"), | ||
editor.getModel()!, | ||
new Set([editor]), | ||
provider.awareness | ||
); | ||
return () => { | ||
binding.destroy(); | ||
}; | ||
}, [ydoc, provider, editor]); | ||
|
||
return ( | ||
<div className="p-5 h-full bg-gray-200 flex flex-col gap-5"> | ||
<div className="flex items-center w-full justify-center gap-10"> | ||
<button | ||
onClick={joinRoom} | ||
disabled={joinedRoom || !room} | ||
className="bg-sv-purple text-white h-10 px-4 rounded-md hover:bg-sv-primary-900 transition-all duration-300 disabled:bg-sv-primary-200 disabled:cursor-not-allowed" | ||
> | ||
Join room | ||
</button> | ||
<button | ||
onClick={leaveRoom} | ||
disabled={!joinedRoom || !room} | ||
className="text-sv-gray-400 border-sv-gray-400 border h-10 px-4 rounded-md hover:bg-sv-gray-400 hover:text-white transition-all duration-300 cursor-pointer disabled:bg-sv-gray-100 disabled:cursor-not-allowed disabled:text-sv-gray-400" | ||
> | ||
Leave room | ||
</button> | ||
</div> | ||
<div className="bg-[#1e1e1e] shadow-none h-[90%] overflow-auto rounded-sm"> | ||
<div className="yRemoteSelectionHead"></div> | ||
<Editor | ||
defaultValue="// Connect to the room to start collaborating" | ||
defaultLanguage="typescript" | ||
onMount={(editor) => { | ||
setEditor(editor); | ||
}} | ||
options={{ | ||
padding: { | ||
top: 32, | ||
}, | ||
}} | ||
theme="vs-dark" | ||
/> | ||
</div> | ||
</div> | ||
); | ||
} |
Oops, something went wrong.