collect values from multiple users

This commit is contained in:
Orion Reed 2024-07-19 17:04:07 +02:00
parent d34955e5dd
commit d6524330cc
5 changed files with 96 additions and 25 deletions

View File

@ -5,6 +5,7 @@ import { AgentButton } from "./components/AgentButton";
import { SocialShapeUtil } from "./SocialShapeUtil";
import { SocialShapeTool } from "./SocialShapeTool";
import { CustomToolbar, overrides } from "./ui";
import { getDocumentMeta, getUserId, getUsersInRoom, setDocumentMeta } from "./storeUtils";
const shapeUtils = [SocialShapeUtil];
const tools = [SocialShapeTool];
@ -34,6 +35,18 @@ export default function Canvas() {
onMount={(editor) => {
//@ts-ignore
editor.getStateDescendant('select.idle').handleDoubleClickOnCanvas = () => void null;
console.log(editor.store.allRecords())
const userId = getUserId(editor)
setDocumentMeta(editor, {
[userId]: 123
})
// console.log(getDocumentMeta(editor))
// removeDocumentMeta(editor, 'test')
setTimeout(() => {
console.log(getDocumentMeta(editor))
console.log(getUsersInRoom(editor))
}, 2000);
}}
components={{
SharePanel: AgentButton,

View File

@ -8,6 +8,7 @@ import {
resizeBox,
toDomPrecision,
} from 'tldraw'
import { getUserId } from './storeUtils'
export type ValueType = "scalar" | "boolean" | null
@ -19,6 +20,7 @@ export type ISocialShape = TLBaseShape<
text: string
selector: string
valueType: ValueType
values: Record<string, any>
}
>
@ -27,7 +29,7 @@ export class SocialShapeUtil extends BaseBoxShapeUtil<ISocialShape> {
override canBind = () => false
override canEdit = () => false
override getDefaultProps(): ISocialShape['props'] {
return { w: 160 * 2, h: 90 * 2, text: '', selector: '', valueType: null }
return { w: 160 * 2, h: 90 * 2, text: '', selector: '', valueType: null, values: {} }
}
override onResize: TLOnResizeHandler<ISocialShape> = (shape, info) => {
return resizeBox(shape, info)
@ -39,6 +41,7 @@ export class SocialShapeUtil extends BaseBoxShapeUtil<ISocialShape> {
isFilled: true,
})
}
indicator(shape: ISocialShape) {
const bounds = this.editor.getShapeGeometry(shape).bounds
return (
@ -50,16 +53,22 @@ export class SocialShapeUtil extends BaseBoxShapeUtil<ISocialShape> {
)
}
override component(machine: ISocialShape) {
override component(shape: ISocialShape) {
const currentUser = getUserId(this.editor)
const handleOnChange = (newValue: any) => {
this.updateProps(shape, { values: { ...shape.props.values, [currentUser]: newValue } })
console.log(shape.props.values)
}
return (
<HTMLContainer style={{ padding: 4, borderRadius: 4, border: '1px solid #ccc', pointerEvents: 'all' }}>
<textarea style={{ width: '100%', height: '100%', border: 'none', outline: 'none', resize: 'none' }} value={machine.props.text} onChange={(e) => this.updateProps(machine, { text: e.target.value })} />
<HTMLContainer style={{ padding: 4, borderRadius: 4, border: '1px solid #ccc' }} onPointerDown={(e) => e.stopPropagation()}>
<textarea style={{ width: '100%', height: '50%', border: 'none', outline: 'none', resize: 'none', pointerEvents: 'all' }} value={shape.props.text} onChange={(e) => this.updateProps(shape, { text: e.target.value })} />
<ValueInterface type='boolean' value={shape.props.values[currentUser] ?? false} values={shape.props.values} onChange={handleOnChange} />
</HTMLContainer>
)
}
private updateProps(shape: ISocialShape, props: Partial<ISocialShape['props']>) {
this.editor.updateShape<ISocialShape>({
id: shape.id,
@ -70,18 +79,23 @@ export class SocialShapeUtil extends BaseBoxShapeUtil<ISocialShape> {
},
})
}
// static removeParticipantsNotInRoom(editor: Editor, shapeId: TLShapeId) {
// const roomMembers = getRoomMembers(editor)
// const _shape = editor.getShape(shapeId)
// if (!_shape || _shape.type !== 'gmachine') return
// const shape = _shape as IGMachineShape
// const participants = new Map(shape.props.participants.map(p => [p.id, p]))
// participants.forEach((participant: any) => {
// if (!roomMembers.some(rm => rm.id === participant.id)) {
// participants.delete(participant.id)
// }
// })
// updateProps(editor, shape, { participants: Array.from(participants.values()) })
// }
}
function ValueInterface({ type, value, values, onChange }: { type: ValueType; value: any; values: Record<string, any>; onChange: (value: any) => void }) {
switch (type) {
case 'boolean':
return <>
<div style={{ display: 'flex', flexDirection: 'row', alignItems: 'center', gap: '4px' }}>
<input style={{ pointerEvents: 'all', width: '20px', height: '20px', margin: 0 }} type="checkbox" value={value} onChange={(e) => onChange(e.target.checked)} />
<div style={{ width: '1px', height: '20px', backgroundColor: 'grey' }} />
{Object.values(values).map((bool, i) => (
<div key={`boolean-${i}`} style={{ backgroundColor: bool ? 'blue' : 'white', width: '20px', height: '20px', border: '1px solid grey', borderRadius: 2 }} />
))}
</div>
</>
case 'scalar':
return <div>Slider</div>
default:
return <div>No Interface...</div>
}
}

View File

@ -1,10 +1,10 @@
import React from "react";
// import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App.tsx";
import "./style.css";
ReactDOM.createRoot(document.getElementById("root")!).render(
<React.StrictMode>
// <React.StrictMode>
<App />
</React.StrictMode>,
// </React.StrictMode>,
);

43
src/storeUtils.ts Normal file
View File

@ -0,0 +1,43 @@
import { Editor, RecordId, TLDocument } from "tldraw";
const docId = 'document:document' as RecordId<TLDocument>
export function setDocumentMeta(editor: Editor, meta: Record<string, any>) {
const updateFunc = (doc: TLDocument) => {
return {
...doc,
meta: {
...doc.meta,
...meta
}
}
}
editor.store.update(docId, updateFunc)
}
export function getDocumentMeta(editor: Editor) {
const document = editor.store.get(docId)
if (!document) return
return document.meta
}
export function removeDocumentMeta(editor: Editor, key: string) {
const updateFunc = (doc: TLDocument) => {
const { [key]: _, ...restMeta } = doc.meta;
return {
...doc,
meta: restMeta
};
};
editor.store.update(docId, updateFunc);
}
export function getUserId(editor: Editor) {
return editor.user.getId()
}
export function setUserPreferences(editor: Editor, name: string, color: string) {
editor.user.updateUserPreferences({
name,
color
})
}
export function getUsersInRoom(editor: Editor) {
return editor.getCollaborators().map(c=> c.userId)
}

View File

@ -18,7 +18,8 @@ agents: {
social shape props:
```json
function: string // e.g. "@all sum(SCALAR)"
text: string // e.g. "@all sum(SCALAR)"
selector: string // e.g. "@all"
valueType: string // e.g. "SCALAR"
values: Record<string, any>
```