Tailwind classes in OCaml
1type t = Css.t
2
3(* Module aliases *)
4module Css = Css
5module Color = Color
6module Size = Size
7module Spacing = Spacing
8module Display = Display
9module Flexbox = Flexbox
10module Grid = Grid
11module Position = Position
12module Layout = Layout
13module Typography = Typography
14module Effects = Effects
15module Responsive = Responsive
16module Variants = Variants
17
18let tw classes = Css.concat classes
19
20let class_list pairs =
21 List.fold_left (fun acc (classes, condition) ->
22 if condition then Css.combine acc classes else acc
23 ) Css.empty pairs
24
25let to_string = Css.to_string
26
27(* Common utility patterns *)
28let flex_center =
29 tw [
30 Display.to_class Flex;
31 Flexbox.(to_class (justify Center));
32 Flexbox.(to_class (align_items Center));
33 ]
34
35let absolute_center =
36 tw [
37 Css.make "absolute";
38 Css.make "top-1/2";
39 Css.make "left-1/2";
40 Css.make "-translate-x-1/2";
41 Css.make "-translate-y-1/2";
42 ]
43
44let sr_only =
45 tw [
46 Css.make "sr-only";
47 ]
48
49let focus_ring ?color ?width () =
50 let base_classes = [
51 Css.make "focus:outline-none";
52 Css.make "focus:ring-2";
53 Css.make "focus:ring-offset-2";
54 ] in
55 let color_class = match color with
56 | Some c -> [Color.ring c]
57 | None -> [Css.make "focus:ring-blue-500"]
58 in
59 let width_class = match width with
60 | Some _ -> [] (* Could implement width variations *)
61 | None -> []
62 in
63 tw (base_classes @ color_class @ width_class)
64
65let container ?center () =
66 let base = Css.make "container" in
67 let center_class = match center with
68 | Some true -> Css.make "mx-auto"
69 | _ -> Css.empty
70 in
71 Css.combine base center_class
72
73let button_reset =
74 tw [
75 Css.make "border-0";
76 Css.make "bg-transparent";
77 Css.make "p-0";
78 Css.make "cursor-pointer";
79 ]
80
81let input_reset =
82 tw [
83 Css.make "border-0";
84 Css.make "outline-none";
85 Css.make "bg-transparent";
86 Css.make "appearance-none";
87 ]
88
89let transition transition_type =
90 let class_name = match transition_type with
91 | `None -> "transition-none"
92 | `All -> "transition-all"
93 | `Colors -> "transition-colors"
94 | `Opacity -> "transition-opacity"
95 | `Shadow -> "transition-shadow"
96 | `Transform -> "transition-transform"
97 in
98 Css.make class_name
99
100let duration ms = Css.make (Printf.sprintf "duration-%d" ms)
101
102let ease timing =
103 let class_name = match timing with
104 | `Linear -> "ease-linear"
105 | `In -> "ease-in"
106 | `Out -> "ease-out"
107 | `In_out -> "ease-in-out"
108 in
109 Css.make class_name
110
111module V4 = struct
112 let container_query size classes =
113 let container_class = match size with
114 | Responsive.Xs -> "@xs:"
115 | Responsive.Sm -> "@sm:"
116 | Responsive.Md -> "@md:"
117 | Responsive.Lg -> "@lg:"
118 | Responsive.Xl -> "@xl:"
119 | Responsive.Xl2 -> "@2xl:"
120 | Responsive.Xl3 -> "@3xl:"
121 | Responsive.Xl4 -> "@4xl:"
122 | Responsive.Xl5 -> "@5xl:"
123 | Responsive.Xl6 -> "@6xl:"
124 | Responsive.Xl7 -> "@7xl:"
125 in
126 Css.make (container_class ^ Css.to_string classes)
127
128 let starting_style classes =
129 Css.make ("@starting-style " ^ Css.to_string classes)
130
131 let text_shadow shadow_size =
132 let class_name = match shadow_size with
133 | `None -> "text-shadow-none"
134 | `Sm -> "text-shadow-sm"
135 | `Base -> "text-shadow"
136 | `Lg -> "text-shadow-lg"
137 | `Xl -> "text-shadow-xl"
138 in
139 Css.make class_name
140
141 let mask mask_type =
142 let class_name = match mask_type with
143 | `Auto -> "mask-auto"
144 | `Cover -> "mask-cover"
145 | `Contain -> "mask-contain"
146 in
147 Css.make class_name
148
149 let perspective perspective_type =
150 let class_name = match perspective_type with
151 | `None -> "perspective-none"
152 | `Distant -> "perspective-distant"
153 | `Normal -> "perspective-normal"
154 | `Near -> "perspective-near"
155 in
156 Css.make class_name
157end