{-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE OverloadedLabels #-} {-# LANGUAGE OverloadedStrings #-} module Main where import Control.Lens ((^.)) import Data.Generics.Labels () import Data.Maybe (fromMaybe) import Data.Text (Text, pack, unpack) import GHC.Generics (Generic) import Safe (readMay) import Shpadoinkle (Html, JSM, text) import Shpadoinkle.Backend.ParDiff (runParDiff) import Shpadoinkle.Html (button, div_, for', getBody, id', input', label, onClick, onInput, value) import Shpadoinkle.Lens (onRecord, onSum) import Shpadoinkle.Run (runJSorWarp, simple) data Form = Form { name :: Text , age :: Int } deriving (Eq, Show, Generic) form :: Functor m => Form -> Html m Form form f = div_ [ label [ for' "name" ] [ "Name" ] , onRecord #name $ input' [ id' "name" , value $ f ^. #name , onInput const ] , label [ for' "age" ] [ "Age" ] , onRecord #age $ input' [ id' "age" , value . pack . show $ f ^. #age , onInput $ const . fromMaybe 0 . readMay . unpack ] ] newtype Counter = Counter Int deriving (Eq, Ord, Num, Show, Generic) counter :: Counter -> Html m Counter counter c = div_ [ label [ for' "counter" ] [ text . pack $ show c ] , button [ id' "counter", onClick (+ 1) ] [ "Increment" ] ] data Model = MCounter Counter | MForm Form deriving (Eq, Show, Generic) view :: Applicative m => Model -> Html m Model view = \case MCounter c -> div_ [ onSum #_MCounter $ counter c , button [ onClick . const. MForm $ Form "" 18 ] [ "Go to Form" ] ] MForm f -> div_ [ onSum #_MForm $ form f , button [ onClick . const $ MCounter 0 ] [ "Go to Counter" ] ] app :: JSM () app = simple runParDiff (MCounter 0) view getBody main :: IO () main = runJSorWarp 8080 app