增加背景样式种类
This commit is contained in:
+56
-11
@@ -1,15 +1,20 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { ref, onMounted } from 'vue'
|
import { ref, onMounted, computed } from 'vue'
|
||||||
import PromptEditor from './components/PromptEditor.vue'
|
import PromptEditor from './components/PromptEditor.vue'
|
||||||
import PromptManager from './components/PromptManager.vue'
|
import PromptManager from './components/PromptManager.vue'
|
||||||
import PresetManager from './components/PresetManager.vue'
|
import PresetManager from './components/PresetManager.vue'
|
||||||
import BackgroundCanvas from './components/BackgroundCanvas.vue'
|
import BackgroundCanvas from './components/Background/BackgroundCanvas.vue'
|
||||||
|
import GradientBackground from './components/Background/GradientBackground.vue'
|
||||||
|
import GridBackground from './components/Background/GridBackground.vue'
|
||||||
import DevtoolsBanner from './components/DevtoolsBanner.vue'
|
import DevtoolsBanner from './components/DevtoolsBanner.vue'
|
||||||
import { usePromptStore } from './stores/promptStore'
|
import { usePromptStore } from './stores/promptStore'
|
||||||
|
|
||||||
const currentView = ref<'editor' | 'manager' | 'presets'>('editor')
|
const currentView = ref<'editor' | 'manager' | 'presets'>('editor')
|
||||||
const isDark = ref(false)
|
const isDark = ref(false)
|
||||||
const showBackground = ref(true)
|
const bgModes = ['particles', 'grid', 'gradient', 'off'] as const
|
||||||
|
type BgMode = typeof bgModes[number]
|
||||||
|
const currentBgMode = ref<BgMode>('particles')
|
||||||
|
|
||||||
const store = usePromptStore()
|
const store = usePromptStore()
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
@@ -19,8 +24,19 @@ onMounted(() => {
|
|||||||
updateTheme()
|
updateTheme()
|
||||||
// 初始化词库与编辑器状态(仅一次)
|
// 初始化词库与编辑器状态(仅一次)
|
||||||
store.initialize()
|
store.initialize()
|
||||||
const bg = localStorage.getItem('bg.enabled')
|
|
||||||
showBackground.value = bg === null ? true : bg === 'on'
|
// Initialize background mode
|
||||||
|
const savedMode = localStorage.getItem('bg.mode') as BgMode | null
|
||||||
|
const legacyBg = localStorage.getItem('bg.enabled')
|
||||||
|
|
||||||
|
if (savedMode && bgModes.includes(savedMode)) {
|
||||||
|
currentBgMode.value = savedMode
|
||||||
|
} else if (legacyBg !== null) {
|
||||||
|
// Migrate legacy setting
|
||||||
|
currentBgMode.value = legacyBg === 'on' ? 'particles' : 'off'
|
||||||
|
} else {
|
||||||
|
currentBgMode.value = 'particles'
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
function toggleTheme() {
|
function toggleTheme() {
|
||||||
@@ -37,15 +53,32 @@ function switchView(view: 'editor' | 'manager' | 'presets') {
|
|||||||
currentView.value = view
|
currentView.value = view
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleBackground() {
|
function cycleBackground() {
|
||||||
showBackground.value = !showBackground.value
|
const currentIndex = bgModes.indexOf(currentBgMode.value)
|
||||||
localStorage.setItem('bg.enabled', showBackground.value ? 'on' : 'off')
|
const nextIndex = (currentIndex + 1) % bgModes.length
|
||||||
|
const nextMode = bgModes[nextIndex]
|
||||||
|
if (nextMode) {
|
||||||
|
currentBgMode.value = nextMode
|
||||||
|
localStorage.setItem('bg.mode', currentBgMode.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bgModeLabel = computed(() => {
|
||||||
|
switch (currentBgMode.value) {
|
||||||
|
case 'particles': return '粒子特效'
|
||||||
|
case 'grid': return '网格特效'
|
||||||
|
case 'gradient': return '渐变特效'
|
||||||
|
case 'off': return '关闭背景'
|
||||||
|
default: return ''
|
||||||
|
}
|
||||||
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="app-container" :class="{ dark: isDark }">
|
<div class="app-container" :class="{ dark: isDark }">
|
||||||
<BackgroundCanvas v-if="showBackground" />
|
<BackgroundCanvas v-if="currentBgMode === 'particles'" />
|
||||||
|
<GridBackground v-else-if="currentBgMode === 'grid'" />
|
||||||
|
<GradientBackground v-else-if="currentBgMode === 'gradient'" />
|
||||||
<DevtoolsBanner />
|
<DevtoolsBanner />
|
||||||
<!-- 顶部导航栏 -->
|
<!-- 顶部导航栏 -->
|
||||||
<header class="app-header">
|
<header class="app-header">
|
||||||
@@ -112,13 +145,25 @@ function toggleBackground() {
|
|||||||
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
<button class="bg-toggle" :class="{ active: showBackground }" @click="toggleBackground" title="背景开关">
|
<button class="bg-toggle" :class="{ active: currentBgMode !== 'off' }" @click="cycleBackground" :title="bgModeLabel">
|
||||||
<svg v-if="showBackground" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<!-- Particles Icon -->
|
||||||
|
<svg v-if="currentBgMode === 'particles'" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<circle cx="6" cy="12" r="1.5" fill="currentColor"/>
|
<circle cx="6" cy="12" r="1.5" fill="currentColor"/>
|
||||||
<circle cx="12" cy="9" r="1.5" fill="currentColor"/>
|
<circle cx="12" cy="9" r="1.5" fill="currentColor"/>
|
||||||
<circle cx="18" cy="13" r="1.5" fill="currentColor"/>
|
<circle cx="18" cy="13" r="1.5" fill="currentColor"/>
|
||||||
<path d="M4 16c4-2 8-2 12 0" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
<path d="M4 16c4-2 8-2 12 0" stroke="currentColor" stroke-width="1.5" stroke-linecap="round"/>
|
||||||
</svg>
|
</svg>
|
||||||
|
<!-- Grid Icon -->
|
||||||
|
<svg v-else-if="currentBgMode === 'grid'" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M3 3h18v18H3z" stroke="currentColor" stroke-width="2"/>
|
||||||
|
<path d="M3 9h18M3 15h18M9 3v18M15 3v18" stroke="currentColor" stroke-width="2"/>
|
||||||
|
</svg>
|
||||||
|
<!-- Gradient Icon -->
|
||||||
|
<svg v-else-if="currentBgMode === 'gradient'" width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="2"/>
|
||||||
|
<path d="M8 12s1.5-2 4-2 4 2 4 2" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
|
</svg>
|
||||||
|
<!-- Off Icon -->
|
||||||
<svg v-else width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
<svg v-else width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
<path d="M5 5l14 14" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
<path d="M5 5l14 14" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>
|
||||||
<circle cx="12" cy="12" r="6" stroke="currentColor" stroke-width="2"/>
|
<circle cx="12" cy="12" r="6" stroke="currentColor" stroke-width="2"/>
|
||||||
|
|||||||
@@ -0,0 +1,206 @@
|
|||||||
|
<template>
|
||||||
|
<canvas ref="canvas" class="bg-gradient"></canvas>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||||
|
|
||||||
|
const canvas = ref<HTMLCanvasElement | null>(null)
|
||||||
|
let ctx: CanvasRenderingContext2D | null = null
|
||||||
|
let width = 0
|
||||||
|
let height = 0
|
||||||
|
let raf = 0
|
||||||
|
let running = true
|
||||||
|
|
||||||
|
// Mouse interaction
|
||||||
|
const mouse = { x: 0, y: 0, tx: 0, ty: 0 }
|
||||||
|
|
||||||
|
function parseColor(c: string): [number, number, number] {
|
||||||
|
if (!c) return [0, 0, 0]
|
||||||
|
if (c.startsWith('#')) {
|
||||||
|
const v = c.slice(1)
|
||||||
|
const n = v.length === 3 ? v.split('').map(ch => ch + ch).join('') : v
|
||||||
|
const r = parseInt(n.slice(0, 2), 16)
|
||||||
|
const g = parseInt(n.slice(2, 4), 16)
|
||||||
|
const b = parseInt(n.slice(4, 6), 16)
|
||||||
|
return [r, g, b]
|
||||||
|
}
|
||||||
|
return [255, 255, 255]
|
||||||
|
}
|
||||||
|
|
||||||
|
function getThemeColors() {
|
||||||
|
const cs = getComputedStyle(document.documentElement)
|
||||||
|
const accent = parseColor(cs.getPropertyValue('--color-accent').trim())
|
||||||
|
const primary = parseColor(cs.getPropertyValue('--color-bg-primary').trim())
|
||||||
|
|
||||||
|
return { accent, primary }
|
||||||
|
}
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
if (!canvas.value) return
|
||||||
|
width = window.innerWidth
|
||||||
|
height = window.innerHeight
|
||||||
|
canvas.value.width = width
|
||||||
|
canvas.value.height = height
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mesh points
|
||||||
|
interface Point {
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
originX: number
|
||||||
|
originY: number
|
||||||
|
noiseOffsetX: number
|
||||||
|
noiseOffsetY: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const points: Point[] = []
|
||||||
|
const gridSize = 100 // Size of mesh cells
|
||||||
|
|
||||||
|
function initMesh() {
|
||||||
|
points.length = 0
|
||||||
|
const cols = Math.ceil(width / gridSize) + 2
|
||||||
|
const rows = Math.ceil(height / gridSize) + 2
|
||||||
|
|
||||||
|
for (let i = 0; i < cols; i++) {
|
||||||
|
for (let j = 0; j < rows; j++) {
|
||||||
|
const x = (i - 1) * gridSize
|
||||||
|
const y = (j - 1) * gridSize
|
||||||
|
points.push({
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
originX: x,
|
||||||
|
originY: y,
|
||||||
|
noiseOffsetX: Math.random() * 1000,
|
||||||
|
noiseOffsetY: Math.random() * 1000
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
if (!ctx) return
|
||||||
|
|
||||||
|
ctx.clearRect(0, 0, width, height)
|
||||||
|
|
||||||
|
// Smooth mouse
|
||||||
|
mouse.x += (mouse.tx - mouse.x) * 0.05
|
||||||
|
mouse.y += (mouse.ty - mouse.y) * 0.05
|
||||||
|
|
||||||
|
const time = performance.now() / 2000
|
||||||
|
const { accent, primary } = getThemeColors()
|
||||||
|
|
||||||
|
// Update points
|
||||||
|
points.forEach(p => {
|
||||||
|
// Simplex-like noise movement (simplified with sine/cos)
|
||||||
|
const noiseX = Math.sin(time + p.noiseOffsetX) * 30
|
||||||
|
const noiseY = Math.cos(time + p.noiseOffsetY) * 30
|
||||||
|
|
||||||
|
// Mouse influence (gentle push)
|
||||||
|
const dx = mouse.x - p.originX
|
||||||
|
const dy = mouse.y - p.originY
|
||||||
|
const dist = Math.sqrt(dx*dx + dy*dy)
|
||||||
|
const maxDist = 400
|
||||||
|
let mouseX = 0
|
||||||
|
let mouseY = 0
|
||||||
|
|
||||||
|
if (dist < maxDist) {
|
||||||
|
const force = Math.pow(1 - dist / maxDist, 2) * 40
|
||||||
|
const angle = Math.atan2(dy, dx)
|
||||||
|
mouseX = Math.cos(angle) * force
|
||||||
|
mouseY = Math.sin(angle) * force
|
||||||
|
}
|
||||||
|
|
||||||
|
p.x = p.originX + noiseX - mouseX
|
||||||
|
p.y = p.originY + noiseY - mouseY
|
||||||
|
})
|
||||||
|
|
||||||
|
// Draw mesh
|
||||||
|
ctx.lineWidth = 1
|
||||||
|
// Create gradient for lines
|
||||||
|
const gradient = ctx.createLinearGradient(0, 0, width, height)
|
||||||
|
gradient.addColorStop(0, `rgba(${accent[0]}, ${accent[1]}, ${accent[2]}, 0.05)`)
|
||||||
|
gradient.addColorStop(0.5, `rgba(${accent[0]}, ${accent[1]}, ${accent[2]}, 0.1)`)
|
||||||
|
gradient.addColorStop(1, `rgba(${accent[0]}, ${accent[1]}, ${accent[2]}, 0.05)`)
|
||||||
|
|
||||||
|
ctx.strokeStyle = gradient
|
||||||
|
|
||||||
|
const cols = Math.ceil(width / gridSize) + 2
|
||||||
|
const rows = Math.ceil(height / gridSize) + 2
|
||||||
|
|
||||||
|
// Draw connections
|
||||||
|
ctx.beginPath()
|
||||||
|
for (let i = 0; i < cols; i++) {
|
||||||
|
for (let j = 0; j < rows; j++) {
|
||||||
|
const index = i * rows + j
|
||||||
|
const p = points[index]
|
||||||
|
|
||||||
|
if (i < cols - 1) {
|
||||||
|
const right = points[(i + 1) * rows + j]
|
||||||
|
if (p) ctx.moveTo(p.x, p.y)
|
||||||
|
if (right) ctx.lineTo(right.x, right.y)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (j < rows - 1) {
|
||||||
|
const bottom = points[i * rows + (j + 1)]
|
||||||
|
if (p) ctx.moveTo(p.x, p.y)
|
||||||
|
if (bottom) ctx.lineTo(bottom.x, bottom.y)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.stroke()
|
||||||
|
|
||||||
|
// Fill subtle gradient background
|
||||||
|
const bgGradient = ctx.createRadialGradient(
|
||||||
|
mouse.x, mouse.y, 0,
|
||||||
|
mouse.x, mouse.y, Math.max(width, height)
|
||||||
|
)
|
||||||
|
bgGradient.addColorStop(0, `rgba(${accent[0]}, ${accent[1]}, ${accent[2]}, 0.03)`)
|
||||||
|
bgGradient.addColorStop(1, 'rgba(0,0,0,0)')
|
||||||
|
|
||||||
|
ctx.fillStyle = bgGradient
|
||||||
|
ctx.fillRect(0, 0, width, height)
|
||||||
|
}
|
||||||
|
|
||||||
|
function loop() {
|
||||||
|
if (!running) return
|
||||||
|
draw()
|
||||||
|
raf = requestAnimationFrame(loop)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseMove(e: MouseEvent) {
|
||||||
|
mouse.tx = e.clientX
|
||||||
|
mouse.ty = e.clientY
|
||||||
|
}
|
||||||
|
|
||||||
|
function onResize() {
|
||||||
|
resize()
|
||||||
|
initMesh()
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (!canvas.value) return
|
||||||
|
ctx = canvas.value.getContext('2d')
|
||||||
|
resize()
|
||||||
|
initMesh()
|
||||||
|
window.addEventListener('resize', onResize)
|
||||||
|
window.addEventListener('mousemove', onMouseMove)
|
||||||
|
raf = requestAnimationFrame(loop)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
running = false
|
||||||
|
cancelAnimationFrame(raf)
|
||||||
|
window.removeEventListener('resize', onResize)
|
||||||
|
window.removeEventListener('mousemove', onMouseMove)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.bg-gradient {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -0,0 +1,153 @@
|
|||||||
|
<template>
|
||||||
|
<canvas ref="canvas" class="bg-grid"></canvas>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { ref, onMounted, onBeforeUnmount } from 'vue'
|
||||||
|
|
||||||
|
const canvas = ref<HTMLCanvasElement | null>(null)
|
||||||
|
let ctx: CanvasRenderingContext2D | null = null
|
||||||
|
let width = 0
|
||||||
|
let height = 0
|
||||||
|
let raf = 0
|
||||||
|
let running = true
|
||||||
|
|
||||||
|
// Mouse interaction
|
||||||
|
const mouse = { x: 0, y: 0, tx: 0, ty: 0 }
|
||||||
|
|
||||||
|
// Grid properties
|
||||||
|
const gridSize = 50 // Increased grid size for cleaner look
|
||||||
|
let offset = 0
|
||||||
|
|
||||||
|
function parseColor(c: string): [number, number, number] {
|
||||||
|
if (!c) return [0, 0, 0]
|
||||||
|
if (c.startsWith('#')) {
|
||||||
|
const v = c.slice(1)
|
||||||
|
const n = v.length === 3 ? v.split('').map(ch => ch + ch).join('') : v
|
||||||
|
const r = parseInt(n.slice(0, 2), 16)
|
||||||
|
const g = parseInt(n.slice(2, 4), 16)
|
||||||
|
const b = parseInt(n.slice(4, 6), 16)
|
||||||
|
return [r, g, b]
|
||||||
|
}
|
||||||
|
return [255, 255, 255]
|
||||||
|
}
|
||||||
|
|
||||||
|
function getThemeColors() {
|
||||||
|
const cs = getComputedStyle(document.documentElement)
|
||||||
|
const accent = parseColor(cs.getPropertyValue('--color-accent').trim())
|
||||||
|
const text = parseColor(cs.getPropertyValue('--color-text-primary').trim())
|
||||||
|
|
||||||
|
return { accent, text }
|
||||||
|
}
|
||||||
|
|
||||||
|
function resize() {
|
||||||
|
if (!canvas.value) return
|
||||||
|
width = window.innerWidth
|
||||||
|
height = window.innerHeight
|
||||||
|
canvas.value.width = width
|
||||||
|
canvas.value.height = height
|
||||||
|
}
|
||||||
|
|
||||||
|
function draw() {
|
||||||
|
if (!ctx) return
|
||||||
|
|
||||||
|
// Clear canvas
|
||||||
|
ctx.clearRect(0, 0, width, height)
|
||||||
|
|
||||||
|
// Smooth mouse
|
||||||
|
mouse.x += (mouse.tx - mouse.x) * 0.1
|
||||||
|
mouse.y += (mouse.ty - mouse.y) * 0.1
|
||||||
|
|
||||||
|
const { accent, text } = getThemeColors()
|
||||||
|
const time = performance.now() / 1000
|
||||||
|
|
||||||
|
// Moving grid effect
|
||||||
|
offset = (time * 20) % gridSize // Slower movement
|
||||||
|
|
||||||
|
ctx.lineWidth = 1
|
||||||
|
|
||||||
|
// Draw vertical lines
|
||||||
|
for (let x = 0; x <= width; x += gridSize) {
|
||||||
|
const dx = x - mouse.x
|
||||||
|
const dist = Math.abs(dx)
|
||||||
|
const maxDist = 400
|
||||||
|
|
||||||
|
let drawX = x
|
||||||
|
let alpha = 0.03 // Very subtle base opacity
|
||||||
|
|
||||||
|
if (dist < maxDist) {
|
||||||
|
const force = Math.cos((dist / maxDist) * Math.PI / 2)
|
||||||
|
drawX += (dx > 0 ? 1 : -1) * force * 15
|
||||||
|
alpha += force * 0.08 // Subtle highlight
|
||||||
|
}
|
||||||
|
|
||||||
|
const [r, g, b] = x % (gridSize * 4) === 0 ? accent : text
|
||||||
|
ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${alpha})`
|
||||||
|
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(drawX, 0)
|
||||||
|
ctx.lineTo(drawX, height)
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw horizontal lines
|
||||||
|
for (let y = offset; y <= height; y += gridSize) {
|
||||||
|
const dy = y - mouse.y
|
||||||
|
const dist = Math.abs(dy)
|
||||||
|
const maxDist = 400
|
||||||
|
|
||||||
|
let drawY = y
|
||||||
|
let alpha = 0.03
|
||||||
|
|
||||||
|
if (dist < maxDist) {
|
||||||
|
const force = Math.cos((dist / maxDist) * Math.PI / 2)
|
||||||
|
drawY += (dy > 0 ? 1 : -1) * force * 15
|
||||||
|
alpha += force * 0.08
|
||||||
|
}
|
||||||
|
|
||||||
|
const [r, g, b] = Math.abs(y - offset) % (gridSize * 4) < 1 ? accent : text
|
||||||
|
ctx.strokeStyle = `rgba(${r}, ${g}, ${b}, ${alpha})`
|
||||||
|
|
||||||
|
ctx.beginPath()
|
||||||
|
ctx.moveTo(0, drawY)
|
||||||
|
ctx.lineTo(width, drawY)
|
||||||
|
ctx.stroke()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function loop() {
|
||||||
|
if (!running) return
|
||||||
|
draw()
|
||||||
|
raf = requestAnimationFrame(loop)
|
||||||
|
}
|
||||||
|
|
||||||
|
function onMouseMove(e: MouseEvent) {
|
||||||
|
mouse.tx = e.clientX
|
||||||
|
mouse.ty = e.clientY
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
if (!canvas.value) return
|
||||||
|
ctx = canvas.value.getContext('2d')
|
||||||
|
resize()
|
||||||
|
window.addEventListener('resize', resize)
|
||||||
|
window.addEventListener('mousemove', onMouseMove)
|
||||||
|
raf = requestAnimationFrame(loop)
|
||||||
|
})
|
||||||
|
|
||||||
|
onBeforeUnmount(() => {
|
||||||
|
running = false
|
||||||
|
cancelAnimationFrame(raf)
|
||||||
|
window.removeEventListener('resize', resize)
|
||||||
|
window.removeEventListener('mousemove', onMouseMove)
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.bg-grid {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user