mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-03-07 14:39:30 -07:00
fix ChromaGrid errors
This commit is contained in:
@@ -5,7 +5,7 @@ export const chromaGrid: CodeObject = {
|
|||||||
cli: `npx jsrepo add https://vue-bits.dev/ui/Components/ChromaGrid`,
|
cli: `npx jsrepo add https://vue-bits.dev/ui/Components/ChromaGrid`,
|
||||||
installation: `npm install gsap`,
|
installation: `npm install gsap`,
|
||||||
usage: `<template>
|
usage: `<template>
|
||||||
<div style="height: 600px; position: relative">
|
<div class="w-[600px] relative">
|
||||||
<ChromaGrid
|
<ChromaGrid
|
||||||
:items="items"
|
:items="items"
|
||||||
:radius="300"
|
:radius="300"
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted, computed } from 'vue'
|
import { ref, onMounted, computed } from 'vue';
|
||||||
import gsap from 'gsap'
|
import gsap from 'gsap';
|
||||||
|
|
||||||
interface CardItem {
|
interface CardItem {
|
||||||
image: string
|
image: string;
|
||||||
title: string
|
title: string;
|
||||||
subtitle: string
|
subtitle: string;
|
||||||
handle?: string
|
handle?: string;
|
||||||
borderColor?: string
|
borderColor?: string;
|
||||||
gradient?: string
|
gradient?: string;
|
||||||
url?: string
|
url?: string;
|
||||||
location?: string
|
location?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GridMotionProps {
|
interface GridMotionProps {
|
||||||
items?: CardItem[]
|
items?: CardItem[];
|
||||||
className?: string
|
className?: string;
|
||||||
radius?: number
|
radius?: number;
|
||||||
damping?: number
|
damping?: number;
|
||||||
fadeOut?: number
|
fadeOut?: number;
|
||||||
ease?: string
|
ease?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<GridMotionProps>(), {
|
const props = withDefaults(defineProps<GridMotionProps>(), {
|
||||||
@@ -28,85 +28,85 @@ const props = withDefaults(defineProps<GridMotionProps>(), {
|
|||||||
radius: 300,
|
radius: 300,
|
||||||
damping: 0.45,
|
damping: 0.45,
|
||||||
fadeOut: 0.6,
|
fadeOut: 0.6,
|
||||||
ease: 'power3.out',
|
ease: 'power3.out'
|
||||||
})
|
});
|
||||||
|
|
||||||
const rootRef = ref<HTMLElement | null>(null)
|
const rootRef = ref<HTMLElement | null>(null);
|
||||||
const fadeRef = ref<HTMLElement | null>(null)
|
const fadeRef = ref<HTMLElement | null>(null);
|
||||||
const setX = ref<any>(null)
|
const setX = ref<((value: number | string) => void) | null>(null);
|
||||||
const setY = ref<any>(null)
|
const setY = ref<((value: number | string) => void) | null>(null);
|
||||||
const pos = ref({ x: 0, y: 0 })
|
const pos = ref({ x: 0, y: 0 });
|
||||||
|
|
||||||
const demo: CardItem[] = [
|
const demo: CardItem[] = [
|
||||||
{
|
{
|
||||||
image: "https://i.pravatar.cc/300?img=8",
|
image: 'https://i.pravatar.cc/300?img=8',
|
||||||
title: "Alex Rivera",
|
title: 'Alex Rivera',
|
||||||
subtitle: "Full Stack Developer",
|
subtitle: 'Full Stack Developer',
|
||||||
handle: "@alexrivera",
|
handle: '@alexrivera',
|
||||||
borderColor: "#4F46E5",
|
borderColor: '#4F46E5',
|
||||||
gradient: "linear-gradient(145deg,#4F46E5,#000)",
|
gradient: 'linear-gradient(145deg,#4F46E5,#000)',
|
||||||
url: "https://github.com/",
|
url: 'https://github.com/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: "https://i.pravatar.cc/300?img=11",
|
image: 'https://i.pravatar.cc/300?img=11',
|
||||||
title: "Jordan Chen",
|
title: 'Jordan Chen',
|
||||||
subtitle: "DevOps Engineer",
|
subtitle: 'DevOps Engineer',
|
||||||
handle: "@jordanchen",
|
handle: '@jordanchen',
|
||||||
borderColor: "#10B981",
|
borderColor: '#10B981',
|
||||||
gradient: "linear-gradient(210deg,#10B981,#000)",
|
gradient: 'linear-gradient(210deg,#10B981,#000)',
|
||||||
url: "https://linkedin.com/in/",
|
url: 'https://linkedin.com/in/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: "https://i.pravatar.cc/300?img=3",
|
image: 'https://i.pravatar.cc/300?img=3',
|
||||||
title: "Morgan Blake",
|
title: 'Morgan Blake',
|
||||||
subtitle: "UI/UX Designer",
|
subtitle: 'UI/UX Designer',
|
||||||
handle: "@morganblake",
|
handle: '@morganblake',
|
||||||
borderColor: "#F59E0B",
|
borderColor: '#F59E0B',
|
||||||
gradient: "linear-gradient(165deg,#F59E0B,#000)",
|
gradient: 'linear-gradient(165deg,#F59E0B,#000)',
|
||||||
url: "https://dribbble.com/",
|
url: 'https://dribbble.com/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: "https://i.pravatar.cc/300?img=16",
|
image: 'https://i.pravatar.cc/300?img=16',
|
||||||
title: "Casey Park",
|
title: 'Casey Park',
|
||||||
subtitle: "Data Scientist",
|
subtitle: 'Data Scientist',
|
||||||
handle: "@caseypark",
|
handle: '@caseypark',
|
||||||
borderColor: "#EF4444",
|
borderColor: '#EF4444',
|
||||||
gradient: "linear-gradient(195deg,#EF4444,#000)",
|
gradient: 'linear-gradient(195deg,#EF4444,#000)',
|
||||||
url: "https://kaggle.com/",
|
url: 'https://kaggle.com/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: "https://i.pravatar.cc/300?img=25",
|
image: 'https://i.pravatar.cc/300?img=25',
|
||||||
title: "Sam Kim",
|
title: 'Sam Kim',
|
||||||
subtitle: "Mobile Developer",
|
subtitle: 'Mobile Developer',
|
||||||
handle: "@thesamkim",
|
handle: '@thesamkim',
|
||||||
borderColor: "#8B5CF6",
|
borderColor: '#8B5CF6',
|
||||||
gradient: "linear-gradient(225deg,#8B5CF6,#000)",
|
gradient: 'linear-gradient(225deg,#8B5CF6,#000)',
|
||||||
url: "https://github.com/",
|
url: 'https://github.com/'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
image: "https://i.pravatar.cc/300?img=60",
|
image: 'https://i.pravatar.cc/300?img=60',
|
||||||
title: "Tyler Rodriguez",
|
title: 'Tyler Rodriguez',
|
||||||
subtitle: "Cloud Architect",
|
subtitle: 'Cloud Architect',
|
||||||
handle: "@tylerrod",
|
handle: '@tylerrod',
|
||||||
borderColor: "#06B6D4",
|
borderColor: '#06B6D4',
|
||||||
gradient: "linear-gradient(135deg,#06B6D4,#000)",
|
gradient: 'linear-gradient(135deg,#06B6D4,#000)',
|
||||||
url: "https://aws.amazon.com/",
|
url: 'https://aws.amazon.com/'
|
||||||
},
|
}
|
||||||
]
|
];
|
||||||
|
|
||||||
const data = computed(() => (props.items.length ? props.items : demo))
|
const data = computed(() => (props.items.length ? props.items : demo));
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
const el = rootRef.value
|
const el = rootRef.value;
|
||||||
if (!el) return
|
if (!el) return;
|
||||||
|
|
||||||
setX.value = gsap.quickSetter(el, '--x', 'px')
|
setX.value = gsap.quickSetter(el, '--x', 'px') as (value: number | string) => void;
|
||||||
setY.value = gsap.quickSetter(el, '--y', 'px')
|
setY.value = gsap.quickSetter(el, '--y', 'px') as (value: number | string) => void;
|
||||||
const { width, height } = el.getBoundingClientRect()
|
const { width, height } = el.getBoundingClientRect();
|
||||||
pos.value = { x: width / 2, y: height / 2 }
|
pos.value = { x: width / 2, y: height / 2 };
|
||||||
setX.value(pos.value.x)
|
setX.value?.(pos.value.x);
|
||||||
setY.value(pos.value.y)
|
setY.value?.(pos.value.y);
|
||||||
})
|
});
|
||||||
|
|
||||||
const moveTo = (x: number, y: number) => {
|
const moveTo = (x: number, y: number) => {
|
||||||
gsap.to(pos.value, {
|
gsap.to(pos.value, {
|
||||||
@@ -115,38 +115,38 @@ const moveTo = (x: number, y: number) => {
|
|||||||
duration: props.damping,
|
duration: props.damping,
|
||||||
ease: props.ease,
|
ease: props.ease,
|
||||||
onUpdate: () => {
|
onUpdate: () => {
|
||||||
setX.value?.(pos.value.x)
|
setX.value?.(pos.value.x);
|
||||||
setY.value?.(pos.value.y)
|
setY.value?.(pos.value.y);
|
||||||
},
|
},
|
||||||
overwrite: true,
|
overwrite: true
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleMove = (e: PointerEvent) => {
|
const handleMove = (e: PointerEvent) => {
|
||||||
const r = rootRef.value?.getBoundingClientRect()
|
const r = rootRef.value?.getBoundingClientRect();
|
||||||
if (!r) return
|
if (!r) return;
|
||||||
moveTo(e.clientX - r.left, e.clientY - r.top)
|
moveTo(e.clientX - r.left, e.clientY - r.top);
|
||||||
gsap.to(fadeRef.value, { opacity: 0, duration: 0.25, overwrite: true })
|
gsap.to(fadeRef.value, { opacity: 0, duration: 0.25, overwrite: true });
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleLeave = () => {
|
const handleLeave = () => {
|
||||||
gsap.to(fadeRef.value, {
|
gsap.to(fadeRef.value, {
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
duration: props.fadeOut,
|
duration: props.fadeOut,
|
||||||
overwrite: true,
|
overwrite: true
|
||||||
})
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleCardClick = (url?: string) => {
|
const handleCardClick = (url?: string) => {
|
||||||
if (url) window.open(url, "_blank", "noopener,noreferrer")
|
if (url) window.open(url, '_blank', 'noopener,noreferrer');
|
||||||
}
|
};
|
||||||
|
|
||||||
const handleCardMove = (e: MouseEvent) => {
|
const handleCardMove = (e: MouseEvent) => {
|
||||||
const c = e.currentTarget as HTMLElement
|
const c = e.currentTarget as HTMLElement;
|
||||||
const rect = c.getBoundingClientRect()
|
const rect = c.getBoundingClientRect();
|
||||||
c.style.setProperty('--mouse-x', `${e.clientX - rect.left}px`)
|
c.style.setProperty('--mouse-x', `${e.clientX - rect.left}px`);
|
||||||
c.style.setProperty('--mouse-y', `${e.clientY - rect.top}px`)
|
c.style.setProperty('--mouse-y', `${e.clientY - rect.top}px`);
|
||||||
}
|
};
|
||||||
|
|
||||||
const spotlightStyle = {
|
const spotlightStyle = {
|
||||||
backdropFilter: 'grayscale(1) brightness(0.78)',
|
backdropFilter: 'grayscale(1) brightness(0.78)',
|
||||||
@@ -155,8 +155,8 @@ const spotlightStyle = {
|
|||||||
maskImage:
|
maskImage:
|
||||||
'radial-gradient(circle var(--r) at var(--x) var(--y),transparent 0%,transparent 15%,rgba(0,0,0,0.10) 30%,rgba(0,0,0,0.22)45%,rgba(0,0,0,0.35)60%,rgba(0,0,0,0.50)75%,rgba(0,0,0,0.68)88%,white 100%)',
|
'radial-gradient(circle var(--r) at var(--x) var(--y),transparent 0%,transparent 15%,rgba(0,0,0,0.10) 30%,rgba(0,0,0,0.22)45%,rgba(0,0,0,0.35)60%,rgba(0,0,0,0.50)75%,rgba(0,0,0,0.68)88%,white 100%)',
|
||||||
WebkitMaskImage:
|
WebkitMaskImage:
|
||||||
'radial-gradient(circle var(--r) at var(--x) var(--y),transparent 0%,transparent 15%,rgba(0,0,0,0.10) 30%,rgba(0,0,0,0.22)45%,rgba(0,0,0,0.35)60%,rgba(0,0,0,0.50)75%,rgba(0,0,0,0.68)88%,white 100%)',
|
'radial-gradient(circle var(--r) at var(--x) var(--y),transparent 0%,transparent 15%,rgba(0,0,0,0.10) 30%,rgba(0,0,0,0.22)45%,rgba(0,0,0,0.35)60%,rgba(0,0,0,0.50)75%,rgba(0,0,0,0.68)88%,white 100%)'
|
||||||
}
|
};
|
||||||
|
|
||||||
const fadeStyle = {
|
const fadeStyle = {
|
||||||
...spotlightStyle,
|
...spotlightStyle,
|
||||||
@@ -164,8 +164,8 @@ const fadeStyle = {
|
|||||||
'radial-gradient(circle var(--r) at var(--x) var(--y),white 0%,white 15%,rgba(255,255,255,0.90)30%,rgba(255,255,255,0.78)45%,rgba(255,255,255,0.65)60%,rgba(255,255,255,0.50)75%,rgba(255,255,255,0.32)88%,transparent 100%)',
|
'radial-gradient(circle var(--r) at var(--x) var(--y),white 0%,white 15%,rgba(255,255,255,0.90)30%,rgba(255,255,255,0.78)45%,rgba(255,255,255,0.65)60%,rgba(255,255,255,0.50)75%,rgba(255,255,255,0.32)88%,transparent 100%)',
|
||||||
WebkitMaskImage:
|
WebkitMaskImage:
|
||||||
'radial-gradient(circle var(--r) at var(--x) var(--y),white 0%,white 15%,rgba(255,255,255,0.90)30%,rgba(255,255,255,0.78)45%,rgba(255,255,255,0.65)60%,rgba(255,255,255,0.50)75%,rgba(255,255,255,0.32)88%,transparent 100%)',
|
'radial-gradient(circle var(--r) at var(--x) var(--y),white 0%,white 15%,rgba(255,255,255,0.90)30%,rgba(255,255,255,0.78)45%,rgba(255,255,255,0.65)60%,rgba(255,255,255,0.50)75%,rgba(255,255,255,0.32)88%,transparent 100%)',
|
||||||
opacity: 1,
|
opacity: 1
|
||||||
}
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -175,7 +175,7 @@ const fadeStyle = {
|
|||||||
:style="{
|
:style="{
|
||||||
'--r': `${props.radius}px`,
|
'--r': `${props.radius}px`,
|
||||||
'--x': '50%',
|
'--x': '50%',
|
||||||
'--y': '50%',
|
'--y': '50%'
|
||||||
}"
|
}"
|
||||||
@pointermove="handleMove"
|
@pointermove="handleMove"
|
||||||
@pointerleave="handleLeave"
|
@pointerleave="handleLeave"
|
||||||
@@ -187,7 +187,7 @@ const fadeStyle = {
|
|||||||
:style="{
|
:style="{
|
||||||
'--card-border': c.borderColor || 'transparent',
|
'--card-border': c.borderColor || 'transparent',
|
||||||
background: c.gradient,
|
background: c.gradient,
|
||||||
'--spotlight-color': 'rgba(255,255,255,0.3)',
|
'--spotlight-color': 'rgba(255,255,255,0.3)'
|
||||||
}"
|
}"
|
||||||
@mousemove="handleCardMove"
|
@mousemove="handleCardMove"
|
||||||
@click="() => handleCardClick(c.url)"
|
@click="() => handleCardClick(c.url)"
|
||||||
@@ -195,16 +195,12 @@ const fadeStyle = {
|
|||||||
<div
|
<div
|
||||||
class="absolute inset-0 pointer-events-none transition-opacity duration-500 z-20 opacity-0 group-hover:opacity-100"
|
class="absolute inset-0 pointer-events-none transition-opacity duration-500 z-20 opacity-0 group-hover:opacity-100"
|
||||||
:style="{
|
:style="{
|
||||||
background: 'radial-gradient(circle at var(--mouse-x) var(--mouse-y), var(--spotlight-color), transparent 70%)',
|
background:
|
||||||
|
'radial-gradient(circle at var(--mouse-x) var(--mouse-y), var(--spotlight-color), transparent 70%)'
|
||||||
}"
|
}"
|
||||||
/>
|
/>
|
||||||
<div class="relative z-10 flex-1 p-[10px] box-border">
|
<div class="relative z-10 flex-1 p-[10px] box-border">
|
||||||
<img
|
<img :src="c.image" :alt="c.title" loading="lazy" class="w-full h-full object-cover rounded-[10px]" />
|
||||||
:src="c.image"
|
|
||||||
:alt="c.title"
|
|
||||||
loading="lazy"
|
|
||||||
class="w-full h-full object-cover rounded-[10px]"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
<footer class="relative z-10 p-3 text-white font-sans grid grid-cols-[1fr_auto] gap-x-3 gap-y-1">
|
<footer class="relative z-10 p-3 text-white font-sans grid grid-cols-[1fr_auto] gap-x-3 gap-y-1">
|
||||||
<h3 class="m-0 text-[1.05rem] font-semibold">{{ c.title }}</h3>
|
<h3 class="m-0 text-[1.05rem] font-semibold">{{ c.title }}</h3>
|
||||||
@@ -222,4 +218,3 @@ const fadeStyle = {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -19,55 +19,54 @@
|
|||||||
</TabbedLayout>
|
</TabbedLayout>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup lang="ts">
|
||||||
import CliInstallation from '../../components/code/CliInstallation.vue';
|
import CliInstallation from '../../components/code/CliInstallation.vue';
|
||||||
import CodeExample from '../../components/code/CodeExample.vue';
|
import CodeExample from '../../components/code/CodeExample.vue';
|
||||||
import Dependencies from '../../components/code/Dependencies.vue';
|
import Dependencies from '../../components/code/Dependencies.vue';
|
||||||
import PropTable from '../../components/common/PropTable.vue';
|
import PropTable from '../../components/common/PropTable.vue';
|
||||||
import TabbedLayout from '../../components/common/TabbedLayout.vue';
|
import TabbedLayout from '../../components/common/TabbedLayout.vue';
|
||||||
|
|
||||||
|
import { chromaGrid } from '../../constants/code/Components/chromaGridCode';
|
||||||
import { chromaGrid } from '../../constants/code/Components/chromaGridCode'
|
import ChromaGrid from '../../content/Components/ChromaGrid/ChromaGrid.vue';
|
||||||
import ChromaGrid from '../../content/Components/ChromaGrid/ChromaGrid.vue'
|
|
||||||
|
|
||||||
const propData = [
|
const propData = [
|
||||||
{
|
{
|
||||||
name: 'items',
|
name: 'items',
|
||||||
type: 'Array',
|
type: 'Array',
|
||||||
default: 'Demo []',
|
default: 'Demo []',
|
||||||
description: 'Array of ChromaItem objects to display in the grid',
|
description: 'Array of ChromaItem objects to display in the grid'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'className',
|
name: 'className',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: "''",
|
default: "''",
|
||||||
description: 'Additional CSS classes to apply to the grid container',
|
description: 'Additional CSS classes to apply to the grid container'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'radius',
|
name: 'radius',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
default: '300',
|
default: '300',
|
||||||
description: 'Size of the spotlight effect in pixels',
|
description: 'Size of the spotlight effect in pixels'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'damping',
|
name: 'damping',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
default: '0.45',
|
default: '0.45',
|
||||||
description: 'Cursor follow animation duration in seconds',
|
description: 'Cursor follow animation duration in seconds'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'fadeOut',
|
name: 'fadeOut',
|
||||||
type: 'number',
|
type: 'number',
|
||||||
default: '0.6',
|
default: '0.6',
|
||||||
description: 'Fade-out animation duration in seconds when mouse leaves',
|
description: 'Fade-out animation duration in seconds when mouse leaves'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'ease',
|
name: 'ease',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: "'power3.out'",
|
default: "'power3.out'",
|
||||||
description: 'GSAP easing function for animations',
|
description: 'GSAP easing function for animations'
|
||||||
},
|
}
|
||||||
]
|
];
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
Reference in New Issue
Block a user