App.res
1%%raw("import 'maplibre-gl/dist/maplibre-gl.css';")
2open Preact
3
4let minimized = Signal.make(false)
5let onMinimize = () => {
6 minimized->Signal.set(true)
7}
8let onOpen = () => {
9 minimized->Signal.set(false)
10}
11
12// BaseUI renders portals to this root in an isolated context
13module BaseUIRoot = {
14 @jsx.component
15 let make = (~children: option<Jsx.element>=?) => {
16 <div className="root"> {children->Option.getOr(<> </>)} </div>
17 }
18}
19let root = <BaseUIRoot />
20
21{
22 let doc = Obj.magic(WebAPI.Global.document)
23
24 let handleConnectionStatus = (rawEvent: {..}) => {
25 let status: string = Obj.magic(rawEvent["detail"])
26 switch status {
27 | "offline" | "error" => Signal.set(State.ysweetStatus, Offline)
28 | "connecting" | "handshaking" => Signal.set(State.ysweetStatus, Connecting)
29 | "connected" => Signal.set(State.ysweetStatus, Synced)
30 | _ => ()
31 }
32 }
33
34 let handleLocalChanges = (rawEvent: {..}) => {
35 let hasChanges: bool = Obj.magic(rawEvent["detail"])
36 if hasChanges {
37 Signal.set(State.ysweetStatus, Saving)
38 } else {
39 Signal.set(State.ysweetStatus, Synced)
40 }
41 }
42
43 let handleWaypointClick = (rawEvent: {..}) => {
44 let gid: string = Obj.magic(rawEvent["gid"])
45 // get the document ID that contains this waypoint gid
46 // TODO: for multiple docs that may contain the same gid, need to compose the event and add the document ID
47 // as it bubbles up through the editor
48 let docID =
49 State.waypoints
50 ->Map.keys
51 ->Iterator.toArray
52 ->Array.find(docID => {
53 switch State.waypoints
54 ->Map.get(docID)
55 ->Option.map(wps => wps->Preact.Signal.get->Array.find(wp => wp.gid == gid)) {
56 | Some(_) => true
57 | None => false
58 }
59 })
60 switch docID {
61 | Some(docID) => {
62 let wps = State.waypoints->Map.get(docID)->Option.map(wps => wps->Preact.Signal.get)
63 let attrs = wps->Option.flatMap(wps => wps->Array.find(wp => wp.gid == gid))
64 switch (wps, attrs) {
65 | (Some(waypoints), Some(attrs)) => {
66 let _ = State.Editor.get(docID)->Option.map(ed => ed->Tiptap.Commands.blur)
67 State.content->Preact.Signal.set(Some(<EditWaypoint docID waypoints attrs />))
68 }
69 | (_, _) => ()
70 }
71 }
72 | None => ()
73 }
74 }
75
76 let _ = PreactDOM.addEventListener(doc, "ysweet-connection-status", handleConnectionStatus)
77 let _ = PreactDOM.addEventListener(doc, "ysweet-local-changes", handleLocalChanges)
78 let _ = PreactDOM.addEventListener(doc, "waypoint:click", handleWaypointClick)
79
80 switch Initdata.getInitdata() {
81 | Some(data) => {
82 State.readonly->Signal.set(data.readonly)
83 State.user->Signal.set(
84 Some({id: data.id, email: data.email, handle: data.handle, registered: data.registered}),
85 )
86 }
87 | None => ()
88 }
89
90 ()
91}
92
93@jsx.component
94let make = (~doc: string) => {
95 <>
96 {root}
97 <Menugroup />
98 <MapInstance doc={doc} />
99 <Panel onMinimize={onMinimize} onOpen={onOpen}>
100 <Editor doc={doc} disabled={minimized} hidden={minimized} className="w-full h-full">
101 <Editor.Content />
102 <FloatingMenu doc={doc} />
103 <FormattingMenu doc={doc} />
104 </Editor>
105 </Panel>
106 </>
107}