feat: Search pagination and UX improvements
- Add pagination support to search (previously limited to 50 results) - Search now scoped to current mailbox/folder - Support shared mailbox folders in search - Display total results count (e.g., "50 of 1400 conversations") - Add clear (X) button to search input - Re-run search when changing folders during active search - Remove unused sidebar screenshot
This commit is contained in:
@@ -60,6 +60,7 @@ export function EmailList({
|
||||
loadMoreEmails,
|
||||
hasMoreEmails,
|
||||
isLoadingMore,
|
||||
totalEmails,
|
||||
mailboxes,
|
||||
selectedMailbox,
|
||||
expandedThreadIds,
|
||||
@@ -260,7 +261,13 @@ export function EmailList({
|
||||
)}
|
||||
</button>
|
||||
<h2 className="text-sm font-medium text-foreground">
|
||||
{isLoading ? 'Loading...' : threadGroups.length > 0 ? `${threadGroups.length} conversations` : 'No conversations'}
|
||||
{isLoading ? 'Loading...' : threadGroups.length > 0
|
||||
? (totalEmails > threadGroups.length
|
||||
? `${threadGroups.length} of ${totalEmails} conversations`
|
||||
: hasMoreEmails
|
||||
? `${threadGroups.length}+ conversations`
|
||||
: `${threadGroups.length} conversations`)
|
||||
: 'No conversations'}
|
||||
</h2>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
ChevronUp,
|
||||
Users,
|
||||
User,
|
||||
X,
|
||||
} from "lucide-react";
|
||||
import { cn, buildMailboxTree, MailboxNode, formatFileSize } from "@/lib/utils";
|
||||
import { Mailbox } from "@/lib/jmap/types";
|
||||
@@ -37,6 +38,8 @@ interface SidebarProps {
|
||||
onCompose?: () => void;
|
||||
onLogout?: () => void;
|
||||
onSearch?: (query: string) => void;
|
||||
onClearSearch?: () => void;
|
||||
activeSearchQuery?: string;
|
||||
quota?: { used: number; total: number } | null;
|
||||
isPushConnected?: boolean;
|
||||
className?: string;
|
||||
@@ -206,6 +209,8 @@ export function Sidebar({
|
||||
onCompose,
|
||||
onLogout,
|
||||
onSearch,
|
||||
onClearSearch,
|
||||
activeSearchQuery = "",
|
||||
quota,
|
||||
isPushConnected = false,
|
||||
className,
|
||||
@@ -215,6 +220,11 @@ export function Sidebar({
|
||||
const [expandedFolders, setExpandedFolders] = useState<Set<string>>(new Set());
|
||||
const [showMenu, setShowMenu] = useState(false);
|
||||
const t = useTranslations('sidebar');
|
||||
|
||||
// Sync local search query with store's active search query
|
||||
useEffect(() => {
|
||||
setSearchQuery(activeSearchQuery);
|
||||
}, [activeSearchQuery]);
|
||||
const params = useParams();
|
||||
const router = useRouter();
|
||||
|
||||
@@ -334,9 +344,22 @@ export function Sidebar({
|
||||
placeholder={t("search_placeholder")}
|
||||
value={searchQuery}
|
||||
onChange={(e) => setSearchQuery(e.target.value)}
|
||||
className="pl-9"
|
||||
className={cn("pl-9", searchQuery && "pr-8")}
|
||||
data-search-input
|
||||
/>
|
||||
{searchQuery && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
setSearchQuery("");
|
||||
onClearSearch?.();
|
||||
}}
|
||||
className="absolute right-2 top-1/2 transform -translate-y-1/2 p-1 rounded-full hover:bg-muted text-muted-foreground hover:text-foreground transition-colors"
|
||||
aria-label="Clear search"
|
||||
>
|
||||
<X className="w-4 h-4" />
|
||||
</button>
|
||||
)}
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user