95 lines
2.9 KiB
Vue
95 lines
2.9 KiB
Vue
<template>
|
|
<Transition name="intro-fade">
|
|
<div
|
|
v-if="visible"
|
|
class="fixed inset-0 z-[1000] flex flex-col items-center justify-center overflow-hidden bg-ink text-bone"
|
|
aria-live="polite"
|
|
aria-busy="true"
|
|
>
|
|
<div class="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_at_center,rgba(200,255,46,0.12),transparent_55%)]" />
|
|
<p
|
|
class="relative px-6 text-center font-display font-extrabold leading-[0.95] tracking-[-0.04em]"
|
|
:style="{ fontSize: 'clamp(2.6rem, 13vw, 9rem)' }"
|
|
>
|
|
<span class="block animate-fade-up">{{ brandParts.first }}</span>
|
|
<span
|
|
v-if="brandParts.second"
|
|
class="mt-2 block font-accent tracking-normal text-volt animate-fade-up md:mt-3"
|
|
style="animation-delay: 0.12s"
|
|
>{{ brandParts.second }}</span>
|
|
</p>
|
|
<div class="relative mt-16 flex w-[min(300px,72vw)] flex-col items-center gap-3 animate-fade-up" style="animation-delay: 0.25s">
|
|
<div class="h-px w-full overflow-hidden bg-white/10">
|
|
<div class="h-full bg-volt transition-[width] duration-75 ease-linear" :style="{ width: `${progress}%` }" />
|
|
</div>
|
|
<span class="font-mono text-xs tracking-[0.4em] text-ash tabular-nums" dir="ltr">
|
|
{{ String(Math.floor(progress)).padStart(2, "0") }}%
|
|
</span>
|
|
</div>
|
|
</div>
|
|
</Transition>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
const props = withDefaults(
|
|
defineProps<{ title?: string }>(),
|
|
{ title: "هوشافزار منتک" },
|
|
);
|
|
|
|
const visible = ref(false);
|
|
const progress = ref(0);
|
|
|
|
const brandParts = computed(() => {
|
|
const raw = (props.title || "هوشافزار منتک").trim();
|
|
const parts = raw.split(/\s+/);
|
|
if (parts.length <= 1) return { first: raw, second: "" };
|
|
return {
|
|
first: parts.slice(0, -1).join(" "),
|
|
second: parts.at(-1) || "",
|
|
};
|
|
});
|
|
|
|
onMounted(() => {
|
|
const reduced = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
if (reduced) return;
|
|
|
|
visible.value = true;
|
|
document.documentElement.style.overflow = "hidden";
|
|
|
|
const start = performance.now();
|
|
const duration = 2400;
|
|
let raf = 0;
|
|
|
|
const tick = (now: number) => {
|
|
const t = Math.min(1, (now - start) / duration);
|
|
const eased = 1 - Math.pow(1 - t, 3);
|
|
progress.value = Math.min(100, eased * 100);
|
|
if (t < 1) {
|
|
raf = requestAnimationFrame(tick);
|
|
return;
|
|
}
|
|
progress.value = 100;
|
|
window.setTimeout(() => {
|
|
visible.value = false;
|
|
document.documentElement.style.overflow = "";
|
|
}, 320);
|
|
};
|
|
|
|
raf = requestAnimationFrame(tick);
|
|
onUnmounted(() => {
|
|
cancelAnimationFrame(raf);
|
|
document.documentElement.style.overflow = "";
|
|
});
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
.intro-fade-leave-active {
|
|
transition: opacity 0.75s cubic-bezier(0.22, 1, 0.36, 1), transform 0.75s cubic-bezier(0.22, 1, 0.36, 1);
|
|
}
|
|
.intro-fade-leave-to {
|
|
opacity: 0;
|
|
transform: scale(1.06);
|
|
}
|
|
</style>
|