Compare commits
2 commits
1ccac024a4
...
e03d91ece9
| Author | SHA1 | Date | |
|---|---|---|---|
| e03d91ece9 | |||
| be3b52f150 |
2 changed files with 27 additions and 7 deletions
|
|
@ -201,7 +201,7 @@ const cardStyle = computed(() => {
|
|||
'transparent'
|
||||
|
||||
return {
|
||||
transform: `translate(${deltaX.value}px, ${deltaY.value}px) scale(0.35)`,
|
||||
transform: `translate(${deltaX.value}px, ${deltaY.value - 80}px) scale(0.55)`,
|
||||
borderRadius: '50%',
|
||||
background: aura,
|
||||
transition: 'border-radius 150ms ease, background 150ms ease',
|
||||
|
|
@ -230,6 +230,7 @@ const cardStyle = computed(() => {
|
|||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: flex-start;
|
||||
overflow: visible; /* ball must escape the collapsed stack bounds */
|
||||
}
|
||||
|
||||
.card-stack.bucket-mode .card-shadow {
|
||||
|
|
@ -269,6 +270,10 @@ const cardStyle = computed(() => {
|
|||
}
|
||||
.card-wrapper.is-held {
|
||||
cursor: grabbing;
|
||||
/* Override bucket-mode clip and opacity so the held ball renders cleanly */
|
||||
clip-path: none !important;
|
||||
opacity: 1 !important;
|
||||
pointer-events: auto !important;
|
||||
}
|
||||
|
||||
/* Dismissal animations — dismiss class is only applied during the motion.rich await window,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="label-view">
|
||||
<!-- Header bar -->
|
||||
<header class="lv-header">
|
||||
<header class="lv-header" :class="{ 'is-held': isHeld }">
|
||||
<span class="queue-count">
|
||||
<span v-if="loading" class="queue-status">Loading…</span>
|
||||
<template v-else-if="store.totalRemaining > 0">
|
||||
|
|
@ -54,7 +54,7 @@
|
|||
>→</div>
|
||||
</Transition>
|
||||
|
||||
<div class="card-stack-wrapper">
|
||||
<div class="card-stack-wrapper" :class="{ 'is-held': isHeld }">
|
||||
<EmailCardStack
|
||||
:item="store.current"
|
||||
:is-bucket-mode="isHeld"
|
||||
|
|
@ -314,7 +314,8 @@ onUnmounted(() => {
|
|||
padding: 1rem;
|
||||
max-width: 640px;
|
||||
margin: 0 auto;
|
||||
min-height: 100dvh;
|
||||
height: 100dvh; /* hard cap — prevents grid from drifting below fold */
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.queue-status {
|
||||
|
|
@ -328,6 +329,11 @@ onUnmounted(() => {
|
|||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
flex-wrap: wrap;
|
||||
transition: opacity 200ms ease;
|
||||
}
|
||||
.lv-header.is-held {
|
||||
opacity: 0.2;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.queue-count {
|
||||
|
|
@ -418,24 +424,33 @@ onUnmounted(() => {
|
|||
|
||||
.card-stack-wrapper {
|
||||
flex: 1;
|
||||
/* Give bottom breathing room so grid doesn't overlap content */
|
||||
min-height: 0; /* allow flex child to shrink — default auto prevents this */
|
||||
overflow-y: auto;
|
||||
padding-bottom: 0.5rem;
|
||||
transition: opacity 200ms ease;
|
||||
}
|
||||
/* When held: escape the overflow clip so the ball floats freely,
|
||||
and rise above the footer (z-index 10) so the ball is visible. */
|
||||
.card-stack-wrapper.is-held {
|
||||
overflow: visible;
|
||||
position: relative;
|
||||
z-index: 20;
|
||||
}
|
||||
|
||||
/* Bucket grid stays pinned to the bottom of the viewport while the email card
|
||||
can be scrolled freely. "hired" (10th button) may clip on very small screens
|
||||
— that is intentional per design. */
|
||||
.bucket-grid-footer {
|
||||
position: sticky;
|
||||
bottom: 0;
|
||||
background: var(--color-bg, var(--color-surface, #f0f4fc));
|
||||
padding: 0.5rem 0 0.75rem;
|
||||
z-index: 10;
|
||||
transition: transform 250ms cubic-bezier(0.34, 1.56, 0.64, 1),
|
||||
opacity 200ms ease,
|
||||
background 200ms ease;
|
||||
}
|
||||
.bucket-grid-footer.grid-active {
|
||||
transform: translateY(-8px);
|
||||
opacity: 0.45; /* semi-transparent so ball aura is visible through it */
|
||||
}
|
||||
|
||||
/* ── Toss edge zones ── */
|
||||
|
|
|
|||
Loading…
Reference in a new issue