44 MagnifyingGlassIcon ,
55 ArrowUpRightIcon ,
66 ArrowLeftIcon ,
7+ SortAscendingIcon ,
8+ CalendarBlankIcon
79} from '@phosphor-icons/react' ;
810import Seo from '../../components/Seo' ;
911import { appIcons } from '../../utils/appIcons' ;
@@ -30,6 +32,7 @@ const LuxeAppsPage = () => {
3032 const [ isLoading , setIsLoading ] = useState ( true ) ;
3133 const [ activeCategory , setActiveCategory ] = useState ( 'All' ) ;
3234 const [ availableCategories , setAvailableCategories ] = useState ( [ ] ) ;
35+ const [ sortOrder , setSortOrder ] = useState ( 'alphabetical' ) ; // 'alphabetical' or 'newest'
3336
3437 useEffect ( ( ) => {
3538 setIsLoading ( true ) ;
@@ -59,15 +62,22 @@ const LuxeAppsPage = () => {
5962 . finally ( ( ) => setIsLoading ( false ) ) ;
6063 } , [ ] ) ;
6164
62- const filteredApps = apps . filter ( ( app ) => {
63- const query = searchQuery . toLowerCase ( ) ;
64- const matchesSearch =
65- app . name . toLowerCase ( ) . includes ( query ) ||
66- app . description . toLowerCase ( ) . includes ( query ) ;
67- const matchesCategory =
68- activeCategory === 'All' || app . categoryName === activeCategory ;
69- return matchesSearch && matchesCategory ;
70- } ) ;
65+ const sortedApps = [ ...apps ]
66+ . filter ( ( app ) => {
67+ const query = searchQuery . toLowerCase ( ) ;
68+ const matchesSearch =
69+ app . name . toLowerCase ( ) . includes ( query ) ||
70+ app . description . toLowerCase ( ) . includes ( query ) ;
71+ const matchesCategory =
72+ activeCategory === 'All' || app . categoryName === activeCategory ;
73+ return matchesSearch && matchesCategory ;
74+ } )
75+ . sort ( ( a , b ) => {
76+ if ( sortOrder === 'newest' ) {
77+ return new Date ( b . date || 0 ) - new Date ( a . date || 0 ) ;
78+ }
79+ return a . name . localeCompare ( b . name ) ;
80+ } ) ;
7181
7282 return (
7383 < div className = "min-h-screen bg-[#F5F5F0] text-[#1A1A1A] font-sans selection:bg-[#C0B298] selection:text-black pt-24 pb-20" >
@@ -103,21 +113,38 @@ const LuxeAppsPage = () => {
103113 </ div >
104114 </ header >
105115
106- { /* Category Filter */ }
107- < div className = "flex gap-2 overflow-x-auto no-scrollbar mb-20 pb-4 border-b border-[#1A1A1A]/5" >
108- { availableCategories . map ( ( cat ) => (
109- < button
110- key = { cat }
111- onClick = { ( ) => setActiveCategory ( cat ) }
112- className = { `px-6 py-2 rounded-full font-outfit text-[10px] uppercase tracking-[0.2em] transition-all whitespace-nowrap ${
113- activeCategory === cat
114- ? 'bg-[#1A1A1A] text-white shadow-lg'
115- : 'bg-white/50 text-[#1A1A1A]/40 border border-[#1A1A1A]/10 hover:border-[#1A1A1A] hover:text-[#1A1A1A]'
116- } `}
117- >
118- { cat }
119- </ button >
120- ) ) }
116+ { /* Category Filter & Sort */ }
117+ < div className = "flex flex-col md:flex-row justify-between items-center gap-8 mb-20 pb-4 border-b border-[#1A1A1A]/5" >
118+ < div className = "flex gap-2 overflow-x-auto no-scrollbar flex-1 w-full" >
119+ { availableCategories . map ( ( cat ) => (
120+ < button
121+ key = { cat }
122+ onClick = { ( ) => setActiveCategory ( cat ) }
123+ className = { `px-6 py-2 rounded-full font-outfit text-[10px] uppercase tracking-[0.2em] transition-all whitespace-nowrap ${
124+ activeCategory === cat
125+ ? 'bg-[#1A1A1A] text-white shadow-lg'
126+ : 'bg-white/50 text-[#1A1A1A]/40 border border-[#1A1A1A]/10 hover:border-[#1A1A1A] hover:text-[#1A1A1A]'
127+ } `}
128+ >
129+ { cat }
130+ </ button >
131+ ) ) }
132+ </ div >
133+
134+ < div className = "flex bg-white rounded-full p-1 border border-[#1A1A1A]/5 shadow-sm shrink-0" >
135+ < button
136+ onClick = { ( ) => setSortOrder ( 'alphabetical' ) }
137+ className = { `flex items-center gap-2 px-4 py-2 rounded-full font-outfit text-[10px] uppercase tracking-widest transition-all ${ sortOrder === 'alphabetical' ? 'bg-[#1A1A1A] text-white' : 'text-[#1A1A1A]/40 hover:text-[#1A1A1A]' } ` }
138+ >
139+ < SortAscendingIcon size = { 14 } /> A-Z
140+ </ button >
141+ < button
142+ onClick = { ( ) => setSortOrder ( 'newest' ) }
143+ className = { `flex items-center gap-2 px-4 py-2 rounded-full font-outfit text-[10px] uppercase tracking-widest transition-all ${ sortOrder === 'newest' ? 'bg-[#1A1A1A] text-white' : 'text-[#1A1A1A]/40 hover:text-[#1A1A1A]' } ` }
144+ >
145+ < CalendarBlankIcon size = { 14 } /> Newest
146+ </ button >
147+ </ div >
121148 </ div >
122149
123150 { isLoading ? (
@@ -126,7 +153,7 @@ const LuxeAppsPage = () => {
126153 </ div >
127154 ) : (
128155 < div className = "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-12" >
129- { filteredApps . map ( ( app ) => {
156+ { sortedApps . map ( ( app ) => {
130157 const categoryColor =
131158 categoryColors [ app . categoryName ] || categoryColors . Default ;
132159 const Icon = appIcons [ app . icon ] || appIcons [ `${ app . icon } Icon` ] ;
0 commit comments