feat(ui): unify logistics-style side panel flow
This commit is contained in:
86
app/components/shell/MapSidePanel.vue
Normal file
86
app/components/shell/MapSidePanel.vue
Normal file
@@ -0,0 +1,86 @@
|
||||
<script setup lang="ts">
|
||||
const props = withDefaults(defineProps<{
|
||||
title?: string
|
||||
initialCollapsed?: boolean
|
||||
collapsible?: boolean
|
||||
positionClass?: string
|
||||
topOffsetClass?: string
|
||||
bottomOffsetClass?: string
|
||||
widthClass?: string
|
||||
}>(), {
|
||||
title: '',
|
||||
initialCollapsed: false,
|
||||
collapsible: true,
|
||||
positionClass: 'left-4',
|
||||
topOffsetClass: 'top-[96px]',
|
||||
bottomOffsetClass: 'bottom-4',
|
||||
widthClass: 'w-[min(calc(100vw-1rem),440px)] md:w-[420px] xl:w-[460px]',
|
||||
})
|
||||
|
||||
const collapsed = ref(props.initialCollapsed)
|
||||
|
||||
function toggleCollapsed() {
|
||||
collapsed.value = !collapsed.value
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="pointer-events-none fixed z-40" :class="[positionClass, topOffsetClass, bottomOffsetClass]">
|
||||
<section
|
||||
class="pointer-events-auto flex h-full flex-col overflow-hidden rounded-[28px] border-0 bg-[#f3eee6] text-[#2f2418] shadow-[0_28px_70px_rgba(38,29,18,0.18)]"
|
||||
:class="collapsible && collapsed ? 'w-16 rounded-full' : widthClass"
|
||||
style="transition: width 260ms ease;"
|
||||
>
|
||||
<template v-if="collapsible && collapsed">
|
||||
<button
|
||||
type="button"
|
||||
class="flex h-full w-full cursor-pointer flex-col items-center justify-between px-3 py-3 text-left transition hover:bg-[#eee6dc]"
|
||||
:aria-expanded="String(!collapsed)"
|
||||
:aria-label="$t('ui.expand_panel')"
|
||||
@click="toggleCollapsed"
|
||||
>
|
||||
<span class="flex h-10 w-10 items-center justify-center rounded-full bg-white text-[#5f4b33] transition">
|
||||
<svg viewBox="0 0 24 24" fill="none" class="h-4 w-4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m9 6 6 6-6 6" />
|
||||
</svg>
|
||||
</span>
|
||||
|
||||
<p v-if="title" class="origin-center whitespace-nowrap -rotate-90 text-[11px] font-bold uppercase tracking-[0.14em] text-[#6f6353]">
|
||||
{{ title }}
|
||||
</p>
|
||||
|
||||
<div class="h-10 w-10" aria-hidden="true" />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<header v-if="title || $slots.header" class="flex shrink-0 items-start justify-between gap-3 border-b border-[#ded3c2] bg-[#f3eee6] px-5 py-4">
|
||||
<div class="min-w-0 flex-1">
|
||||
<slot name="header">
|
||||
<h1 v-if="title" class="truncate text-xl font-black text-[#2f2418] md:text-2xl">{{ title }}</h1>
|
||||
</slot>
|
||||
</div>
|
||||
<button
|
||||
v-if="collapsible"
|
||||
type="button"
|
||||
class="flex h-10 w-10 shrink-0 items-center justify-center rounded-full bg-white text-[#5f4b33] transition hover:bg-[#fbf8f4]"
|
||||
:aria-label="$t('ui.collapse_panel')"
|
||||
@click="toggleCollapsed"
|
||||
>
|
||||
<svg viewBox="0 0 24 24" fill="none" class="h-4 w-4" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
||||
<path d="m15 18-6-6 6-6" />
|
||||
</svg>
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div class="min-h-0 flex-1 overflow-y-auto p-4 md:p-5">
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<footer v-if="$slots.footer" class="shrink-0 border-t border-[#ded3c2] bg-[#f3eee6] px-4 py-4 md:px-5 md:py-5">
|
||||
<slot name="footer" />
|
||||
</footer>
|
||||
</template>
|
||||
</section>
|
||||
</div>
|
||||
</template>
|
||||
Reference in New Issue
Block a user