Hyperbole applications are divided into top-level Pages, which run side effects, then return an HTML View
hello :: Page es '[]
hello = do
  pure $ el "Hello World"
Run an Application via Warp and WAI. This runs on port 3000 and responds to everything with "Hello World"
main :: IO ()
main = do
  run 3000 $ liveApp quickStartDocument (runPage hello)
Views are HTML fragments with a context
helloWorld :: View context ()
helloWorld =
  el "Hello World"
>>> renderText helloWorld
"<div>Hello World</div>"
We can factor Views into reusable functions:
messageView :: Text -> View context ()
messageView msg =
  el $ text msg

page :: Page es '[]
page = do
  pure $ messageView "Hello World"
Using atomic-css we can use functions to factor styles as well
Let's get interactive! Using Hyperbole, we divide our Page into independent live subsections called HyperViews
To start, define a data type that uniquely identifies an interactive section of the page. Make it an instance of ViewId. We will call this datatype a ViewId
data Message = Message1 | Message2
  deriving (Generic, ViewId)
Next we make the ViewId an instance of HyperView:
  • Create an Action type with a constructor for every possible way that the user can interact with it
  • Write an update for each Action
instance HyperView Message es where
  data Action Message
    = Louder Text
    deriving (Generic, ViewAction)

  update (Louder msg) = do
    let new = msg <> "!"
    pure $ messageView new
If an Action occurs, the contents of our HyperView will be replaced with the result of update.
Choose where the new HyperView will appear on the page using the hyper function, and add the ViewId type to the type-level list of Page
page :: Page es '[Message]
page = do
  pure $ do
    el "Unchanging Header"
    hyper Message1 $ messageView "Hello"
    hyper Message2 $ messageView "World"
Finally, let's create a View with a button that triggers our Action. Instead of using a generic context in the View type signature, we must set it to our ViewId. The compiler will tell us if we try to trigger actions that don't belong to our HyperView instance
messageView :: Text -> View Message ()
messageView msg = do
  button (Louder msg) ~ border 1 $ text msg
When the user clicks the button, the contents of hyper will be replaced with the result of update, leaving the rest of the page untouched.