Countdown timer
Product details display
import React, { useState, useEffect } from 'react'; import { Flexbox, Text } from '@evlop/native-components'; function Digit({ char, textStyle }) { const fontSize = (textStyle && textStyle.fontSize) || 18; return ( <Text color={textStyle.color} fontSize={fontSize} fontWeight={textStyle.fontWeight} style={{ lineHeight: fontSize * 1.25, textAlign: 'center' }}> {char} </Text> ); } function StaticNumber({ value, textStyle = {} }) { const str = String(value); return ( <Flexbox flexDirection="row" alignItems="center"> {str.split('').map((ch, idx) => ( <Digit key={idx} char={ch} textStyle={textStyle} /> ))} </Flexbox> ); } // The component now accepts a `data` prop (provided by the builder). Make the countdown configurable const Countdown:AppBlock =function ({ data = {} }) { const [timeLeft, setTimeLeft] = useState({}); const targetDateString = data.targetDate || '2026-01-01T00:00:00'; const target = new Date(targetDateString); const calculateTimeLeft = () => { const now = new Date(); const difference = +target - +now; if (difference <= 0) return { days: 0, hours: 0, minutes: 0, seconds: 0 }; return { days: Math.floor(difference / (1000 * 60 * 60 * 24)), hours: Math.floor((difference / (1000 * 60 * 60)) % 24), minutes: Math.floor((difference / 1000 / 60) % 60), seconds: Math.floor((difference / 1000) % 60), }; }; useEffect(() => { setTimeLeft(calculateTimeLeft()); const id = setInterval(() => setTimeLeft(calculateTimeLeft()), 1000); return () => clearInterval(id); // target may change via data prop — update when it does }, [targetDateString]); const formatNumber = (n) => String(n).padStart(2, '0'); const intervals = [ { key: 'days', label: 'DAYS' }, { key: 'hours', label: 'HOURS' }, { key: 'minutes', label: 'MIN' }, { key: 'seconds', label: 'SEC' }, ]; // colorful palette for timer blocks (kept default but could be exposed later) const timerColors = ['#FFEDD5', '#EDE9FE', '#DBEAFE', '#ECFCCB']; const timerTextColors = ['#9A3412', '#5B21B6', '#1E40AF', '#365314']; const showLabels = data.showLabels !== undefined ? Boolean(data.showLabels) : true; const timerComponents = intervals.map((it, idx) => ( <Flexbox key={it.key} bg={timerColors[idx % timerColors.length]} p="xs" borderRadius={10} alignItems="center" justifyContent="center" flexDirection="column" style={{ minWidth: 56, marginHorizontal: 6, shadowColor: '#000', shadowOpacity: 0.03, shadowRadius: 6 }} > <StaticNumber value={formatNumber(timeLeft[it.key] ?? 0)} textStyle={{ color: timerTextColors[idx % timerTextColors.length], fontSize: 16, fontWeight: '800' }} /> {showLabels && <Text color="#475569" fontSize="xs">{it.label}</Text>} </Flexbox> )); const title = data.title || 'Countdown to 2026'; const subtitle = data.subtitle || 'A colorful countdown.'; return ( <Flexbox bg="#fff7ed" p="xl" gap={20} flexDirection="column" alignItems="center" justifyContent="center" style={{ flex: 1 }} > <Flexbox bg="white" borderRadius={16} p="lg" gap={12} flexDirection="column" alignItems="center" style={{ width: '100%', maxWidth: 720, elevation: 3 }} > {/* colorful stripe */} <Flexbox flexDirection="row" style={{ width: '100%', height: 8, borderRadius: 8, overflow: 'hidden' }}> <Flexbox bg="#FB7185" style={{ flex: 1 }} /> <Flexbox bg="#F59E0B" style={{ flex: 1 }} /> <Flexbox bg="#10B981" style={{ flex: 1 }} /> <Flexbox bg="#7C3AED" style={{ flex: 1 }} /> </Flexbox> <Text color="#6D28D9" fontSize="2xl" fontWeight="bold">{title}</Text> <Text color="#374151" fontSize="sm">{subtitle}</Text> <Flexbox flexDirection="row" alignItems="center" justifyContent="center" style={{ width: '100%', flexWrap: 'nowrap' }}> {timerComponents} </Flexbox> </Flexbox> </Flexbox> ); } export default Countdown;
{ "title": "Countdown to 2026", "subtitle": "A colorful, animated countdown — numbers slide in from the bottom as they update.", "targetDate": "2026-01-01T00:00:00", "showLabels": true }
Loading...