···
+
(* GADT-based Tailwind HTML library with heterogeneous lists *)
+
let blue variant = Tailwind.Color.make `Blue ~variant:(match variant with
+
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
+
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
+
let gray variant = Tailwind.Color.make `Gray ~variant:(match variant with
+
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
+
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
+
let red variant = Tailwind.Color.make `Red ~variant:(match variant with
+
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
+
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
+
let green variant = Tailwind.Color.make `Green ~variant:(match variant with
+
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
+
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
+
let yellow variant = Tailwind.Color.make `Yellow ~variant:(match variant with
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
+
let indigo variant = Tailwind.Color.make `Indigo ~variant:(match variant with
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
+
let purple variant = Tailwind.Color.make `Purple ~variant:(match variant with
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
+
let pink variant = Tailwind.Color.make `Pink ~variant:(match variant with
| 50 -> `V50 | 100 -> `V100 | 200 -> `V200 | 300 -> `V300 | 400 -> `V400
| 500 -> `V500 | 600 -> `V600 | 700 -> `V700 | 800 -> `V800 | 900 -> `V900
···
let screen = Tailwind.Size.screen
let txt s = Htmlit.El.txt s
+
(* GADT for Tailwind properties with types indicating their category *)
+
| Text_color : Tailwind.Color.t -> [`Text_color] tw_prop
+
| Bg_color : Tailwind.Color.t -> [`Bg_color] tw_prop
+
| Font_size : Tailwind.Typography.font_size -> [`Font_size] tw_prop
+
| Font_weight : Tailwind.Typography.font_weight -> [`Font_weight] tw_prop
+
| Margin : Tailwind.Size.t -> [`Margin] tw_prop
+
| Margin_x : Tailwind.Size.t -> [`Margin] tw_prop
+
| Margin_y : Tailwind.Size.t -> [`Margin] tw_prop
+
| Margin_top : Tailwind.Size.t -> [`Margin] tw_prop
+
| Margin_bottom : Tailwind.Size.t -> [`Margin] tw_prop
+
| Margin_left : Tailwind.Size.t -> [`Margin] tw_prop
+
| Margin_right : Tailwind.Size.t -> [`Margin] tw_prop
+
| Padding : Tailwind.Size.t -> [`Padding] tw_prop
+
| Padding_x : Tailwind.Size.t -> [`Padding] tw_prop
+
| Padding_y : Tailwind.Size.t -> [`Padding] tw_prop
+
| Width : Tailwind.Size.t -> [`Width] tw_prop
+
| Height : Tailwind.Size.t -> [`Height] tw_prop
+
| Max_width : Tailwind.Size.t -> [`Width] tw_prop
+
| Min_height : Tailwind.Size.t -> [`Height] tw_prop
+
| Display_flex : [`Layout] tw_prop
+
| Display_block : [`Layout] tw_prop
+
| Display_inline : [`Layout] tw_prop
+
| Display_inline_block : [`Layout] tw_prop
+
| Items_center : [`Layout] tw_prop
+
| Items_start : [`Layout] tw_prop
+
| Items_end : [`Layout] tw_prop
+
| Justify_center : [`Layout] tw_prop
+
| Justify_between : [`Layout] tw_prop
+
| Justify_start : [`Layout] tw_prop
+
| Justify_end : [`Layout] tw_prop
+
| Flex_col : [`Layout] tw_prop
+
| Flex_row : [`Layout] tw_prop
+
| Text_center : [`Layout] tw_prop
+
| Text_left : [`Layout] tw_prop
+
| Text_right : [`Layout] tw_prop
+
| Rounded : [< `Sm | `Md | `Lg | `Full ] -> [`Effects] tw_prop
+
| Shadow : [< `Sm | `Md | `Lg ] -> [`Effects] tw_prop
+
| Border : [`Effects] tw_prop
+
| Border_color : Tailwind.Color.t -> [`Effects] tw_prop
+
| Transition : [`Effects] tw_prop
+
(* Heterogeneous list *)
+
type tw_list = tw_list_item list
+
and tw_list_item = Any : 'a tw_prop -> tw_list_item
+
(* Convert GADT properties to Tailwind classes *)
+
let to_tailwind_classes (props : tw_list) : Tailwind.t list =
+
let convert_prop : type a. a tw_prop -> Tailwind.t = function
+
| Text_color color -> Tailwind.Color.text color
+
| Bg_color color -> Tailwind.Color.bg color
+
| Font_size size -> Tailwind.Typography.(to_class (font_size size))
+
| Font_weight weight -> Tailwind.Typography.(to_class (font_weight weight))
+
| Margin size -> Tailwind.Spacing.(to_class (m size))
+
| Margin_x size -> Tailwind.Spacing.(to_class (mx size))
+
| Margin_y size -> Tailwind.Spacing.(to_class (my size))
+
| Margin_top size -> Tailwind.Spacing.(to_class (mt size))
+
| Margin_bottom size -> Tailwind.Spacing.(to_class (mb size))
+
| Margin_left size -> Tailwind.Spacing.(to_class (ml size))
+
| Margin_right size -> Tailwind.Spacing.(to_class (mr size))
+
| Padding size -> Tailwind.Spacing.(to_class (p size))
+
| Padding_x size -> Tailwind.Spacing.(to_class (px size))
+
| Padding_y size -> Tailwind.Spacing.(to_class (py size))
+
| Width size -> Tailwind.Layout.(to_class (width size))
+
| Height size -> Tailwind.Layout.(to_class (height size))
+
| Max_width size -> Tailwind.Layout.(to_class (max_width size))
+
| Min_height size -> Tailwind.Layout.(to_class (min_height size))
+
| Display_flex -> Tailwind.Display.flex
+
| Display_block -> Tailwind.Display.block
+
| Display_inline -> Tailwind.Display.inline
+
| Display_inline_block -> Tailwind.Display.inline_block
+
| Items_center -> Tailwind.Flexbox.(to_class (align_items `Center))
+
| Items_start -> Tailwind.Flexbox.(to_class (align_items `Start))
+
| Items_end -> Tailwind.Flexbox.(to_class (align_items `End))
+
| Justify_center -> Tailwind.Flexbox.(to_class (justify `Center))
+
| Justify_between -> Tailwind.Flexbox.(to_class (justify `Between))
+
| Justify_start -> Tailwind.Flexbox.(to_class (justify `Start))
+
| Justify_end -> Tailwind.Flexbox.(to_class (justify `End))
+
| Flex_col -> Tailwind.Flexbox.(to_class (direction `Col))
+
| Flex_row -> Tailwind.Flexbox.(to_class (direction `Row))
+
| Text_center -> Tailwind.Typography.(to_class (text_align `Center))
+
| Text_left -> Tailwind.Typography.(to_class (text_align `Left))
+
| Text_right -> Tailwind.Typography.(to_class (text_align `Right))
+
| `Sm -> Tailwind.Effects.rounded_sm
+
| `Md -> Tailwind.Effects.rounded_md
+
| `Lg -> Tailwind.Effects.rounded_lg
+
| `Full -> Tailwind.Effects.rounded_full)
+
| `Sm -> Tailwind.Effects.shadow_sm
+
| `Md -> Tailwind.Effects.shadow_md
+
| `Lg -> Tailwind.Effects.shadow_lg)
+
| Border -> Tailwind.Effects.border
+
| Border_color color -> Tailwind.Color.border color
+
| Transition -> Tailwind.Effects.transition `All
+
List.map (fun (Any prop) -> convert_prop prop) props
+
(* Convert heterogeneous list to Tailwind.t *)
+
Tailwind.Css.tw (to_tailwind_classes props)
+
(* Helper for HTML class attribute *)
+
let classes_attr props =
+
Htmlit.At.class' (Tailwind.to_string (styles props))
+
(* Helper constructors for convenient usage *)
+
let text_color c = Any (Text_color c)
+
let bg_color c = Any (Bg_color c)
+
let font_size s = Any (Font_size s)
+
let font_weight w = Any (Font_weight w)
+
let margin s = Any (Margin s)
+
let margin_x s = Any (Margin_x s)
+
let margin_y s = Any (Margin_y s)
+
let margin_top s = Any (Margin_top s)
+
let margin_bottom s = Any (Margin_bottom s)
+
let margin_left s = Any (Margin_left s)
+
let margin_right s = Any (Margin_right s)
+
let padding s = Any (Padding s)
+
let padding_x s = Any (Padding_x s)
+
let padding_y s = Any (Padding_y s)
+
let width s = Any (Width s)
+
let height s = Any (Height s)
+
let max_width s = Any (Max_width s)
+
let min_height s = Any (Min_height s)
+
let flex = Any Display_flex
+
let block = Any Display_block
+
let inline = Any Display_inline
+
let inline_block = Any Display_inline_block
+
let items_center = Any Items_center
+
let items_start = Any Items_start
+
let items_end = Any Items_end
+
let justify_center = Any Justify_center
+
let justify_between = Any Justify_between
+
let justify_start = Any Justify_start
+
let justify_end = Any Justify_end
+
let flex_col = Any Flex_col
+
let flex_row = Any Flex_row
+
let text_center = Any Text_center
+
let text_left = Any Text_left
+
let text_right = Any Text_right
+
let rounded r = Any (Rounded r)
+
let shadow s = Any (Shadow s)
+
let border = Any Border
+
let border_color c = Any (Border_color c)
+
let transition = Any Transition
+
(* GADT-based element functions *)
+
let h1 ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.h1 ~at:attrs children
+
let h2 ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.h2 ~at:attrs children
+
let h3 ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.h3 ~at:attrs children
+
let h4 ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.h4 ~at:attrs children
+
let h5 ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.h5 ~at:attrs children
+
let h6 ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.h6 ~at:attrs children
+
let p ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.p ~at:attrs children
+
let div ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.div ~at:attrs children
+
let span ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.span ~at:attrs children
+
let button ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.button ~at:attrs children
+
let a ?styles ~href children =
+
let attrs = [Htmlit.At.href href] @ (match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.a ~at:attrs children
+
let img ?styles ~src ~alt () =
+
let attrs = [Htmlit.At.src src; Htmlit.At.alt alt] @ (match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.img ~at:attrs ()
+
let ul ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.ul ~at:attrs children
+
let ol ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.ol ~at:attrs children
+
let li ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.li ~at:attrs children
+
let section ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.section ~at:attrs children
+
let article ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.article ~at:attrs children
+
let nav ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.nav ~at:attrs children
+
let header ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.header ~at:attrs children
+
let footer ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.footer ~at:attrs children
+
let main ?styles children =
+
let attrs = match styles with
+
| Some s -> [classes_attr s]
+
Htmlit.El.main ~at:attrs children
+
(* Pre-built component helpers *)
+
max_width (Tailwind.Size.rem 80.0);
let flex_center children =
+
div ~styles:[flex; items_center; justify_center] children
+
let card ?elevated children =
+
let shadow_style = if elevated = Some true then [shadow `Lg] else [shadow `Md] in
+
bg_color (Tailwind.Color.white);
+
] @ shadow_style) children
+
let btn_primary ?size children =
+
let size_styles = match size with
+
| Some `Sm -> [padding_x (rem 0.75); padding_y (rem 0.375); font_size `Sm]
+
| Some `Lg -> [padding_x (rem 2.0); padding_y (rem 0.75); font_size `Base]
+
| _ -> [padding_x (rem 1.0); padding_y (rem 0.5); font_size `Sm]
+
text_color (Tailwind.Color.white);
+
] @ size_styles) children
+
let btn_secondary ?size children =
+
let size_styles = match size with
+
| Some `Sm -> [padding_x (rem 0.75); padding_y (rem 0.375); font_size `Sm]
+
| Some `Lg -> [padding_x (rem 2.0); padding_y (rem 0.75); font_size `Base]
+
| _ -> [padding_x (rem 1.0); padding_y (rem 0.5); font_size `Sm]
+
] @ size_styles) children
+
let btn_outline ?size children =
+
let size_styles = match size with
+
| Some `Sm -> [padding_x (rem 0.75); padding_y (rem 0.375); font_size `Sm]
+
| Some `Lg -> [padding_x (rem 2.0); padding_y (rem 0.75); font_size `Base]
+
| _ -> [padding_x (rem 1.0); padding_y (rem 0.5); font_size `Sm]
+
bg_color (Tailwind.Color.transparent);
+
border_color (gray 300);
+
] @ size_styles) children