@@ -4,20 +4,12 @@ import {
44 type ServerProviderSkill ,
55 type ServerProviderSlashCommand ,
66} from "@t3tools/contracts" ;
7- import { BotIcon } from "lucide-react" ;
8- import { memo , useLayoutEffect , useMemo , useRef } from "react" ;
7+ import { memo , useLayoutEffect , useRef } from "react" ;
98
109import { type ComposerSlashCommand , type ComposerTriggerKind } from "../../composer-logic" ;
1110import { formatProviderSkillInstallSource } from "~/providerSkillPresentation" ;
1211import { cn } from "~/lib/utils" ;
13- import {
14- Command ,
15- CommandGroup ,
16- CommandGroupLabel ,
17- CommandItem ,
18- CommandList ,
19- CommandSeparator ,
20- } from "../ui/command" ;
12+ import { Command , CommandGroup , CommandItem , CommandList } from "../ui/command" ;
2113import { PierreEntryIcon } from "./PierreEntryIcon" ;
2214
2315export type ComposerCommandItem =
@@ -53,73 +45,17 @@ export type ComposerCommandItem =
5345 description : string ;
5446 } ;
5547
56- type ComposerCommandGroup = {
57- id : string ;
58- label : string | null ;
59- items : ComposerCommandItem [ ] ;
60- } ;
61-
62- function SkillGlyph ( props : { className ?: string } ) {
63- return (
64- < svg
65- viewBox = "0 0 24 24"
66- fill = "none"
67- stroke = "currentColor"
68- strokeWidth = "1.85"
69- strokeLinecap = "round"
70- strokeLinejoin = "round"
71- className = { props . className }
72- aria-hidden = "true"
73- >
74- < path d = "M21 8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16Z" />
75- < path d = "m3.3 7 8.7 5 8.7-5" />
76- < path d = "M12 22V12" />
77- </ svg >
78- ) ;
79- }
80-
81- function groupCommandItems (
82- items : ComposerCommandItem [ ] ,
83- triggerKind : ComposerTriggerKind | null ,
84- groupSlashCommandSections : boolean ,
85- ) : ComposerCommandGroup [ ] {
86- if ( triggerKind === "skill" ) {
87- return items . length > 0 ? [ { id : "skills" , label : "Skills" , items } ] : [ ] ;
88- }
89- if ( triggerKind !== "slash-command" || ! groupSlashCommandSections ) {
90- return [ { id : "default" , label : null , items } ] ;
91- }
92-
93- const builtInItems = items . filter ( ( item ) => item . type === "slash-command" ) ;
94- const providerItems = items . filter ( ( item ) => item . type === "provider-slash-command" ) ;
95-
96- const groups : ComposerCommandGroup [ ] = [ ] ;
97- if ( builtInItems . length > 0 ) {
98- groups . push ( { id : "built-in" , label : "Built-in" , items : builtInItems } ) ;
99- }
100- if ( providerItems . length > 0 ) {
101- groups . push ( { id : "provider" , label : "Provider" , items : providerItems } ) ;
102- }
103- return groups ;
104- }
105-
10648export const ComposerCommandMenu = memo ( function ComposerCommandMenu ( props : {
10749 items : ComposerCommandItem [ ] ;
10850 resolvedTheme : "light" | "dark" ;
10951 isLoading : boolean ;
11052 triggerKind : ComposerTriggerKind | null ;
111- groupSlashCommandSections ?: boolean ;
11253 emptyStateText ?: string ;
11354 activeItemId : string | null ;
11455 onHighlightedItemChange : ( itemId : string | null ) => void ;
11556 onSelect : ( item : ComposerCommandItem ) => void ;
11657} ) {
11758 const listRef = useRef < HTMLDivElement > ( null ) ;
118- const groups = useMemo (
119- ( ) =>
120- groupCommandItems ( props . items , props . triggerKind , props . groupSlashCommandSections ?? true ) ,
121- [ props . groupSlashCommandSections , props . items , props . triggerKind ] ,
122- ) ;
12359
12460 useLayoutEffect ( ( ) => {
12561 if ( ! props . activeItemId || ! listRef . current ) return ;
@@ -141,57 +77,38 @@ export const ComposerCommandMenu = memo(function ComposerCommandMenu(props: {
14177 >
14278 < div
14379 ref = { listRef }
144- className = "dropdown-glass relative w-full overflow-hidden rounded-[20px] shadow-[0_16px_40px_-18px_rgb(0_0_0/55%)] **:data-[slot=scroll-area-scrollbar]:data-[orientation=vertical]:my-4 dark:shadow-[0_18px_44px_-18px_rgb(0_0_0/80%)]"
80+ className = "chat-composer-drawer-surface chat-composer-drawer-attached relative w-full overflow-hidden **:data-[slot=scroll-area-scrollbar]:data-[orientation=vertical]:my-4"
81+ data-composer-command-drawer = "true"
14582 >
14683 { props . items . length > 0 ? (
147- < CommandList className = "max-h-72 not-empty:py-3" >
148- { groups . map ( ( group , groupIndex ) => (
149- < div key = { group . id } >
150- { groupIndex > 0 ? < CommandSeparator className = "my-0.5" /> : null }
151- < CommandGroup >
152- { group . label ? (
153- < CommandGroupLabel className = "px-3 pt-2 pb-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-secondary-label" >
154- { group . label }
155- </ CommandGroupLabel >
156- ) : null }
157- { group . items . map ( ( item ) => (
158- < ComposerCommandMenuItem
159- key = { item . id }
160- item = { item }
161- resolvedTheme = { props . resolvedTheme }
162- isActive = { props . activeItemId === item . id }
163- onHighlight = { props . onHighlightedItemChange }
164- onSelect = { props . onSelect }
165- />
166- ) ) }
167- </ CommandGroup >
168- </ div >
169- ) ) }
84+ < CommandList className = "max-h-72 scroll-pb-6 pb-6!" >
85+ < CommandGroup >
86+ { props . items . map ( ( item ) => (
87+ < ComposerCommandMenuItem
88+ key = { item . id }
89+ item = { item }
90+ resolvedTheme = { props . resolvedTheme }
91+ isActive = { props . activeItemId === item . id }
92+ onHighlight = { props . onHighlightedItemChange }
93+ onSelect = { props . onSelect }
94+ />
95+ ) ) }
96+ </ CommandGroup >
17097 </ CommandList >
17198 ) : (
172- < div className = "px-5 py-3.5" >
173- { props . triggerKind === "skill" ? (
174- < CommandGroup >
175- < CommandGroupLabel className = "px-0 pt-0 pb-1 text-[10px] font-semibold uppercase tracking-[0.08em] text-secondary-label" >
176- Skills
177- </ CommandGroupLabel >
178- < p className = "text-secondary-label text-xs" >
179- { props . isLoading
180- ? "Searching workspace skills..."
181- : ( props . emptyStateText ??
182- "No skills found. Try / to browse provider commands." ) }
183- </ p >
184- </ CommandGroup >
185- ) : (
186- < p className = "text-secondary-label text-xs" >
187- { props . isLoading
188- ? "Searching workspace files..."
189- : ( props . emptyStateText ??
190- ( props . triggerKind === "path"
99+ < div className = "px-5 pt-3.5 pb-7" >
100+ < p className = "text-secondary-label text-xs" >
101+ { props . isLoading
102+ ? props . triggerKind === "skill"
103+ ? "Searching workspace skills..."
104+ : "Searching workspace files..."
105+ : ( props . emptyStateText ??
106+ ( props . triggerKind === "skill"
107+ ? "No skills found. Try / to browse provider commands."
108+ : props . triggerKind === "path"
191109 ? "No matching files or folders."
192110 : "No matching command." ) ) }
193- </ p >
194- ) }
111+ </ p >
195112 </ div >
196113 ) }
197114 </ div >
@@ -214,7 +131,7 @@ const ComposerCommandMenuItem = memo(function ComposerCommandMenuItem(props: {
214131 value = { props . item . id }
215132 data-composer-item-id = { props . item . id }
216133 className = { cn (
217- "cursor-pointer select-none gap-2 hover:bg-transparent hover:text-inherit data-highlighted:bg-transparent data-highlighted:text-inherit" ,
134+ "cursor-pointer select-none gap-3 rounded-lg px-3 py-2! hover:bg-transparent hover:text-inherit data-highlighted:bg-transparent data-highlighted:text-inherit" ,
218135 props . isActive && "bg-accent! text-accent-foreground!" ,
219136 ) }
220137 onMouseMove = { ( ) => {
@@ -234,22 +151,11 @@ const ComposerCommandMenuItem = memo(function ComposerCommandMenuItem(props: {
234151 theme = { props . resolvedTheme }
235152 />
236153 ) : null }
237- { props . item . type === "slash-command" ? (
238- < BotIcon className = "size-4 shrink-0 text-icon-muted" />
239- ) : null }
240- { props . item . type === "provider-slash-command" ? (
241- < span className = "inline-flex size-4 shrink-0 items-center justify-center text-icon-muted" >
242- < SkillGlyph className = "size-3.5" />
154+ < span className = "flex min-w-0 flex-1 items-baseline gap-3" >
155+ < span className = "shrink-0 font-sans text-xs font-medium text-foreground" >
156+ { props . item . label }
243157 </ span >
244- ) : null }
245- { props . item . type === "skill" ? (
246- < span className = "inline-flex size-4 shrink-0 items-center justify-center text-icon-muted" >
247- < SkillGlyph className = "size-3.5" />
248- </ span >
249- ) : null }
250- < span className = "flex min-w-0 flex-1 items-center gap-2" >
251- < span className = "shrink-0" > { props . item . label } </ span >
252- < span className = "min-w-0 flex-1 truncate text-secondary-label text-xs" >
158+ < span className = "min-w-0 flex-1 truncate text-right text-secondary-label text-xs" >
253159 { props . item . description }
254160 </ span >
255161 </ span >
0 commit comments