Refactor MarketPage layout for improved mobile responsiveness and user experience
- Optimized the Market Header and Fuzzy Search components for better mobile display, enhancing usability on smaller screens. - Adjusted spacing and font sizes for various elements to ensure a cohesive look across devices. - Improved the active filters summary and category filters for better accessibility and visual clarity. These changes enhance the overall user experience by providing a more responsive and visually appealing interface in the MarketPage.
This commit is contained in:
parent
f2a432b6df
commit
8fe53d3d71
1 changed files with 55 additions and 51 deletions
|
|
@ -23,32 +23,36 @@
|
|||
|
||||
<!-- Market Content -->
|
||||
<div v-else>
|
||||
<!-- Market Header -->
|
||||
<div class="flex items-center justify-between mb-8">
|
||||
<div class="flex items-center space-x-4">
|
||||
<Avatar v-if="marketStore.activeMarket?.opts?.logo">
|
||||
<AvatarImage :src="marketStore.activeMarket.opts.logo" />
|
||||
<AvatarFallback>M</AvatarFallback>
|
||||
</Avatar>
|
||||
<div>
|
||||
<h1 class="text-3xl font-bold">
|
||||
{{ marketStore.activeMarket?.opts?.name || 'Market' }}
|
||||
</h1>
|
||||
<p v-if="marketStore.activeMarket?.opts?.description" class="text-gray-600">
|
||||
{{ marketStore.activeMarket.opts.description }}
|
||||
</p>
|
||||
<!-- Market Header - Optimized for Mobile -->
|
||||
<div class="mb-4 sm:mb-6 lg:mb-8">
|
||||
<!-- Market Info and Search - Responsive Layout -->
|
||||
<div class="flex flex-col lg:flex-row lg:items-center lg:justify-between gap-3 sm:gap-4 lg:gap-6">
|
||||
<!-- Market Info - Compact on Mobile -->
|
||||
<div class="flex items-center space-x-3 sm:space-x-4">
|
||||
<Avatar v-if="marketStore.activeMarket?.opts?.logo" class="h-10 w-10 sm:h-12 sm:w-12">
|
||||
<AvatarImage :src="marketStore.activeMarket.opts.logo" />
|
||||
<AvatarFallback>M</AvatarFallback>
|
||||
</Avatar>
|
||||
<div>
|
||||
<h1 class="text-xl sm:text-2xl lg:text-3xl font-bold">
|
||||
{{ marketStore.activeMarket?.opts?.name || 'Market' }}
|
||||
</h1>
|
||||
<p v-if="marketStore.activeMarket?.opts?.description" class="text-muted-foreground text-xs sm:text-sm lg:text-base line-clamp-1 sm:line-clamp-2">
|
||||
{{ marketStore.activeMarket.opts.description }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Enhanced Fuzzy Search Bar - Full Width on Mobile -->
|
||||
<div class="w-full lg:flex-1 lg:max-w-md">
|
||||
<MarketFuzzySearch
|
||||
:data="marketStore.products"
|
||||
:options="searchOptions"
|
||||
@results="handleSearchResults"
|
||||
@filter-category="handleCategoryFilter"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Enhanced Fuzzy Search Bar -->
|
||||
<div class="flex-1 max-w-md ml-8">
|
||||
<MarketFuzzySearch
|
||||
:data="marketStore.products"
|
||||
:options="searchOptions"
|
||||
@results="handleSearchResults"
|
||||
@filter-category="handleCategoryFilter"
|
||||
class="w-full"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -57,28 +61,28 @@
|
|||
<!-- Enhanced Category Filters -->
|
||||
<section
|
||||
v-if="allCategories.length > 0"
|
||||
class="mb-6"
|
||||
class="mb-4 sm:mb-6"
|
||||
aria-labelledby="category-filters-heading"
|
||||
>
|
||||
<div class="flex items-center justify-between mb-3">
|
||||
<div class="flex items-center gap-4">
|
||||
<h3 id="category-filters-heading" class="text-lg font-semibold text-gray-700">
|
||||
<div class="flex items-center justify-between mb-2 sm:mb-3">
|
||||
<div class="flex items-center gap-2 sm:gap-4">
|
||||
<h3 id="category-filters-heading" class="text-sm sm:text-lg font-semibold text-gray-700">
|
||||
Browse by Category
|
||||
</h3>
|
||||
|
||||
<!-- AND/OR Filter Mode Toggle -->
|
||||
<div
|
||||
v-if="selectedCategoriesCount > 1"
|
||||
class="flex items-center gap-2"
|
||||
class="flex items-center gap-1 sm:gap-2"
|
||||
role="group"
|
||||
aria-label="Filter mode selection"
|
||||
>
|
||||
<span class="text-xs text-muted-foreground">Match:</span>
|
||||
<span class="text-xs text-muted-foreground hidden sm:inline">Match:</span>
|
||||
<Button
|
||||
@click="setFilterMode('any')"
|
||||
:variant="filterMode === 'any' ? 'default' : 'outline'"
|
||||
size="sm"
|
||||
class="h-6 px-2 text-xs"
|
||||
class="h-5 sm:h-6 px-1.5 sm:px-2 text-xs"
|
||||
:aria-pressed="filterMode === 'any'"
|
||||
aria-label="Show products with any selected category"
|
||||
>
|
||||
|
|
@ -88,7 +92,7 @@
|
|||
@click="setFilterMode('all')"
|
||||
:variant="filterMode === 'all' ? 'default' : 'outline'"
|
||||
size="sm"
|
||||
class="h-6 px-2 text-xs"
|
||||
class="h-5 sm:h-6 px-1.5 sm:px-2 text-xs"
|
||||
:aria-pressed="filterMode === 'all'"
|
||||
aria-label="Show products with all selected categories"
|
||||
>
|
||||
|
|
@ -102,16 +106,16 @@
|
|||
@click="clearAllCategoryFilters"
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
class="text-sm"
|
||||
class="text-xs sm:text-sm px-2 sm:px-3 py-1 sm:py-2"
|
||||
:aria-label="`Clear all ${selectedCategoriesCount} selected category filters`"
|
||||
>
|
||||
Clear All ({{ selectedCategoriesCount }})
|
||||
<X class="w-4 h-4 ml-1" aria-hidden="true" />
|
||||
<span class="hidden sm:inline">Clear All </span><span class="sm:hidden">Clear </span>({{ selectedCategoriesCount }})
|
||||
<X class="w-3 h-3 sm:w-4 sm:h-4 ml-1" aria-hidden="true" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex flex-wrap gap-3"
|
||||
class="flex flex-wrap gap-1.5 sm:gap-3"
|
||||
role="group"
|
||||
aria-label="Filter products by category"
|
||||
>
|
||||
|
|
@ -130,7 +134,7 @@
|
|||
>
|
||||
<Badge
|
||||
:variant="category.selected ? 'default' : 'outline'"
|
||||
class="px-4 py-2 text-sm font-medium transition-all duration-200"
|
||||
class="px-2 py-1 sm:px-4 sm:py-2 text-xs sm:text-sm font-medium transition-all duration-200"
|
||||
:class="{
|
||||
'bg-primary text-primary-foreground shadow-md': category.selected,
|
||||
'hover:bg-primary/10 hover:border-primary': !category.selected,
|
||||
|
|
@ -138,10 +142,10 @@
|
|||
}"
|
||||
:aria-hidden="true"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<div class="flex items-center gap-1 sm:gap-2">
|
||||
<span>{{ category.category }}</span>
|
||||
<div
|
||||
class="px-2 py-0.5 rounded-full text-xs font-bold transition-colors"
|
||||
class="px-1 py-0.5 sm:px-2 rounded-full text-xs font-bold transition-colors"
|
||||
:class="category.selected
|
||||
? 'bg-primary-foreground/20 text-primary-foreground'
|
||||
: 'bg-secondary text-secondary-foreground'"
|
||||
|
|
@ -159,9 +163,9 @@
|
|||
<!-- Selection indicator -->
|
||||
<div
|
||||
v-if="category.selected"
|
||||
class="absolute -top-1 -right-1 w-3 h-3 bg-green-500 rounded-full border-2 border-white shadow-sm"
|
||||
class="absolute -top-0.5 -right-0.5 sm:-top-1 sm:-right-1 w-2.5 h-2.5 sm:w-3 sm:h-3 bg-green-500 rounded-full border-2 border-white shadow-sm"
|
||||
>
|
||||
<Check class="w-2 h-2 text-white absolute top-0.5 left-0.5" />
|
||||
<Check class="w-1.5 h-1.5 sm:w-2 sm:h-2 text-white absolute top-0 left-0 sm:top-0.5 sm:left-0.5" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -169,34 +173,34 @@
|
|||
<!-- Active Filters Summary -->
|
||||
<div
|
||||
v-if="selectedCategoriesCount > 0"
|
||||
class="mt-4 p-3 bg-accent/50 rounded-lg border border-border"
|
||||
class="mt-2 sm:mt-4 p-2 sm:p-3 bg-accent/50 rounded-lg border border-border"
|
||||
role="region"
|
||||
aria-label="Active category filters"
|
||||
aria-live="polite"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="flex items-center gap-2">
|
||||
<Filter class="w-4 h-4 text-accent-foreground/80" aria-hidden="true" />
|
||||
<span class="text-sm font-medium text-accent-foreground">
|
||||
Active Filters
|
||||
<div class="flex flex-col sm:flex-row sm:items-center sm:justify-between gap-2">
|
||||
<div class="flex items-center gap-1.5 sm:gap-2">
|
||||
<Filter class="w-3 h-3 sm:w-4 sm:h-4 text-accent-foreground/80" aria-hidden="true" />
|
||||
<span class="text-xs sm:text-sm font-medium text-accent-foreground">
|
||||
<span class="hidden sm:inline">Active Filters</span><span class="sm:hidden">Filters</span>
|
||||
<span v-if="selectedCategoriesCount > 1" class="text-xs opacity-75">
|
||||
({{ filterMode === 'any' ? 'Any' : 'All' }} match):
|
||||
</span>
|
||||
<span v-else>:</span>
|
||||
</span>
|
||||
<div class="flex gap-1" role="list" aria-label="Selected category filters">
|
||||
<div class="flex gap-0.5 sm:gap-1 flex-wrap" role="list" aria-label="Selected category filters">
|
||||
<Badge
|
||||
v-for="category in selectedCategories"
|
||||
:key="category"
|
||||
variant="secondary"
|
||||
class="text-xs"
|
||||
class="text-xs px-1.5 py-0.5"
|
||||
role="listitem"
|
||||
>
|
||||
{{ category }}
|
||||
</Badge>
|
||||
</div>
|
||||
</div>
|
||||
<div class="text-sm text-muted-foreground" aria-live="polite">
|
||||
<div class="text-xs sm:text-sm text-muted-foreground" aria-live="polite">
|
||||
{{ productsToDisplay.length }} products found
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue