module Recipes where import Control.Monad.Trans.Class qualified as MT import Control.Monad.Trans.State.Strict qualified as MT import Data.ByteString.Builder qualified as Builder import Data.List qualified as List import Data.Map.Strict qualified as Map import Data.Text qualified as Text import Data.Text.Short qualified as ShortText import Graph.DOT qualified as DOT import Text.Blaze import Text.Blaze.Renderer.Utf8 qualified as Blaze import Text.Blaze.XHtml1.FrameSet qualified as H import Text.Blaze.XHtml1.FrameSet.Attributes qualified as H import Worksheets.Utils.HTML qualified as HTML import Worksheets.Utils.Prelude type Type = ShortText type Name = ShortText type Quantity = ShortText data Recipe = Recipe { recipeName :: Name , recipeFunctions :: [(Name, Function)] } data Term = TermDescr {termQuantity :: Quantity} | TermRef { termRefName :: Name , termRefPort :: Maybe Name , termRefQuantity :: Maybe Quantity } termToShortText :: Term -> ShortText termToShortText = \case TermDescr s -> s TermRef{..} -> termRefName <> (termRefPort & maybe "" (\p -> ":" <> p)) instance IsString Term where fromString = TermDescr . ShortText.pack data Function = Function { functionInputs :: Map Name Term , functionSteps :: [ShortText] , functionOutputs :: Map Name Type } data RecipeState = RecipeState { recipeStateStep :: Natural } recipeDOT :: Recipe -> Builder.Builder recipeDOT Recipe{..} = (`MT.evalState` RecipeState{recipeStateStep = 1}) $ DOT.runDOT $ do DOT.dotLine "digraph g" DOT.dotBlock do DOT.dotLine "size=\"8.267,11.7!\"" DOT.dotLine "margin=0" DOT.dotLine "nodesep=10" DOT.dotLine "ranksep=10" DOT.dotLine "rankdir=TD" DOT.dotLine "//fontnames=\"DejaVu Sans Mono,\"" DOT.dotLine "splines=true" DOT.dotLine "overlap=false" DOT.dotLine "stylesheet=\"recipe.css\"" DOT.dotLine "ratio=\"fill\"" DOT.dotLine "//graph [layout=\"dot\" fontname=\"helvetica\"];" DOT.dotLine "node [fontsize=400 shape=\"box\" style=\"plaintext\" fontname=\"Linux Libertine Capitals\"];" DOT.dotLine "edge [color=\"#aaaaaa\" fontcolor=blue penwidth=30 arrowhead=open arrowsize=20];" forM_ (recipeFunctions & ol1) \(functionNum, (functionName, Recipes.Function{..})) -> do -- step <- MT.lift $ MT.lift $ MT.state \st -> -- ( recipeStateStep st -- , st{recipeStateStep = recipeStateStep st + fromIntegral (List.length functionSteps) } -- ) DOT.dotNode (functionName & DOT.builderQuotedShortText) [ "label" := DOT.ValueHTML $ Blaze.renderMarkupBuilder $ do H.table ! H.border "0" ! H.cellspacing "0" ! H.cellpadding "0" ! H.valign "MIDDLE" ! H.customAttribute "cellborder" "0" ! H.customAttribute "rows" "*" -- ! H.customAttribute "columns" "*" $ do H.tr do H.td ! H.colspan "4" ! H.height "300" ! H.bgcolor "grey80" ! H.customAttribute "cellborder" "0" $ do H.b do xhtml1_text functionNum ! H.customAttribute "color" "blue" xhtml1_text (". " :: ShortText) xhtml1_text functionName ! H.customAttribute "color" "black" forM_ (functionInputs & Map.toList) \(inputName, inputValue) -> do H.tr do td_checkbox ! H.align "left" ! H.customAttribute "port" (inputName & ShortText.unpack & ("input-" <>) & toValue) let td_quantity = H.td ! H.valign "MIDDLE" ! H.align "right" ! H.bgcolor "white" ! H.width "0" ! H.height "100" -- ! H.customAttribute "fixedsize" "true" td_quantity do case inputValue of TermDescr{termQuantity} | termQuantity /= "" -> do -- !? ( case inputValue of -- TermDescr{} -> (False, H.customAttribute "port" "") -- TermRef{..} -> (True, termRefPort & maybe (H.customAttribute "port" "") (H.customAttribute "port" . toValue . ShortText.unpack)) -- -- " PORT="<>ShortText.unpack termRefPort -- --(isJust termRefPort, H.customAttribute "port" (termRefPort & fromMaybe "")) -- ) xhtml1_quantity termQuantity TermRef{..} | termRefQuantity & isJust -> do termRefQuantity & maybe "" \q -> do xhtml1_quantity q _ -> xhtml1_quantity "1×" H.td ! H.valign "MIDDLE" ! H.align "left" ! H.bgcolor "white" ! H.width "0" ! H.height "100" ! H.colspan "1" $ do xhtml1_text inputName H.td do "" forM_ (functionSteps & ol1) \(stepNum, stepName) -> do H.tr do td_checkbox ! H.align "left" H.td ! H.align "left" ! H.valign "MIDDLE" ! H.colspan "3" ! H.bgcolor "lightyellow" $ do H.b do xhtml1_text (" " :: ShortText) xhtml1_text (functionNum & show & ShortText.pack) ! H.customAttribute "color" "blue" xhtml1_text ("." :: ShortText) xhtml1_text (stepNum & show & ShortText.pack) xhtml1_text (". " :: ShortText) stepName & ShortText.toText & Text.lines <&> xhtml1_text & List.intersperse H.br & mconcat xhtml1_text @ShortText " " forM_ (functionOutputs & Map.toList) \(outputName, outputValue) -> do H.tr do H.td ! H.width "0" $ do "" H.td ! H.valign "MIDDLE" ! H.align "right" ! H.bgcolor "white" ! H.width "0" ! H.height "100" $ do xhtml1_quantity outputValue H.td ! H.valign "MIDDLE" ! H.align "left" ! H.bgcolor "white" ! H.width "0" ! H.height "100" $ do xhtml1_text outputName td_checkbox ! H.align "right" ! H.customAttribute "port" (outputName & ShortText.unpack & ("output-" <>) & toValue) ] forM_ recipeFunctions \(functionName, Recipes.Function{..}) -> do forM_ (functionInputs & Map.toList) \(inputName, inputTerm) -> do case inputTerm of TermDescr{} -> return () TermRef{..} -> DOT.dotEdges [ [ [termRefName & DOT.builderQuotedShortText] , termRefPort & maybeToList <&> (("output-" <>) >>> DOT.builderQuotedShortText) , ["e"] ] & mconcat & List.intersperse (Builder.charUtf8 ':') & mconcat , [ [functionName & DOT.builderQuotedShortText] , [inputName & ("input-" <>) & DOT.builderQuotedShortText] , ["w"] ] & mconcat & List.intersperse (Builder.charUtf8 ':') & mconcat ] [] td_checkbox = H.td ! H.valign "MIDDLE" ! H.bgcolor "white" ! H.width "0" ! H.height "200" -- ! H.customAttribute "fixedsize" "true" $ do H.font ! H.customAttribute "face" "Liberation Sans" ! H.customAttribute "point-size" "200" $ do "☐" xhtml1_text :: HTML.ToMarkup s => s -> _ xhtml1_text t = H.font ! H.customAttribute "face" "Linux Libertine Capitals" ! H.customAttribute "point-size" "200" $ do t & HTML.toHtml xhtml1_quantity :: ShortText -> _ xhtml1_quantity "" = return () xhtml1_quantity q = H.font ! H.customAttribute "face" "Courier" ! H.customAttribute "point-size" "200" $ do H.b do q & HTML.toHtml " " --
| ☐ 70g SucreSemoule |