mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-04-22 01:54:38 -06:00
Merge branch 'main' into feat/grid-scan
This commit is contained in:
@@ -0,0 +1,230 @@
|
||||
<template>
|
||||
<TabbedLayout>
|
||||
<template #preview>
|
||||
<div class="demo-container h-[600px] overflow-hidden p-0">
|
||||
<Antigravity
|
||||
:key="componentKey"
|
||||
:count="count"
|
||||
:magnetRadius="magnetRadius"
|
||||
:ringRadius="ringRadius"
|
||||
:waveSpeed="waveSpeed"
|
||||
:waveAmplitude="waveAmplitude"
|
||||
:particleSize="particleSize"
|
||||
:lerpSpeed="lerpSpeed"
|
||||
:color="color"
|
||||
:autoAnimate="autoAnimate"
|
||||
:particleVariance="particleVariance"
|
||||
:rotationSpeed="rotationSpeed"
|
||||
:depthFactor="depthFactor"
|
||||
:pulseSpeed="pulseSpeed"
|
||||
:particleShape="particleShape"
|
||||
:fieldStrength="fieldStrength"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Customize>
|
||||
<PreviewColor title="Color" v-model="color" />
|
||||
|
||||
<PreviewSelect
|
||||
title="Particle Shape"
|
||||
:options="shapeOptions"
|
||||
v-model="particleShape"
|
||||
/>
|
||||
|
||||
<PreviewSlider title="Magnet Radius" :min="5" :max="50" :step="1" v-model="magnetRadius" />
|
||||
|
||||
<PreviewSlider title="Ring Radius" :min="5" :max="25" :step="1" v-model="ringRadius" />
|
||||
|
||||
<PreviewSlider title="Wave Speed" :min="0" :max="5" :step="0.1" v-model="waveSpeed" />
|
||||
|
||||
<PreviewSlider title="Wave Amplitude" :min="0" :max="5" :step="0.1" v-model="waveAmplitude" />
|
||||
|
||||
<PreviewSlider title="Particle Size" :min="0.1" :max="2" :step="0.1" v-model="particleSize" />
|
||||
|
||||
<PreviewSlider title="Particle Variance" :min="0" :max="1" :step="0.1" v-model="particleVariance" />
|
||||
|
||||
<PreviewSlider title="Lerp Speed" :min="0.01" :max="0.2" :step="0.01" v-model="lerpSpeed" />
|
||||
|
||||
<PreviewSlider title="Count" :min="100" :max="5000" :step="100" v-model="count" />
|
||||
|
||||
<PreviewSlider title="Rotation Speed" :min="0" :max="5" :step="0.1" v-model="rotationSpeed" />
|
||||
|
||||
<PreviewSlider title="Depth Factor" :min="0" :max="5" :step="0.1" v-model="depthFactor" />
|
||||
|
||||
<PreviewSlider title="Pulse Speed" :min="0" :max="10" :step="0.1" v-model="pulseSpeed" />
|
||||
|
||||
<PreviewSlider title="Field Strength" :min="0.1" :max="20" :step="0.1" v-model="fieldStrength" />
|
||||
|
||||
<PreviewSwitch title="Auto Animate" v-model="autoAnimate" />
|
||||
</Customize>
|
||||
|
||||
<PropTable :data="propData" />
|
||||
<Dependencies :dependency-list="['three']" />
|
||||
</template>
|
||||
|
||||
<template #code>
|
||||
<CodeExample :code-object="antigravity" />
|
||||
</template>
|
||||
|
||||
<template #cli>
|
||||
<CliInstallation :command="antigravity.cli" />
|
||||
</template>
|
||||
</TabbedLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
import CliInstallation from '../../components/code/CliInstallation.vue';
|
||||
import CodeExample from '../../components/code/CodeExample.vue';
|
||||
import Dependencies from '../../components/code/Dependencies.vue';
|
||||
import Customize from '../../components/common/Customize.vue';
|
||||
import PreviewColor from '../../components/common/PreviewColor.vue';
|
||||
import PreviewSelect from '../../components/common/PreviewSelect.vue';
|
||||
import PreviewSlider from '../../components/common/PreviewSlider.vue';
|
||||
import PreviewSwitch from '../../components/common/PreviewSwitch.vue';
|
||||
import PropTable from '../../components/common/PropTable.vue';
|
||||
import TabbedLayout from '../../components/common/TabbedLayout.vue';
|
||||
import { antigravity } from '../../constants/code/Animations/antigravityCode';
|
||||
import Antigravity, { type ParticleShape } from '../../content/Animations/Antigravity/Antigravity.vue';
|
||||
|
||||
const magnetRadius = ref(6);
|
||||
const ringRadius = ref(7);
|
||||
const waveSpeed = ref(0.4);
|
||||
const waveAmplitude = ref(1);
|
||||
const particleSize = ref(1.5);
|
||||
const lerpSpeed = ref(0.05);
|
||||
const count = ref(300);
|
||||
const color = ref('#27FF64');
|
||||
const autoAnimate = ref(true);
|
||||
const particleVariance = ref(1);
|
||||
const rotationSpeed = ref(0);
|
||||
const depthFactor = ref(1);
|
||||
const pulseSpeed = ref(3);
|
||||
const particleShape = ref<ParticleShape>('capsule');
|
||||
const fieldStrength = ref(10);
|
||||
|
||||
const componentKey = ref(0);
|
||||
|
||||
const shapeOptions = [
|
||||
{ value: 'capsule', label: 'Capsule' },
|
||||
{ value: 'sphere', label: 'Sphere' },
|
||||
{ value: 'box', label: 'Box' },
|
||||
{ value: 'tetrahedron', label: 'Tetrahedron' }
|
||||
];
|
||||
|
||||
watch(
|
||||
[
|
||||
magnetRadius,
|
||||
ringRadius,
|
||||
waveSpeed,
|
||||
waveAmplitude,
|
||||
particleSize,
|
||||
lerpSpeed,
|
||||
count,
|
||||
color,
|
||||
autoAnimate,
|
||||
particleVariance,
|
||||
rotationSpeed,
|
||||
depthFactor,
|
||||
pulseSpeed,
|
||||
particleShape,
|
||||
fieldStrength
|
||||
],
|
||||
() => {
|
||||
componentKey.value++;
|
||||
}
|
||||
);
|
||||
|
||||
const propData = [
|
||||
{
|
||||
name: 'count',
|
||||
type: 'number',
|
||||
default: '300',
|
||||
description: 'Number of particles'
|
||||
},
|
||||
{
|
||||
name: 'magnetRadius',
|
||||
type: 'number',
|
||||
default: '10',
|
||||
description: 'Radius of the magnetic field'
|
||||
},
|
||||
{
|
||||
name: 'ringRadius',
|
||||
type: 'number',
|
||||
default: '10',
|
||||
description: 'Radius of the formed ring'
|
||||
},
|
||||
{
|
||||
name: 'waveSpeed',
|
||||
type: 'number',
|
||||
default: '0.4',
|
||||
description: 'Speed of the wave animation'
|
||||
},
|
||||
{
|
||||
name: 'waveAmplitude',
|
||||
type: 'number',
|
||||
default: '1',
|
||||
description: 'Intensity of the wave (0 for perfect circle)'
|
||||
},
|
||||
{
|
||||
name: 'particleSize',
|
||||
type: 'number',
|
||||
default: '2',
|
||||
description: 'Scale multiplier for particles'
|
||||
},
|
||||
{
|
||||
name: 'lerpSpeed',
|
||||
type: 'number',
|
||||
default: '0.1',
|
||||
description: 'How fast particles move to the ring'
|
||||
},
|
||||
{
|
||||
name: 'color',
|
||||
type: 'string',
|
||||
default: '#27FF64',
|
||||
description: 'Color of the particles'
|
||||
},
|
||||
{
|
||||
name: 'autoAnimate',
|
||||
type: 'boolean',
|
||||
default: 'false',
|
||||
description: 'Automatically animate when idle'
|
||||
},
|
||||
{
|
||||
name: 'particleVariance',
|
||||
type: 'number',
|
||||
default: '1',
|
||||
description: 'Variance in particle size (0-1)'
|
||||
},
|
||||
{
|
||||
name: 'rotationSpeed',
|
||||
type: 'number',
|
||||
default: '0',
|
||||
description: 'Rotation speed of the ring'
|
||||
},
|
||||
{
|
||||
name: 'depthFactor',
|
||||
type: 'number',
|
||||
default: '1',
|
||||
description: 'Z-axis depth multiplier'
|
||||
},
|
||||
{
|
||||
name: 'pulseSpeed',
|
||||
type: 'number',
|
||||
default: '3',
|
||||
description: 'Speed of particle size pulsation'
|
||||
},
|
||||
{
|
||||
name: 'particleShape',
|
||||
type: 'string',
|
||||
default: 'capsule',
|
||||
description: 'Shape of the particles (capsule, sphere, box, tetrahedron)'
|
||||
},
|
||||
{
|
||||
name: 'fieldStrength',
|
||||
type: 'number',
|
||||
default: '10',
|
||||
description: 'Tightness of the ring formation'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
@@ -33,8 +33,8 @@
|
||||
<span class="ml-1 text-gray-400">{{ blobType }}</span>
|
||||
</button>
|
||||
|
||||
<PreviewColor title="Fill Color" v-model="fillColor" />
|
||||
<PreviewColor title="Inner Color" v-model="innerColor" />
|
||||
<PreviewColor title="Fill Color" v-model="fillColor" class="mb-4" />
|
||||
<PreviewColor title="Inner Color" v-model="innerColor" class="mb-4" />
|
||||
<PreviewColor title="Shadow Color" v-model="shadowColor" />
|
||||
|
||||
<PreviewSlider
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<TabbedLayout>
|
||||
<template #preview>
|
||||
<div class="demo-container relative h-[400px] overflow-hidden flex items-center justify-center">
|
||||
<PixelTrail
|
||||
:key="key"
|
||||
:grid-size="gridSize"
|
||||
:trail-size="trailSize"
|
||||
:max-age="maxAge"
|
||||
:interpolate="interpolate"
|
||||
:color="color"
|
||||
:gooey-filter="gooeyEnabled ? { id: 'custom-goo-filter', strength: gooStrength } : undefined"
|
||||
/>
|
||||
<div
|
||||
class="absolute inset-0 flex items-center justify-center pointer-events-none text-[4.5rem] font-[900] text-[#222] select-none"
|
||||
>
|
||||
Move Cursor.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Customize>
|
||||
<PreviewSlider title="Grid Size" v-model="gridSize" :min="10" :max="100" :step="1" @update:model-value="forceRerender" />
|
||||
|
||||
<PreviewSlider title="Trail Size" v-model="trailSize" :min="0.05" :max="0.5" :step="0.01" @update:model-value="forceRerender" />
|
||||
|
||||
<PreviewSlider title="Max Age" v-model="maxAge" :min="100" :max="1000" :step="50" @update:model-value="forceRerender" />
|
||||
|
||||
<PreviewSlider title="Interpolate" v-model="interpolate" :min="0" :max="10" :step="0.1" @update:model-value="forceRerender" />
|
||||
|
||||
<PreviewColor title="Color" v-model="color" @update:model-value="forceRerender" />
|
||||
|
||||
<PreviewSwitch title="Gooey Filter" v-model="gooeyEnabled" @update:model-value="forceRerender" />
|
||||
|
||||
<PreviewSlider
|
||||
v-if="gooeyEnabled"
|
||||
title="Gooey Strength"
|
||||
v-model="gooStrength"
|
||||
:min="1"
|
||||
:max="20"
|
||||
:step="1"
|
||||
@update:model-value="forceRerender"
|
||||
/>
|
||||
</Customize>
|
||||
|
||||
<PropTable :data="propData" />
|
||||
|
||||
<Dependencies :dependency-list="['three']" />
|
||||
</template>
|
||||
|
||||
<template #code>
|
||||
<CodeExample :code-object="pixelTrail" />
|
||||
</template>
|
||||
|
||||
<template #cli>
|
||||
<CliInstallation :command="pixelTrail.cli" />
|
||||
</template>
|
||||
</TabbedLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from 'vue';
|
||||
import TabbedLayout from '../../components/common/TabbedLayout.vue';
|
||||
import PropTable from '../../components/common/PropTable.vue';
|
||||
import Dependencies from '../../components/code/Dependencies.vue';
|
||||
import CliInstallation from '../../components/code/CliInstallation.vue';
|
||||
import CodeExample from '../../components/code/CodeExample.vue';
|
||||
import Customize from '../../components/common/Customize.vue';
|
||||
import PreviewSlider from '../../components/common/PreviewSlider.vue';
|
||||
import PreviewSwitch from '../../components/common/PreviewSwitch.vue';
|
||||
import PreviewColor from '../../components/common/PreviewColor.vue';
|
||||
import PixelTrail from '../../content/Animations/PixelTrail/PixelTrail.vue';
|
||||
import { pixelTrail } from '@/constants/code/Animations/pixelTrailCode';
|
||||
import { useForceRerender } from '@/composables/useForceRerender';
|
||||
|
||||
const { rerenderKey: key, forceRerender } = useForceRerender();
|
||||
|
||||
const gridSize = ref(50);
|
||||
const trailSize = ref(0.1);
|
||||
const maxAge = ref(250);
|
||||
const interpolate = ref(5);
|
||||
const color = ref('#27FF64');
|
||||
const gooeyEnabled = ref(true);
|
||||
const gooStrength = ref(2);
|
||||
|
||||
const propData = [
|
||||
{ name: 'gridSize', type: 'number', default: '40', description: 'Number of pixels in grid.' },
|
||||
{ name: 'trailSize', type: 'number', default: '0.1', description: 'Size of each trail dot.' },
|
||||
{ name: 'maxAge', type: 'number', default: '250', description: 'Duration of the trail effect.' },
|
||||
{ name: 'interpolate', type: 'number', default: '5', description: 'Interpolation factor for pointer movement.' },
|
||||
{ name: 'color', type: 'string', default: '#ffffff', description: 'Pixel color.' },
|
||||
{ name: 'gooeyFilter', type: 'object', default: "{ id: 'custom-goo-filter', strength: 5 }", description: 'Configuration for gooey filter.' }
|
||||
];
|
||||
</script>
|
||||
@@ -2,9 +2,11 @@
|
||||
<TabbedLayout>
|
||||
<template #preview>
|
||||
<div class="demo-container h-[500px] overflow-hidden">
|
||||
<InfiniteMenu :items="demoItems" />
|
||||
<InfiniteMenu :items="demoItems" :scale="scaleFactor" />
|
||||
</div>
|
||||
|
||||
<Customize>
|
||||
<PreviewSlider title="Scale" v-model="scaleFactor" :min="1" :max="10" :step="1" />
|
||||
</Customize>
|
||||
<PropTable :data="propData" />
|
||||
<Dependencies :dependency-list="['gl-matrix']" />
|
||||
</template>
|
||||
@@ -27,6 +29,9 @@ import PropTable from '../../components/common/PropTable.vue';
|
||||
import TabbedLayout from '../../components/common/TabbedLayout.vue';
|
||||
import { infiniteMenu } from '../../constants/code/Components/infiniteMenuCode';
|
||||
import InfiniteMenu from '../../content/Components/InfiniteMenu/InfiniteMenu.vue';
|
||||
import { ref } from 'vue';
|
||||
import PreviewSlider from '../../components/common/PreviewSlider.vue';
|
||||
import Customize from '../../components/common/Customize.vue';
|
||||
|
||||
const demoItems = [
|
||||
{
|
||||
@@ -55,12 +60,20 @@ const demoItems = [
|
||||
}
|
||||
];
|
||||
|
||||
const scaleFactor = ref<number>(3);
|
||||
|
||||
const propData = [
|
||||
{
|
||||
name: 'items',
|
||||
type: 'InfiniteMenuItem[]',
|
||||
default: '[{...}]',
|
||||
description: 'Array of menu items with image, title, description, and link properties.'
|
||||
},
|
||||
{
|
||||
name: 'scale',
|
||||
type: 'number',
|
||||
default: '3',
|
||||
description: 'scale camera position'
|
||||
}
|
||||
];
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,237 @@
|
||||
<template>
|
||||
<TabbedLayout>
|
||||
<template #preview>
|
||||
<div class="demo-container py-6 overflow-hidden">
|
||||
<RefreshButton @click="forceRerender" />
|
||||
|
||||
<div :key="key" class="w-full h-[400px] flex items-center justify-center">
|
||||
<Shuffle
|
||||
text="VUE BITS"
|
||||
:ease="ease"
|
||||
:duration="duration"
|
||||
:shuffle-times="shuffleTimes"
|
||||
:stagger="stagger"
|
||||
:shuffle-direction="shuffleDirection"
|
||||
:loop="loop"
|
||||
:loop-delay="loopDelay"
|
||||
:trigger-on-hover="triggerOnHover"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Customize>
|
||||
<PreviewSelect
|
||||
title="Direction"
|
||||
v-model="shuffleDirection"
|
||||
:options="directionOptions"
|
||||
/>
|
||||
|
||||
<PreviewSelect
|
||||
title="Ease"
|
||||
v-model="ease"
|
||||
:options="easeOptions"
|
||||
/>
|
||||
|
||||
<PreviewSlider
|
||||
title="Duration"
|
||||
v-model="duration"
|
||||
:min="0.1"
|
||||
:max="1.5"
|
||||
:step="0.05"
|
||||
value-unit="s"
|
||||
/>
|
||||
|
||||
<PreviewSlider
|
||||
title="Shuffle Times"
|
||||
v-model="shuffleTimes"
|
||||
:min="1"
|
||||
:max="8"
|
||||
:step="1"
|
||||
/>
|
||||
|
||||
<PreviewSlider
|
||||
title="Stagger"
|
||||
v-model="stagger"
|
||||
:min="0"
|
||||
:max="0.2"
|
||||
:step="0.01"
|
||||
value-unit="s"
|
||||
/>
|
||||
|
||||
<PreviewSwitch
|
||||
title="Hover Replay"
|
||||
v-model="triggerOnHover"
|
||||
/>
|
||||
|
||||
<PreviewSwitch
|
||||
title="Loop"
|
||||
v-model="loop"
|
||||
/>
|
||||
|
||||
<PreviewSlider
|
||||
title="Loop Delay"
|
||||
v-model="loopDelay"
|
||||
:min="0"
|
||||
:max="2"
|
||||
:step="0.1"
|
||||
:disabled="!loop"
|
||||
value-unit="s"
|
||||
/>
|
||||
</Customize>
|
||||
|
||||
<PropTable :data="propData" />
|
||||
<Dependencies :dependency-list="['gsap']" />
|
||||
</template>
|
||||
|
||||
<template #code>
|
||||
<CodeExample :code-object="shuffle" />
|
||||
</template>
|
||||
|
||||
<template #cli>
|
||||
<CliInstallation :command="shuffle.cli" />
|
||||
</template>
|
||||
</TabbedLayout>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, watch } from 'vue';
|
||||
import TabbedLayout from '../../components/common/TabbedLayout.vue';
|
||||
import PropTable from '../../components/common/PropTable.vue';
|
||||
import Dependencies from '../../components/code/Dependencies.vue';
|
||||
import CliInstallation from '../../components/code/CliInstallation.vue';
|
||||
import CodeExample from '../../components/code/CodeExample.vue';
|
||||
import Customize from '../../components/common/Customize.vue';
|
||||
import PreviewSlider from '../../components/common/PreviewSlider.vue';
|
||||
import PreviewSwitch from '../../components/common/PreviewSwitch.vue';
|
||||
import PreviewSelect from '../../components/common/PreviewSelect.vue';
|
||||
import RefreshButton from '../../components/common/RefreshButton.vue';
|
||||
import Shuffle from '../../content/TextAnimations/Shuffle/Shuffle.vue';
|
||||
import { shuffle } from '@/constants/code/TextAnimations/shuffleCode';
|
||||
import { useForceRerender } from '@/composables/useForceRerender';
|
||||
|
||||
const { rerenderKey: key, forceRerender } = useForceRerender();
|
||||
|
||||
const duration = ref(0.35);
|
||||
const shuffleTimes = ref(1);
|
||||
const stagger = ref(0.03);
|
||||
const shuffleDirection = ref<'left' | 'right'>('right');
|
||||
const ease = ref('power3.out');
|
||||
const loop = ref(false);
|
||||
const loopDelay = ref(0);
|
||||
const triggerOnHover = ref(true);
|
||||
|
||||
const directionOptions = [
|
||||
{ label: 'Right', value: 'right' },
|
||||
{ label: 'Left', value: 'left' }
|
||||
];
|
||||
|
||||
const easeOptions = [
|
||||
{ label: 'power2.out', value: 'power2.out' },
|
||||
{ label: 'power3.out', value: 'power3.out' },
|
||||
{ label: 'back.out(1.1)', value: 'back.out(1.1)' },
|
||||
{ label: 'expo.out', value: 'expo.out' }
|
||||
];
|
||||
|
||||
const propData = [
|
||||
{ name: 'text', type: 'string', default: '""', description: 'The text content to shuffle.' },
|
||||
{ name: 'className', type: 'string', default: '""', description: 'Optional CSS class for the wrapper element.' },
|
||||
{ name: 'style', type: 'object', default: '{}', description: 'Inline styles applied to the wrapper element.' },
|
||||
{
|
||||
name: 'shuffleDirection',
|
||||
type: '"left" | "right"',
|
||||
default: '"right"',
|
||||
description: 'Direction the per-letter strip slides to reveal the final character.'
|
||||
},
|
||||
{ name: 'duration', type: 'number', default: '0.35', description: 'Duration (s) of the strip slide per letter.' },
|
||||
{
|
||||
name: 'maxDelay',
|
||||
type: 'number',
|
||||
default: '0',
|
||||
description: 'Max random delay per strip when animationMode = "random".'
|
||||
},
|
||||
{
|
||||
name: 'ease',
|
||||
type: 'string | Function',
|
||||
default: '"power3.out"',
|
||||
description: 'GSAP ease for sliding and color tween.'
|
||||
},
|
||||
{
|
||||
name: 'threshold',
|
||||
type: 'number',
|
||||
default: '0.1',
|
||||
description: 'Portion of the element that must enter view before starting.'
|
||||
},
|
||||
{
|
||||
name: 'rootMargin',
|
||||
type: 'string',
|
||||
default: '"-100px"',
|
||||
description: 'ScrollTrigger start offset (px, %, etc.).'
|
||||
},
|
||||
{
|
||||
name: 'tag',
|
||||
type: '"h1" | "h2" | "h3" | "h4" | "h5" | "h6" | "p" | "span"',
|
||||
default: '"p"',
|
||||
description: 'HTML tag to render for the text container.'
|
||||
},
|
||||
{
|
||||
name: 'textAlign',
|
||||
type: 'CSS text-align',
|
||||
default: '"center"',
|
||||
description: 'Text alignment applied via inline style.'
|
||||
},
|
||||
{
|
||||
name: 'onShuffleComplete',
|
||||
type: '() => void',
|
||||
default: 'undefined',
|
||||
description: 'Called after a full run completes (and on each loop repeat).'
|
||||
},
|
||||
{
|
||||
name: 'shuffleTimes',
|
||||
type: 'number',
|
||||
default: '1',
|
||||
description: 'How many interim scrambled glyphs to scroll past before the final char.'
|
||||
},
|
||||
{
|
||||
name: 'animationMode',
|
||||
type: '"evenodd" | "random"',
|
||||
default: '"evenodd"',
|
||||
description: 'Odd/even staggered strips or random per-strip delays.'
|
||||
},
|
||||
{ name: 'loop', type: 'boolean', default: 'false', description: 'Repeat the shuffle indefinitely.' },
|
||||
{ name: 'loopDelay', type: 'number', default: '0', description: 'Delay (s) between loop repeats.' },
|
||||
{ name: 'stagger', type: 'number', default: '0.03', description: 'Stagger (s) for strips in "evenodd" mode.' },
|
||||
{
|
||||
name: 'scrambleCharset',
|
||||
type: 'string',
|
||||
default: '""',
|
||||
description: 'Characters to use for interim scrambles; empty keeps original copies.'
|
||||
},
|
||||
{
|
||||
name: 'colorFrom',
|
||||
type: 'string',
|
||||
default: 'undefined',
|
||||
description: 'Optional starting text color while shuffling.'
|
||||
},
|
||||
{ name: 'colorTo', type: 'string', default: 'undefined', description: 'Optional final text color to tween to.' },
|
||||
{ name: 'triggerOnce', type: 'boolean', default: 'true', description: 'Auto-run only on first scroll into view.' },
|
||||
{
|
||||
name: 'respectReducedMotion',
|
||||
type: 'boolean',
|
||||
default: 'true',
|
||||
description: 'Skip animation if user prefers reduced motion.'
|
||||
},
|
||||
{
|
||||
name: 'triggerOnHover',
|
||||
type: 'boolean',
|
||||
default: 'true',
|
||||
description: 'Allow re-playing the animation on hover after it completes.'
|
||||
}
|
||||
];
|
||||
|
||||
watch(
|
||||
() => [shuffleDirection.value, ease.value, loop.value, triggerOnHover.value],
|
||||
() => {
|
||||
forceRerender();
|
||||
}
|
||||
);
|
||||
</script>
|
||||
Reference in New Issue
Block a user