hyperbole-0.3.5: example/Example/Counter.hs
module Example.Counter where
import Data.Text (pack)
import Effectful
import Effectful.Concurrent.STM
import Example.Style as Style
import Web.Hyperbole
-- We are using a TVar to manage our state
-- In normal web applications, state will be managed in a database, abstracted behind a custom Effect. See Example.EFfects.Users for the interface
-- Optionally, the count could be stored in a session. See Example.Sessions
page :: (Hyperbole :> es, Concurrent :> es) => TVar Int -> Page es Response
page var = do
handle $ counter var
load $ do
n <- readTVarIO var
pure $ col (pad 20 . gap 10) $ do
el h1 "Counter"
hyper Counter (viewCount n)
data Counter = Counter
deriving (Generic, Param)
instance HyperView Counter where
type Action Counter = Count
data Count
= Increment
| Decrement
deriving (Generic, Param)
counter :: (Hyperbole :> es, Concurrent :> es) => TVar Int -> Counter -> Count -> Eff es (View Counter ())
counter var _ Increment = do
n <- modify var $ \n -> n + 1
pure $ viewCount n
counter var _ Decrement = do
n <- modify var $ \n -> n - 1
pure $ viewCount n
viewCount :: Int -> View Counter ()
viewCount n = col (gap 10) $ do
row id $ do
el (bold . fontSize 48 . border 1 . pad (XY 20 0)) $ text $ pack $ show n
row (gap 10) $ do
button Decrement Style.btn "Decrement"
button Increment Style.btn "Increment"
modify :: (Concurrent :> es) => TVar Int -> (Int -> Int) -> Eff es Int
modify var f =
atomically $ do
modifyTVar var f
readTVar var
initCounter :: (Concurrent :> es) => Eff es (TVar Int)
initCounter = newTVarIO 0