This commit is contained in:
David Haz
2025-08-01 23:23:01 +03:00
parent f0db19d5e2
commit 92dce03146
5 changed files with 43 additions and 115 deletions

View File

@@ -1,11 +1,5 @@
<template> <template>
<div <div ref="containerRef" :class="['w-full h-full relative pointer-events-none z-[3] overflow-hidden', className]" />
ref="containerRef"
:class="[
'w-full h-full relative pointer-events-none z-[3] overflow-hidden',
className
]"
/>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -96,18 +90,12 @@ const observerRef = ref<IntersectionObserver | null>(null);
const resizeTimeoutRef = ref<number | null>(null); const resizeTimeoutRef = ref<number | null>(null);
const rgbColor = computed<[number, number, number]>(() => hexToRgb(props.raysColor)); const rgbColor = computed<[number, number, number]>(() => hexToRgb(props.raysColor));
const pulsatingValue = computed<number>(() => props.pulsating ? 1.0 : 0.0); const pulsatingValue = computed<number>(() => (props.pulsating ? 1.0 : 0.0));
const devicePixelRatio = computed<number>(() => Math.min(window.devicePixelRatio || 1, 2)); const devicePixelRatio = computed<number>(() => Math.min(window.devicePixelRatio || 1, 2));
const hexToRgb = (hex: string): [number, number, number] => { const hexToRgb = (hex: string): [number, number, number] => {
const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); const m = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
return m return m ? [parseInt(m[1], 16) / 255, parseInt(m[2], 16) / 255, parseInt(m[3], 16) / 255] : [1, 1, 1];
? [
parseInt(m[1], 16) / 255,
parseInt(m[2], 16) / 255,
parseInt(m[3], 16) / 255,
]
: [1, 1, 1];
}; };
const getAnchorAndDir = (origin: RaysOrigin, w: number, h: number): AnchorAndDirection => { const getAnchorAndDir = (origin: RaysOrigin, w: number, h: number): AnchorAndDirection => {
@@ -288,7 +276,7 @@ const initializeWebGL = async (): Promise<void> => {
mousePos: { value: [0.5, 0.5] }, mousePos: { value: [0.5, 0.5] },
mouseInfluence: { value: props.mouseInfluence }, mouseInfluence: { value: props.mouseInfluence },
noiseAmount: { value: props.noiseAmount }, noiseAmount: { value: props.noiseAmount },
distortion: { value: props.distortion }, distortion: { value: props.distortion }
}; };
uniformsRef.value = uniforms; uniformsRef.value = uniforms;
@@ -296,7 +284,7 @@ const initializeWebGL = async (): Promise<void> => {
const program = new Program(gl, { const program = new Program(gl, {
vertex: vertexShader, vertex: vertexShader,
fragment: fragmentShader, fragment: fragmentShader,
uniforms, uniforms
}); });
const mesh = new Mesh(gl, { geometry, program }); const mesh = new Mesh(gl, { geometry, program });
meshRef.value = mesh; meshRef.value = mesh;
@@ -330,17 +318,10 @@ const initializeWebGL = async (): Promise<void> => {
if (props.followMouse && props.mouseInfluence > 0.0) { if (props.followMouse && props.mouseInfluence > 0.0) {
const smoothing = 0.92; const smoothing = 0.92;
smoothMouseRef.value.x = smoothMouseRef.value.x = smoothMouseRef.value.x * smoothing + mouseRef.value.x * (1 - smoothing);
smoothMouseRef.value.x * smoothing + smoothMouseRef.value.y = smoothMouseRef.value.y * smoothing + mouseRef.value.y * (1 - smoothing);
mouseRef.value.x * (1 - smoothing);
smoothMouseRef.value.y =
smoothMouseRef.value.y * smoothing +
mouseRef.value.y * (1 - smoothing);
uniforms.mousePos.value = [ uniforms.mousePos.value = [smoothMouseRef.value.x, smoothMouseRef.value.y];
smoothMouseRef.value.x,
smoothMouseRef.value.y,
];
} }
try { try {
@@ -376,8 +357,7 @@ const initializeWebGL = async (): Promise<void> => {
if (renderer) { if (renderer) {
try { try {
const canvas = renderer.gl.canvas; const canvas = renderer.gl.canvas;
const loseContextExt = const loseContextExt = renderer.gl.getExtension('WEBGL_lose_context');
renderer.gl.getExtension('WEBGL_lose_context');
if (loseContextExt) { if (loseContextExt) {
loseContextExt.loseContext(); loseContextExt.loseContext();
} }
@@ -460,7 +440,7 @@ watch(
() => props.saturation, () => props.saturation,
() => props.mouseInfluence, () => props.mouseInfluence,
() => props.noiseAmount, () => props.noiseAmount,
() => props.distortion, () => props.distortion
], ],
(): void => { (): void => {
if (!uniformsRef.value || !containerRef.value || !rendererRef.value) return; if (!uniformsRef.value || !containerRef.value || !rendererRef.value) return;

View File

@@ -738,7 +738,13 @@ const setupCardRef = (el: HTMLDivElement | null, index: number) => {
:glow-color="glowColor" :glow-color="glowColor"
/> />
<BentoCardGrid :grid-ref="(el: HTMLDivElement | null) => { gridRef = el; }"> <BentoCardGrid
:grid-ref="
(el: HTMLDivElement | null) => {
gridRef = el;
}
"
>
<div class="gap-2 grid card-responsive"> <div class="gap-2 grid card-responsive">
<template v-for="(card, index) in cardData" :key="index"> <template v-for="(card, index) in cardData" :key="index">
<ParticleCard <ParticleCard

View File

@@ -261,18 +261,15 @@ const handleComplete = () => {
props.onFinalStepCompleted?.(); props.onFinalStepCompleted?.();
}; };
watch( watch(currentStep, (newStep, oldStep) => {
currentStep, props.onStepChange?.(newStep);
(newStep, oldStep) => { if (newStep !== oldStep && !isCompleted.value) {
props.onStepChange?.(newStep); nextTick(measureHeight);
if (newStep !== oldStep && !isCompleted.value) { } else if (!props.lockOnComplete && isCompleted.value) {
nextTick(measureHeight); isCompleted.value = false;
} else if (!props.lockOnComplete && isCompleted.value) { nextTick(measureHeight);
isCompleted.value = false;
nextTick(measureHeight);
}
} }
); });
onMounted(() => { onMounted(() => {
if (props.initialStep !== 1) { if (props.initialStep !== 1) {

View File

@@ -22,80 +22,25 @@
</div> </div>
<Customize> <Customize>
<PreviewColor <PreviewColor title="Rays Color" v-model="raysColor" />
title="Rays Color"
v-model="raysColor"
/>
<PreviewSelect <PreviewSelect title="Rays Origin" v-model="raysOrigin" :options="raysOriginOptions" />
title="Rays Origin"
v-model="raysOrigin"
:options="raysOriginOptions"
/>
<PreviewSlider <PreviewSlider title="Rays Speed" v-model="raysSpeed" :min="0.1" :max="3" :step="0.1" />
title="Rays Speed"
v-model="raysSpeed"
:min="0.1"
:max="3"
:step="0.1"
/>
<PreviewSlider <PreviewSlider title="Light Spread" v-model="lightSpread" :min="0.1" :max="2" :step="0.1" />
title="Light Spread"
v-model="lightSpread"
:min="0.1"
:max="2"
:step="0.1"
/>
<PreviewSlider <PreviewSlider title="Ray Length" v-model="rayLength" :min="0.5" :max="3" :step="0.1" />
title="Ray Length"
v-model="rayLength"
:min="0.5"
:max="3"
:step="0.1"
/>
<PreviewSlider <PreviewSlider title="Fade Distance" v-model="fadeDistance" :min="0.5" :max="2" :step="0.1" />
title="Fade Distance"
v-model="fadeDistance"
:min="0.5"
:max="2"
:step="0.1"
/>
<PreviewSlider <PreviewSlider title="Saturation" v-model="saturation" :min="0" :max="2" :step="0.1" />
title="Saturation"
v-model="saturation"
:min="0"
:max="2"
:step="0.1"
/>
<PreviewSlider <PreviewSlider title="Mouse Influence" v-model="mouseInfluence" :min="0" :max="1" :step="0.1" />
title="Mouse Influence"
v-model="mouseInfluence"
:min="0"
:max="1"
:step="0.1"
/>
<PreviewSlider <PreviewSlider title="Noise Amount" v-model="noiseAmount" :min="0" :max="0.5" :step="0.01" />
title="Noise Amount"
v-model="noiseAmount"
:min="0"
:max="0.5"
:step="0.01"
/>
<PreviewSlider <PreviewSlider title="Distortion" v-model="distortion" :min="0" :max="1" :step="0.1" />
title="Distortion"
v-model="distortion"
:min="0"
:max="1"
:step="0.1"
/>
<PreviewSwitch title="Pulsating" v-model="pulsating" /> <PreviewSwitch title="Pulsating" v-model="pulsating" />
</Customize> </Customize>

View File

@@ -73,7 +73,7 @@
<script setup lang="ts"> <script setup lang="ts">
import { ref } from 'vue'; import { ref } from 'vue';
import { toast, Toaster } from 'vue-sonner'; import { toast, Toaster } from 'vue-sonner';
import 'vue-sonner/style.css' import 'vue-sonner/style.css';
import TabbedLayout from '@/components/common/TabbedLayout.vue'; import TabbedLayout from '@/components/common/TabbedLayout.vue';
import PropTable from '@/components/common/PropTable.vue'; import PropTable from '@/components/common/PropTable.vue';
@@ -115,25 +115,25 @@ const propData = [
{ {
name: 'stepCircleContainerClassName', name: 'stepCircleContainerClassName',
type: 'string', type: 'string',
default: "-", default: '-',
description: 'Custom class name for the container holding the step indicators.' description: 'Custom class name for the container holding the step indicators.'
}, },
{ {
name: 'stepContainerClassName', name: 'stepContainerClassName',
type: 'string', type: 'string',
default: "-", default: '-',
description: 'Custom class name for the row holding the step circles/connectors.' description: 'Custom class name for the row holding the step circles/connectors.'
}, },
{ {
name: 'contentClassName', name: 'contentClassName',
type: 'string', type: 'string',
default: "-", default: '-',
description: "Custom class name for the step's main content container." description: "Custom class name for the step's main content container."
}, },
{ {
name: 'footerClassName', name: 'footerClassName',
type: 'string', type: 'string',
default: "-", default: '-',
description: 'Custom class name for the footer area containing navigation buttons.' description: 'Custom class name for the footer area containing navigation buttons.'
}, },
{ {
@@ -188,12 +188,12 @@ const handleStepChange = (newStep: number) => {
step.value = newStep; step.value = newStep;
if (newStep === 4) { if (newStep === 4) {
if (name.value) { if (name.value) {
toast(`👋🏻 Hello ${name.value}!`) toast(`👋🏻 Hello ${name.value}!`);
} else { } else {
toast(`You didn't provide your name :(`) toast(`You didn't provide your name :(`);
} }
} else { } else {
toast(`✅ Step ${newStep}!`) toast(`✅ Step ${newStep}!`);
} }
}; };
</script> </script>