mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-02-06 07:03:51 +01:00
docs(app): improve stars lazy loading
This commit is contained in:
@@ -1,4 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { kebabCase } from 'scule'
|
||||||
|
|
||||||
interface Star {
|
interface Star {
|
||||||
x: number
|
x: number
|
||||||
y: number
|
y: number
|
||||||
@@ -22,6 +24,8 @@ const props = withDefaults(defineProps<{
|
|||||||
speed: 'normal'
|
speed: 'normal'
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
// Generate random stars
|
// Generate random stars
|
||||||
const generateStars = (count: number): Star[] => {
|
const generateStars = (count: number): Star[] => {
|
||||||
return Array.from({ length: count }, () => {
|
return Array.from({ length: count }, () => {
|
||||||
@@ -35,7 +39,7 @@ const generateStars = (count: number): Star[] => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate all stars
|
// 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
|
// Compute twinkle animation duration based on speed
|
||||||
const twinkleDuration = computed(() => {
|
const twinkleDuration = computed(() => {
|
||||||
@@ -50,22 +54,20 @@ const twinkleDuration = computed(() => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="absolute pointer-events-none z-[-1] inset-y-0 left-4 right-4 lg:right-[50%] overflow-hidden">
|
<div class="absolute pointer-events-none z-[-1] inset-y-0 left-4 right-4 lg:right-[50%] overflow-hidden">
|
||||||
<ClientOnly>
|
<div
|
||||||
<div
|
v-for="star in stars"
|
||||||
v-for="star in stars"
|
:key="star.id"
|
||||||
:key="star.id"
|
class="star absolute"
|
||||||
class="star absolute"
|
:style="{
|
||||||
:style="{
|
'left': `${star.x}%`,
|
||||||
'left': `${star.x}%`,
|
'top': `${star.y}%`,
|
||||||
'top': `${star.y}%`,
|
'transform': 'translate(-50%, -50%)',
|
||||||
'transform': 'translate(-50%, -50%)',
|
'--star-size': `${star.size}px`,
|
||||||
'--star-size': `${star.size}px`,
|
'--star-color': color,
|
||||||
'--star-color': color,
|
'--twinkle-delay': `${star.twinkleDelay}s`,
|
||||||
'--twinkle-delay': `${star.twinkleDelay}s`,
|
'--twinkle-duration': twinkleDuration
|
||||||
'--twinkle-duration': twinkleDuration
|
}"
|
||||||
}"
|
/>
|
||||||
/>
|
|
||||||
</ClientOnly>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,12 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
|
import { kebabCase } from 'scule'
|
||||||
|
|
||||||
|
interface Star {
|
||||||
|
x: number
|
||||||
|
y: number
|
||||||
|
size: number
|
||||||
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<{
|
const props = withDefaults(defineProps<{
|
||||||
starCount?: number
|
starCount?: number
|
||||||
color?: string
|
color?: string
|
||||||
@@ -14,8 +22,10 @@ const props = withDefaults(defineProps<{
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const route = useRoute()
|
||||||
|
|
||||||
// Generate random star positions and sizes
|
// Generate random star positions and sizes
|
||||||
const generateStars = (count: number) => {
|
const generateStars = (count: number): Star[] => {
|
||||||
return Array.from({ length: count }, () => ({
|
return Array.from({ length: count }, () => ({
|
||||||
x: Math.floor(Math.random() * 2000),
|
x: Math.floor(Math.random() * 2000),
|
||||||
y: 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
|
// Define speed configurations once
|
||||||
const starLayers = computed(() => {
|
const speedMap = {
|
||||||
const speedMap = {
|
slow: { duration: 200, opacity: 0.5, ratio: 0.3 },
|
||||||
slow: { duration: 200, opacity: 0.5 },
|
normal: { duration: 150, opacity: 0.75, ratio: 0.3 },
|
||||||
normal: { duration: 150, opacity: 0.75 },
|
fast: { duration: 100, opacity: 1, ratio: 0.4 }
|
||||||
fast: { duration: 100, opacity: 1 }
|
}
|
||||||
}
|
|
||||||
|
|
||||||
return [
|
// Use a more efficient approach to generate and store stars
|
||||||
{ stars: generateStars(props.starCount), ...speedMap.fast },
|
const stars = useState<{ slow: Star[], normal: Star[], fast: Star[] }>(`${kebabCase(route.path)}-stars`, () => {
|
||||||
{ stars: generateStars(Math.floor(props.starCount * 0.6)), ...speedMap.normal },
|
return {
|
||||||
{ stars: generateStars(Math.floor(props.starCount * 0.3)), ...speedMap.slow }
|
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>
|
</script>
|
||||||
|
|
||||||
<template>
|
<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">
|
<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
|
<div
|
||||||
v-for="(layer, index) in starLayers"
|
v-for="(star, starIndex) in layer.stars"
|
||||||
:key="index"
|
:key="starIndex"
|
||||||
class="star-layer"
|
class="star absolute rounded-full"
|
||||||
:style="{
|
:style="{
|
||||||
'--star-duration': `${layer.duration}s`,
|
left: `${star.x}px`,
|
||||||
'--star-opacity': layer.opacity,
|
top: `${star.y}px`,
|
||||||
'--star-color': color
|
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>
|
</div>
|
||||||
</ClientOnly>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|||||||
@@ -119,7 +119,8 @@ onMounted(() => {
|
|||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<StarsBg />
|
<LazyStarsBg hydrate-never />
|
||||||
|
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
</UPageHero>
|
</UPageHero>
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<SkyBg />
|
<LazySkyBg hydrate-never />
|
||||||
|
|
||||||
<div class="h-[344px] lg:h-full lg:relative w-full lg:min-h-[calc(100vh-var(--ui-header-height)-1px)] overflow-hidden">
|
<div class="h-[344px] lg:h-full lg:relative w-full lg:min-h-[calc(100vh-var(--ui-header-height)-1px)] overflow-hidden">
|
||||||
<UPageMarquee
|
<UPageMarquee
|
||||||
@@ -93,7 +93,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
:overlay="false"
|
:overlay="false"
|
||||||
:ui="{
|
:ui="{
|
||||||
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full left-0 border-y lg:border-x lg:border-y-0 lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:flex-col',
|
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full left-0 border-y lg:border-x lg:border-y-0 lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:flex-col',
|
||||||
content: 'lg:w-auto lg:h-full lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content]'
|
content: 'lg:w-auto lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content]'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<ULink
|
<ULink
|
||||||
@@ -118,7 +118,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
:overlay="false"
|
:overlay="false"
|
||||||
:ui="{
|
:ui="{
|
||||||
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full mt-[180px] left-0 border-y lg:mt-auto lg:left-auto lg:border-y-0 lg:border-x lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:right-0 lg:flex-col',
|
root: '[--gap:--spacing(4)] [--duration:40s] border-(--ui-border) absolute w-full mt-[180px] left-0 border-y lg:mt-auto lg:left-auto lg:border-y-0 lg:border-x lg:w-[calc(50%-6px)] 2xl:w-[320px] lg:right-0 lg:flex-col',
|
||||||
content: 'lg:w-auto lg:h-full lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content] lg:[animation-direction:reverse]'
|
content: 'lg:w-auto lg:flex-col lg:animate-[marquee-vertical_var(--duration)_linear_infinite] lg:rtl:animate-[marquee-vertical-rtl_var(--duration)_linear_infinite] lg:h-[fit-content] lg:[animation-direction:reverse]'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<ULink
|
<ULink
|
||||||
@@ -241,7 +241,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div ref="contributorsRef" class="p-4 sm:px-6 md:px-8 lg:px-12 xl:px-14 overflow-hidden flex relative">
|
<div ref="contributorsRef" class="p-4 sm:px-6 md:px-8 lg:px-12 xl:px-14 overflow-hidden flex relative">
|
||||||
<LazyHomeContributors :contributors="module?.contributors" :paused="!isContributorsInView || isContributorsHovered" />
|
<LazyHomeContributors :contributors="module?.contributors" :paused="!isContributorsInView || isContributorsHovered" hydrate-never />
|
||||||
</div>
|
</div>
|
||||||
</UPageSection>
|
</UPageSection>
|
||||||
|
|
||||||
@@ -261,7 +261,7 @@ useIntersectionObserver(contributorsRef, ([entry]) => {
|
|||||||
</UButton>
|
</UButton>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<StarsBg />
|
<LazyStarsBg hydrate-never />
|
||||||
|
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
<div class="relative h-[400px] border border-(--ui-border) bg-(--ui-bg-muted) overflow-hidden border-x-0 -mx-4 sm:-mx-6 lg:mx-0 lg:border-x w-screen lg:w-full">
|
<div class="relative h-[400px] border border-(--ui-border) bg-(--ui-bg-muted) overflow-hidden border-x-0 -mx-4 sm:-mx-6 lg:mx-0 lg:border-x w-screen lg:w-full">
|
||||||
|
|||||||
@@ -71,7 +71,8 @@ onMounted(() => {
|
|||||||
<template>
|
<template>
|
||||||
<UMain>
|
<UMain>
|
||||||
<UPageHero headline="License Activation" :title="title" :description="description" :ui="{ container: 'relative overflow-hidden', wrapper: 'lg:px-12', description: 'text-pretty' }">
|
<UPageHero headline="License Activation" :title="title" :description="description" :ui="{ container: 'relative overflow-hidden', wrapper: 'lg:px-12', description: 'text-pretty' }">
|
||||||
<StarsBg />
|
<LazyStarsBg hydrate-never />
|
||||||
|
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
|
|
||||||
<div class="px-4 py-10 lg:border border-(--ui-border) bg-(--ui-bg)">
|
<div class="px-4 py-10 lg:border border-(--ui-border) bg-(--ui-bg)">
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ useSeoMeta({
|
|||||||
<MDC :value="page.hero.description" tag="span" unwrap="p" cache-key="pro-hero-description" />
|
<MDC :value="page.hero.description" tag="span" unwrap="p" cache-key="pro-hero-description" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<StarsBg />
|
<LazyStarsBg hydrate-never />
|
||||||
|
|
||||||
<Motion as-child :initial="{ height: 0 }" :animate="{ height: 'auto' }" :transition="{ delay: 0.2, duration: 1 }">
|
<Motion as-child :initial="{ height: 0 }" :animate="{ height: 'auto' }" :transition="{ delay: 0.2, duration: 1 }">
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
@@ -196,7 +196,7 @@ useSeoMeta({
|
|||||||
class="overflow-hidden"
|
class="overflow-hidden"
|
||||||
orientation="horizontal"
|
orientation="horizontal"
|
||||||
>
|
>
|
||||||
<StarsBg />
|
<LazyStarsBg hydrate-never />
|
||||||
|
|
||||||
<video
|
<video
|
||||||
class="rounded-[var(--ui-radius)] z-10"
|
class="rounded-[var(--ui-radius)] z-10"
|
||||||
|
|||||||
@@ -27,8 +27,10 @@ useSeoMeta({
|
|||||||
<MDC :value="page.pricing.title" unwrap="p" cache-key="pro-pricing-title" />
|
<MDC :value="page.pricing.title" unwrap="p" cache-key="pro-pricing-title" />
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<StarsBg />
|
<LazyStarsBg hydrate-never />
|
||||||
|
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
|
|
||||||
<div class="flex flex-col bg-(--ui-bg) gap-8 lg:gap-0">
|
<div class="flex flex-col bg-(--ui-bg) gap-8 lg:gap-0">
|
||||||
<UPricingPlan
|
<UPricingPlan
|
||||||
v-bind="page.pricing.freePlan"
|
v-bind="page.pricing.freePlan"
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ useSeoMeta({
|
|||||||
<template>
|
<template>
|
||||||
<div class="relative">
|
<div class="relative">
|
||||||
<UPageHero :links="page.links" :ui="{ container: 'relative' }">
|
<UPageHero :links="page.links" :ui="{ container: 'relative' }">
|
||||||
<StarsBg />
|
<LazyStarsBg hydrate-never />
|
||||||
|
|
||||||
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
<div aria-hidden="true" class="hidden lg:block absolute z-[-1] border-x border-(--ui-border) inset-0 mx-4 sm:mx-6 lg:mx-8" />
|
||||||
|
|
||||||
<template #title>
|
<template #title>
|
||||||
|
|||||||
Reference in New Issue
Block a user