/******************************************************************************** * Copyright (c) 2026 Contributors to the Eclipse Foundation * * See the NOTICE file(s) distributed with this work for additional * information regarding copyright ownership. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License 2.0 which is available at * https://www.eclipse.org/legal/epl-2.0 * * SPDX-License-Identifier: EPL-2.0 ********************************************************************************/ import { FunctionComponent, useState } from 'react'; import { Box } from '@mui/material'; import { SortBy, SortOrder } from '../../extension-registry-types'; import { ExtensionCategory } from '../../extension-registry-types'; import { ExtensionList } from '../../components/extension-list'; import { CATEGORY_ICONS, DefaultCategoryIcon } from '../../components/categories'; import { CategoryPill } from '../../components/category-pill'; import { CategoryListItem } from '../../components/category-list-item'; import { Eyebrow } from '../../components/page-primitives'; import { PageContainer } from '../../components/page-container'; import { NAVBAR_HEIGHT } from '../../default/theme'; import { useSearch } from '../../hooks/use-search'; import { useCategories } from '../../components/categories'; import { SearchHeader } from './search-header'; export const SearchPage: FunctionComponent = () => { const { filter, search } = useSearch(); const { query: searchQuery, category, sortBy, sortOrder } = filter; const categories = useCategories(); const [resultNumber, setResultNumber] = useState(0); return ( // flushTop hugs the nav; flushBottom moves the footer gap into the results // column, so its seam runs unbroken into the footer divider. Growing into the // layout's leftover space keeps the seam continuous on short result sets too. {/* Mobile category pills — outside the flex row so negative-margin bleed isn't clipped */} {categories.length > 0 && ( {(['', ...categories] as Array).map(cat => { const Icon = cat ? CATEGORY_ICONS[cat] : DefaultCategoryIcon; return ( search({ category: cat })} /> ); })} )} {/* Desktop categories sidebar */} Categories {(['', ...categories] as Array).map(cat => { const Icon = cat ? CATEGORY_ICONS[cat] : DefaultCategoryIcon; return ( search({ category: cat })} /> ); })} {/* Main content, split from the sidebar like VS Code's sidebar/editor seam. The color rides in the shorthand: a separate borderColor would be overridden by this media-queried shorthand resetting it. */} ({ flex: 1, minWidth: 0, borderLeft: { xs: 'none', md: `1px solid ${theme.palette.border2}` }, pl: { md: '1.25rem' }, // The footer gap PageContainer would normally own (flushBottom). pb: { xs: '2.5rem', sm: '4rem' } })}> search({ sortBy })} onSortOrderChanged={(sortOrder: SortOrder) => search({ sortOrder })} /> ); };