1
1
mirror of https://github.com/srid/ema.git synced 2024-11-25 20:12:20 +03:00

Allow encodeRoute (thus routeUrl) take model as argument

This commit is contained in:
Sridhar Ratnakumar 2021-06-02 20:01:24 -04:00
parent f6bbecf194
commit d366c83fc9
7 changed files with 19 additions and 18 deletions

View File

@ -15,6 +15,7 @@
- now returns relative URLs (ie. without the leading `/`)
- Use the `<base>` tag to specify an explicit prefix for relative URLs in generated HTML. This way hosting on GitHub Pages without CNAME will continue to have functional links.
- Fix: prevent encoding of non-HTML paths
- Now takes the `model` type as argument, inasmuch as `encodeRoute` takes it as as well (to accomodate scenarios where route path can only be computed depending on model state; storing slug aliases for instance)
- `Ema.Slug`
- Add `Ord`, `Generic`, `Data` and Aeson instances to `Slug`
- Unicode normalize slugs using NFC

View File

@ -7,7 +7,7 @@ module Ema.Class where
-- | Enrich a model to work with Ema
class Ema model route | route -> model where
-- | Get the filepath on disk corresponding to this route.
encodeRoute :: route -> FilePath
encodeRoute :: model -> route -> FilePath
-- | Decode a filepath on disk into a route.
decodeRoute :: model -> FilePath -> Maybe route
@ -23,7 +23,7 @@ class Ema model route | route -> model where
-- | The unit model is useful when using Ema in pure fashion (see
-- @Ema.runEmaPure@) with a single route (index.html) only.
instance Ema () () where
encodeRoute () = []
encodeRoute () () = []
decodeRoute () = \case
[] -> Just ()
_ -> Nothing

View File

@ -19,10 +19,10 @@ data Route
| About
deriving (Show, Enum, Bounded)
data Model = Model Text
newtype Model = Model {unModel :: Text}
instance Ema Model Route where
encodeRoute =
encodeRoute _model =
\case
Index -> "index.html"
About -> "about.html"
@ -39,13 +39,13 @@ main = do
liftIO $ threadDelay maxBound
render :: Ema.CLI.Action -> Model -> Route -> LByteString
render emaAction (Model s) r =
render emaAction model r =
Tailwind.layout emaAction (H.title "Basic site" >> H.base ! A.href "/") $
H.div ! A.class_ "container mx-auto" $ do
H.div ! A.class_ "mt-8 p-2 text-center" $ do
case r of
Index -> do
H.toHtml s
H.toHtml (unModel model)
"You are on the index page. "
routeElem About "Go to About"
About -> do
@ -55,4 +55,4 @@ render emaAction (Model s) r =
routeElem r' w =
H.a ! A.class_ "text-red-500 hover:underline" ! routeHref r' $ w
routeHref r' =
A.href (fromString . toString $ Ema.routeUrl r')
A.href (fromString . toString $ Ema.routeUrl model r')

View File

@ -28,7 +28,7 @@ data Route
deriving (Show, Enum, Bounded)
instance Ema UTCTime Route where
encodeRoute = \case
encodeRoute _time = \case
Index -> "index.html"
OnlyTime -> "time.html"
decodeRoute _time = \case
@ -70,7 +70,7 @@ render emaAction now r =
routeElem r' w =
H.a ! A.class_ "text-xl text-purple-500 hover:underline" ! routeHref r' $ w
routeHref r' =
A.href (fromString . toString $ Ema.routeUrl r')
A.href (fromString . toString $ Ema.routeUrl now r')
randomColor t =
let epochSecs = fromMaybe 0 . readMaybe @Int $ formatTime defaultTimeLocale "%s" t
colors = ["green", "gray", "purple", "red", "blue", "yellow", "black", "pink"]

View File

@ -6,8 +6,8 @@ module Ema.Generate where
import Control.Exception (throw)
import Control.Monad.Logger
import Ema.Asset
import Ema.Class
import Ema.Asset (Asset (..))
import Ema.Class (Ema (allRoutes, encodeRoute))
import System.Directory (copyFile, createDirectoryIfMissing, doesDirectoryExist, doesFileExist, doesPathExist)
import System.FilePath (takeDirectory, (</>))
import System.FilePattern.Directory (getDirectoryFiles)
@ -38,7 +38,7 @@ generate dest model render = do
routes <&> \r ->
case render model r of
AssetStatic fp -> Left (r, fp)
AssetGenerated _fmt s -> Right (encodeRoute r, s)
AssetGenerated _fmt s -> Right (encodeRoute model r, s)
forM_ generatedPaths $ \(relPath, !s) -> do
let fp = dest </> relPath
log LevelInfo $ toText $ "W " <> fp
@ -50,7 +50,7 @@ generate dest model render = do
True ->
-- TODO: In current branch, we don't expect this to be a directory.
-- Although the user may pass it, but review before merge.
copyDirRecursively (encodeRoute r) staticPath dest
copyDirRecursively (encodeRoute model r) staticPath dest
False ->
log LevelWarn $ toText $ "? " <> staticPath <> " (missing)"

View File

@ -19,9 +19,9 @@ import qualified Network.URI.Encode as UE
--
-- TODO: Allow a way to configure disabling stripping of .html, since not all
-- static site hosts support pretty URLs.
routeUrl :: forall r model. Ema model r => r -> Text
routeUrl =
relUrlFromPath . encodeRoute
routeUrl :: forall r model. Ema model r => model -> r -> Text
routeUrl model =
relUrlFromPath . encodeRoute model
where
relUrlFromPath :: FilePath -> Text
relUrlFromPath fp =

View File

@ -83,7 +83,7 @@ runServerWithWebSocketHotReload port model render = do
AssetGenerated Other _s ->
-- HACK: Websocket client should check for REDIRECT prefix.
-- Not bothering with JSON to avoid having to JSON parse every HTML dump.
liftIO $ WS.sendTextData conn $ "REDIRECT " <> toText (encodeRoute r)
liftIO $ WS.sendTextData conn $ "REDIRECT " <> toText (encodeRoute s r)
log LevelDebug $ " ~~> " <> show r
loop = flip runLoggingT logger $ do
-- Notice that we @askClientForRoute@ in succession twice here.
@ -134,7 +134,7 @@ runServerWithWebSocketHotReload port model render = do
let s = html <> emaStatusHtml <> wsClientShim
liftIO $ f $ Wai.responseLBS H.status200 [(H.hContentType, "text/html")] s
AssetGenerated Other s -> do
let mimeType = Static.getMimeType $ encodeRoute r
let mimeType = Static.getMimeType $ encodeRoute val r
liftIO $ f $ Wai.responseLBS H.status200 [(H.hContentType, mimeType)] s
renderCatchingErrors logger m r =
unsafeCatch (render m r) $ \(err :: SomeException) ->