module Vdom.ToHtml ( toHtml , vdomElementToHtmlElement ) where import Color as Color import Data.Array as Array import Data.Array.NonEmpty as NonEmptyArray import Data.Map as Map import Data.Maybe (Maybe(..)) import Data.Maybe as Maybe import Data.String.NonEmpty (NonEmptyString) import Data.String.NonEmpty as NonEmptyString import Data.Tuple as Tuple import Html.Data as Html import Html.Wellknown as Wellknown import Prelude as Prelude import StructuredUrl as StructuredUrl import Type.Proxy (Proxy(..)) import Vdom.VdomPicked as Data toHtml :: forall message location. { vdom :: Data.VdomPicked message location , locationToPathAndSearchParams :: location -> StructuredUrl.PathAndSearchParams } -> Html.RawHtmlElement toHtml { vdom: vdom@(Data.VdomPicked rec), locationToPathAndSearchParams } = Wellknown.html rec.language (headElement vdom) ( Wellknown.body rec.bodyClass ( Html.ElementList ( Array.cons (noScriptElement rec.appName) ( Prelude.map ( \(Tuple.Tuple _ element) -> vdomElementToHtmlElement { origin: rec.origin , element , locationToPathAndSearchParams } ) rec.children ) ) ) ) headElement :: forall message location. Data.VdomPicked message location -> Html.RawHtmlElement headElement (Data.VdomPicked option) = Wellknown.head ( Html.ElementList ( Array.concat [ [ charsetElement , viewportElement , Wellknown.title option.pageName , descriptionElement option.description ] , case option.themeColor of Just themeColor -> [ themeColorElement themeColor ] Nothing -> [] , iconElement ( StructuredUrl.StructuredUrl { origin: option.origin , pathAndSearchParams: option.iconPath } ) , [ twitterCardElement ] , case option.path of Just path -> [ ogUrlElement ( StructuredUrl.StructuredUrl { origin: option.origin , pathAndSearchParams: path } ) ] Nothing -> [] , [ ogTitleElement option.pageName , ogSiteName option.appName , ogDescription option.description , ogImage ( StructuredUrl.StructuredUrl { origin: option.origin , pathAndSearchParams: option.coverImagePath } ) , Wellknown.style option.style ] , case option.scriptPath of Just scriptPath -> [ Wellknown.script (StructuredUrl.StructuredUrl { origin: option.origin, pathAndSearchParams: scriptPath }) ] Nothing -> [] ] ) ) charsetElement :: Html.RawHtmlElement charsetElement = Wellknown.meta (Map.singleton (NonEmptyString.nes (Proxy :: Proxy "charset")) (Just "utf-8")) viewportElement :: Html.RawHtmlElement viewportElement = Wellknown.meta ( Map.fromFoldable [ Tuple.Tuple (NonEmptyString.nes (Proxy :: Proxy "name")) (Just "viewport") , Tuple.Tuple (NonEmptyString.nes (Proxy :: Proxy "content")) ( Just "width=device-width,initial-scale=1.0" ) ] ) descriptionElement :: String -> Html.RawHtmlElement descriptionElement description = Wellknown.meta ( Map.fromFoldable [ Tuple.Tuple (NonEmptyString.nes (Proxy :: Proxy "name")) (Just "description") , contentAttribute description ] ) themeColorElement :: Color.Color -> Html.RawHtmlElement themeColorElement themeColor = Wellknown.meta ( Map.fromFoldable [ Tuple.Tuple (NonEmptyString.nes (Proxy :: Proxy "name")) (Just "theme-color") , Tuple.Tuple (NonEmptyString.nes (Proxy :: Proxy "content")) (Just (Color.toHexString themeColor)) ] ) iconElement :: StructuredUrl.StructuredUrl -> Array Html.RawHtmlElement iconElement iconUrl = let href :: String href = NonEmptyString.toString (StructuredUrl.toString iconUrl) in [ Wellknown.link "icon" href , Wellknown.link "apple-touch-icon" href ] twitterCardElement :: Html.RawHtmlElement twitterCardElement = Wellknown.meta ( Map.fromFoldable ( [ Tuple.Tuple (NonEmptyString.nes (Proxy :: Proxy "name")) (Just "twitter:card") , Tuple.Tuple (NonEmptyString.nes (Proxy :: Proxy "content")) (Just "summary_large_image") ] ) ) propertyAttribute :: String -> Tuple.Tuple NonEmptyString (Maybe.Maybe String) propertyAttribute value = Tuple.Tuple (NonEmptyString.nes (Proxy :: Proxy "property")) (Just value) contentAttribute :: String -> Tuple.Tuple NonEmptyString (Maybe.Maybe String) contentAttribute value = Tuple.Tuple (NonEmptyString.nes (Proxy :: Proxy "content")) (Just value) ogUrlElement :: StructuredUrl.StructuredUrl -> Html.RawHtmlElement ogUrlElement url = Wellknown.meta ( Map.fromFoldable [ propertyAttribute "og:url" , contentAttribute (NonEmptyString.toString (StructuredUrl.toString url)) ] ) ogTitleElement :: NonEmptyString -> Html.RawHtmlElement ogTitleElement title = Wellknown.meta ( Map.fromFoldable [ propertyAttribute "og:title" , contentAttribute (NonEmptyString.toString title) ] ) ogSiteName :: NonEmptyString -> Html.RawHtmlElement ogSiteName siteName = Wellknown.meta ( Map.fromFoldable [ propertyAttribute "og:site_name" , contentAttribute (NonEmptyString.toString siteName) ] ) ogDescription :: String -> Html.RawHtmlElement ogDescription description = Wellknown.meta ( Map.fromFoldable [ propertyAttribute "og:description" , contentAttribute description ] ) ogImage :: StructuredUrl.StructuredUrl -> Html.RawHtmlElement ogImage url = Wellknown.meta ( Map.fromFoldable [ propertyAttribute "og:image" , contentAttribute (NonEmptyString.toString (StructuredUrl.toString url)) ] ) noScriptElement :: NonEmptyString -> Html.RawHtmlElement noScriptElement appName = Wellknown.noscript ( Html.Text ( Prelude.append (NonEmptyString.toString appName) " では JavaScript を使用します. ブラウザの設定で有効にしてください." ) ) vdomElementToHtmlElement :: forall message location. { origin :: NonEmptyString , element :: Data.ElementAndClass message location , locationToPathAndSearchParams :: location -> StructuredUrl.PathAndSearchParams } -> Html.RawHtmlElement vdomElementToHtmlElement { origin, element: Data.ElementAndClass { element, class: className, id }, locationToPathAndSearchParams } = case element of Data.ElementDiv (Data.Div rec) -> Wellknown.div { id, class: className } (vdomChildrenToHtmlChildren { origin, children: rec.children, locationToPathAndSearchParams }) Data.ElementSpan (Data.Span rec) -> Wellknown.span { id, class: className } (vdomChildrenToHtmlChildren { origin, children: rec.children, locationToPathAndSearchParams }) Data.ElementH1 (Data.H1 rec) -> Wellknown.h1 { id, class: className } (vdomChildrenToHtmlChildren { origin, children: rec.children, locationToPathAndSearchParams }) Data.ElementH2 (Data.H2 rec) -> Wellknown.h2 { id, class: className } (vdomChildrenToHtmlChildren { origin, children: rec.children, locationToPathAndSearchParams }) Data.ElementCode (Data.Code rec) -> Wellknown.code { id, class: className } (vdomChildrenToHtmlChildren { origin, children: rec.children, locationToPathAndSearchParams }) Data.ElementExternalLink (Data.ExternalLink rec) -> Wellknown.a { id, class: className, href: rec.href } (vdomChildrenToHtmlChildren { origin, children: rec.children, locationToPathAndSearchParams }) Data.ElementSameOriginLink (Data.SameOriginLink rec) -> Wellknown.a { id , class: className , href: StructuredUrl.StructuredUrl { origin , pathAndSearchParams: locationToPathAndSearchParams rec.href } } (vdomChildrenToHtmlChildren { origin, children: rec.children, locationToPathAndSearchParams }) Data.ElementButton (Data.Button rec) -> Wellknown.button { id, class: className } (vdomChildrenToHtmlChildren { origin, children: rec.children, locationToPathAndSearchParams }) Data.ElementImg (Data.Img rec) -> Wellknown.img { id, class: className, alt: rec.alt, src: rec.src } Data.ElementInputRadio (Data.InputRadio rec) -> Wellknown.inputRadio { id, class: className, name: rec.name } Data.ElementInputText (Data.InputText rec) -> Wellknown.inputText { id , class: className , value: rec.value , readonly: Maybe.isNothing rec.inputOrReadonly } Data.ElementTextArea (Data.TextArea rec) -> Wellknown.textarea { id , class: className , value: rec.value , readonly: Maybe.isNothing rec.inputOrReadonly } Data.ElementLabel (Data.Label rec) -> Wellknown.label { id , class: className , for: rec.for } ( vdomChildrenToHtmlChildren { origin, children: rec.children, locationToPathAndSearchParams } ) Data.ElementSvg (Data.Svg { attributes: Data.SvgAttributes attributes, children }) -> Wellknown.svg { id , class: className , viewBox: attributes.viewBox } ( vdomChildListToHtmlChildList { origin, childList: children, locationToPathAndSearchParams } ) Data.ElementSvgPath (Data.SvgPath rec) -> Wellknown.svgPath { id , class: className , d: rec.d , fill: rec.fill } Data.ElementSvgCircle (Data.SvgCircle rec) -> Wellknown.svgCircle { id , class: className , fill: rec.fill , stroke: rec.stroke , cx: rec.cx , cy: rec.cy , r: rec.r } ( vdomChildListToHtmlChildList { origin, childList: rec.children, locationToPathAndSearchParams } ) Data.ElementSvgAnimate (Data.SvgAnimate rec) -> Wellknown.svgAnimate rec Data.ElementSvgG (Data.SvgG rec) -> Wellknown.svgG { transform: rec.transform } ( vdomChildListToHtmlChildList { origin, childList: rec.children, locationToPathAndSearchParams } ) Data.ElementSvgPolygon (Data.SvgPolygon rec) -> Wellknown.svgPolygon rec Data.ElementSvgEllipse (Data.SvgEllipse rec) -> Wellknown.svgEllipse rec Data.ElementSvgText attributes -> Wellknown.svgText attributes vdomChildrenToHtmlChildren :: forall message location. { origin :: NonEmptyString , children :: Data.Children message location , locationToPathAndSearchParams :: location -> StructuredUrl.PathAndSearchParams } -> Html.HtmlChildren vdomChildrenToHtmlChildren { origin, children, locationToPathAndSearchParams } = case children of Data.ChildrenElementList list -> Html.ElementList ( vdomChildListToHtmlChildList { origin , childList: NonEmptyArray.toArray list , locationToPathAndSearchParams } ) Data.ChildrenText text -> Html.Text text vdomChildListToHtmlChildList :: forall message location. { origin :: NonEmptyString , childList :: Array (Tuple.Tuple String (Data.ElementAndClass message location)) , locationToPathAndSearchParams :: location -> StructuredUrl.PathAndSearchParams } -> Array Html.RawHtmlElement vdomChildListToHtmlChildList { origin, childList, locationToPathAndSearchParams } = Prelude.map ( \(Tuple.Tuple _ element) -> vdomElementToHtmlElement { origin, element, locationToPathAndSearchParams } ) childList