-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Web Framework inspired by HTMX -- -- Web Framework inspired by HTMX. @package hyperbole @version 0.2.0 module Web.Hyperbole.Embed -- | Default CSS to remove unintuitive default styles. This or -- cssResetLink is required. -- --
-- import Data.String.Interpolate (i)
--
-- toDocument :: Text -> Text
-- toDocument cnt =
-- [i|<html>
-- <head>
-- <style type="text/css">#{cssResetEmbed}</style>
-- </head>
-- <body>#{cnt}</body>
-- </html>|]
--
cssResetEmbed :: ByteString
-- | Alternatively, the reset is available as on a CDN
--
--
-- import Data.String.Interpolate (i)
--
-- toDocument :: Text -> Text
-- toDocument cnt =
-- [i|<html>
-- <head>
-- <link rel="stylesheet" href="#{cssResetEmbed}">
-- </head>
-- <body>#{cnt}</body>
-- </html>|]
--
cssResetLink :: Text
scriptEmbed :: ByteString
module Web.Hyperbole.Route
type IsAbsolute = Bool
type Segment = Text
data Path
Path :: Bool -> [Segment] -> Path
[$sel:isAbsolute:Path] :: Path -> Bool
[$sel:segments:Path] :: Path -> [Segment]
class Route a
matchRoute :: Route a => Path -> Maybe a
routePath :: Route a => a -> Path
defRoute :: Route a => a
matchRoute :: (Route a, Generic a, GenRoute (Rep a)) => Path -> Maybe a
routePath :: (Route a, Generic a, Eq a, GenRoute (Rep a)) => a -> Path
defRoute :: (Route a, Generic a, GenRoute (Rep a)) => a
-- | Use the default route if it's empty
findRoute :: Route a => [Text] -> Maybe a
pathUrl :: Path -> Url
cleanSegment :: Segment -> Segment
pathSegments :: Text -> [Segment]
class GenRoute f
genRoute :: GenRoute f => [Text] -> Maybe (f p)
genPaths :: GenRoute f => f p -> [Text]
genFirst :: GenRoute f => f p
genRouteRead :: Read x => [Text] -> Maybe (K1 R x a)
matchRouteRead :: Read a => Path -> Maybe a
routePathShow :: Show a => a -> Path
instance GHC.Show.Show Web.Hyperbole.Route.Path
instance Web.Hyperbole.Route.Route sub => Web.Hyperbole.Route.GenRoute (GHC.Generics.K1 GHC.Generics.R sub)
instance Web.Hyperbole.Route.Route Data.Text.Internal.Text
instance Web.Hyperbole.Route.Route GHC.Base.String
instance Web.Hyperbole.Route.Route GHC.Num.Integer.Integer
instance Web.Hyperbole.Route.Route GHC.Types.Int
instance Web.Hyperbole.Route.Route a => Web.Hyperbole.Route.Route (GHC.Maybe.Maybe a)
instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.Route.GenRoute f => Web.Hyperbole.Route.GenRoute (GHC.Generics.M1 GHC.Generics.D c f)
instance forall k (c :: GHC.Generics.Meta) (f :: k -> *). (GHC.Generics.Constructor c, Web.Hyperbole.Route.GenRoute f) => Web.Hyperbole.Route.GenRoute (GHC.Generics.M1 GHC.Generics.C c f)
instance Web.Hyperbole.Route.GenRoute GHC.Generics.U1
instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.Route.GenRoute f => Web.Hyperbole.Route.GenRoute (GHC.Generics.M1 GHC.Generics.S c f)
instance forall k (a :: k -> *) (b :: k -> *). (Web.Hyperbole.Route.GenRoute a, Web.Hyperbole.Route.GenRoute b) => Web.Hyperbole.Route.GenRoute (a GHC.Generics.:+: b)
instance forall k (a :: k -> *) (b :: k -> *). (Web.Hyperbole.Route.GenRoute a, Web.Hyperbole.Route.GenRoute b) => Web.Hyperbole.Route.GenRoute (a GHC.Generics.:*: b)
instance Data.String.IsString Web.Hyperbole.Route.Path
module Web.Hyperbole.HyperView
-- | Associate a live id with a set of actions
class (Param id, Param (Action id)) => HyperView id where {
type Action id :: Type;
}
viewId :: forall id ctx. HyperView id => id -> View id () -> View ctx ()
button :: HyperView id => Action id -> Mod -> View id () -> View id ()
onRequest :: View id () -> View id () -> View id ()
-- | Internal
dataTarget :: Param a => a -> Mod
-- | Change the target of any code running inside, allowing actions to
-- target other live views on the page
target :: HyperView id => id -> View id () -> View a ()
dropdown :: HyperView id => (opt -> action) -> (opt -> Bool) -> Mod -> View (Option opt id action) () -> View id ()
option :: (HyperView id, Eq opt) => opt -> View (Option opt id (Action id)) () -> View (Option opt id (Action id)) ()
selected :: Bool -> Mod
data Option opt id action
Option :: (opt -> action) -> (opt -> Bool) -> Option opt id action
[$sel:toAction:Option] :: Option opt id action -> opt -> action
[$sel:selected:Option] :: Option opt id action -> opt -> Bool
class Param a
parseParam :: Param a => Text -> Maybe a
parseParam :: (Param a, Read a) => Text -> Maybe a
toParam :: Param a => a -> Text
toParam :: (Param a, Show a) => a -> Text
link :: Route a => a -> Mod -> View c () -> View c ()
instance Web.Hyperbole.HyperView.Param GHC.Num.Integer.Integer
instance Web.Hyperbole.HyperView.Param GHC.Types.Float
instance Web.Hyperbole.HyperView.Param GHC.Types.Int
instance Web.Hyperbole.HyperView.Param ()
instance Web.Hyperbole.HyperView.Param Data.Text.Internal.Text
module Web.Hyperbole.Effect
data Request
Request :: [Text] -> Query -> ByteString -> Request
[$sel:path:Request] :: Request -> [Text]
[$sel:query:Request] :: Request -> Query
[$sel:body:Request] :: Request -> ByteString
data Response
ErrParse :: Text -> Response
ErrNoHandler :: Response
Response :: View () () -> Response
NotFound :: Response
newtype Page es a
Page :: Eff es a -> Page es a
data Event act id
Event :: id -> act -> Event act id
[$sel:viewId:Event] :: Event act id -> id
[$sel:action:Event] :: Event act id -> act
data Hyperbole :: Effect
[GetForm] :: Hyperbole m Form
[GetEvent] :: HyperView id => Hyperbole m (Maybe (Event (Action id) id))
[Respond] :: Response -> Hyperbole m a
runHyperboleRoute :: Route route => Request -> (route -> Eff (Hyperbole : es) ()) -> Eff es Response
runHyperbole :: Request -> Eff (Hyperbole : es) a -> Eff es (Either Response a)
formData :: Hyperbole :> es => Eff es Form
notFound :: Hyperbole :> es => Eff es a
parseError :: Hyperbole :> es => Text -> Eff es a
-- | Set the response to the view. Note that page already expects a
-- view to be returned from the effect
view :: Hyperbole :> es => View () () -> Eff es ()
-- | Load the entire page when no HyperViews match
load :: Hyperbole :> es => Eff es (View () ()) -> Page es ()
-- | Handle a HyperView. If the event matches our handler, respond with the
-- fragment
hyper :: (Hyperbole :> es, HyperView id) => (id -> Action id -> Eff es (View id ())) -> Page es ()
page :: Hyperbole :> es => Page es () -> Eff es ()
instance GHC.Show.Show Web.Hyperbole.Effect.Request
instance GHC.Base.Functor (Web.Hyperbole.Effect.Page es)
instance GHC.Base.Monad (Web.Hyperbole.Effect.Page es)
instance GHC.Base.Applicative (Web.Hyperbole.Effect.Page es)
module Web.Hyperbole.Forms
-- | The only time we can use Fields is inside a form
newtype FormFields f id
FormFields :: id -> FormFields f id
-- | TODO: there are many more of these:
-- https://developer.mozilla.org/en-US/docs/Web/HTML/Attributes/autocomplete
data FieldInput
NewPassword :: FieldInput
CurrentPassword :: FieldInput
Username :: FieldInput
Email :: FieldInput
Number :: FieldInput
TextInput :: FieldInput
Name :: FieldInput
OneTimeCode :: FieldInput
Organization :: FieldInput
StreetAddress :: FieldInput
Country :: FieldInput
CountryName :: FieldInput
PostalCode :: FieldInput
Search :: FieldInput
data Label a
data Input a
Input :: Input a
newtype InputName
InputName :: Text -> InputName
field :: Mod -> View (Input id) () -> View (FormFields form id) ()
label :: Text -> View (Input id) ()
input :: FieldInput -> Mod -> InputName -> View (Input id) ()
form :: forall form id. (Form form, HyperView id) => Action id -> Mod -> (form Label -> View (FormFields form id) ()) -> View id ()
submit :: Mod -> View (FormFields form id) () -> View (FormFields form id) ()
parseForm :: forall form es. (Form form, Hyperbole :> es) => Eff es (form Identity)
class Form (form :: (Type -> Type) -> Type)
formLabels :: Form form => form Label
formLabels :: (Form form, Generic (form Label), GFormLabels (Rep (form Label))) => form Label
fromForm :: Form form => Form -> Either Text (form Identity)
fromForm :: (Form form, Generic (form Identity), GFromForm (form Identity) (Rep (form Identity))) => Form -> Either Text (form Identity)
type family Field (context :: Type -> Type) a
-- | Automatically derive labels from form field names
class GFormLabels f
gFormLabels :: GFormLabels f => f p
instance forall k (f :: k) id. GHC.Show.Show id => GHC.Show.Show (Web.Hyperbole.Forms.FormFields f id)
instance GHC.Show.Show Web.Hyperbole.Forms.FieldInput
instance Web.Hyperbole.Forms.GFormLabels GHC.Generics.U1
instance forall k (f :: k -> *) (g :: k -> *). (Web.Hyperbole.Forms.GFormLabels f, Web.Hyperbole.Forms.GFormLabels g) => Web.Hyperbole.Forms.GFormLabels (f GHC.Generics.:*: g)
instance GHC.Generics.Selector s => Web.Hyperbole.Forms.GFormLabels (GHC.Generics.M1 GHC.Generics.S s (GHC.Generics.K1 GHC.Generics.R Web.Hyperbole.Forms.InputName))
instance forall k (f :: k -> *) (d :: GHC.Generics.Meta). Web.Hyperbole.Forms.GFormLabels f => Web.Hyperbole.Forms.GFormLabels (GHC.Generics.M1 GHC.Generics.D d f)
instance forall k (f :: k -> *) (c :: GHC.Generics.Meta). Web.Hyperbole.Forms.GFormLabels f => Web.Hyperbole.Forms.GFormLabels (GHC.Generics.M1 GHC.Generics.C c f)
instance forall k id (f :: k). (Web.Hyperbole.HyperView.Param id, GHC.Show.Show id) => Web.Hyperbole.HyperView.Param (Web.Hyperbole.Forms.FormFields f id)
instance forall k id (f :: k). (Web.Hyperbole.HyperView.HyperView id, GHC.Show.Show id) => Web.Hyperbole.HyperView.HyperView (Web.Hyperbole.Forms.FormFields f id)
module Web.Hyperbole.Application
waiApplication :: Route route => (ByteString -> ByteString) -> (route -> Eff '[Hyperbole, IOE] ()) -> Application
-- | Start both a websockets and a WAI server. Wai app serves initial
-- pages, and attempt to process actions via sockets If the socket
-- connection is unavailable, will fall back to the WAI app to process
-- actions
application :: Route route => (ByteString -> ByteString) -> (route -> Eff '[Hyperbole, IOE] ()) -> Application
-- | Upgrade a websockets ServerApp to a wai
-- Application. Uses the given backup Application to handle
-- Requests that are not WebSocket requests.
--
-- -- websocketsOr opts ws_app backup_app = \req respond -> -- case websocketsApp opts ws_app req of -- Nothing -> backup_app req send_response -- Just res -> respond res ---- -- For example, below is an Application that sends "Hello, -- client!" to each connected client. -- --
-- app :: Application
-- app = websocketsOr defaultConnectionOptions wsApp backupApp
-- where
-- wsApp :: ServerApp
-- wsApp pending_conn = do
-- conn <- acceptRequest pending_conn
-- sendTextData conn ("Hello, client!" :: Text)
--
-- backupApp :: Application
-- backupApp _ respond = respond $ responseLBS status400 [] "Not a WebSocket request"
--
websocketsOr :: ConnectionOptions -> ServerApp -> Application -> Application
instance GHC.Classes.Eq Web.Hyperbole.Application.SocketError
instance GHC.Show.Show Web.Hyperbole.Application.SocketError
module Web.Hyperbole
-- | Element functions expect a Mod function as their first argument that
-- adds attributes and classes.
--
-- -- userEmail :: User -> View c () -- userEmail user = input (fontSize 16 . active) (text user.email) -- where -- active = isActive user then bold else id --type Mod = Attributes -> Attributes -- | Views are HTML fragments that carry all CSS used by any child -- element. -- --
-- view :: View c () -- view = col (pad 10 . gap 10) $ do -- el bold "Hello" -- el_ "World" ---- -- They can also have a context which can be used to create type-safe or -- context-aware elements. See table for an example data () => View context a -- | Hexidecimal Color. Can be specified with or without the leading -- #. Recommended to use an AppColor type instead of manually -- using hex colors. See ToColor newtype () => HexColor HexColor :: Text -> HexColor -- | ToColor allows you to create a type containing your application's -- colors: -- --
-- data AppColor -- = White -- | Primary -- | Dark -- -- instance ToColor AppColor where -- colorValue White = "#FFF" -- colorValue Dark = "#333" -- colorValue Primary = "#00F" -- -- hello :: View c () -- hello = el (bg Primary . color White) "Hello" --class () => ToColor a colorValue :: ToColor a => a -> HexColor colorName :: ToColor a => a -> Text newtype () => Url Url :: Text -> Url -- | Options for styles that support specifying various sides. This has a -- "fake" Num instance to support literals -- --
-- border 5 -- border (X 2) -- border (TRBL 0 5 0 0) --data () => Sides a All :: a -> Sides a TRBL :: a -> a -> a -> a -> Sides a X :: a -> Sides a Y :: a -> Sides a XY :: a -> a -> Sides a -- | Media allows for responsive designs that change based on -- characteristics of the window. See Layout Example data () => Media MinWidth :: Int -> Media MaxWidth :: Int -> Media -- | Milliseconds, used for transitions data () => Ms -- | Px, converted to Rem. Allows for the user to change the document font -- size and have the app scale accordingly. But allows the programmer to -- code in pixels to match a design data () => PxRem data () => TransitionProperty Width :: PxRem -> TransitionProperty Height :: PxRem -> TransitionProperty -- | Add text to a view. Not required for string literals -- --
-- el_ $ do -- "Hello: " -- text user.name --text :: Text -> View c () -- | Space that fills the available space in the parent row or -- col. -- --
-- row id $ do -- space -- el_ "Right" ---- -- This is equivalent to an empty element with grow -- --
-- space = el grow none --space :: View c () -- | Apply to even-numbered children even :: Mod -> Mod -- | Apply to odd-numbered children odd :: Mod -> Mod value :: Text -> Mod -- | Space surrounding the children of the element -- -- To create even spacing around and between all elements: -- --
-- col (pad 10 . gap 10) $ do -- el_ "one" -- el_ "two" -- el_ "three" --pad :: Sides PxRem -> Mod style :: Text -> View c () -- | We can intuitively create layouts with combindations of row, -- col, grow, and space -- -- Wrap main content in layout to allow the view to consume -- vertical screen space -- --
-- holygrail :: View c () -- holygrail = layout id $ do -- row section "Top Bar" -- row grow $ do -- col section "Left Sidebar" -- col (section . grow) "Main Content" -- col section "Right Sidebar" -- row section "Bottom Bar" -- where section = border 1 --layout :: Mod -> View c () -> View c () name :: Text -> Mod -- | Apply when hovering over an element -- --
-- el (bg Primary . hover (bg PrimaryLight)) "Hover" --hover :: Mod -> Mod -- | Embed static, unescaped HTML or SVG. Take care not to use raw -- with user-generated content. -- --
-- spinner = raw "<svg>...</svg>" --raw :: Text -> View c () -- | Lay out children in a row -- --
-- row id $ do -- el_ "Left" -- space -- el_ "Right" --row :: Mod -> View c () -> View c () -- | Lay out children in a column. -- --
-- col grow $ do -- el_ "Top" -- space -- el_ "Bottom" --col :: Mod -> View c () -> View c () -- | Create a type safe data table by specifying columns -- --
-- usersTable :: [User] -> View c () -- usersTable us = do -- table id us $ do -- tcol (th hd "Name") $ \u -> td cell $ text u.name -- tcol (th hd "Email") $ \u -> td cell $ text u.email -- where -- hd = cell . bold -- cell = pad 4 . border 1 --table :: Mod -> [dt] -> Eff '[Writer [TableColumn c dt]] () -> View c () -- | Default CSS to remove unintuitive default styles. This or -- cssResetLink is required. -- --
-- import Data.String.Interpolate (i)
--
-- toDocument :: Text -> Text
-- toDocument cnt =
-- [i|<html>
-- <head>
-- <style type="text/css">#{cssResetEmbed}</style>
-- </head>
-- <body>#{cnt}</body>
-- </html>|]
--
cssResetEmbed :: ByteString
-- | Alternatively, the reset is available as on a CDN
--
--
-- import Data.String.Interpolate (i)
--
-- toDocument :: Text -> Text
-- toDocument cnt =
-- [i|<html>
-- <head>
-- <link rel="stylesheet" href="#{cssResetEmbed}">
-- </head>
-- <body>#{cnt}</body>
-- </html>|]
--
cssResetLink :: Text
-- | Set to a specific width
width :: PxRem -> Mod
-- | Set to a specific height
height :: PxRem -> Mod
-- | Allow width to grow to contents but not shrink any smaller than value
minWidth :: PxRem -> Mod
-- | Allow height to grow to contents but not shrink any smaller than value
minHeight :: PxRem -> Mod
-- | The space between child elements. See pad
gap :: PxRem -> Mod
fontSize :: PxRem -> Mod
-- | Set container to be a row. Favor row when possible
flexRow :: Mod
-- | Set container to be a column. Favor col when possible
flexCol :: Mod
-- | Adds a basic drop shadow to an element
shadow :: Mod
-- | Round the corners of the element
rounded :: PxRem -> Mod
-- | Set the background color. See ToColor
bg :: ToColor c => c -> Mod
-- | Set the text color. See ToColor
color :: ToColor c => c -> Mod
bold :: Mod
-- | Hide an element. See parent and media
hide :: Mod
-- | Set a border around the element
--
-- -- el (border 1) "all sides" -- el (border (X 1)) "only left and right" --border :: Sides PxRem -> Mod -- | Set a border color. See ToColor borderColor :: ToColor c => c -> Mod -- | Use a button-like cursor when hovering over the element -- -- Button-like elements: -- --
-- btn = pointer . bg Primary . hover (bg PrimaryLight) -- -- options = row id $ do -- el btn "Login" -- el btn "Sign Up" --pointer :: Mod -- | Animate changes to the given property -- --
-- el (transition 100 (Height 400)) "Tall" -- el (transition 100 (Height 100)) "Small" --transition :: Ms -> TransitionProperty -> Mod textAlign :: Align -> Mod -- | Apply when the mouse is pressed down on an element active :: Mod -> Mod -- | Apply when the Media matches the current window. This allows for -- responsive designs -- --
-- el (width 100 . media (MinWidth 800) (width 400)) -- "Big if window > 800" --media :: Media -> Mod -> Mod -- | Apply when the element is somewhere inside an anscestor. -- -- For example, the HTMX library applies an "htmx-request" class to the -- body when a request is pending. We can use this to create a loading -- indicator -- --
-- el (pad 10) $ do -- el (parent "htmx-request" flexRow . hide) "Loading..." -- el (parent "htmx-request" hide . flexRow) "Normal Content" --parent :: Text -> Mod -> Mod -- | Get the current context context :: View context context -- | Run a view with a specific context in a parent View with -- a different context. This can be used to create type safe view -- functions, like table addContext :: context -> View context () -> View c () -- | Create a new element constructor -- --
-- aside :: Mod -> View c () -> View c () -- aside = tag "aside" --tag :: Text -> Mod -> View c () -> View c () -- | Set an attribute, replacing existing value -- --
-- hlink :: Text -> View c () -> View c () -- hlink url content = tag "a" (att "href" url) content --att :: Name -> AttValue -> Mod -- | Renders a View as HTML with embedded CSS class definitions -- --
-- >>> renderText $ el bold "Hello"
-- <style type='text/css'>.bold { font-weight:bold }</style>
-- <div class='bold'>Hello</div>
--
renderText :: View () () -> Text
renderLazyText :: View () () -> Text
renderLazyByteString :: View () () -> ByteString
-- | A basic element
--
-- -- el (bold . pad 10) "Hello" --el :: Mod -> View c () -> View c () -- | A basic element, with no modifiers -- --
-- el_ "Hello" --el_ :: View c () -> View c () -- | Do not show any content -- --
-- if isVisible -- then content -- else none --none :: View c () pre :: Mod -> Text -> View c () script :: Text -> View c () stylesheet :: Text -> View c () tcol :: forall dt c. View (TableHead c) () -> (dt -> View dt ()) -> Eff '[Writer [TableColumn c dt]] () th :: Mod -> View c () -> View (TableHead c) () td :: Mod -> View () () -> View dt () -- | As layout but as a Mod -- --
-- holygrail = col root $ do -- ... --root :: Mod -- | Grow to fill the available space in the parent row or -- col -- --
-- row id $ do -- el grow none -- el_ "Right" --grow :: Mod -- | Allow items to become smaller than their contents. This is not the -- opposite of grow! collapse :: Mod -- | Make a fixed layout by putting scroll on a child-element -- --
-- document = row root $ do -- nav (width 300) "Sidebar" -- col (grow . scroll) "Main Content" --scroll :: Mod -- | A Nav element nav :: Mod -> View c () -> View c () -- | The WAI application. -- -- Note that, since WAI 3.0, this type is structured in continuation -- passing style to allow for proper safe resource handling. This was -- handled in the past via other means (e.g., ResourceT). As a -- demonstration: -- --
-- app :: Application -- app req respond = bracket_ -- (putStrLn "Allocating scarce resource") -- (putStrLn "Cleaning up") -- (respond $ responseLBS status200 [] "Hello World") --type Application = Request -> Response -> IO ResponseReceived -> IO ResponseReceived -- | Run an Application on the given port. This calls -- runSettings with defaultSettings. run :: Port -> Application -> IO () scriptEmbed :: ByteString