Skip to content

Commit 706dd48

Browse files
authored
feat(leaves): add list component (#35)
The list can be filtered, and elements can be selected.
1 parent 68e7182 commit 706dd48

File tree

8 files changed

+437
-1
lines changed

8 files changed

+437
-1
lines changed

examples/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
<img src="./fullscreen/demo.gif"/>
1919
</a>
2020

21+
## List
22+
23+
<a href="./list/main.ml">
24+
<img src="./list/demo.gif"/>
25+
</a>
26+
2127
## Progress
2228

2329
<a href="./progress/main.ml">

examples/list/demo.gif

196 KB
Loading

examples/list/demo.tape

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Output demo.gif
2+
3+
Require echo
4+
5+
Set Shell "bash"
6+
Set Framerate 24
7+
Set FontSize 20
8+
Set Width 1200
9+
Set Height 600
10+
11+
Sleep 1s
12+
Type "dune exec --no-print-directory ./main.exe"
13+
Enter
14+
15+
Sleep 1s
16+
Type " "
17+
Type "j "
18+
Sleep 500ms
19+
Type "j "
20+
Sleep 500ms
21+
Type "/"
22+
Sleep 500ms
23+
Type "str"
24+
Sleep 500ms
25+
Enter
26+
Sleep 500ms
27+
Type " "
28+
Sleep 500ms
29+
Enter
30+
Sleep 2s

examples/list/dune

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
(executable
2+
(name main)
3+
(libraries minttea spices leaves str))

examples/list/main.ml

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
open Minttea
2+
module Input = Leaves.Text_input
3+
module FList = Leaves.Filtered_list
4+
5+
type model = {
6+
elements : FList.t;
7+
choices : string list option;
8+
edit_filter : bool;
9+
filter_input : Input.t;
10+
}
11+
12+
let initial_model =
13+
{
14+
(* Choices is to Some list at the end of the program *)
15+
choices = None;
16+
(* A Text_input is used to enter a substring used for filtering *)
17+
filter_input = Input.make "" ~prompt:"/" ();
18+
edit_filter = false;
19+
elements =
20+
FList.make
21+
[
22+
"brain 🧠";
23+
"bread 🍞";
24+
"butter 🧈";
25+
"cake 🍰";
26+
"carrots 🥕";
27+
"chocolate 🍫";
28+
"cupcakes 🧁";
29+
"empanadas 🥟";
30+
"hamburgers 🍔";
31+
"ice cream 🍦";
32+
"milk 🥛";
33+
"pizza 🍕";
34+
"strawberries 🍓";
35+
"waffles 🧇";
36+
"yogurt 🥛";
37+
]
38+
~style_selected:Spices.(default |> bold true)
39+
();
40+
}
41+
42+
let init _model = Command.Noop
43+
44+
let update event model : model * Command.t =
45+
if model.edit_filter then
46+
match event with
47+
(* validate the search and go back to navigating the list *)
48+
| Event.KeyDown Enter ->
49+
let elements =
50+
FList.show_string_contains model.elements
51+
(Input.current_text model.filter_input)
52+
in
53+
({ model with elements; edit_filter = false }, Command.Noop)
54+
(* cancel the search and go back to navigating the list *)
55+
| Event.KeyDown Escape ->
56+
let elements = FList.show_all model.elements in
57+
( {
58+
model with
59+
elements;
60+
edit_filter = false;
61+
filter_input = Input.set_text "" model.filter_input;
62+
},
63+
Command.Noop )
64+
(* everything else is passed to underlying component *)
65+
| _ ->
66+
let filter_input = Input.update model.filter_input event in
67+
(* incremental search: update the search on all event *)
68+
let elements =
69+
FList.show_string_contains model.elements
70+
(Input.current_text filter_input)
71+
in
72+
({ model with filter_input; elements }, Command.Noop)
73+
else
74+
match event with
75+
(* Validate the selection, print it and quit *)
76+
| Event.KeyDown Enter ->
77+
let elements = FList.get_selection model.elements in
78+
({ model with choices = Some elements }, Command.Quit)
79+
(* Quit right away *)
80+
| Event.KeyDown (Key "q" | Escape) -> (model, Command.Quit)
81+
(* Open the search Text_input *)
82+
| Event.KeyDown (Key "/") ->
83+
({ model with edit_filter = true }, Command.Noop)
84+
(* Delegate the rest to the list *)
85+
| _ ->
86+
let elements = FList.update event model.elements in
87+
({ model with elements }, Command.Noop)
88+
89+
let view model =
90+
match model.choices with
91+
(* ready to leave *)
92+
| Some elements -> String.concat "\n" elements
93+
(* normal running *)
94+
| None ->
95+
let help_msg =
96+
if model.edit_filter then "Esc: cancel filter, Enter: validate filter"
97+
else "q: quit, /: search, j/k: up/down, space: select, enter: validate."
98+
in
99+
Format.sprintf {|Pick your favorite food:
100+
101+
%s
102+
%s
103+
104+
%s|}
105+
(FList.view model.elements)
106+
(if model.edit_filter then Input.view model.filter_input else "")
107+
help_msg
108+
109+
let app = Minttea.app ~init ~update ~view ()
110+
let () = Minttea.start app ~initial_model

leaves/dune

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,4 @@
44
(library
55
(public_name leaves)
66
(name leaves)
7-
(libraries minttea spices ptime ptime.clock.os uuseg))
7+
(libraries minttea spices ptime ptime.clock.os uuseg str))

0 commit comments

Comments
 (0)