(ns examples.views "Multiple views example - demonstrates state machine pattern. Mirrors bubbletea's views example." (:require [tui.core :as tui] [tui.events :as ev])) ;; === Model === (def initial-model {:view :menu ; :menu, :detail, :confirm :cursor 0 :items [{:name "Profile" :desc "View and edit your profile settings"} {:name "Settings" :desc "Configure application preferences"} {:name "Help" :desc "Get help and documentation"} {:name "About" :desc "About this application"}] :selected nil}) ;; === Update === (defn update-fn [{:keys [model event]}] (let [{:keys [view cursor items]} model] (case view ;; Menu view :menu (cond (or (ev/key= event \q) (ev/key= event \c #{:ctrl})) {:model model :events [(ev/quit)]} (or (ev/key= event :up) (ev/key= event \k)) {:model (update model :cursor #(max 0 (dec %)))} (or (ev/key= event :down) (ev/key= event \j)) {:model (update model :cursor #(min (dec (count items)) (inc %)))} (ev/key= event :enter) {:model (assoc model :view :detail :selected (nth items cursor))} :else {:model model}) ;; Detail view :detail (cond (or (ev/key= event \q) (ev/key= event \c #{:ctrl})) {:model (assoc model :view :confirm)} (or (ev/key= event :escape) (ev/key= event \b)) {:model (assoc model :view :menu :selected nil)} :else {:model model}) ;; Confirm quit dialog :confirm (cond (ev/key= event \y) {:model model :events [(ev/quit)]} (or (ev/key= event \n) (ev/key= event :escape)) {:model (assoc model :view :detail)} :else {:model model})))) ;; === Views === (defn menu-view [{:keys [cursor items]}] [:col {:gap 1} [:box {:border :rounded :padding [0 1] :title "Main Menu"} [:col (for [[idx item] (map-indexed vector items)] (let [is-cursor (= idx cursor)] [:row {:gap 1} [:text {:fg (when is-cursor :cyan)} (if is-cursor ">" " ")] [:text {:bold is-cursor :fg (when is-cursor :cyan)} (:name item)]]))]] [:text {:fg :gray} "j/k: navigate enter: select q: quit"]]) (defn detail-view [{:keys [selected]}] [:col {:gap 1} [:box {:border :double :padding [1 2]} [:col {:gap 1} [:text {:bold true :fg :cyan} (:name selected)] [:text ""] [:text (:desc selected)]]] [:text {:fg :gray} "b/esc: back q: quit"]]) (defn confirm-view [_model] [:col {:gap 1} [:box {:border :rounded :padding [1 2]} [:col [:text {:bold true :fg :yellow} "Quit?"] [:text ""] [:text "Are you sure you want to quit?"] [:text ""] [:row {:gap 2} [:text {:fg :green} "[y] Yes"] [:text {:fg :red} "[n] No"]]]]]) (defn view [{:keys [view] :as model}] (case view :menu (menu-view model) :detail (detail-view model) :confirm (confirm-view model))) ;; === Main === (defn -main [& _args] (println "Starting views demo...") (tui/run {:init initial-model :update update-fn :view view}) (println "Views demo finished."))