feat: add transitions and micro-interactions across all views
- Page transitions with slide-up/fade on route changes (App.vue) - NavRail sliding active indicator with spring-like easing - List enter/leave/move animations on Entries, Projects, Clients, Timer - Modal enter/leave transitions with scale+fade on all dialogs - Dropdown transitions with overshoot on all select/picker components - Button feedback (scale on hover/active), card hover lift effects - Timer pulse on start, glow on stop, floating empty state icons - Content fade-in on Dashboard, Reports, Calendar, Timesheet - Tag chip enter/leave animations in AppTagInput - Progress bar smooth width transitions - Implementation plan document
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { ref, computed, onMounted, onBeforeUnmount, nextTick } from 'vue'
|
||||
import { ChevronDown, Check } from 'lucide-vue-next'
|
||||
import { computeDropdownPosition } from '../utils/dropdown'
|
||||
|
||||
interface Props {
|
||||
modelValue: any
|
||||
@@ -77,25 +78,9 @@ function isSelected(item: any): boolean {
|
||||
return val === props.modelValue
|
||||
}
|
||||
|
||||
function getZoomFactor(): number {
|
||||
const app = document.getElementById('app')
|
||||
if (!app) return 1
|
||||
const zoom = (app.style as any).zoom
|
||||
return zoom ? parseFloat(zoom) / 100 : 1
|
||||
}
|
||||
|
||||
function updatePosition() {
|
||||
if (!triggerRef.value) return
|
||||
const rect = triggerRef.value.getBoundingClientRect()
|
||||
const zoom = getZoomFactor()
|
||||
panelStyle.value = {
|
||||
position: 'fixed',
|
||||
top: `${(rect.bottom + 4) / zoom}px`,
|
||||
left: `${rect.left / zoom}px`,
|
||||
width: `${rect.width / zoom}px`,
|
||||
zIndex: '9999',
|
||||
zoom: `${zoom * 100}%`,
|
||||
}
|
||||
panelStyle.value = computeDropdownPosition(triggerRef.value, { estimatedHeight: 280 })
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
@@ -268,11 +253,12 @@ onBeforeUnmount(() => {
|
||||
|
||||
<!-- Dropdown panel -->
|
||||
<Teleport to="body">
|
||||
<Transition name="dropdown">
|
||||
<div
|
||||
v-if="isOpen"
|
||||
ref="panelRef"
|
||||
:style="panelStyle"
|
||||
class="bg-bg-surface border border-border-visible rounded-xl shadow-[0_4px_24px_rgba(0,0,0,0.4)] overflow-hidden animate-dropdown-enter"
|
||||
class="bg-bg-surface border border-border-visible rounded-xl shadow-[0_4px_24px_rgba(0,0,0,0.4)] overflow-hidden"
|
||||
>
|
||||
<div v-if="searchable" class="px-2 pt-2 pb-1">
|
||||
<input
|
||||
@@ -307,6 +293,7 @@ onBeforeUnmount(() => {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</Teleport>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user