Magnified Dock
Recreation of the magnification effect from the Mac OS dock, inspired by Build UI.
Althought Vue doesn't have the popular framer-motion library, but we by leveraging vueuse, and vueuse/motion, we can achieve the same effect just as well.
We need to create 2 component,
First, a Dock
component that would hold all the AppIcon.
Dock.vue
<script setup lang="ts">
import AppIcon from './AppIcon.vue'
const mouseX = ref(Infinity)
</script>
<template>
<div
class=" flex h-16 items-end gap-4 rounded-2xl bg-white bg-opacity-20 backdrop-blur-md px-4 pb-3"
@mousemove="mouseX = $event.pageX"
@mouseleave="mouseX = Infinity"
>
<AppIcon v-for="i in 8" :key="i" :mouse-x="mouseX" />
</div>
</template>
Secondly, we will create the AppIcon
that will react to the mouseX position and adjust the size.
AppIcon.vue
<script setup lang="ts">
import { useMotionProperties, useMotionTransitions } from '@vueuse/motion'
const props = defineProps<{
mouseX: number
}>()
const { mouseX } = toRefs(props)
const target = ref<HTMLElement>()
const { motionProperties } = useMotionProperties(target, { width: 40 })
const { push } = useMotionTransitions()
// relative distance of target element to mouseX
const distance = computed(() => {
const bounds = target.value?.getBoundingClientRect() ?? { x: 0, width: 0 }
const val = Math.abs(mouseX.value - bounds.x - bounds.width / 2)
return val > 150 ? 150 : val
})
const widthSync = useProjection(distance, [0, 150], [100, 40])
watch(widthSync, () => {
push('width', widthSync.value, motionProperties, { type: 'spring', mass: 0.1, stiffness: 150, damping: 12 })
})
</script>
<template>
<div ref="target" class="aspect-square w-10 rounded-full bg-white" />
</template>