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}