diff --git a/src/Roux/Html.hs b/src/Roux/Html.hs
index c13074b..43e59af 100644
--- a/src/Roux/Html.hs
+++ b/src/Roux/Html.hs
@@ -329,6 +329,39 @@ searchJs =
, "})();"
]
+-- ---------------------------------------------------------------------------
+-- SSE live-reload scripts
+-- ---------------------------------------------------------------------------
+
+-- | Inline JavaScript for SSE live-reload on the recipe detail page.
+sseRecipeJs :: Text
+sseRecipeJs =
+ T.unlines
+ [ "(function(){"
+ , "'use strict';"
+ , "if (!window.EventSource) return;"
+ , "var el = document.getElementById('roux-current-recipe');"
+ , "if (!el) return;"
+ , "var currentRecipe = el.textContent;"
+ , "var es = new EventSource('/events');"
+ , "es.addEventListener('recipe-changed', function(e) {"
+ , " if (e.data === currentRecipe) location.reload();"
+ , "});"
+ , "})();"
+ ]
+
+-- | Inline JavaScript for SSE live-reload on the index page.
+sseIndexJs :: Text
+sseIndexJs =
+ T.unlines
+ [ "(function(){"
+ , "'use strict';"
+ , "if (!window.EventSource) return;"
+ , "var es = new EventSource('/events');"
+ , "es.addEventListener('recipe-changed', function() { location.reload(); });"
+ , "})();"
+ ]
+
-- | Render the recipe index page -- shell with embedded JSON + JS rendering.
indexPage :: SortMode -> [Idx.RecipeInfo] -> ByteString
indexPage _mode recipes =
@@ -356,6 +389,8 @@ indexPage _mode recipes =
H.toHtml (decodeUtf8 (LB.toStrict (Fleece.encode (Fleece.encoder (FC.list Idx.recipeSearchEntrySchema)) (Prelude.map Idx.toSearchEntry (filterBad recipes)))))
-- Inline JS
H.script ! A.type_ "text/javascript" $ H.preEscapedText searchJs
+ -- Inline JS for SSE live-reload
+ H.script ! A.type_ "text/javascript" $ H.preEscapedText sseIndexJs
where
filterOk = filter (isRight . Idx.riRecipe)
filterBad = filter (isLeft . Idx.riRecipe)
@@ -368,9 +403,19 @@ recipePage info =
H.nav $ H.ul $ H.li $ H.a ! A.href "/" $ "← Back"
H.h2 "Parse Error"
H.p $ H.toHtml (Idx.riTitle info <> ": " <> T.pack err)
+ hiddenRecipeSpan info
+ sseScript
Right recipe ->
- page (titleText recipe) $
+ page (titleText recipe) $ do
renderRecipe recipe
+ hiddenRecipeSpan info
+ sseScript
+ where
+ hiddenRecipeSpan rInfo =
+ H.span ! A.id "roux-current-recipe" ! A.style "display: none;" $
+ H.toHtml (T.pack (Idx.riFilename rInfo))
+ sseScript =
+ H.script ! A.type_ "text/javascript" $ H.preEscapedText sseRecipeJs
-- | Render the body of a recipe page (no page shell).
renderRecipe :: Recipe -> Html