Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
0fc1863
feat(search): add size filter to global search
victor-ferro Jul 24, 2026
99a1a51
refactor(search): share filter radio list and close panels on enter
victor-ferro Jul 24, 2026
d6186c6
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Jul 29, 2026
c420428
[PB-6258] fix: allow conflicting custom size range so the search show…
victor-ferro Jul 29, 2026
65c0d5a
Revert "[PB-6258] fix: allow conflicting custom size range so the sea…
victor-ferro Jul 29, 2026
5c942a9
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Jul 31, 2026
27113b6
[PB-6258] fix: make size and date radio rows fully clickable via shar…
victor-ferro Jul 31, 2026
8c56bc8
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Jul 31, 2026
2db17e6
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Jul 31, 2026
5bd958b
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Jul 31, 2026
3fabc52
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Aug 3, 2026
74e3c1f
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Aug 3, 2026
0440644
[PB-6258] fix: make the size filter clear control a real button
victor-ferro Aug 3, 2026
7208f3f
[PB-6258] fix: keep the search filter pills inside the results panel
victor-ferro Aug 4, 2026
0dd9b8e
[PB-6258] feat: show a spinner while the global search is loading
victor-ferro Aug 4, 2026
6f96c31
[PB-6258] fix: only mark the date and size filters as applied when th…
victor-ferro Aug 4, 2026
4c29b88
[PB-6258] fix: accept only digits in the specific date inputs
victor-ferro Aug 4, 2026
04388a6
[PB-6258] fix: switch between search filter dropdowns with a single c…
victor-ferro Aug 4, 2026
a4fde62
[PB-6258] fix: keep custom size values within the exact integer range
victor-ferro Aug 4, 2026
e82cc3e
Merge remote-tracking branch 'origin/PB-6258-search-date-filter' into…
victor-ferro Aug 6, 2026
314f7df
Merge branch 'PB-6258-search-date-filter' into PB-6258-search-size-fi…
victor-ferro Aug 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions src/app/i18n/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,23 @@
"after": "Nach",
"before": "Vor",
"selectToday": "Heute auswählen"
},
"size": {
"size": "Größe",
"anySize": "Beliebige Größe",
"less5mb": "Weniger als 5 MB",
"less100mb": "Weniger als 100 MB",
"less1gb": "Weniger als 1 GB",
"more1gb": "Mehr als 1 GB",
"customRange": "Benutzerdefinierter Größenbereich",
"biggerThan": "Größer als",
"smallerThan": "Kleiner als",
"unit": "Einheit",
"bytes": "Bytes",
"kilobytes": "Kilobytes",
"megabytes": "Megabytes",
"gigabytes": "Gigabytes",
"terabytes": "Terabytes"
}
},
"emptyState": {
Expand Down
17 changes: 17 additions & 0 deletions src/app/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,23 @@
"after": "After",
"before": "Before",
"selectToday": "Select today"
},
"size": {
"size": "Size",
"anySize": "Any size",
"less5mb": "Less than 5 MB",
"less100mb": "Less than 100 MB",
"less1gb": "Less than 1 GB",
"more1gb": "More than 1 GB",
"customRange": "Custom size range",
"biggerThan": "Bigger than",
"smallerThan": "Smaller than",
"unit": "Unit",
"bytes": "Bytes",
"kilobytes": "Kilobytes",
"megabytes": "Megabytes",
"gigabytes": "Gigabytes",
"terabytes": "Terabytes"
}
},
"emptyState": {
Expand Down
17 changes: 17 additions & 0 deletions src/app/i18n/locales/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,23 @@
"after": "Después de",
"before": "Antes de",
"selectToday": "Seleccionar hoy"
},
"size": {
"size": "Tamaño",
"anySize": "Cualquier tamaño",
"less5mb": "Menos de 5 MB",
"less100mb": "Menos de 100 MB",
"less1gb": "Menos de 1 GB",
"more1gb": "Más de 1 GB",
"customRange": "Rango de tamaño personalizado",
"biggerThan": "Mayor que",
"smallerThan": "Menor que",
"unit": "Unidad",
"bytes": "Bytes",
"kilobytes": "Kilobytes",
"megabytes": "Megabytes",
"gigabytes": "Gigabytes",
"terabytes": "Terabytes"
}
},
"emptyState": {
Expand Down
17 changes: 17 additions & 0 deletions src/app/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,23 @@
"after": "Après",
"before": "Avant",
"selectToday": "Sélectionner aujourd'hui"
},
"size": {
"size": "Taille",
"anySize": "Toute taille",
"less5mb": "Moins de 5 MB",
"less100mb": "Moins de 100 MB",
"less1gb": "Moins de 1 GB",
"more1gb": "Plus de 1 GB",
"customRange": "Plage de taille personnalisée",
"biggerThan": "Supérieur à",
"smallerThan": "Inférieur à",
"unit": "Unité",
"bytes": "Octets",
"kilobytes": "Kilo-octets",
"megabytes": "Méga-octets",
"gigabytes": "Giga-octets",
"terabytes": "Téra-octets"
}
},
"emptyState": {
Expand Down
17 changes: 17 additions & 0 deletions src/app/i18n/locales/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,23 @@
"after": "Dopo",
"before": "Prima",
"selectToday": "Seleziona oggi"
},
"size": {
"size": "Dimensione",
"anySize": "Qualsiasi dimensione",
"less5mb": "Meno di 5 MB",
"less100mb": "Meno di 100 MB",
"less1gb": "Meno di 1 GB",
"more1gb": "Più di 1 GB",
"customRange": "Intervallo di dimensioni personalizzato",
"biggerThan": "Maggiore di",
"smallerThan": "Minore di",
"unit": "Unità",
"bytes": "Byte",
"kilobytes": "Kilobyte",
"megabytes": "Megabyte",
"gigabytes": "Gigabyte",
"terabytes": "Terabyte"
}
},
"emptyState": {
Expand Down
17 changes: 17 additions & 0 deletions src/app/i18n/locales/ru.json
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,23 @@
"after": "После",
"before": "До",
"selectToday": "Выбрать сегодня"
},
"size": {
"size": "Размер",
"anySize": "Любой размер",
"less5mb": "Менее 5 MB",
"less100mb": "Менее 100 MB",
"less1gb": "Менее 1 GB",
"more1gb": "Более 1 GB",
"customRange": "Пользовательский диапазон размера",
"biggerThan": "Больше чем",
"smallerThan": "Меньше чем",
"unit": "Единица",
"bytes": "Байты",
"kilobytes": "Килобайты",
"megabytes": "Мегабайты",
"gigabytes": "Гигабайты",
"terabytes": "Терабайты"
}
},
"emptyState": {
Expand Down
17 changes: 17 additions & 0 deletions src/app/i18n/locales/tw.json
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,23 @@
"after": "之後",
"before": "之前",
"selectToday": "選擇今天"
},
"size": {
"size": "大小",
"anySize": "任何大小",
"less5mb": "小於 5 MB",
"less100mb": "小於 100 MB",
"less1gb": "小於 1 GB",
"more1gb": "大於 1 GB",
"customRange": "自訂大小範圍",
"biggerThan": "大於",
"smallerThan": "小於",
"unit": "單位",
"bytes": "位元組",
"kilobytes": "KB",
"megabytes": "MB",
"gigabytes": "GB",
"terabytes": "TB"
}
},
"emptyState": {
Expand Down
17 changes: 17 additions & 0 deletions src/app/i18n/locales/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,23 @@
"after": "之后",
"before": "之前",
"selectToday": "选择今天"
},
"size": {
"size": "大小",
"anySize": "任何大小",
"less5mb": "小于 5 MB",
"less100mb": "小于 100 MB",
"less1gb": "小于 1 GB",
"more1gb": "大于 1 GB",
"customRange": "自定义大小范围",
"biggerThan": "大于",
"smallerThan": "小于",
"unit": "单位",
"bytes": "字节",
"kilobytes": "KB",
"megabytes": "MB",
"gigabytes": "GB",
"terabytes": "TB"
}
},
"emptyState": {
Expand Down
17 changes: 0 additions & 17 deletions src/views/Home/components/DropdownCloseObserver.tsx

This file was deleted.

17 changes: 17 additions & 0 deletions src/views/Home/components/DropdownOpenObserver.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useEffect, useRef } from 'react';

interface DropdownOpenObserverProps {
open: boolean;
onOpenChange: (open: boolean) => void;
}

const DropdownOpenObserver = ({ open, onOpenChange }: DropdownOpenObserverProps): null => {
const wasOpen = useRef(false);
useEffect(() => {
if (wasOpen.current !== open) onOpenChange(open);
wasOpen.current = open;
}, [open]);
return null;
};

export default DropdownOpenObserver;
83 changes: 74 additions & 9 deletions src/views/Home/components/NavbarGlobalSearch.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings';
import { SearchResult } from '@internxt/sdk/dist/drive/storage/types';
import { defaultSearchFilters, searchItems, SearchFileCategory, SearchFilters } from '../services';
import { ArrowSquareOutIcon, GearIcon, GiftIcon, MagnifyingGlassIcon, XIcon } from '@phosphor-icons/react';
import { Loader } from '@internxt/ui';
import AccountPopover from './AccountPopover';
import referralService from 'services/referral.service';
import i18next from 'i18next';
Expand All @@ -21,8 +22,16 @@ import NotFoundState from './NotFoundState';
import EmptyState from './EmptyState';
import { toggleAllTypeCategories, toggleTypeCategory } from '../utils/typeFilterUtils';
import { changeSpecificDate, datePresetToRange, SearchDatePreset, SpecificDateRange } from '../utils/dateFilterUtils';
import {
changeCustomSize,
CustomSizeRange,
emptyCustomSizeRange,
SearchSizePreset,
sizePresetToRange,
} from '../utils/sizeFilterUtils';
import SearchTypeFilter from './SearchTypeFilter';
import SearchDateFilter from './SearchDateFilter';
import SearchSizeFilter from './SearchSizeFilter';
import { Dayjs } from 'dayjs';
import { getItemPlainName } from 'app/crypto/services/utils';
import navigationService from 'services/navigation.service';
Expand All @@ -35,6 +44,8 @@ interface NavbarProps {
plan: PlanState;
}

type SearchFilterName = 'type' | 'date' | 'size';

const getSearchBoxClassName = (openSearchBox: boolean) => {
const baseClass = 'relative flex w-full items-center rounded-lg transition-all duration-150 ease-out';
const widthClass = openSearchBox ? 'max-w-screen-sm' : 'max-w-sm';
Expand All @@ -56,6 +67,13 @@ const getClearButtonClassName = (query: string, openSearchBox: boolean) => {
return `${baseClass} ${visibilityClass}`;
};

const getSearchLoaderClassName = (loadingSearch: boolean, openSearchBox: boolean) => {
const baseClass = 'absolute right-9 top-1/2 z-1 -translate-y-1/2 transition-all duration-100 ease-out';
const isHidden = !loadingSearch || !openSearchBox;
const visibilityClass = isHidden ? 'opacity-0' : '';
return `${baseClass} ${visibilityClass}`;
};

const getSearchResultsClassName = (openSearchBox: boolean) => {
const baseClass =
'absolute top-12 z-10 flex h-80 w-full max-w-screen-sm origin-top flex-col rounded-xl bg-surface text-gray-100 shadow-subtle-hard ring-1 ring-gray-10 transition-all duration-150 ease-out dark:bg-gray-5';
Expand Down Expand Up @@ -85,6 +103,8 @@ const Navbar = (props: NavbarProps) => {
const [filters, setFilters] = useState<SearchFilters>(defaultSearchFilters);
const [datePreset, setDatePreset] = useState<SearchDatePreset>('any');
const [specificDates, setSpecificDates] = useState<SpecificDateRange>({});
const [sizePreset, setSizePreset] = useState<SearchSizePreset>('any');
const [customSize, setCustomSize] = useState<CustomSizeRange>(emptyCustomSizeRange);

const [query, setQuery] = useState('');
const [searchResult, setSearchResult] = useState<SearchResult[]>([]);
Expand Down Expand Up @@ -137,22 +157,55 @@ const Navbar = (props: NavbarProps) => {
const applyDateFilter = (preset: SearchDatePreset, specific: SpecificDateRange) => {
setDatePreset(preset);
setSpecificDates(specific);
setFilters((current) => ({ ...current, ...datePresetToRange(preset, specific) }));
setFilters((current) => {
const range = datePresetToRange(preset, specific);
const unchanged =
range.modifiedAfter === current.modifiedAfter && range.modifiedBefore === current.modifiedBefore;
return unchanged ? current : { ...current, ...range };
});
};

const selectDatePreset = (preset: SearchDatePreset) => {
if (preset !== datePreset) applyDateFilter(preset, {});
};

const changeDateFilterDate = (field: 'after' | 'before', date?: Dayjs) =>
applyDateFilter('specific', changeSpecificDate(specificDates, field, date));
const changeDateFilterDate = (field: 'after' | 'before', date?: Dayjs) => {
const nextSpecificDates = changeSpecificDate(specificDates, field, date);
if (nextSpecificDates !== specificDates) applyDateFilter('specific', nextSpecificDates);
};

const applySizeFilter = (preset: SearchSizePreset, custom: CustomSizeRange) => {
setSizePreset(preset);
setCustomSize(custom);
setFilters((current) => {
const range = sizePresetToRange(preset, custom);
const unchanged = range.minSize === current.minSize && range.maxSize === current.maxSize;
return unchanged ? current : { ...current, ...range };
});
};

const selectSizePreset = (preset: SearchSizePreset) => {
if (preset !== sizePreset) applySizeFilter(preset, emptyCustomSizeRange);
};

const changeCustomSizeFilter = (changes: Partial<CustomSizeRange>) => {
const nextCustomSize = changeCustomSize(customSize, changes);
if (nextCustomSize !== customSize) applySizeFilter('custom', nextCustomSize);
};

const openSearchBoxRef = useRef(openSearchBox);
openSearchBoxRef.current = openSearchBox;

const refocusSearchInput = () => {
const openDropdown = useRef<SearchFilterName | null>(null);

const handleDropdownOpenChange = (name: SearchFilterName) => (open: boolean) => {
if (open) {
openDropdown.current = name;
return;
}
if (openDropdown.current === name) openDropdown.current = null;
setTimeout(() => {
if (openSearchBoxRef.current) searchInput.current?.focus();
if (openSearchBoxRef.current && openDropdown.current === null) searchInput.current?.focus();
}, 0);
};

Expand Down Expand Up @@ -282,7 +335,7 @@ const Navbar = (props: NavbarProps) => {
spellCheck="false"
type="text"
value={query}
className="inxt-input left-icon h-10 w-full appearance-none rounded-lg border border-transparent bg-gray-5 px-9 text-lg text-gray-100 placeholder-gray-60 outline-none ring-1 ring-gray-10 transition-all duration-150 ease-out hover:shadow-sm hover:ring-gray-20 focus:border-primary focus:bg-surface focus:placeholder-gray-80 focus:shadow-none focus:ring-3 focus:ring-primary/10 dark:focus:bg-gray-1 dark:focus:ring-primary/20"
className="inxt-input left-icon h-10 w-full appearance-none rounded-lg border border-transparent bg-gray-5 pl-9 pr-16 text-lg text-gray-100 placeholder-gray-60 outline-none ring-1 ring-gray-10 transition-all duration-150 ease-out hover:shadow-sm hover:ring-gray-20 focus:border-primary focus:bg-surface focus:placeholder-gray-80 focus:shadow-none focus:ring-3 focus:ring-primary/10 dark:focus:bg-gray-1 dark:focus:ring-primary/20"
onChange={(e) => {
setQuery(e.target.value);
handleSearch();
Expand All @@ -307,6 +360,11 @@ const Navbar = (props: NavbarProps) => {
placeholder={translate('general.searchBar.placeholder')}
/>
<div className={getKeyboardShortcutClassName(openSearchBox)}>{isMacOs ? '⌘F' : 'Ctrl F'}</div>
<Loader
classNameContainer={getSearchLoaderClassName(loadingSearch, openSearchBox)}
classNameLoader="text-gray-60"
size={20}
/>
<XIcon
className={getClearButtonClassName(query, openSearchBox)}
onMouseDownCapture={() => {
Expand All @@ -324,19 +382,26 @@ const Navbar = (props: NavbarProps) => {
onMouseEnter={() => setPreventBlur(true)}
onMouseLeave={() => setPreventBlur(false)}
>
<div className="flex w-full shrink-0 items-center space-x-2 border-b border-gray-5 px-2.5 py-2.5 dark:border-gray-10">
<div className="flex w-full shrink-0 flex-wrap items-center gap-2 border-b border-gray-5 px-2.5 py-2.5 dark:border-gray-10">
<SearchTypeFilter
selected={filters.type}
onToggle={toggleTypeFilter}
onToggleAll={toggleAllTypeFilters}
onClose={refocusSearchInput}
onOpenChange={handleDropdownOpenChange('type')}
/>
<SearchDateFilter
preset={datePreset}
specific={specificDates}
onSelectPreset={selectDatePreset}
onChangeDate={changeDateFilterDate}
onClose={refocusSearchInput}
onOpenChange={handleDropdownOpenChange('date')}
/>
<SearchSizeFilter
preset={sizePreset}
custom={customSize}
onSelectPreset={selectSizePreset}
onChangeCustom={changeCustomSizeFilter}
onOpenChange={handleDropdownOpenChange('size')}
/>
</div>

Expand Down
Loading
Loading