mirror of
https://github.com/DavidHDev/vue-bits.git
synced 2026-03-07 22:49:31 -07:00
Migrate <ShapeBlur />
This commit is contained in:
@@ -72,6 +72,7 @@ export const CATEGORIES = [
|
|||||||
'Lightning',
|
'Lightning',
|
||||||
'Letter Glitch',
|
'Letter Glitch',
|
||||||
'Particles',
|
'Particles',
|
||||||
|
'Shape Blur',
|
||||||
'Waves',
|
'Waves',
|
||||||
'Squares',
|
'Squares',
|
||||||
'Iridescence',
|
'Iridescence',
|
||||||
|
|||||||
@@ -62,7 +62,8 @@ const backgrounds = {
|
|||||||
'aurora': () => import('../demo/Backgrounds/AuroraDemo.vue'),
|
'aurora': () => import('../demo/Backgrounds/AuroraDemo.vue'),
|
||||||
'beams': () => import('../demo/Backgrounds/BeamsDemo.vue'),
|
'beams': () => import('../demo/Backgrounds/BeamsDemo.vue'),
|
||||||
'grid-motion': () => import('../demo/Backgrounds/GridMotionDemo.vue'),
|
'grid-motion': () => import('../demo/Backgrounds/GridMotionDemo.vue'),
|
||||||
'hyperspeed': () => import('../demo/Backgrounds/HyperspeedDemo.vue')
|
'hyperspeed': () => import('../demo/Backgrounds/HyperspeedDemo.vue'),
|
||||||
|
'shape-blur': () => import('../demo/Backgrounds/ShapeBlurDemo.vue')
|
||||||
};
|
};
|
||||||
|
|
||||||
export const componentMap = {
|
export const componentMap = {
|
||||||
|
|||||||
24
src/constants/code/Backgrounds/shapeBlurCode.ts
Normal file
24
src/constants/code/Backgrounds/shapeBlurCode.ts
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
import code from '@content/Backgrounds/ShapeBlur/ShapeBlur.vue?raw';
|
||||||
|
import type { CodeObject } from '../../../types/code';
|
||||||
|
|
||||||
|
export const shapeBlur: CodeObject = {
|
||||||
|
cli: `npx jsrepo add https://vue-bits.dev/ui/Backgrounds/ShapeBlur`,
|
||||||
|
installation: `npm install three`,
|
||||||
|
usage: `<template>
|
||||||
|
<ShapeBlur
|
||||||
|
:variation="0"
|
||||||
|
:pixel-ratio-prop="2"
|
||||||
|
:shape-size="1.2"
|
||||||
|
:roundness="0.4"
|
||||||
|
:border-size="0.05"
|
||||||
|
:circle-size="0.3"
|
||||||
|
:circle-edge="0.5"
|
||||||
|
class="shape-blur-effect"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import ShapeBlur from "./ShapeBlur.vue";
|
||||||
|
</script>`,
|
||||||
|
code
|
||||||
|
};
|
||||||
334
src/content/Backgrounds/ShapeBlur/ShapeBlur.vue
Normal file
334
src/content/Backgrounds/ShapeBlur/ShapeBlur.vue
Normal file
@@ -0,0 +1,334 @@
|
|||||||
|
<template>
|
||||||
|
<div ref="shapeBlurContainer" class="shape-blur-container" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onUnmounted, watch } from 'vue';
|
||||||
|
import * as THREE from 'three';
|
||||||
|
|
||||||
|
interface ShapeBlurProps {
|
||||||
|
className?: string;
|
||||||
|
variation?: number;
|
||||||
|
pixelRatioProp?: number;
|
||||||
|
shapeSize?: number;
|
||||||
|
roundness?: number;
|
||||||
|
borderSize?: number;
|
||||||
|
circleSize?: number;
|
||||||
|
circleEdge?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const props = withDefaults(defineProps<ShapeBlurProps>(), {
|
||||||
|
className: '',
|
||||||
|
variation: 0,
|
||||||
|
pixelRatioProp: 2,
|
||||||
|
shapeSize: 1.2,
|
||||||
|
roundness: 0.4,
|
||||||
|
borderSize: 0.05,
|
||||||
|
circleSize: 0.3,
|
||||||
|
circleEdge: 0.5
|
||||||
|
});
|
||||||
|
|
||||||
|
const shapeBlurContainer = ref<HTMLDivElement>();
|
||||||
|
|
||||||
|
let animationFrameId: number;
|
||||||
|
let time = 0;
|
||||||
|
let lastTime = 0;
|
||||||
|
let scene: THREE.Scene;
|
||||||
|
let camera: THREE.OrthographicCamera;
|
||||||
|
let renderer: THREE.WebGLRenderer;
|
||||||
|
let material: THREE.ShaderMaterial;
|
||||||
|
let quad: THREE.Mesh;
|
||||||
|
let resizeObserver: ResizeObserver | null = null;
|
||||||
|
|
||||||
|
const vMouse = new THREE.Vector2();
|
||||||
|
const vMouseDamp = new THREE.Vector2();
|
||||||
|
const vResolution = new THREE.Vector2();
|
||||||
|
|
||||||
|
let w = 1;
|
||||||
|
let h = 1;
|
||||||
|
|
||||||
|
const vertexShader = /* glsl */ `
|
||||||
|
varying vec2 v_texcoord;
|
||||||
|
void main() {
|
||||||
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||||
|
v_texcoord = uv;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const fragmentShader = /* glsl */ `
|
||||||
|
varying vec2 v_texcoord;
|
||||||
|
|
||||||
|
uniform vec2 u_mouse;
|
||||||
|
uniform vec2 u_resolution;
|
||||||
|
uniform float u_pixelRatio;
|
||||||
|
|
||||||
|
uniform float u_shapeSize;
|
||||||
|
uniform float u_roundness;
|
||||||
|
uniform float u_borderSize;
|
||||||
|
uniform float u_circleSize;
|
||||||
|
uniform float u_circleEdge;
|
||||||
|
|
||||||
|
#ifndef PI
|
||||||
|
#define PI 3.1415926535897932384626433832795
|
||||||
|
#endif
|
||||||
|
#ifndef TWO_PI
|
||||||
|
#define TWO_PI 6.2831853071795864769252867665590
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef VAR
|
||||||
|
#define VAR 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FNC_COORD
|
||||||
|
#define FNC_COORD
|
||||||
|
vec2 coord(in vec2 p) {
|
||||||
|
p = p / u_resolution.xy;
|
||||||
|
if (u_resolution.x > u_resolution.y) {
|
||||||
|
p.x *= u_resolution.x / u_resolution.y;
|
||||||
|
p.x += (u_resolution.y - u_resolution.x) / u_resolution.y / 2.0;
|
||||||
|
} else {
|
||||||
|
p.y *= u_resolution.y / u_resolution.x;
|
||||||
|
p.y += (u_resolution.x - u_resolution.y) / u_resolution.x / 2.0;
|
||||||
|
}
|
||||||
|
p -= 0.5;
|
||||||
|
p *= vec2(-1.0, 1.0);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define st0 coord(gl_FragCoord.xy)
|
||||||
|
#define mx coord(u_mouse * u_pixelRatio)
|
||||||
|
|
||||||
|
float sdRoundRect(vec2 p, vec2 b, float r) {
|
||||||
|
vec2 d = abs(p - 0.5) * 4.2 - b + vec2(r);
|
||||||
|
return min(max(d.x, d.y), 0.0) + length(max(d, 0.0)) - r;
|
||||||
|
}
|
||||||
|
float sdCircle(in vec2 st, in vec2 center) {
|
||||||
|
return length(st - center) * 2.0;
|
||||||
|
}
|
||||||
|
float sdPoly(in vec2 p, in float w, in int sides) {
|
||||||
|
float a = atan(p.x, p.y) + PI;
|
||||||
|
float r = TWO_PI / float(sides);
|
||||||
|
float d = cos(floor(0.5 + a / r) * r - a) * length(max(abs(p) * 1.0, 0.0));
|
||||||
|
return d * 2.0 - w;
|
||||||
|
}
|
||||||
|
|
||||||
|
float aastep(float threshold, float value) {
|
||||||
|
float afwidth = length(vec2(dFdx(value), dFdy(value))) * 0.70710678118654757;
|
||||||
|
return smoothstep(threshold - afwidth, threshold + afwidth, value);
|
||||||
|
}
|
||||||
|
float fill(in float x) { return 1.0 - aastep(0.0, x); }
|
||||||
|
float fill(float x, float size, float edge) {
|
||||||
|
return 1.0 - smoothstep(size - edge, size + edge, x);
|
||||||
|
}
|
||||||
|
float stroke(in float d, in float t) { return (1.0 - aastep(t, abs(d))); }
|
||||||
|
float stroke(float x, float size, float w, float edge) {
|
||||||
|
float d = smoothstep(size - edge, size + edge, x + w * 0.5) - smoothstep(size - edge, size + edge, x - w * 0.5);
|
||||||
|
return clamp(d, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
float strokeAA(float x, float size, float w, float edge) {
|
||||||
|
float afwidth = length(vec2(dFdx(x), dFdy(x))) * 0.70710678;
|
||||||
|
float d = smoothstep(size - edge - afwidth, size + edge + afwidth, x + w * 0.5)
|
||||||
|
- smoothstep(size - edge - afwidth, size + edge + afwidth, x - w * 0.5);
|
||||||
|
return clamp(d, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec2 st = st0 + 0.5;
|
||||||
|
vec2 posMouse = mx * vec2(1., -1.) + 0.5;
|
||||||
|
|
||||||
|
float size = u_shapeSize;
|
||||||
|
float roundness = u_roundness;
|
||||||
|
float borderSize = u_borderSize;
|
||||||
|
float circleSize = u_circleSize;
|
||||||
|
float circleEdge = u_circleEdge;
|
||||||
|
|
||||||
|
float sdfCircle = fill(
|
||||||
|
sdCircle(st, posMouse),
|
||||||
|
circleSize,
|
||||||
|
circleEdge
|
||||||
|
);
|
||||||
|
|
||||||
|
float sdf;
|
||||||
|
if (VAR == 0) {
|
||||||
|
sdf = sdRoundRect(st, vec2(size), roundness);
|
||||||
|
sdf = strokeAA(sdf, 0.0, borderSize, sdfCircle) * 4.0;
|
||||||
|
} else if (VAR == 1) {
|
||||||
|
sdf = sdCircle(st, vec2(0.5));
|
||||||
|
sdf = fill(sdf, 0.6, sdfCircle) * 1.2;
|
||||||
|
} else if (VAR == 2) {
|
||||||
|
sdf = sdCircle(st, vec2(0.5));
|
||||||
|
sdf = strokeAA(sdf, 0.58, 0.02, sdfCircle) * 4.0;
|
||||||
|
} else if (VAR == 3) {
|
||||||
|
sdf = sdPoly(st - vec2(0.5, 0.45), 0.3, 3);
|
||||||
|
sdf = fill(sdf, 0.05, sdfCircle) * 1.4;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 color = vec3(1.0);
|
||||||
|
float alpha = sdf;
|
||||||
|
gl_FragColor = vec4(color.rgb, alpha);
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
const onPointerMove = (e: PointerEvent | MouseEvent) => {
|
||||||
|
const mount = shapeBlurContainer.value;
|
||||||
|
if (!mount) return;
|
||||||
|
const rect = mount.getBoundingClientRect();
|
||||||
|
vMouse.set(e.clientX - rect.left, e.clientY - rect.top);
|
||||||
|
};
|
||||||
|
|
||||||
|
const resize = () => {
|
||||||
|
const container = shapeBlurContainer.value;
|
||||||
|
if (!container) return;
|
||||||
|
|
||||||
|
w = container.clientWidth;
|
||||||
|
h = container.clientHeight;
|
||||||
|
const dpr = Math.min(window.devicePixelRatio || 1, 2);
|
||||||
|
|
||||||
|
renderer.setSize(w, h, false);
|
||||||
|
renderer.setPixelRatio(dpr);
|
||||||
|
|
||||||
|
camera.left = -w / 2;
|
||||||
|
camera.right = w / 2;
|
||||||
|
camera.top = h / 2;
|
||||||
|
camera.bottom = -h / 2;
|
||||||
|
camera.updateProjectionMatrix();
|
||||||
|
|
||||||
|
quad.scale.set(w, h, 1);
|
||||||
|
vResolution.set(w, h).multiplyScalar(dpr);
|
||||||
|
material.uniforms.u_pixelRatio.value = dpr;
|
||||||
|
};
|
||||||
|
|
||||||
|
const update = () => {
|
||||||
|
time = performance.now() * 0.001;
|
||||||
|
const dt = time - lastTime;
|
||||||
|
lastTime = time;
|
||||||
|
|
||||||
|
vMouseDamp.x = THREE.MathUtils.damp(vMouseDamp.x, vMouse.x, 8, dt);
|
||||||
|
vMouseDamp.y = THREE.MathUtils.damp(vMouseDamp.y, vMouse.y, 8, dt);
|
||||||
|
|
||||||
|
renderer.render(scene, camera);
|
||||||
|
animationFrameId = requestAnimationFrame(update);
|
||||||
|
};
|
||||||
|
|
||||||
|
const initShapeBlur = () => {
|
||||||
|
const mount = shapeBlurContainer.value;
|
||||||
|
if (!mount) return;
|
||||||
|
|
||||||
|
scene = new THREE.Scene();
|
||||||
|
camera = new THREE.OrthographicCamera();
|
||||||
|
camera.position.z = 1;
|
||||||
|
|
||||||
|
renderer = new THREE.WebGLRenderer({ alpha: true });
|
||||||
|
renderer.setClearColor(0x000000, 0);
|
||||||
|
renderer.domElement.style.width = '100%';
|
||||||
|
renderer.domElement.style.height = '100%';
|
||||||
|
renderer.domElement.style.display = 'block';
|
||||||
|
mount.appendChild(renderer.domElement);
|
||||||
|
|
||||||
|
const geo = new THREE.PlaneGeometry(1, 1);
|
||||||
|
material = new THREE.ShaderMaterial({
|
||||||
|
vertexShader,
|
||||||
|
fragmentShader,
|
||||||
|
uniforms: {
|
||||||
|
u_mouse: { value: vMouseDamp },
|
||||||
|
u_resolution: { value: vResolution },
|
||||||
|
u_pixelRatio: { value: props.pixelRatioProp },
|
||||||
|
u_shapeSize: { value: props.shapeSize },
|
||||||
|
u_roundness: { value: props.roundness },
|
||||||
|
u_borderSize: { value: props.borderSize },
|
||||||
|
u_circleSize: { value: props.circleSize },
|
||||||
|
u_circleEdge: { value: props.circleEdge }
|
||||||
|
},
|
||||||
|
defines: { VAR: props.variation },
|
||||||
|
transparent: true
|
||||||
|
});
|
||||||
|
|
||||||
|
quad = new THREE.Mesh(geo, material);
|
||||||
|
scene.add(quad);
|
||||||
|
|
||||||
|
document.addEventListener('mousemove', onPointerMove);
|
||||||
|
document.addEventListener('pointermove', onPointerMove);
|
||||||
|
|
||||||
|
resize();
|
||||||
|
|
||||||
|
if (typeof ResizeObserver !== 'undefined') {
|
||||||
|
resizeObserver = new ResizeObserver(resize);
|
||||||
|
resizeObserver.observe(mount);
|
||||||
|
} else {
|
||||||
|
window.addEventListener('resize', resize);
|
||||||
|
}
|
||||||
|
|
||||||
|
update();
|
||||||
|
};
|
||||||
|
|
||||||
|
const cleanup = () => {
|
||||||
|
if (animationFrameId) {
|
||||||
|
cancelAnimationFrame(animationFrameId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resizeObserver) {
|
||||||
|
resizeObserver.disconnect();
|
||||||
|
} else {
|
||||||
|
window.removeEventListener('resize', resize);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.removeEventListener('mousemove', onPointerMove);
|
||||||
|
document.removeEventListener('pointermove', onPointerMove);
|
||||||
|
|
||||||
|
const mount = shapeBlurContainer.value;
|
||||||
|
if (mount && renderer) {
|
||||||
|
mount.removeChild(renderer.domElement);
|
||||||
|
renderer.dispose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
watch(
|
||||||
|
() => [
|
||||||
|
props.variation,
|
||||||
|
props.pixelRatioProp,
|
||||||
|
props.shapeSize,
|
||||||
|
props.roundness,
|
||||||
|
props.borderSize,
|
||||||
|
props.circleSize,
|
||||||
|
props.circleEdge
|
||||||
|
],
|
||||||
|
() => {
|
||||||
|
if (material) {
|
||||||
|
material.uniforms.u_pixelRatio.value = props.pixelRatioProp;
|
||||||
|
material.uniforms.u_shapeSize.value = props.shapeSize;
|
||||||
|
material.uniforms.u_roundness.value = props.roundness;
|
||||||
|
material.uniforms.u_borderSize.value = props.borderSize;
|
||||||
|
material.uniforms.u_circleSize.value = props.circleSize;
|
||||||
|
material.uniforms.u_circleEdge.value = props.circleEdge;
|
||||||
|
material.defines.VAR = props.variation;
|
||||||
|
material.needsUpdate = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{ deep: true }
|
||||||
|
);
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
initShapeBlur();
|
||||||
|
});
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
cleanup();
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.shape-blur-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.shape-blur-container :deep(canvas) {
|
||||||
|
width: 100% !important;
|
||||||
|
height: 100% !important;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
129
src/demo/Backgrounds/ShapeBlurDemo.vue
Normal file
129
src/demo/Backgrounds/ShapeBlurDemo.vue
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
<template>
|
||||||
|
<div class="shape-blur-demo">
|
||||||
|
<TabbedLayout>
|
||||||
|
<template #preview>
|
||||||
|
<div class="demo-container">
|
||||||
|
<ShapeBlur
|
||||||
|
:variation="0"
|
||||||
|
:pixel-ratio-prop="pixelRatioProp"
|
||||||
|
:shape-size="shapeSize"
|
||||||
|
:roundness="roundness"
|
||||||
|
:border-size="borderSize"
|
||||||
|
:circle-size="circleSize"
|
||||||
|
:circle-edge="circleEdge"
|
||||||
|
class="shapeblur-demo"
|
||||||
|
/>
|
||||||
|
<div class="hover-text">Hover Me.</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Customize>
|
||||||
|
<PreviewSlider title="Shape Size" v-model="shapeSize" :min="0.1" :max="2" :step="0.1" />
|
||||||
|
|
||||||
|
<PreviewSlider title="Roundness" v-model="roundness" :min="0" :max="1" :step="0.05" />
|
||||||
|
|
||||||
|
<PreviewSlider title="Border Size" v-model="borderSize" :min="0.01" :max="0.2" :step="0.005" />
|
||||||
|
|
||||||
|
<PreviewSlider title="Circle Size" v-model="circleSize" :min="0.1" :max="0.5" :step="0.01" />
|
||||||
|
|
||||||
|
<PreviewSlider title="Circle Edge" v-model="circleEdge" :min="0.1" :max="2" :step="0.1" />
|
||||||
|
</Customize>
|
||||||
|
|
||||||
|
<PropTable :data="propData" />
|
||||||
|
|
||||||
|
<Dependencies :dependency-list="['three']" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #code>
|
||||||
|
<CodeExample :code-object="shapeBlur" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #cli>
|
||||||
|
<CliInstallation :command="shapeBlur.cli" />
|
||||||
|
</template>
|
||||||
|
</TabbedLayout>
|
||||||
|
</div>
|
||||||
|
</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 ShapeBlur from '../../content/Backgrounds/ShapeBlur/ShapeBlur.vue';
|
||||||
|
import { shapeBlur } from '@/constants/code/Backgrounds/shapeBlurCode';
|
||||||
|
|
||||||
|
const pixelRatioProp = ref(window.devicePixelRatio || 1);
|
||||||
|
const shapeSize = ref(1.0);
|
||||||
|
const roundness = ref(0.5);
|
||||||
|
const borderSize = ref(0.05);
|
||||||
|
const circleSize = ref(0.25);
|
||||||
|
const circleEdge = ref(1);
|
||||||
|
|
||||||
|
const propData = [
|
||||||
|
{
|
||||||
|
name: 'variation',
|
||||||
|
type: 'number',
|
||||||
|
default: '0',
|
||||||
|
description: 'Selects the shape variation (0-3) used by the shader.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'pixelRatioProp',
|
||||||
|
type: 'number',
|
||||||
|
default: '2',
|
||||||
|
description: 'Overrides the pixel ratio, typically set to the device pixel ratio.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'shapeSize',
|
||||||
|
type: 'number',
|
||||||
|
default: '1.2',
|
||||||
|
description: 'Controls the size of the shape.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'roundness',
|
||||||
|
type: 'number',
|
||||||
|
default: '0.4',
|
||||||
|
description: "Determines the roundness of the shape's corners."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'borderSize',
|
||||||
|
type: 'number',
|
||||||
|
default: '0.05',
|
||||||
|
description: 'Sets the thickness of the border.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'circleSize',
|
||||||
|
type: 'number',
|
||||||
|
default: '0.3',
|
||||||
|
description: 'Determines the size of the hover circle effect.'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'circleEdge',
|
||||||
|
type: 'number',
|
||||||
|
default: '0.5',
|
||||||
|
description: 'Controls the edge softness of the hover circle.'
|
||||||
|
}
|
||||||
|
];
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.hover-text {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
top: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
font-size: 6rem;
|
||||||
|
font-weight: 900;
|
||||||
|
z-index: 0;
|
||||||
|
color: #222;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.demo-container {
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user