feat(ui): redesign GlobalSearchBar, split layouts, and remove hero section
All checks were successful
Build Docker Image / build (push) Successful in 5m25s

- Make GlobalSearchBar functional with searchStore integration
- Add destination search using hubs/nodes GraphQL query
- Navigate to /request page instead of /catalog/offers
- Remove hero section from index.vue (search is now in header)
- Add padding (px-3 lg:px-6) to topnav layout
- Implement split layout for catalog pages (offers, hubs, suppliers)
  - Left side: filters + scrollable card list (40%)
  - Right side: map (60%, hidden on mobile)
This commit is contained in:
Ruslan Bakiev
2026-01-08 08:13:22 +07:00
parent 1e179ab04c
commit 1a2693bcd6
6 changed files with 194 additions and 254 deletions

View File

@@ -1,68 +1,5 @@
<template>
<Stack gap="12">
<Section variant="hero">
<Stack gap="6">
<Heading :level="1" tone="inverse">{{ $t('search.title') }}</Heading>
<Text tone="inverse">{{ $t('search.description') }}</Text>
<Card padding="lg">
<Stack gap="6">
<!-- Search form -->
<Grid :cols="1" :md="4" :gap="4">
<Stack gap="2">
<Text tag="p" size="base" weight="semibold">{{ $t('search.product_label') }}</Text>
<FieldButton
:value="searchStore.searchForm.product"
:placeholder="$t('search.product_placeholder')"
@click="navigateTo(localePath('/goods'))"
/>
</Stack>
<Stack gap="2">
<Text tag="p" size="base" weight="semibold">{{ $t('search.quantity_label') }}</Text>
<Input
type="number"
v-model="searchStore.searchForm.quantity"
:placeholder="$t('search.quantity_placeholder')"
/>
</Stack>
<Stack gap="2">
<Text tag="p" size="base" weight="semibold">{{ $t('search.location_label') }}</Text>
<FieldButton
:value="searchStore.searchForm.location"
:placeholder="$t('search.location_placeholder')"
@click="navigateTo(localePath({ path: '/select-location', query: { mode: 'search' } }))"
/>
</Stack>
<Stack gap="2" align="stretch">
<Text tag="p" size="base" weight="semibold" tone="muted"> </Text>
<Button type="button" @click="handleSearch">
{{ searchError ? $t('search.error') : $t('search.search_button') }}
</Button>
</Stack>
</Grid>
</Stack>
</Card>
<Stack v-if="popularExamples.length" gap="2" align="center">
<Text tone="inverse" size="sm">{{ $t('search.popular_requests') }}</Text>
<Stack direction="row" gap="2" justify="center" align="center" class="flex-wrap text-center">
<button
v-for="example in popularExamples"
:key="`${example.product}-${example.location}`"
type="button"
class="badge badge-dash badge-primary text-sm"
@click="fillExample(example)"
>
{{ example.product }} {{ example.quantity }}{{ $t('search.units.tons_short') }} {{ example.location }}
</button>
</Stack>
</Stack>
</Stack>
</Section>
<Section variant="plain">
<Stack gap="8" align="center">
<Heading :level="2">{{ $t('roles.title') }}</Heading>
@@ -152,48 +89,4 @@
definePageMeta({
layout: 'topnav'
})
const { t } = useI18n()
const searchStore = useSearchStore()
const searchError = ref('')
const localePath = useLocalePath()
const popularExamples = computed(() => ([
{ product: t('search.examples.metal_sheet.product'), quantity: 120, location: t('search.examples.metal_sheet.location') },
{ product: t('search.examples.green_coffee.product'), quantity: 200, location: t('search.examples.green_coffee.location') },
{ product: t('search.examples.wheat.product'), quantity: 500, location: t('search.examples.wheat.location') },
{ product: t('search.examples.cocoa.product'), quantity: 150, location: t('search.examples.cocoa.location') },
]))
const handleSearch = () => {
const location = (searchStore.searchForm.location || '').trim()
const productText = (searchStore.searchForm.product || '').trim()
const hasProduct = !!(searchStore.searchForm.productUuid || productText)
if (!location) {
searchError.value = t('search.validation.fill_product_location')
setTimeout(() => (searchError.value = ''), 2000)
return
}
if (!hasProduct) {
navigateTo(localePath('/goods'))
return
}
const query = {
productUuid: searchStore.searchForm.productUuid || undefined,
product: productText || undefined,
quantity: searchStore.searchForm.quantity || undefined,
locationUuid: searchStore.searchForm.locationUuid || undefined,
location: searchStore.searchForm.location || undefined
}
navigateTo(localePath({ path: '/request', query }))
}
const fillExample = (example) => {
searchStore.searchForm.product = example.product
searchStore.searchForm.quantity = example.quantity
searchStore.searchForm.location = example.location
}
</script>