(ns auto-ap.ssr.components.buttons (:require [auto-ap.ssr.svg :as svg] [auto-ap.ssr.hiccup-helper :as hh])) (defn button-icon- [_ i] [:div.h-4.w-4 i]) (defn bg-colors [color disabled] (let [base-color (cond (= :primary color) "green" (= :secondary color) "blue" (= :red color) "red" (nil? color) "white" (sequential? color) (first color) :else color) base-weight (or (when (sequential? color) (second color)) 500) disabled-weight (when disabled 400)] (format " bg-%s-%d hover:bg-%s-%d focus:ring-%s-%d dark:bg-%s-%d dark:hover:bg-%s-%d " base-color (or disabled-weight (+ base-weight 0)) base-color (or disabled-weight (+ base-weight 100)) base-color (or disabled-weight (int (* base-weight 0.5))) base-color (or disabled-weight (+ base-weight 100)) base-color (or disabled-weight (+ base-weight 200))))) (defn dark-color-weight [disabled] (if disabled 400 600)) (defn hover-color-weight [disabled] (if disabled 400 600)) (for [color ["green" "blue" "white"] weight (range 100 900 100)] (str "bg-" color "-" weight)) ;;ensuring these colors show up ;; => ("bg-green-100" ;; "bg-green-200" ;; "bg-green-300" ;; "bg-green-400" ;; "bg-green-500" ;; "bg-green-600" ;; "bg-green-700" ;; "bg-green-800" ;; "bg-blue-100" ;; "bg-blue-200" ;; "bg-blue-300" ;; "bg-blue-400" ;; "bg-blue-500" ;; "bg-blue-600" ;; "bg-blue-700" ;; "bg-blue-800" ;; "bg-white-100" ;; "bg-white-200" ;; "bg-white-300" ;; "bg-white-400" ;; "bg-white-500" ;; "bg-white-600" ;; "bg-white-700" ;; "bg-white-800") (defn button- [params & children] [:button (update params :class #(cond-> % true (str " focus:ring-4 font-bold rounded-lg text-xs p-3 text-center mr-2 inline-flex items-center relative justify-center disabled:opacity-50" (bg-colors (:color params) (:disabled params))) (not (:disabled params)) (str " hover:scale-105 transition duration-100") (:disabled params) (str " cursor-not-allowed") (not (nil? (:color params))) (str " text-white ") (nil? (:color params)) (str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100 font-medium border border-gray-300 dark:border-gray-700"))) [:div.htmx-indicator.flex.items-center.absolute.inset-0.justify-center (svg/spinner {:class "inline w-4 h-4 text-white"}) (when (not (:minimal-loading? params)) [:div.ml-3 "Loading..."])] (into [:div.htmx-indicator-invisible.inline-flex.gap-2.items-center.justify-center] children)]) (defn a-button- [params & children] [:a (-> params (update :class #(cond-> % true (str " focus:ring-4 font-bold rounded-lg text-xs p-3 text-center mr-2 inline-flex items-center hover:scale-105 transition duration-100 justify-center") (= :secondary (:color params)) (str " text-white bg-blue-500 hover:bg-blue-600 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700") (= :primary (:color params)) (str " text-white bg-green-500 hover:bg-green-600 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 ") (nil? (:color params)) (str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100 font-medium border border-gray-300 dark:border-gray-700"))) (assoc :tabindex 0) (assoc :href (:href params "#"))) [:div.htmx-indicator.flex.items-center (svg/spinner {:class "inline w-4 h-4 text-white"}) [:div.ml-3 "Loading..."]] (into [:div.htmx-indicator-hidden.inline-flex.gap-2.items-center.justify-center] children)]) (defn icon-button- [params & children] (into [:button (update params :class #(cond-> % true (str " inline-flex items-center justify-center items-center p-3 text-sm font-medium border border-gray-300 dark:border-gray-700 text-center rounded-lg hover:scale-110") (= :secondary (:color params)) (str " bg-blue-500 hover:bg-blue-600 focus:ring-blue-300 dark:bg-blue-600 dark:hover:bg-blue-700") (= :primary (:color params)) (str " bg-green-500 hover:bg-green-600 focus:ring-green-300 dark:bg-green-600 dark:hover:bg-green-700 ") (= :primary-light (:color params)) (str " bg-green-200 hover:bg-green-300 focus:ring-green-200 dark:bg-green-700 dark:hover:bg-green-600 text-gray-800 dark:text-gray-200") (= :secondary-light (:color params)) (str " bg-blue-200 hover:bg-blue-300 focus:ring-blue-200 dark:bg-blue-700 dark:hover:bg-blue-600 text-gray-800 dark:text-gray-200") (= :danger-light (:color params)) (str " bg-red-200 hover:bg-red-300 focus:ring-red-200 dark:bg-red-700 dark:hover:bg-red-600 text-gray-800 dark:text-gray-200") (nil? (:color params)) (str " bg-white dark:bg-gray-600 border-gray-300 dark:border-gray-700 text-gray-500 hover:text-gray-800 dark:text-gray-400 dark:hover:text-gray-100"))) [:div.htmx-indicator.flex.items-center (svg/spinner {:class "inline w-4 h-4 text-white"})] [:div.htmx-indicator-hidden.inline-flex.gap-2.items-center.justify-center (into [:div.h-4.w-4] children)]])) (defn a-icon-button- [params & children] (into [:a (-> params (update :class str " inline-flex items-center justify-center bg-white dark:bg-gray-600 items-center p-3 text-sm font-medium border border-gray-300 dark:border-gray-700 text-center text-gray-500 hover:text-gray-800 rounded-lg dark:text-gray-400 dark:hover:text-gray-100") (update :href #(or % ""))) [:div.h-4.w-4 children]])) (defn save-button- [params & children] [:button {:class "text-white bg-green-500 hover:bg-green-700 focus:ring-4 focus:ring-blue-300 font-medium rounded-lg text-sm px-5 py-2.5 text-center mr-2 dark:bg-green-600 dark:hover:bg-green-700 dark:focus:ring-green-800 inline-flex items-center hover:scale-105 transition duration-300"} [:div.htmx-indicator.flex.items-center (svg/spinner {:class "inline w-4 h-4 text-white"}) [:div.ml-3 "Loading..."]] (into [:div.htmx-indicator-hidden] children)]) (defn group-button- [{:keys [size] :or {size :normal} :as params} & children] (into [:button (cond-> params true (assoc :type (or (:type params) "button")) true (update :class (fn [c] (cond-> c true (str " font-medium text-gray-900 bg-white border border-gray-200 hover:bg-gray-100 hover:text-primary-700 focus:z-10 focus:ring-2 focus:ring-green-700 focus:text-green-700 dark:bg-gray-700 dark:border-gray-600 dark:text-white dark:hover:text-white dark:hover:bg-gray-600 dark:focus:ring-green-500 dark:focus:text-white") (= :small size) (str " text-xs px-3 py-2") (= :normal size) (str " text-sm px-4 py-2")))) true (dissoc :size))] children)) (defn group- [{:keys [name]} & children] (let [children (-> children vec (update-in [0 1 :class] str " rounded-l-lg") (update-in [(dec (count children)) 1 :class] str " rounded-r-lg"))] (into [:div {:class "inline-flex rounded-md shadow-sm", :role "group" :hx-on:click "this.querySelector(\"input\").value = event.target.value; this.querySelector(\"input\").dispatchEvent(new Event('change', {bubbles: true}));"} [:input {:type "hidden" :name name}]] children))) (defn navigation-button- [{:keys [class next-arrow?] :or {next-arrow? true} :as params} & children] [:button (-> params (update :class (fnil hh/add-class "") "p-4 text-green-700 border border-gray-300 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-green-800 dark:text-green-400 focus:ring-green-400 focus:ring-2 hover:border-green-300 hover:bg-green-200 hover:dark:bg-gray-800 hover:dark:border-green-800 hover:dark:text-green-400") (dissoc :next-arrow?)) [:div {:class "flex items-center justify-between"} [:span {:class "sr-only"} children] [:h3 {:class "font-medium"} children] (when next-arrow? [:div.w-4.h-4 svg/arrow-right])]]) (defn navigation-button-list- [{:keys []} & children] [:ol {:class "space-y-4 w-72"} (for [n children] [:li n]) #_[:li [:div {:class "w-full p-4 text-gray-900 bg-gray-100 border border-gray-300 rounded-lg dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400", :role "alert"} [:div {:class "flex items-center justify-between"} [:span {:class "sr-only"} "Review"] [:h3 {:class "font-medium"} "4. Review"]]]] #_[:li [:div {:class "w-full p-4 text-gray-900 bg-gray-100 border border-gray-300 rounded-lg dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400", :role "alert"} [:div {:class "flex items-center justify-between"} [:span {:class "sr-only"} "Confirmation"] [:h3 {:class "font-medium"} "5. Confirmation"]]]]]) (defn validated-save-button- [{:keys [errors class] :as params} & children] (button- (-> {:color (or (:color params) :primary) :type "submit" :class (cond-> (or class "") true (hh/add-class "w-32") (seq errors) (hh/add-class "animate-shake"))} (merge (dissoc params :class)) (dissoc :errors)) (if (seq children) children "Save"))) (defn tooltip- [{:as params} & children] [:div (assoc params :class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50 p-4 opacity-0") [:span children]])