@@ -576,25 +583,30 @@
-
-
+
+
+
+
{{
@@ -978,8 +990,12 @@ const canPromptInstall = ref(false)
/** اپ از قبل نصب شده یا در حالت standalone اجرا میشود */
const isAppInstalledOrStandalone = ref(false)
const statsMetricsEl = ref(null)
+const heroChartPlotEl = ref(null)
+const liveChartPlotEl = ref(null)
const metricAnimatedValues = ref([0, 0, 0, 0])
const metricsCountStarted = ref(false)
+const heroChartDrawn = ref(false)
+const liveChartDrawn = ref(false)
const projectName = computed(() => config.config?.name_fa ?? 'بورسمس')
const patternMaskStyle = computed(() => ({
WebkitMaskImage: `url(${heroPattern})`,
@@ -1465,6 +1481,8 @@ onMounted(() => {
void nextTick(() => {
setupMetricsCountUp()
+ setupHeroChartDraw()
+ setupLiveChartDraw()
})
})
@@ -1475,6 +1493,10 @@ onBeforeUnmount(() => {
syncBodyScrollLock(false)
metricsObserver?.disconnect()
metricsObserver = undefined
+ heroChartObserver?.disconnect()
+ heroChartObserver = undefined
+ liveChartObserver?.disconnect()
+ liveChartObserver = undefined
if (metricsRaf) cancelAnimationFrame(metricsRaf)
if (pricePollTimer) {
clearInterval(pricePollTimer)
@@ -1513,8 +1535,87 @@ const displayMetrics = computed(() =>
)
let metricsObserver: IntersectionObserver | undefined
+let heroChartObserver: IntersectionObserver | undefined
+let liveChartObserver: IntersectionObserver | undefined
let metricsRaf = 0
+function prefersReducedMotion() {
+ return (
+ typeof window !== 'undefined' &&
+ window.matchMedia('(prefers-reduced-motion: reduce)').matches
+ )
+}
+
+function setupChartDrawOnce(
+ el: HTMLElement | null,
+ drawn: { value: boolean },
+ getObserver: () => IntersectionObserver | undefined,
+ setObserver: (observer: IntersectionObserver | undefined) => void,
+) {
+ if (drawn.value) return
+ if (!el) return
+
+ if (prefersReducedMotion() || typeof IntersectionObserver === 'undefined') {
+ drawn.value = true
+ return
+ }
+
+ getObserver()?.disconnect()
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ if (entries.some((entry) => entry.isIntersecting)) {
+ drawn.value = true
+ observer.disconnect()
+ setObserver(undefined)
+ }
+ },
+ { threshold: 0.35 },
+ )
+ setObserver(observer)
+ observer.observe(el)
+}
+
+function setupHeroChartDraw() {
+ setupChartDrawOnce(
+ heroChartPlotEl.value,
+ heroChartDrawn,
+ () => heroChartObserver,
+ (observer) => {
+ heroChartObserver = observer
+ },
+ )
+}
+
+function setupLiveChartDraw() {
+ setupChartDrawOnce(
+ liveChartPlotEl.value,
+ liveChartDrawn,
+ () => liveChartObserver,
+ (observer) => {
+ liveChartObserver = observer
+ },
+ )
+}
+
+watch(
+ () => landingChart.value.hasData,
+ async (hasData) => {
+ if (!hasData || heroChartDrawn.value) return
+ await nextTick()
+ setupHeroChartDraw()
+ },
+)
+
+watch(
+ () => liveSectionChart.value.hasData,
+ async (hasData) => {
+ if (!hasData || liveChartDrawn.value) return
+ await nextTick()
+ setupLiveChartDraw()
+ },
+)
+
function isStandaloneDisplay() {
return (
window.matchMedia('(display-mode: standalone)').matches ||
diff --git a/src/views/base/aboutUs/desktop/styles/desktop-about-us.less b/src/views/base/aboutUs/desktop/styles/desktop-about-us.less
index 51ad128..0756edb 100644
--- a/src/views/base/aboutUs/desktop/styles/desktop-about-us.less
+++ b/src/views/base/aboutUs/desktop/styles/desktop-about-us.less
@@ -597,6 +597,33 @@ body.dlanding-menu-open {
height: clamp(80px, 10vw, 96px);
}
+ &__path {
+ stroke-dasharray: 1;
+ stroke-dashoffset: 1;
+ }
+
+ &__area {
+ opacity: 0;
+ }
+
+ &__endpoint {
+ opacity: 0;
+ }
+
+ &__plot.is-drawn {
+ .dlanding-chart__path {
+ animation: dlanding-chart-draw 1.45s cubic-bezier(0.22, 1, 0.36, 1) forwards;
+ }
+
+ .dlanding-chart__area {
+ animation: dlanding-chart-fade 0.55s ease-out 0.75s forwards;
+ }
+
+ .dlanding-chart__endpoint {
+ animation: dlanding-chart-fade 0.35s ease-out 1.25s forwards;
+ }
+ }
+
&__empty {
display: flex;
align-items: center;
@@ -677,6 +704,48 @@ body.dlanding-menu-open {
}
}
+@keyframes dlanding-chart-draw {
+ to {
+ stroke-dashoffset: 0;
+ }
+}
+
+@keyframes dlanding-chart-fade {
+ to {
+ opacity: 1;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .dlanding-chart {
+ &__path {
+ stroke-dasharray: none;
+ stroke-dashoffset: 0;
+ animation: none !important;
+ }
+
+ &__area,
+ &__endpoint {
+ opacity: 1;
+ animation: none !important;
+ }
+ }
+
+ .dlanding-live {
+ &__chart-path {
+ stroke-dasharray: none;
+ stroke-dashoffset: 0;
+ animation: none !important;
+ }
+
+ &__chart-area,
+ &__chart-endpoint {
+ opacity: 1;
+ animation: none !important;
+ }
+ }
+}
+
.dlanding-order-card {
width: 556px;
max-width: 100%;
@@ -1517,6 +1586,33 @@ body.dlanding-menu-open {
height: 100%;
}
+ &__chart-path {
+ stroke-dasharray: 1;
+ stroke-dashoffset: 1;
+ }
+
+ &__chart-area {
+ opacity: 0;
+ }
+
+ &__chart-endpoint {
+ opacity: 0;
+ }
+
+ &__chart.is-drawn {
+ .dlanding-live__chart-path {
+ animation: dlanding-chart-draw 1.55s cubic-bezier(0.22, 1, 0.36, 1) forwards;
+ }
+
+ .dlanding-live__chart-area {
+ animation: dlanding-chart-fade 0.55s ease-out 0.85s forwards;
+ }
+
+ .dlanding-live__chart-endpoint {
+ animation: dlanding-chart-fade 0.35s ease-out 1.35s forwards;
+ }
+ }
+
&__chart-empty {
display: flex;
align-items: center;