content: {-# LANGUAGE DataKinds #-}
  {-# LANGUAGE FlexibleContexts #-}
  {-# LANGUAGE GADTs #-}
  {-# LANGUAGE LambdaCase #-}
  {-# LANGUAGE OverloadedStrings #-}
  {-# LANGUAGE QuasiQuotes #-}
  {-# LANGUAGE Rank2Types #-}
  {-# LANGUAGE RecordWildCards #-}
  {-# LANGUAGE ScopedTypeVariables #-}
  {-# LANGUAGE TupleSections #-}
  {-# LANGUAGE TypeApplications #-}
  {-# LANGUAGE ViewPatterns #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  
  -- | HTML & CSS
  module Neuron.Frontend.View where
  
  import Control.Monad.Fix (MonadFix)
  import Data.Tagged (untag)
  import Neuron.Frontend.Common (neuronFonts)
  import qualified Neuron.Frontend.Impulse as Impulse
  import Neuron.Frontend.Route
    ( NeuronWebT,
      Route,
      routeSiteData,
      routeTitle',
    )
  import Neuron.Frontend.Route.Data.Types
  import Neuron.Frontend.Widget (LoadableData, elLinkGoogleFonts)
  import qualified Neuron.Frontend.Widget as W
  import qualified Neuron.Frontend.Zettel.View as ZettelView
  import Reflex.Dom.Core
  import Reflex.Dom.Pandoc.Raw (RawBuilder)
  import Relude
  
  headTemplate ::
    (DomBuilder t m, PostBuild t m, MonadHold t m, MonadFix m) =>
    Route a ->
    Dynamic t (LoadableData a) ->
    m ()
  headTemplate r vLDyn = do
    elAttr "meta" ("http-equiv" =: "Content-Type" <> "content" =: "text/html; charset=utf-8") blank
    elAttr "meta" ("name" =: "viewport" <> "content" =: "width=device-width, initial-scale=1") blank
    W.loadingWidget' vLDyn (el "title" $ text "Loading...") (const $ el "title" $ text "Error") $ \vDyn ->
      dyn_ $
        ffor vDyn $ \v ->
          el "title" $ text $ routeTitle r v
    elAttr "link" ("rel" =: "stylesheet" <> "href" =: "https://cdn.jsdelivr.net/npm/fomantic-ui@2.8.7/dist/semantic.min.css") blank
    elLinkGoogleFonts neuronFonts
  
  -- The `a` is used to find zettel title, and `Config` for site title.
  routeTitle :: Route a -> a -> Text
  routeTitle r v =
    let siteTitle = siteDataSiteTitle (routeSiteData v r)
     in withSuffix siteTitle (routeTitle' v r)
    where
      withSuffix suffix x =
        if x == suffix
          then x
          else x <> " - " <> suffix
  
  bodyTemplate ::
    (DomBuilder t m, PostBuild t m) =>
    Dynamic t (Maybe NeuronVersion) ->
    m () ->
    m ()
  bodyTemplate neuronVersionM w = do
    divClass "ui fluid container universe" $ do
      w
      renderBrandFooter neuronVersionM
  
  renderRouteImpulse ::
    forall t m js.
    (DomBuilder t m, PostBuild t m, MonadHold t m, MonadFix m, Prerender js t m) =>
    Dynamic t (LoadableData (SiteData, ImpulseData)) ->
    NeuronWebT t m ()
  renderRouteImpulse dataLDyn = do
    let siteData = fmap fst . W.getData <$> dataLDyn
    -- HTML for this route is all handled in JavaScript (compiled from
    -- impulse's sources).
    bodyTemplate (fmap siteDataNeuronVersion <$> siteData) $ do
      elAttr "div" ("class" =: "ui text container" <> "id" =: "zettel-container" <> "style" =: "position: relative") $ do
        Impulse.renderImpulse dataLDyn
  
  renderRouteZettel ::
    forall t m js.
    ( DomBuilder t m,
      RawBuilder m,
      PostBuild t m,
      MonadHold t m,
      MonadFix m,
      Prerender js t m
    ) =>
    Dynamic t (LoadableData (SiteData, ZettelData)) ->
    NeuronWebT t m ()
  renderRouteZettel dataLDyn = do
    let siteData = fmap fst . W.getData <$> dataLDyn
    bodyTemplate (fmap siteDataNeuronVersion <$> siteData) $ do
      W.loadingWidget dataLDyn $ \dataDyn -> do
        dyn_ $
          uncurry ZettelView.renderZettel <$> dataDyn
  
  renderBrandFooter :: (DomBuilder t m, PostBuild t m) => Dynamic t (Maybe NeuronVersion) -> m ()
  renderBrandFooter ver =
    divClass "ui center aligned container footer-version" $ do
      divClass "ui tiny image" $ do
        elAttr "a" ("href" =: "https://neuron.zettel.page") $ do
          let attr = ffor ver $ \mver ->
                "title" =: ("Generated by Neuron " <> maybe "" untag mver)
                  <> "src" =: "https://raw.githubusercontent.com/srid/neuron/master/assets/neuron.svg"
                  <> "alt" =: "logo"
          elDynAttr "img" attr blank
  