bulk edit is now possible

This commit is contained in:
2025-01-20 21:18:52 -08:00
parent 747bf66206
commit 956d233fe1
6 changed files with 416 additions and 91 deletions

View File

@@ -25,43 +25,41 @@
"w-4 h-4 bg-gray-100 indeterminate:bg-gray-300 border-gray-300 rounded text-primary-600 focus:ring-primary-500 dark:focus:ring-primary-600 dark:ring-offset-gray-800 focus:ring-2 dark:bg-gray-700 dark:border-gray-600")
(defn select- [params & children]
(into
[:select (-> params
(dissoc :allow-blank? :value :options)
(update
:class (fnil hh/add-class "") default-input-classes))
(cond->>
(map (fn [[k v]]
[:option {:value k :selected (= k (:value params))} v])
(:options params))
(:allow-blank? params) (conj [:option {:value "" :selected (not (:value params))} ""]))]
children))
(into
[:select (-> params
(dissoc :allow-blank? :value :options)
(update
:class (fnil hh/add-class "") default-input-classes))
(cond->>
(map (fn [[k v]]
[:option {:value k :selected (= k (:value params))} v])
(:options params))
(:allow-blank? params) (conj [:option {:value "" :selected (not (:value params))} ""]))]
children))
(defn checkbox- [params & rest]
(if (seq rest)
[:label {:class "text-sm text-gray-800 dark:text-gray-300 "}
[:input (merge (dissoc params :indeterminate?)
[:input (merge (dissoc params :indeterminate?)
{:type "checkbox" :class (hh/add-class default-checkbox-classes (:class params ""))}
(when (:indeterminate? params)
{:x-init "$el.indeterminate = true"}))]
[:span.ml-2
[:span.ml-2
rest]]
[:input (merge (dissoc params :indeterminate params)
[:input (merge (dissoc params :indeterminate params)
{:type "checkbox" :class (hh/add-class default-checkbox-classes (:class params ""))}
(when (:indeterminate? params)
{:x-init "$el.indeterminate = true"}))
]))
{:x-init "$el.indeterminate = true"}))]))
(defn typeahead- [params]
[:div.relative {:x-data (hx/json { :baseUrl (str (:url params))
[:div.relative {:x-data (hx/json {:baseUrl (str (:url params))
:value {:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))}
:tippy nil
:search ""
:active -1
:elements (if ((:value-fn params identity) (:value params))
[{:value ((:value-fn params identity) (:value params)) :label ((:content-fn params identity) (:value params))}]
[])
})
[])})
:x-modelable "value.value"
:x-model (:x-model params)}
(if (:disabled params)
@@ -72,7 +70,7 @@
"@keydown.down.prevent.stop" "tippy.show();"
"@keydown.backspace" "tippy.hide(); value = {value: '', label: '' }"
:tabindex 0
:x-init (str "$nextTick(() => tippy = $el.__x_tippy); " (:x-init params))
:x-init (str "$nextTick(() => tippy = $el.__x_tippy); " (:x-init params))
:x-ref "input"}
[:input (-> params
(dissoc :class)
@@ -91,9 +89,9 @@
[:span.flex-grow.text-left {"x-text" "value.label"}]
[:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"}
svg/drop-down]
[:div {:x-show "value.warning" }
[:div {:x-show "value.warning"}
(tags/badge- {:class "peer"
:x-tooltip "value.warning"} "!") ]]])
:x-tooltip "value.warning"} "!")]]])
[:template {:x-ref "dropdown"}
[:ul.dropdown-contents {:class "bg-gray-100 dark:bg-gray-600 ring-1"
@@ -148,22 +146,19 @@
"x-init" " $el.focus(); $watch('search', s => { if($el.value.length > 2) {fetch(addQueryParam(baseUrl, 'q', s)).then(data=>data.json()).then(data => reset_elements(data)) }})"}]]
[:div.dropdown-options {:class "overflow-hidden divide-y divide-gray-200 "}
[:template {:x-for "(element, index) in elements"}
[:li {":style" "index == 0 && 'border: 0 !important;'"}
[:li {":style" "index == 0 && 'border: 0 !important;'"}
[:label {:class "p-3 group rounded flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-300 [&.active]:dark:bg-primary-700 [&.implied]:text-gray-500 text-gray-800 dark:text-gray-100 cursor-pointer"
:href "#"
":class" (hx/json {"active" (hx/js-fn "active==index")
"implied" (hx/js-fn "all_selected && index != 0")
} )
"implied" (hx/js-fn "all_selected && index != 0")})
"@mouseover" "active = index"
"@mouseout" "active = -1"
"@click.prevent" "toggle(element)"}
(checkbox- {":checked" "value.has(element.value) || all_selected"
:class "group-[&.implied]:bg-green-200"
})
#_[:input {:type "checkbox" }]
(checkbox- {":checked" "value.has(element.value) || all_selected"
:class "group-[&.implied]:bg-green-200"})
#_[:input {:type "checkbox"}]
[:span {"x-html" "element.label"}]]]]
[:template {:x-if "elements.length == 0"}
[:li {:class "px-4 pt-4 flex gap-2 items-center outline-0 focus:bg-neutral-100 hover:bg-neutral-100 whitespace-nowrap [&.active]:bg-primary-500 text-gray-800 dark:text-gray-100 text-xs " "style" "border: 0 !important"}
@@ -172,12 +167,10 @@
(defn multi-typeahead-selected-pill- [params]
[:div.flex-grow.flex
[:template {:x-if "value.size > 0"}
[:a.bg-blue-100.rounded-full.px-3
[:span.text-left
[:a.bg-blue-100.rounded-full.px-3
[:span.text-left
[:span {"x-text" "value.has('all') ? 'All' : value.size"}]
" selected"]
]]
" selected"]]]
[:template {:x-if "value.size == 0"}
[:span.text-left.text-gray-400 "None selected"]]
[:div {:class "w-4 h-4 ml-2 inline text-gray-500 self-center rounded-full bg-gray-100 text-gray-500"
@@ -223,7 +216,7 @@
(sequential? (:value params))
(map (fn [v] ((:value-fn params identity) v))
(:value params))
:else
[])
:tippy nil
@@ -238,7 +231,7 @@
:elements (cond-> [{:value "all" :label "All"}]
(sequential? (:value params))
(into (map (fn [v]
{:value ((:value-fn params identity) v)
{:value ((:value-fn params identity) v)
:label ((:content-fn params identity) v)})
(:value params))))
:x-ref "r"})
@@ -265,8 +258,7 @@
[:input (-> params
(dissoc :class :value-fn :content-fn :placeholder :x-model)
(assoc :type "hidden"
:value ""
))]]
:value ""))]]
[:div.flex.w-full.justify-items-stretch
(multi-typeahead-selected-pill- params)
[:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"}
@@ -281,7 +273,7 @@
:x-ref "warning_pop"
:class "hidden peer-hover:block bg-red-50 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50 p-4"
:x-text "value.warning"}]]]
(multi-typeahead-dropdown- params) ])])
(multi-typeahead-dropdown- params)])])
(defn use-size [size]
@@ -292,26 +284,25 @@
(defn text-input- [{:keys [size error?] :as params}]
[:input
(-> params
[:input
(-> params
(dissoc :error?)
(assoc :type "text" :autocomplete "off")
(update
:class #(-> ""
(hh/add-class default-input-classes)
(hh/add-class %)))
(update
:class #(-> ""
(hh/add-class default-input-classes)
(hh/add-class %)))
(update :class #(str % (use-size size))))])
(defn text-area- [{:keys [] :as params}]
[:textarea
(-> params
[:textarea
(-> params
(update :class #(-> ""
(hh/add-class default-input-classes)
(hh/add-class %)))) ]
)
(hh/add-class %))))])
(defn money-input- [{:keys [size] :as params}]
[:input
[:input
(-> params
(update :class (fnil hh/add-class "") default-input-classes)
(update :class hh/add-class "appearance-none text-right")
@@ -321,7 +312,7 @@
(dissoc :size))])
(defn int-input- [{:keys [size] :as params}]
[:input
[:input
(-> params
(update :class (fnil hh/add-class "") default-input-classes)
(update :class hh/add-class "appearance-none text-right")
@@ -331,12 +322,11 @@
(dissoc :size))])
(defn date-input- [{:keys [size] :as params}]
[:div.shrink {:x-data (hx/json {:value (:value params)
[:div.shrink {:x-data (hx/json {:value (:value params)
:tippy nil
:dp nil})
"x-effect" "console.log('changed to' +value)"
"@change-date.camel" "$dispatch('change')"
}
"@change-date.camel" "$dispatch('change')"}
[:input
(-> params
(update :class (fnil hh/add-class "") default-input-classes)
@@ -349,13 +339,13 @@
(assoc "autocomplete" "off")
(assoc "@change" "value = $event.target.value;")
(assoc "@keydown.escape" "tippy.hide(); " )
(assoc "@keydown.escape" "tippy.hide(); ")
#_(assoc "hx-on" (hiccup/raw "changeDate: htmx.trigger(this, \"change\") "))
(update :class #(str % (use-size size) " w-full"))
(dissoc :size))]
[:template {:x-ref "tooltip" }
[:div.shrink
[:template {:x-ref "tooltip"}
[:div.shrink
[:div
(-> params
(update :class (fnil hh/add-class "") default-input-classes)
@@ -369,19 +359,19 @@
(assoc "@htmx:before-cleanup-element" "destroyDatepicker(dp)")
(assoc "x-destroy" "destroyDatepicker(dp)")
(assoc "@change-date.camel" "value = dp.getDate(\"mm/dd/yyyy\");")
(update :class #(str % (use-size size) " w-full"))
(dissoc :size :name :x-model :x-modelable))]]]])
(defn multi-calendar-input- [{:keys [size] :as params}]
(let [value (str/join ", "
(for [v (:value params)
:when v]
(let [value (str/join ", "
(for [v (:value params)
:when v]
(some-> v (atime/unparse-local atime/normal-date))))]
[:div.shrink {:x-data (hx/json {:value value
:dp nil })
:dp nil})
:x-modelable "value"
:x-model (:x-model params) }
:x-model (:x-model params)}
[:template {:x-for "v in value"}
[:input {:type "hidden" :name (:name params) :x-model "v"}]]
[:div
@@ -393,8 +383,8 @@
(assoc :x-init "$nextTick(() => { dp = initMultiDatepicker($el, value); ;}); ")
(assoc "x-effect" "if(dp) { dp.setDate(Array.from(value), {clear: true}); } ")
(assoc ":data-date" "Array.prototype.join.call(value, ', ')")
(assoc "@htmx:before-history-save" "destroyDatepicker(dp)" )
(assoc "@htmx:before-cleanup-element" "destroyDatepicker(dp)" )
(assoc "@htmx:before-history-save" "destroyDatepicker(dp)")
(assoc "@htmx:before-cleanup-element" "destroyDatepicker(dp)")
(assoc "x-destroy" "destroyDatepicker(dp)")
(assoc "@change-date.camel" "value = dp.getDate(\"mm/dd/yyyy\");")
@@ -404,9 +394,9 @@
(defn calendar-input- [{:keys [size] :as params}]
(let [value (:value params)]
[:div.shrink {:x-data (hx/json {:value value
:dp nil })
:dp nil})
:x-modelable "value"
:x-model (:x-model params) }
:x-model (:x-model params)}
[:input {:type "hidden" :name (:name params) :x-model "value"}]
[:div
(-> params
@@ -417,8 +407,8 @@
(assoc :x-init "$nextTick(() => { dp = initCalendar($el); ;}); ")
(assoc "x-effect" "if(dp) { dp.setDate(value); } ")
(assoc ":data-date" "value")
(assoc "@htmx:before-history-save" "destroyDatepicker(dp)" )
(assoc "@htmx:before-cleanup-element" "destroyDatepicker(dp)" )
(assoc "@htmx:before-history-save" "destroyDatepicker(dp)")
(assoc "@htmx:before-cleanup-element" "destroyDatepicker(dp)")
(assoc "x-destroy" "destroyDatepicker(dp)")
(assoc "@change-date.camel" "value = dp.getDate(\"mm/dd/yyyy\");")
@@ -429,12 +419,12 @@
(defn field-errors- [{:keys [source key]} & rest]
(let [errors (:errors (cond-> (meta source)
key (get key)))]
key (get key)))]
[:p.mt-2.text-xs.text-red-600.dark:text-red-500.h-4 (str/join ", " errors)]))
(defn field- [params & rest]
[:div (-> params
(update :class #(hh/add-class (or % "") "group" )))
(update :class #(hh/add-class (or % "") "group")))
(when (:label params)
[:label {:class "block mb-2 text-sm font-medium text-gray-900 dark:text-white"} (:label params)])
rest
@@ -444,7 +434,7 @@
(defn inline-field- [params & rest]
[:div (-> params
(update :class #(hh/add-class (or % "") "group flex items-baseline gap-2" )))
(update :class #(hh/add-class (or % "") "group flex items-baseline gap-2")))
(when (:label params)
[:label {:class "mb-2 text-sm font-medium text-gray-900 dark:text-white"} (:label params)])
rest
@@ -471,10 +461,10 @@
(defn validated-inline-field- [params & rest]
(inline-field- (cond-> params
true (dissoc :errors)
(sequential? (:errors params)) (update :class #(hh/add-class (or % "") "has-error")))
rest
(errors- {:errors (:errors params)})))
true (dissoc :errors)
(sequential? (:errors params)) (update :class #(hh/add-class (or % "") "has-error")))
rest
(errors- {:errors (:errors params)})))
(defn hidden- [{:keys [name value] :as params}]
[:input (merge {:type "hidden" :value value :name name} params)])