Added useTemplateRef API support

This commit is contained in:
msavulescu
2025-07-18 16:20:35 +03:00
parent 2aad0d4f4c
commit 6af299052a
69 changed files with 157 additions and 158 deletions

View File

@@ -6,7 +6,7 @@
</router-link>
<div class="nav-cta-group">
<nav class="landing-nav-items" ref="navRef">
<nav class="landing-nav-items">
<router-link class="nav-link" :class="{ 'active-link': activeItem === 'home' }" to="/">Home</router-link>
<router-link class="nav-link" to="/text-animations/split-text">Docs</router-link>
@@ -25,7 +25,7 @@
</template>
<script setup lang="ts">
import { ref, watch } from 'vue';
import { watch, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
import VueBitsLogo from '@/components/common/Logo.vue';
import { useStars } from '@/composables/useStars';
@@ -38,8 +38,7 @@ interface Props {
defineProps<Props>();
const navRef = ref<HTMLElement | null>(null);
const starCountRef = ref<HTMLElement | null>(null);
const starCountRef = useTemplateRef<HTMLElement>('starCountRef');
const stars = useStars();
const openGitHub = () => {

View File

@@ -44,13 +44,13 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, defineComponent, h } from 'vue';
import { ref, onMounted, onUnmounted, defineComponent, h, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
import CountUp from '../../../content/Animations/CountUp/CountUp.vue';
import './FeatureCards.css';
const isMobile = ref(false);
const gridRef = ref<HTMLDivElement | null>(null);
const gridRef = useTemplateRef<HTMLDivElement>('gridRef');
const checkIsMobile = () => {
isMobile.value = window.innerWidth <= 768;

View File

@@ -13,7 +13,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { Renderer, Camera, Transform, Program, Mesh, Geometry } from 'ogl';
interface Props {
@@ -150,7 +150,7 @@ void main() {
const isMobile = ref(false);
const isVisible = ref(true);
const containerRef = ref<HTMLDivElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const uniformOffset = ref(new Float32Array([props.xOffset, props.yOffset]));
const uniformResolution = ref(new Float32Array([1, 1]));
const rendererRef = ref<Renderer | null>(null);

View File

@@ -101,7 +101,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, nextTick, watch, defineComponent, h, computed } from 'vue';
import { ref, onMounted, onUnmounted, nextTick, watch, defineComponent, h, computed, useTemplateRef } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { CATEGORIES, NEW, UPDATED } from '../../constants/Categories';
import Logo from '../../assets/logos/vue-bits-logo.svg';
@@ -118,8 +118,8 @@ const pendingActivePath = ref<string | null>(null);
const isScrolledToBottom = ref(false);
const isTransitioning = ref(false);
const sidebarRef = ref<HTMLDivElement>();
const sidebarContainerRef = ref<HTMLDivElement>();
const sidebarRef = useTemplateRef<HTMLDivElement>('sidebarRef');
const sidebarContainerRef = useTemplateRef<HTMLDivElement>('sidebarContainerRef');
let hoverTimeoutRef: number | null = null;
let hoverDelayTimeoutRef: number | null = null;

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
@@ -37,7 +37,7 @@ const emit = defineEmits<{
complete: [];
}>();
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
onMounted(() => {
const el = containerRef.value;

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import gsap from 'gsap';
import { onMounted, onUnmounted, ref } from 'vue';
import { onMounted, onUnmounted, ref, useTemplateRef } from 'vue';
interface BlobCursorProps {
blobType?: 'circle' | 'square';
@@ -48,7 +48,7 @@ const props = withDefaults(defineProps<BlobCursorProps>(), {
zIndex: 100
});
const containerRef = ref<HTMLDivElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const blobsRef = ref<(HTMLElement | null)[]>([]);
const updateOffset = () => {

View File

@@ -7,7 +7,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed, watch } from 'vue';
import { ref, onMounted, onUnmounted, computed, watch, useTemplateRef } from 'vue';
interface Spark {
x: number;
@@ -36,8 +36,8 @@ const props = withDefaults(defineProps<Props>(), {
extraScale: 1.0
});
const containerRef = ref<HTMLDivElement | null>(null);
const canvasRef = ref<HTMLCanvasElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
const sparks = ref<Spark[]>([]);
const startTimeRef = ref<number | null>(null);
const animationId = ref<number | null>(null);

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, computed } from 'vue';
import { ref, onMounted, onUnmounted, watch, computed, useTemplateRef } from 'vue';
interface Props {
to: number;
@@ -28,7 +28,7 @@ const props = withDefaults(defineProps<Props>(), {
separator: ''
});
const elementRef = ref<HTMLSpanElement | null>(null);
const elementRef = useTemplateRef<HTMLSpanElement>('elementRef');
const currentValue = ref(props.direction === 'down' ? props.to : props.from);
const isInView = ref(false);
const animationId = ref<number | null>(null);

View File

@@ -77,7 +77,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, withDefaults } from 'vue';
import { ref, computed, onMounted, onUnmounted, withDefaults, useTemplateRef } from 'vue';
import gsap from 'gsap';
interface Gap {
@@ -122,7 +122,7 @@ const props = withDefaults(defineProps<Props>(), {
rippleSpeed: 2
});
const sceneRef = ref<HTMLDivElement | null>(null);
const sceneRef = useTemplateRef<HTMLDivElement>('sceneRef');
const rafRef = ref<number | null>(null);
const idleTimerRef = ref<number | null>(null);
const userActiveRef = ref(false);

View File

@@ -13,7 +13,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { ref, onMounted, onUnmounted, useTemplateRef } from 'vue';
interface Props {
blur?: boolean;
@@ -36,7 +36,7 @@ const props = withDefaults(defineProps<Props>(), {
});
const inView = ref(false);
const elementRef = ref<HTMLDivElement | null>(null);
const elementRef = useTemplateRef<HTMLDivElement>('elementRef');
let observer: IntersectionObserver | null = null;
onMounted(() => {

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, computed } from 'vue';
import { computed, useTemplateRef } from 'vue';
interface GlareHoverProps {
width?: string;
@@ -33,7 +33,7 @@ const props = withDefaults(defineProps<GlareHoverProps>(), {
style: () => ({})
});
const overlayRef = ref<HTMLDivElement | null>(null);
const overlayRef = useTemplateRef<HTMLDivElement>('overlayRef');
const rgba = computed(() => {
const hex = props.glareColor.replace('#', '');

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { nextTick, onMounted, ref } from 'vue';
import { nextTick, onMounted, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
function lerp(a: number, b: number, n: number): number {
@@ -1194,7 +1194,7 @@ const props = withDefaults(defineProps<ImageTrailProps>(), {
variant: 1
});
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
onMounted(async () => {
await nextTick();

View File

@@ -19,7 +19,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
import { ref, computed, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
interface Props {
padding?: number;
@@ -45,7 +45,7 @@ defineOptions({
inheritAttrs: false
});
const magnetRef = ref<HTMLDivElement | null>(null);
const magnetRef = useTemplateRef<HTMLDivElement>('magnetRef');
const isActive = ref(false);
const position = ref({ x: 0, y: 0 });

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed } from 'vue';
import { onMounted, onUnmounted, computed, useTemplateRef } from 'vue';
interface MagnetLinesProps {
rows?: number;
@@ -25,7 +25,7 @@ const props = withDefaults(defineProps<MagnetLinesProps>(), {
style: () => ({})
});
const containerRef = ref<HTMLDivElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const total = computed(() => props.rows * props.columns);

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { Camera, Mesh, Program, Renderer, Transform, Triangle, Vec3 } from 'ogl';
import { onMounted, onUnmounted, shallowRef, watch } from 'vue';
import { onMounted, onUnmounted, useTemplateRef, watch } from 'vue';
interface MetaBallsProps {
color?: string;
@@ -118,7 +118,7 @@ void main() {
}
`;
const containerRef = shallowRef<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
let cleanUpAnimation: () => void = () => {};
const setupAnimation = () => {

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
import { ref, onMounted, onUnmounted, watch, nextTick, useTemplateRef } from 'vue';
interface ShaderParams {
patternScale: number;
@@ -30,7 +30,7 @@ const props = withDefaults(defineProps<Props>(), {
})
});
const canvasRef = ref<HTMLCanvasElement | null>(null);
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
const gl = ref<WebGL2RenderingContext | null>(null);
const uniforms = ref<Record<string, WebGLUniformLocation>>({});
const totalAnimationTime = ref(0);

View File

@@ -7,7 +7,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue';
import { onMounted, onBeforeUnmount, useTemplateRef } from 'vue';
interface NoiseProps {
patternRefreshInterval?: number;
@@ -21,7 +21,7 @@ const props = withDefaults(defineProps<NoiseProps>(), {
mixBlendMode: 'normal'
});
const grainRef = ref<HTMLCanvasElement | null>(null);
const grainRef = useTemplateRef<HTMLCanvasElement>('grainRef');
let animationId = 0;
let frame = 0;

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, watch, onUnmounted, nextTick } from 'vue';
import { ref, onMounted, watch, onUnmounted, nextTick, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
interface PixelTransitionProps {
@@ -20,9 +20,9 @@ const props = withDefaults(defineProps<PixelTransitionProps>(), {
aspectRatio: '100%'
});
const containerRef = ref<HTMLDivElement | null>(null);
const pixelGridRef = ref<HTMLDivElement | null>(null);
const activeRef = ref<HTMLDivElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const pixelGridRef = useTemplateRef<HTMLDivElement>('pixelGridRef');
const activeRef = useTemplateRef<HTMLDivElement>('activeRef');
const isActive = ref(false);
let delayedCall: gsap.core.Tween | null = null;

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { Renderer, Transform, Vec3, Color, Polyline } from 'ogl';
interface RibbonsProps {
@@ -36,7 +36,7 @@ const props = withDefaults(defineProps<RibbonsProps>(), {
backgroundColor: () => [0, 0, 0, 0]
});
const ribbonsContainer = ref<HTMLDivElement>();
const ribbonsContainer = useTemplateRef<HTMLDivElement>('ribbonsContainer');
let renderer: Renderer;
let scene: Transform;

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import * as THREE from 'three';
interface ShapeBlurProps {
@@ -28,7 +28,7 @@ const props = withDefaults(defineProps<ShapeBlurProps>(), {
circleEdge: 0.5
});
const shapeBlurContainer = ref<HTMLDivElement>();
const shapeBlurContainer = useTemplateRef<HTMLDivElement>('shapeBlurContainer');
let animationFrameId: number;
let time = 0;

View File

@@ -5,7 +5,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, withDefaults } from 'vue';
import { onMounted, withDefaults, useTemplateRef } from 'vue';
/* ---------- types ---------- */
interface ColorRGB {
@@ -50,7 +50,7 @@ const props = withDefaults(defineProps<SplashCursorProps>(), {
});
/* ---------- refs ---------- */
const canvasRef = ref<HTMLCanvasElement | null>(null);
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
/* ---------- helper types ---------- */
interface Pointer {

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, type CSSProperties } from 'vue';
import { onMounted, onUnmounted, watch, type CSSProperties, useTemplateRef } from 'vue';
import { Renderer, Program, Mesh, Color, Triangle } from 'ogl';
interface AuroraProps {
@@ -27,7 +27,7 @@ const props = withDefaults(defineProps<AuroraProps>(), {
style: () => ({})
});
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const VERT = `#version 300 es
in vec2 position;

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, watch, onMounted, onUnmounted, type CSSProperties } from 'vue';
import { watch, onMounted, onUnmounted, type CSSProperties, useTemplateRef } from 'vue';
import { Renderer, Program, Mesh, Triangle } from 'ogl';
interface BalatroProps {
@@ -42,7 +42,7 @@ const props = withDefaults(defineProps<BalatroProps>(), {
style: () => ({})
});
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const hexToVec4 = (hex: string): [number, number, number, number] => {
const hexStr = hex.replace('#', '');

View File

@@ -26,7 +26,7 @@ import {
type WebGLRendererParameters
} from 'three';
import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment.js';
import { onMounted, onUnmounted, ref } from 'vue';
import { defineProps, onMounted, onUnmounted, useTemplateRef, ref } from 'vue';
gsap.registerPlugin(Observer);
@@ -86,7 +86,7 @@ const props = withDefaults(defineProps<Props>(), {
controlSphere0: false
});
const canvasRef = ref<HTMLCanvasElement | null>(null);
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
const spheresInstanceRef = ref<CreateBallpitReturn | null>(null);
interface PostProcessing {

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, computed } from 'vue';
import { onMounted, onUnmounted, watch, computed, useTemplateRef } from 'vue';
import * as THREE from 'three';
import { degToRad } from 'three/src/math/MathUtils.js';
@@ -29,7 +29,7 @@ const props = withDefaults(defineProps<BeamsProps>(), {
rotation: 0
});
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
let renderer: THREE.WebGLRenderer | null = null;
let scene: THREE.Scene | null = null;

View File

@@ -7,7 +7,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed, watch, nextTick } from 'vue';
import { ref, onMounted, onUnmounted, computed, watch, nextTick, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
import { InertiaPlugin } from 'gsap/InertiaPlugin';
@@ -64,8 +64,8 @@ const props = withDefaults(defineProps<DotGridProps>(), {
style: () => ({})
});
const wrapperRef = ref<HTMLDivElement>();
const canvasRef = ref<HTMLCanvasElement>();
const wrapperRef = useTemplateRef<HTMLDivElement>('wrapperRef');
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
const dots = ref<Dot[]>([]);
const pointer = ref({
x: 0,

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import * as THREE from 'three';
import { onMounted, onUnmounted, ref, watch } from 'vue';
import { onMounted, onUnmounted, ref, watch, useTemplateRef } from 'vue';
interface GridDistortionProps {
grid?: number;
@@ -44,7 +44,7 @@ void main() {
}
`;
const containerRef = ref<HTMLDivElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const imageAspectRef = ref(1);
const cameraRef = ref<THREE.OrthographicCamera | null>(null);
const initialDataRef = ref<Float32Array | null>(null);

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, computed } from 'vue';
import { ref, onMounted, onBeforeUnmount, computed, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
interface GridMotionProps {
@@ -12,7 +12,7 @@ const props = withDefaults(defineProps<GridMotionProps>(), {
gradientColor: '#222222'
});
const gridRef = ref<HTMLElement | null>(null);
const gridRef = useTemplateRef<HTMLElement>('gridRef');
const rowRefs = ref<HTMLElement[]>([]);
const mouseX = ref(window.innerWidth / 2);

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import * as THREE from 'three';
import { BloomEffect, EffectComposer, EffectPass, RenderPass, SMAAEffect, SMAAPreset } from 'postprocessing';
@@ -66,7 +66,7 @@ const props = withDefaults(defineProps<HyperspeedProps>(), {
effectOptions: () => ({})
});
const hyperspeedContainer = ref<HTMLDivElement>();
const hyperspeedContainer = useTemplateRef<HTMLDivElement>('hyperspeedContainer');
let appRef: App | null = null;
const defaultOptions: HyperspeedOptions = {

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { Renderer, Program, Mesh, Color, Triangle } from 'ogl';
import type { OGLRenderingContext } from 'ogl';
@@ -21,7 +21,7 @@ const props = withDefaults(defineProps<Props>(), {
mouseReact: true
});
const containerRef = ref<HTMLDivElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const mousePos = ref({ x: 0.5, y: 0.5 });
let renderer: Renderer | null = null;

View File

@@ -15,7 +15,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
interface Props {
glitchColors?: string[];
@@ -33,7 +33,7 @@ const props = withDefaults(defineProps<Props>(), {
smooth: true
});
const canvasRef = ref<HTMLCanvasElement | null>(null);
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
const animationRef = ref<number | null>(null);
const letters = ref<
{

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
interface LightningProps {
hue?: number;
@@ -21,7 +21,7 @@ const props = withDefaults(defineProps<LightningProps>(), {
size: 1
});
const canvasRef = ref<HTMLCanvasElement>();
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
let animationId = 0;
let gl: WebGLRenderingContext | null = null;
let program: WebGLProgram | null = null;

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { Renderer, Program, Mesh, Triangle } from 'ogl';
interface LiquidChromeProps {
@@ -20,7 +20,7 @@ const props = withDefaults(defineProps<LiquidChromeProps>(), {
interactive: true
});
const containerRef = ref<HTMLDivElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
let cleanupAnimation: (() => void) | null = null;

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { Renderer, Program, Mesh, Triangle, Vec3 } from 'ogl';
interface OrbProps {
@@ -16,7 +16,7 @@ const props = withDefaults(defineProps<OrbProps>(), {
forceHoverState: false
});
const ctnDom = ref<HTMLDivElement | null>(null);
const ctnDom = useTemplateRef<HTMLDivElement>('ctnDom');
const vert = /* glsl */ `
precision highp float;

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { Renderer, Camera, Geometry, Program, Mesh } from 'ogl';
interface ParticlesProps {
@@ -36,7 +36,7 @@ const props = withDefaults(defineProps<ParticlesProps>(), {
className: ''
});
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const mouseRef = ref({ x: 0, y: 0 });
let renderer: Renderer | null = null;

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, type CSSProperties } from 'vue';
import { onMounted, onUnmounted, watch, type CSSProperties, useTemplateRef } from 'vue';
import { Renderer, Program, Mesh, Plane, Camera } from 'ogl';
interface SilkProps {
@@ -26,7 +26,7 @@ const props = withDefaults(defineProps<SilkProps>(), {
style: () => ({})
});
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const hexToNormalizedRGB = (hex: string): [number, number, number] => {
const clean = hex.replace('#', '');

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
type CanvasStrokeStyle = string | CanvasGradient | CanvasPattern;
@@ -28,7 +28,7 @@ const props = withDefaults(defineProps<Props>(), {
hoverFillColor: '#222'
});
const canvasRef = ref<HTMLCanvasElement | null>(null);
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
const requestRef = ref<number | null>(null);
const numSquaresX = ref<number>(0);
const numSquaresY = ref<number>(0);

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { Renderer, Program, Mesh, Triangle, Color } from 'ogl';
import type { OGLRenderingContext } from 'ogl';
@@ -21,7 +21,7 @@ const props = withDefaults(defineProps<Props>(), {
enableMouseInteraction: false
});
const containerRef = ref<HTMLDivElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
let renderer: Renderer | null = null;
let gl: OGLRenderingContext | null = null;

View File

@@ -18,7 +18,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, type CSSProperties } from 'vue';
import { onMounted, onUnmounted, watch, type CSSProperties, useTemplateRef } from 'vue';
class Grad {
x: number;
@@ -180,8 +180,8 @@ const props = withDefaults(defineProps<WavesProps>(), {
className: ''
});
const containerRef = ref<HTMLDivElement>();
const canvasRef = ref<HTMLCanvasElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
let ctx: CanvasRenderingContext2D | null = null;
let bounding = { width: 0, height: 0, left: 0, top: 0 };

View File

@@ -70,7 +70,7 @@ export { makeSlot, placeNow };
</script>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, nextTick, computed } from 'vue';
import { ref, onMounted, onUnmounted, watch, nextTick, computed, useTemplateRef } from 'vue';
const props = withDefaults(defineProps<CardSwapProps>(), {
width: 500,
@@ -87,7 +87,7 @@ const emit = defineEmits<{
'card-click': [index: number];
}>();
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const cardRefs = ref<HTMLElement[]>([]);
const order = ref<number[]>([0, 1, 2]);
const tlRef = ref<gsap.core.Timeline | null>(null);

View File

@@ -139,7 +139,7 @@ export const DEFAULT_ITEMS: CarouselItem[] = [
</script>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
import { ref, computed, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { Motion, useMotionValue, useTransform } from 'motion-v';
const DRAG_BUFFER = 0;
@@ -167,7 +167,7 @@ const motionX = useMotionValue(0);
const isHovered = ref<boolean>(false);
const isResetting = ref<boolean>(false);
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
let autoplayTimer: number | null = null;
const dragConstraints = computed(() => {

View File

@@ -3,7 +3,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { Camera, Mesh, Plane, Program, Renderer, Texture, Transform } from 'ogl';
interface CircularGalleryProps {
@@ -25,7 +25,7 @@ const props = withDefaults(defineProps<CircularGalleryProps>(), {
scrollEase: 0.05
});
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
let app: App | null = null;
type GL = Renderer['gl'];

View File

@@ -56,7 +56,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { ref, onMounted, onUnmounted, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
interface Props {
@@ -71,7 +71,7 @@ withDefaults(defineProps<Props>(), {
image: 'https://picsum.photos/300/400?grayscale'
});
const svgRef = ref<HTMLDivElement | null>(null);
const svgRef = useTemplateRef<HTMLDivElement>('svgRef');
const displacementMapRef = ref<SVGFEDisplacementMapElement | null>(null);
let cursor = {

View File

@@ -72,7 +72,7 @@
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, type Component } from 'vue';
import { ref, computed, watch, onMounted, type Component, useTemplateRef } from 'vue';
const MAX_OVERFLOW = 50;
@@ -98,9 +98,9 @@ const props = withDefaults(defineProps<Props>(), {
rightIcon: '+'
});
const sliderRef = ref<HTMLDivElement>();
const leftIconRef = ref<HTMLDivElement>();
const rightIconRef = ref<HTMLDivElement>();
const sliderRef = useTemplateRef<HTMLDivElement>('sliderRef');
const leftIconRef = useTemplateRef<HTMLDivElement>('leftIconRef');
const rightIconRef = useTemplateRef<HTMLDivElement>('rightIconRef');
const value = ref(props.defaultValue);
const region = ref<'left' | 'middle' | 'right'>('middle');

View File

@@ -546,7 +546,7 @@ export { Canvas, Media };
</script>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
const props = withDefaults(defineProps<FlyingPostersProps>(), {
items: () => [],
@@ -559,8 +559,8 @@ const props = withDefaults(defineProps<FlyingPostersProps>(), {
className: ''
});
const containerRef = ref<HTMLDivElement>();
const canvasRef = ref<HTMLCanvasElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
const instanceRef = ref<Canvas | null>(null);
const initCanvas = () => {

View File

@@ -38,7 +38,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
interface GooeyNavItem {
label: string;
@@ -66,10 +66,10 @@ const props = withDefaults(defineProps<GooeyNavProps>(), {
initialActiveIndex: 0
});
const containerRef = ref<HTMLDivElement>();
const navRef = ref<HTMLUListElement>();
const filterRef = ref<HTMLSpanElement>();
const textRef = ref<HTMLSpanElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const navRef = useTemplateRef<HTMLUListElement>('navRef');
const filterRef = useTemplateRef<HTMLSpanElement>('filterRef');
const textRef = useTemplateRef<HTMLSpanElement>('textRef');
const activeIndex = ref<number>(props.initialActiveIndex);
let resizeObserver: ResizeObserver | null = null;

View File

@@ -38,7 +38,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
import { Observer } from 'gsap/Observer';
@@ -76,8 +76,8 @@ const props = withDefaults(defineProps<Props>(), {
pauseOnHover: false
});
const wrapperRef = ref<HTMLDivElement | null>(null);
const containerRef = ref<HTMLDivElement | null>(null);
const wrapperRef = useTemplateRef<HTMLDivElement>('wrapperRef');
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
let observer: Observer | null = null;
let rafId: number | null = null;
let velocity = 0;

View File

@@ -24,7 +24,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watchEffect, nextTick } from 'vue';
import { ref, computed, onMounted, onUnmounted, watchEffect, nextTick, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
interface Item {
@@ -74,7 +74,7 @@ const useMedia = (queries: string[], values: number[], defaultValue: number) =>
};
const useMeasure = () => {
const containerRef = ref<HTMLDivElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const size = ref({ width: 0, height: 0 });
let resizeObserver: ResizeObserver | null = null;

View File

@@ -18,7 +18,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, computed, watch } from 'vue';
import { ref, onMounted, onUnmounted, computed, watch, useTemplateRef } from 'vue';
class Pixel {
width: number;
@@ -189,8 +189,8 @@ const props = withDefaults(defineProps<PixelCardProps>(), {
className: ''
});
const containerRef = ref<HTMLDivElement>();
const canvasRef = ref<HTMLCanvasElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
const pixelsRef = ref<Pixel[]>([]);
const animationRef = ref<number | null>(null);
const timePreviousRef = ref(performance.now());

View File

@@ -58,7 +58,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted } from 'vue';
import { computed, onMounted, onUnmounted, useTemplateRef } from 'vue';
interface Props {
avatarUrl?: string;
@@ -100,8 +100,8 @@ const emit = defineEmits<{
contactClick: [];
}>();
const wrapRef = ref<HTMLDivElement>();
const cardRef = ref<HTMLElement>();
const wrapRef = useTemplateRef<HTMLDivElement>('wrapRef');
const cardRef = useTemplateRef<HTMLElement>('cardRef');
const DEFAULT_BEHIND_GRADIENT =
'radial-gradient(farthest-side circle at var(--pointer-x) var(--pointer-y),hsla(266,100%,90%,var(--card-opacity)) 4%,hsla(266,50%,80%,calc(var(--card-opacity)*0.75)) 10%,hsla(266,25%,70%,calc(var(--card-opacity)*0.5)) 50%,hsla(266,0%,60%,0) 100%),radial-gradient(35% 52% at 55% 20%,#00ffaac4 0%,#073aff00 100%),radial-gradient(100% 100% at 50% 50%,#00c1ffff 1%,#073aff00 76%),conic-gradient(from 124deg at 50% 50%,#c137ffff 0%,#07c6ffff 40%,#07c6ffff 60%,#c137ffff 100%)';

View File

@@ -21,7 +21,7 @@
</template>
<script setup lang="ts">
import { ref } from 'vue';
import { ref, useTemplateRef } from 'vue';
interface Position {
x: number;
@@ -35,7 +35,7 @@ interface SpotlightCardProps {
const { className = '', spotlightColor = 'rgba(255, 255, 255, 0.25)' } = defineProps<SpotlightCardProps>();
const divRef = ref<HTMLDivElement>();
const divRef = useTemplateRef<HTMLDivElement>('divRef');
const isFocused = ref<boolean>(false);
const position = ref<Position>({ x: 0, y: 0 });
const opacity = ref<number>(0);

View File

@@ -65,7 +65,7 @@
</template>
<script setup lang="ts">
import { ref, computed } from 'vue';
import { ref, computed, useTemplateRef } from 'vue';
import { Motion } from 'motion-v';
interface TiltedCardProps {
@@ -99,7 +99,7 @@ const props = withDefaults(defineProps<TiltedCardProps>(), {
displayOverlayContent: false
});
const cardRef = ref<HTMLElement | null>(null);
const cardRef = useTemplateRef<HTMLElement>('cardRef');
const xValue = ref(0);
const yValue = ref(0);
const rotateXValue = ref(0);

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import * as THREE from 'three';
interface AsciiTextProps {
@@ -495,7 +495,7 @@ class CanvAscii {
}
}
const containerRef = ref<HTMLDivElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
let asciiRef: CanvAscii | null = null;
const initializeAscii = () => {

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
import { ref, computed, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { Motion } from 'motion-v';
interface BlurTextProps {
@@ -45,7 +45,7 @@ const buildKeyframes = (
const elements = computed(() => (props.animateBy === 'words' ? props.text.split(' ') : props.text.split('')));
const inView = ref(false);
const rootRef = ref<HTMLParagraphElement | null>(null);
const rootRef = useTemplateRef<HTMLParagraphElement>('rootRef');
let observer: IntersectionObserver | null = null;
const defaultFrom = computed(() =>

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
import { ref, onMounted, onUnmounted, watch, nextTick, useTemplateRef } from 'vue';
interface DecryptedTextProps {
text: string;
@@ -33,7 +33,7 @@ const emit = defineEmits<{
animationComplete: [];
}>();
const containerRef = ref<HTMLSpanElement>();
const containerRef = useTemplateRef<HTMLSpanElement>('containerRef');
const displayText = ref(props.text);
const isHovering = ref(false);
const isScrambling = ref(false);

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
import { ref, onMounted, onUnmounted, watch, nextTick, useTemplateRef } from 'vue';
import Matter from 'matter-js';
interface FallingTextProps {
@@ -24,9 +24,9 @@ const props = withDefaults(defineProps<FallingTextProps>(), {
fontSize: '1rem'
});
const containerRef = ref<HTMLDivElement>();
const textRef = ref<HTMLDivElement>();
const canvasContainerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const textRef = useTemplateRef<HTMLDivElement>('textRef');
const canvasContainerRef = useTemplateRef<HTMLDivElement>('canvasContainerRef');
const effectStarted = ref(false);

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
import { onMounted, onUnmounted, watch, nextTick, useTemplateRef } from 'vue';
interface FuzzyTextProps {
text: string;
@@ -23,7 +23,7 @@ const props = withDefaults(defineProps<FuzzyTextProps>(), {
hoverIntensity: 0.5
});
const canvasRef = ref<HTMLCanvasElement | null>(null);
const canvasRef = useTemplateRef<HTMLCanvasElement>('canvasRef');
let animationFrameId: number;
let isCancelled = false;
let cleanup: (() => void) | null = null;

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
import { SplitText } from 'gsap/SplitText';
import { ScrambleTextPlugin } from 'gsap/ScrambleTextPlugin';
@@ -24,7 +24,7 @@ const props = withDefaults(defineProps<ScrambleTextProps>(), {
style: () => ({})
});
const rootRef = ref<HTMLDivElement | null>(null);
const rootRef = useTemplateRef<HTMLDivElement>('rootRef');
let splitText: SplitText | null = null;
let handleMove: ((e: PointerEvent) => void) | null = null;

View File

@@ -12,7 +12,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
import { computed, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
@@ -40,7 +40,7 @@ const props = withDefaults(defineProps<Props>(), {
stagger: 0.03
});
const containerRef = ref<HTMLElement | null>(null);
const containerRef = useTemplateRef<HTMLElement>('containerRef');
let scrollTriggerInstance: ScrollTrigger | null = null;
const splitText = computed(() => {

View File

@@ -9,7 +9,7 @@
</template>
<script setup lang="ts">
import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
import { computed, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
@@ -39,7 +39,7 @@ const props = withDefaults(defineProps<Props>(), {
wordAnimationEnd: 'bottom bottom'
});
const containerRef = ref<HTMLElement | null>(null);
const containerRef = useTemplateRef<HTMLElement>('containerRef');
let scrollTriggerInstances: ScrollTrigger[] = [];
const splitText = computed(() => {

View File

@@ -12,7 +12,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch, nextTick } from 'vue';
import { ref, onMounted, onUnmounted, watch, nextTick, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
import { SplitText as GSAPSplitText } from 'gsap/SplitText';
@@ -51,7 +51,7 @@ const emit = defineEmits<{
'animation-complete': [];
}>();
const textRef = ref<HTMLParagraphElement | null>(null);
const textRef = useTemplateRef<HTMLParagraphElement>('textRef');
const animationCompletedRef = ref(false);
const scrollTriggerRef = ref<ScrollTrigger | null>(null);
const timelineRef = ref<gsap.core.Timeline | null>(null);

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { ref, onMounted, onUnmounted, useTemplateRef } from 'vue';
import { Motion } from 'motion-v';
interface TextCursorProps {
@@ -34,7 +34,7 @@ const props = withDefaults(defineProps<TextCursorProps>(), {
maxPoints: 5
});
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const trail = ref<TrailItem[]>([]);
const lastMoveTime = ref(Date.now());
const idCounter = ref(0);

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, nextTick, computed, watch } from 'vue';
import { ref, onMounted, onUnmounted, nextTick, computed, watch, useTemplateRef } from 'vue';
interface TextPressureProps {
text?: string;
@@ -37,8 +37,8 @@ const props = withDefaults(defineProps<TextPressureProps>(), {
minFontSize: 24
});
const containerRef = ref<HTMLDivElement | null>(null);
const titleRef = ref<HTMLHeadingElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const titleRef = useTemplateRef<HTMLHeadingElement>('titleRef');
const spansRef = ref<(HTMLSpanElement | null)[]>([]);
const mouseRef = ref({ x: 0, y: 0 });

View File

@@ -1,5 +1,5 @@
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import {
CanvasTexture,
Clock,
@@ -49,7 +49,7 @@ const props = withDefaults(defineProps<TextTrailProps>(), {
supersample: 2
});
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const hexToRgb = (hex: string): [number, number, number] => {
let h = hex.replace('#', '');

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { motion } from 'motion-v';
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
import { computed, nextTick, onMounted, onUnmounted, ref, watch, useTemplateRef } from 'vue';
interface TrueFocusProps {
sentence?: string;
@@ -25,7 +25,7 @@ const props = withDefaults(defineProps<TrueFocusProps>(), {
const words = computed(() => props.sentence.split(' '));
const currentIndex = ref(0);
const lastActiveIndex = ref<number | null>(null);
const containerRef = ref<HTMLDivElement>();
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
const wordRefs = ref<HTMLSpanElement[]>([]);
const focusRect = ref({ x: 0, y: 0, width: 0, height: 0 });

View File

@@ -36,7 +36,7 @@
<script setup lang="ts">
import { useForceRerender } from '@/composables/useForceRerender';
import { ref, watch } from 'vue';
import { ref, watch, useTemplateRef } from 'vue';
import CliInstallation from '../../components/code/CliInstallation.vue';
import CodeExample from '../../components/code/CodeExample.vue';
import Dependencies from '../../components/code/Dependencies.vue';
@@ -53,7 +53,7 @@ const { rerenderKey: key, forceRerender } = useForceRerender();
const grid = ref(10);
const mouse = ref(0.25);
const containerRef = ref<HTMLDivElement | null>(null);
const containerRef = useTemplateRef<HTMLDivElement>('containerRef');
watch(
() => [grid, mouse],

View File

@@ -47,7 +47,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted } from 'vue';
import { ref, onMounted, onUnmounted, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
import TabbedLayout from '../../components/common/TabbedLayout.vue';
import PropTable from '../../components/common/PropTable.vue';
@@ -58,7 +58,7 @@ import ScrollFloat from '../../content/TextAnimations/ScrollFloat/ScrollFloat.vu
import PreviewSlider from '../../components/common/PreviewSlider.vue';
import { scrollFloatCode } from '@/constants/code/TextAnimations/scrollFloatCode';
const containerRef = ref<HTMLElement | null>(null);
const containerRef = useTemplateRef<HTMLElement>('containerRef');
const scrollText = ref('Vue Bits!');
const animationDuration = ref(1);
const ease = ref('back.inOut(2)');

View File

@@ -42,7 +42,7 @@
</template>
<script setup lang="ts">
import { ref, onMounted, onUnmounted, watch } from 'vue';
import { ref, onMounted, onUnmounted, watch, useTemplateRef } from 'vue';
import { gsap } from 'gsap';
import TabbedLayout from '../../components/common/TabbedLayout.vue';
import PropTable from '../../components/common/PropTable.vue';
@@ -55,7 +55,7 @@ import PreviewSwitch from '../../components/common/PreviewSwitch.vue';
import { scrollRevealCode } from '@/constants/code/TextAnimations/scrollRevealCode';
import { useForceRerender } from '@/composables/useForceRerender';
const containerRef = ref<HTMLElement | null>(null);
const containerRef = useTemplateRef<HTMLElement>('containerRef');
const scrollText = ref(
'When does a man die? When he is hit by a bullet? No! When he suffers a disease? No! When he ate a soup made out of a poisonous mushroom? No! A man dies when he is forgotten!'
);

View File

@@ -19,14 +19,14 @@
</template>
<script setup lang="ts">
import { ref, computed, watch, onMounted, nextTick, defineAsyncComponent } from 'vue';
import { computed, watch, onMounted, nextTick, defineAsyncComponent, useTemplateRef } from 'vue';
import { useRoute } from 'vue-router';
import { componentMap } from '../constants/Components';
import { decodeLabel } from '../utils/utils';
import BackToTopButton from '@/components/common/BackToTopButton.vue';
const route = useRoute();
const scrollRef = ref<HTMLDivElement | null>(null);
const scrollRef = useTemplateRef<HTMLDivElement>('scrollRef');
const subcategory = computed(() => route.params.subcategory as string);
const decodedLabel = computed(() => decodeLabel(subcategory.value));