diff --git a/src/cg/05-palette.cg b/src/cg/05-palette.cg index 771c00b..8d4efe8 100644 --- a/src/cg/05-palette.cg +++ b/src/cg/05-palette.cg @@ -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,