feat(calendar): seamless zoom animation with clone-and-swap + full-area coverage
Zoom-in: fade siblings → fade source content → clone source style to fly-rect → hide source → animate fly-rect to viewport → switch view → fade in new content. Zoom-out: fade scene → show fly-rect at viewport → switch view → clone target style → animate fly-rect to target → fade in scene. Full-area: all views (month/week/day) now fill 100% of container height. Month grid rows stretch equally, day cells fill row height, depth layers flex. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -180,7 +180,7 @@ defineProps<{
|
||||
>
|
||||
<div
|
||||
class="grid grid-cols-1 gap-2 sm:grid-cols-2 xl:grid-cols-3 auto-rows-fr"
|
||||
:style="calendarView === 'year' && calendarViewportHeight > 0 ? { minHeight: `${Math.max(420, calendarViewportHeight)}px` } : undefined"
|
||||
:style="calendarViewportHeight > 0 ? { minHeight: `${calendarView === 'year' ? Math.max(420, calendarViewportHeight) : calendarViewportHeight}px` } : undefined"
|
||||
>
|
||||
<article
|
||||
v-for="item in yearMonths"
|
||||
@@ -190,14 +190,14 @@ defineProps<{
|
||||
:class="[
|
||||
calendarView === 'year'
|
||||
? 'h-full hover:border-primary/50 hover:bg-primary/5 cursor-zoom-in'
|
||||
: 'cursor-default min-h-[26rem] bg-base-100 sm:col-span-2 xl:col-span-3',
|
||||
: 'cursor-default bg-base-100 sm:col-span-2 xl:col-span-3 flex flex-col',
|
||||
calendarHoveredMonthIndex === item.monthIndex ? 'calendar-hover-target' : '',
|
||||
calendarZoomPrimeToken === calendarPrimeMonthToken(item.monthIndex) ? 'calendar-zoom-prime-active' : '',
|
||||
]"
|
||||
:style="{
|
||||
...calendarPrimeStyle(calendarPrimeMonthToken(item.monthIndex)),
|
||||
...(calendarView !== 'year' && item.monthIndex === calendarCursorMonth && calendarViewportHeight > 0
|
||||
? { minHeight: `${Math.max(420, calendarViewportHeight)}px` }
|
||||
? { minHeight: `${calendarViewportHeight}px` }
|
||||
: {}),
|
||||
}"
|
||||
:data-calendar-month-index="item.monthIndex"
|
||||
@@ -230,11 +230,11 @@ defineProps<{
|
||||
<span>Sat</span>
|
||||
</div>
|
||||
|
||||
<div class="space-y-1">
|
||||
<div class="flex flex-1 flex-col gap-1">
|
||||
<div
|
||||
v-for="row in monthRows"
|
||||
:key="row.key"
|
||||
class="group relative calendar-hover-targetable"
|
||||
class="group relative flex-1 calendar-hover-targetable"
|
||||
:class="[
|
||||
calendarHoveredWeekStartKey === row.startKey ? 'calendar-hover-target' : '',
|
||||
calendarZoomPrimeToken === calendarPrimeWeekToken(row.startKey) ? 'calendar-zoom-prime-active' : '',
|
||||
@@ -243,11 +243,11 @@ defineProps<{
|
||||
:data-calendar-week-start-key="row.startKey"
|
||||
@mouseenter="setCalendarHoveredWeekStartKey(row.startKey)"
|
||||
>
|
||||
<div class="grid grid-cols-7 gap-1">
|
||||
<div class="grid grid-cols-7 gap-1 h-full">
|
||||
<button
|
||||
v-for="cell in row.cells"
|
||||
:key="cell.key"
|
||||
class="group relative min-h-24 rounded-lg border p-1 text-left"
|
||||
class="group relative rounded-lg border p-1 text-left"
|
||||
:class="[
|
||||
cell.inMonth ? 'border-base-300 bg-base-100' : 'border-base-200 bg-base-200/40 text-base-content/40',
|
||||
selectedDateKey === cell.key ? 'border-primary bg-primary/5' : '',
|
||||
@@ -379,7 +379,10 @@ defineProps<{
|
||||
|
||||
.calendar-depth-stack {
|
||||
position: relative;
|
||||
min-height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex: 1;
|
||||
min-height: 0;
|
||||
}
|
||||
|
||||
.calendar-depth-layer {
|
||||
@@ -392,6 +395,9 @@ defineProps<{
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
pointer-events: auto;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.calendar-depth-layer-hidden {
|
||||
@@ -451,9 +457,6 @@ defineProps<{
|
||||
|
||||
.calendar-fly-rect {
|
||||
position: absolute;
|
||||
border-radius: 12px;
|
||||
border: 2px solid color-mix(in oklab, var(--color-primary) 70%, transparent);
|
||||
background: color-mix(in oklab, var(--color-base-200) 60%, transparent);
|
||||
z-index: 20;
|
||||
pointer-events: none;
|
||||
will-change: left, top, width, height;
|
||||
|
||||
Reference in New Issue
Block a user