@@ -3,33 +3,40 @@ import React, { useState, useMemo } from 'react';
33interface Application {
44 name : string ;
55 description : string ;
6- githubUrl : string ;
6+ githubUrl ?: string ;
7+ docsUrl ?: string ;
78 teaser : string ;
89 services : string [ ] ;
910 integrations : string [ ] ;
1011 useCases : string [ ] ;
12+ // Snowflake-only
13+ features ?: string [ ] ;
1114}
1215
1316interface FilterState {
1417 services : string [ ] ;
1518 useCases : string [ ] ;
1619 integrations : string [ ] ;
20+ // Snowflake-only
21+ features : string [ ] ;
1722}
1823
1924interface ApplicationsShowcaseProps {
2025 applications : Application [ ] ;
2126 services : Record < string , string > ;
2227 integrations : Record < string , string > ;
28+ docs ?: 'aws' | 'snowflake' ;
2329}
2430
2531const ApplicationCard : React . FC < {
2632 app : Application ;
2733 services : Record < string , string > ;
2834 integrations : Record < string , string > ;
29- } > = ( { app, services, integrations } ) => {
35+ docs ?: 'aws' | 'snowflake' ;
36+ } > = ( { app, services, integrations, docs } ) => {
3037 return (
3138 < a
32- href = { app . githubUrl }
39+ href = { app . githubUrl || app . docsUrl || '#' }
3340 target = "_blank"
3441 rel = "noopener noreferrer"
3542 className = "app-card"
@@ -43,19 +50,31 @@ const ApplicationCard: React.FC<{
4350
4451 < div className = "card-content" >
4552 < h3 className = "card-title" > { app . name } </ h3 >
46- < div className = "service-icons" >
47- { app . services . slice ( 0 , 10 ) . map ( ( serviceCode ) => (
48- < div key = { serviceCode } className = "service-icon" title = { services [ serviceCode ] || serviceCode } >
49- < img
50- src = { `/images/aws/${ serviceCode } .svg` }
51- alt = { services [ serviceCode ] || serviceCode }
52- />
53- </ div >
54- ) ) }
55- { app . services . length > 10 && (
56- < div className = "service-more" > +{ app . services . length - 10 } </ div >
57- ) }
58- </ div >
53+ { docs === 'aws' && (
54+ < div className = "service-icons" >
55+ { app . services . slice ( 0 , 10 ) . map ( ( serviceCode ) => (
56+ < div key = { serviceCode } className = "service-icon" title = { services [ serviceCode ] || serviceCode } >
57+ < img
58+ src = { `/images/aws/${ serviceCode } .svg` }
59+ alt = { services [ serviceCode ] || serviceCode }
60+ />
61+ </ div >
62+ ) ) }
63+ { app . services . length > 10 && (
64+ < div className = "service-more" > +{ app . services . length - 10 } </ div >
65+ ) }
66+ </ div >
67+ ) }
68+ { docs === 'snowflake' && ( app . features ?. length ?? 0 ) > 0 && (
69+ < div className = "feature-pills" >
70+ { ( app . features as string [ ] ) . slice ( 0 , 10 ) . map ( ( feature ) => (
71+ < span key = { feature } className = "feature-pill" > { feature } </ span >
72+ ) ) }
73+ { ( app . features as string [ ] ) . length > 10 && (
74+ < div className = "service-more" > +{ ( app . features as string [ ] ) . length - 10 } </ div >
75+ ) }
76+ </ div >
77+ ) }
5978 < p className = "card-description" > { app . description } </ p >
6079
6180 < div className = "card-footer" >
@@ -73,11 +92,13 @@ export const ApplicationsShowcase: React.FC<ApplicationsShowcaseProps> = ({
7392 applications,
7493 services,
7594 integrations,
95+ docs,
7696} ) => {
7797 const [ filters , setFilters ] = useState < FilterState > ( {
7898 services : [ ] ,
7999 useCases : [ ] ,
80100 integrations : [ ] ,
101+ features : [ ] ,
81102 } ) ;
82103
83104 const [ searchTerm , setSearchTerm ] = useState ( '' ) ;
@@ -89,6 +110,13 @@ export const ApplicationsShowcase: React.FC<ApplicationsShowcaseProps> = ({
89110 return Array . from ( allServices ) . sort ( ( a , b ) => ( services [ a ] || a ) . localeCompare ( services [ b ] || b ) ) ;
90111 } , [ applications , services ] ) ;
91112
113+ const uniqueFeatures = useMemo ( ( ) => {
114+ const allFeatures = new Set (
115+ applications . flatMap ( app => ( app . features ?? [ ] ) )
116+ ) ;
117+ return Array . from ( allFeatures ) . sort ( ) ;
118+ } , [ applications ] ) ;
119+
92120 const uniqueUseCases = useMemo ( ( ) => {
93121 const allUseCases = new Set ( applications . flatMap ( app => app . useCases ) ) ;
94122 return Array . from ( allUseCases ) . sort ( ) ;
@@ -109,13 +137,19 @@ export const ApplicationsShowcase: React.FC<ApplicationsShowcaseProps> = ({
109137 app . name . toLowerCase ( ) . includes ( searchLower ) ||
110138 app . description . toLowerCase ( ) . includes ( searchLower ) ||
111139 app . useCases . some ( useCase => useCase . toLowerCase ( ) . includes ( searchLower ) ) ||
112- app . services . some ( service => ( services [ service ] || service ) . toLowerCase ( ) . includes ( searchLower ) ) ||
140+ ( docs === 'aws' && app . services . some ( service => ( services [ service ] || service ) . toLowerCase ( ) . includes ( searchLower ) ) ) ||
141+ ( docs === 'snowflake' && ( app . features ?? [ ] ) . some ( feature => feature . toLowerCase ( ) . includes ( searchLower ) ) ) ||
113142 app . integrations . some ( integration => ( integrations [ integration ] || integration ) . toLowerCase ( ) . includes ( searchLower ) ) ;
114143 if ( ! matchesSearch ) return false ;
115144 }
116145
117146 // Other filters
118- if ( filters . services . length > 0 && ! filters . services . some ( service => app . services . includes ( service ) ) ) return false ;
147+ if ( docs === 'aws' ) {
148+ if ( filters . services . length > 0 && ! filters . services . some ( service => app . services . includes ( service ) ) ) return false ;
149+ } else if ( docs === 'snowflake' ) {
150+ const appFeatures = app . features ?? [ ] ;
151+ if ( filters . features . length > 0 && ! filters . features . some ( feature => appFeatures . includes ( feature ) ) ) return false ;
152+ }
119153 if ( filters . useCases . length > 0 && ! filters . useCases . some ( useCase => app . useCases . includes ( useCase ) ) ) return false ;
120154 if ( filters . integrations . length > 0 && ! filters . integrations . some ( integration => app . integrations . includes ( integration ) ) ) return false ;
121155
@@ -126,7 +160,7 @@ export const ApplicationsShowcase: React.FC<ApplicationsShowcaseProps> = ({
126160 return filtered . sort ( ( a , b ) => {
127161 return a . name . localeCompare ( b . name ) ;
128162 } ) ;
129- } , [ applications , filters , searchTerm , sortBy , services , integrations ] ) ;
163+ } , [ applications , filters , searchTerm , sortBy , services , integrations , docs ] ) ;
130164
131165 const isSingleResult = filteredApplications . length === 1 ;
132166 const gridStyle = useMemo < React . CSSProperties > ( ( ) => ( {
@@ -148,13 +182,15 @@ export const ApplicationsShowcase: React.FC<ApplicationsShowcaseProps> = ({
148182 services : [ ] ,
149183 useCases : [ ] ,
150184 integrations : [ ] ,
185+ features : [ ] ,
151186 } ) ;
152187 setSearchTerm ( '' ) ;
153188 } ;
154189
155190 const hasActiveFilters = filters . services . length > 0 ||
156191 filters . useCases . length > 0 ||
157192 filters . integrations . length > 0 ||
193+ filters . features . length > 0 ||
158194 searchTerm . length > 0 ;
159195
160196 return (
@@ -401,6 +437,22 @@ export const ApplicationsShowcase: React.FC<ApplicationsShowcaseProps> = ({
401437 font-size: 0.875rem;
402438 }
403439
440+ .feature-pills {
441+ display: flex;
442+ gap: 0.375rem;
443+ flex-wrap: wrap;
444+ margin: 0 0 0.75rem 0;
445+ }
446+
447+ .feature-pill {
448+ padding: 0.25rem 0.5rem;
449+ background: var(--sl-color-bg);
450+ border: 1px solid var(--sl-color-gray-6);
451+ border-radius: 0.25rem;
452+ font-size: 0.75rem;
453+ color: var(--sl-color-gray-3);
454+ }
455+
404456 .card-footer {
405457 display: flex;
406458 justify-content: flex-start;
@@ -557,21 +609,39 @@ export const ApplicationsShowcase: React.FC<ApplicationsShowcaseProps> = ({
557609 ) }
558610 </ div >
559611
560- < select
561- value = { filters . services [ 0 ] || '' }
562- onChange = { ( e ) => setFilters ( prev => ( {
563- ...prev ,
564- services : e . target . value ? [ e . target . value ] : [ ]
565- } ) ) }
566- className = "filter-select"
567- >
568- < option value = "" > Services</ option >
569- { uniqueServices . map ( ( service ) => (
570- < option key = { service } value = { service } >
571- { services [ service ] || service }
572- </ option >
573- ) ) }
574- </ select >
612+ { docs === 'aws' ? (
613+ < select
614+ value = { filters . services [ 0 ] || '' }
615+ onChange = { ( e ) => setFilters ( prev => ( {
616+ ...prev ,
617+ services : e . target . value ? [ e . target . value ] : [ ]
618+ } ) ) }
619+ className = "filter-select"
620+ >
621+ < option value = "" > Services</ option >
622+ { uniqueServices . map ( ( service ) => (
623+ < option key = { service } value = { service } >
624+ { services [ service ] || service }
625+ </ option >
626+ ) ) }
627+ </ select >
628+ ) : (
629+ < select
630+ value = { ( filters . features ?. [ 0 ] as string ) || '' }
631+ onChange = { ( e ) => setFilters ( prev => ( {
632+ ...prev ,
633+ features : e . target . value ? [ e . target . value ] : [ ]
634+ } ) ) }
635+ className = "filter-select"
636+ >
637+ < option value = "" > Features</ option >
638+ { uniqueFeatures . map ( ( feature ) => (
639+ < option key = { feature } value = { feature } >
640+ { feature }
641+ </ option >
642+ ) ) }
643+ </ select >
644+ ) }
575645
576646 < select
577647 value = { filters . useCases [ 0 ] || '' }
@@ -624,6 +694,7 @@ export const ApplicationsShowcase: React.FC<ApplicationsShowcaseProps> = ({
624694 app = { app }
625695 services = { services }
626696 integrations = { integrations }
697+ docs = { docs }
627698 />
628699 ) ) }
629700
0 commit comments