(ns examples.list-selection "List selection example - demonstrates cursor navigation and multi-select. Mirrors bubbletea's list examples." (:require [tui.core :as tui] [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-model [{:keys [cursor items] :as model} msg] (cond ;; Quit (or (tui/key= msg "q") (tui/key= msg [:ctrl \c])) [model tui/quit] ;; Move up (or (tui/key= msg :up) (tui/key= msg "k")) [(update model :cursor #(max 0 (dec %))) nil] ;; Move down (or (tui/key= msg :down) (tui/key= msg "j")) [(update model :cursor #(min (dec (count items)) (inc %))) nil] ;; Toggle selection (tui/key= msg " ") [(update model :selected #(if (contains? % cursor) (disj % cursor) (conj % cursor))) nil] ;; Submit (tui/key= msg :enter) [(assoc model :submitted true) tui/quit] :else [model nil])) ;; === View === (defn view [{:keys [cursor items selected submitted]}] (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-model :view view})] (when submitted (println) (println "Your order:") (doseq [idx (sort selected)] (println " -" (nth items idx))))))