module HTML.Showcase where
open import Agda.Builtin.String using (String)
open import Cubical.Data.Bool.Base using (true; false)
open import Cubical.Data.List.Base using ([]; _∷_)
import FF.CSS.Spec.Safe.Syntax as CSS
open import FF.HTML.Render using (render)
import FF.HTML.Spec.Safe.Selector as Select
import FF.HTML.Spec.Safe.StyleSheet as StyleSheet
open import FF.HTML.Spec.Safe.Syntax
infixr 5 _∷ˢ_
_∷ˢ_ : CSS.DeclarationT -> InlineStyle -> InlineStyle
_∷ˢ_ = styleCons
rem : String -> CSS.LengthPercentage
rem value = CSS.lp (CSS.remLength value)
px : String -> CSS.LengthPercentage
px value = CSS.lp (CSS.pxLength value)
percent : String -> CSS.LengthPercentage
percent value = CSS.pct (CSS.percent value)
size-rem : String -> CSS.PreferredSize
size-rem value = CSS.size-lp (rem value)
size-percent : String -> CSS.PreferredSize
size-percent value = CSS.size-lp (percent value)
margin-rem : String -> CSS.MarginSize
margin-rem value = CSS.margin-lp (rem value)
color-hex : String -> CSS.Color
color-hex value = CSS.hex (CSS.hexColor value)
custom-property : String -> String -> CSS.DeclarationT
custom-property name value =
CSS._:=_ (CSS.customProp name) (CSS.specific (CSS.customValue (CSS.raw value)))
bodyStyle : InlineStyle
bodyStyle =
custom-property "brand" "#195a96" ∷ˢ
custom-property "accent" "#df7b36" ∷ˢ
custom-property "surface" "#ffffff" ∷ˢ
CSS.background-color (color-hex "#f4f7fb") ∷ˢ
CSS.color (color-hex "#172033") ∷ˢ
CSS.margin (CSS.oneSide CSS.marginAuto) ∷ˢ
CSS.font-size (rem "1") ∷ˢ
styleOne (CSS._:=_ CSS.boxSizingProp (CSS.specific (CSS.boxSizingValue CSS.borderBox)))
shellStyle : InlineStyle
shellStyle =
CSS.width (size-percent "100") ∷ˢ
CSS.margin (CSS.twoSides (margin-rem "0") (margin-rem "0")) ∷ˢ
CSS.padding (CSS.twoSides (rem "2") (rem "2.5")) ∷ˢ
styleOne (CSS._:=_ CSS.maxWidthProp (CSS.specific (CSS.maxWidthValue (CSS.maxSize (CSS.sizeLengthPercentage (rem "86"))))))
barStyle : InlineStyle
barStyle =
CSS.display (CSS.displayOutsideInside CSS.outsideBlock CSS.insideFlex) ∷ˢ
CSS.gap (CSS.oneValue (CSS.gap-value (rem "1"))) ∷ˢ
CSS.padding (CSS.twoSides (rem "1") (rem "1.25")) ∷ˢ
CSS.background-color (color-hex "#ffffff") ∷ˢ
styleOne (CSS._:=_ CSS.borderRadiusProp (CSS.specific (CSS.borderRadiusValue (CSS.radiusSimple (CSS.oneSide (rem "1"))))))
heroStyle : InlineStyle
heroStyle =
CSS.display (CSS.displayOutsideInside CSS.outsideBlock CSS.insideGrid) ∷ˢ
CSS.gap (CSS.oneValue (CSS.gap-value (rem "1.5"))) ∷ˢ
CSS.padding (CSS.twoSides (rem "3") (rem "2.5")) ∷ˢ
CSS.background-color (color-hex "#e7f0ff") ∷ˢ
styleOne (CSS._:=_ CSS.borderRadiusProp (CSS.specific (CSS.borderRadiusValue (CSS.radiusSimple (CSS.oneSide (rem "1.25"))))))
cardStyle : InlineStyle
cardStyle =
CSS.background-color (color-hex "#ffffff") ∷ˢ
CSS.padding (CSS.oneSide (rem "1.25")) ∷ˢ
CSS.display (CSS.displayOutsideInside CSS.outsideBlock CSS.insideGrid) ∷ˢ
CSS.gap (CSS.oneValue (CSS.gap-value (rem "0.5"))) ∷ˢ
styleOne (CSS._:=_ CSS.borderRadiusProp (CSS.specific (CSS.borderRadiusValue (CSS.radiusSimple (CSS.oneSide (rem "0.75"))))))
mutedStyle : InlineStyle
mutedStyle =
CSS.color (color-hex "#5f6c80") ∷ˢ
styleOne (CSS.font-size (rem "0.95"))
sectionStyle : InlineStyle
sectionStyle =
CSS.display (CSS.displayOutsideInside CSS.outsideBlock CSS.insideGrid) ∷ˢ
CSS.gap (CSS.oneValue (CSS.gap-value (rem "1"))) ∷ˢ
CSS.margin (CSS.twoSides (margin-rem "2") (margin-rem "0")) ∷ˢ
styleOne (CSS.padding (CSS.twoSides (rem "1.5") (rem "0")))
controlStyle : InlineStyle
controlStyle =
CSS.width (size-percent "100") ∷ˢ
CSS.padding (CSS.twoSides (rem "0.75") (rem "0.85")) ∷ˢ
styleOne (CSS._:=_ CSS.borderRadiusProp (CSS.specific (CSS.borderRadiusValue (CSS.radiusSimple (CSS.oneSide (rem "0.5"))))))
buttonStyle : InlineStyle
buttonStyle =
CSS.background-color (color-hex "#195a96") ∷ˢ
CSS.color (color-hex "#ffffff") ∷ˢ
CSS.padding (CSS.twoSides (rem "0.75") (rem "1")) ∷ˢ
styleOne (CSS._:=_ CSS.borderRadiusProp (CSS.specific (CSS.borderRadiusValue (CSS.radiusSimple (CSS.oneSide (rem "0.5"))))))
dashboardCss : String
dashboardCss =
".topbar{justify-content:space-between;align-items:center;box-shadow:0 18px 45px rgba(25,90,150,.12)}"
++ ".nav-list{display:flex;gap:1rem;list-style:none;margin:0;padding:0}"
++ ".hero{grid-template-columns:minmax(0,1.15fr) minmax(18rem,.85fr);align-items:center}"
++ ".metrics{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));gap:1rem}"
++ ".two-col{display:grid;grid-template-columns:minmax(0,1fr) minmax(18rem,.8fr);gap:1rem}"
++ ".field{display:grid;gap:.35rem;margin-block:.75rem}"
++ "table{width:100%;border-collapse:collapse;background:#fff}"
++ "th,td{padding:.75rem;border-bottom:1px solid #d9e2ef;text-align:left}"
++ "img,video,iframe{max-width:100%;border-radius:.75rem}"
exampleStyleSheet : StyleSheet.StyleSheetT
exampleStyleSheet =
StyleSheet.sheet
( StyleSheet.rule
(Select.single (Select.compound (Select.tag bodyTag)))
( CSS.background-color (color-hex "#f4f7fb")
∷ CSS.color (color-hex "#172033")
∷ CSS.margin (CSS.oneSide CSS.marginAuto)
∷ []
)
∷ StyleSheet.rule
(Select.single (Select.compound (Select.tagWith sectionTag (Select.dataAttrEquals "stage" "stylesheet" ∷ []))))
( CSS.display (CSS.displayOutsideInside CSS.outsideBlock CSS.insideGrid)
∷ CSS.gap (CSS.oneValue (CSS.gap-value (rem "1")))
∷ CSS.padding (CSS.twoSides (rem "1.5") (rem "1.5"))
∷ CSS.background-color (color-hex "#ffffff")
∷ []
)
∷ StyleSheet.rule
(Select.single
(Select.descendantOf
(Select.compound (Select.tag navTag))
(Select.tagWith aTag (Select.typedClass "nav-link" ∷ []))))
( CSS.color (CSS.named CSS.rebeccapurple)
∷ CSS.font-size (rem "1.05")
∷ []
)
∷ StyleSheet.rule
(Select.single (Select.compound (Select.tagWith pTag (Select.typedPseudo "empty" ∷ []))))
(CSS.display (CSS.displayBox CSS.displayNone) ∷ [])
∷ []
)
exampleStyleSheetText : String
exampleStyleSheetText = StyleSheet.render exampleStyleSheet
headWithTitle : String -> HtmlT
headWithTitle titleText =
‹ head ›
void Feature.voidMeta (meta-charset "utf-8" ∷ []) ∷
void Feature.voidMeta
( meta-name "viewport"
∷ meta-content "width=device-width, initial-scale=1"
∷ []
)
∷
void Feature.voidMeta
( meta-name "theme-color"
∷ meta-content "#195a96"
∷ []
)
∷
‹ title-tag ›
text titleText ∷ []
‹/› ∷
void Feature.voidLink
( link-rel-keywords (relCons relPreload (relOne relStylesheet))
∷ link-href "/assets/console.css"
∷ link-as asStyle
∷ link-type "text/css"
∷ link-fetchpriority high
∷ []
)
∷
‹ styleTag ›
text dashboardCss ∷ []
‹/› ∷
[]
‹/›
documentHead : HtmlT
documentHead = headWithTitle "Safe HTML Operations Console"
introPage : HtmlT
introPage =
‹ html ❴ attribute langAttr (language "en") ∷ [] ❵›
headWithTitle "ff-html intro example" ∷
‹ body ❴ style-decls bodyStyle ∷ data- "example" "intro" ∷ [] ❵›
‹ main ❴ style-decls shellStyle ∷ [] ❵›
‹ h1 › text "Intro: typed nodes and attributes" ∷ [] ‹/› ∷
‹ p ❴ style-decls mutedStyle ∷ [] ❵›
text "This smallest page uses safe tags, global attributes, typed language metadata, and ff-css inline declarations." ∷ []
‹/› ∷
‹ a ❴ href "https://developer.mozilla.org/en-US/docs/Web/HTML"
∷ target blank
∷ rel-keywords (relCons relExternal (relCons relNoopener (relOne relNoreferrer)))
∷ style-decls buttonStyle
∷ [] ❵›
text "Open HTML reference" ∷ []
‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/›
semanticArticlePage : HtmlT
semanticArticlePage =
‹ html ❴ attribute langAttr (language "en") ∷ [] ❵›
headWithTitle "ff-html semantic article example" ∷
‹ body ❴ style-decls bodyStyle ∷ data- "example" "semantic-article" ∷ [] ❵›
‹ main ❴ style-decls shellStyle ∷ [] ❵›
‹ articleTag ❴ class "article-example"
∷ attribute itemtypeAttr "https://schema.org/TechArticle"
∷ attribute itemscopeAttr present
∷ style-decls cardStyle
∷ [] ❵›
‹ header ›
‹ h1 ❴ attribute itempropAttr (tokens "headline") ∷ [] ❵›
text "Semantic article with typed Safe attributes" ∷ []
‹/› ∷
‹ p ❴ style-decls mutedStyle ∷ [] ❵›
text "Published " ∷
‹ timeTag ❴ attribute (datetimeAttr datetimeTime) (dateTime "2026-06-14")
∷ attribute itempropAttr (tokens "datePublished")
∷ [] ❵›
text "14 June 2026" ∷ []
‹/› ∷
text "." ∷
[]
‹/› ∷
[]
‹/› ∷
‹ p ›
text "The example mixes " ∷
‹ codeTag › text "code" ∷ [] ‹/› ∷
text ", " ∷
‹ kbdTag › text "keyboard" ∷ [] ‹/› ∷
text ", " ∷
‹ markTag › text "highlighted" ∷ [] ‹/› ∷
text ", and quoted inline text." ∷
[]
‹/› ∷
‹ blockquoteTag ❴ attribute (citeAttr citeBlockquote) (url "https://developer.mozilla.org/en-US/docs/Web/HTML")
∷ [] ❵›
‹ p ›
text "HTML semantics are represented as ordinary typed values before rendering." ∷ []
‹/› ∷
[]
‹/› ∷
‹ olTag ❴ attribute startAttr "3"
∷ attribute olTypeAttr upperRoman
∷ [] ❵›
‹ li › text "Construct a typed tree." ∷ [] ‹/› ∷
‹ li › text "Render it with an explicit renderer." ∷ [] ‹/› ∷
‹ li › text "Check selectors and stylesheets over the same tree." ∷ [] ‹/› ∷
[]
‹/› ∷
‹ p ›
‹ delTag ❴ attribute (datetimeAttr datetimeDel) (dateTime "2026-06-01")
∷ attribute (citeAttr citeDel) (url "/notes/old")
∷ [] ❵›
text "Old wording" ∷ []
‹/› ∷
text " was replaced by " ∷
‹ insTag ❴ attribute (datetimeAttr datetimeIns) (dateTime "2026-06-14")
∷ attribute (citeAttr citeIns) (url "/notes/current")
∷ [] ❵›
text "current wording" ∷ []
‹/› ∷
text "." ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/›
selectorStyleSheetPage : HtmlT
selectorStyleSheetPage =
‹ html ❴ attribute langAttr (language "en") ∷ [] ❵›
headWithTitle "ff-html selector stylesheet example" ∷
‹ body ❴ data- "example" "selectors-and-stylesheets" ∷ [] ❵›
StyleSheet.styleElement exampleStyleSheet ∷
‹ main ❴ class "shell" ∷ [] ❵›
‹ h1 › text "Selectors and stylesheets" ∷ [] ‹/› ∷
‹ nav ❴ aria- "label" "Example sections" ∷ [] ❵›
‹ a ❴ href "#styled"
∷ class "nav-link"
∷ rel-keyword relBookmark
∷ [] ❵›
text "Styled section" ∷ []
‹/› ∷
[]
‹/› ∷
‹ section ❴ id "styled" ∷ data- "stage" "stylesheet" ∷ [] ❵›
‹ h2 › text "Matched by a typed data-* selector" ∷ [] ‹/› ∷
‹ p › text "The stylesheet on this page is built from Safe selectors and ff-css declarations." ∷ [] ‹/› ∷
‹ p › [] ‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/›
topBar : HtmlT
topBar =
‹ header ❴ class "topbar" ∷ style-decls barStyle ∷ [] ❵›
‹ div ❴ class "brand" ∷ [] ❵›
‹ h1 ❴ style-decls (CSS.margin (CSS.oneSide (margin-rem "0")) ∷ˢ styleOne (CSS.font-size (rem "1.25"))) ∷ [] ❵›
text "Operations Console" ∷ []
‹/› ∷
‹ p ❴ style-decls mutedStyle ∷ [] ❵›
text "Typed HTML composed from the Safe spec and CSS declarations." ∷ []
‹/› ∷
[]
‹/› ∷
‹ nav ❴ aria- "label" "Primary" ∷ [] ❵›
‹ ul ❴ class "nav-list" ∷ [] ❵›
‹ li › ‹ a ❴ href "#metrics" ∷ rel-keyword relBookmark ∷ [] ❵› text "Metrics" ∷ [] ‹/› ∷ [] ‹/› ∷
‹ li › ‹ a ❴ href "#intake" ∷ rel-keyword relBookmark ∷ [] ❵› text "Intake" ∷ [] ‹/› ∷ [] ‹/› ∷
‹ li › ‹ a ❴ href "#media" ∷ rel-keyword relBookmark ∷ [] ❵› text "Media" ∷ [] ‹/› ∷ [] ‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/›
hero : HtmlT
hero =
‹ section ❴ class "hero" ∷ style-decls heroStyle ∷ aria- "labelledby" "hero-title" ∷ [] ❵›
‹ div ›
‹ h1 ❴ id "hero-title" ∷ [] ❵›
text "A non-trivial page rendered from typed Agda data" ∷ []
‹/› ∷
‹ p ❴ style-decls mutedStyle ∷ [] ❵›
text "The document uses indexed HTML attributes, typed token lists, and inline CSS declarations imported from ff-css." ∷ []
‹/› ∷
‹ a ❴ href "https://developer.mozilla.org/en-US/docs/Web/HTML"
∷ target blank
∷ rel-keywords (relCons relExternal (relCons relNoopener (relOne relNoreferrer)))
∷ style-decls buttonStyle
∷ [] ❵›
text "Open MDN HTML reference" ∷ []
‹/› ∷
[]
‹/› ∷
‹ figureTag ❴ style-decls cardStyle ∷ [] ❵›
void Feature.voidImg
( src "/assets/typed-console.png"
∷ alt "Dashboard mockup with charts and form controls"
∷ img-loading eager
∷ img-fetchpriority high
∷ []
)
∷
‹ figcaptionTag ❴ style-decls mutedStyle ∷ [] ❵›
text "The image element is represented as a void element with typed media attributes." ∷ []
‹/› ∷
[]
‹/› ∷
[]
‹/›
metricCard : String -> String -> String -> HtmlT
metricCard label value detail =
‹ articleTag ❴ class "metric-card" ∷ style-decls cardStyle ∷ [] ❵›
‹ span ❴ style-decls mutedStyle ∷ [] ❵› text label ∷ [] ‹/› ∷
‹ strongTag ❴ style-decls (CSS.font-size (rem "1.8") ∷ˢ styleOne (CSS.color (color-hex "#195a96"))) ∷ [] ❵›
text value ∷ []
‹/› ∷
‹ p ❴ style-decls mutedStyle ∷ [] ❵› text detail ∷ [] ‹/› ∷
[]
‹/›
metrics : HtmlT
metrics =
‹ section ❴ id "metrics" ∷ style-decls sectionStyle ∷ aria- "labelledby" "metrics-title" ∷ [] ❵›
‹ h2 ❴ id "metrics-title" ∷ [] ❵› text "Coverage snapshot" ∷ [] ‹/› ∷
‹ div ❴ class "metrics" ∷ [] ❵›
metricCard "Tags" "115" "Active HTML elements represented." ∷
metricCard "Attributes" "126" "MDN table names covered by renderers." ∷
metricCard "Token grammars" "3" "rel, sandbox, and controlslist are typed." ∷
metricCard "CSS source" "ff-css" "Inline style declarations come from the CSS library." ∷
[]
‹/› ∷
[]
‹/›
reportTable : HtmlT
reportTable =
‹ section ❴ style-decls sectionStyle ∷ [] ❵›
‹ h2 › text "Recent formalisation work" ∷ [] ‹/› ∷
‹ table ❴ table-summary "Summary of represented HTML areas" ∷ [] ❵›
‹ caption ❴ legacy-align alignCaption "top" ∷ [] ❵›
text "HTML Safe coverage ledger" ∷ []
‹/› ∷
‹ theadTag ›
‹ tr ›
‹ th ❴ th-abbr "Area" ∷ [] ❵› text "Area" ∷ [] ‹/› ∷
‹ th ❴ th-abbr "Status" ∷ [] ❵› text "Status" ∷ [] ‹/› ∷
‹ th ❴ th-abbr "Notes" ∷ [] ❵› text "Notes" ∷ [] ‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
‹ tbody ›
‹ tr ›
‹ td › text "Elements" ∷ [] ‹/› ∷
‹ td › text "Done" ∷ [] ‹/› ∷
‹ td › text "All active MDN groups are represented." ∷ [] ‹/› ∷
[]
‹/› ∷
‹ tr ›
‹ td › text "Attributes" ∷ [] ‹/› ∷
‹ td › text "Broad partial" ∷ [] ‹/› ∷
‹ td › text "Names and rendering are covered; deeper constraints continue to grow." ∷ [] ‹/› ∷
[]
‹/› ∷
‹ tr ›
‹ td › text "CSS integration" ∷ [] ‹/› ∷
‹ td › text "Started" ∷ [] ‹/› ∷
‹ td › text "style accepts ff-css declarations through InlineStyle." ∷ [] ‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/›
intakeForm : HtmlT
intakeForm =
‹ section ❴ id "intake" ∷ class "two-col" ∷ style-decls sectionStyle ∷ [] ❵›
‹ form ❴ action "/requests"
∷ method post
∷ form-autocomplete autocompleteOn
∷ accept-charset "UTF-8"
∷ style-decls cardStyle
∷ [] ❵›
‹ h2 › text "Request intake" ∷ [] ‹/› ∷
‹ label ❴ for "requester" ∷ class "field" ∷ [] ❵›
text "Requester email" ∷
void Feature.voidInput
( input-type emailInput
∷ input-name "requester"
∷ id "requester"
∷ placeholder "[email protected]"
∷ input-autocomplete (autocompleteTokens "email")
∷ style-decls controlStyle
∷ required
∷ []
)
∷ []
‹/› ∷
‹ label ❴ for "plan" ∷ class "field" ∷ [] ❵›
text "Plan" ∷
‹ select ❴ id "plan"
∷ select-required
∷ select-autocomplete autocompleteOff
∷ style-decls controlStyle
∷ [] ❵›
‹ option › text "Starter" ∷ [] ‹/› ∷
‹ option › text "Team" ∷ [] ‹/› ∷
‹ option › text "Enterprise" ∷ [] ‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
‹ label ❴ for "notes" ∷ class "field" ∷ [] ❵›
text "Notes" ∷
‹ textarea ❴ id "notes"
∷ textarea-placeholder "Constraints, rollout window, or audit notes"
∷ textarea-required
∷ textarea-dirname "notes.dir"
∷ style-decls controlStyle
∷ [] ❵›
[]
‹/› ∷
[]
‹/› ∷
‹ button ❴ button-type submitButton
∷ button-formmethod post
∷ button-formenctype urlEncoded
∷ style-decls buttonStyle
∷ [] ❵›
text "Submit request" ∷ []
‹/› ∷
[]
‹/› ∷
‹ asideTag ❴ style-decls cardStyle ∷ [] ❵›
‹ h2 › text "Progressive controls" ∷ [] ‹/› ∷
‹ p ❴ style-decls mutedStyle ∷ [] ❵›
text "The button below targets a popover and dialog-like detail panel with typed global and element-specific attributes." ∷ []
‹/› ∷
‹ button ❴ button-type plainButton
∷ button-popovertarget "policy-popover"
∷ button-popovertargetaction togglePopover
∷ style-decls buttonStyle
∷ [] ❵›
text "Toggle policy notes" ∷ []
‹/› ∷
‹ div ❴ id "policy-popover" ∷ popover popoverManual ∷ style-decls cardStyle ∷ [] ❵›
‹ p › text "Popover state is exposed through the Safe global attribute set." ∷ [] ‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/›
mediaAndEmbeds : HtmlT
mediaAndEmbeds =
‹ section ❴ id "media" ∷ class "two-col" ∷ style-decls sectionStyle ∷ [] ❵›
‹ div ❴ style-decls cardStyle ∷ [] ❵›
‹ h2 › text "Media" ∷ [] ‹/› ∷
‹ video ❴ video-src "/media/walkthrough.mp4"
∷ video-controls
∷ video-poster "/media/walkthrough-poster.jpg"
∷ video-playsinline
∷ video-loading lazy
∷ video-controlslist-keywords (controlsCons noDownload (controlsOne noRemotePlayback))
∷ [] ❵›
[]
‹/› ∷
‹ audio ❴ audio-src "/media/summary.mp3"
∷ audio-controls
∷ audio-preload preloadMetadata
∷ audio-controlslist-keyword noDownload
∷ [] ❵›
[]
‹/› ∷
[]
‹/› ∷
‹ div ❴ style-decls cardStyle ∷ [] ❵›
‹ h2 › text "Embeds and disclosure" ∷ [] ‹/› ∷
‹ iframe ❴ iframe-src "/embed/status"
∷ iframe-loading lazy
∷ iframe-sandbox-tokens (sandboxCons allowScripts (sandboxOne allowSameOrigin))
∷ iframe-allow "fullscreen"
∷ iframe-csp "default-src 'self'"
∷ [] ❵›
[]
‹/› ∷
‹ details ❴ details-name "notes" ∷ details-open ∷ [] ❵›
‹ summary › text "Audit notes" ∷ [] ‹/› ∷
‹ p ❴ style-decls mutedStyle ∷ [] ❵›
text "Details elements have typed open/name attributes in the Safe spec." ∷ []
‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/›
webComponentTemplate : HtmlT
webComponentTemplate =
‹ template ❴ template-shadowrootmode shadowRootOpen
∷ template-shadowrootserializable
∷ template-shadowrootslotassignment namedSlotAssignment
∷ [] ❵›
‹ section ❴ style-decls cardStyle ∷ [] ❵›
‹ h2 › text "Projected detail" ∷ [] ‹/› ∷
‹ slot ❴ slot-name "detail" ∷ [] ❵›
text "Fallback detail from the template." ∷ []
‹/› ∷
[]
‹/› ∷
[]
‹/›
dashboardPage : HtmlT
dashboardPage =
‹ html ❴ attribute langAttr (language "en") ∷ [] ❵›
documentHead ∷
‹ body ❴ class "safe-html-showcase"
∷ style-decls bodyStyle
∷ data- "generated-by" "HTML.Generate"
∷ [] ❵›
‹ div ❴ class "shell" ∷ style-decls shellStyle ∷ [] ❵›
topBar ∷
hero ∷
metrics ∷
reportTable ∷
intakeForm ∷
mediaAndEmbeds ∷
webComponentTemplate ∷
‹ footerTag ❴ style-decls mutedStyle ∷ [] ❵›
text "Generated by an Agda reflection macro from typed Safe HTML." ∷ []
‹/› ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/›
componentGalleryPage : HtmlT
componentGalleryPage =
‹ html ❴ attribute langAttr (language "en") ∷ [] ❵›
documentHead ∷
‹ body ❴ style-decls bodyStyle ∷ [] ❵›
‹ main ❴ style-decls shellStyle ∷ [] ❵›
‹ h1 › text "Component gallery" ∷ [] ‹/› ∷
metrics ∷
intakeForm ∷
mediaAndEmbeds ∷
[]
‹/› ∷
[]
‹/› ∷
[]
‹/›
renderedDashboardPage : String
renderedDashboardPage = render renderer dashboardPage
renderedComponentGalleryPage : String
renderedComponentGalleryPage = render renderer componentGalleryPage