feat(classiques): enforce uniform physical scroll speed across all marquees and match clock box design from img 1
This commit is contained in:
1 parent
75d0a05f21
commit
5d954af44a
5 files changed
+59
-38
No files matched your search
@@ -1,23 +1,42 @@
|
|||||||
import React, { useRef, useState, useEffect } from 'react';
|
import React, { useRef, useState, useEffect } from 'react';
|
||||||
import './MarqueeText.css';
|
import './MarqueeText.css';
|
||||||
|
|
||||||
const MarqueeText = ({ text, className, style, duration = '10s' }) => {
|
const DEFAULT_SPEED = 50; // pixels per second for uniform, calm scrolling
|
||||||
|
|
||||||
|
const MarqueeText = ({ text, className, style, speed = DEFAULT_SPEED, duration }) => {
|
||||||
const containerRef = useRef(null);
|
const containerRef = useRef(null);
|
||||||
const textRef = useRef(null);
|
const textRef = useRef(null);
|
||||||
const [isOverflowing, setIsOverflowing] = useState(false);
|
const [isOverflowing, setIsOverflowing] = useState(false);
|
||||||
|
const [computedDuration, setComputedDuration] = useState('20s');
|
||||||
const formattedDuration = typeof duration === 'number' ? `${duration}s` : duration;
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const checkOverflow = () => {
|
const updateMarquee = () => {
|
||||||
if (containerRef.current && textRef.current) {
|
if (containerRef.current && textRef.current) {
|
||||||
setIsOverflowing(textRef.current.scrollWidth > containerRef.current.clientWidth);
|
const containerWidth = containerRef.current.clientWidth;
|
||||||
|
const textWidth = textRef.current.scrollWidth;
|
||||||
|
const overflowing = textWidth > containerWidth;
|
||||||
|
setIsOverflowing(overflowing);
|
||||||
|
|
||||||
|
if (overflowing) {
|
||||||
|
if (duration) {
|
||||||
|
setComputedDuration(typeof duration === 'number' ? `${duration}s` : duration);
|
||||||
|
} else {
|
||||||
|
const totalDistance = textWidth + containerWidth;
|
||||||
|
const seconds = totalDistance / speed;
|
||||||
|
setComputedDuration(`${seconds.toFixed(2)}s`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
checkOverflow();
|
|
||||||
window.addEventListener('resize', checkOverflow);
|
updateMarquee();
|
||||||
return () => window.removeEventListener('resize', checkOverflow);
|
window.addEventListener('resize', updateMarquee);
|
||||||
}, [text]);
|
const timer = setTimeout(updateMarquee, 100);
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener('resize', updateMarquee);
|
||||||
|
clearTimeout(timer);
|
||||||
|
};
|
||||||
|
}, [text, speed, duration]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={`marquee-container ${className || ''}`} ref={containerRef} style={{ ...style, overflow: 'hidden', whiteSpace: 'nowrap', width: '100%', flex: '1 1 0' }}>
|
<div className={`marquee-container ${className || ''}`} ref={containerRef} style={{ ...style, overflow: 'hidden', whiteSpace: 'nowrap', width: '100%', flex: '1 1 0' }}>
|
||||||
@@ -26,7 +45,7 @@ const MarqueeText = ({ text, className, style, duration = '10s' }) => {
|
|||||||
ref={textRef}
|
ref={textRef}
|
||||||
style={{
|
style={{
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
animation: isOverflowing ? `marquee-scroll ${formattedDuration} linear infinite` : 'none',
|
animation: isOverflowing ? `marquee-scroll ${computedDuration} linear infinite` : 'none',
|
||||||
paddingLeft: isOverflowing ? '100%' : '0',
|
paddingLeft: isOverflowing ? '100%' : '0',
|
||||||
fontSize: 'inherit',
|
fontSize: 'inherit',
|
||||||
fontWeight: 'inherit',
|
fontWeight: 'inherit',
|
||||||
|
|||||||
@@ -356,8 +356,8 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding-left: 24px;
|
padding-left: 24px;
|
||||||
padding-right: 12px;
|
padding-right: 14px;
|
||||||
background: linear-gradient(180deg, #13571d 0%, #0a2d0f 100%) !important;
|
background: linear-gradient(180deg, #165b21 0%, #0a2d0f 100%) !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 25;
|
z-index: 25;
|
||||||
border-top: 1.5px solid rgba(255, 255, 255, 0.18);
|
border-top: 1.5px solid rgba(255, 255, 255, 0.18);
|
||||||
@@ -383,22 +383,22 @@
|
|||||||
|
|
||||||
.aff-classiques-arrivees__bottom-clock {
|
.aff-classiques-arrivees__bottom-clock {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border: 3.5px solid #ffffff;
|
border: 2.5px solid rgba(255, 255, 255, 0.85);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 4px 16px;
|
padding: 6px 14px 4px 14px;
|
||||||
background: #0d3613;
|
background: rgba(10, 42, 16, 0.45);
|
||||||
font-family: "Achemine", sans-serif;
|
font-family: "Achemine", sans-serif;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-right: 6px;
|
margin-right: 4px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: 76px;
|
height: 74px;
|
||||||
gap: 12px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.aff-classiques-arrivees__bottom-clock-hm {
|
.aff-classiques-arrivees__bottom-clock-hm {
|
||||||
font-size: 54px;
|
font-size: 52px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
letter-spacing: 1.5px;
|
letter-spacing: 1.5px;
|
||||||
@@ -406,10 +406,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.aff-classiques-arrivees__bottom-clock-s {
|
.aff-classiques-arrivees__bottom-clock-s {
|
||||||
font-size: 54px;
|
font-size: 34px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
letter-spacing: 1.5px;
|
letter-spacing: 0.5px;
|
||||||
color: var(--yellow) !important;
|
color: var(--yellow) !important;
|
||||||
margin-top: 0;
|
margin-top: 1px;
|
||||||
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
@@ -1314,7 +1314,7 @@ export default function ClassiquesArrivees(){
|
|||||||
<div className="aff-classiques-arrivees__sub-stops">
|
<div className="aff-classiques-arrivees__sub-stops">
|
||||||
<MarqueeText
|
<MarqueeText
|
||||||
className="aff-classiques-arrivees__sub-stops-marquee"
|
className="aff-classiques-arrivees__sub-stops-marquee"
|
||||||
duration="38s"
|
speed={50}
|
||||||
text={
|
text={
|
||||||
<span className="aff-classiques-arrivees__stops-chain">
|
<span className="aff-classiques-arrivees__stops-chain">
|
||||||
{stopsList.map((stopName, sIdx) => (
|
{stopsList.map((stopName, sIdx) => (
|
||||||
|
|||||||
@@ -356,8 +356,8 @@
|
|||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
padding-left: 24px;
|
padding-left: 24px;
|
||||||
padding-right: 12px;
|
padding-right: 14px;
|
||||||
background: linear-gradient(180deg, #07418a 0%, #00225e 100%) !important;
|
background: linear-gradient(180deg, #093c83 0%, #001f55 100%) !important;
|
||||||
position: relative;
|
position: relative;
|
||||||
z-index: 25;
|
z-index: 25;
|
||||||
border-top: 1.5px solid rgba(255, 255, 255, 0.18);
|
border-top: 1.5px solid rgba(255, 255, 255, 0.18);
|
||||||
@@ -383,22 +383,22 @@
|
|||||||
|
|
||||||
.aff-classiques-departs__bottom-clock {
|
.aff-classiques-departs__bottom-clock {
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: flex-start;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
border: 3.5px solid #ffffff;
|
border: 2.5px solid rgba(255, 255, 255, 0.85);
|
||||||
border-radius: 6px;
|
border-radius: 6px;
|
||||||
padding: 4px 16px;
|
padding: 6px 14px 4px 14px;
|
||||||
background: #001e40;
|
background: rgba(0, 24, 64, 0.45);
|
||||||
font-family: "Achemine", sans-serif;
|
font-family: "Achemine", sans-serif;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
margin-right: 6px;
|
margin-right: 4px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
height: 76px;
|
height: 74px;
|
||||||
gap: 12px;
|
gap: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.aff-classiques-departs__bottom-clock-hm {
|
.aff-classiques-departs__bottom-clock-hm {
|
||||||
font-size: 54px;
|
font-size: 52px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
letter-spacing: 1.5px;
|
letter-spacing: 1.5px;
|
||||||
@@ -406,10 +406,11 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.aff-classiques-departs__bottom-clock-s {
|
.aff-classiques-departs__bottom-clock-s {
|
||||||
font-size: 54px;
|
font-size: 34px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
line-height: 1;
|
line-height: 1;
|
||||||
letter-spacing: 1.5px;
|
letter-spacing: 0.5px;
|
||||||
color: var(--yellow) !important;
|
color: var(--yellow) !important;
|
||||||
margin-top: 0;
|
margin-top: 1px;
|
||||||
|
margin-left: 2px;
|
||||||
}
|
}
|
||||||
@@ -1311,7 +1311,7 @@ export default function ClassiquesDeparts(){
|
|||||||
<div className="aff-classiques-departs__sub-stops">
|
<div className="aff-classiques-departs__sub-stops">
|
||||||
<MarqueeText
|
<MarqueeText
|
||||||
className="aff-classiques-departs__sub-stops-marquee"
|
className="aff-classiques-departs__sub-stops-marquee"
|
||||||
duration="38s"
|
speed={50}
|
||||||
text={
|
text={
|
||||||
<span className="aff-classiques-departs__stops-chain">
|
<span className="aff-classiques-departs__stops-chain">
|
||||||
{stopsList.map((stopName, sIdx) => (
|
{stopsList.map((stopName, sIdx) => (
|
||||||
|
|||||||
Reference in new issue
Block a user