refactor(charts): unify on Chart.js, remove Chartist

The admin page was the only consumer of Chartist while the dashboard and
expense report already use Chart.js. Convert the admin "Growth in clients"
(bar) and "Changes by hour" (line) charts to Chart.js using the same
Alpine x-data/x-init canvas pattern as the dashboard, and drop the global
Chartist CSS/JS includes from the base page.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-02 07:55:47 -07:00
parent d52159637e
commit 1f6395382d
2 changed files with 57 additions and 26 deletions

View File

@@ -10,8 +10,7 @@
[bidi.bidi :as bidi] [bidi.bidi :as bidi]
[clj-time.coerce :as coerce] [clj-time.coerce :as coerce]
[clj-time.core :as time] [clj-time.core :as time]
[datomic.api :as dc] [datomic.api :as dc]))
[hiccup2.core :as hiccup]))
(defn hourly-changes [] (defn hourly-changes []
(let [tx-instant-attr (:db/id (dc/pull (dc/db conn) '[:db/id] :db/txInstant)) (let [tx-instant-attr (:db/id (dc/pull (dc/db conn) '[:db/id] :db/txInstant))
@@ -56,34 +55,68 @@
[:div [:div
[:h1.text-2xl.mb-3.font-bold "Growth in clients"] [:h1.text-2xl.mb-3.font-bold "Growth in clients"]
[:div [:div
[:div {:class "w-full h-64" [:div.w-full.h-64
:id "client-chart" [:canvas.w-full.h-full {:x-data (hx/json {:chart nil
:data-chart (hx/json {:labels ["2 years ago" "1 year ago" "today"], :labels ["2 years ago" "1 year ago" "today"]
:series [(for [n [2 1 0] :data (for [n [2 1 0]
:let [start (time/plus (time/now) (time/years (- n)))]] :let [start (time/plus (time/now) (time/years (- n)))]]
(->> (dc/q '[:find (count ?c) (->> (dc/q '[:find (count ?c)
:in $ :in $
:where [?c :client/code]] :where [?c :client/code]]
(dc/as-of (dc/db conn) (coerce/to-date start))) (dc/as-of (dc/db conn) (coerce/to-date start)))
first first
first))]})}] first))})
[:script {:lang "javascript"} :x-init "new Chart($el, {
(hiccup/raw type: 'bar',
"new Chartist.Bar('#client-chart', JSON.parse(document.getElementById('client-chart').getAttribute('data-chart')))")]]]]) data: {
labels: labels,
datasets: [{
label: 'Clients',
data: data,
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});"}]]]]])
(com/content-card {:class "w-1/2"} (com/content-card {:class "w-1/2"}
[:div {:class "flex flex-col px-4 py-3 space-y-3"} [:div {:class "flex flex-col px-4 py-3 space-y-3"}
[:div [:div
[:h1.text-2xl.mb-3.font-bold "Changes by hour"] [:h1.text-2xl.mb-3.font-bold "Changes by hour"]
[:div [:div
[:div {:class "w-full h-64" [:div.w-full.h-64
:id "changes" [:canvas.w-full.h-full {:x-data (hx/json {:chart nil
:data-chart (hx/json {:labels (for [n (range -24 0)] :labels (for [n (range -24 0)]
(format "%d" n)), (format "%d" n))
:series [(hourly-changes)]})}] :data (hourly-changes)})
[:script {:lang "javascript"} :x-init "new Chart($el, {
(hiccup/raw type: 'line',
"new Chartist.Line('#changes', JSON.parse(document.getElementById('changes').getAttribute('data-chart')))")]]]])]) data: {
labels: labels,
datasets: [{
label: 'Changes',
data: data,
borderWidth: 1
}]
},
options: {
responsive: true,
maintainAspectRatio: false,
scales: {
y: {
beginAtZero: true
}
}
}
});"}]]]]])])
"Admin")) "Admin"))
(def key->handler (def key->handler

View File

@@ -23,8 +23,6 @@
[:title (str "Integreat | " page-name)] [:title (str "Integreat | " page-name)]
[:link {:href "/css/font.min.css", :rel "stylesheet"}] [:link {:href "/css/font.min.css", :rel "stylesheet"}]
[:link {:rel "icon" :type "image/png" :href "/favicon.png"}] [:link {:rel "icon" :type "image/png" :href "/favicon.png"}]
[:link {:rel "stylesheet" :href "//cdn.jsdelivr.net/chartist.js/latest/chartist.min.css"}]
[:script {:src "//cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"}]
[:link {:rel "stylesheet", :href "/output.css"}] [:link {:rel "stylesheet", :href "/output.css"}]
[:script {:src "https://cdn.plaid.com/link/v2/stable/link-initialize.js"}] [:script {:src "https://cdn.plaid.com/link/v2/stable/link-initialize.js"}]
[:script {:src "https://cdn.jsdelivr.net/npm/@ryangjchandler/alpine-tooltip@1.x.x/dist/cdn.min.js" :defer true}] [:script {:src "https://cdn.jsdelivr.net/npm/@ryangjchandler/alpine-tooltip@1.x.x/dist/cdn.min.js" :defer true}]