From 0eb6e6ea3cdd7c0d9bc875c50d70db2c663cd695 Mon Sep 17 00:00:00 2001 From: James Brechtel Date: Wed, 27 May 2026 20:59:24 -0400 Subject: [PATCH] UI adjustments: Import link in header, matching font sizes, cook history titles, click-to-upload images - Add Import link to all page headers (landing, recipe, cook history, import) - Match ingredient list font size to recipe method text (both 15px) - Show recipe titles instead of filenames on Cook History page - Make clicking anywhere on recipe hero image/placeholder trigger file upload dialog --- src/Roux/Html.hs | 34 ++++++++++++++++++++-------------- src/Roux/Server.hs | 6 +++++- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/Roux/Html.hs b/src/Roux/Html.hs index 67ee2b5..76a097d 100644 --- a/src/Roux/Html.hs +++ b/src/Roux/Html.hs @@ -811,8 +811,11 @@ importPage :: Maybe Text -> ByteString importPage merror = page "Roux \8212 Import Recipe" $ do H.nav ! A.class_ "roux-navbar" $ do - H.ul $ H.li $ H.a ! A.href "/" $ "\8592 Back" - H.ul $ H.li $ H.strong "Import Recipe" + H.ul $ H.li $ H.a ! A.class_ "roux-logo" ! A.href "/" $ "Roux" + H.ul $ do + H.li $ H.a ! A.href "/recipes" $ "Recipes" + H.li $ H.a ! A.class_ "active" ! A.href "/import" $ "Import" + H.li $ H.a ! A.href "/cook-history" $ "Cook History" case merror of Just err -> H.p ! A.style "color: var(--roux-accent);" $ H.toHtml err Nothing -> pure () @@ -922,8 +925,8 @@ recipePageStyles = , ".rp-hero { width: 100%; aspect-ratio: 2.2; border-radius: 10px; background-size: cover; background-position: center; margin-bottom: 32px; position: relative; }" , ".rp-hero-placeholder { background: linear-gradient(135deg, #E8B86A, #C9893F 50%, #8A5A2A); cursor: pointer; display: flex; align-items: center; justify-content: center; }" , ".rp-hero-upload { font-size: 14px; color: rgba(61,44,30,0.4); }" - , ".rp-hero-overlay { position: absolute; bottom: 0; left: 0; right: 0; background: rgba(61,44,30,0.6); color: #F5EFE0; font-size: 0.7rem; text-align: center; padding: 4px 0; cursor: pointer; opacity: 0; transition: opacity 0.15s; border-radius: 0 0 10px 10px; }" - , ".rp-hero:hover .rp-hero-overlay { opacity: 1; }" + , ".rp-hero-overlay { position: absolute; top: 0; left: 0; right: 0; bottom: 0; background: rgba(61,44,30,0.4); color: #F5EFE0; font-size: 14px; display: flex; align-items: center; justify-content: center; cursor: pointer; opacity: 0; transition: opacity 0.15s; border-radius: 10px; }" + , ".rp-hero-wrap:hover .rp-hero-overlay { opacity: 1; }" , ".rp-hero-wrap { position: relative; margin-bottom: 32px; }" , ".rp-hero-wrap .rp-hero { margin-bottom: 0; }" , "" @@ -939,7 +942,7 @@ recipePageStyles = , ".rp-ingredient-row input[type=checkbox]:checked { border-color: rgba(61,44,30,0.5); }" , ".rp-ingredient-row input[type=checkbox]:checked::after { content: '\x2713'; position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); font-size: 11px; font-weight: 400; color: var(--roux-text); opacity: 0.5; line-height: 1; }" , ".rp-ingredient-row .rp-qty { color: #8A7560; min-width: 48px; font-variant-numeric: tabular-nums; transition: opacity 0.15s; }" - , ".rp-ingredient-row .name { font-size: 0.9rem; line-height: 1.5; color: var(--roux-text); transition: opacity 0.15s; }" + , ".rp-ingredient-row .name { font-size: 15px; line-height: 1.5; color: var(--roux-text); transition: opacity 0.15s; }" , ".rp-ingredient-row:has(input:checked) .rp-qty { opacity: 0.4; }" , ".rp-ingredient-row:has(input:checked) .name { opacity: 0.4; text-decoration: line-through; }" , ".rp-ing-section { font-size: 13px; font-weight: 500; color: #6B5847; margin: 16px 0 6px; letter-spacing: 0.03em; }" @@ -975,6 +978,7 @@ renderRecipe filename recipe entries = do H.a ! A.class_ "rp-logo" ! A.href "/" $ "ROUX" H.div ! A.class_ "rp-nav-links" $ do H.a ! A.href "/recipes" $ "Recipes" + H.a ! A.href "/import" $ "Import" H.a ! A.href "/cook-history" $ "Cook History" let meta = recipeMetadata recipe course = metaCourse meta @@ -1300,30 +1304,31 @@ isRight :: Either a b -> Bool isRight = not . isLeft -- | Render the cook history page (all entries across recipes). -cookHistoryPage :: [(Text, [CookLog.CookEntry])] -> ByteString -cookHistoryPage grouped = +cookHistoryPage :: (Text -> Text) -> [(Text, [CookLog.CookEntry])] -> ByteString +cookHistoryPage lookupTitle grouped = page "Cook History" $ do H.nav ! A.class_ "roux-navbar" $ do H.ul $ H.li $ H.a ! A.class_ "roux-logo" ! A.href "/" $ "Roux" H.ul $ do H.li $ H.a ! A.href "/recipes" $ "Recipes" + H.li $ H.a ! A.href "/import" $ "Import" H.li $ H.a ! A.class_ "active" ! A.href "/cook-history" $ "Cook History" H.h1 "Cook History" - mapM_ renderMonthGroup grouped + mapM_ (renderMonthGroup lookupTitle) grouped -renderMonthGroup :: (Text, [CookLog.CookEntry]) -> Html -renderMonthGroup (month, entries) = do +renderMonthGroup :: (Text -> Text) -> (Text, [CookLog.CookEntry]) -> Html +renderMonthGroup lookupTitle (month, entries) = do H.h2 $ H.toHtml month H.ul ! A.style "list-style: none; padding: 0;" $ do - mapM_ renderHistoryEntry entries + mapM_ (renderHistoryEntry lookupTitle) entries -renderHistoryEntry :: CookLog.CookEntry -> Html -renderHistoryEntry entry = do +renderHistoryEntry :: (Text -> Text) -> CookLog.CookEntry -> Html +renderHistoryEntry lookupTitle entry = do H.li ! A.style "margin-bottom: 0.5rem;" $ do H.strong $ H.toHtml (formatDay (CookLog.ceCookedDate entry)) " — " H.a ! A.href (H.toValue ("/recipes/" <> CookLog.ceRecipeFilename entry <> ".cook")) $ - H.toHtml (CookLog.ceRecipeFilename entry) + H.toHtml (lookupTitle (CookLog.ceRecipeFilename entry)) unless (T.null (CookLog.ceComment entry)) $ do H.br H.span $ H.toHtml (CookLog.ceComment entry) @@ -1417,6 +1422,7 @@ landingPage allRecipes recentlyCooked recentlyAdded = H.div ! A.class_ "lnd-nav-links" $ do H.a ! A.class_ "active" $ "Home" H.a ! A.href "/recipes" $ "Recipes" + H.a ! A.href "/import" $ "Import" H.a ! A.href "/cook-history" $ "Cook History" -- Shuffle card H.div ! A.class_ "lnd-shuffle" $ do diff --git a/src/Roux/Server.hs b/src/Roux/Server.hs index 14acc2a..c52f42b 100644 --- a/src/Roux/Server.hs +++ b/src/Roux/Server.hs @@ -667,7 +667,11 @@ handleRequest recipeDir state db request respond = do ["cook-history"] -> do entries <- CookLog.fetchAllEntries db let grouped = groupEntries entries - respond $ htmlResponse (Html.cookHistoryPage grouped) + recipeTitleLookup fn = + case Map.lookup (map toLower (stripCookExt (T.unpack fn))) recipes of + Just info -> Idx.riTitle info + Nothing -> fn + respond $ htmlResponse (Html.cookHistoryPage recipeTitleLookup grouped) -- Cook log JSON endpoint for all entries ["cook-log"] -> do entries <- CookLog.fetchAllEntries db