|
|
|
|
@ -1,53 +1,14 @@
|
|
|
|
|
# TODO
|
|
|
|
|
# Section labels - flat list with Section/Item types,
|
|
|
|
|
# skip sections in keyboard nav, when scrolling with keyboard
|
|
|
|
|
# itemHeight
|
|
|
|
|
# items = [
|
|
|
|
|
# Section { label = "Suggestions" },
|
|
|
|
|
# Item { name = "Calendar", type = "Application", icon = "..." },
|
|
|
|
|
# Item { name = "Weather", type = "Application", icon = "..." },
|
|
|
|
|
# Section { label = "Commands" },
|
|
|
|
|
# Item { name = "DynamoDB", subtitle = "Amazon AWS", type = "Command" },
|
|
|
|
|
# ...
|
|
|
|
|
# ];
|
|
|
|
|
#
|
|
|
|
|
# itemHeight = item \ item
|
|
|
|
|
# | Section _ \ 30
|
|
|
|
|
# | Item _ \ 44;
|
|
|
|
|
#
|
|
|
|
|
# itemYOffset = items index \
|
|
|
|
|
# sum (map itemHeight (take index items));
|
|
|
|
|
# Then render based on type:
|
|
|
|
|
# renderItem = item \ item
|
|
|
|
|
# | Section { label = l } \ ui.text { content = l, color = "#888" }
|
|
|
|
|
# | Item i \ paletteRow { ... };
|
|
|
|
|
#
|
|
|
|
|
# For keyboard nav, you'd skip sections when moving focus:
|
|
|
|
|
# nextSelectableIndex = items currentIndex direction \
|
|
|
|
|
# next = currentIndex + direction;
|
|
|
|
|
# (nth next items
|
|
|
|
|
# | Some (Section _) \ nextSelectableIndex items next direction
|
|
|
|
|
# | Some (Item _) \ next
|
|
|
|
|
# | None \ currentIndex);
|
|
|
|
|
|
|
|
|
|
paletteState = {
|
|
|
|
|
query = "",
|
|
|
|
|
focusedIndex = 0
|
|
|
|
|
focusedIndex = 0,
|
|
|
|
|
scrollOffset = 0
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
nextSelectable = items index direction \
|
|
|
|
|
next = index + direction;
|
|
|
|
|
nth next items
|
|
|
|
|
| Some (Section _) \ nextSelectable items next direction
|
|
|
|
|
| Some (Item _) \ next
|
|
|
|
|
| None \ index;
|
|
|
|
|
|
|
|
|
|
palette = config \
|
|
|
|
|
windowHeight = 400;
|
|
|
|
|
windowWidth = 600;
|
|
|
|
|
|
|
|
|
|
# results = take 8 (config.search paletteState.query);
|
|
|
|
|
results = config.search paletteState.query; # once you get scrolling..
|
|
|
|
|
results = take 100 (config.search paletteState.query);
|
|
|
|
|
|
|
|
|
|
effectiveIndex = nth paletteState.focusedIndex results
|
|
|
|
|
| Some (Section _) \ nextSelectable results paletteState.focusedIndex 1
|
|
|
|
|
@ -56,10 +17,35 @@ palette = config \
|
|
|
|
|
dialogPadding = 0;
|
|
|
|
|
|
|
|
|
|
textInputHeight = 40;
|
|
|
|
|
sectionHeight = 30;
|
|
|
|
|
contentWidth = windowWidth - (dialogPadding * 2);
|
|
|
|
|
contentHeight = windowHeight - (dialogPadding * 2);
|
|
|
|
|
listHeight = contentHeight - 40;
|
|
|
|
|
|
|
|
|
|
nextSelectable = items index direction \
|
|
|
|
|
next = index + direction;
|
|
|
|
|
nth next items
|
|
|
|
|
| Some (Section _) \ nextSelectable items next direction
|
|
|
|
|
| Some (Item _) \ next
|
|
|
|
|
| None \ index;
|
|
|
|
|
|
|
|
|
|
itemHeight = entry \ entry
|
|
|
|
|
| Section _ \ sectionHeight
|
|
|
|
|
| Item _ \ textInputHeight
|
|
|
|
|
| _ \ 0;
|
|
|
|
|
|
|
|
|
|
itemY = i \ (sum (map itemHeight (take i results))) + i;
|
|
|
|
|
|
|
|
|
|
scrollTo = index \
|
|
|
|
|
y = itemY index;
|
|
|
|
|
h = unwrapOr 0 (nth index (map itemHeight results));
|
|
|
|
|
offset = paletteState.scrollOffset;
|
|
|
|
|
(y < offset
|
|
|
|
|
| True \ y
|
|
|
|
|
| False \ (y + h > offset + listHeight
|
|
|
|
|
| True \ y + h - listHeight
|
|
|
|
|
| False \ offset));
|
|
|
|
|
|
|
|
|
|
paletteRow = config \
|
|
|
|
|
color = (config.selected | True \ "rgba(255,255,255,0.2)" | False \ "transparent");
|
|
|
|
|
|
|
|
|
|
@ -86,11 +72,13 @@ palette = config \
|
|
|
|
|
init = {},
|
|
|
|
|
|
|
|
|
|
update = state event \ event
|
|
|
|
|
| Key { printable = True } \ { state = state, emit = [paletteState.focusedIndex := nextSelectable results 0 1] }
|
|
|
|
|
| Key { key = "ArrowUp" } \
|
|
|
|
|
{ state = state, emit = [paletteState.focusedIndex := nextSelectable results effectiveIndex (0 - 1)] }
|
|
|
|
|
| Key { key = "ArrowDown" } \
|
|
|
|
|
{ state = state, emit = [paletteState.focusedIndex := nextSelectable results effectiveIndex 1] }
|
|
|
|
|
| Key { printable = True } \ { state = state, emit = [paletteState.focusedIndex := nextSelectable results 0 1, paletteState.scrollIndex := 0] }
|
|
|
|
|
| Key { key = "ArrowUp" } \ (
|
|
|
|
|
newIndex = nextSelectable results effectiveIndex (0 - 1);
|
|
|
|
|
{ state = state, emit = [paletteState.focusedIndex := newIndex, paletteState.scrollOffset := scrollTo newIndex] })
|
|
|
|
|
| Key { key = "ArrowDown" } \ (
|
|
|
|
|
newIndex = nextSelectable results effectiveIndex 1;
|
|
|
|
|
{ state = state, emit = [paletteState.focusedIndex := newIndex, paletteState.scrollOffset := scrollTo newIndex] })
|
|
|
|
|
| Key { key = "Enter" } \
|
|
|
|
|
(nth paletteState.focusedIndex results
|
|
|
|
|
| Some (Item data) \ { state = state, emit = [paletteState.focusedIndex := 0, config.onSelect data.label] }
|
|
|
|
|
@ -121,16 +109,18 @@ palette = config \
|
|
|
|
|
onChange = text \ batch [paletteState.query := text],
|
|
|
|
|
},
|
|
|
|
|
|
|
|
|
|
ui.clip {
|
|
|
|
|
scrollable {
|
|
|
|
|
w = contentWidth,
|
|
|
|
|
h = listHeight,
|
|
|
|
|
scrollX = 0,
|
|
|
|
|
scrollY = paletteState.scrollOffset,
|
|
|
|
|
child = ui.column {
|
|
|
|
|
gap = 1,
|
|
|
|
|
children = [
|
|
|
|
|
...(mapWithIndex (entry i \ entry
|
|
|
|
|
| Section title \ box {
|
|
|
|
|
w = contentWidth,
|
|
|
|
|
h = 30,
|
|
|
|
|
h = sectionHeight,
|
|
|
|
|
color = "transparent",
|
|
|
|
|
paddingLeft = 6,
|
|
|
|
|
paddingTop = 8,
|
|
|
|
|
|