feat: add slide-in animation for right panel in BaseModalLayout

This commit is contained in:
Alexander Brown
2026-01-16 16:49:55 -08:00
parent ea78e3c2a3
commit 9146b33659
2 changed files with 55 additions and 27 deletions

View File

@@ -14,7 +14,7 @@
</nav>
</Transition>
<div class="flex-1 flex bg-base-background">
<div class="flex-1 flex bg-base-background overflow-hidden">
<div class="flex h-full w-full flex-col">
<header
v-if="$slots.header"
@@ -65,32 +65,35 @@
</div>
</main>
</div>
<aside
v-if="hasRightPanel && isRightPanelOpen"
class="flex w-72 shrink-0 bg-modal-panel-background flex-col"
>
<header
data-component-id="RightPanelHeader"
class="flex h-16 shrink-0 items-center gap-2 px-4"
<Transition name="slide-panel-right">
<aside
v-if="hasRightPanel && isRightPanelOpen"
key="right-panel"
class="flex w-72 shrink-0 bg-modal-panel-background flex-col"
>
<h2 v-if="rightPanelTitle" class="flex-1 text-lg font-semibold">
{{ rightPanelTitle }}
</h2>
<div v-else class="flex-1">
<slot name="rightPanelHeaderTitle" />
<header
data-component-id="RightPanelHeader"
class="flex h-16 shrink-0 items-center gap-2 px-4"
>
<h2 v-if="rightPanelTitle" class="flex-1 text-lg font-semibold">
{{ rightPanelTitle }}
</h2>
<div v-else class="flex-1">
<slot name="rightPanelHeaderTitle" />
</div>
<slot name="rightPanelHeaderActions" />
<Button size="icon" @click="toggleRightPanel">
<i class="icon-[lucide--panel-right-close] text-sm" />
</Button>
<Button size="icon" @click="closeDialog">
<i class="pi pi-times" />
</Button>
</header>
<div class="min-h-0 flex-1 overflow-y-auto">
<slot name="rightPanel" />
</div>
<slot name="rightPanelHeaderActions" />
<Button size="icon" @click="toggleRightPanel">
<i class="icon-[lucide--panel-right-close] text-sm" />
</Button>
<Button size="icon" @click="closeDialog">
<i class="pi pi-times" />
</Button>
</header>
<div class="min-h-0 flex-1 overflow-y-auto">
<slot name="rightPanel" />
</div>
</aside>
</aside>
</Transition>
</div>
</div>
</div>
@@ -201,4 +204,21 @@ const toggleRightPanel = () => {
.slide-panel-leave-to {
transform: translateX(-100%);
}
/* Slide transition for right panel */
.slide-panel-right-enter-active,
.slide-panel-right-leave-active {
position: absolute;
right: 0;
top: 0;
height: 100%;
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1);
will-change: transform;
backface-visibility: hidden;
}
.slide-panel-right-enter-from,
.slide-panel-right-leave-to {
transform: translateX(100%);
}
</style>

View File

@@ -1,7 +1,7 @@
<template>
<BaseModalLayout
:hide-right-panel-button="true"
:right-panel-open="!!focusedAsset"
:right-panel-open="isPanelOpen"
data-component-id="AssetBrowserModal"
class="size-full max-h-full max-w-full min-w-0"
:content-title="displayTitle"
@@ -74,7 +74,7 @@
</template>
<script setup lang="ts">
import { breakpointsTailwind, useBreakpoints } from '@vueuse/core'
import { breakpointsTailwind, refDebounced, useBreakpoints } from '@vueuse/core'
import { computed, provide, ref } from 'vue'
import { useI18n } from 'vue-i18n'
@@ -168,6 +168,14 @@ const {
const focusedAsset = ref<AssetDisplayItem | null>(null)
// Debounce panel visibility to prevent flicker when switching between assets
// (blur fires before focus when clicking a different card)
const isPanelOpen = refDebounced(
computed(() => !!focusedAsset.value),
16,
{ maxWait: 16 }
)
const primaryCategoryTag = computed(() => {
const assets = fetchedAssets.value ?? []
const tagFromAssets = assets