95 lines
2.9 KiB
Clojure
95 lines
2.9 KiB
Clojure
(ns examples.list-selection
|
|
"List selection example - demonstrates cursor navigation and multi-select.
|
|
Mirrors bubbletea's list examples."
|
|
(:require [tui.core :as tui]
|
|
[tui.events :as ev]
|
|
[clojure.string :as str]))
|
|
|
|
;; === Model ===
|
|
(def initial-model
|
|
{:cursor 0
|
|
:items ["Pizza" "Sushi" "Tacos" "Burger" "Pasta" "Salad" "Soup" "Steak"]
|
|
:selected #{}
|
|
:submitted false})
|
|
|
|
;; === Update ===
|
|
(defn update-fn [{:keys [model event]}]
|
|
(let [{:keys [cursor items]} model]
|
|
(cond
|
|
;; Quit
|
|
(or (ev/key= event \q)
|
|
(ev/key= event \c #{:ctrl}))
|
|
{:model model :events [(ev/quit)]}
|
|
|
|
;; Move up
|
|
(or (ev/key= event :up)
|
|
(ev/key= event \k))
|
|
{:model (update model :cursor #(max 0 (dec %)))}
|
|
|
|
;; Move down
|
|
(or (ev/key= event :down)
|
|
(ev/key= event \j))
|
|
{:model (update model :cursor #(min (dec (count items)) (inc %)))}
|
|
|
|
;; Toggle selection
|
|
(ev/key= event \space)
|
|
{:model (update model :selected
|
|
#(if (contains? % cursor)
|
|
(disj % cursor)
|
|
(conj % cursor)))}
|
|
|
|
;; Submit
|
|
(ev/key= event :enter)
|
|
{:model (assoc model :submitted true)
|
|
:events [(ev/quit)]}
|
|
|
|
:else
|
|
{:model model})))
|
|
|
|
;; === View ===
|
|
(defn view [{:keys [cursor items selected submitted]} _size]
|
|
(if submitted
|
|
[:col
|
|
[:text {:bold true :fg :green} "You selected:"]
|
|
[:text ""]
|
|
(if (empty? selected)
|
|
[:text {:fg :gray} "(nothing selected)"]
|
|
[:col
|
|
(for [idx (sort selected)]
|
|
[:text (str " - " (nth items idx))])])]
|
|
|
|
[:col {:gap 1}
|
|
[:box {:border :rounded :padding [0 1] :title "What's for lunch?"}
|
|
[:col
|
|
(for [[idx item] (map-indexed vector items)]
|
|
(let [is-cursor (= idx cursor)
|
|
is-selected (contains? selected idx)]
|
|
[:row {:gap 1}
|
|
[:text {:fg (when is-cursor :cyan)} (if is-cursor ">" " ")]
|
|
[:text (if is-selected "[x]" "[ ]")]
|
|
[:text {:bold is-cursor
|
|
:fg (cond
|
|
is-selected :green
|
|
is-cursor :cyan
|
|
:else :default)}
|
|
item]]))]]
|
|
[:row {:gap 2}
|
|
[:text {:fg :gray} "j/k: move"]
|
|
[:text {:fg :gray} "space: select"]
|
|
[:text {:fg :gray} "enter: confirm"]
|
|
[:text {:fg :gray} "q: quit"]]
|
|
[:text {:fg :cyan}
|
|
(str (count selected) " item" (when (not= 1 (count selected)) "s") " selected")]]))
|
|
|
|
;; === Main ===
|
|
(defn -main [& _args]
|
|
(println "Starting list selection...")
|
|
(let [{:keys [items selected submitted]} (tui/run {:init initial-model
|
|
:update update-fn
|
|
:view view})]
|
|
(when submitted
|
|
(println)
|
|
(println "Your order:")
|
|
(doseq [idx (sort selected)]
|
|
(println " -" (nth items idx))))))
|