DirectorySite Specialization
Directory site type with listings, search, filters, and map views
DirectorySite Specialization
The DirectorySite type is optimized for listings, catalogs, and searchable directories. It extends the base Site component with specialized components for search, filtering, map views, and listing management.
Naming Convention
DirectorySite follows the ${SiteType}${Component} pattern:
DirectoryHeader = Header + search and filters
SearchBar = Search + directory-specific features
FilterPanel = Panel + faceted filtering
ListingGrid = Grid + directory listings
ListingCard = Card + listing preview
ListingDetail = Detail + full listing viewAll directory components are the base component enhanced with directory site-specific capabilities.
Type Definition
import type { DirectorySite } from 'mdxui'
interface DirectorySite extends BaseSite {
type: 'directory'
directory?: {
itemsPerPage?: number // Items per page (default: 20)
filters?: boolean // Enable filtering (default: true)
sorting?: boolean // Enable sorting (default: true)
map?: boolean // Enable map view (default: false)
search?: {
enabled?: boolean // Enable search (default: true)
placeholder?: string // Search placeholder text
}
}
}Usage
Basic Example
import { Site, DirectoryHeader, SearchBar, ListingGrid } from '@mdxui/beacon'
<Site
type="directory"
name="Find Restaurants"
directory={{
itemsPerPage: 20,
filters: true,
sorting: true,
map: true
}}
>
<DirectoryHeader />
<SearchBar placeholder="Search restaurants..." />
<ListingGrid listings={restaurants} />
</Site>With Map View
<Site
type="directory"
name="Store Locator"
directory={{
map: true,
search: {
enabled: true,
placeholder: "Find stores near you"
}
}}
>
<MapView locations={stores} />
<ListingGrid listings={stores} />
</Site>Required Components
DirectorySite requires these specialized components:
DirectoryHeader
Required: Yes
Directory header with search and filter controls.
<DirectoryHeader
logo={<Logo />}
search={true}
filterToggle={true}
viewToggle={true} // Grid/List/Map view switcher
navigation={[
{ label: "Home", href: "/" },
{ label: "Directory", href: "/directory" },
{ label: "Submit", href: "/submit" }
]}
/>SearchBar
Required: Yes
Search interface with autocomplete and suggestions.
<SearchBar
placeholder="Search by name, category, or location..."
autocomplete={true}
suggestions={recentSearches}
onSearch={(query) => {
// Handle search
}}
filters={activeFilters}
/>ListingGrid
Required: Yes
Grid of directory listings.
<ListingGrid
listings={[
{
id: "1",
title: "Joe's Pizza",
category: "Restaurant",
location: "New York, NY",
image: "/listings/joes-pizza.jpg",
rating: 4.5,
reviews: 120,
verified: true
}
]}
layout="grid" // or "list"
itemsPerPage={20}
/>Optional Components
FilterPanel
Faceted filter sidebar or panel.
<FilterPanel
filters={[
{
type: "category",
label: "Category",
options: [
{ value: "restaurant", label: "Restaurants", count: 42 },
{ value: "cafe", label: "Cafes", count: 28 }
]
},
{
type: "location",
label: "Location",
options: [
{ value: "new-york", label: "New York", count: 35 },
{ value: "los-angeles", label: "Los Angeles", count: 25 }
]
},
{
type: "rating",
label: "Rating",
options: [
{ value: "4+", label: "4+ Stars", count: 30 },
{ value: "3+", label: "3+ Stars", count: 55 }
]
}
]}
selected={selectedFilters}
onChange={(filters) => {
// Apply filters
}}
/>ListingCard
Individual listing card for grid/list view.
<ListingCard
title="Joe's Pizza"
category="Restaurant"
location="New York, NY"
image="/listings/joes-pizza.jpg"
rating={4.5}
reviews={120}
verified={true}
badges={["Popular", "Open Now"]}
href="/listings/joes-pizza"
/>ListingDetail
Detailed listing page with full information.
<ListingDetail
listing={{
title: "Joe's Pizza",
category: "Restaurant",
description: "Authentic New York pizza since 1975",
location: {
address: "123 Main St, New York, NY 10001",
lat: 40.7589,
lng: -73.9851
},
hours: {
monday: "11:00 AM - 10:00 PM",
tuesday: "11:00 AM - 10:00 PM",
// ...
},
contact: {
phone: "(555) 123-4567",
email: "info@joespizza.com",
website: "https://joespizza.com"
},
images: ["/img1.jpg", "/img2.jpg"],
rating: 4.5,
reviews: reviewsData,
verified: true
}}
/>MapView
Map-based listing view with markers.
<MapView
listings={listings}
center={{ lat: 40.7589, lng: -73.9851 }}
zoom={12}
onMarkerClick={(listing) => {
// Show listing details
}}
cluster={true} // Cluster nearby markers
heatmap={false}
/>Pagination
Pagination controls for listing navigation.
<Pagination
currentPage={1}
totalPages={10}
itemsPerPage={20}
totalItems={200}
onPageChange={(page) => {
// Load page
}}
/>Component Specializations
DirectoryHeader
Base Header component + directory features.
// Enhanced with:
- Full-text search bar
- Filter toggle button
- View mode switcher (grid/list/map)
- Sort dropdown
- Results count displaySearchBar
Search component with directory-specific features.
// Enhanced with:
- Autocomplete suggestions
- Search by category, location, name
- Recent searches
- Popular searches
- Search filters integration
- Geolocation searchFilterPanel
Filter sidebar with faceted search.
// Enhanced with:
- Multi-select filters
- Filter counts
- Clear filters button
- Active filter chips
- Hierarchical categories
- Range sliders (price, distance)ListingGrid
Grid layout with sorting and filtering.
// Enhanced with:
- Grid/List view toggle
- Sort by: relevance, rating, distance, newest
- Infinite scroll or pagination
- Featured listings
- Sponsored listings
- Empty state handlingSearch and Filtering
Search Types
<SearchBar
searchTypes={[
{ type: "name", label: "Search by name" },
{ type: "category", label: "Search by category" },
{ type: "location", label: "Search by location" }
]}
onSearch={(query, type) => {
// Handle typed search
}}
/>Faceted Filtering
<FilterPanel
filters={[
{
type: "category",
label: "Category",
multiple: true,
options: categories
},
{
type: "price",
label: "Price Range",
component: "range-slider",
min: 0,
max: 100
},
{
type: "distance",
label: "Distance",
component: "range-slider",
min: 0,
max: 50,
unit: "miles"
}
]}
/>Active Filters
<ActiveFilters
filters={[
{ type: "category", value: "restaurant", label: "Restaurants" },
{ type: "rating", value: "4+", label: "4+ Stars" }
]}
onRemove={(filter) => {
// Remove filter
}}
onClearAll={() => {
// Clear all filters
}}
/>Sorting Options
Sort Dropdown
<SortDropdown
options={[
{ value: "relevance", label: "Most Relevant" },
{ value: "rating", label: "Highest Rated" },
{ value: "distance", label: "Nearest" },
{ value: "newest", label: "Newest" },
{ value: "popular", label: "Most Popular" }
]}
selected="relevance"
onChange={(sort) => {
// Apply sorting
}}
/>Map Integration
Map View
<MapView
listings={listings}
provider="mapbox" // or "google", "openstreetmap"
apiKey="YOUR_API_KEY"
center={{ lat: 40.7589, lng: -73.9851 }}
zoom={12}
markers={listings.map(listing => ({
id: listing.id,
position: listing.location,
popup: <ListingCardMini listing={listing} />
}))}
onMarkerClick={(listing) => {
// Show details
}}
cluster={true}
clusterRadius={50}
/>Geolocation Search
<SearchBar
geolocation={true}
onGeolocation={(coords) => {
// Search near user location
searchNear(coords.lat, coords.lng)
}}
/>Listing Details
Contact Information
<ContactInfo
phone="(555) 123-4567"
email="info@example.com"
website="https://example.com"
social={{
facebook: "https://facebook.com/example",
instagram: "https://instagram.com/example"
}}
/>Hours of Operation
<Hours
schedule={{
monday: "9:00 AM - 5:00 PM",
tuesday: "9:00 AM - 5:00 PM",
wednesday: "9:00 AM - 5:00 PM",
thursday: "9:00 AM - 5:00 PM",
friday: "9:00 AM - 5:00 PM",
saturday: "10:00 AM - 3:00 PM",
sunday: "Closed"
}}
timezone="America/New_York"
currentStatus="open" // or "closed"
/>Reviews and Ratings
<Reviews
averageRating={4.5}
totalReviews={120}
distribution={{
5: 80,
4: 25,
3: 10,
2: 3,
1: 2
}}
reviews={[
{
author: "John Doe",
rating: 5,
date: "2024-01-15",
text: "Great place! Highly recommend.",
verified: true
}
]}
allowSubmit={true}
/>Best Practices
Directory Structure
- Clear categories: Logical, non-overlapping categories
- Rich listings: Complete information for every listing
- Quality images: High-quality photos for all listings
- Verification: Badge verified/official listings
- Regular updates: Keep listings current and accurate
Search Experience
- Fast search: Sub-100ms search results
- Autocomplete: Suggest as user types
- Typo tolerance: Handle misspellings
- Location-aware: Default to user's location
- Remember searches: Save recent searches
Filter Design
- Show counts: Display result count for each filter
- Clear hierarchy: Organize filters logically
- Mobile-friendly: Drawer or bottom sheet on mobile
- Persistent state: Remember filter selections
- Easy reset: Clear all filters with one click
Real-World Example
Complete directory site:
import {
Site,
DirectoryHeader,
SearchBar,
FilterPanel,
ListingGrid,
ListingCard,
ListingDetail,
MapView,
Pagination
} from '@mdxui/beacon'
<Site
type="directory"
name="Restaurant Finder"
domain="restaurantfinder.com"
directory={{
itemsPerPage: 20,
filters: true,
sorting: true,
map: true,
search: {
enabled: true,
placeholder: "Search restaurants, cuisine, or location..."
}
}}
>
<DirectoryHeader
logo={<Logo />}
search={true}
filterToggle={true}
viewToggle={true}
/>
<div className="directory-layout">
{/* Filter Sidebar */}
<FilterPanel
filters={[
{
type: "category",
label: "Cuisine",
options: cuisineTypes
},
{
type: "price",
label: "Price Range",
component: "range-slider",
min: 1,
max: 4
},
{
type: "rating",
label: "Rating",
options: ratingOptions
},
{
type: "features",
label: "Features",
options: [
{ value: "delivery", label: "Delivery Available" },
{ value: "outdoor", label: "Outdoor Seating" },
{ value: "parking", label: "Parking Available" }
]
}
]}
selected={activeFilters}
onChange={handleFilterChange}
/>
{/* Main Content */}
<main>
<SearchBar
placeholder="Search restaurants..."
autocomplete={true}
geolocation={true}
onSearch={handleSearch}
/>
<div className="results-header">
<p>{totalResults} restaurants found</p>
<SortDropdown
options={sortOptions}
selected={currentSort}
onChange={handleSort}
/>
<ViewToggle
views={["grid", "list", "map"]}
current={currentView}
onChange={setView}
/>
</div>
{currentView === "map" ? (
<MapView
listings={listings}
provider="mapbox"
center={mapCenter}
zoom={12}
cluster={true}
/>
) : (
<>
<ListingGrid
listings={listings}
layout={currentView}
itemsPerPage={20}
/>
<Pagination
currentPage={currentPage}
totalPages={totalPages}
onPageChange={handlePageChange}
/>
</>
)}
</main>
</div>
{/* Listing Detail Page */}
<ListingDetail
listing={currentListing}
showMap={true}
showReviews={true}
showSimilar={true}
/>
</Site>TypeScript
Full type definition:
import { z } from 'zod'
import { BaseSiteSchema } from 'mdxui/zod'
export const DirectorySiteSchema = BaseSiteSchema.extend({
type: z.literal('directory'),
directory: z.object({
itemsPerPage: z.number().default(20),
filters: z.boolean().default(true),
sorting: z.boolean().default(true),
map: z.boolean().default(false),
search: z.object({
enabled: z.boolean().default(true),
placeholder: z.string().optional(),
}).optional(),
}).optional(),
})
export type DirectorySite = z.infer<typeof DirectorySiteSchema>Related Documentation
- Site Component - Base site configuration
- Search Component - Search functionality
- Card Component - Card layouts
- Map Component - Map integration