diff --git a/src/App/Page/Authentication.purs b/src/App/Page/Authentication.purs index 9f79bc6..2ad9557 100644 --- a/src/App/Page/Authentication.purs +++ b/src/App/Page/Authentication.purs @@ -206,16 +206,12 @@ render { current_tab, authenticationForm, passwordRecoveryForm, newPasswordForm, auth_form = [ Web.h3 "Authentication", render_auth_form ] passrecovery_form = [ Web.h3 "You forgot your password (or your login)" - , Web.div_content [] - [ Web.p "Enter either your login or email and you'll receive a recovery token." - ] + , Web.quote [ Web.p "Enter either your login or email and you'll receive a recovery token." ] , render_password_recovery_form ] newpass_form = [ Web.h3 "You got the password recovery mail" - , Web.div_content [] - [ Web.p "Nice! You get to choose your new password." - ] + , Web.quote [ Web.p "Nice! You get to choose your new password." ] , render_new_password_form ] diff --git a/src/App/Page/Home.purs b/src/App/Page/Home.purs index 97c288c..da3f02c 100644 --- a/src/App/Page/Home.purs +++ b/src/App/Page/Home.purs @@ -67,9 +67,9 @@ render _ = HH.div_ where url_linuxfr = "https://linuxfr.org/news/netlibre-un-service-libre-et-un-nom-de-domaine-gratuit" title = Web.h3 - expl content = Web.div_content [] [ Web.explanation content ] + expl content = Web.quote [ Web.explanation content ] p = Web.p - b x = Web.column_ [ Web.box [ Web.div_content [] x ] ] + b x = Web.column_ [ Web.box [ Web.quote x ] ] render_description = Web.columns_ [ render_basics, render_no_expert, render_no_housing ] render_update_why_and_contact = Web.columns_ [ render_updates, render_why, render_contact ] diff --git a/src/App/Page/MailValidation.purs b/src/App/Page/MailValidation.purs index 485c83e..ee64cb2 100644 --- a/src/App/Page/MailValidation.purs +++ b/src/App/Page/MailValidation.purs @@ -88,7 +88,7 @@ render { mailValidationForm } b e = Web.column_ [ Web.box e ] mail_validation_form = [ Web.h3 "Verify your account" - , Web.div_content [] [Web.explanation [Web.p "Email addresses must be validated within 30 minutes."]] + , Web.quote [Web.p "Email addresses must be validated within 30 minutes."] , render_register_form ] diff --git a/src/App/Templates/Modal.purs b/src/App/Templates/Modal.purs index c0ee50c..288c6ab 100644 --- a/src/App/Templates/Modal.purs +++ b/src/App/Templates/Modal.purs @@ -117,17 +117,17 @@ current_rr_modal selected_domain form rr_modal render_introduction_text :: AcceptedRRTypes -> HH.HTML w i render_introduction_text = case _ of - A -> Web.div_content [] [Web.explanation Explanations.a_introduction] - AAAA -> Web.div_content [] [Web.explanation Explanations.aaaa_introduction] - TXT -> Web.div_content [] [Web.explanation Explanations.txt_introduction] - CNAME -> Web.div_content [] [Web.explanation Explanations.cname_introduction] - NS -> Web.div_content [] [Web.explanation Explanations.ns_introduction] + A -> Web.quote Explanations.a_introduction + AAAA -> Web.quote Explanations.aaaa_introduction + TXT -> Web.quote Explanations.txt_introduction + CNAME -> Web.quote Explanations.cname_introduction + NS -> Web.quote Explanations.ns_introduction _ -> HH.p_ [] modal_content_mx :: Array (HH.HTML w i) modal_content_mx = [ render_errors - , Web.div_content [] [Web.explanation Explanations.mx_introduction] + , Web.quote Explanations.mx_introduction , side_text_for_name_input "domainMX" , Web.input_with_side_text "domainMX" "" "www" (action_update_form <<< Field.Domain) @@ -147,7 +147,7 @@ current_rr_modal selected_domain form rr_modal modal_content_caa :: Array (HH.HTML w i) modal_content_caa = [ render_errors - , Web.div_content [] [Web.explanation Explanations.caa_introduction] + , Web.quote Explanations.caa_introduction , side_text_for_name_input "domainCAA" , Web.input_with_side_text "domainCAA" "" "www" (action_update_form <<< Field.Domain) @@ -172,7 +172,7 @@ current_rr_modal selected_domain form rr_modal modal_content_srv :: Array (HH.HTML w i) modal_content_srv = - [ Web.div_content [] [Web.explanation Explanations.srv_introduction] + [ Web.quote Explanations.srv_introduction , render_errors , Web.box_input ("ttlSRV") "TTL" "1800" (action_update_form <<< Field.TTL) @@ -188,12 +188,12 @@ current_rr_modal selected_domain form rr_modal , Web.box_input ("portSRV") "Port of the service" "5061" (action_update_form <<< Field.Port) (maybe "" show form._rr.port) - , Web.div_content [] [Web.explanation [Web.p "The priority field is a numeric value that indicates the preference of the server (lower values indicate higher priority)."]] + , Web.quote [Web.p "The priority field is a numeric value that indicates the preference of the server (lower values indicate higher priority)."] , Web.box_input ("prioritySRV") "Priority" "10" (action_update_form <<< Field.Priority) (maybe "" show form._rr.priority) - -- Web.div_content [] [Web.explanation Explanations.spf_introduction], Web.p "Modifiers provide additional instructions, such as explanations for SPF failures or redirecting SPF checks to another domain." - , Web.div_content [] [Web.explanation [Web.p "The weight field is a relative weight used when multiple servers have the same priority, determining how often they should be used."]] + -- Web.quote Explanations.spf_introduction, Web.p "Modifiers provide additional instructions, such as explanations for SPF failures or redirecting SPF checks to another domain." + , Web.quote [Web.p "The weight field is a relative weight used when multiple servers have the same priority, determining how often they should be used."] , Web.box_input ("weightSRV") "Weight" "100" (action_update_form <<< Field.Weight) (maybe "" show form._rr.weight) @@ -201,7 +201,7 @@ current_rr_modal selected_domain form rr_modal modal_content_spf :: Array (HH.HTML w i) modal_content_spf = - [ Web.div_content [] [Web.explanation Explanations.spf_introduction] + [ Web.quote Explanations.spf_introduction , render_errors , side_text_for_name_input "domainSPF" , Web.input_with_side_text "domainSPF" "" "Let this alone." @@ -216,7 +216,7 @@ current_rr_modal selected_domain form rr_modal -- Just v -> Web.box_input "vSPF" "Version" "spf1" (action_update_form <<< Field.SPF_v) v , Web.hr , Web.box_with_tag [C.has_background_info_light] tag_mechanisms - [ Web.div_content [] [Web.explanation [Web.p "Mechanisms specify which mail servers are allowed to send mail for the domain and how to evaluate the sending mail server’s IP address."] ] + [ Web.quote [Web.p "Mechanisms specify which mail servers are allowed to send mail for the domain and how to evaluate the sending mail server’s IP address."] , maybe (Web.p "You don't have any mechanism.") (Table.display_mechanisms (action_update_rr <<< SPF_remove_mechanism)) form._rr.mechanisms , Web.hr , Web.h4 "New mechanism" @@ -229,7 +229,7 @@ current_rr_modal selected_domain form rr_modal ] , Web.hr , Web.box_with_tag [C.has_background_success_light] tag_modifiers - [ Web.div_content [] [Web.explanation [Web.p "Modifiers provide additional instructions, such as explanations for SPF failures or redirecting SPF checks to another domain."] ] + [ Web.quote [Web.p "Modifiers provide additional instructions, such as explanations for SPF failures or redirecting SPF checks to another domain."] , maybe (Web.p "You don't have any modifier.") (Table.display_modifiers (action_update_rr <<< SPF_remove_modifier)) form._rr.modifiers , Web.hr , Web.h4 "New modifier" @@ -242,7 +242,7 @@ current_rr_modal selected_domain form rr_modal , Web.hr , Web.box [ Web.h3 "Default behavior" - , Web.div_content [] [Web.explanation Explanations.spf_default_behavior] + , Web.quote Explanations.spf_default_behavior , Web.selection (action_update_rr <<< SPF_Qualifier) qualifier_types (maybe default_qualifier_str show_qualifier form._rr.q) ] ] @@ -255,7 +255,7 @@ current_rr_modal selected_domain form rr_modal modal_content_dkim :: Array (HH.HTML w i) modal_content_dkim = - [ Web.div_content [] [Web.explanation Explanations.dkim_introduction] + [ Web.quote Explanations.dkim_introduction , render_errors , side_text_for_name_input "domainDKIM" , Web.input_with_side_text "domainDKIM" "" "default._domainkey" @@ -266,7 +266,7 @@ current_rr_modal selected_domain form rr_modal (action_update_form <<< Field.TTL) (show form._rr.ttl) , Web.hr - , Web.div_content [] [Web.explanation Explanations.dkim_default_algorithms] + , Web.quote Explanations.dkim_default_algorithms , Web.selection_field "idDKIMSignature" "Signature algo" (action_update_rr <<< DKIM_sign_algo) (map show DKIM.sign_algos) @@ -281,7 +281,7 @@ current_rr_modal selected_domain form rr_modal modal_content_dmarc :: Array (HH.HTML w i) modal_content_dmarc = - [ Web.div_content [] [Web.explanation Explanations.dmarc_introduction] + [ Web.quote Explanations.dmarc_introduction , render_errors , side_text_for_name_input "domainDMARC" , Web.input_with_side_text "domainDMARC" "" "_dmarc" @@ -291,27 +291,27 @@ current_rr_modal selected_domain form rr_modal , Web.box_input "ttlDMARC" "TTL" "1800" (action_update_form <<< Field.TTL) (show form._rr.ttl) , Web.hr - , Web.div_content [] [Web.explanation Explanations.dmarc_policy] + , Web.quote Explanations.dmarc_policy , Web.selection_field' "idDMARCPolicy" "Policy" (action_update_rr <<< DMARC_policy) (A.zip DMARC.policies_txt DMARC.policies_raw) (show form.tmp.dmarc.p) - , Web.div_content [] [Web.explanation Explanations.dmarc_sp_policy] + , Web.quote Explanations.dmarc_sp_policy , Web.selection_field' "idDMARCPolicy_sp" "Policy for subdomains" (action_update_rr <<< DMARC_sp_policy) (zip_nullable DMARC.policies_txt_with_null DMARC.policies_raw) (maybe "-" show form.tmp.dmarc.sp) , Web.hr - , Web.div_content [] [Web.explanation Explanations.dmarc_adkim] + , Web.quote Explanations.dmarc_adkim , Web.selection_field' "idDMARCadkim" "Consistency Policy for DKIM" (action_update_rr <<< DMARC_adkim) (zip_nullable DMARC.consistency_policies_txt DMARC.consistency_policies_raw) (maybe "-" show form.tmp.dmarc.adkim) - , Web.div_content [] [Web.explanation Explanations.dmarc_aspf] + , Web.quote Explanations.dmarc_aspf , Web.selection_field' "idDMARCaspf" "Consistency Policy for SPF" (action_update_rr <<< DMARC_aspf) (zip_nullable DMARC.consistency_policies_txt DMARC.consistency_policies_raw) (maybe "-" show form.tmp.dmarc.aspf) , Web.hr - , Web.div_content [] [Web.explanation Explanations.dmarc_pct] + , Web.quote Explanations.dmarc_pct , Web.box_input "idDMARCpct" "Sample rate (between 0 and 100)" "100" (action_update_rr <<< DMARC_pct) (maybe "100" show form.tmp.dmarc.pct) , Web.hr @@ -320,7 +320,7 @@ current_rr_modal selected_domain form rr_modal (maybe "-" show form.tmp.dmarc.fo) , Web.hr - , Web.div_content [] [Web.explanation Explanations.dmarc_contact] + , Web.quote Explanations.dmarc_contact , Web.box_with_tag [C.has_background_info_light] tag_aggregated_reports [ maybe (Web.p "There is no address to send aggregated reports to.") (Table.display_dmarc_mail_addresses (action_update_rr <<< DMARC_remove_rua)) @@ -341,7 +341,7 @@ current_rr_modal selected_domain form rr_modal ] [] , Web.hr - , Web.div_content [] [Web.explanation Explanations.dmarc_ri] + , Web.quote Explanations.dmarc_ri , Web.box_input "idDMARCri" "Report interval (in seconds)" "86400" (action_update_rr <<< DMARC_ri) (maybe "0" show form.tmp.dmarc.ri) ] diff --git a/src/App/Text/Explanations.purs b/src/App/Text/Explanations.purs index d9752c8..9feee00 100644 --- a/src/App/Text/Explanations.purs +++ b/src/App/Text/Explanations.purs @@ -4,10 +4,8 @@ import Halogen.HTML.Properties as HP import Web as Web import CSSClasses as C -expl' :: forall w i. String -> HH.HTML w i -expl' text = expl [Web.p text] -expl :: forall w i. Array (HH.HTML w i) -> HH.HTML w i -expl content = Web.div_content [] [ Web.explanation content ] +expl :: forall w i. String -> HH.HTML w i +expl text = Web.quote [Web.p text] expl_txt :: forall w i. String -> HH.HTML w i expl_txt content = Web.explanation [ Web.p content ] @@ -17,30 +15,31 @@ col arr = Web.column_ [ Web.box arr ] tokens :: forall w i. HH.HTML w i tokens = HH.div_ [ Web.h3 "What are tokens?" - , expl' """ - Tokens are a simple way to update a resource record (A or AAAA) with your current IP address. - """ + , expl """ + Tokens are a simple way to update a resource record (A or AAAA) with your current IP address. + """ , HH.p_ [ HH.text "Let's take an example: you have an A record (IPv4) pointing to your web server at home, " , HH.text "but your ISP changes your IP address from time to time. " , HH.text "You can ask for a token (which looks like " , HH.u_ [HH.text "53be0c45-61c4-4d29-8ae9-c2cc8767603d"] , HH.text ") for this specific entry, then make your server regularly visit the following website." ] - , expl [ HH.p_ [ HH.text "https://www.netlib.re/token-update/" - , HH.u_ [HH.text ""] - ] - ] + , Web.quote + [ HH.p_ [ HH.text "https://www.netlib.re/token-update/" + , HH.u_ [HH.text ""] + ] + ] , Web.p "For example: https://www.netlib.re/token-update/53be0c45-61c4-4d29-8ae9-c2cc8767603d" , Web.hr , Web.h3 "How to automate the update of my IP address?" , Web.p "On Linux, you can make your computer access the update link with the following command." - , expl [ Web.strong "wget https://www.netlib.re/token-update/" ] + , Web.quote [ Web.strong "wget https://www.netlib.re/token-update/" ] , Web.p """ No need for a more complex program. This works just fine. And you can run this command every hour. For example, in your crontab (Linux and Unix related): """ - , expl [ Web.strong "0 * * * * wget " ] + , Web.quote [ Web.strong "0 * * * * wget " ] , Web.p """ Commands for other operating systems may differ, but you get the idea. """ @@ -50,11 +49,12 @@ tokens = HH.div_ Make sure to access the website using the related IP address. To update an IPv6 address (AAAA), force your application to access the URL using an IPv6 address. """ - , expl [ HH.p_ [ Web.strong "wget -6 " ] - , HH.p_ [ HH.text "To force the use of an IPv6 address." ] - , HH.p_ [ Web.strong "wget -4 " ] - , HH.p_ [ HH.text "To force the use of an IPv4 address." ] - ] + , Web.quote + [ HH.p_ [ Web.strong "wget -6 " ] + , HH.p_ [ HH.text "To force the use of an IPv6 address." ] + , HH.p_ [ Web.strong "wget -4 " ] + , HH.p_ [ HH.text "To force the use of an IPv4 address." ] + ] ] basics :: forall w i. HH.HTML w i @@ -69,7 +69,7 @@ basics = HH.div_ , Web.hr , Web.h3 "I have something to host (A and AAAA records)." - , expl' "Let's assume you have a web server and you host your website somewhere." + , expl "Let's assume you have a web server and you host your website somewhere." , Web.p """ You want an A (IPv4) or AAAA (IPv6) record pointing to your server, named "enigma" for example. """ @@ -94,10 +94,10 @@ basics = HH.div_ , Web.hr , Web.h3 "I want an email server." - , expl' """ - Hosting a mail server is quite complex. - This section will focus on the main parts regarding the DNS. - """ + , expl """ + Hosting a mail server is quite complex. + This section will focus on the main parts regarding the DNS. + """ , Web.notification_danger' """ The actual configuration of your mail server is complex and depends on your choice of software. This won't be covered here. @@ -111,17 +111,17 @@ basics = HH.div_ """ , Web.columns_ [ col - [ expl' """ - Spam mitigation 1: tell what are the right mail servers for your domain with Sender Policy Framework (SPF). - """ + [ expl """ + Spam mitigation 1: tell what are the right mail servers for your domain with Sender Policy Framework (SPF). + """ , expl_txt """ You need a SPF record to tell other mail servers what are the acceptable mail servers for your domain. """ ] , col - [ expl' """ - Spam mitigation 2: prove that the mails come from your mail server with DomainKeys Identified Mail (DKIM). - """ + [ expl """ + Spam mitigation 2: prove that the mails come from your mail server with DomainKeys Identified Mail (DKIM). + """ , expl_txt """ You will have to configure your mail server to sign the emails you send. This involves creating a pair of keys (public and private). @@ -131,10 +131,10 @@ basics = HH.div_ """ ] , col - [ expl' """ - Spam mitigation 3: mitigate fraud (impersonators) with Domain-based Message Authentication Reporting and Conformance (DMARC). - Tell other mail servers to only accept emails from your domain which actually are coming from your domain (SPF) and sent by your mail server (DKIM). - """ + [ expl """ + Spam mitigation 3: mitigate fraud (impersonators) with Domain-based Message Authentication Reporting and Conformance (DMARC). + Tell other mail servers to only accept emails from your domain which actually are coming from your domain (SPF) and sent by your mail server (DKIM). + """ , expl_txt """ Last but not least, DMARC. """ @@ -490,67 +490,69 @@ legal_notice = HH.div_ [ Web.h3 "Legal Notice" , Web.strong "Website Publisher" - , expl [ HH.p_ [ HH.text "You can contact this website's owner and publisher at: " - , Web.strong website_owner_address - ] - , HH.p_ [ HH.text "For legal matter: " - , Web.strong website_abuse_address - ] - ] + , Web.quote + [ HH.p_ [ HH.text "You can contact this website's owner and publisher at: " + , Web.strong website_owner_address + ] + , HH.p_ [ HH.text "For legal matter: " + , Web.strong website_abuse_address + ] + ] , Web.strong "Website Hosting" - , expl [ HH.p_ [ HH.text "This website is hosted by " - , Web.strong "Alsace Réseau Neutre" - , HH.text "." - , HH.br_ - , HH.text "Website: " - , Web.outside_link [] "https://arn-fai.net" "arn-fai.net" - , HH.br_ - , HH.text "Address & contact: " - , Web.outside_link [] "https://arn-fai.net/fr/mentions" "Legal Notice of ARN" - ] - ] + , Web.quote + [ HH.p_ [ HH.text "This website is hosted by " + , Web.strong "Alsace Réseau Neutre" + , HH.text "." + , HH.br_ + , HH.text "Website: " + , Web.outside_link [] "https://arn-fai.net" "arn-fai.net" + , HH.br_ + , HH.text "Address & contact: " + , Web.outside_link [] "https://arn-fai.net/fr/mentions" "Legal Notice of ARN" + ] + ] , Web.strong "Intellectual Property" - , expl' """ - The code of this website is released under the ISC License. You - are free to copy, modify, and distribute the code, provided - that you comply with the terms of the ISC License. - """ + , expl """ + The code of this website is released under the ISC License. You + are free to copy, modify, and distribute the code, provided + that you comply with the terms of the ISC License. + """ , Web.strong "Personal Data Collection" - , expl' """ - This website collects only the personal data necessary for its proper functioning. - This includes data such as: a login (arbitrary set of - characters), a password (that is stored encrypted), an email - to contact the owner of the domain, domain names and zone data. - """ + , expl """ + This website collects only the personal data necessary for its proper functioning. + This includes data such as: a login (arbitrary set of + characters), a password (that is stored encrypted), an email + to contact the owner of the domain, domain names and zone data. + """ , Web.strong "Data Sharing" - , expl' """ - None of the collected data will be shared to third parties. - """ + , expl """ + None of the collected data will be shared to third parties. + """ , Web.strong "Data Retention" - , expl' """ - The personal data collected on this website will be retained - for as long as necessary to fulfill the purposes for which it - was collected, including the management of user accounts. + , expl """ + The personal data collected on this website will be retained + for as long as necessary to fulfill the purposes for which it + was collected, including the management of user accounts. - However, please note that even after the deletion of your - account, your data may be retained for up to 6 months due - to technical constraints, such as backups made for disaster - recovery purposes in the event of a hardware failure. + However, please note that even after the deletion of your + account, your data may be retained for up to 6 months due + to technical constraints, such as backups made for disaster + recovery purposes in the event of a hardware failure. - This retention period is necessary to ensure the security and - integrity of our system and to allow for the restoration of - data in case of any unforeseen issues. + This retention period is necessary to ensure the security and + integrity of our system and to allow for the restoration of + data in case of any unforeseen issues. - After this period, all data will be securely deleted. - """ + After this period, all data will be securely deleted. + """ , Web.strong "Liability" - , expl + , Web.quote [ Web.p """ The publisher of this website makes every effort to ensure that @@ -586,12 +588,13 @@ legal_notice = HH.div_ ] , Web.strong "GDPR compliance" - , expl [ HH.p_ [ HH.text """ - You have the right to access, correct and delete your personal - data at any time via this website or by contacting us at the - following email address: - """ - , Web.strong website_owner_address - ] - ] + , Web.quote + [ HH.p_ [ HH.text """ + You have the right to access, correct and delete your personal + data at any time via this website or by contacting us at the + following email address: + """ + , Web.strong website_owner_address + ] + ] ] diff --git a/src/Web/Basics.purs b/src/Web/Basics.purs index 5d5baa9..d16f721 100644 --- a/src/Web/Basics.purs +++ b/src/Web/Basics.purs @@ -22,13 +22,13 @@ p_ :: forall w i. Array HH.ClassName -> String -> HH.HTML w i p_ classes str = HH.p [HP.classes classes] [ HH.text str ] ul :: forall w i. Array (HH.HTML w i) -> HH.HTML w i -ul content = HH.ul_ content +ul body = HH.ul_ body li :: forall w i. String -> HH.HTML w i -li content = li_ [] content +li body = li_ [] body li_ :: forall w i. Array HH.ClassName -> String -> HH.HTML w i -li_ classes content = HH.li [HP.classes classes] [ HH.text content ] +li_ classes body = HH.li [HP.classes classes] [ HH.text body ] strong :: forall w i. String -> HH.HTML w i strong str = HH.strong_ [ HH.text str ] @@ -37,25 +37,25 @@ hr :: forall w i. HH.HTML w i hr = HH.hr_ div :: forall w i. Array (HH.HTML w i) -> HH.HTML w i -div content = HH.div_ content +div body = HH.div_ body div_ :: forall w i. HH.Node DHI.HTMLdiv w i div_ = HH.div -div_large_content :: forall w i. Array (HH.HTML w i) -> HH.HTML w i -div_large_content content = HH.div [HP.classes [C.is_large, C.content]] content +content :: forall w i. Array (HH.HTML w i) -> HH.HTML w i +content body = HH.div [HP.classes [C.content]] body -div_content :: forall w i. Array HH.ClassName -> Array (HH.HTML w i) -> HH.HTML w i -div_content classes content = HH.div [HP.classes ([C.content] <> classes)] content +content_ :: forall w i. Array HH.ClassName -> Array (HH.HTML w i) -> HH.HTML w i +content_ classes body = HH.div [HP.classes ([C.content] <> classes)] body explanation :: forall w i. Array (HH.HTML w i) -> HH.HTML w i -explanation content = HH.blockquote [HP.classes [HH.ClassName "justified"]] content +explanation body = HH.blockquote [HP.classes [HH.ClassName "justified"]] body quote :: forall w i. Array (HH.HTML w i) -> HH.HTML w i -quote content = div_content [] [ explanation content ] +quote body = content [ explanation body ] simple_quote :: forall w i. String -> HH.HTML w i -simple_quote content = quote [ p content ] +simple_quote string = quote [ p string ] article_ :: forall w i. Array HH.ClassName -> HH.HTML w i -> HH.HTML w i -> HH.HTML w i article_ classes head body = HH.article [HP.classes $ [C.message] <> classes] @@ -67,7 +67,7 @@ article :: forall w i. HH.HTML w i -> HH.HTML w i -> HH.HTML w i article head body = article_ [] head body container :: forall w i. Array (HH.HTML w i) -> HH.HTML w i -container = HH.div [HP.classes [C.container, C.is_info]] +container body = HH.div [HP.classes [C.container, C.is_info]] body hdiv :: forall (w :: Type) (a :: Type). Array (HH.HTML w a) -> HH.HTML w a hdiv = HH.div [ HP.classes [HH.ClassName "mt-5"] ]