summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLLLL Colonq <llll@colonq>2025-04-15 21:10:01 -0400
committerLLLL Colonq <llll@colonq>2025-04-15 21:10:01 -0400
commitb31fd7881f8da11dbdd1cc259907b535d96a47a4 (patch)
tree1829fe570e53a0876990c6056da6f71880b65493
parentbd1256504b6154c7d9b8feb0fefb6755b11586ee (diff)
Add gizmo page
-rw-r--r--main.css36
-rw-r--r--src/Main.purs2
-rw-r--r--src/Main/Gizmo.purs34
-rw-r--r--src/UI.js26
-rw-r--r--src/UI.purs12
-rw-r--r--src/Utils.purs12
-rw-r--r--templates/api/gizmo.html26
7 files changed, 148 insertions, 0 deletions
diff --git a/main.css b/main.css
index cb79905..3ae4a25 100644
--- a/main.css
+++ b/main.css
@@ -571,3 +571,39 @@ a.lcolonq-button-link :active {
#lcolonq-throwshade-current {
margin: 0.5rem;
}
+
+/* gizmo */
+#lcolonq-gizmo-body {
+ width: 100vw;
+ height: 100vh;
+}
+#lcolonq-gizmo {
+ width: 100%;
+ height: 100%;
+}
+#lcolonq-gizmo-top {
+ position: absolute;
+ opacity: 0;
+ transition: opacity 0.2s ease-in-out;
+ right: 0px;
+ top: 0px;
+ color: white;
+ background-color: black;
+ padding-top: 1rem;
+ padding-left: 1rem;
+ padding-right: 1rem;
+ padding-bottom: 1rem;
+}
+#lcolonq-gizmo-top:hover {
+ opacity: 1;
+}
+#lcolonq-gizmo-bottom {
+ background-color: white;
+ width: 100%;
+ height: 100%;
+}
+#lcolonq-gizmo-contents {
+ border: none;
+ width: 100%;
+ height: 100%;
+}
diff --git a/src/Main.purs b/src/Main.purs
index 34ca80b..ab98c40 100644
--- a/src/Main.purs
+++ b/src/Main.purs
@@ -9,6 +9,7 @@ import Main.API as API
import Main.Auth as Auth
import Main.Button as Button
import Main.Extension as Extension
+import Main.Gizmo as Gizmo
import Main.Greencircle as Greencircle
import Main.Menu as Menu
import Main.OBS as OBS
@@ -28,4 +29,5 @@ main = case Config.mode of
"auth" -> Auth.main
"greencircle" -> Greencircle.main
"throwshade" -> Throwshade.main
+ "gizmo" -> Gizmo.main
_ -> throw $ "unknown mode: " <> Config.mode
diff --git a/src/Main/Gizmo.purs b/src/Main/Gizmo.purs
new file mode 100644
index 0000000..e728e66
--- /dev/null
+++ b/src/Main/Gizmo.purs
@@ -0,0 +1,34 @@
+module Main.Gizmo where
+
+import Prelude
+
+import Config as Config
+import Data.Foldable (for_)
+import Data.String (Pattern(..), split)
+import Data.String as String
+import Effect (Effect)
+import Effect.Aff (launchAff_)
+import Effect.Class (class MonadEffect, liftEffect)
+import Effect.Console (log)
+import Fetch (fetch)
+import UI (addOption, onInput, startBufferRefresh)
+import Utils (byId, getSelectValue, setIFrameSrc)
+
+loadBuffer :: forall m. MonadEffect m => String -> m Unit
+loadBuffer nm = do
+ contents <- byId "lcolonq-gizmo-contents"
+ setIFrameSrc (Config.apiServer <> "/gizmo?buf=" <> nm) contents
+
+main :: Effect Unit
+main = launchAff_ do
+ liftEffect $ log "hello from gizmo"
+ select <- byId "lcolonq-gizmo-select"
+ onInput select \d -> loadBuffer d
+ { text: text } <- fetch (Config.apiServer <> "/gizmo/list") {}
+ glist <- text
+ for_ (split (Pattern "\n") glist) \buf -> do
+ when (not $ String.null buf) $ addOption buf select
+ initial <- getSelectValue =<< byId "lcolonq-gizmo-select"
+ loadBuffer initial
+ contents <- byId "lcolonq-gizmo-contents"
+ startBufferRefresh contents
diff --git a/src/UI.js b/src/UI.js
index eb10598..044eba9 100644
--- a/src/UI.js
+++ b/src/UI.js
@@ -36,3 +36,29 @@ export const _submitShader = (url) => (shader) => () => {
body: data,
});
};
+
+export const _addOption = (nm) => (el) => () => {
+ const opt = document.createElement("option");
+ opt.value = nm
+ opt.innerHTML = nm;
+ el.appendChild(opt);
+};
+
+export const _onInput = (el) => (f) => () => {
+ el.addEventListener("input", (ev) => {
+ f(ev.target.value)();
+ });
+};
+
+export const _startBufferRefresh = (url) => (iframe) => () => {
+ const socket = new WebSocket(url);
+ socket.addEventListener("open", (ev) => {
+ console.log("connected");
+ });
+ const select = document.getElementById("lcolonq-gizmo-select");
+ socket.addEventListener("message", async (ev) => {
+ if (select.value == ev.data) {
+ iframe.src = iframe.src;
+ }
+ });
+};
diff --git a/src/UI.purs b/src/UI.purs
index d5913b7..645c346 100644
--- a/src/UI.purs
+++ b/src/UI.purs
@@ -37,3 +37,15 @@ setShader s = liftEffect $ _setShader s
foreign import _submitShader :: String -> String -> Effect Unit
submitShader :: forall m. MonadEffect m => String -> m Unit
submitShader el = liftEffect $ _submitShader (Config.secureApiServer <> "/redeem") el
+
+foreign import _addOption :: String -> DOM.El.Element -> Effect Unit
+addOption :: forall m. MonadEffect m => String -> DOM.El.Element -> m Unit
+addOption o el = liftEffect $ _addOption o el
+
+foreign import _onInput :: DOM.El.Element -> (String -> Effect Unit) -> Effect Unit
+onInput :: forall m. MonadEffect m => DOM.El.Element -> (String -> Effect Unit) -> m Unit
+onInput el f = liftEffect $ _onInput el f
+
+foreign import _startBufferRefresh :: String -> DOM.El.Element -> Effect Unit
+startBufferRefresh :: forall m. MonadEffect m => DOM.El.Element -> m Unit
+startBufferRefresh el = liftEffect $ _startBufferRefresh (Config.apiServer <> "/gizmo/events") el
diff --git a/src/Utils.purs b/src/Utils.purs
index 7be7be8..cee8f70 100644
--- a/src/Utils.purs
+++ b/src/Utils.purs
@@ -26,7 +26,9 @@ import Web.Event.EventTarget as Ev.Tar
import Web.HTML as HTML
import Web.HTML.HTMLDocument as HTML.Doc
import Web.HTML.HTMLInputElement as HTML.Input
+import Web.HTML.HTMLSelectElement as HTML.Select
import Web.HTML.HTMLTextAreaElement as HTML.TextArea
+import Web.HTML.HTMLIFrameElement as HTML.IFrame
import Web.HTML.Window as HTML.Win
maybeToArray :: forall a. Maybe a -> Array a
@@ -102,6 +104,11 @@ getValue e = case HTML.Input.fromElement e of
Just inp -> liftEffect $ HTML.Input.value inp
Nothing -> liftEffect $ throw "element is not an input"
+getSelectValue :: forall m. MonadEffect m => DOM.Element -> m String
+getSelectValue e = case HTML.Select.fromElement e of
+ Just inp -> liftEffect $ HTML.Select.value inp
+ Nothing -> liftEffect $ throw "element is not a select"
+
addClass :: forall m. MonadEffect m => String -> DOM.Element -> m Unit
addClass c e = do
cl <- liftEffect $ DOM.El.classList e
@@ -120,6 +127,11 @@ toggleClass c e = do
_ <- liftEffect $ DOM.DTL.toggle cl c
pure unit
+setIFrameSrc :: forall m. MonadEffect m => String -> DOM.Element -> m Unit
+setIFrameSrc src e = case HTML.IFrame.fromElement e of
+ Just iframe -> liftEffect $ HTML.IFrame.setSrc src iframe
+ Nothing -> liftEffect $ throw "element is not an iframe"
+
checkAuth :: AuthInfo -> Aff String
checkAuth auth = do
{ text: resp } <-
diff --git a/templates/api/gizmo.html b/templates/api/gizmo.html
new file mode 100644
index 0000000..665f44f
--- /dev/null
+++ b/templates/api/gizmo.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
+ <title>LCOLONQ Gizmo Extravaganza FES</title>
+ <link rel="icon" href="./assets/mrgreen.png">
+ <link rel="stylesheet" type="text/css" href="./main.css">
+ <script type="module">
+CONFIG_SUBST
+ globalThis.mode = "gizmo";
+ </script>
+ <script type="module" src="./main.js"></script>
+ </head>
+ <body id="lcolonq-gizmo-body">
+ <div id="lcolonq-gizmo">
+ <div id="lcolonq-gizmo-top">
+ gizmo selection
+ <select name="gizmo" id="lcolonq-gizmo-select"></select>
+ </div>
+ <div id="lcolonq-gizmo-bottom">
+ <iframe id="lcolonq-gizmo-contents"></iframe>
+ </div>
+ </div>
+ </body>
+</html>