opencode-navigator 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,11 +1,21 @@
1
1
  import"./chunk-bv0nm1tj.js"
2
2
  import"./chunk-v6bz59xn.js";
3
- import {createComponent as _$createComponent4} from "@opentui/solid"
4
- import {mergeProps as _$mergeProps} from "@opentui/solid"
5
- import {memo as _$memo3} from "@opentui/solid"
3
+ import {createComponent as _$createComponent7} from "@opentui/solid"
4
+ import {mergeProps as _$mergeProps2} from "@opentui/solid"
5
+ import {memo as _$memo5} from "@opentui/solid"
6
6
  import {createSignal} from "solid-js"
7
7
  function toolbarPinKey(pin){return pin.kind==="action"?`action:${pin.id}`:`skill:${pin.location}`
8
8
  }
9
+ function validToolbarPinText(text){return text.length<=128&&[...text].every((character)=>{const point=character.codePointAt(0)??0
10
+ return point>=32&&point!==127&&point!==8232&&point!==8233
11
+ })
12
+ }
13
+ function toolbarPinIcons(pin,state){if(state&&pin.stateIconLists?.[state])
14
+ return pin.stateIconLists[state]
15
+ if(state&&pin.stateIcons?.[state])
16
+ return [pin.stateIcons[state]]
17
+ return pin.icons??[pin.icon]
18
+ }
9
19
  import {createDialogStack} from "./tui.js"
10
20
  import {createComponent as _$createComponent2} from "@opentui/solid"
11
21
  import {createEffect,onCleanup,untrack} from "solid-js"
@@ -72,7 +82,7 @@ if(!pin){dialogs.back()
72
82
  return
73
83
  }
74
84
  dialogs.open(()=>_$createComponent2(SelectionMenu2,{get api(){return props.api
75
- },title:"Toolbar button",options:[{title:"Configure icons\u2026",value:"configure",description:"Base and available state icons",icon:"edit"
85
+ },title:"Toolbar button",options:[{title:"Configure icons and text\u2026",value:"configure",description:"Zero to three icons, optional text and state choices",icon:"edit"
76
86
  },{title:"Move up",value:"up",description:"Earlier in the toolbar",icon:"selected"
77
87
  },{title:"Move down",value:"down",description:"Later in the toolbar",icon:"selected"
78
88
  },{title:"Unpin",value:"remove",description:"Keep the original bookmark unchanged",icon:"delete"
@@ -89,73 +99,172 @@ dialogs.back()
89
99
  }}}))
90
100
  }})
91
101
  }
102
+ import {mergeProps as _$mergeProps} from "@opentui/solid"
103
+ import {createComponent as _$createComponent6} from "@opentui/solid"
104
+ import {memo as _$memo4} from "@opentui/solid"
105
+ import {quickActionStates as quickActionStates2} from "./tui.js"
106
+ import {SelectionMenu as SelectionMenu5,terminalIcon as terminalIcon3,useIcons as useIcons3} from "./tui.js"
107
+ import {setProp as _$setProp} from "@opentui/solid"
108
+ import {effect as _$effect} from "@opentui/solid"
109
+ import {createTextNode as _$createTextNode} from "@opentui/solid"
110
+ import {insertNode as _$insertNode} from "@opentui/solid"
111
+ import {createElement as _$createElement} from "@opentui/solid"
92
112
  import {createComponent as _$createComponent3} from "@opentui/solid"
93
113
  import {memo as _$memo2} from "@opentui/solid"
94
- import {quickActionStates} from "./tui.js"
95
- import {IconPicker,SelectionMenu as SelectionMenu3,terminalIcon,useDialogState,useDialogs as useDialogs2,useIcons} from "./tui.js"
96
- function ToolbarPinDialog(props){const dialogs=useDialogs2(props.api)
97
- const icons=useIcons()
98
- const [icon,setIcon]=useDialogState("pin-icon",props.pin.icon)
99
- const [states,setStates]=useDialogState("pin-states",{...props.pin.stateIcons
100
- })
114
+ import {IconPicker,useDialogState,useDialogs as useDialogs2} from "./tui.js"
115
+ function createToolbarPinDraft(props){const dialogs=useDialogs2(props.api)
116
+ const initialStates=Object.fromEntries(Object.keys({...props.pin.stateIcons,...props.pin.stateIconLists
117
+ }).map((state)=>[state,[...toolbarPinIcons(props.pin,state)]]))
118
+ const [base,setBase]=useDialogState("pin-icons",[...toolbarPinIcons(props.pin)])
119
+ const [text,setText]=useDialogState("pin-text",props.pin.text??"")
120
+ const [states,setStates]=useDialogState("pin-state-groups",initialStates)
101
121
  const [sourceRoute]=useDialogState("pin-route",JSON.stringify(props.api.route.current))
102
122
  const [sourceTarget]=useDialogState("pin-target",props.skills?.target().key)
103
- const existing=()=>props.preferences.toolbarPins().find((pin)=>toolbarPinKey(pin)===toolbarPinKey(props.pin))
104
- function choose(state){dialogs.open(()=>_$createComponent3(IconPicker,{get api(){return props.api
105
- },get value(){return state?states()[state]??icon():icon()
106
- },onSelect:(id)=>{if(state)
107
- setStates((value)=>({...value,[state]:id
123
+ const group=(state)=>state?states()[state]??base():base()
124
+ const changeGroup=(value,state)=>{if(state)
125
+ setStates((previous)=>({...previous,[state]:[...value]
108
126
  }))
109
127
  else
110
- setIcon(id)
128
+ setBase([...value])
129
+ }
130
+ function choose(state){dialogs.open(()=>_$createComponent3(IconPicker,{get api(){return props.api
131
+ },get value(){return group(state)[0]??"bolt"
132
+ },onSelect:(id)=>{changeGroup([id,...group(state).slice(1)],state)
111
133
  dialogs.back()
112
134
  }}),"large")
113
135
  }
136
+ function editText(){dialogs.prompt({title:"Toolbar button text",value:text(),description:()=>(()=>{var _el$=_$createElement("text")
137
+ _$insertNode(_el$,_$createTextNode(`Optional single line, up to 128 characters. Leave empty for icons only.`))
138
+ _$effect((_$p)=>_$setProp(_el$,"fg",props.api.theme.current.textMuted,_$p))
139
+ return _el$
140
+ })(),onConfirm(value){if(!validToolbarPinText(value))
141
+ throw new Error("Use a single line of up to 128 characters")
142
+ setText(value.trim())
143
+ dialogs.back()
144
+ }})
145
+ }
114
146
  function save(){try{if(sourceRoute()!==JSON.stringify(props.api.route.current)||sourceTarget()!==props.skills?.target().key)
115
147
  throw new Error("Workspace or session changed; reopen pin configuration")
148
+ if(!text()&&(base().length===0||Object.values(states()).some((value)=>value.length===0)))
149
+ throw new Error("Add an icon or text for every configured appearance")
116
150
  const source=props.pin.kind==="skill"?props.pin.location:undefined
117
151
  if(!props.expected&&source&&!props.skills?.list().some((skill)=>skill.location===source))
118
152
  throw new Error("Skill source changed; choose it again")
119
- const pin={...props.pin,icon:icon(),stateIcons:states()
153
+ const stateIcons=Object.fromEntries(Object.entries(states()).filter(([,value])=>value.length===1).map(([key,value])=>[key,value[0]]))
154
+ const stateIconLists=Object.fromEntries(Object.entries(states()).filter(([,value])=>value.length!==1))
155
+ const pin={...props.pin,icon:base()[0]??props.pin.icon,icons:base().length===1?undefined:base(),text:text()||undefined,stateIcons,stateIconLists
120
156
  }
121
- props.preferences.changeToolbarPin(props.expected?{operation:"configure",key:toolbarPinKey(pin),icon:pin.icon,stateIcons:pin.stateIcons,expected:props.expected
157
+ const keys=Object.keys({...initialStates,...states()
158
+ })
159
+ props.preferences.changeToolbarPin(props.expected?{operation:"configure",key:toolbarPinKey(pin),icon:pin.icon,icons:pin.icons??null,text:pin.text??null,expected:props.expected,stateIcons:Object.fromEntries(keys.map((key)=>[key,stateIcons[key]??null])),stateIconLists:Object.fromEntries(keys.map((key)=>[key,stateIconLists[key]??null]))
122
160
  }:{operation:"pin",pin
123
161
  })
124
162
  dialogs.back()
125
163
  } catch(error){props.api.ui.toast({variant:"error",title:"Toolbar",message:String(error)
126
164
  })
127
165
  }}
128
- return _$createComponent3(SelectionMenu3,{adaptive:true,get api(){return props.api
129
- },get title(){return _$memo2(()=>props.pin.kind==="skill")()?`Pin Skill \xB7 ${props.pin.name}`:"Pin Quick Action"
130
- },height:16,get options(){return [{title:`${terminalIcon(icon(), icons.style())} Base icon`,value:"base",description:"Used when the state is unavailable or has no custom icon",icon:"edit"
131
- },...props.pin.kind==="action"?quickActionStates(props.api,props.pin.id).map((state)=>({title:`${terminalIcon(states()[state.id] ?? icon(), icons.style())} ${state.label}`,value:`state:${state.id}`,description:states()[state.id]?"Custom state icon":"Uses base icon",icon:"edit"
132
- })):[],{title:props.expected?"Save":"Pin to toolbar",value:"save",description:"Save this draft",icon:"save"
166
+ return{dialogs,base,text,states,group,changeGroup,choose,editText,save
167
+ }}
168
+ import {createComponent as _$createComponent5} from "@opentui/solid"
169
+ import {quickActionStates} from "./tui.js"
170
+ import {SelectionMenu as SelectionMenu4,terminalIcon as terminalIcon2,useDialogs as useDialogs4,useIcons as useIcons2} from "./tui.js"
171
+ import {createComponent as _$createComponent4} from "@opentui/solid"
172
+ import {memo as _$memo3} from "@opentui/solid"
173
+ import {IconPicker as IconPicker2,SelectionMenu as SelectionMenu3,terminalIcon,terminalIconLabel,useDialogState as useDialogState2,useDialogs as useDialogs3,useIcons} from "./tui.js"
174
+ function ToolbarIconGroupDialog(props){const dialogs=useDialogs3(props.api)
175
+ const icons=useIcons()
176
+ const [values,setValues]=useDialogState2("icon-group",[...props.initial])
177
+ function choose(index){dialogs.open(()=>_$createComponent4(IconPicker2,{get api(){return props.api
178
+ },get value(){return values()[index]??"bolt"
179
+ },onSelect:(id)=>{setValues((current)=>{const next=[...current]
180
+ next[index]=id
181
+ return next
182
+ })
183
+ dialogs.back()
184
+ }}),"large")
185
+ }
186
+ return _$createComponent4(SelectionMenu3,{get api(){return props.api
187
+ },get title(){return props.title
188
+ },adaptive:true,height:18,get options(){return [...values().map((id,index)=>({title:`${terminalIcon(id, icons.style())} Icon ${index + 1}`,value:`edit:${index}`,description:terminalIconLabel(id),icon:"edit"
189
+ })),...values().length<3?[{title:"Add icon\u2026",value:"add",description:`${values().length} of 3 icons selected`,icon:"add"
190
+ }]:[],{title:"Use these icons",value:"apply",description:values().length>0?"Return to the unsaved button draft":"Text-only appearance",icon:"save"
191
+ },...values().map((_id,index)=>({title:`Remove icon ${index + 1}`,value:`remove:${index}`,description:"Keep the remaining icons in order",icon:"delete"
192
+ })),{title:"Cancel",value:"cancel",description:"Discard this icon-group draft",icon:"close"
193
+ }]
194
+ },onSelect:(option)=>{if(option.value==="add")
195
+ choose(values().length)
196
+ else if(option.value.startsWith("edit:"))
197
+ choose(Number(option.value.slice(5)))
198
+ else if(option.value.startsWith("remove:"))
199
+ setValues((current)=>current.filter((_,index)=>index!==Number(option.value.slice(7))))
200
+ else{if(option.value==="apply")
201
+ props.onConfirm(values())
202
+ dialogs.back()
203
+ }}})
204
+ }
205
+ function ToolbarAppearanceDialog(props){const dialogs=useDialogs4(props.api)
206
+ const icons=useIcons2()
207
+ const states=()=>{const known=props.pin.kind==="action"?quickActionStates(props.api,props.pin.id):[]
208
+ const saved=Object.keys(props.draft.states()).filter((id)=>known.every((state)=>state.id!==id))
209
+ return [...known,...saved.map((id)=>({id,label:`Saved state: ${id}`
210
+ }))]
211
+ }
212
+ const preview=(state)=>props.draft.group(state).map((id)=>terminalIcon2(id,icons.style())).join(" ")||"No icons"
213
+ return _$createComponent5(SelectionMenu4,{get api(){return props.api
214
+ },title:"Toolbar icons and text",adaptive:true,height:18,get options(){return [{title:"Base icons\u2026",value:"base",description:`${props.draft.base().length} of 3 \xB7 ${preview()}`,icon:"edit"
215
+ },{title:"Text\u2026",value:"text",description:props.draft.text()||"Optional custom label",icon:"edit"
216
+ },...states().map((state)=>({title:`${state.label} icons\u2026`,value:`state:${state.id}`,description:preview(state.id),icon:"edit"
217
+ })),{title:"Back",value:"back",description:"Return to the unsaved button configuration",icon:"close"
218
+ }]
219
+ },onSelect:(option)=>{if(option.value==="text")
220
+ props.draft.editText()
221
+ else if(option.value==="base"||option.value.startsWith("state:")){const state=option.value==="base"?undefined:option.value.slice(6)
222
+ dialogs.open(()=>_$createComponent5(ToolbarIconGroupDialog,{get api(){return props.api
223
+ },title:"Choose zero to three icons",get initial(){return props.draft.group(state)
224
+ },onConfirm:(value)=>props.draft.changeGroup(value,state)
225
+ }))
226
+ } else
227
+ dialogs.back()
228
+ }})
229
+ }
230
+ function ToolbarPinDialog(props){const model=createToolbarPinDraft(props)
231
+ const icons=useIcons3()
232
+ const existing=()=>props.preferences.toolbarPins().some((pin)=>toolbarPinKey(pin)===toolbarPinKey(props.pin))
233
+ const preview=(state)=>model.group(state).map((id)=>terminalIcon3(id,icons.style())).join(" ")
234
+ return _$createComponent6(SelectionMenu5,{adaptive:true,get api(){return props.api
235
+ },get title(){return _$memo4(()=>props.pin.kind==="skill")()?`Pin Skill \xB7 ${props.pin.name}`:"Pin Quick Action"
236
+ },height:21,get options(){return [{title:`${preview()} Base icon`,value:"base",description:"Choose the primary icon",icon:"edit"
237
+ },...props.pin.kind==="action"?quickActionStates2(props.api,props.pin.id).map((state)=>({title:`${preview(state.id)} ${state.label}`,value:`state:${state.id}`,description:model.states()[state.id]?"Custom state icons":"Uses base icons",icon:"edit"
238
+ })):[],{title:props.expected?"Save":"Pin to toolbar",value:"save",description:"Save this button draft",icon:"save"
239
+ },{title:"Icons and text\u2026",value:"appearance",description:`${model.base().length} icons${model.text() ? ` \xB7 ${model.text()}` : ""}`,icon:"edit"
133
240
  },...existing()?[{title:"Unpin",value:"unpin",description:"Remove only this toolbar button",icon:"delete"
134
241
  }]:[],{title:"Cancel",value:"cancel",description:"Discard this draft",icon:"close"
135
242
  }]
136
243
  },onSelect:(option)=>{if(option.value==="base")
137
- choose()
244
+ model.choose()
138
245
  else if(option.value.startsWith("state:"))
139
- choose(option.value.slice(6))
246
+ model.choose(option.value.slice(6))
140
247
  else if(option.value==="save")
141
- save()
142
- else if(option.value==="unpin"){props.preferences.changeToolbarPin({operation:"remove",key:toolbarPinKey(props.pin)
248
+ model.save()
249
+ else if(option.value==="appearance")
250
+ model.dialogs.open(()=>_$createComponent6(ToolbarAppearanceDialog,_$mergeProps(props,{draft:model
251
+ })))
252
+ else{if(option.value==="unpin")
253
+ props.preferences.changeToolbarPin({operation:"remove",key:toolbarPinKey(props.pin)
143
254
  })
144
- dialogs.back()
145
- } else
146
- dialogs.back()
147
- }})
255
+ model.dialogs.back()
256
+ }}})
148
257
  }
149
258
  function navigation(input){const route=JSON.stringify(input.api.route.current)
150
259
  return input.dialogs??createDialogStack(input.api,input.preferences.lspIconStyle,()=>route===JSON.stringify(input.api.route.current),input.preferences.cornerFont)
151
260
  }
152
261
  function openToolbarPin(input){const dialogs=navigation(input)
153
262
  const current=input.preferences.toolbarPins().find((pin)=>toolbarPinKey(pin)===toolbarPinKey(input.pin))
154
- dialogs.open(()=>_$createComponent4(ToolbarPinDialog,_$mergeProps(input,{get pin(){return current??input.pin
263
+ dialogs.open(()=>_$createComponent7(ToolbarPinDialog,_$mergeProps2(input,{get pin(){return current??input.pin
155
264
  },get expected(){return current&&JSON.stringify(current)
156
265
  }})),"large")
157
266
  }
158
- function openToolbarManager(input){navigation(input).open(()=>_$createComponent4(ToolbarManager,input),"large")
267
+ function openToolbarManager(input){navigation(input).open(()=>_$createComponent7(ToolbarManager,input),"large")
159
268
  }
160
269
  export{openToolbarManager,openToolbarPin
161
270
  }