aboutsummaryrefslogtreecommitdiff
path: root/server/lib/Uplcg/Views.hs
blob: a004f57b2851d486f903fb405a5df46d3b08bdd0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
{-# LANGUAGE OverloadedStrings #-}
module Uplcg.Views
    ( RoomView (..)
    , rooms
    , client
    ) where

import           Control.Monad                (when)
import qualified Data.ByteString.Builder      as BLB
import           Data.Foldable                (for_)
import qualified Data.HashMap.Strict          as HMS
import           Data.List                    (sort, sortBy)
import           Data.Ord                     (comparing)
import           Data.Text                    (Text)
import qualified Data.Text.Encoding           as T
import qualified Network.HTTP.Types.URI       as HttpUri
import qualified Text.Blaze.Html5             as H
import qualified Text.Blaze.Html5.Attributes  as A
import           Uplcg.Cards
import           Uplcg.Version                (version)

data RoomView = RoomView Text Bool Int

template :: Text -> H.Html -> H.Html
template title body = H.docTypeHtml $ do
    H.head $ do
        H.meta H.! A.charset "UTF-8"
        H.link H.! A.rel "stylesheet" H.! A.type_ "text/css"
            H.! A.href "/assets/style.css?v=1"
        H.title $ H.toHtml title
        H.meta H.! A.name "viewport" H.! A.content "width=device-width"
    H.body $ do
        body
        H.footer $ do
            H.a H.! A.href "https://github.com/jaspervdj/uplcg" $
                "Untitled PL Card Game"
            " version "
            H.toHtml version

rooms :: [RoomView] -> CardSets -> Maybe String -> H.Html
rooms rooms0 decks mbError = template "Untitled PL Card Game" $
    H.div H.! A.class_ "rooms" $ do
        H.h1 "Rooms"
        if null rooms0
            then H.p "No rooms online."
            else H.ul $ for_ rooms1 $ \(RoomView rid lock num) -> H.li $ do
                H.a H.! A.href (H.toValue $ "/rooms/" <> rid) $
                    H.toHtml rid
                when lock  " 🔒"
                " ("
                H.toHtml num
                ")"

        H.br
        H.h1 "Create Room"
        case mbError of
            Nothing  -> mempty
            Just err -> H.p H.! A.class_ "error" $ H.toHtml err
        H.form H.! A.method "POST" H.! A.action "/rooms" $ do
            H.label H.! A.for "name" $ "Room identifier (alphanumeric only): "
            H.input H.! A.type_ "text" H.! A.name "id"
            H.br
            H.label H.! A.for "name" $ "Password (optional): "
            H.input H.! A.type_ "text" H.! A.name "password"
            H.br
            H.label H.! A.for "deck" $ "Card set to use: "

            let sorted = sort . HMS.keys $ csCards decks
            H.select H.! A.name "deck" $ for_ sorted $ \deck ->
                if Just deck == csDefault decks then
                    H.option H.! A.value (H.toValue deck)
                        H.! A.selected "selected" $ H.toHtml deck
                else
                    H.option H.! A.value (H.toValue deck) $ H.toHtml deck

            H.br
            H.input H.! A.type_ "submit" H.! A.value "Create room"
  where
    rooms1 = sortBy (comparing (\(RoomView rid _ _) -> rid)) rooms0

client :: Text -> Maybe Text -> H.Html
client roomId mbPassword = template "Untitled PL Card Game" $ do
    H.div H.! A.id "main" $ ""
    H.script H.! A.type_ "text/JavaScript"
        H.! A.src "/assets/client.js" $ ""
    H.script H.! A.type_ "text/JavaScript" $ H.unsafeLazyByteString entryPoint
  where
    t2b = BLB.byteString . T.encodeUtf8
    entryPoint = BLB.toLazyByteString $
      "var app = Elm.Client.init({node: document.querySelector('main')});" <>

      "function connect() {" <>
      "  var protocol = 'ws:';" <>
      "  if(document.location.protocol == 'https:') {" <>
      "    protocol = 'wss:'" <>
      "  }" <>
      "  var url = protocol + '//' + document.location.host +" <>
      "    '/rooms/" <> t2b roomId <> "/events" <>
          (case mbPassword of
              Nothing -> ""
              Just pwd -> BLB.byteString $ HttpUri.renderSimpleQuery True
                  [("password", T.encodeUtf8 pwd)]) <>
              "';" <>
      "  var socket = new WebSocket(url);" <>
      "  var socketSend = function(message) {" <>
      "    socket.send(message);" <>
      "  };" <>
      "  app.ports.webSocketOut.subscribe(socketSend);" <>
      "  socket.onmessage = function(event) {" <>
      "    app.ports.webSocketIn.send(event.data);" <>
      "  };" <>
      "  socket.onclose = function(event) {" <>
      "    app.ports.webSocketOut.unsubscribe(socketSend);" <>
      "    setTimeout(function() {" <>
      "      connect();" <>
      "    }, 1000);" <>
      "  };" <>
      "  socket.onerror = function(event) {" <>
      "    socket.close();" <>
      "  };" <>
      "}" <>
      "connect();"