Add vendor pre-population for bulk code and individual edit forms
- Add vendor-changed HTMX handlers for both bulk code and individual edit - Pre-populate default account at 100% when vendor is selected and no accounts exist - Fix render-accounts-section to render from step-params correctly - Change bulk code vendor-changed from hx-get to hx-post to include form data - Add routes for vendor-changed endpoints - Update e2e tests to cover vendor pre-population - Run lein cljfmt fix across codebase
This commit is contained in:
@@ -55,8 +55,8 @@
|
||||
":style" (format "selected == '%s' ? 'max-height: ' + $el.scrollHeight + 'px' : ''" (:selector params))))
|
||||
(for [c children]
|
||||
[:li
|
||||
(update-in c [1 1 :class ] (fn [c]
|
||||
(hh/add-class (or c "") " flex items-center p-2 pl-11 w-full text-base font-normal rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700")))])])
|
||||
(update-in c [1 1 :class] (fn [c]
|
||||
(hh/add-class (or c "") " flex items-center p-2 pl-11 w-full text-base font-normal rounded-lg transition duration-75 group hover:bg-gray-100 dark:text-white dark:hover:bg-gray-700")))])])
|
||||
|
||||
(defn left-aside- [{:keys [nav page-specific]} & _]
|
||||
[:aside {:id "left-nav",
|
||||
@@ -83,7 +83,6 @@
|
||||
[:div {:class "overflow-y-auto py-5 px-3 h-full bg-gray-50 border-r border-gray-200 dark:bg-gray-800 dark:border-gray-700"}
|
||||
nav
|
||||
|
||||
|
||||
(when page-specific
|
||||
[:div {:class " pt-5 mt-5 space-y-2 border-t border-gray-200 dark:border-gray-700"}
|
||||
page-specific])]])
|
||||
@@ -94,7 +93,7 @@
|
||||
"invoices"
|
||||
|
||||
(#{:pos-sales :pos-expected-deposits :pos-tenders :pos-refunds :pos-cash-drawer-shifts ::ss-routes/page} (:matched-route request))
|
||||
"sales"
|
||||
"sales"
|
||||
(#{::payment-routes/all-page ::payment-routes/pending-page ::payment-routes/cleared-page ::payment-routes/voided-page} (:matched-route request))
|
||||
"payments"
|
||||
(#{::transaction-routes/page ::transaction-routes/approved-page ::transaction-routes/unapproved-page ::transaction-routes/requires-feedback-page :transaction-insights} (:matched-route request))
|
||||
@@ -108,7 +107,7 @@
|
||||
|
||||
[:li
|
||||
(menu-button- {:icon svg/pie
|
||||
:href (bidi/path-for ssr-routes/only-routes
|
||||
:href (bidi/path-for ssr-routes/only-routes
|
||||
::dashboard/page)}
|
||||
"Dashboard")]
|
||||
|
||||
@@ -147,7 +146,6 @@
|
||||
:hx-boost "true"}
|
||||
"Voided")
|
||||
|
||||
|
||||
(when (can? (:identity request)
|
||||
{:subject :invoice
|
||||
:activity :import})
|
||||
@@ -156,7 +154,6 @@
|
||||
:active? (= ::invoice-route/import-page (:matched-route request))
|
||||
:hx-boost "true"} "Import"))
|
||||
|
||||
|
||||
#_(when (can? (:identity request)
|
||||
{:subject :invoice
|
||||
:activity :import})
|
||||
@@ -168,7 +165,6 @@
|
||||
"Glimpse"
|
||||
(tags/pill- {:color :secondary} "Beta")]))
|
||||
|
||||
|
||||
(when (can? (:identity request)
|
||||
{:subject :ar-invoice
|
||||
:activity :read})
|
||||
@@ -213,12 +209,12 @@
|
||||
:hx-boost "true"}
|
||||
|
||||
"Refunds")
|
||||
(menu-button- {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
:pos-cash-drawer-shifts)
|
||||
"?date-range=week")
|
||||
:active? (= :pos-cash-drawer-shifts (:matched-route request))
|
||||
:hx-boost "true"}
|
||||
"Cash drawer shifts")
|
||||
(menu-button- {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
:pos-cash-drawer-shifts)
|
||||
"?date-range=week")
|
||||
:active? (= :pos-cash-drawer-shifts (:matched-route request))
|
||||
:hx-boost "true"}
|
||||
"Cash drawer shifts")
|
||||
(menu-button- {:href (str (bidi/path-for ssr-routes/only-routes
|
||||
::ss-routes/page)
|
||||
"?date-range=week")
|
||||
@@ -288,7 +284,6 @@
|
||||
(menu-button- {:href (bidi/path-for ssr-routes/only-routes
|
||||
:transaction-insights)} "Insights")))]
|
||||
|
||||
|
||||
(when (can? (:identity request)
|
||||
{:subject :ledger-page})
|
||||
(list
|
||||
@@ -314,7 +309,7 @@
|
||||
[:div.flex.gap-2
|
||||
"External Register"
|
||||
(tags/pill- {:color :secondary} "WIP")]))
|
||||
|
||||
|
||||
(menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes
|
||||
::ledger-routes/profit-and-loss))
|
||||
:active? (= ::ledger-routes/profit-and-loss (:matched-route request))
|
||||
@@ -322,7 +317,7 @@
|
||||
[:div.flex.gap-2
|
||||
"Profit and loss"
|
||||
(tags/pill- {:color :secondary} "WIP")])
|
||||
|
||||
|
||||
(menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes
|
||||
::ledger-routes/cash-flows))
|
||||
:active? (= ::ledger-routes/cash-flows (:matched-route request))
|
||||
@@ -330,7 +325,7 @@
|
||||
[:div.flex.gap-2
|
||||
"Cash flows"
|
||||
(tags/pill- {:color :secondary} "WIP")])
|
||||
|
||||
|
||||
(menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes
|
||||
::ledger-routes/balance-sheet))
|
||||
:active? (= ::ledger-routes/balance-sheet (:matched-route request))
|
||||
@@ -338,8 +333,7 @@
|
||||
[:div.flex.gap-2
|
||||
"Balance Sheet"
|
||||
(tags/pill- {:color :secondary} "WIP")])
|
||||
|
||||
|
||||
|
||||
(menu-button- {:href (hu/url (bidi/path-for ssr-routes/only-routes
|
||||
::ledger-routes/external-import-page)
|
||||
{:date-range "month"})
|
||||
@@ -349,7 +343,6 @@
|
||||
"External Import"
|
||||
(tags/pill- {:color :secondary} "WIP")]))))]))
|
||||
|
||||
|
||||
(defn company-aside-nav- [request]
|
||||
[:ul {:class "space-y-2" :hx-boost "true"}
|
||||
[:li
|
||||
@@ -465,7 +458,6 @@
|
||||
:hx-boost true}
|
||||
"Background Jobs")]
|
||||
|
||||
|
||||
(menu-button- {:icon svg/arrow-in
|
||||
"@click.prevent" "if (selected == 'import') {selected = null } else { selected = 'import'} "}
|
||||
"Import")
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns auto-ap.ssr.components.bank-account-icon
|
||||
(ns auto-ap.ssr.components.bank-account-icon
|
||||
(:require [auto-ap.ssr.hiccup-helper :as hh]
|
||||
[auto-ap.ssr.svg :as svg]))
|
||||
|
||||
|
||||
@@ -8,15 +8,15 @@
|
||||
[:a {:href "#", :class "inline-flex w-4 h-4 mr-2 items-center text-sm font-medium text-gray-700 hover:text-blue-600 dark:text-gray-400 dark:hover:text-white"}
|
||||
[:div.w-4.h-4 svg/home]]]
|
||||
(for [p steps]
|
||||
[:li
|
||||
[:li
|
||||
[:div {:class "flex items-center"}
|
||||
|
||||
[:div {:class "w-6 h-6 text-gray-400",}
|
||||
|
||||
[:div {:class "w-6 h-6 text-gray-400"}
|
||||
svg/breadcrumb-component]
|
||||
|
||||
|
||||
(update-in p [1 :class] str " ml-1 text-sm font-medium text-gray-700 hover:text-blue-600 md:ml-2 dark:text-gray-400 dark:hover:text-white")]])
|
||||
#_[:li {:aria-current "page"}
|
||||
[:div {:class "flex items-center"}
|
||||
[:svg {:aria-hidden "true", :class "w-6 h-6 text-gray-400", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"}
|
||||
[:path {:fill-rule "evenodd", :d "M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z", :clip-rule "evenodd"}]]
|
||||
[:span {:class "ml-1 text-sm font-medium text-gray-500 md:ml-2 dark:text-gray-400"} "Flowbite"]]]]])
|
||||
[:div {:class "flex items-center"}
|
||||
[:svg {:aria-hidden "true", :class "w-6 h-6 text-gray-400", :fill "currentColor", :viewbox "0 0 20 20", :xmlns "http://www.w3.org/2000/svg"}
|
||||
[:path {:fill-rule "evenodd", :d "M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z", :clip-rule "evenodd"}]]
|
||||
[:span {:class "ml-1 text-sm font-medium text-gray-500 md:ml-2 dark:text-gray-400"} "Flowbite"]]]]])
|
||||
|
||||
@@ -113,9 +113,9 @@
|
||||
(= :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 ")
|
||||
(= :secondary-light (:color params)) (str " text-blue-800 bg-white-200 border-gray-100 border hover:bg-blue-100 focus:ring-blue-100 dark:bg-blue-400 dark:hover:bg-blue-800 ")
|
||||
|
||||
|
||||
(not (nil? (:color params)))
|
||||
(str " text-white " (bg-colors (:color params) (:disabled params)))
|
||||
(str " text-white " (bg-colors (:color params) (:disabled params)))
|
||||
|
||||
(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")))
|
||||
@@ -126,7 +126,7 @@
|
||||
(svg/spinner {:class "inline w-4 h-4 text-white"})
|
||||
[:div.ml-3 "Loading..."]])
|
||||
(into [:div.inline-flex.gap-2.items-center.justify-center {:class (when (:indicator? params true)
|
||||
"htmx-indicator-hidden")}]
|
||||
"htmx-indicator-hidden")}]
|
||||
children)])
|
||||
|
||||
(defn icon-button- [params & children]
|
||||
@@ -162,8 +162,6 @@
|
||||
[: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"))
|
||||
@@ -191,7 +189,7 @@
|
||||
(defn navigation-button- [{:keys [class next-arrow?] :or {next-arrow? true} :as params} & children]
|
||||
[:button
|
||||
(-> params
|
||||
(update :class (fnil hh/add-class "")
|
||||
(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
|
||||
@@ -211,7 +209,7 @@
|
||||
{:class "space-y-4 w-72"}
|
||||
(for [n children]
|
||||
[:li n])
|
||||
|
||||
|
||||
#_[:li
|
||||
[:div
|
||||
{:class
|
||||
@@ -231,7 +229,6 @@
|
||||
[: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 "")
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
[clojure.string :as str]))
|
||||
|
||||
(defn card- [params & children]
|
||||
(into [:div (update params :class
|
||||
(into [:div (update params :class
|
||||
#(cond-> (or % "")
|
||||
(not (str/includes? (or % "") "bg-")) (hh/add-class "dark:bg-gray-800 bg-white ")
|
||||
true (hh/add-class "shadow-md sm:rounded-lg border-2 border-gray-200 dark:border-gray-900 overflow-hidden")))]
|
||||
@@ -13,6 +13,6 @@
|
||||
(defn content-card- [params & children]
|
||||
[:section (merge params {:class (hh/add-class " py-3 sm:py-5" (:class params))})
|
||||
[:div {:class (:max-w params "max-w-screen-2xl")}
|
||||
(into
|
||||
[:div {:class "relative overflow-scroll shadow-md dark:bg-gray-800 sm:rounded-lg border-2 border-gray-200 dark:border-gray-900 bg-white"}]
|
||||
children)]])
|
||||
(into
|
||||
[:div {:class "relative overflow-scroll shadow-md dark:bg-gray-800 sm:rounded-lg border-2 border-gray-200 dark:border-gray-900 bg-white"}]
|
||||
children)]])
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
"@click" (format "$dispatch('sorted', {key: '%s'})" (:sort-key params))
|
||||
:style (:style params)}]
|
||||
(if (:sort-key params)
|
||||
[(into [:a {:href "#"} ] rest)]
|
||||
[(into [:a {:href "#"}] rest)]
|
||||
rest)))
|
||||
|
||||
(defn sort-header- [params & rest]
|
||||
[:th.px-4.py-3 {:scope "col" :class (:class params)
|
||||
"@click" (format "$dispatch('sorted', {key: '%s'})" (:sort-key params)) }
|
||||
(into [:a {:href "#"} ] rest)])
|
||||
"@click" (format "$dispatch('sorted', {key: '%s'})" (:sort-key params))}
|
||||
(into [:a {:href "#"}] rest)])
|
||||
|
||||
(defn row- [params & rest]
|
||||
(into [:tr (update params
|
||||
@@ -31,11 +31,11 @@
|
||||
(defn cell- [params & rest]
|
||||
(into [:td.px-4.py-2 (update params
|
||||
:class #(str (-> ""
|
||||
(hh/add-class (or % ""))))) ]
|
||||
(hh/add-class (or % "")))))]
|
||||
rest))
|
||||
|
||||
(defn right-stack-cell- [params & rest]
|
||||
(cell- params (into [:div.flex.flex-row-reverse.items-center.justify-between
|
||||
(cell- params (into [:div.flex.flex-row-reverse.items-center.justify-between
|
||||
rest])))
|
||||
|
||||
(defn checkbox-header- [params & rest]
|
||||
@@ -46,17 +46,17 @@
|
||||
|
||||
(defn data-grid-
|
||||
[{:keys [headers thead-params id] :as params} & rest]
|
||||
[:div.shrink.overflow-y-scroll
|
||||
[:div.shrink.overflow-y-scroll
|
||||
[:table (merge {:class "w-full text-sm text-left text-gray-500 dark:text-gray-400 shrink"}
|
||||
(dissoc params :headers :thead-params))
|
||||
[:thead (update thead-params :class #(-> "text-xs text-gray-800 uppercase bg-gray-50 dark:bg-gray-700 dark:text-gray-400 group-[.raw]:sticky group-[.raw]:z-10 group-[.raw]:top-0"
|
||||
(hh/add-class (or % ""))))
|
||||
(into
|
||||
[:tr]
|
||||
headers)]
|
||||
(into
|
||||
[:tbody {}]
|
||||
rest)]])
|
||||
(into
|
||||
[:tr]
|
||||
headers)]
|
||||
(into
|
||||
[:tbody {}]
|
||||
rest)]])
|
||||
|
||||
;; needed for tailwind
|
||||
;; lg:table-cell md:table-cell
|
||||
@@ -81,35 +81,35 @@
|
||||
rows] :as params} & children]
|
||||
(let [card (if raw? raw-table-card content-card-)]
|
||||
(card
|
||||
(cond-> { :id id :class (cond-> "group" raw? (hh/add-class "raw h-full flex flex-col overflow-hidden")) }
|
||||
root-params (merge root-params)
|
||||
route (assoc
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
route
|
||||
:request-method :get)
|
||||
:hx-trigger "clientSelected from:body, invalidated from:body"
|
||||
:hx-swap "outerHTML swap:300ms"))
|
||||
[:div {:class " flex flex-col px-4 py-3 space-y-3 lg:flex-row lg:items-baseline lg:justify-between lg:space-y-0 lg:space-x-4 text-gray-800 dark:text-gray-100"}
|
||||
[:h1.text-2xl.mb-3.font-bold title]
|
||||
[:div {:class "flex items-center flex-1 space-x-4"}
|
||||
[:h5
|
||||
(when subtitle
|
||||
[:span subtitle])]]
|
||||
(into [:div {:class "group-[.raw]:hidden flex flex-col flex-shrink-0 space-y-3 md:flex-row md:items-center lg:justify-end md:space-y-0 md:space-x-3"}]
|
||||
action-buttons)]
|
||||
[:div {:class "overflow-x-auto contents"}
|
||||
(data-grid- {:headers headers
|
||||
:thead-params thead-params}
|
||||
rows)]
|
||||
(cond-> {:id id :class (cond-> "group" raw? (hh/add-class "raw h-full flex flex-col overflow-hidden"))}
|
||||
root-params (merge root-params)
|
||||
route (assoc
|
||||
:hx-get (bidi/path-for ssr-routes/only-routes
|
||||
route
|
||||
:request-method :get)
|
||||
:hx-trigger "clientSelected from:body, invalidated from:body"
|
||||
:hx-swap "outerHTML swap:300ms"))
|
||||
[:div {:class " flex flex-col px-4 py-3 space-y-3 lg:flex-row lg:items-baseline lg:justify-between lg:space-y-0 lg:space-x-4 text-gray-800 dark:text-gray-100"}
|
||||
[:h1.text-2xl.mb-3.font-bold title]
|
||||
[:div {:class "flex items-center flex-1 space-x-4"}
|
||||
[:h5
|
||||
(when subtitle
|
||||
[:span subtitle])]]
|
||||
(into [:div {:class "group-[.raw]:hidden flex flex-col flex-shrink-0 space-y-3 md:flex-row md:items-center lg:justify-end md:space-y-0 md:space-x-3"}]
|
||||
action-buttons)]
|
||||
[:div {:class "overflow-x-auto contents"}
|
||||
(data-grid- {:headers headers
|
||||
:thead-params thead-params}
|
||||
rows)]
|
||||
|
||||
(when (or paginate?
|
||||
(nil? paginate?))
|
||||
[:div {:class "contents group-[.raw]:block"}
|
||||
(paginator- {:start start
|
||||
:end (Math/min (+ start per-page) total)
|
||||
:per-page per-page
|
||||
:total total
|
||||
:a-params (fn [page]
|
||||
(when (or paginate?
|
||||
(nil? paginate?))
|
||||
[:div {:class "contents group-[.raw]:block"}
|
||||
(paginator- {:start start
|
||||
:end (Math/min (+ start per-page) total)
|
||||
:per-page per-page
|
||||
:total total
|
||||
:a-params (fn [page]
|
||||
;; TODO it might be good to have a more global form defined in the specific page
|
||||
;; with elements that are part of item
|
||||
;; that way this is not deeply coupled
|
||||
@@ -117,44 +117,43 @@
|
||||
;; TODO the other way to think about this is that we want the request to include
|
||||
;; all of the correct parameters, not parameters to merge with the current ones.
|
||||
;; think sorting, filters, pagination
|
||||
{:hx-get (hu/url (bidi/path-for ssr-routes/only-routes
|
||||
route
|
||||
:request-method :get)
|
||||
{:start (* page per-page)})
|
||||
:hx-target (str "#" id)
|
||||
:hx-swap "outerHTML show:#app:top"
|
||||
:hx-indicator (str "#" id)})
|
||||
:per-page-params {:hx-get (hu/url (bidi/path-for ssr-routes/only-routes
|
||||
{:hx-get (hu/url (bidi/path-for ssr-routes/only-routes
|
||||
route
|
||||
:request-method :get))
|
||||
:hx-trigger "change"
|
||||
:hx-include "this"
|
||||
:hx-target (str "#" id) ;
|
||||
:request-method :get)
|
||||
{:start (* page per-page)})
|
||||
:hx-target (str "#" id)
|
||||
:hx-swap "outerHTML show:#app:top"
|
||||
:hx-indicator (str "#" id)}})])
|
||||
children
|
||||
[:div {:class "htmx-indicator absolute -translate-x-1/2 -translate-y-1/2 top-2/4 left-1/2 overflow-hidden w-full h-full"}
|
||||
[:div {:class "flex items-center justify-center w-full h-full border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700 bg-opacity-50" }
|
||||
[:div {:class "px-3 py-1 text-xs font-medium leading-none text-center text-blue-800 bg-blue-200 rounded-full animate-pulse dark:bg-blue-900 dark:text-blue-200"} "loading..."]]])))
|
||||
:hx-indicator (str "#" id)})
|
||||
:per-page-params {:hx-get (hu/url (bidi/path-for ssr-routes/only-routes
|
||||
route
|
||||
:request-method :get))
|
||||
:hx-trigger "change"
|
||||
:hx-include "this"
|
||||
:hx-target (str "#" id) ;
|
||||
:hx-swap "outerHTML show:#app:top"
|
||||
:hx-indicator (str "#" id)}})])
|
||||
children
|
||||
[:div {:class "htmx-indicator absolute -translate-x-1/2 -translate-y-1/2 top-2/4 left-1/2 overflow-hidden w-full h-full"}
|
||||
[:div {:class "flex items-center justify-center w-full h-full border border-gray-200 rounded-lg bg-gray-50 dark:bg-gray-800 dark:border-gray-700 bg-opacity-50"}
|
||||
[:div {:class "px-3 py-1 text-xs font-medium leading-none text-center text-blue-800 bg-blue-200 rounded-full animate-pulse dark:bg-blue-900 dark:text-blue-200"} "loading..."]]])))
|
||||
|
||||
(defn new-row- [{:keys [index colspan tr-params row-offset] :as params} & content]
|
||||
(row-
|
||||
(merge {:class "new-row"
|
||||
"x-on:htmx:after-settle.camel" "let options=$el.parentNode.querySelectorAll('tr'); let target=options[options.length-2]; $nextTick(() => $focus.within(target).first())"
|
||||
(merge {:class "new-row"
|
||||
"x-on:htmx:after-settle.camel" "let options=$el.parentNode.querySelectorAll('tr'); let target=options[options.length-2]; $nextTick(() => $focus.within(target).first())"
|
||||
|
||||
:x-data (hx/json {:newRowIndex index
|
||||
:offset (or row-offset 0)}) }
|
||||
tr-params)
|
||||
(cell- {:colspan colspan
|
||||
:class "bg-gray-100"}
|
||||
[:div.flex.justify-center
|
||||
(a-button- (merge
|
||||
(dissoc params :index :colspan)
|
||||
{"@click.prevent" "$dispatch('newRow', {index: (newRowIndex++)})"
|
||||
:color :secondary
|
||||
:hx-trigger "newRow"
|
||||
:hx-vals (hiccup/raw "js:{index: event.detail.index }")
|
||||
:hx-target "closest .new-row"
|
||||
:hx-swap "beforebegin"
|
||||
})
|
||||
content)])))
|
||||
:x-data (hx/json {:newRowIndex index
|
||||
:offset (or row-offset 0)})}
|
||||
tr-params)
|
||||
(cell- {:colspan colspan
|
||||
:class "bg-gray-100"}
|
||||
[:div.flex.justify-center
|
||||
(a-button- (merge
|
||||
(dissoc params :index :colspan)
|
||||
{"@click.prevent" "$dispatch('newRow', {index: (newRowIndex++)})"
|
||||
:color :secondary
|
||||
:hx-trigger "newRow"
|
||||
:hx-vals (hiccup/raw "js:{index: event.detail.index }")
|
||||
:hx-target "closest .new-row"
|
||||
:hx-swap "beforebegin"})
|
||||
content)])))
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
[auto-ap.ssr.hx :as hx]
|
||||
[auto-ap.ssr.svg :as svg]))
|
||||
|
||||
|
||||
(defn modal-
|
||||
"This modal function is used to create a modal window with a stack that allows for transitioning between modals.
|
||||
|
||||
@@ -26,16 +25,16 @@
|
||||
:class (fn [c] (-> c
|
||||
(or "")
|
||||
(hh/add-class "w-full p-4 modal-card flex max-h-[inherit]"))))
|
||||
[:div {:class "bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content w-full flex flex-col max-h-full overflow-hidden" }
|
||||
[:div {:class "bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content w-full flex flex-col max-h-full overflow-hidden"}
|
||||
[:div {:class "flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600 shrink-0"} header]
|
||||
[:div {:class "px-6 py-2 space-y-6 overflow-y-scroll w-full shrink"}
|
||||
|
||||
|
||||
content]
|
||||
(when footer [:div {:class "p-4"}
|
||||
[:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex (hx/alpine-appear {:x-show "unexpectedError" :class "dark:bg-red-900 dark:text-red-300"})
|
||||
[:span {:class "w-2 h-2 mr-1 bg-red-500 rounded-full"}] [:span.px-2.py-0.5 "An unexpected error has occured. Integreat staff have been notified."]]
|
||||
(when (:error params )
|
||||
[:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex { :class "dark:bg-red-900 dark:text-red-300"}
|
||||
(when (:error params)
|
||||
[:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex {:class "dark:bg-red-900 dark:text-red-300"}
|
||||
[:span {:class "w-2 h-2 mr-1 bg-red-500 rounded-full"}]
|
||||
[:span.px-2.py-0.5 (:error params)]])
|
||||
[:div {:class "shrink-0"}
|
||||
@@ -45,7 +44,6 @@
|
||||
[:div {:class "flex items-start justify-between p-4 border-b rounded-t dark:border-gray-600 shrink-0"}
|
||||
children])
|
||||
|
||||
|
||||
(defn modal-header-attachment- [params & children]
|
||||
[:div {:class "flex items-start justify-between p-4 border-b shrink-0"}
|
||||
children])
|
||||
@@ -56,7 +54,7 @@
|
||||
|
||||
(defn modal-footer- [params & children]
|
||||
[:div {:class "p-4 border-t"}
|
||||
[:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex
|
||||
[:span.items-center.bg-red-100.text-red-800.text-xs.font-medium.mb-2.p-1.rounded-full.inline-flex
|
||||
(hx/alpine-appear {:x-show "unexpectedError" :class "dark:bg-red-900 dark:text-red-300"})
|
||||
(hx/alpine-appear {:x-show "unexpectedError" :class "dark:bg-red-900 dark:text-red-300"})
|
||||
[:span {:class "w-2 h-2 bg-red-500 rounded-full"}]
|
||||
@@ -66,7 +64,7 @@
|
||||
|
||||
(defn modal-card-advanced- [params & children]
|
||||
[:div (merge params
|
||||
{:class (hh/add-class "modal-card bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content flex flex-col max-h-screen max-w-screen" (:class params "")) })
|
||||
{:class (hh/add-class "modal-card bg-white rounded-lg shadow dark:bg-gray-700 dark:text-white modal-content flex flex-col max-h-screen max-w-screen" (:class params ""))})
|
||||
children])
|
||||
|
||||
(defn success-modal- [{:keys [title]} & children]
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
[clojure.string :as str]
|
||||
[hiccup2.core :as hiccup]))
|
||||
|
||||
|
||||
(def default-input-classes
|
||||
["bg-gray-50" "border" "text-sm" "rounded-lg" "" "block"
|
||||
"p-2.5" "border-gray-300" "text-gray-900" "focus:ring-blue-500" "focus:border-blue-500"
|
||||
@@ -149,7 +148,6 @@
|
||||
[: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")})
|
||||
@@ -178,7 +176,6 @@
|
||||
:x-show "value.size > 0"}
|
||||
svg/x]])
|
||||
|
||||
|
||||
(defn multi-typeahead- [params]
|
||||
[:div.relative {:x-data (hx/json {:baseUrl (str (:url params))
|
||||
:reset_elements (js-fn "function(e) {
|
||||
@@ -268,21 +265,17 @@
|
||||
:x-effect "if (value.warning) { $nextTick(()=> warning_badge.update()) }"}
|
||||
(tags/badge- {:class "peer"} "!")
|
||||
|
||||
|
||||
[:div {:x-show "value.warning"
|
||||
: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)])])
|
||||
|
||||
|
||||
(defn use-size [size]
|
||||
(if (= :small size)
|
||||
(str " " "text-xs p-2")
|
||||
(str " " "text-sm p-2.25")))
|
||||
|
||||
|
||||
|
||||
(defn text-input- [{:keys [size error?] :as params}]
|
||||
[:input
|
||||
(-> params
|
||||
@@ -415,8 +408,6 @@
|
||||
(update :class #(str % (use-size size) " w-full"))
|
||||
(dissoc :size :name :x-model :x-modelable))]]))
|
||||
|
||||
|
||||
|
||||
(defn field-errors- [{:keys [source key]} & rest]
|
||||
(let [errors (:errors (cond-> (meta source)
|
||||
key (get key)))]
|
||||
@@ -469,8 +460,6 @@
|
||||
(defn hidden- [{:keys [name value] :as params}]
|
||||
[:input (merge {:type "hidden" :value value :name name} params)])
|
||||
|
||||
|
||||
|
||||
(defn toggle- [params & children]
|
||||
[:label {:class "inline-flex items-center cursor-pointer"}
|
||||
[:input (merge {:type "checkbox", :class "sr-only peer"} params)]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns auto-ap.ssr.components.link-dropdown
|
||||
(ns auto-ap.ssr.components.link-dropdown
|
||||
(:require [auto-ap.ssr.components :as com]
|
||||
[auto-ap.ssr.hx :as hx]
|
||||
[auto-ap.ssr.svg :as svg]))
|
||||
@@ -8,8 +8,7 @@
|
||||
[:div {:x-data (hx/json {})}
|
||||
|
||||
(com/a-icon-button {:class "relative"
|
||||
"@click.prevent" "$tooltip($refs.tooltip, {content: ()=>$refs.tooltip.innerHTML, theme: 'light', allowHTML: true, interactive:true, popperOptions: {strategy: 'fixed', modifiers: [{name: 'flip', options: {fallbackPlacements: ['top']}}]}})"
|
||||
}
|
||||
"@click.prevent" "$tooltip($refs.tooltip, {content: ()=>$refs.tooltip.innerHTML, theme: 'light', allowHTML: true, interactive:true, popperOptions: {strategy: 'fixed', modifiers: [{name: 'flip', options: {fallbackPlacements: ['top']}}]}})"}
|
||||
svg/paperclip
|
||||
(com/badge {:color "blue"} (count links)))
|
||||
[:template {:x-ref "tooltip"}
|
||||
|
||||
@@ -15,12 +15,11 @@
|
||||
[malli.core :as mc]
|
||||
[malli.core :as m]))
|
||||
|
||||
|
||||
(def default-form-props {:hx-ext "response-targets"
|
||||
:hx-swap "outerHTML"
|
||||
:hx-target-400 "#form-errors .error-content"
|
||||
:hx-trigger "submit"
|
||||
:hx-target "this" })
|
||||
:hx-target "this"})
|
||||
|
||||
(defprotocol ModalWizardStep
|
||||
(step-key [this])
|
||||
@@ -57,7 +56,6 @@
|
||||
(or (get-in (:snapshot multi-form-state) edit-path)
|
||||
default)))
|
||||
|
||||
|
||||
(defn merge-multi-form-state [{:keys [snapshot edit-path step-params] :as multi-form-state}]
|
||||
(let [cursor (cursor/cursor (or snapshot {}))
|
||||
;; this hack makes sure that, in the event of a missing vector entry, will make sure to add it first
|
||||
@@ -87,8 +85,6 @@
|
||||
(fn encode-step-key [sk]
|
||||
(mc/encode step-key-schema sk main-transformer))))
|
||||
|
||||
|
||||
|
||||
(defn render-timeline [linear-wizard current-step validation-route]
|
||||
(let [step-names (map #(step-name (get-step linear-wizard %)) (steps linear-wizard))
|
||||
active-index (.indexOf step-names (step-name current-step))]
|
||||
@@ -148,9 +144,9 @@
|
||||
next-button-content]}]
|
||||
[:div.flex.justify-end
|
||||
[:div.flex.items-baseline.gap-x-4
|
||||
(let [step-errors (:step-params fc/*form-errors*)]
|
||||
(com/form-errors {:errors (or (:errors step-errors)
|
||||
(when (sequential? step-errors) step-errors))}))
|
||||
(let [step-errors (:step-params fc/*form-errors*)]
|
||||
(com/form-errors {:errors (or (:errors step-errors)
|
||||
(when (sequential? step-errors) step-errors))}))
|
||||
(when (not= (first (steps linear-wizard))
|
||||
(step-key step))
|
||||
(when validation-route
|
||||
@@ -172,7 +168,7 @@
|
||||
(com/modal-card-advanced
|
||||
{"@keydown.enter.prevent.stop" "if ($refs.next ) {$refs.next.click()}"
|
||||
:class (str
|
||||
(or width-height-class " md:w-[750px] md:h-[600px] ")
|
||||
(or width-height-class " md:w-[750px] md:h-[600px] ")
|
||||
" w-full h-full
|
||||
group-[.forward]/transition:htmx-swapping:opacity-0
|
||||
group-[.forward]/transition:htmx-swapping:-translate-x-1/4
|
||||
@@ -261,7 +257,7 @@
|
||||
:oob (or oob []))))
|
||||
|
||||
(def next-handler
|
||||
|
||||
|
||||
(-> (fn [{:keys [wizard] :as request}]
|
||||
(let [current-step (get-current-step wizard)]
|
||||
(if (satisfies? CustomNext current-step)
|
||||
@@ -361,8 +357,6 @@
|
||||
(render-wizard wizard request)])
|
||||
(get query-params :replace-modal) (assoc-in [:headers "hx-trigger"] "modalswap")))
|
||||
|
||||
|
||||
|
||||
(defn wrap-init-multi-form-state [handler get-multi-form-state]
|
||||
(->
|
||||
(fn init-multi-form [request]
|
||||
|
||||
@@ -6,16 +6,15 @@
|
||||
[config.core :refer [env]]
|
||||
[hiccup2.core :as hiccup]))
|
||||
|
||||
(defn page- [{:keys [nav page-specific client clients client-selection identity app-params request] :or {app-params {}} } & children]
|
||||
[:div#app { "@notification.document" "notificationDetails=event.detail.value; showNotification=true"
|
||||
(defn page- [{:keys [nav page-specific client clients client-selection identity app-params request] :or {app-params {}}} & children]
|
||||
[:div#app {"@notification.document" "notificationDetails=event.detail.value; showNotification=true"
|
||||
|
||||
:x-data (hx/json {:leftNavShow true
|
||||
:showError false
|
||||
:errorDetails ""
|
||||
:showNotification false
|
||||
:notificationDetails ""})
|
||||
"@htmx:response-error.camel" "errorDetails = $event.detail.xhr.response; showError=true;"
|
||||
}
|
||||
"@htmx:response-error.camel" "errorDetails = $event.detail.xhr.response; showError=true;"}
|
||||
(navbar- {:client-selection client-selection
|
||||
:clients clients
|
||||
:client client
|
||||
@@ -29,33 +28,32 @@
|
||||
:page-specific page-specific})
|
||||
[:div#main-content {:class "relative w-full h-full overflow-y-auto px-4 bg-gray-100 dark:bg-gray-900 min-h-content lg:pl-64"
|
||||
":class" "leftNavShow ? 'lg:pl-64' : ''"
|
||||
:x-effect "leftNavShow ? $el.classList.add('lg:pl-64') : $el.classList.remove('lg:pl-64')"
|
||||
}
|
||||
:x-effect "leftNavShow ? $el.classList.add('lg:pl-64') : $el.classList.remove('lg:pl-64')"}
|
||||
[:div#notification-holder
|
||||
[:div.fixed.top-0.right-0.left-0.z-30.mx-auto.max-w-screen-lg.w-screen-lg.my-0.pt-8.rounded-lg {:x-show "showNotification" }
|
||||
[:div.fixed.top-0.right-0.left-0.z-30.mx-auto.max-w-screen-lg.w-screen-lg.my-0.pt-8.rounded-lg {:x-show "showNotification"}
|
||||
[:div.relative
|
||||
[:button.absolute.right-2.top-2.w-6.h-6.z-50.text-blue-400
|
||||
{ "@click" "showNotification=false"}
|
||||
{"@click" "showNotification=false"}
|
||||
svg/filled-x]]
|
||||
|
||||
|
||||
[:div.m-4.overflow-auto.z-30.flex.center-items.justify-center.text-blue-800.bg-blue-50.dark:bg-gray-800.dark:text-blue-400.border-blue-300.rounded-lg.border.max-h-96
|
||||
{:x-show "showNotification"
|
||||
"x-transition:enter" "transition duration-300 transform ease-in-out"
|
||||
"x-transition:enter-start" "opacity-0 translate-y-full"
|
||||
"x-transition:enter-end" "opacity-100 translate-y-0"
|
||||
"x-transition:leave" "transition duration-300 transform ease-in-out"
|
||||
"x-transition:leave-start" "opacity-100 translate-y-0"
|
||||
"x-transition:leave-end" "opacity-0 translate-y-full"}
|
||||
|
||||
"x-transition:enter" "transition duration-300 transform ease-in-out"
|
||||
"x-transition:enter-start" "opacity-0 translate-y-full"
|
||||
"x-transition:enter-end" "opacity-100 translate-y-0"
|
||||
"x-transition:leave" "transition duration-300 transform ease-in-out"
|
||||
"x-transition:leave-start" "opacity-100 translate-y-0"
|
||||
"x-transition:leave-end" "opacity-0 translate-y-full"}
|
||||
|
||||
[:div {:class "p-4 text-lg w-full" :role "alert"}
|
||||
[:div.text-sm
|
||||
[:pre#notification-details.text-xs {:x-html "notificationDetails"}]]]]]]
|
||||
[:div {:x-show "showError"
|
||||
:x-init ""}
|
||||
[:div {:x-show "showError"
|
||||
:x-init ""}
|
||||
[:div.fixed.top-0.right-0.left-0.z-30.mx-auto.max-w-screen-lg.w-screen-lg.my-0.pt-8.rounded-lg
|
||||
[:div.relative
|
||||
[:button.absolute.right-2.top-2.w-6.h-6.z-50.text-red-600
|
||||
{ "@click" "showError=false"}
|
||||
{"@click" "showError=false"}
|
||||
svg/filled-x]]
|
||||
|
||||
[:div.m-4.overflow-auto.z-30.flex.center-items.justify-center.text-red-800.bg-red-50.dark:bg-gray-800.dark:text-red-400.border-red-300.rounded-lg.border.max-h-96
|
||||
@@ -63,7 +61,7 @@
|
||||
"x-transition:enter" "transition duration-300"
|
||||
"x-transition:enter-start" "opacity-0"
|
||||
"x-transition:enter-end" "opacity-100"}
|
||||
|
||||
|
||||
[:div {:class "p-4 mb-4 text-lg w-full" :role "alert"}
|
||||
[:div.inline-block.w-8.h-8.mr-2 svg/alert]
|
||||
[:span.font-medium "Oh, drat! An unexpected error has occurred."]
|
||||
@@ -73,6 +71,4 @@
|
||||
[:pre#error-details.text-xs {:x-show "expandError" :x-text "errorDetails"}]]]]]]
|
||||
(into
|
||||
[:div.p-4]
|
||||
children)]]
|
||||
|
||||
])
|
||||
children)]]])
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
x
|
||||
(> y z)
|
||||
z
|
||||
:else
|
||||
:else
|
||||
y))
|
||||
|
||||
(def elipsis-button
|
||||
@@ -24,42 +24,41 @@
|
||||
current-page (long (Math/floor (/ start per-page)))
|
||||
first-page-button (bound 0 (- current-page buttons-before) (- total-pages max-buttons))
|
||||
all-buttons (into [] (for [x (range total-pages)]
|
||||
[:li
|
||||
[:li
|
||||
[:a (-> (a-params x)
|
||||
(update
|
||||
:class #(cond-> %
|
||||
true (str " flex items-center justify-center px-3 py-2 text-sm leading-tight border ")
|
||||
(update
|
||||
:class #(cond-> %
|
||||
true (str " flex items-center justify-center px-3 py-2 text-sm leading-tight border ")
|
||||
|
||||
(= current-page x)
|
||||
(str " text-primary-600 bg-primary-50 border-primary-300 hover:bg-primary-100 hover:text-primary-700 dark:border-gray-700 dark:bg-gray-700 dark:text-white")
|
||||
(= current-page x)
|
||||
(str " text-primary-600 bg-primary-50 border-primary-300 hover:bg-primary-100 hover:text-primary-700 dark:border-gray-700 dark:bg-gray-700 dark:text-white")
|
||||
|
||||
(not= current-page x)
|
||||
(str " text-gray-500 bg-white border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white")))
|
||||
(not= current-page x)
|
||||
(str " text-gray-500 bg-white border-gray-300 hover:bg-gray-100 hover:text-gray-700 dark:bg-gray-800 dark:border-gray-700 dark:text-gray-400 dark:hover:bg-gray-700 dark:hover:text-white")))
|
||||
(assoc :href "#"))
|
||||
[:div.htmx-indicator.flex.items-center
|
||||
(svg/spinner {:class "inline w-4 h-4 text-black"})]
|
||||
[:div.htmx-indicator-hidden
|
||||
[:div.htmx-indicator-hidden
|
||||
(inc x)]]]))
|
||||
|
||||
|
||||
last-page-button (Math/min (long total-pages) (long (+ max-buttons first-page-button)))
|
||||
|
||||
extended-last-page-button (when (not= last-page-button total-pages)
|
||||
(list
|
||||
elipsis-button
|
||||
(last all-buttons)))
|
||||
elipsis-button
|
||||
(last all-buttons)))
|
||||
|
||||
extended-first-page-button (when (not= first-page-button 0)
|
||||
(list
|
||||
(first all-buttons)
|
||||
elipsis-button))]
|
||||
(first all-buttons)
|
||||
elipsis-button))]
|
||||
[:nav.flex.items-center.space-x-3
|
||||
[:span.text-sm.text-gray-500 "Per page"]
|
||||
(inputs/select- (merge per-page-params
|
||||
{:options [[25 "25"]
|
||||
[50 "50"]
|
||||
[100 "100"]
|
||||
[200 "200"]]
|
||||
[50 "50"]
|
||||
[100 "100"]
|
||||
[200 "200"]]
|
||||
:value per-page
|
||||
:name "per-page"}))
|
||||
[:ul {:class "inline-flex items-stretch -space-x-px"}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
(ns auto-ap.ssr.components.periods
|
||||
(ns auto-ap.ssr.components.periods
|
||||
(:require
|
||||
[auto-ap.ssr.components.buttons :as buttons]
|
||||
[auto-ap.ssr.components.inputs :as inputs]
|
||||
@@ -19,7 +19,7 @@
|
||||
(atime/unparse-local atime/normal-date))})
|
||||
|
||||
:x-effect "console.log('periods are', periods)"
|
||||
:x-init "$watch('periods', ds => source_date= ds.length > 0 ? ds[0].end : null)" }
|
||||
:x-init "$watch('periods', ds => source_date= ds.length > 0 ? ds[0].end : null)"}
|
||||
[:template {:x-for "(v,n) in periods" ":key" "n"}
|
||||
[:div
|
||||
[:input {:type "hidden"
|
||||
@@ -29,62 +29,61 @@
|
||||
":name" "'periods[' + n + '][end]'"
|
||||
:x-model "v.end"}]]]
|
||||
(buttons/a-button- {"x-tooltip.on.click.theme.dropdown.placement.bottom.interactive" "{content: ()=> $refs.tooltip.innerHTML, allowHTML: true, appendTo: $root}"
|
||||
:indicator? false}
|
||||
[:template {:x-if "periods.length == 0"}
|
||||
[:span.text-left.text-gray-400 "None selected"]]
|
||||
[:template {:x-if "periods.length < 3 && periods.length > 0"}
|
||||
[:span.inline-flex.gap-2
|
||||
[:template {:x-for "p in periods"}
|
||||
(tags/pill- {:color :secondary}
|
||||
[:span {:x-text "p.start"}]
|
||||
" - "
|
||||
[:span {:x-text "p.end"}])]]]
|
||||
[:template {:x-if "periods.length >= 3"}
|
||||
(tags/pill- {:color :secondary}
|
||||
[:span {:x-text "periods.length"}]
|
||||
" periods selected")]
|
||||
[:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"}
|
||||
svg/drop-down])
|
||||
:indicator? false}
|
||||
[:template {:x-if "periods.length == 0"}
|
||||
[:span.text-left.text-gray-400 "None selected"]]
|
||||
[:template {:x-if "periods.length < 3 && periods.length > 0"}
|
||||
[:span.inline-flex.gap-2
|
||||
[:template {:x-for "p in periods"}
|
||||
(tags/pill- {:color :secondary}
|
||||
[:span {:x-text "p.start"}]
|
||||
" - "
|
||||
[:span {:x-text "p.end"}])]]]
|
||||
[:template {:x-if "periods.length >= 3"}
|
||||
(tags/pill- {:color :secondary}
|
||||
[:span {:x-text "periods.length"}]
|
||||
" periods selected")]
|
||||
[:div {:class "w-3 h-3 m-1 inline ml-1 justify-self-end text-gray-500 self-center"}
|
||||
svg/drop-down])
|
||||
[:template {:x-ref "tooltip"}
|
||||
[:div.p-4.gap-2 {:class "bg-gray-100 dark:bg-gray-600 rounded-lg shadow-2xl w-max z-50 ring-1 p-4 w-[700px] "}
|
||||
[:div.flex.flex-col.gap-2
|
||||
(tabs/tabs-
|
||||
{:tabs [{:name "Quick"
|
||||
:content [:div.flex.flex.gap-2
|
||||
(inputs/calendar-input- {:placeholder "12/21/2020" :x-model "source_date"})
|
||||
[:div.flex.flex-col.gap-2
|
||||
(buttons/a-button- {"@click" "periods=getFourWeekPeriodsPeriods(source_date)"} [:span "13 periods, ending "
|
||||
[:span {:x-text "source_date"}]])
|
||||
(buttons/a-button- {"@click" "periods=[calendarYearPeriod(source_date)]"} [:span "Calendar year ("
|
||||
[:span {:x-text "parseMMDDYYYY(source_date).getFullYear()"}]
|
||||
")"])
|
||||
(buttons/a-button- {"@click" "periods=getTwelveCalendarMonthsPeriods(source_date)"} [:span "12 months, ending "
|
||||
[:span {:x-text "parseMMDDYYYY(source_date).toLocaleString('default', { month: 'long' })"}]])
|
||||
[:hr {:class "h-px my-1 bg-gray-200 border-0 dark:bg-gray-700"} ]
|
||||
(buttons/a-button- {"@click" "periods=getLastMonthPeriods()"} "Last Month")
|
||||
(buttons/a-button- {"@click" "periods=getMonthToDatePeriods()"} "Month to date")
|
||||
(buttons/a-button- {"@click" "periods=getYearToDatePeriods()"} "Year to date")
|
||||
(buttons/a-button- {"@click" "periods=[]"} "Clear")]]}
|
||||
{:name "Advanced"
|
||||
:content [:div.flex.gap-4 {:class "overflow-hidden max-h-[300px]"
|
||||
:x-data (hx/json {:calendarTarget "0"
|
||||
:calendarWhich "start"})
|
||||
"@change-date.camel" "$el.querySelectorAll('.text-inputs.' + calendarWhich)[calendarTarget].focus()"}
|
||||
(inputs/calendar-input- {:x-model "periods[calendarTarget][calendarWhich]"})
|
||||
[:div.flex.flex-col.gap-4.p-2
|
||||
[:div.overflow-y-scroll.flex.flex-col.gap-4
|
||||
[:template {:x-for "(p, i) in periods" ":key" "i"}
|
||||
[:div.flex.gap-4.
|
||||
(inputs/text-input- { :class "text-inputs start" :x-model "periods[i].start" "@focus" "calendarTarget =i; calendarWhich='start'" })
|
||||
(inputs/text-input- { :class "text-inputs end" :x-model "periods[i].end" "@focus" "calendarTarget =i; calendarWhich='end'"})
|
||||
(buttons/a-icon-button- {"@click.prevent.stop" "periods=periods.filter((_, i2) => i !== i2); calendarTarget=0"} svg/x)]
|
||||
#_(com/pill {:color :secondary}
|
||||
[:span {:x-text "p.start"}]
|
||||
" - "
|
||||
[:span {:x-text "p.end"}])]]
|
||||
(buttons/button- {"@click.prevent.stop" "periods.push({start: '', end: ''}); calendarTarget=0" :class "w-32"} "Add new period")]
|
||||
]}]
|
||||
:active "Quick"}) ]]]])
|
||||
{:tabs [{:name "Quick"
|
||||
:content [:div.flex.flex.gap-2
|
||||
(inputs/calendar-input- {:placeholder "12/21/2020" :x-model "source_date"})
|
||||
[:div.flex.flex-col.gap-2
|
||||
(buttons/a-button- {"@click" "periods=getFourWeekPeriodsPeriods(source_date)"} [:span "13 periods, ending "
|
||||
[:span {:x-text "source_date"}]])
|
||||
(buttons/a-button- {"@click" "periods=[calendarYearPeriod(source_date)]"} [:span "Calendar year ("
|
||||
[:span {:x-text "parseMMDDYYYY(source_date).getFullYear()"}]
|
||||
")"])
|
||||
(buttons/a-button- {"@click" "periods=getTwelveCalendarMonthsPeriods(source_date)"} [:span "12 months, ending "
|
||||
[:span {:x-text "parseMMDDYYYY(source_date).toLocaleString('default', { month: 'long' })"}]])
|
||||
[:hr {:class "h-px my-1 bg-gray-200 border-0 dark:bg-gray-700"}]
|
||||
(buttons/a-button- {"@click" "periods=getLastMonthPeriods()"} "Last Month")
|
||||
(buttons/a-button- {"@click" "periods=getMonthToDatePeriods()"} "Month to date")
|
||||
(buttons/a-button- {"@click" "periods=getYearToDatePeriods()"} "Year to date")
|
||||
(buttons/a-button- {"@click" "periods=[]"} "Clear")]]}
|
||||
{:name "Advanced"
|
||||
:content [:div.flex.gap-4 {:class "overflow-hidden max-h-[300px]"
|
||||
:x-data (hx/json {:calendarTarget "0"
|
||||
:calendarWhich "start"})
|
||||
"@change-date.camel" "$el.querySelectorAll('.text-inputs.' + calendarWhich)[calendarTarget].focus()"}
|
||||
(inputs/calendar-input- {:x-model "periods[calendarTarget][calendarWhich]"})
|
||||
[:div.flex.flex-col.gap-4.p-2
|
||||
[:div.overflow-y-scroll.flex.flex-col.gap-4
|
||||
[:template {:x-for "(p, i) in periods" ":key" "i"}
|
||||
[:div.flex.gap-4.
|
||||
(inputs/text-input- {:class "text-inputs start" :x-model "periods[i].start" "@focus" "calendarTarget =i; calendarWhich='start'"})
|
||||
(inputs/text-input- {:class "text-inputs end" :x-model "periods[i].end" "@focus" "calendarTarget =i; calendarWhich='end'"})
|
||||
(buttons/a-icon-button- {"@click.prevent.stop" "periods=periods.filter((_, i2) => i !== i2); calendarTarget=0"} svg/x)]
|
||||
#_(com/pill {:color :secondary}
|
||||
[:span {:x-text "p.start"}]
|
||||
" - "
|
||||
[:span {:x-text "p.end"}])]]
|
||||
(buttons/button- {"@click.prevent.stop" "periods.push({start: '', end: ''}); calendarTarget=0" :class "w-32"} "Add new period")]]}]
|
||||
:active "Quick"})]]]])
|
||||
|
||||
(defn dates-dropdown- [{:keys [value name]}]
|
||||
[:div {:x-data (hx/json {:dates (map #(atime/unparse-local % atime/normal-date) value)})}
|
||||
@@ -122,16 +121,16 @@
|
||||
(buttons/a-button- {"@click" "dates=[]"} "Clear")]]}
|
||||
{:name "Advanced oooo"
|
||||
:content [:div.flex.gap-4 {:class "overflow-hidden max-h-[300px]"
|
||||
:x-data (hx/json {:calendarTarget "0" })
|
||||
:x-data (hx/json {:calendarTarget "0"})
|
||||
"@change-date.camel" "$el.querySelectorAll('.text-inputs')[calendarTarget].focus();"}
|
||||
(inputs/calendar-input- {:x-model "dates[calendarTarget]" })
|
||||
(inputs/calendar-input- {:x-model "dates[calendarTarget]"})
|
||||
[:div.flex.flex-col.gap-4.p-2
|
||||
[:div.overflow-y-scroll.flex.flex-col.gap-4
|
||||
[:template {:x-for "(p, i) in dates" ":key" "i"}
|
||||
[:div.flex.gap-4.
|
||||
(inputs/text-input- {:x-model "dates[i]"
|
||||
(inputs/text-input- {:x-model "dates[i]"
|
||||
"@focus" "calendarTarget =i; "
|
||||
:class "text-inputs"})
|
||||
(buttons/a-icon-button- {"@click.prevent.stop" "dates=dates.filter((_, i2) => i !== i2); calendarTarget=0"} svg/x)] ]]
|
||||
(buttons/a-icon-button- {"@click.prevent.stop" "dates=dates.filter((_, i2) => i !== i2); calendarTarget=0"} svg/x)]]]
|
||||
(buttons/button- {"@click.prevent.stop" "dates.push(null); calendarTarget=0" :class "w-32"} "Add new period")]]}]
|
||||
:active "Quick"})]]]])
|
||||
@@ -1,28 +1,26 @@
|
||||
(ns auto-ap.ssr.components.tabs
|
||||
(ns auto-ap.ssr.components.tabs
|
||||
(:require
|
||||
[auto-ap.ssr.hx :as hx]))
|
||||
|
||||
(defn tabs- [{:keys [tabs active]}]
|
||||
[:div.flex.flex-col.gap-2 {:x-data (hx/json {:activeTab active})}
|
||||
[:div {:class "text-sm font-medium text-center text-gray-500 border-b border-gray-200 dark:text-gray-400 dark:border-gray-700" }
|
||||
[:div {:class "text-sm font-medium text-center text-gray-500 border-b border-gray-200 dark:text-gray-400 dark:border-gray-700"}
|
||||
[:ul {:class "flex flex-wrap -mb-px"}
|
||||
(for [tab tabs]
|
||||
[:li {:class "me-2"}
|
||||
[:a {:href "#"
|
||||
:x-data (hx/json {:tabName (:name tab)})
|
||||
":data-active" (format "activeTab==tabName")
|
||||
"@click" (format "activeTab=tabName" )
|
||||
:class "inline-block data-[active]:text-blue-600 data-[active]:border-blue-600 p-4 border-b-2 rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300"}
|
||||
"@click" (format "activeTab=tabName")
|
||||
:class "inline-block data-[active]:text-blue-600 data-[active]:border-blue-600 p-4 border-b-2 rounded-t-lg hover:text-gray-600 hover:border-gray-300 dark:hover:text-gray-300"}
|
||||
(:name tab)]])
|
||||
|
||||
|
||||
|
||||
|
||||
#_[:li
|
||||
[:a {:class "inline-block p-4 text-gray-400 rounded-t-lg cursor-not-allowed dark:text-gray-500"} "Disabled"]]]]
|
||||
(for [tab tabs]
|
||||
[:div {:x-data (hx/json {:tabName (:name tab)})
|
||||
:x-show (format "activeTab==tabName")
|
||||
:x-show (format "activeTab==tabName")
|
||||
"x-transition:enter" "transition-opacity duration-300"
|
||||
"x-transition:enter-start" "opacity-0"
|
||||
"x-transition:enter-end" "opacity-100"}
|
||||
(:content tab) ])])
|
||||
"x-transition:enter-start" "opacity-0"
|
||||
"x-transition:enter-end" "opacity-100"}
|
||||
(:content tab)])])
|
||||
@@ -1,7 +1,6 @@
|
||||
(ns auto-ap.ssr.components.tags
|
||||
(:require [auto-ap.ssr.hiccup-helper :as hh]))
|
||||
|
||||
|
||||
(defn pill- [params & children]
|
||||
(into
|
||||
[:span (cond-> params
|
||||
@@ -23,7 +22,6 @@
|
||||
(defn badge- [params & children]
|
||||
[:div (merge params {:class (-> (hh/add-class "absolute inline-flex items-center z-10 justify-center w-6 h-6 text-xs font-black text-white
|
||||
border-3 border-white rounded-full -top-2 -right-2 dark:border-gray-900"
|
||||
(:class params)
|
||||
)
|
||||
(:class params))
|
||||
(hh/add-class (or (some-> (:color params) (#(str "bg-" % "-300")))
|
||||
"bg-red-300")))}) children])
|
||||
|
||||
@@ -30,14 +30,14 @@
|
||||
(if active?
|
||||
[:li {:class "flex items-center text-primary-600 font-medium dark:text-primary-500"}
|
||||
[:span {:class "flex items-center justify-center w-5 h-5 mr-2 text-xs border-2 border-primary-600 rounded-full shrink-0 dark:border-primary-500"}]
|
||||
children ]
|
||||
children]
|
||||
[:li {:class (cond-> "flex items-center"
|
||||
(not visited?) (hh/add-class "text-gray-400"))}
|
||||
[:span {:class "flex items-center justify-center w-5 h-5 mr-2 text-xs border border-gray-500 rounded-full shrink-0 dark:border-gray-400"}
|
||||
(when visited?
|
||||
[:svg {:class "w-3 h-3 text-primary-600 dark:text-primary-500", :aria-hidden "true", :xmlns "http://www.w3.org/2000/svg", :fill "none", :viewbox "0 0 16 12"}
|
||||
[:path {:stroke "currentColor", :stroke-linecap "round", :stroke-linejoin "round", :stroke-width "2", :d "M1 5.917 5.724 10.5 15 1.5"}]])]
|
||||
children ]))
|
||||
children]))
|
||||
|
||||
(defn vertical-timeline [params & children]
|
||||
[:ol {:class (hh/add-class "flex flex-col items-start space-y-2 text-xs text-center text-gray-500 bg-gray-100 dark:text-gray-400 sm:text-base dark:bg-gray-800 sm:space-y-4 px-2"
|
||||
|
||||
@@ -10,15 +10,14 @@
|
||||
[:div {:class "flex items-center ml-3 mr-10"}
|
||||
[:div
|
||||
[:button#user-menu-button {:type "button", :class "flex text-sm bg-gray-800 rounded-full focus:ring-4 focus:ring-gray-300 dark:focus:ring-gray-600", :aria-expanded "false"
|
||||
"@click" "$tooltip($refs.tooltip, {content: ()=>$refs.tooltip.innerHTML, theme: $store.darkMode.on ? 'dark' : 'light', allowHTML: true, interactive:true})"
|
||||
}
|
||||
"@click" "$tooltip($refs.tooltip, {content: ()=>$refs.tooltip.innerHTML, theme: $store.darkMode.on ? 'dark' : 'light', allowHTML: true, interactive:true})"}
|
||||
[:span {:class "sr-only"} "Open user menu"]
|
||||
[:img {:class "w-8 h-8 rounded-full", :src (pull-attr (dc/db conn) :user/profile-image-url (:db/id identity)) :alt "user photo" :referrerpolicy "no-referrer"}]]]
|
||||
[:template {:class ""
|
||||
:x-ref "tooltip"}
|
||||
:x-ref "tooltip"}
|
||||
[:div {:class "px-4 py-3", :role "none"}
|
||||
[:p {:class "text-sm text-gray-900 dark:text-white", :role "none"} (:user/name identity)]
|
||||
[:p {:class "text-sm font-medium text-gray-900 truncate dark:text-gray-300", :role "none"} (pull-attr (dc/db conn) :user/email (:db/id identity))] ]
|
||||
[:p {:class "text-sm font-medium text-gray-900 truncate dark:text-gray-300", :role "none"} (pull-attr (dc/db conn) :user/email (:db/id identity))]]
|
||||
[:ul {:class "py-1", :role "none"}
|
||||
[:li
|
||||
[:a {:href (bidi/path-for ssr-routes/only-routes :company), :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"} "My Company"]]
|
||||
@@ -27,7 +26,7 @@
|
||||
:class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"} "Admin"])
|
||||
[:li
|
||||
[:a {:href "#", :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"
|
||||
"@click.prevent" "$store.darkMode.toggle()" }
|
||||
"@click.prevent" "$store.darkMode.toggle()"}
|
||||
"Night Mode"]]
|
||||
[:li
|
||||
[:a {:href "/logout", :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"} "Sign out"]]]] ])
|
||||
[:a {:href "/logout", :class "block px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 dark:text-gray-300 dark:hover:bg-gray-600 dark:hover:text-white", :role "menuitem"} "Sign out"]]]]])
|
||||
|
||||
Reference in New Issue
Block a user