@@ -9,6 +9,7 @@ import { CategorySidebar } from './CategorySidebar';
99import { FilterBar , type FilterState } from './FilterBar' ;
1010import { ViewToggle } from './ViewToggle' ;
1111import { Button } from './ui/button' ;
12+ import { Clock } from 'lucide-react' ;
1213import type { ScriptCard as ScriptCardType } from '~/types/script' ;
1314
1415
@@ -220,6 +221,31 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) {
220221 } ) ;
221222 } , [ combinedScripts , localScriptsData ] ) ;
222223
224+ // Check if any filters are active (excluding default state)
225+ const hasActiveFilters = React . useMemo ( ( ) => {
226+ return (
227+ filters . searchQuery ?. trim ( ) !== '' ||
228+ filters . showUpdatable !== null ||
229+ filters . selectedTypes . length > 0 ||
230+ filters . sortBy !== 'name' ||
231+ filters . sortOrder !== 'asc' ||
232+ selectedCategory !== null
233+ ) ;
234+ } , [ filters , selectedCategory ] ) ;
235+
236+ // Get the 6 newest scripts based on date_created field
237+ const newestScripts = React . useMemo ( ( ) : ScriptCardType [ ] => {
238+ return scriptsWithStatus
239+ . filter ( script => script ?. date_created ) // Only scripts with date_created
240+ . sort ( ( a , b ) => {
241+ const aCreated = a ?. date_created ?? '' ;
242+ const bCreated = b ?. date_created ?? '' ;
243+ // Sort by date descending (newest first)
244+ return bCreated . localeCompare ( aCreated ) ;
245+ } )
246+ . slice ( 0 , 6 ) ; // Take only the first 6
247+ } , [ scriptsWithStatus ] ) ;
248+
223249 // Filter scripts based on all filters and category
224250 const filteredScripts = React . useMemo ( ( ) : ScriptCardType [ ] => {
225251 let scripts = scriptsWithStatus ;
@@ -270,6 +296,12 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) {
270296 } ) ;
271297 }
272298
299+ // Exclude newest scripts from main grid when no filters are active (they'll be shown in carousel)
300+ if ( ! hasActiveFilters ) {
301+ const newestScriptSlugs = new Set ( newestScripts . map ( script => script . slug ) . filter ( Boolean ) ) ;
302+ scripts = scripts . filter ( script => ! newestScriptSlugs . has ( script . slug ) ) ;
303+ }
304+
273305 // Apply sorting
274306 scripts . sort ( ( a , b ) => {
275307 if ( ! a || ! b ) return 0 ;
@@ -309,7 +341,7 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) {
309341 } ) ;
310342
311343 return scripts ;
312- } , [ scriptsWithStatus , filters , selectedCategory ] ) ;
344+ } , [ scriptsWithStatus , filters , selectedCategory , hasActiveFilters , newestScripts ] ) ;
313345
314346 // Calculate filter counts for FilterBar
315347 const filterCounts = React . useMemo ( ( ) => {
@@ -619,6 +651,51 @@ export function ScriptsGrid({ onInstallScript }: ScriptsGridProps) {
619651 onViewModeChange = { setViewMode }
620652 />
621653
654+ { /* Newest Scripts Carousel - Only show when no filters are active */ }
655+ { ! hasActiveFilters && newestScripts . length > 0 && (
656+ < div className = "mb-8" >
657+ < div className = "bg-card border-l-4 border-l-primary border border-border rounded-lg p-6 shadow-lg" >
658+ < div className = "flex items-center justify-between mb-4" >
659+ < h2 className = "text-xl font-semibold text-foreground flex items-center gap-2" >
660+ < Clock className = "h-6 w-6 text-primary" />
661+ Newest Scripts
662+ </ h2 >
663+ < span className = "text-sm text-muted-foreground" >
664+ { newestScripts . length } recently added
665+ </ span >
666+ </ div >
667+
668+ < div className = "overflow-x-auto scrollbar-thin scrollbar-thumb-gray-300 dark:scrollbar-thumb-gray-600 scrollbar-track-transparent" >
669+ < div className = "flex gap-4 pb-2" style = { { minWidth : 'max-content' } } >
670+ { newestScripts . map ( ( script , index ) => {
671+ if ( ! script || typeof script !== 'object' ) {
672+ return null ;
673+ }
674+
675+ const uniqueKey = `newest-${ script . slug ?? 'unknown' } -${ script . name ?? 'unnamed' } -${ index } ` ;
676+
677+ return (
678+ < div key = { uniqueKey } className = "flex-shrink-0 w-64 sm:w-72 md:w-80" >
679+ < div className = "relative" >
680+ < ScriptCard
681+ script = { script }
682+ onClick = { handleCardClick }
683+ isSelected = { selectedSlugs . has ( script . slug ?? '' ) }
684+ onToggleSelect = { toggleScriptSelection }
685+ />
686+ { /* NEW badge */ }
687+ < div className = "absolute top-2 right-2 bg-green-600 text-white text-xs font-semibold px-2 py-1 rounded-md shadow-md z-10" >
688+ NEW
689+ </ div >
690+ </ div >
691+ </ div >
692+ ) ;
693+ } ) }
694+ </ div >
695+ </ div >
696+ </ div >
697+ </ div >
698+ ) }
622699
623700 { /* Action Buttons */ }
624701 < div className = "flex flex-wrap gap-2 mb-4" >
0 commit comments