text customization
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import {motion, frame} from "motion-v";
|
||||
|
||||
const {
|
||||
name,
|
||||
img = undefined,
|
||||
@@ -9,6 +10,8 @@ const {
|
||||
scaleFactor = 2,
|
||||
initialWidth = undefined,
|
||||
initialHeight = undefined,
|
||||
topTextOffset = undefined,
|
||||
bottomTextOffset = undefined,
|
||||
} = defineProps<{
|
||||
name: string,
|
||||
img?: string,
|
||||
@@ -18,12 +21,18 @@ const {
|
||||
scaleFactor?: number,
|
||||
initialWidth?: string,
|
||||
initialHeight?: string,
|
||||
topTextOffset?: string,
|
||||
bottomTextOffset?: string,
|
||||
}>()
|
||||
|
||||
const emit = defineEmits(['positionChanged'])
|
||||
|
||||
const isHoveringParent = ref(false)
|
||||
const roundedDivClass = `rounded-full w-full h-full absolute ${color}`
|
||||
|
||||
const imageMaskClass = `avatar mask mask-squircle ${initialWidth ? initialWidth : 'w-30'} ${initialHeight ? initialHeight : 'h-30'}`
|
||||
const roundedDivClass = `rounded-full absolute ${color} ${initialWidth ? initialWidth : 'w-30'} ${initialHeight ? initialHeight : 'h-30'}`
|
||||
const topTextClass = `absolute w-full text-center ${topTextOffset ? topTextOffset : '-top-30'}`
|
||||
const bottomTextClass = `absolute w-full text-center ${bottomTextOffset ? bottomTextOffset : '-bottom-30'}`
|
||||
|
||||
function getRandomArbitrary(min: number, max: number): number {
|
||||
return Math.random() * (max - min) + min;
|
||||
@@ -42,8 +51,8 @@ const handlePointerMove = ({clientX, clientY}: { clientX: number; clientY: numbe
|
||||
const element = elementRef.value?.$el
|
||||
if (!element) return
|
||||
frame.read(() => {
|
||||
xPoint.set((clientX - element.offsetLeft - element.offsetWidth / 2)/moveFactorValue)
|
||||
yPoint.set((clientY - element.offsetTop - element.offsetHeight / 2)/moveFactorValue)
|
||||
xPoint.set((clientX - element.offsetLeft - element.offsetWidth / 2) / moveFactorValue)
|
||||
yPoint.set((clientY - element.offsetTop - element.offsetHeight / 2) / moveFactorValue)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -53,8 +62,8 @@ useRafFn(() => {
|
||||
return
|
||||
emit(
|
||||
'positionChanged',
|
||||
x.get() + element.offsetLeft + element.offsetWidth/2,
|
||||
y.get() + element.offsetTop + element.offsetHeight/2,)
|
||||
x.get() + element.offsetLeft + element.offsetWidth / 2,
|
||||
y.get() + element.offsetTop + element.offsetHeight / 2,)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
@@ -65,43 +74,50 @@ onUnmounted(() => {
|
||||
window.removeEventListener("pointermove", handlePointerMove)
|
||||
})
|
||||
|
||||
const baseElementClass = ref(`${initialWidth ? initialWidth : 'w-30'} ${initialHeight ? initialHeight : 'h-30'} avatar absolute`)
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<motion.div
|
||||
ref="elementRef"
|
||||
:class="baseElementClass"
|
||||
:style="{ x, y }"
|
||||
:while-hover="{ scale: scaleFactor }"
|
||||
@hover-start="event => {isHoveringParent=true}"
|
||||
@hover-end="event => {isHoveringParent=false}">
|
||||
class="w-60 h-24 absolute flex items-center justify-center"
|
||||
:style="{ x, y }">
|
||||
|
||||
<div v-if="img !== undefined" class="mask mask-squircle w-full">
|
||||
<motion.div
|
||||
v-if="img !== undefined"
|
||||
:class="imageMaskClass"
|
||||
:while-hover="{ scale: scaleFactor }"
|
||||
@hover-start="event => {isHoveringParent=true}"
|
||||
@hover-end="event => {isHoveringParent=false}">
|
||||
<NuxtImg :src="img"/>
|
||||
</div>
|
||||
<div v-else :class="roundedDivClass"/>
|
||||
|
||||
<motion.p
|
||||
v-if="textTop"
|
||||
v-show="isHoveringParent"
|
||||
class="-top-8 absolute text-xs"
|
||||
:initial="{ opacity: 0 }"
|
||||
:animate="{ opacity: 1 }"
|
||||
:exit="{ opacity: 0 }">
|
||||
{{ name }}
|
||||
</motion.p>
|
||||
|
||||
<motion.p
|
||||
</motion.div>
|
||||
<motion.div
|
||||
v-else
|
||||
v-show="isHoveringParent"
|
||||
class="-bottom-8 absolute text-xs"
|
||||
:initial="{ opacity: 0 }"
|
||||
:animate="{ opacity: 1 }"
|
||||
:exit="{ opacity: 0 }">
|
||||
{{ name }}
|
||||
</motion.p>
|
||||
:class="roundedDivClass"
|
||||
:while-hover="{ scale: scaleFactor }"
|
||||
@hover-start="event => {isHoveringParent=true}"
|
||||
@hover-end="event => {isHoveringParent=false}"/>
|
||||
|
||||
<AnimatePresence>
|
||||
<motion.p
|
||||
v-if="textTop"
|
||||
v-show="isHoveringParent"
|
||||
:class="topTextClass"
|
||||
:initial="{ opacity: 0, scale: 0 }"
|
||||
:animate="{ opacity: 1, scale: 1 }"
|
||||
:exit="{ opacity: 0, scale: 0 }">
|
||||
{{ name }}
|
||||
</motion.p>
|
||||
|
||||
<motion.p
|
||||
v-else
|
||||
v-show="isHoveringParent"
|
||||
:class="bottomTextClass"
|
||||
:initial="{ opacity: 0, scale: 0 }"
|
||||
:animate="{ opacity: 1, scale: 1 }"
|
||||
:exit="{ opacity: 0, scale: 0 }">
|
||||
{{ name }}
|
||||
</motion.p>
|
||||
</AnimatePresence>
|
||||
</motion.div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -6,8 +6,12 @@ const nodes = [
|
||||
img: "/face.jpg",
|
||||
textTop: true,
|
||||
moveFactor: 6,
|
||||
initialWidth: 'w-50',
|
||||
initialHeight: 'h-50',
|
||||
scaleFactor: 2,
|
||||
hOffset: 'left-1/3',
|
||||
vOffset: 'top-1/3',
|
||||
topTextOffset: '-top-50',
|
||||
},
|
||||
{
|
||||
name: "DevOps engineer",
|
||||
@@ -17,6 +21,7 @@ const nodes = [
|
||||
initialWidth: 'w-2',
|
||||
initialHeight: 'h-2',
|
||||
scaleFactor: 10,
|
||||
bottomTextOffset: '-bottom-10'
|
||||
},
|
||||
{
|
||||
name: "Game developer",
|
||||
@@ -98,6 +103,8 @@ useRafFn(() => {
|
||||
:scale-factor="node.scaleFactor"
|
||||
:initial-width="node.initialWidth"
|
||||
:initial-height="node.initialHeight"
|
||||
:top-text-offset="node.topTextOffset"
|
||||
:bottom-text-offset="node.bottomTextOffset"
|
||||
@position-changed="(x, y) => { nodeMoved(index, x, y) }"/>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
Reference in New Issue
Block a user