docs(app): improve stars lazy loading

This commit is contained in:
Benjamin Canac
2025-03-19 14:54:14 +01:00
parent fd160339a6
commit edb0f0afc6
8 changed files with 88 additions and 65 deletions

View File

@@ -1,4 +1,6 @@
<script setup lang="ts">
import { kebabCase } from 'scule'
interface Star {
x: number
y: number
@@ -22,6 +24,8 @@ const props = withDefaults(defineProps<{
speed: 'normal'
})
const route = useRoute()
// Generate random stars
const generateStars = (count: number): Star[] => {
return Array.from({ length: count }, () => {
@@ -35,7 +39,7 @@ const generateStars = (count: number): Star[] => {
}
// Generate all stars
const stars = ref<Star[]>(generateStars(props.starCount))
const stars = useState<Star[]>(`${kebabCase(route.path)}-sky`, () => generateStars(props.starCount))
// Compute twinkle animation duration based on speed
const twinkleDuration = computed(() => {
@@ -50,22 +54,20 @@ const twinkleDuration = computed(() => {
<template>
<div class="absolute pointer-events-none z-[-1] inset-y-0 left-4 right-4 lg:right-[50%] overflow-hidden">
<ClientOnly>
<div
v-for="star in stars"
:key="star.id"
class="star absolute"
:style="{
'left': `${star.x}%`,
'top': `${star.y}%`,
'transform': 'translate(-50%, -50%)',
'--star-size': `${star.size}px`,
'--star-color': color,
'--twinkle-delay': `${star.twinkleDelay}s`,
'--twinkle-duration': twinkleDuration
}"
/>
</ClientOnly>
<div
v-for="star in stars"
:key="star.id"
class="star absolute"
:style="{
'left': `${star.x}%`,
'top': `${star.y}%`,
'transform': 'translate(-50%, -50%)',
'--star-size': `${star.size}px`,
'--star-color': color,
'--twinkle-delay': `${star.twinkleDelay}s`,
'--twinkle-duration': twinkleDuration
}"
/>
</div>
</template>

View File

@@ -1,4 +1,12 @@
<script setup lang="ts">
import { kebabCase } from 'scule'
interface Star {
x: number
y: number
size: number
}
const props = withDefaults(defineProps<{
starCount?: number
color?: string
@@ -14,8 +22,10 @@ const props = withDefaults(defineProps<{
})
})
const route = useRoute()
// Generate random star positions and sizes
const generateStars = (count: number) => {
const generateStars = (count: number): Star[] => {
return Array.from({ length: count }, () => ({
x: Math.floor(Math.random() * 2000),
y: Math.floor(Math.random() * 2000),
@@ -25,52 +35,58 @@ const generateStars = (count: number) => {
}))
}
// Compute star layers with different speeds and opacities
const starLayers = computed(() => {
const speedMap = {
slow: { duration: 200, opacity: 0.5 },
normal: { duration: 150, opacity: 0.75 },
fast: { duration: 100, opacity: 1 }
}
// Define speed configurations once
const speedMap = {
slow: { duration: 200, opacity: 0.5, ratio: 0.3 },
normal: { duration: 150, opacity: 0.75, ratio: 0.3 },
fast: { duration: 100, opacity: 1, ratio: 0.4 }
}
return [
{ stars: generateStars(props.starCount), ...speedMap.fast },
{ stars: generateStars(Math.floor(props.starCount * 0.6)), ...speedMap.normal },
{ stars: generateStars(Math.floor(props.starCount * 0.3)), ...speedMap.slow }
]
// Use a more efficient approach to generate and store stars
const stars = useState<{ slow: Star[], normal: Star[], fast: Star[] }>(`${kebabCase(route.path)}-stars`, () => {
return {
slow: generateStars(Math.floor(props.starCount * speedMap.slow.ratio)),
normal: generateStars(Math.floor(props.starCount * speedMap.normal.ratio)),
fast: generateStars(Math.floor(props.starCount * speedMap.fast.ratio))
}
})
// Compute star layers with different speeds and opacities
const starLayers = computed(() => [
{ stars: stars.value.fast, ...speedMap.fast },
{ stars: stars.value.normal, ...speedMap.normal },
{ stars: stars.value.slow, ...speedMap.slow }
])
</script>
<template>
<div class="absolute pointer-events-none z-[-1] inset-y-0 inset-x-5 sm:inset-x-7 lg:inset-x-9 overflow-hidden">
<ClientOnly>
<div class="stars size-full absolute inset-x-0 top-0">
<div class="stars size-full absolute inset-x-0 top-0">
<div
v-for="(layer, index) in starLayers"
:key="index"
class="star-layer"
:style="{
'--star-duration': `${layer.duration}s`,
'--star-opacity': layer.opacity,
'--star-color': color
}"
>
<div
v-for="(layer, index) in starLayers"
:key="index"
class="star-layer"
v-for="(star, starIndex) in layer.stars"
:key="starIndex"
class="star absolute rounded-full"
:style="{
'--star-duration': `${layer.duration}s`,
'--star-opacity': layer.opacity,
'--star-color': color
left: `${star.x}px`,
top: `${star.y}px`,
width: `${star.size}px`,
height: `${star.size}px`,
backgroundColor: 'var(--star-color)',
opacity: 'var(--star-opacity)'
}"
>
<div
v-for="(star, starIndex) in layer.stars"
:key="starIndex"
class="star absolute rounded-full"
:style="{
left: `${star.x}px`,
top: `${star.y}px`,
width: `${star.size}px`,
height: `${star.size}px`,
backgroundColor: 'var(--star-color)',
opacity: 'var(--star-opacity)'
}"
/>
</div>
/>
</div>
</ClientOnly>
</div>
</div>
</template>