feat(ui): refresh glass header and map bottom sheets
All checks were successful
Build Docker Image / build (push) Successful in 5m23s

This commit is contained in:
Ruslan Bakiev
2026-03-08 08:56:58 +07:00
parent 4001756c3c
commit e4d6c9ce81
4 changed files with 118 additions and 98 deletions

View File

@@ -2,84 +2,84 @@
<Transition name="address-slide"> <Transition name="address-slide">
<div <div
v-if="isOpen && addressUuid" v-if="isOpen && addressUuid"
class="fixed inset-x-0 bottom-0 z-50 flex flex-col" class="fixed inset-x-0 bottom-0 z-50 flex justify-center px-3 md:px-4"
style="height: 70vh" style="height: 72vh"
> >
<!-- Backdrop (clickable to close) --> <!-- Backdrop (clickable to close) -->
<div <div
class="absolute inset-0 -top-[30vh] bg-black/30" class="absolute inset-0 -top-[32vh] bg-gradient-to-t from-black/45 via-black/20 to-transparent"
@click="emit('close')" @click="emit('close')"
/> />
<!-- Sheet content --> <!-- Sheet content -->
<div class="relative flex-1 bg-black/40 backdrop-blur-xl rounded-t-2xl border-t border-white/20 shadow-2xl overflow-hidden"> <div class="relative flex w-full max-w-[980px] flex-col overflow-hidden rounded-t-[2rem] border border-white/60 bg-base-100/95 shadow-[0_-24px_70px_rgba(15,23,42,0.3)] backdrop-blur-xl">
<!-- Header with drag handle and close --> <!-- Header with drag handle and close -->
<div class="sticky top-0 z-10 bg-black/30 backdrop-blur-md border-b border-white/10"> <div class="sticky top-0 z-10 border-b border-base-300 bg-base-100/90">
<div class="flex justify-center py-2"> <div class="flex justify-center py-2">
<div class="w-12 h-1.5 bg-white/30 rounded-full" /> <div class="h-1.5 w-12 rounded-full bg-base-content/20" />
</div> </div>
<div class="flex items-center justify-between px-6 pb-4"> <div class="flex items-center justify-between px-6 pb-4">
<template v-if="address"> <template v-if="address">
<div class="flex items-center gap-3 flex-1 min-w-0"> <div class="flex items-center gap-3 flex-1 min-w-0">
<div class="w-10 h-10 bg-emerald-500/20 rounded-xl flex items-center justify-center flex-shrink-0 text-2xl"> <div class="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-xl bg-success/20 text-2xl">
{{ isoToEmoji(address.countryCode) }} {{ isoToEmoji(address.countryCode) }}
</div> </div>
<div class="min-w-0"> <div class="min-w-0">
<div class="font-bold text-white truncate">{{ address.name }}</div> <div class="truncate text-xl font-black text-base-content">{{ address.name }}</div>
<div class="text-sm text-white/60 truncate">{{ address.address }}</div> <div class="truncate text-sm text-base-content/60">{{ address.address }}</div>
</div> </div>
</div> </div>
</template> </template>
<template v-else> <template v-else>
<div class="flex items-center gap-3 flex-1"> <div class="flex items-center gap-3 flex-1">
<div class="w-10 h-10 bg-white/10 rounded-xl animate-pulse" /> <div class="h-10 w-10 animate-pulse rounded-xl bg-base-300/70" />
<div class="flex-1"> <div class="flex-1">
<div class="h-5 bg-white/10 rounded w-48 animate-pulse" /> <div class="h-5 w-48 animate-pulse rounded bg-base-300/70" />
<div class="h-4 bg-white/10 rounded w-32 mt-1 animate-pulse" /> <div class="mt-1 h-4 w-32 animate-pulse rounded bg-base-300/70" />
</div> </div>
</div> </div>
</template> </template>
<button class="btn btn-ghost btn-sm btn-circle text-white/60 hover:text-white flex-shrink-0" @click="emit('close')"> <button class="btn btn-ghost btn-sm btn-circle flex-shrink-0 text-base-content/60 hover:text-base-content" @click="emit('close')">
<Icon name="lucide:x" size="20" /> <Icon name="lucide:x" size="20" />
</button> </button>
</div> </div>
</div> </div>
<!-- Content --> <!-- Content -->
<div v-if="address" class="overflow-y-auto h-[calc(70vh-100px)] px-6 py-4 space-y-4"> <div v-if="address" class="h-[calc(72vh-110px)] overflow-y-auto px-6 py-4 space-y-4">
<!-- Location info --> <!-- Location info -->
<div class="bg-white/5 rounded-xl p-4 border border-white/10"> <div class="rounded-2xl border border-base-300 bg-base-100 p-4">
<div class="font-semibold text-white mb-3 flex items-center gap-2"> <div class="mb-3 flex items-center gap-2 text-base-content">
<Icon name="lucide:map-pin" size="18" /> <Icon name="lucide:map-pin" size="18" />
{{ t('profileAddresses.detail.location') }} <span class="text-lg font-black">{{ t('profileAddresses.detail.location') }}</span>
</div> </div>
<div class="space-y-2 text-sm"> <div class="space-y-2 text-sm">
<div class="flex items-start gap-2 text-white/80"> <div class="flex items-start gap-2 text-base-content/80">
<Icon name="lucide:navigation" size="14" class="text-white/50 mt-0.5 flex-shrink-0" /> <Icon name="lucide:navigation" size="14" class="mt-0.5 flex-shrink-0 text-base-content/50" />
<span>{{ address.address }}</span> <span>{{ address.address }}</span>
</div> </div>
<div v-if="address.latitude && address.longitude" class="flex items-center gap-2 text-white/60"> <div v-if="address.latitude && address.longitude" class="flex items-center gap-2 text-base-content/60">
<Icon name="lucide:crosshair" size="14" class="text-white/50" /> <Icon name="lucide:crosshair" size="14" class="text-base-content/50" />
<span class="font-mono text-xs">{{ address.latitude.toFixed(6) }}, {{ address.longitude.toFixed(6) }}</span> <span class="font-mono text-xs">{{ address.latitude.toFixed(6) }}, {{ address.longitude.toFixed(6) }}</span>
</div> </div>
</div> </div>
</div> </div>
<!-- Map preview --> <!-- Map preview -->
<div v-if="address.latitude && address.longitude" class="bg-white/5 rounded-xl p-4 border border-white/10"> <div v-if="address.latitude && address.longitude" class="rounded-2xl border border-base-300 bg-base-100 p-4">
<div class="font-semibold text-white mb-3 flex items-center gap-2"> <div class="mb-3 flex items-center gap-2 text-base-content">
<Icon name="lucide:map" size="18" /> <Icon name="lucide:map" size="18" />
{{ t('profileAddresses.detail.map') }} <span class="text-lg font-black">{{ t('profileAddresses.detail.map') }}</span>
</div> </div>
<div class="h-48 rounded-lg overflow-hidden"> <div class="h-48 overflow-hidden rounded-xl">
<ClientOnly> <ClientOnly>
<MapboxMap <MapboxMap
:map-id="'address-preview-' + addressUuid" :map-id="'address-preview-' + addressUuid"
style="width: 100%; height: 100%" style="width: 100%; height: 100%"
:options="{ :options="{
style: 'mapbox://styles/mapbox/dark-v11', style: 'mapbox://styles/mapbox/light-v11',
center: [address.longitude, address.latitude], center: [address.longitude, address.latitude],
zoom: 14, zoom: 14,
interactive: false interactive: false
@@ -98,7 +98,7 @@
<!-- Actions --> <!-- Actions -->
<div class="flex gap-3"> <div class="flex gap-3">
<NuxtLink :to="localePath(`/clientarea/addresses/${addressUuid}`)" class="flex-1"> <NuxtLink :to="localePath(`/clientarea/addresses/${addressUuid}`)" class="flex-1">
<button class="btn btn-sm w-full bg-white/10 border-white/20 text-white hover:bg-white/20"> <button class="btn btn-sm w-full btn-outline">
<Icon name="lucide:pencil" size="14" class="mr-2" /> <Icon name="lucide:pencil" size="14" class="mr-2" />
{{ t('profileAddresses.actions.edit') }} {{ t('profileAddresses.actions.edit') }}
</button> </button>
@@ -115,8 +115,8 @@
<!-- Loading state --> <!-- Loading state -->
<div v-else class="px-6 py-4 space-y-4"> <div v-else class="px-6 py-4 space-y-4">
<div class="h-24 bg-white/5 rounded-xl animate-pulse" /> <div class="h-24 animate-pulse rounded-xl bg-base-300/70" />
<div class="h-48 bg-white/5 rounded-xl animate-pulse" /> <div class="h-48 animate-pulse rounded-xl bg-base-300/70" />
</div> </div>
</div> </div>
</div> </div>

View File

@@ -2,40 +2,40 @@
<Transition name="order-slide"> <Transition name="order-slide">
<div <div
v-if="isOpen && orderUuid" v-if="isOpen && orderUuid"
class="fixed inset-x-0 bottom-0 z-50 flex flex-col" class="fixed inset-x-0 bottom-0 z-50 flex justify-center px-3 md:px-4"
style="height: 70vh" style="height: 72vh"
> >
<!-- Backdrop (clickable to close) --> <!-- Backdrop (clickable to close) -->
<div <div
class="absolute inset-0 -top-[30vh] bg-black/30" class="absolute inset-0 -top-[32vh] bg-gradient-to-t from-black/45 via-black/20 to-transparent"
@click="emit('close')" @click="emit('close')"
/> />
<!-- Sheet content --> <!-- Sheet content -->
<div class="relative flex-1 bg-black/40 backdrop-blur-xl rounded-t-2xl border-t border-white/20 shadow-2xl overflow-hidden"> <div class="relative flex w-full max-w-[980px] flex-col overflow-hidden rounded-t-[2rem] border border-white/60 bg-base-100/95 shadow-[0_-24px_70px_rgba(15,23,42,0.3)] backdrop-blur-xl">
<!-- Header with drag handle and close --> <!-- Header with drag handle and close -->
<div class="sticky top-0 z-10 bg-black/30 backdrop-blur-md border-b border-white/10"> <div class="sticky top-0 z-10 border-b border-base-300 bg-base-100/90">
<div class="flex justify-center py-2"> <div class="flex justify-center py-2">
<div class="w-12 h-1.5 bg-white/30 rounded-full" /> <div class="h-1.5 w-12 rounded-full bg-base-content/20" />
</div> </div>
<div class="flex items-center justify-between px-6 pb-4"> <div class="flex items-center justify-between px-6 pb-4">
<template v-if="hasOrderError"> <template v-if="hasOrderError">
<div class="flex-1"> <div class="flex-1">
<div class="font-semibold text-white">{{ t('common.error') }}</div> <div class="font-black text-base-content">{{ t('common.error') }}</div>
<div class="text-sm text-white/50">{{ orderError }}</div> <div class="text-sm text-base-content/60">{{ orderError }}</div>
</div> </div>
</template> </template>
<template v-else-if="!isLoadingOrder && order"> <template v-else-if="!isLoadingOrder && order">
<div class="flex items-center gap-3 flex-1 min-w-0"> <div class="flex items-center gap-3 flex-1 min-w-0">
<div class="w-10 h-10 bg-indigo-500/20 rounded-xl flex items-center justify-center flex-shrink-0"> <div class="flex h-12 w-12 flex-shrink-0 items-center justify-center rounded-xl bg-primary/15">
<Icon name="lucide:package" size="24" class="text-indigo-400" /> <Icon name="lucide:package" size="24" class="text-primary" />
</div> </div>
<div class="min-w-0"> <div class="min-w-0">
<div class="font-bold text-white truncate">{{ orderTitle }}</div> <div class="truncate text-xl font-black text-base-content">{{ orderTitle }}</div>
<div class="flex items-center gap-2 mt-0.5"> <div class="mt-0.5 flex items-center gap-2">
<span class="badge badge-primary badge-sm">#{{ order.name }}</span> <span class="badge badge-primary badge-sm">#{{ order.name }}</span>
<span v-if="order.status" class="badge badge-outline badge-sm text-white/60">{{ order.status }}</span> <span v-if="order.status" class="badge badge-outline badge-sm">{{ order.status }}</span>
</div> </div>
</div> </div>
</div> </div>
@@ -43,15 +43,15 @@
<template v-else> <template v-else>
<div class="flex items-center gap-3 flex-1"> <div class="flex items-center gap-3 flex-1">
<div class="w-10 h-10 bg-white/10 rounded-xl animate-pulse" /> <div class="h-10 w-10 animate-pulse rounded-xl bg-base-300/70" />
<div class="flex-1"> <div class="flex-1">
<div class="h-5 bg-white/10 rounded w-48 animate-pulse" /> <div class="h-5 w-48 animate-pulse rounded bg-base-300/70" />
<div class="h-4 bg-white/10 rounded w-32 mt-1 animate-pulse" /> <div class="mt-1 h-4 w-32 animate-pulse rounded bg-base-300/70" />
</div> </div>
</div> </div>
</template> </template>
<button class="btn btn-ghost btn-sm btn-circle text-white/60 hover:text-white flex-shrink-0" @click="emit('close')"> <button class="btn btn-ghost btn-sm btn-circle flex-shrink-0 text-base-content/60 hover:text-base-content" @click="emit('close')">
<Icon name="lucide:x" size="20" /> <Icon name="lucide:x" size="20" />
</button> </button>
</div> </div>
@@ -59,26 +59,26 @@
<!-- Error state --> <!-- Error state -->
<div v-if="hasOrderError" class="px-6 py-8 text-center"> <div v-if="hasOrderError" class="px-6 py-8 text-center">
<div class="text-white/70 mb-4">{{ orderError }}</div> <div class="mb-4 text-base-content/70">{{ orderError }}</div>
<button class="btn btn-sm bg-white/10 border-white/20 text-white" @click="loadOrder"> <button class="btn btn-sm btn-outline" @click="loadOrder">
{{ t('ordersDetail.errors.retry') }} {{ t('ordersDetail.errors.retry') }}
</button> </button>
</div> </div>
<!-- Scrollable content --> <!-- Scrollable content -->
<div v-else-if="order" class="overflow-y-auto h-[calc(70vh-100px)] px-6 py-4 space-y-4"> <div v-else-if="order" class="h-[calc(72vh-110px)] overflow-y-auto px-6 py-4 space-y-4">
<!-- Order meta --> <!-- Order meta -->
<div class="flex flex-wrap gap-2 text-sm"> <div class="flex flex-wrap gap-2 text-sm">
<span v-for="(meta, idx) in orderMeta" :key="idx" class="px-3 py-1 bg-white/10 rounded-full text-white/70"> <span v-for="(meta, idx) in orderMeta" :key="idx" class="rounded-full border border-base-300 bg-base-200 px-3 py-1 text-base-content/70">
{{ meta }} {{ meta }}
</span> </span>
</div> </div>
<!-- Route stages --> <!-- Route stages -->
<div v-if="orderStageItems.length" class="bg-white/5 rounded-xl p-4 border border-white/10"> <div v-if="orderStageItems.length" class="rounded-2xl border border-base-300 bg-base-100 p-4">
<div class="font-semibold text-white mb-3 flex items-center gap-2"> <div class="mb-3 flex items-center gap-2 text-base-content">
<Icon name="lucide:route" size="18" /> <Icon name="lucide:route" size="18" />
{{ t('ordersDetail.sections.stages.title', 'Маршрут') }} <span class="text-lg font-black">{{ t('ordersDetail.sections.stages.title', 'Маршрут') }}</span>
</div> </div>
<div class="space-y-3"> <div class="space-y-3">
<div <div
@@ -87,15 +87,15 @@
class="flex gap-3" class="flex gap-3"
> >
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">
<div class="w-3 h-3 rounded-full bg-indigo-500" /> <div class="h-3 w-3 rounded-full bg-primary" />
<div v-if="idx < orderStageItems.length - 1" class="w-0.5 flex-1 bg-white/20 my-1" /> <div v-if="idx < orderStageItems.length - 1" class="my-1 w-0.5 flex-1 bg-base-300" />
</div> </div>
<div class="flex-1 pb-3"> <div class="flex-1 pb-3">
<div class="text-sm text-white font-medium">{{ stage.from }}</div> <div class="text-sm font-bold text-base-content">{{ stage.from }}</div>
<div v-if="stage.to && stage.to !== stage.from" class="text-xs text-white/50 mt-0.5"> <div v-if="stage.to && stage.to !== stage.from" class="mt-0.5 text-xs text-base-content/60">
{{ stage.to }} {{ stage.to }}
</div> </div>
<div v-if="stage.meta?.length" class="text-xs text-white/40 mt-1"> <div v-if="stage.meta?.length" class="mt-1 text-xs text-base-content/50">
{{ stage.meta.join(' · ') }} {{ stage.meta.join(' · ') }}
</div> </div>
</div> </div>
@@ -104,10 +104,10 @@
</div> </div>
<!-- Timeline --> <!-- Timeline -->
<div v-if="order.stages?.length" class="bg-white/5 rounded-xl p-4 border border-white/10"> <div v-if="order.stages?.length" class="rounded-2xl border border-base-300 bg-base-100 p-4">
<div class="font-semibold text-white mb-3 flex items-center gap-2"> <div class="mb-3 flex items-center gap-2 text-base-content">
<Icon name="lucide:calendar" size="18" /> <Icon name="lucide:calendar" size="18" />
{{ t('ordersDetail.sections.timeline.title') }} <span class="text-lg font-black">{{ t('ordersDetail.sections.timeline.title') }}</span>
</div> </div>
<GanttTimeline <GanttTimeline
:stages="order.stages" :stages="order.stages"
@@ -117,10 +117,10 @@
</div> </div>
<!-- Map preview (small) --> <!-- Map preview (small) -->
<div v-if="orderRoutesForMap.length" class="bg-white/5 rounded-xl p-4 border border-white/10"> <div v-if="orderRoutesForMap.length" class="rounded-2xl border border-base-300 bg-base-100 p-4">
<div class="font-semibold text-white mb-3 flex items-center gap-2"> <div class="mb-3 flex items-center gap-2 text-base-content">
<Icon name="lucide:map" size="18" /> <Icon name="lucide:map" size="18" />
{{ t('ordersDetail.sections.map.title', 'Карта') }} <span class="text-lg font-black">{{ t('ordersDetail.sections.map.title', 'Карта') }}</span>
</div> </div>
<RequestRoutesMap :routes="orderRoutesForMap" :height="200" /> <RequestRoutesMap :routes="orderRoutesForMap" :height="200" />
</div> </div>
@@ -128,9 +128,9 @@
<!-- Loading state --> <!-- Loading state -->
<div v-else class="px-6 py-4 space-y-4"> <div v-else class="px-6 py-4 space-y-4">
<div class="h-20 bg-white/5 rounded-xl animate-pulse" /> <div class="h-20 animate-pulse rounded-xl bg-base-300/70" />
<div class="h-32 bg-white/5 rounded-xl animate-pulse" /> <div class="h-32 animate-pulse rounded-xl bg-base-300/70" />
<div class="h-48 bg-white/5 rounded-xl animate-pulse" /> <div class="h-48 animate-pulse rounded-xl bg-base-300/70" />
</div> </div>
</div> </div>
</div> </div>

View File

@@ -8,7 +8,8 @@
<div class="flex-1 flex flex-col" :style="contentStyle"> <div class="flex-1 flex flex-col" :style="contentStyle">
<!-- Fixed Header Container --> <!-- Fixed Header Container -->
<div class="fixed top-0 left-0 right-0 z-40" :style="headerContainerStyle"> <div class="liquid-header fixed top-0 left-0 right-0 z-40" :style="headerContainerStyle">
<div class="liquid-header-backdrop" aria-hidden="true" />
<!-- Animated background for home page --> <!-- Animated background for home page -->
<HeroBackground v-if="isHomePage" :collapse-progress="collapseProgress" /> <HeroBackground v-if="isHomePage" :collapse-progress="collapseProgress" />
@@ -357,3 +358,21 @@ const onSearch = () => {
searchTrigger.value++ searchTrigger.value++
} }
</script> </script>
<style scoped>
.liquid-header {
background: transparent;
}
.liquid-header-backdrop {
position: absolute;
inset: 0;
height: 320%;
background: rgba(255, 255, 255, 0.08);
-webkit-backdrop-filter: blur(16px) saturate(180%);
backdrop-filter: blur(16px) saturate(180%);
-webkit-mask-image: linear-gradient(to bottom, black 0%, black 22%, rgba(0, 0, 0, 0.45) 42%, rgba(0, 0, 0, 0.12) 68%, transparent 100%);
mask-image: linear-gradient(to bottom, black 0%, black 22%, rgba(0, 0, 0, 0.45) 42%, rgba(0, 0, 0, 0.12) 68%, transparent 100%);
pointer-events: none;
}
</style>

View File

@@ -12,27 +12,28 @@
<!-- Bottom Sheet with slide-up animation --> <!-- Bottom Sheet with slide-up animation -->
<Transition name="slide-up" appear> <Transition name="slide-up" appear>
<div class="fixed inset-x-0 bottom-0 z-50 flex flex-col" style="height: 70vh"> <div class="fixed inset-x-0 bottom-0 z-50 flex justify-center px-3 md:px-4" style="height: 72vh">
<!-- Glass sheet --> <div class="absolute inset-0 -top-[32vh] bg-gradient-to-t from-black/45 via-black/20 to-transparent" />
<div class="relative flex-1 bg-black/40 backdrop-blur-xl rounded-t-2xl border-t border-white/20 shadow-2xl overflow-hidden"> <!-- Sheet -->
<div class="relative flex w-full max-w-[980px] flex-col overflow-hidden rounded-t-[2rem] border border-white/60 bg-base-100/95 shadow-[0_-24px_70px_rgba(15,23,42,0.3)] backdrop-blur-xl">
<!-- Drag handle --> <!-- Drag handle -->
<div class="flex justify-center py-2"> <div class="flex justify-center py-2">
<div class="w-12 h-1.5 bg-white/30 rounded-full" /> <div class="h-1.5 w-12 rounded-full bg-base-content/20" />
</div> </div>
<!-- Header --> <!-- Header -->
<div class="px-6 pb-4 border-b border-white/10"> <div class="border-b border-base-300 bg-base-100/90 px-6 pb-4">
<!-- Back button --> <!-- Back button -->
<NuxtLink :to="localePath('/clientarea/orders')" class="inline-flex items-center gap-1 text-white/60 hover:text-white text-sm mb-3"> <NuxtLink :to="localePath('/clientarea/orders')" class="mb-3 inline-flex items-center gap-1 text-sm text-base-content/60 hover:text-base-content">
<Icon name="lucide:arrow-left" size="16" /> <Icon name="lucide:arrow-left" size="16" />
{{ t('common.back') }} {{ t('common.back') }}
</NuxtLink> </NuxtLink>
<template v-if="hasOrderError"> <template v-if="hasOrderError">
<div class="bg-error/20 border border-error/30 rounded-lg p-4"> <div class="rounded-lg border border-error/30 bg-error/10 p-4">
<div class="font-semibold text-white mb-2">{{ t('common.error') }}</div> <div class="mb-2 font-black text-base-content">{{ t('common.error') }}</div>
<div class="text-sm text-white/70 mb-3">{{ orderError }}</div> <div class="mb-3 text-sm text-base-content/70">{{ orderError }}</div>
<button class="btn btn-sm bg-white/10 border-white/20 text-white" @click="loadOrder"> <button class="btn btn-sm btn-outline" @click="loadOrder">
{{ t('ordersDetail.errors.retry') }} {{ t('ordersDetail.errors.retry') }}
</button> </button>
</div> </div>
@@ -40,13 +41,13 @@
<template v-else-if="!isLoadingOrder && order"> <template v-else-if="!isLoadingOrder && order">
<div class="flex items-center gap-3"> <div class="flex items-center gap-3">
<div class="w-12 h-12 rounded-xl bg-indigo-500/20 flex items-center justify-center"> <div class="flex h-12 w-12 items-center justify-center rounded-xl bg-primary/15">
<Icon name="lucide:package" size="24" class="text-indigo-400" /> <Icon name="lucide:package" size="24" class="text-primary" />
</div> </div>
<div class="flex-1 min-w-0"> <div class="flex-1 min-w-0">
<div class="font-bold text-lg text-white truncate">{{ orderTitle }}</div> <div class="truncate text-xl font-black text-base-content">{{ orderTitle }}</div>
<div class="flex items-center gap-2 flex-wrap"> <div class="flex items-center gap-2 flex-wrap">
<span v-for="(meta, idx) in orderMeta" :key="idx" class="text-xs text-white/50"> <span v-for="(meta, idx) in orderMeta" :key="idx" class="text-xs text-base-content/55">
{{ meta }}{{ idx < orderMeta.length - 1 ? ' · ' : '' }} {{ meta }}{{ idx < orderMeta.length - 1 ? ' · ' : '' }}
</span> </span>
</div> </div>
@@ -56,18 +57,18 @@
<template v-else> <template v-else>
<div class="animate-pulse"> <div class="animate-pulse">
<div class="h-12 bg-white/10 rounded-xl w-48" /> <div class="h-12 w-48 rounded-xl bg-base-300/70" />
</div> </div>
</template> </template>
</div> </div>
<!-- Scrollable content --> <!-- Scrollable content -->
<div v-if="!hasOrderError && order" class="overflow-y-auto h-[calc(70vh-140px)] px-6 py-4 space-y-4"> <div v-if="!hasOrderError && order" class="h-[calc(72vh-150px)] overflow-y-auto px-6 py-4 space-y-4">
<!-- Route stages --> <!-- Route stages -->
<div v-if="orderStageItems.length" class="bg-white/5 rounded-xl p-4 border border-white/10"> <div v-if="orderStageItems.length" class="rounded-2xl border border-base-300 bg-base-100 p-4">
<div class="font-semibold text-white mb-3 flex items-center gap-2"> <div class="mb-3 flex items-center gap-2 text-base-content">
<Icon name="lucide:route" size="18" /> <Icon name="lucide:route" size="18" />
{{ t('ordersDetail.sections.stages.title', 'Маршрут') }} <span class="text-lg font-black">{{ t('ordersDetail.sections.stages.title', 'Маршрут') }}</span>
</div> </div>
<div class="space-y-3"> <div class="space-y-3">
<div <div
@@ -76,15 +77,15 @@
class="flex gap-3" class="flex gap-3"
> >
<div class="flex flex-col items-center"> <div class="flex flex-col items-center">
<div class="w-3 h-3 rounded-full bg-indigo-500" /> <div class="h-3 w-3 rounded-full bg-primary" />
<div v-if="idx < orderStageItems.length - 1" class="w-0.5 flex-1 bg-white/20 my-1" /> <div v-if="idx < orderStageItems.length - 1" class="my-1 w-0.5 flex-1 bg-base-300" />
</div> </div>
<div class="flex-1 pb-3"> <div class="flex-1 pb-3">
<div class="text-sm text-white font-medium">{{ stage.from }}</div> <div class="text-sm font-bold text-base-content">{{ stage.from }}</div>
<div v-if="stage.to && stage.to !== stage.from" class="text-xs text-white/50 mt-0.5"> <div v-if="stage.to && stage.to !== stage.from" class="mt-0.5 text-xs text-base-content/60">
{{ stage.to }} {{ stage.to }}
</div> </div>
<div v-if="stage.meta?.length" class="text-xs text-white/40 mt-1"> <div v-if="stage.meta?.length" class="mt-1 text-xs text-base-content/50">
{{ stage.meta.join(' · ') }} {{ stage.meta.join(' · ') }}
</div> </div>
</div> </div>
@@ -93,10 +94,10 @@
</div> </div>
<!-- Timeline --> <!-- Timeline -->
<div v-if="order.stages?.length" class="bg-white/5 rounded-xl p-4 border border-white/10"> <div v-if="order.stages?.length" class="rounded-2xl border border-base-300 bg-base-100 p-4">
<div class="font-semibold text-white mb-3 flex items-center gap-2"> <div class="mb-3 flex items-center gap-2 text-base-content">
<Icon name="lucide:calendar" size="18" /> <Icon name="lucide:calendar" size="18" />
{{ t('ordersDetail.sections.timeline.title') }} <span class="text-lg font-black">{{ t('ordersDetail.sections.timeline.title') }}</span>
</div> </div>
<GanttTimeline <GanttTimeline
:stages="order.stages" :stages="order.stages"
@@ -106,10 +107,10 @@
</div> </div>
<!-- Map preview (small) --> <!-- Map preview (small) -->
<div v-if="orderRoutesForMap.length" class="bg-white/5 rounded-xl p-4 border border-white/10"> <div v-if="orderRoutesForMap.length" class="rounded-2xl border border-base-300 bg-base-100 p-4">
<div class="font-semibold text-white mb-3 flex items-center gap-2"> <div class="mb-3 flex items-center gap-2 text-base-content">
<Icon name="lucide:map" size="18" /> <Icon name="lucide:map" size="18" />
{{ t('ordersDetail.sections.map.title', 'Карта') }} <span class="text-lg font-black">{{ t('ordersDetail.sections.map.title', 'Карта') }}</span>
</div> </div>
<RequestRoutesMap :routes="orderRoutesForMap" :height="200" /> <RequestRoutesMap :routes="orderRoutesForMap" :height="200" />
</div> </div>