From 56ef5217cc03408b8d2b09809880e2cfda7a5855 Mon Sep 17 00:00:00 2001 From: stuebinm Date: Fri, 19 Feb 2021 00:23:51 +0100 Subject: Simple Slide-changing client Everything works, EXCEPT: - choosing slidesets - choosing rooms - choosing the number of slides at runtime. --- .gitignore | 2 ++ document.css | 78 ++++++++++++++++++++++++++++++++++++++++++ elm.json | 24 +++++++++++++ index.html | 31 +++++++++++++++++ src/Main.elm | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/Protocol.elm | 24 +++++++++++++ 6 files changed, 260 insertions(+) create mode 100644 .gitignore create mode 100644 document.css create mode 100644 elm.json create mode 100644 index.html create mode 100644 src/Main.elm create mode 100644 src/Protocol.elm diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2bc193d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +elm-stuff/* +app.js diff --git a/document.css b/document.css new file mode 100644 index 0000000..e4379b6 --- /dev/null +++ b/document.css @@ -0,0 +1,78 @@ +/*@font-face { + font-family: "sharetech"; + src: url('{{ "/assets/ShareTech-Regular.ttf" | prepend: site.baseurl }}'); +}*/ + +body { + color: white; + background-color: #222; + text-align: center; +} + +img { + position: absolute; + top: 0; + left: 0; + object-fit: contain; + width: 100%; + height: 100%; +} + + +.slides { + width: 100%; + height: 90vh; + position: relative; +} + +.controls { + margin: auto; +} + +button, .button { + border-radius: 4px; + margin: 1em; + padding: 0.3em; + padding-right: 0.5em; + padding-left: 0.5em; + background-color: #fb0; + border: none; + box-shadow: 0px 0px 7px 7px #fb03; + font-size: 20px; + color: black !important; + text-decoration: none; + cursor: pointer; + transition: 0.2s; + font-family: "sharetech"; +} + +.button a { + color: #000; +} + +button:enabled:hover, .button:hover { + box-shadow: 0px 0px 7px 7px #fb09; +} + +button:enabled:active { + background-color: #615400; + color: #eee; +} + +button:disabled { + filter: grayscale(100%); + -webkit-filter: grayscale(100%); + cursor: not-allowed; +} + +button.pressed { + background-color: #615400; + color: #eee; +} + + + + + + + diff --git a/elm.json b/elm.json new file mode 100644 index 0000000..2d0d191 --- /dev/null +++ b/elm.json @@ -0,0 +1,24 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.5", + "elm/html": "1.0.0", + "elm/json": "1.1.3" + }, + "indirect": { + "elm/time": "1.0.0", + "elm/url": "1.0.0", + "elm/virtual-dom": "1.0.2" + } + }, + "test-dependencies": { + "direct": {}, + "indirect": {} + } +} diff --git a/index.html b/index.html new file mode 100644 index 0000000..32c90e2 --- /dev/null +++ b/index.html @@ -0,0 +1,31 @@ + + + + + Main + + + + + +
+ + + diff --git a/src/Main.elm b/src/Main.elm new file mode 100644 index 0000000..5066ad6 --- /dev/null +++ b/src/Main.elm @@ -0,0 +1,101 @@ +port module Main exposing (..) + +import Browser +import Html exposing (Html, button, div, text, br, input, img) +import Html.Attributes exposing (style, class, value, placeholder, src) +import Html.Events exposing (onInput, onClick) +import Html.Lazy exposing (lazy) +import List exposing (foldr) + +import Protocol exposing (decodeState, encodeState) +import Json.Decode as D + + +main = Browser.document + { init = init + , update = update + , view = view + , subscriptions = subscriptions + } + + -- subscribe to messages from the websocket +subscriptions : Model -> Sub Msg +subscriptions model = recvPort GotMessage + + -- corresponding ports for the subscriptions +port recvPort : (String -> msg) -> Sub msg +port sendPort : String -> Cmd msg + + +{- STATE AND STATE TRANSITIONS -} + + -- the main client state +type alias Model = { slide : Int, max : Int } + + -- start at the first slide, for now just assume that we have ten slides +init : () -> (Model, Cmd Msg) +init f = ( { slide = 0, max = 10 }, Cmd.none) + + -- possible state transitions: +type Msg = GotMessage String + | NextSlide + | PrevSlide + + -- update stuff +update : Msg -> Model -> (Model, Cmd Msg) +update msg model = case msg of + NextSlide -> updateSlide ((+) 1) model + PrevSlide -> updateSlide ((+) -1) model + GotMessage text -> + case decodeState text of + Nothing -> (model, Cmd.none) + Just newstate -> ({model | slide = newstate.state }, Cmd.none) + + -- while changing slides we must take care not to end up in an invalid + -- state (where slide > max), so this logic gets its own function +tweakSlide : (Int -> Int) -> Model -> Model +tweakSlide f model = { model | slide = modBy model.max (f model.slide) } + +updateSlide : (Int -> Int) -> Model -> (Model, Cmd Msg) +updateSlide f model = + let new = tweakSlide f model + in (new, sendPort (encodeState { state = new.slide })) + +{- VIEW COMPONENTS -} + + -- our body consists of a slide container and a couple controls +body : Model -> Html Msg +body model = div [] + [ div [class "slides"] (slideView model.slide model.max) + , div [class "controls"] + [ button [ onClick PrevSlide ] [ text "←" ] + , text (String.fromInt (model.slide+1)) + , button [ onClick NextSlide ] [ text "→" ] + ] + ] + + -- the slide view is just a list of img tags, one for each slide; note + -- that these are all loaded on startup, with visibility done through + -- z indices so we won't have lags while switching between them. +slideView : Int -> Int -> List (Html Msg) +slideView i max = List.range 0 (max - 1) + |> List.map (\x -> ("example/" ++ (padNum 2 (x+1)) ++ ".png", x == i)) + |> List.map (\(path,t) -> img [src path, onTop t] []) + +onTop t = style "z-index" (String.fromInt (if t then 10 else 0)) + + -- format an int with prefixed 0's — apparently elm doesn't have a + -- standard function for that, but it's needed for slide filenames +padNum : Int -> Int -> String +padNum l num = + let str = String.fromInt num + in if (String.length str) > l then str else + (String.repeat (l - String.length str) "0") ++ str + + +view : Model -> Browser.Document Msg +view model = { title = "Websockets example" + , body = [body model] + } + + diff --git a/src/Protocol.elm b/src/Protocol.elm new file mode 100644 index 0000000..371a23a --- /dev/null +++ b/src/Protocol.elm @@ -0,0 +1,24 @@ +module Protocol exposing (State, encodeState, decodeState) + +import Json.Decode as D +import Json.Encode as E + +{- PROTOCOL -} + + -- for now, this is still very boring and just has one field: +type alias State = { state : Int } + +encodeState : State -> String +encodeState state = + E.object [ ("state", E.int state.state) ] + |> E.encode 0 + + +stateDecoder : D.Decoder State +stateDecoder = D.map State (D.field "state" D.int) + +decodeState : String -> Maybe State +decodeState text = case D.decodeString (D.nullable stateDecoder) text of + Err e -> Nothing + Ok value -> value + -- cgit v1.2.3 From 0aaa2a1738b61b056b3e58f473d85e9eb5702402 Mon Sep 17 00:00:00 2001 From: stuebinm Date: Fri, 19 Feb 2021 00:50:11 +0100 Subject: nix derivation with elm2nix (modified, to make it work again — elm2nix generates somewhat obstuse and occasionally useless code) --- .gitignore | 1 + default.nix | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ elm-srcs.nix | 37 +++++++++++++++++++++++++++++++++++++ index.html | 2 +- registry.dat | Bin 0 -> 106150 bytes 5 files changed, 89 insertions(+), 1 deletion(-) create mode 100644 default.nix create mode 100644 elm-srcs.nix create mode 100644 registry.dat diff --git a/.gitignore b/.gitignore index 2bc193d..f628ce3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ elm-stuff/* app.js +result diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..54ebd67 --- /dev/null +++ b/default.nix @@ -0,0 +1,50 @@ +{ nixpkgs ? +, config ? {} +}: + +with (import nixpkgs config); + +let + mkDerivation = + { srcs ? ./elm-srcs.nix + , src + , name + , srcdir ? "./src" + , targets ? [] + , registryDat ? ./registry.dat + , outputJavaScript ? true + }: + stdenv.mkDerivation { + inherit name src; + + buildInputs = [ elmPackages.elm ]; + + buildPhase = pkgs.elmPackages.fetchElmDeps { + elmPackages = import srcs; + elmVersion = "0.19.1"; + inherit registryDat; + }; + + installPhase = let + elmfile = module: "${srcdir}/${builtins.replaceStrings ["."] ["/"] module}.elm"; + extension = if outputJavaScript then "js" else "html"; + in '' + mkdir -p $out/share/doc + ${lib.concatStrings (map (module: '' + echo "compiling ${elmfile module}" + elm make ${elmfile module} --output $out/${module}.${extension} + '') targets)} + cp *.html $out + cp *.css $out + ''; + }; +in mkDerivation { + name = "picarones"; + + srcs = ./elm-srcs.nix; + src = ./.; + targets = ["Main"]; + srcdir = "./src"; + outputJavaScript = true; +} + diff --git a/elm-srcs.nix b/elm-srcs.nix new file mode 100644 index 0000000..becbc8c --- /dev/null +++ b/elm-srcs.nix @@ -0,0 +1,37 @@ +{ + + "elm/json" = { + sha256 = "0kjwrz195z84kwywaxhhlnpl3p251qlbm5iz6byd6jky2crmyqyh"; + version = "1.1.3"; + }; + + "elm/html" = { + sha256 = "1n3gpzmpqqdsldys4ipgyl1zacn0kbpc3g4v3hdpiyfjlgh8bf3k"; + version = "1.0.0"; + }; + + "elm/browser" = { + sha256 = "0nagb9ajacxbbg985r4k9h0jadqpp0gp84nm94kcgbr5sf8i9x13"; + version = "1.0.2"; + }; + + "elm/core" = { + sha256 = "19w0iisdd66ywjayyga4kv2p1v9rxzqjaxhckp8ni6n8i0fb2dvf"; + version = "1.0.5"; + }; + + "elm/url" = { + sha256 = "0av8x5syid40sgpl5vd7pry2rq0q4pga28b4yykn9gd9v12rs3l4"; + version = "1.0.0"; + }; + + "elm/time" = { + sha256 = "0vch7i86vn0x8b850w1p69vplll1bnbkp8s383z7pinyg94cm2z1"; + version = "1.0.0"; + }; + + "elm/virtual-dom" = { + sha256 = "0q1v5gi4g336bzz1lgwpn5b1639lrn63d8y6k6pimcyismp2i1yg"; + version = "1.0.2"; + }; +} diff --git a/index.html b/index.html index 32c90e2..66fe158 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ Main - + diff --git a/registry.dat b/registry.dat new file mode 100644 index 0000000..53c3803 Binary files /dev/null and b/registry.dat differ -- cgit v1.2.3 From f4a1ee55987b7c58745dc5865c4ecf30874a3564 Mon Sep 17 00:00:00 2001 From: stuebinm Date: Sun, 7 Mar 2021 16:46:52 +0100 Subject: add default.nix Somewhat basic for now, but it does build a directory with a functioning website inside of it. --- .gitignore | 1 + default.nix | 1 + 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index f628ce3..b9e5384 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ elm-stuff/* app.js +Main.js result diff --git a/default.nix b/default.nix index 54ebd67..d597f70 100644 --- a/default.nix +++ b/default.nix @@ -36,6 +36,7 @@ let '') targets)} cp *.html $out cp *.css $out + cp -r example $out/ ''; }; in mkDerivation { -- cgit v1.2.3