@@ -29,6 +29,29 @@ function useDebounce(value, delay) {
2929 return debouncedValue ;
3030}
3131
32+ // Custom scrollbar styles
33+ const scrollbarStyles = `
34+ .custom-scrollbar::-webkit-scrollbar {
35+ width: 6px;
36+ }
37+ .custom-scrollbar::-webkit-scrollbar-track {
38+ background: transparent;
39+ }
40+ .custom-scrollbar::-webkit-scrollbar-thumb {
41+ background-color: rgba(156, 163, 175, 0.5);
42+ border-radius: 3px;
43+ }
44+ .custom-scrollbar::-webkit-scrollbar-thumb:hover {
45+ background-color: rgba(156, 163, 175, 0.8);
46+ }
47+ .dark .custom-scrollbar::-webkit-scrollbar-thumb {
48+ background-color: rgba(75, 85, 99, 0.5);
49+ }
50+ .dark .custom-scrollbar::-webkit-scrollbar-thumb:hover {
51+ background-color: rgba(75, 85, 99, 0.8);
52+ }
53+ ` ;
54+
3255export default function AppSearchDemo ( ) {
3356 const [
3457 searchQuery ,
@@ -67,7 +90,7 @@ export default function AppSearchDemo() {
6790 // Convert spaces to underscores for name_slug searching
6891 const searchQuery = query . replace ( / \s + / g, "_" ) ;
6992 const response = await fetch (
70- `/docs/api-demo-connect/apps?q=${ encodeURIComponent ( searchQuery ) } &limit=5 ` ,
93+ `/docs/api-demo-connect/apps?q=${ encodeURIComponent ( searchQuery ) } ` ,
7194 {
7295 headers : {
7396 "Content-Type" : "application/json" ,
@@ -114,6 +137,7 @@ export default function AppSearchDemo() {
114137
115138 return (
116139 < div className = { styles . container } >
140+ < style jsx > { scrollbarStyles } </ style >
117141 < div className = { styles . header } > Search for an app</ div >
118142 < div className = "p-4" >
119143 < input
@@ -143,67 +167,81 @@ export default function AppSearchDemo() {
143167 ) }
144168
145169 { apps . length > 0 && ! isLoading && (
146- < div className = "mt-4 space-y-3" >
147- { apps . map ( ( app ) => (
148- < div
149- key = { app . id }
150- className = "p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-gray-300 dark:hover:border-gray-600 transition-colors"
151- >
152- < div className = "flex items-start gap-3" >
153- { app . icon && (
154- < img
155- src = { app . icon }
156- alt = { app . name }
157- className = "w-10 h-10 rounded"
158- />
159- ) }
160- < div className = "flex-1" >
161- < div className = "flex items-center gap-2 mb-1 flex-nowrap" >
162- < p className = "font-semibold text-base text-gray-800 dark:text-gray-200 flex-shrink-0 m-0" >
163- { app . name }
164- </ p >
165- < code className = "text-sm px-2 py-0.5 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded flex-shrink-0" >
166- { app . name_slug }
167- </ code >
168- < button
169- onClick = { ( ) => copyToClipboard ( app . name_slug ) }
170- className = "p-1 hover:bg-gray-100 dark:hover:bg-gray-700 rounded transition-colors flex-shrink-0"
171- title = { copiedSlug === app . name_slug
172- ? "Copied!"
173- : "Copy app name slug" }
174- >
175- { copiedSlug === app . name_slug
176- ? (
177- < svg className = "w-4 h-4 text-green-600 dark:text-green-400" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
178- < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M5 13l4 4L19 7" />
179- </ svg >
180- )
181- : (
182- < svg className = "w-4 h-4 text-gray-500 dark:text-gray-400" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
183- < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
184- </ svg >
185- ) }
186- </ button >
187- </ div >
188- < p className = { styles . text . muted + " line-clamp-2" } >
189- { app . description }
190- </ p >
191- { app . categories . length > 0 && (
192- < div className = "mt-2 flex flex-wrap gap-1" >
193- { app . categories . map ( ( category ) => (
194- < span
195- key = { category }
196- className = "text-xs px-2 py-1 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded"
197- >
198- { category }
199- </ span >
200- ) ) }
170+ < div className = "mt-4" >
171+ < div className = "relative" >
172+ < div className = "max-h-[500px] overflow-y-auto space-y-3 pr-2 custom-scrollbar" >
173+ { apps . map ( ( app ) => (
174+ < div
175+ key = { app . id }
176+ className = "p-4 border border-gray-200 dark:border-gray-700 rounded-lg hover:border-gray-300 dark:hover:border-gray-600 transition-colors"
177+ >
178+ < div className = "flex items-start gap-3" >
179+ { app . icon && (
180+ < img
181+ src = { app . icon }
182+ alt = { app . name }
183+ className = "w-10 h-10 rounded"
184+ />
185+ ) }
186+ < div className = "flex-1" >
187+ < div className = "flex items-center gap-3 mb-1 flex-wrap" >
188+ < p className = "font-semibold text-base text-gray-800 dark:text-gray-200 m-0" >
189+ { app . name }
190+ </ p >
191+ < div className = "flex items-center gap-1 bg-gray-100 dark:bg-gray-800 rounded px-2 py-0.5" >
192+ < div className = { styles . codeText + " text-xs" } >
193+ { app . name_slug }
194+ </ div >
195+ < button
196+ onClick = { ( ) => copyToClipboard ( app . name_slug ) }
197+ className = "p-0.5 hover:bg-gray-200 dark:hover:bg-gray-700 rounded transition-colors ml-1"
198+ title = { copiedSlug === app . name_slug
199+ ? "Copied!"
200+ : "Copy app name slug" }
201+ >
202+ { copiedSlug === app . name_slug
203+ ? (
204+ < svg className = "w-3.5 h-3.5 text-green-600 dark:text-green-400" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
205+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M5 13l4 4L19 7" />
206+ </ svg >
207+ )
208+ : (
209+ < svg className = "w-3.5 h-3.5 text-gray-500 dark:text-gray-400" fill = "none" stroke = "currentColor" viewBox = "0 0 24 24" >
210+ < path strokeLinecap = "round" strokeLinejoin = "round" strokeWidth = { 2 } d = "M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z" />
211+ </ svg >
212+ ) }
213+ </ button >
214+ </ div >
215+ </ div >
216+ < p className = { styles . text . muted + " line-clamp-2" } >
217+ { app . description }
218+ </ p >
219+ { app . categories . length > 0 && (
220+ < div className = "mt-2 flex flex-wrap gap-1" >
221+ { app . categories . map ( ( category ) => (
222+ < span
223+ key = { category }
224+ className = "text-xs px-2 py-1 bg-gray-100 dark:bg-gray-800 text-gray-600 dark:text-gray-400 rounded"
225+ >
226+ { category }
227+ </ span >
228+ ) ) }
229+ </ div >
230+ ) }
201231 </ div >
202- ) }
232+ </ div >
203233 </ div >
204- </ div >
234+ ) ) }
205235 </ div >
206- ) ) }
236+ { apps . length > 5 && (
237+ < div className = "absolute bottom-0 left-0 right-0 h-8 bg-gradient-to-t from-white dark:from-gray-900 to-transparent pointer-events-none" > </ div >
238+ ) }
239+ </ div >
240+ { apps . length > 5 && (
241+ < p className = "text-xs text-gray-500 dark:text-gray-400 mt-2 text-center" >
242+ Scroll to see more
243+ </ p >
244+ ) }
207245 </ div >
208246 ) }
209247
@@ -219,7 +257,7 @@ export default function AppSearchDemo() {
219257 ) }
220258
221259 < div className = "mt-4" >
222- < p className = { styles . text . small } >
260+ < p className = { styles . text . muted } >
223261 Browse all available apps at{ " " }
224262 < a
225263 href = "https://mcp.pipedream.com"
0 commit comments