diff --git a/README.md b/README.md
index a3bb2c7dfb2154da4e38206a44b97f11fb09e6d8..1d0896befb1e0c70415ab932c8d0aa56bbbf5ee9 100644
--- a/README.md
+++ b/README.md
@@ -75,19 +75,7 @@ Balíček je také možné nainstalovat:
 SMS brána v tuto chvíli vystavuje následující služby:
 
 
-### Uvítací stránka
-
-```http
-GET / HTTP/1.1
-```
-
-```http
-HTTP/1.1 200 OK
-Content-Type: text/html; charset=utf8
-```
-
-Vrací název aplikace a obrázek Pelikána z Wikimedia.
-
+### API
 
 ### Odeslání SMS zprávy na číslo
 
diff --git a/pelican.cabal b/pelican.cabal
index 2ae8fce538f73dc4fcf36f49f83bd0c031d34d41..a383153613cde670dd9155c705bc6880537b9826 100644
--- a/pelican.cabal
+++ b/pelican.cabal
@@ -96,14 +96,17 @@ executable pelican
     other-modules:
         Paths_pelican
         Pelican.Action
+        Pelican.UI
+        Pelican.Public
         Pelican.API
         Pelican.Backend
+        Pelican.Backend.Failer
         Pelican.Backend.Fetcher
         Pelican.Backend.Sender
-        Pelican.Backend.Failer
         Pelican.Build
         Pelican.Common
         Pelican.Errors
+        Pelican.Main
         Pelican.Model
         Pelican.Site
         Pelican.Types
diff --git a/pelican.env b/pelican.env
index 4c3aa4ab7f8a70f32e44c129f77e3a430f86dab3..4024ea136b476c1ec26a85294905d92347b224e0 100644
--- a/pelican.env
+++ b/pelican.env
@@ -10,8 +10,11 @@ DATABASE = postgresql://pelican:pelican@localhost/pelican
 HTTP_PORT = 5000
 HTTP_ROOT = static
 
-# Stylesheet to use
-ASSET_STYLES = https://styleguide.pir-test.eu/2.3.x/styleguide/css/styleguide.min.css
+# Assets to use
+ASSET_VUE_JS   = https://cdn.jsdelivr.net/npm/vue@2.x
+ASSET_MAIN_CSS = https://styleguide.pir-test.eu/2.3.3/css/styles.css
+ASSET_MAIN_JS  = https://styleguide.pir-test.eu/2.3.3/js/main.bundle.js
+ASSET_LOGO     = https://styleguide.pir-test.eu/images/logo-round-white.svg
 
 # Base URL of the SMS gateway
 SMS_API = https://aweg.t-mobile.cz/
diff --git a/sql/009-views.sql b/sql/009-views.sql
new file mode 100644
index 0000000000000000000000000000000000000000..70fcb951a4b192324900cd94e6ec4ab8fa967c9d
--- /dev/null
+++ b/sql/009-views.sql
@@ -0,0 +1,74 @@
+-- Create views for basic message statistics.
+
+create view application_stats as
+	with s365 as (
+		select appid, sum(array_length(parts, 1))
+		from history where ts >= now() - interval '365 days'
+		group by appid
+	), s30 as (
+		select appid, sum(array_length(parts, 1))
+		from history where ts >= now() - interval '30 days'
+		group by appid
+	), s7 as (
+		select appid, sum(array_length(parts, 1))
+		from history where ts >= now() - interval '7 days'
+		group by appid
+	), s1 as (
+		select appid, sum(array_length(parts, 1))
+		from history where ts >= now() - interval '1 day'
+		group by appid
+	)
+	select	a.appid,
+		coalesce(s365.sum, 0) s365,
+		coalesce(s30.sum, 0) s30,
+		coalesce(s7.sum, 0) s7,
+		coalesce(s1.sum, 0) s1
+	from application a
+	left join s365 on s365.appid = a.appid
+	left join s30 on s30.appid = a.appid
+	left join s7 on s7.appid = a.appid
+	left join s1 on s1.appid = a.appid
+	order by 2 desc;
+
+create view cost_centre_stats as
+	with s365 as (
+		select cost_centre, sum(array_length(parts, 1))
+		from history where ts >= now() - interval '365 days'
+		group by cost_centre
+	), s30 as (
+		select cost_centre, sum(array_length(parts, 1))
+		from history where ts >= now() - interval '30 days'
+		group by cost_centre
+	), s7 as (
+		select cost_centre, sum(array_length(parts, 1))
+		from history where ts >= now() - interval '7 days'
+		group by cost_centre
+	), s1 as (
+		select cost_centre, sum(array_length(parts, 1))
+		from history where ts >= now() - interval '1 day'
+		group by cost_centre
+	)
+	select	cc.name,
+		cc.description,
+		coalesce(s365.sum, 0) s365,
+		coalesce(s30.sum, 0) s30,
+		coalesce(s7.sum, 0) s7,
+		coalesce(s1.sum, 0) s1
+	from cost_centre cc
+	left join s365 on s365.cost_centre = cc.name
+	left join s30 on s30.cost_centre = cc.name
+	left join s7 on s7.cost_centre = cc.name
+	left join s1 on s1.cost_centre = cc.name
+	order by 3 desc, 1 asc;
+
+-- Create view for detailed montly statistics.
+
+create view monthly_stats as
+	select	extract(year from ts)::bigint "year",
+		extract(month from ts)::bigint "month",
+		appid,
+		cost_centre,
+		sum(array_length(parts, 1))::bigint total
+	from history
+	group by year, month, appid, cost_centre
+	order by 1 asc, 2 asc, 5 desc;
diff --git a/src/Main.hs b/src/Main.hs
index a27282a744fe1bc1a0470304808c932149db74a9..68ef35e9f715e5c983111832d5a022ae1e17c5bf 100644
--- a/src/Main.hs
+++ b/src/Main.hs
@@ -3,75 +3,16 @@
 -- Copyright   :  Jan Hamal Dvořák
 -- License     :  AGPL-3.0-or-later
 --
--- Maintainer  :  jan.hamal.dvorak@pirati.cz
+-- Maintainer  :  mordae@anilinux.org
 -- Stability   :  unstable
 -- Portability :  non-portable (ghc)
 --
 
-module Main ( main
-            )
+module Main
+  ( main
+  )
 where
-  import Praha
-  import Praha.Config.Environment
-
-  import UnliftIO.Environment (getProgName)
-
-  import Options.Applicative
-
-  import Pelican.Site (serve)
-  import Pelican.Build
-
-  import System.IO
-  import Data.List (reverse)
-
-
-  data Options
-    = Options
-      { optMainFunc    :: Options -> IO ()
-      , optConf        :: [FilePath]
-      }
-
-
-  mainFunc :: Parser (Options -> IO ())
-  mainFunc = flag' mainVersion ( long "version"
-                                 <> short 'V'
-                                 <> help "Show version information"
-                                 <> hidden
-                               )
-             <|> pure mainWebsite
-
-
-  options :: Parser Options
-  options = Options <$> mainFunc
-                    <*> many do
-                          strOption ( long "config"
-                                      <> short 'C'
-                                      <> help "Configuration file to read"
-                                    )
-
-
-  main :: IO ()
-  main = do
-    opts <- execParser $
-      info (helper *> options)
-           ( fullDesc
-             <> progDesc "Pirate SMS Gateway :-)"
-             <> footer "Report bugs at <http://gitlab.pirati.cz/to/pelican/issues>."
-           )
-
-    optMainFunc opts opts
-
-
-  mainVersion :: Options -> IO ()
-  mainVersion _opts = do
-    prog <- getProgName
-    putStrLn $ prog <> " " <> packageVersion
-
-
-  mainWebsite :: Options -> IO ()
-  mainWebsite Options{optConf} = do
-    mapM_ readFileToEnvDefault (reverse optConf)
-    serve
+  import Pelican.Main
 
 
 -- vim:set ft=haskell sw=2 ts=2 et:
diff --git a/src/Pelican/API.hs b/src/Pelican/API.hs
index 0566be1bda1abae5ee31e59b89129106656ba8f2..43c06ab1f2e203bd5aa31ae1a504290f73689500 100644
--- a/src/Pelican/API.hs
+++ b/src/Pelican/API.hs
@@ -14,10 +14,10 @@ module Pelican.API
 where
   import Praha
 
-  import Pelican.Types
   import Pelican.Action
   import Pelican.Common
   import Pelican.Model
+  import Pelican.Types
 
   import Data.Aeson as Aeson
   import Data.Text (splitOn)
@@ -30,8 +30,6 @@ where
 
   apiRoutes :: Dispatch (Action ()) TopLevel ()
   apiRoutes = do
-    route $ getRootR <$ get <* offerHTML
-
     route $ getReceiptR <$ get </ "v1" </ "receipt" <*> argWith fromText
                         <* offerJSON
 
@@ -47,16 +45,6 @@ where
     throwError Conflict (cs sqlErrorDetail)
 
 
-  getRootR :: Action ()
-  getRootR = do
-    sendHTML do
-      page_ "Pelican" do
-        h1_ "Pelican"
-        img_ [ src_ "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d4/Pelikan_Walvis_Bay.jpg/480px-Pelikan_Walvis_Bay.jpg"
-             , alt_ "It's alive!"
-             ]
-
-
   postSendToNumberR :: Action ()
   postSendToNumberR = do
     -- Read the request. Automatically dies on parsing error.
diff --git a/src/Pelican/Common.hs b/src/Pelican/Common.hs
index 163531be6bd66fe64d6fee1c4bfb8a48cd9e268e..a6b08b69e3d9596d382091088221de0fc46185eb 100644
--- a/src/Pelican/Common.hs
+++ b/src/Pelican/Common.hs
@@ -51,16 +51,27 @@ where
     doctypehtml_ $ do
       head_ $ do
         meta_ [charset_ "utf8"]
+        meta_ [name_ "viewport", content_ "width=device-width, initial-scale=1.0"]
         title_ title
 
-        stylesHref <- getConfig "ASSET_STYLES"
+        stylesHref <- getConfig "ASSET_MAIN_CSS"
 
-        link_ [ rel_ "stylesheet"
-              , href_ stylesHref
-              , crossorigin_ "anonymous"
-              ]
+        link_ [rel_ "stylesheet", href_ stylesHref]
 
-      body_ body
+      body_ do
+        res <- body
+
+        vueHref <- getConfig "ASSET_VUE_JS"
+        script_ [ src_ vueHref
+                , crossorigin_ "anonymous"
+                ] (toHtml ("" :: Text))
+
+        scriptHref <- getConfig "ASSET_MAIN_JS"
+        script_ [ src_ scriptHref
+                , crossorigin_ "anonymous"
+                ] (toHtml ("" :: Text))
+
+        return res
 
 
   handlePgErrors :: (MonadUnliftIO m)
diff --git a/src/Pelican/Errors.hs b/src/Pelican/Errors.hs
index f6330bc94361f0ce88cd819ae1e2fdf16213aee9..de8db6c92fe88b358e0ddaa53544068ee950faef 100644
--- a/src/Pelican/Errors.hs
+++ b/src/Pelican/Errors.hs
@@ -40,12 +40,16 @@ where
   errorPage title msg = do
     sendHTML do
       page_ (toHtml title) do
-        div_ [class_ "container vertical-margins"] do
-          h1_ [class_ "title"] do
-            toHtml title
+        div_ [class_ "container container--default grid grid-flow-col auto-cols-max gap-2 my-8"] do
+          div_ [class_ "head-alt-lg my-8 text-right"] do
+            "☒"
 
-          p_ do
-            toHtml msg
+          div_ do
+            h1_ [class_ "head-alt-lg my-8"] do
+              toHtml title
+
+            p_ [class_ "head-alt-md my-8"] do
+              toHtml msg
 
 
 -- vim:set ft=haskell sw=2 ts=2 et:
diff --git a/src/Pelican/Main.hs b/src/Pelican/Main.hs
new file mode 100644
index 0000000000000000000000000000000000000000..a9a36197f1196808c9ea790899bb4102ddf0c7ad
--- /dev/null
+++ b/src/Pelican/Main.hs
@@ -0,0 +1,88 @@
+-- |
+-- Module      :  Pelican.Main
+-- Copyright   :  Jan Hamal Dvořák
+-- License     :  AGPL-3.0-or-later
+--
+-- Maintainer  :  jan.hamal.dvorak@pirati.cz
+-- Stability   :  unstable
+-- Portability :  non-portable (ghc)
+--
+
+module Pelican.Main
+  ( main
+  , develop
+  )
+where
+  import Praha
+  import Praha.Config.Environment
+
+  import Hikaru.Develop
+
+  import UnliftIO.Environment (getProgName)
+
+  import Options.Applicative
+
+  import Pelican.Site (serve)
+  import Pelican.Build
+
+  import System.IO
+  import Data.List (reverse)
+
+
+  data Options
+    = Options
+      { optMainFunc    :: Options -> IO ()
+      , optConf        :: [FilePath]
+      }
+
+
+  mainFunc :: Parser (Options -> IO ())
+  mainFunc = flag' mainVersion ( long "version"
+                                 <> short 'V'
+                                 <> help "Show version information"
+                                 <> hidden
+                               )
+             <|> pure mainWebsite
+
+
+  options :: Parser Options
+  options = Options <$> mainFunc
+                    <*> many do
+                          strOption ( long "config"
+                                      <> short 'C'
+                                      <> help "Configuration file to read"
+                                    )
+
+
+  main :: IO ()
+  main = do
+    opts <- execParser $
+      info (helper *> options)
+           ( fullDesc
+             <> progDesc "Pirate SMS Gateway :-)"
+             <> footer "Report bugs at <http://gitlab.pirati.cz/to/pelican/issues>."
+           )
+
+    optMainFunc opts opts
+
+
+  develop :: IO ()
+  develop = do
+    readFileToEnvDefault "pelican.env"
+    readFileToEnvDefault "test.env"
+    developWith main
+
+
+  mainVersion :: Options -> IO ()
+  mainVersion _opts = do
+    prog <- getProgName
+    putStrLn $ prog <> " " <> packageVersion
+
+
+  mainWebsite :: Options -> IO ()
+  mainWebsite Options{optConf} = do
+    mapM_ readFileToEnvDefault (reverse optConf)
+    serve
+
+
+-- vim:set ft=haskell sw=2 ts=2 et:
diff --git a/src/Pelican/Public.hs b/src/Pelican/Public.hs
new file mode 100644
index 0000000000000000000000000000000000000000..eb0b5c4474fb67f2e72422bcc7fd20d2d215e20b
--- /dev/null
+++ b/src/Pelican/Public.hs
@@ -0,0 +1,213 @@
+-- |
+-- Module      :  Pelican.Public
+-- Copyright   :  Jan Hamal Dvořák
+-- License     :  AGPL-3.0-or-later
+--
+-- Maintainer  :  jan.hamal.dvorak@pirati.cz
+-- Stability   :  unstable
+-- Portability :  non-portable (ghc)
+--
+
+module Pelican.Public
+  ( publicRoutes
+  )
+where
+  import Praha
+  import Praha.Config.Environment
+
+  import Pelican.Action
+  import Pelican.Common
+  import Pelican.Model
+  import Pelican.UI
+
+  import Hikaru.Link
+
+
+  publicRoutes :: Dispatch (Action ()) TopLevel ()
+  publicRoutes = do
+    route $ getRootR   <$ get <* offerHTML
+    route $ getAppR    <$ get </ "app" <*> arg </ "" <* offerHTML
+    route $ getCentreR <$ get </ "cc"  <*> arg </ "" <* offerHTML
+
+
+  getRootR :: Action ()
+  getRootR = do
+    sendHTML do
+      page_ "SMS Brána" do
+        pageMenu_
+        appStats_
+        ccStats_
+
+
+  getAppR :: Text -> Action ()
+  getAppR appid = do
+    ensureApp appid
+
+    months <- query [sql| select year, month, sum(total)::bigint
+                          from monthly_stats where appid = ?
+                          group by year, month |] (Only appid)
+
+    sendHTML do
+      page_ (toHtml appid) do
+        pageMenu_
+        section_ [class_ "container container--default my-16"] do
+          h1_ [class_ "head-alt-lg my-8"] (toHtml appid)
+          h3_ [class_ "head-alt-md"] "Odeslané zprávy po měsících"
+
+          div_ [class_ "overflow-x-auto"] do
+            table_ [class_ "table my-2"] do
+              tr_ do
+                th_ [class_ "text-right"] "Rok"
+                th_ [class_ "text-right"] "Měsíc"
+                th_ [class_ "text-right"] "Odesláno"
+
+              forM_ months \(year :: Int, month :: Int, total :: Int) -> do
+                tr_ do
+                  td_ [class_ "text-right"] $ toHtml (tshow year)
+                  td_ [class_ "text-right"] $ toHtml (tshow month)
+                  td_ [class_ "text-right"] $ toHtml (tshow total)
+
+
+  getCentreR :: Text -> Action ()
+  getCentreR ccid = do
+    desc   <- ensureCostCentre ccid
+    months <- query [sql| select year, month, appid, sum(total)::bigint
+                          from monthly_stats where cost_centre = ?
+                          group by year, month, appid
+                          order by 1 asc, 2 asc, 4 desc |] (Only ccid)
+
+    sendHTML do
+      page_ (toHtml ccid) do
+        pageMenu_
+        section_ [class_ "container container--default my-16"] do
+          h1_ [class_ "head-alt-lg mt-8"] (toHtml ccid)
+          h2_ [class_ "head-alt-md mb-8"] (toHtml desc)
+          h3_ [class_ "head-alt-md"] "Odeslané zprávy po měsících"
+
+          div_ [class_ "overflow-x-auto"] do
+            table_ [class_ "table my-2"] do
+              tr_ do
+                th_ [class_ "text-right w-32"] "Rok"
+                th_ [class_ "text-right w-32"] "Měsíc"
+                th_ [class_ "text-left"]       "Aplikace"
+                th_ [class_ "text-right w-32"] "Odesláno"
+
+              forM_ months \(year, month, appid, total) -> do
+                tr_ do
+                  td_ [class_ "text-right"] $ toHtml (tshow (year :: Int))
+                  td_ [class_ "text-right"] $ toHtml (tshow (month :: Int))
+                  td_ [class_ "text-left"]  $ toHtml (appid :: Text)
+                  td_ [class_ "text-right"] $ toHtml (tshow (total :: Int))
+
+
+  ensureApp :: Text -> Action ()
+  ensureApp appid = do
+    Only n <- query1 "select count(*) from application where appid = ?"
+                     (Only appid)
+
+    if (n :: Int) > 0
+       then return ()
+       else throwError NotFound "No such application."
+
+
+  ensureCostCentre :: Text -> Action Text
+  ensureCostCentre ccid = do
+    descs <- query "select description from cost_centre where name = ?"
+                   (Only ccid)
+
+    case descs of
+      (Only desc : _) -> return desc
+      _otherwise      -> throwError NotFound "No such cost centre."
+
+
+  -- Fragments ---------------------------------------------------------------
+
+
+  pageMenu_ :: HtmlT Action ()
+  pageMenu_ = do
+    logoHref <- getConfig "ASSET_LOGO"
+
+    nav_ [class_ "navbar navbar--simple __js-root"] do
+      uiApp_ [inlineTemplate_] do
+        uiNavbar_ [inlineTemplate_] do
+          div_ [ class_ "container container--default navbar__content"
+               , jsClass_ "{'navbar__content--initialized': true}" ] do
+            div_ [class_ "navbar__brand my-4 flex items-center lg:pr-8 lg:my-0"] do
+              a_ [href_ "/"] do
+                img_ [src_ logoHref, class_ "w-8"]
+              span_ [class_ "pl-4 font-bold text-xl lg:border-r lg:border-grey-300 lg:pr-8"] do
+                  "SMS Brána"
+
+            div_ [class_ "navbar__menutoggle my-4 flex justify-end lg:hidden"] do
+              a_ [ href_ "#"
+                 , atClick_ "show = !show"
+                 , class_ "no-underline hover:no-underline"] do
+                i_ [class_ "ico--menu text-3xl"] ""
+
+            div_ [ vIf_ "show || isLgScreenSize"
+                 , class_ "navbar__main navbar__section navbar__section--expandable container-padding--zero lg:container-padding--auto flex items-center"] do
+              div_ [class_ "flex-grow"] do
+                ul_ [class_ "navbar-menu text-white"] do
+                  li_ [class_ "navbar-menu__item"] do
+                    a_ [href_ "/", class_ "navbar-menu__link"] do
+                      "Statistiky"
+
+
+  appStats_ :: HtmlT Action ()
+  appStats_ = do
+    section_ [class_ "container container--default my-16"] do
+      h1_ [class_ "head-alt-md"] "Odeslané zprávy po aplikacích"
+
+      div_ [class_ "overflow-x-auto"] do
+        table_ [class_ "table my-2 w-full"] do
+          tr_ do
+            th_ [class_ "text-left"] "Aplikace"
+            th_ [class_ "text-right w-32"] "za 365 dnů"
+            th_ [class_ "text-right w-32"] "za 30 dnů"
+            th_ [class_ "text-right w-32"] "za týden"
+            th_ [class_ "text-right w-32"] "dnes"
+
+          stats <- query "select * from application_stats" ()
+
+          forM_ stats \(name, s365, s30, s7, s1) -> do
+            tr_ do
+              td_ [class_ "text-left font-bold"] do
+                a_ [phref_ ["app", name, ""]] do
+                  toHtml (name :: Text)
+
+              td_ [class_ "text-right"] $ toHtml (tshow (s365 :: Int))
+              td_ [class_ "text-right"] $ toHtml (tshow (s30 :: Int))
+              td_ [class_ "text-right"] $ toHtml (tshow (s7 :: Int))
+              td_ [class_ "text-right"] $ toHtml (tshow (s1 :: Int))
+
+
+  ccStats_ :: HtmlT Action ()
+  ccStats_ = do
+    section_ [class_ "container container--default my-16"] do
+      h1_ [class_ "head-alt-md"] "Odeslané zprávy po střediscích"
+
+      div_ [class_ "overflow-x-auto"] do
+        table_ [class_ "table my-2 w-full"] do
+          tr_ do
+            th_ [class_ "text-center w-32"] "Stř."
+            th_ [class_ "text-left"] "Popis"
+            th_ [class_ "text-right w-32"] "za 365 dnů"
+            th_ [class_ "text-right w-32"] "za 30 dnů"
+            th_ [class_ "text-right w-32"] "za týden"
+            th_ [class_ "text-right w-32"] "dnes"
+
+          stats <- query "select* from cost_centre_stats" ()
+          forM_ stats \(name, description, s365, s30, s7, s1) -> do
+            tr_ do
+              td_ [class_ "text-center font-bold"] do
+                a_ [phref_ ["cc", name, ""]] do
+                  toHtml (name :: Text)
+
+              td_ [class_ "text-left"]  $ toHtml (description :: Text)
+              td_ [class_ "text-right"] $ toHtml (tshow (s365 :: Int))
+              td_ [class_ "text-right"] $ toHtml (tshow (s30 :: Int))
+              td_ [class_ "text-right"] $ toHtml (tshow (s7 :: Int))
+              td_ [class_ "text-right"] $ toHtml (tshow (s1 :: Int))
+
+
+-- vim:set ft=haskell sw=2 ts=2 et:
diff --git a/src/Pelican/Site.hs b/src/Pelican/Site.hs
index c2f3dc4025904493538e96b2f2d589683ca5c263..1355df4db99d09e361cdefc8e930e8a2f114c71a 100644
--- a/src/Pelican/Site.hs
+++ b/src/Pelican/Site.hs
@@ -21,11 +21,12 @@ where
   import Pelican.Action
   import Pelican.API
   import Pelican.Backend
+  import Pelican.Backend.Failer
   import Pelican.Backend.Fetcher
   import Pelican.Backend.Sender
-  import Pelican.Backend.Failer
   import Pelican.Errors
   import Pelican.Model
+  import Pelican.Public
 
   import UnliftIO.Async (mapConcurrently_)
   import UnliftIO.Pool (Pool, createPool, withResource)
@@ -74,6 +75,9 @@ where
         handler NotFound notFoundR
         handler Forbidden forbiddenR
 
+        -- Register routes for the public website.
+        publicRoutes
+
         -- Register routes for the RESTful API.
         apiRoutes
 
diff --git a/src/Pelican/UI.hs b/src/Pelican/UI.hs
new file mode 100644
index 0000000000000000000000000000000000000000..24e2b759877fd1c622351c35e8074818e077e2ae
--- /dev/null
+++ b/src/Pelican/UI.hs
@@ -0,0 +1,57 @@
+-- |
+-- Module      :  Pelican.UI
+-- Copyright   :  Jan Hamal Dvořák
+-- License     :  AGPL-3.0-or-later
+--
+-- Maintainer  :  mordae@anilinux.org
+-- Stability   :  unstable
+-- Portability :  non-portable (ghc)
+--
+-- This module wraps the Pirate Styleguide 2.3.x.
+--
+
+module Pelican.UI
+  ( uiApp_
+  , uiNavbar_
+  , uiNavbarSubitem_
+  , inlineTemplate_
+  , jsClass_
+  , atClick_
+  , vIf_
+  )
+where
+  import Praha
+
+  import Lucid
+  import Lucid.Base
+
+
+  uiApp_ :: Term arg result => arg -> result
+  uiApp_ = term "ui-app"
+
+
+  uiNavbar_ :: Term arg result => arg -> result
+  uiNavbar_ = term "ui-navbar"
+
+
+  uiNavbarSubitem_ :: Term arg result => arg -> result
+  uiNavbarSubitem_ = term "ui-navbar-subitem"
+
+
+  inlineTemplate_ :: Attribute
+  inlineTemplate_ = makeAttribute "inline-template" ""
+
+
+  jsClass_ :: Text -> Attribute
+  jsClass_ = makeAttribute ":class"
+
+
+  atClick_ :: Text -> Attribute
+  atClick_ = makeAttribute "@click"
+
+
+  vIf_ :: Text -> Attribute
+  vIf_ = makeAttribute "v-if"
+
+
+-- vim:set ft=haskell sw=2 ts=2 et: