Bugs fixed: - line-through: check full token not just head after hyphen split - gap-x-N/gap-y-N: compound 2-part spacing prefix handler in tw-layout - Negative values (-mt-4): replace ":" with ":-" instead of no-op - Class name doubling: chain replace calls instead of concatenating New features in tw-process-token: - !important modifier (!p-4 → padding:1rem !important) - dark: variant (class-based, .dark ancestor selector) - group-hover:/group-focus:/group-active: (parent state) - peer-focus:/peer-hover:/peer-checked:/peer-disabled: (sibling state) - @container queries (@md:flex → @container(min-width:448px)) - Colour opacity modifier (bg-sky-500/50 → hsl with alpha) - Ring colours (ring-sky-500 → --tw-ring-color) - Arbitrary values (w-[300px], grid-cols-[1fr_2fr], bg-[#ff0000]) - colour-with-alpha helper for HSL+alpha generation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
552 lines
20 KiB
Plaintext
552 lines
20 KiB
Plaintext
(define colour-bases {:orange {:s 95 :h 25} :cyan {:s 94 :h 188} :sky {:s 89 :h 199} :pink {:s 81 :h 330} :zinc {:s 5 :h 240} :amber {:s 92 :h 38} :neutral {:s 0 :h 0} :lime {:s 78 :h 84} :violet {:s 70 :h 263} :fuchsia {:s 84 :h 292} :stone {:s 6 :h 25} :black {:s 0 :h 0} :teal {:s 80 :h 173} :gray {:s 9 :h 220} :red {:s 72 :h 0} :rose {:s 89 :h 350} :blue {:s 91 :h 217} :emerald {:s 84 :h 160} :green {:s 71 :h 142} :yellow {:s 96 :h 48} :purple {:s 81 :h 271} :indigo {:s 84 :h 239} :white {:s 0 :h 0} :slate {:s 16 :h 215}})
|
|
|
|
(define
|
|
colour-with-alpha
|
|
(fn
|
|
(name shade alpha)
|
|
(let
|
|
((base (get colour-bases name)))
|
|
(if
|
|
(nil? base)
|
|
name
|
|
(let
|
|
((h (get base "h"))
|
|
(s (get base "s"))
|
|
(l (shade-to-lightness shade)))
|
|
(str "hsl(" h "," s "%," (round l) "%," alpha ")"))))))
|
|
|
|
(define lerp (fn (a b t) (+ a (* t (- b a)))))
|
|
|
|
(define
|
|
shade-to-lightness
|
|
(fn
|
|
(shade)
|
|
(cond
|
|
(<= shade 50)
|
|
(lerp 100 97 (/ shade 50))
|
|
(<= shade 100)
|
|
(lerp 97 93 (/ (- shade 50) 50))
|
|
(<= shade 200)
|
|
(lerp 93 87 (/ (- shade 100) 100))
|
|
(<= shade 300)
|
|
(lerp 87 77 (/ (- shade 200) 100))
|
|
(<= shade 400)
|
|
(lerp 77 64 (/ (- shade 300) 100))
|
|
(<= shade 500)
|
|
(lerp 64 53 (/ (- shade 400) 100))
|
|
(<= shade 600)
|
|
(lerp 53 45 (/ (- shade 500) 100))
|
|
(<= shade 700)
|
|
(lerp 45 38 (/ (- shade 600) 100))
|
|
(<= shade 800)
|
|
(lerp 38 30 (/ (- shade 700) 100))
|
|
(<= shade 900)
|
|
(lerp 30 21 (/ (- shade 800) 100))
|
|
(<= shade 950)
|
|
(lerp 21 13 (/ (- shade 900) 50))
|
|
:else 13)))
|
|
|
|
(define
|
|
colour
|
|
(fn
|
|
(name shade)
|
|
(let
|
|
((base (get colour-bases name)))
|
|
(if
|
|
(nil? base)
|
|
name
|
|
(if
|
|
(= name "white")
|
|
"#ffffff"
|
|
(if
|
|
(= name "black")
|
|
"#000000"
|
|
(let
|
|
((h (get base "h"))
|
|
(s (get base "s"))
|
|
(l (shade-to-lightness shade)))
|
|
(str "hsl(" h "," s "%," (round l) "%)"))))))))
|
|
|
|
(define tw-colour-props {:ring "--tw-ring-color" :outline "outline-color" :bg "background-color" :accent "accent-color" :border "border-color" :stroke "stroke" :text "color" :fill "fill"})
|
|
|
|
(define tw-breakpoints {:sm "640px" :xl "1280px" :md "768px" :lg "1024px" :2xl "1536px"})
|
|
|
|
(define tw-states {:focus ":focus" :before "::before" :first ":first-child" :disabled ":disabled" :required ":required" :even ":nth-child(even)" :hover ":hover" :focus-visible ":focus-visible" :last ":last-child" :visited ":visited" :odd ":nth-child(odd)" :active ":active" :focus-within ":focus-within" :checked ":checked" :placeholder "::placeholder" :after "::after"})
|
|
|
|
(define tw-selector-states {:group-hover ".group:hover " :peer-disabled ".peer:disabled~" :dark ".dark " :peer-hover ".peer:hover~" :group-focus-within ".group:focus-within " :peer-checked ".peer:checked~" :group-focus ".group:focus " :group-active ".group:active " :peer-invalid ".peer:invalid~" :peer-required ".peer:required~" :peer-focus ".peer:focus~"})
|
|
|
|
(define tw-container-sizes {:xs "320px" :3xl "768px" :7xl "1280px" :sm "384px" :xl "576px" :md "448px" :6xl "1152px" :5xl "1024px" :lg "512px" :2xl "672px" :4xl "896px"})
|
|
|
|
(define
|
|
tw-spacing-value
|
|
(fn
|
|
(v)
|
|
(cond
|
|
(= v "auto")
|
|
"auto"
|
|
(= v "px")
|
|
"1px"
|
|
(= v "0")
|
|
"0px"
|
|
(= v "0.5")
|
|
"0.125rem"
|
|
(= v "1.5")
|
|
"0.375rem"
|
|
(= v "2.5")
|
|
"0.625rem"
|
|
(= v "3.5")
|
|
"0.875rem"
|
|
:else (let
|
|
((n (parse-int v nil)))
|
|
(if (nil? n) nil (str (* n 0.25) "rem"))))))
|
|
|
|
(define
|
|
tw-template
|
|
(fn
|
|
(tmpl v)
|
|
(let
|
|
((i (index-of tmpl "{v}")))
|
|
(if
|
|
(< i 0)
|
|
tmpl
|
|
(let
|
|
((result (str (substring tmpl 0 i) v (substring tmpl (+ i 3) (len tmpl)))))
|
|
(let
|
|
((j (index-of result "{v}")))
|
|
(if
|
|
(< j 0)
|
|
result
|
|
(str
|
|
(substring result 0 j)
|
|
v
|
|
(substring result (+ j 3) (len result))))))))))
|
|
|
|
(define tw-shadow-sizes {:sm "0 1px 2px 0 rgb(0 0 0 / 0.05)" :xl "0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)" :md "0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)" :inner "inset 0 2px 4px 0 rgb(0 0 0 / 0.05)" :lg "0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)" :2xl "0 25px 50px -12px rgb(0 0 0 / 0.25)" :none "0 0 #0000" : "0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)"})
|
|
|
|
(define tw-rounded-sizes {:3xl "1.5rem" :sm "0.125rem" :xl "0.75rem" :full "9999px" :md "0.375rem" :lg "0.5rem" :2xl "1rem" :none "0" : "0.25rem"})
|
|
|
|
(define tw-border-widths {:0 "0px" :2 "2px" :8 "8px" :4 "4px" : "1px"})
|
|
|
|
(define tw-arbitrary-props {:outline-color "outline-color" :max-h "max-height" :mt "margin-top" :max-w "max-width" :inset-x "inset-inline" :font-size "font-size" :leading "line-height" :columns "columns" :size "width" :bg "background-color" :delay "transition-delay" :m "margin" :top "top" :left "left" :grid-cols "grid-template-columns" :my "margin-block" :border "border-width" :pb "padding-bottom" :order "order" :gap "gap" :basis "flex-basis" :mx "margin-inline" :rounded "border-radius" :ml "margin-left" :grid-rows "grid-template-rows" :mr "margin-right" :font "font-family" :border-color "border-color" :mb "margin-bottom" :pl "padding-left" :aspect "aspect-ratio" :gap-y "row-gap" :inset "inset" :indent "text-indent" :accent "accent-color" :gap-x "column-gap" :opacity "opacity" :w "width" :stroke "stroke" :px "padding-inline" :pr "padding-right" :right "right" :text "color" :p "padding" :min-h "min-height" :tracking "letter-spacing" :bottom "bottom" :inset-y "inset-block" :z "z-index" :min-w "min-width" :fill "fill" :pt "padding-top" :py "padding-block" :h "height" :duration "transition-duration" :shadow "box-shadow"})
|
|
|
|
(define
|
|
tw-resolve-arbitrary
|
|
(fn
|
|
(token)
|
|
(let
|
|
((bracket-start (index-of token "[")))
|
|
(if
|
|
(or (nil? bracket-start) (< bracket-start 1))
|
|
nil
|
|
(let
|
|
((bracket-end (index-of token "]")))
|
|
(if
|
|
(nil? bracket-end)
|
|
nil
|
|
(let
|
|
((prefix (substring token 0 (- bracket-start 1)))
|
|
(raw-val (substring token (+ bracket-start 1) bracket-end)))
|
|
(let
|
|
((val (replace raw-val "_" " "))
|
|
(prop (get tw-arbitrary-props prefix)))
|
|
(if (nil? prop) nil (str prop ":" val))))))))))
|
|
|
|
(define
|
|
tw-resolve-style
|
|
(fn
|
|
(token)
|
|
(let
|
|
((parts (split token "-"))
|
|
(head (first parts))
|
|
(rest (slice parts 1)))
|
|
(cond
|
|
(and
|
|
(get tw-colour-props head)
|
|
(>= (len rest) 2)
|
|
(let
|
|
((shade-str (last rest)) (slash-pos (index-of shade-str "/")))
|
|
(let
|
|
((shade-part (if (and slash-pos (>= slash-pos 0)) (substring shade-str 0 slash-pos) shade-str)))
|
|
(and
|
|
(not (nil? (parse-int shade-part nil)))
|
|
(not
|
|
(nil?
|
|
(get
|
|
colour-bases
|
|
(join "-" (slice rest 0 (- (len rest) 1))))))))))
|
|
(let
|
|
((css-prop (get tw-colour-props head))
|
|
(shade-str (last rest))
|
|
(slash-pos (index-of shade-str "/"))
|
|
(cname (join "-" (slice rest 0 (- (len rest) 1)))))
|
|
(let
|
|
((shade-part (if (and slash-pos (>= slash-pos 0)) (substring shade-str 0 slash-pos) shade-str))
|
|
(alpha-part
|
|
(if
|
|
(and slash-pos (>= slash-pos 0))
|
|
(substring shade-str (+ slash-pos 1) (len shade-str))
|
|
nil)))
|
|
(let
|
|
((shade (parse-int shade-part 0)))
|
|
(if
|
|
alpha-part
|
|
(str
|
|
css-prop
|
|
":"
|
|
(colour-with-alpha
|
|
cname
|
|
shade
|
|
(/ (parse-int alpha-part 100) 100)))
|
|
(str css-prop ":" (colour cname shade))))))
|
|
(and
|
|
(get tw-colour-props head)
|
|
(= (len rest) 1)
|
|
(or
|
|
(= (first rest) "white")
|
|
(= (first rest) "black")
|
|
(= (first rest) "transparent")
|
|
(= (first rest) "current")
|
|
(= (first rest) "inherit")))
|
|
(let
|
|
((css-prop (get tw-colour-props head))
|
|
(val
|
|
(case
|
|
(first rest)
|
|
"white"
|
|
"#ffffff"
|
|
"black"
|
|
"#000000"
|
|
"transparent"
|
|
"transparent"
|
|
"current"
|
|
"currentColor"
|
|
"inherit"
|
|
"inherit")))
|
|
(str css-prop ":" val))
|
|
(= head "rounded")
|
|
(cond
|
|
(empty? rest)
|
|
(str "border-radius:" (get tw-rounded-sizes ""))
|
|
(and
|
|
(= (len rest) 1)
|
|
(not (nil? (get tw-rounded-sizes (first rest)))))
|
|
(str "border-radius:" (get tw-rounded-sizes (first rest)))
|
|
(and
|
|
(>= (len rest) 1)
|
|
(or
|
|
(= (first rest) "t")
|
|
(= (first rest) "b")
|
|
(= (first rest) "l")
|
|
(= (first rest) "r")))
|
|
(let
|
|
((size (if (>= (len rest) 2) (get tw-rounded-sizes (nth rest 1)) (get tw-rounded-sizes "")))
|
|
(dir (first rest)))
|
|
(if
|
|
(nil? size)
|
|
nil
|
|
(case
|
|
dir
|
|
"t"
|
|
(str
|
|
"border-top-left-radius:"
|
|
size
|
|
";border-top-right-radius:"
|
|
size)
|
|
"b"
|
|
(str
|
|
"border-bottom-left-radius:"
|
|
size
|
|
";border-bottom-right-radius:"
|
|
size)
|
|
"l"
|
|
(str
|
|
"border-top-left-radius:"
|
|
size
|
|
";border-bottom-left-radius:"
|
|
size)
|
|
"r"
|
|
(str
|
|
"border-top-right-radius:"
|
|
size
|
|
";border-bottom-right-radius:"
|
|
size)
|
|
:else nil)))
|
|
:else nil)
|
|
(= head "border")
|
|
(cond
|
|
(empty? rest)
|
|
"border-width:1px"
|
|
(and
|
|
(= (len rest) 1)
|
|
(not (nil? (get tw-border-widths (first rest)))))
|
|
(str "border-width:" (get tw-border-widths (first rest)))
|
|
(and
|
|
(= (len rest) 1)
|
|
(or
|
|
(= (first rest) "t")
|
|
(= (first rest) "b")
|
|
(= (first rest) "l")
|
|
(= (first rest) "r")
|
|
(= (first rest) "x")
|
|
(= (first rest) "y")))
|
|
(let
|
|
((side (first rest)))
|
|
(case
|
|
side
|
|
"t"
|
|
"border-top-width:1px"
|
|
"b"
|
|
"border-bottom-width:1px"
|
|
"l"
|
|
"border-left-width:1px"
|
|
"r"
|
|
"border-right-width:1px"
|
|
"x"
|
|
"border-left-width:1px;border-right-width:1px"
|
|
"y"
|
|
"border-top-width:1px;border-bottom-width:1px"
|
|
:else nil))
|
|
(and
|
|
(= (len rest) 2)
|
|
(not (nil? (get tw-border-widths (nth rest 1)))))
|
|
(let
|
|
((side (first rest)) (w (get tw-border-widths (nth rest 1))))
|
|
(case
|
|
side
|
|
"t"
|
|
(str "border-top-width:" w)
|
|
"b"
|
|
(str "border-bottom-width:" w)
|
|
"l"
|
|
(str "border-left-width:" w)
|
|
"r"
|
|
(str "border-right-width:" w)
|
|
:else nil))
|
|
:else nil)
|
|
(= head "shadow")
|
|
(let
|
|
((size-key (if (empty? rest) "" (join "-" rest))))
|
|
(let
|
|
((val (get tw-shadow-sizes size-key)))
|
|
(if (nil? val) nil (str "box-shadow:" val))))
|
|
(and (= head "opacity") (= (len rest) 1))
|
|
(let
|
|
((n (parse-int (first rest) nil)))
|
|
(if (nil? n) nil (str "opacity:" (/ n 100))))
|
|
(and
|
|
(= head "ring")
|
|
(>= (len rest) 2)
|
|
(not (nil? (parse-int (last rest) nil)))
|
|
(not
|
|
(nil?
|
|
(get colour-bases (join "-" (slice rest 0 (- (len rest) 1)))))))
|
|
(let
|
|
((cname (join "-" (slice rest 0 (- (len rest) 1))))
|
|
(shade (parse-int (last rest) 0)))
|
|
(str "--tw-ring-color:" (colour cname shade)))
|
|
(and (= head "ring") (or (empty? rest) (= (len rest) 1)))
|
|
(let
|
|
((w (if (empty? rest) "3px" (let ((n (parse-int (first rest) nil))) (if (nil? n) nil (str n "px"))))))
|
|
(if
|
|
(nil? w)
|
|
nil
|
|
(str
|
|
"box-shadow:0 0 0 "
|
|
w
|
|
" var(--tw-ring-color, rgb(59 130 246 / 0.5))")))
|
|
(= head "outline")
|
|
(cond
|
|
(and (= (len rest) 1) (= (first rest) "none"))
|
|
"outline:2px solid transparent;outline-offset:2px"
|
|
(empty? rest)
|
|
"outline-style:solid"
|
|
:else nil)
|
|
(= head "transition")
|
|
(cond
|
|
(empty? rest)
|
|
"transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:150ms"
|
|
(= (first rest) "colors")
|
|
"transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:150ms"
|
|
(= (first rest) "all")
|
|
"transition-property:all;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:150ms"
|
|
(= (first rest) "none")
|
|
"transition-property:none"
|
|
(= (first rest) "opacity")
|
|
"transition-property:opacity;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:150ms"
|
|
(= (first rest) "shadow")
|
|
"transition-property:box-shadow;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:150ms"
|
|
(= (first rest) "transform")
|
|
"transition-property:transform;transition-timing-function:cubic-bezier(0.4,0,0.2,1);transition-duration:150ms"
|
|
:else nil)
|
|
(and (= head "duration") (= (len rest) 1))
|
|
(str "transition-duration:" (first rest) "ms")
|
|
(= head "ease")
|
|
(let
|
|
((val (join "-" rest)))
|
|
(case
|
|
val
|
|
"linear"
|
|
"transition-timing-function:linear"
|
|
"in"
|
|
"transition-timing-function:cubic-bezier(0.4,0,1,1)"
|
|
"out"
|
|
"transition-timing-function:cubic-bezier(0,0,0.2,1)"
|
|
"in-out"
|
|
"transition-timing-function:cubic-bezier(0.4,0,0.2,1)"
|
|
:else nil))
|
|
(and (= head "cursor") (= (len rest) 1))
|
|
(str "cursor:" (first rest))
|
|
(and (= head "cursor") (= (len rest) 2))
|
|
(str "cursor:" (join "-" rest))
|
|
(and
|
|
(= head "pointer")
|
|
(= (len rest) 2)
|
|
(= (first rest) "events"))
|
|
(str "pointer-events:" (nth rest 1))
|
|
(and (= head "select") (= (len rest) 1))
|
|
(str "user-select:" (first rest))
|
|
(and (= head "appearance") (= (len rest) 1))
|
|
(str "appearance:" (first rest))
|
|
(or
|
|
(= token "underline")
|
|
(= token "overline")
|
|
(= token "line-through"))
|
|
(str "text-decoration-line:" token)
|
|
(and (= (len parts) 2) (= head "no") (= (first rest) "underline"))
|
|
"text-decoration-line:none"
|
|
(and (= head "scale") (= (len rest) 1))
|
|
(let
|
|
((n (parse-int (first rest) nil)))
|
|
(if (nil? n) nil (str "transform:scale(" (/ n 100) ")")))
|
|
(and (= head "rotate") (= (len rest) 1))
|
|
(str "transform:rotate(" (first rest) "deg)")
|
|
(= head "animate")
|
|
(cond
|
|
(= (first rest) "spin")
|
|
"animation:spin 1s linear infinite"
|
|
(= (first rest) "ping")
|
|
"animation:ping 1s cubic-bezier(0,0,0.2,1) infinite"
|
|
(= (first rest) "pulse")
|
|
"animation:pulse 2s cubic-bezier(0.4,0,0.6,1) infinite"
|
|
(= (first rest) "bounce")
|
|
"animation:bounce 1s infinite"
|
|
(= (first rest) "none")
|
|
"animation:none"
|
|
:else nil)
|
|
:else nil))))
|
|
|
|
(define
|
|
tw-process-token
|
|
(fn
|
|
(token)
|
|
(let
|
|
((important (starts-with? token "!"))
|
|
(clean-token
|
|
(if
|
|
(starts-with? token "!")
|
|
(substring token 1 (len token))
|
|
token)))
|
|
(let
|
|
((colon-parts (split clean-token ":"))
|
|
(n (len (split clean-token ":")))
|
|
(bp nil)
|
|
(state nil)
|
|
(sel-prefix nil)
|
|
(container nil)
|
|
(base nil))
|
|
(cond
|
|
(= n 1)
|
|
(set! base (first colon-parts))
|
|
(= n 2)
|
|
(do
|
|
(let
|
|
((prefix (first colon-parts)))
|
|
(set! base (nth colon-parts 1))
|
|
(cond
|
|
(get tw-breakpoints prefix)
|
|
(set! bp prefix)
|
|
(get tw-selector-states prefix)
|
|
(set! sel-prefix (get tw-selector-states prefix))
|
|
(starts-with? prefix "@")
|
|
(set! container (substring prefix 1 (len prefix)))
|
|
true
|
|
(set! state prefix))))
|
|
(= n 3)
|
|
(do
|
|
(let
|
|
((p1 (first colon-parts)) (p2 (nth colon-parts 1)))
|
|
(set! base (nth colon-parts 2))
|
|
(cond
|
|
(get tw-breakpoints p1)
|
|
(set! bp p1)
|
|
(get tw-selector-states p1)
|
|
(set! sel-prefix (get tw-selector-states p1))
|
|
(starts-with? p1 "@")
|
|
(set! container (substring p1 1 (len p1)))
|
|
true
|
|
(set! bp p1))
|
|
(if
|
|
(get tw-selector-states p2)
|
|
(set! sel-prefix (get tw-selector-states p2))
|
|
(set! state p2))))
|
|
true
|
|
(set! base clean-token))
|
|
(let
|
|
((negative (and base (starts-with? base "-")))
|
|
(actual-base
|
|
(if
|
|
(and base (starts-with? base "-"))
|
|
(substring base 1 (len base))
|
|
base)))
|
|
(let
|
|
((css (or (tw-resolve-style actual-base) (tw-resolve-layout actual-base) (tw-resolve-type actual-base) (tw-resolve-arbitrary actual-base))))
|
|
(if
|
|
(nil? css)
|
|
nil
|
|
(let
|
|
((neg-css (if negative (replace css ":" ":-") css))
|
|
(final-css
|
|
(if important (str neg-css " !important") neg-css))
|
|
(cls
|
|
(str
|
|
"sx-"
|
|
(replace (replace clean-token ":" "-") "." "d")))
|
|
(pseudo
|
|
(if state (or (get tw-states state) (str ":" state)) ""))
|
|
(selector
|
|
(if
|
|
sel-prefix
|
|
(str sel-prefix "." cls pseudo)
|
|
(str "." cls pseudo))))
|
|
(let
|
|
((rule (cond bp (str "@media(min-width:" (get tw-breakpoints bp) "){" selector "{" final-css "}}") container (let ((csize (get tw-container-sizes container))) (if csize (str "@container(min-width:" csize "){" selector "{" final-css "}}") (str "@container{" selector "{" final-css "}}"))) true (str selector "{" final-css "}"))))
|
|
{:rule rule :cls cls})))))))))
|
|
|
|
(defcomp
|
|
~tw
|
|
(&key tokens)
|
|
(let
|
|
((token-list (filter (fn (t) (not (= t ""))) (split (or tokens "") " ")))
|
|
(results (map tw-process-token token-list))
|
|
(valid (filter (fn (r) (not (nil? r))) results))
|
|
(classes (map (fn (r) (get r "cls")) valid))
|
|
(rules (map (fn (r) (get r "rule")) valid))
|
|
(_ (for-each (fn (rule) (collect! "cssx" rule)) rules)))
|
|
(if (empty? classes) nil (make-spread {:class (join " " classes) :data-tw (or tokens "")}))))
|
|
|
|
(defcomp
|
|
~tw/flush
|
|
()
|
|
:affinity :client
|
|
(let
|
|
((rules (collected "cssx")) (head-style (dom-query "#sx-css")))
|
|
(when
|
|
head-style
|
|
(clear-collected! "cssx")
|
|
(when
|
|
(not (empty? rules))
|
|
(dom-set-prop
|
|
head-style
|
|
"textContent"
|
|
(str (dom-get-prop head-style "textContent") (join "" rules)))))))
|