@@ -174,6 +174,8 @@ export function Files() {
174174 direction : 'asc' | 'desc'
175175 } | null > ( null )
176176 const [ typeFilter , setTypeFilter ] = useState < 'all' | 'document' | 'audio' | 'video' > ( 'all' )
177+ const [ sizeFilter , setSizeFilter ] = useState < 'all' | 'small' | 'medium' | 'large' > ( 'all' )
178+ const [ uploadedByFilter , setUploadedByFilter ] = useState < string [ ] > ( [ ] )
177179
178180 const [ creatingFile , setCreatingFile ] = useState ( false )
179181 const [ isDirty , setIsDirty ] = useState ( false )
@@ -223,6 +225,18 @@ export function Files() {
223225 } )
224226 }
225227
228+ if ( sizeFilter !== 'all' ) {
229+ result = result . filter ( ( f ) => {
230+ if ( sizeFilter === 'small' ) return f . size < 1_048_576
231+ if ( sizeFilter === 'medium' ) return f . size >= 1_048_576 && f . size <= 10_485_760
232+ return f . size > 10_485_760 // large
233+ } )
234+ }
235+
236+ if ( uploadedByFilter . length > 0 ) {
237+ result = result . filter ( ( f ) => uploadedByFilter . includes ( f . uploadedBy ) )
238+ }
239+
226240 const col = activeSort ?. column ?? 'created'
227241 const dir = activeSort ?. direction ?? 'desc'
228242 return [ ...result ] . sort ( ( a , b ) => {
@@ -244,7 +258,7 @@ export function Files() {
244258 }
245259 return dir === 'asc' ? cmp : - cmp
246260 } )
247- } , [ files , debouncedSearchTerm , typeFilter , activeSort ] )
261+ } , [ files , debouncedSearchTerm , typeFilter , sizeFilter , uploadedByFilter , activeSort ] )
248262
249263 const rowCacheRef = useRef (
250264 new Map < string , { row : ResourceRow ; file : WorkspaceFileRecord ; members : typeof members } > ( )
@@ -831,26 +845,105 @@ export function Files() {
831845 </ button >
832846 ) ) }
833847 </ div >
848+ < div className = 'border-[var(--border-1)] border-t border-b px-3 py-2' >
849+ < span className = 'font-medium text-[var(--text-secondary)] text-caption' > Size</ span >
850+ </ div >
851+ < div className = 'flex flex-col gap-0.5 px-3 py-2' >
852+ { (
853+ [
854+ { value : 'all' , label : 'All' } ,
855+ { value : 'small' , label : 'Small (< 1 MB)' } ,
856+ { value : 'medium' , label : 'Medium (1–10 MB)' } ,
857+ { value : 'large' , label : 'Large (> 10 MB)' } ,
858+ ] as const
859+ ) . map ( ( { value, label } ) => (
860+ < button
861+ key = { value }
862+ type = 'button'
863+ className = { cn (
864+ 'flex w-full cursor-pointer select-none items-center rounded-[5px] px-2 py-[5px] font-medium text-[var(--text-secondary)] text-caption outline-none transition-colors hover-hover:bg-[var(--surface-active)]' ,
865+ sizeFilter === value && 'bg-[var(--surface-active)]'
866+ ) }
867+ onClick = { ( ) => setSizeFilter ( value ) }
868+ >
869+ { label }
870+ </ button >
871+ ) ) }
872+ </ div >
873+ { members && members . length > 0 && (
874+ < >
875+ < div className = 'border-[var(--border-1)] border-t border-b px-3 py-2' >
876+ < span className = 'font-medium text-[var(--text-secondary)] text-caption' >
877+ Uploaded By
878+ </ span >
879+ </ div >
880+ < div className = 'flex flex-col gap-0.5 px-3 py-2' >
881+ < button
882+ type = 'button'
883+ className = { cn (
884+ 'flex w-full cursor-pointer select-none items-center rounded-[5px] px-2 py-[5px] font-medium text-[var(--text-secondary)] text-caption outline-none transition-colors hover-hover:bg-[var(--surface-active)]' ,
885+ uploadedByFilter . length === 0 && 'bg-[var(--surface-active)]'
886+ ) }
887+ onClick = { ( ) => setUploadedByFilter ( [ ] ) }
888+ >
889+ All
890+ </ button >
891+ { members . map ( ( member ) => (
892+ < button
893+ key = { member . userId }
894+ type = 'button'
895+ className = { cn (
896+ 'flex w-full cursor-pointer select-none items-center gap-1.5 rounded-[5px] px-2 py-[5px] font-medium text-[var(--text-secondary)] text-caption outline-none transition-colors hover-hover:bg-[var(--surface-active)]' ,
897+ uploadedByFilter . includes ( member . userId ) && 'bg-[var(--surface-active)]'
898+ ) }
899+ onClick = { ( ) =>
900+ setUploadedByFilter ( ( prev ) =>
901+ prev . includes ( member . userId )
902+ ? prev . filter ( ( id ) => id !== member . userId )
903+ : [ ...prev , member . userId ]
904+ )
905+ }
906+ >
907+ { member . image ? (
908+ < img
909+ src = { member . image }
910+ alt = { member . name }
911+ referrerPolicy = 'no-referrer'
912+ className = 'h-[14px] w-[14px] shrink-0 rounded-full border border-[var(--border)] object-cover'
913+ />
914+ ) : (
915+ < span className = 'flex h-[14px] w-[14px] shrink-0 items-center justify-center rounded-full border border-[var(--border)] bg-[var(--surface-3)] font-medium text-[8px] text-[var(--text-secondary)]' >
916+ { member . name . charAt ( 0 ) . toUpperCase ( ) }
917+ </ span >
918+ ) }
919+ < span className = 'truncate' > { member . name } </ span >
920+ </ button >
921+ ) ) }
922+ </ div >
923+ </ >
924+ ) }
834925 </ div >
835926 )
836927
837- const filterTags : FilterTag [ ] = useMemo (
838- ( ) =>
839- typeFilter === 'all'
840- ? [ ]
841- : [
842- {
843- label :
844- typeFilter === 'document'
845- ? 'Type: Documents'
846- : typeFilter === 'audio'
847- ? 'Type: Audio'
848- : 'Type: Video' ,
849- onRemove : ( ) => setTypeFilter ( 'all' ) ,
850- } ,
851- ] ,
852- [ typeFilter ]
853- )
928+ const filterTags : FilterTag [ ] = useMemo ( ( ) => {
929+ const tags : FilterTag [ ] = [ ]
930+ if ( typeFilter !== 'all' ) {
931+ const labels = { document : 'Type: Documents' , audio : 'Type: Audio' , video : 'Type: Video' }
932+ tags . push ( { label : labels [ typeFilter ] , onRemove : ( ) => setTypeFilter ( 'all' ) } )
933+ }
934+ if ( sizeFilter !== 'all' ) {
935+ const labels = { small : 'Size: Small' , medium : 'Size: Medium' , large : 'Size: Large' }
936+ tags . push ( { label : labels [ sizeFilter ] , onRemove : ( ) => setSizeFilter ( 'all' ) } )
937+ }
938+ if ( uploadedByFilter . length > 0 ) {
939+ const label =
940+ uploadedByFilter . length === 1
941+ ? `Uploaded by: ${ members ?. find ( ( m ) => m . userId === uploadedByFilter [ 0 ] ) ?. name ?? '1 member' } `
942+ : `Uploaded by: ${ uploadedByFilter . length } members`
943+ tags . push ( { label, onRemove : ( ) => setUploadedByFilter ( [ ] ) } )
944+ }
945+ return tags
946+ } , [ typeFilter , sizeFilter , uploadedByFilter , members ] )
854947
855948 if ( fileIdFromRoute && ! selectedFile ) {
856949 return (
0 commit comments