diff --git a/src/app/globals.css b/src/app/globals.css index a3d030d..8a55d3a 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -130,3 +130,27 @@ body { background-position: right 10px center; padding-right: 28px; } + +/* ---- Marquee scroll for format rows ---- */ +@keyframes marquee-left { + from { transform: translateX(0); } + to { transform: translateX(-50%); } +} + +@keyframes marquee-right { + from { transform: translateX(-50%); } + to { transform: translateX(0); } +} + +.animate-marquee-left { + animation: marquee-left var(--marquee-duration, 30s) linear infinite; +} + +.animate-marquee-right { + animation: marquee-right var(--marquee-duration, 30s) linear infinite; +} + +.animate-marquee-left:hover, +.animate-marquee-right:hover { + animation-play-state: paused; +} diff --git a/src/app/page.tsx b/src/app/page.tsx index da4ca9b..522e0f9 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -51,68 +51,41 @@ const flowSteps = [ { inputIcon: '\u{1F3B5}', inputLabel: '.FLAC', outputIcon: '\u{1F3A7}', outputLabel: '.MP3' }, ]; -/* ─── Format Cloud Data ─── */ +/* ─── Format Marquee Data ─── */ -type FormatCategory = 'image' | 'document' | 'audio' | 'video' | 'data'; - -const categoryMeta: Record = { - image: { label: 'Images', color: '#f472b6', colorLight: 'rgba(244,114,182,0.10)' }, - document: { label: 'Documents', color: '#60a5fa', colorLight: 'rgba(96,165,250,0.10)' }, - audio: { label: 'Audio', color: '#a78bfa', colorLight: 'rgba(167,139,250,0.10)' }, - video: { label: 'Video', color: '#fb923c', colorLight: 'rgba(251,146,60,0.10)' }, - data: { label: 'Data & Fonts', color: '#34d399', colorLight: 'rgba(52,211,153,0.10)' }, -}; - -const allFormats: { name: string; cat: FormatCategory; popular?: boolean }[] = [ - // Images - { name: 'PNG', cat: 'image', popular: true }, - { name: 'JPG', cat: 'image', popular: true }, - { name: 'WebP', cat: 'image', popular: true }, - { name: 'GIF', cat: 'image' }, - { name: 'AVIF', cat: 'image' }, - { name: 'SVG', cat: 'image', popular: true }, - { name: 'PSD', cat: 'image' }, - { name: 'HEIC', cat: 'image', popular: true }, - { name: 'BMP', cat: 'image' }, - { name: 'TIFF', cat: 'image' }, - { name: 'ICO', cat: 'image' }, - // Documents - { name: 'PDF', cat: 'document', popular: true }, - { name: 'DOCX', cat: 'document', popular: true }, - { name: 'MD', cat: 'document' }, - { name: 'HTML', cat: 'document', popular: true }, - { name: 'TXT', cat: 'document' }, - { name: 'RTF', cat: 'document' }, - { name: 'PPTX', cat: 'document', popular: true }, - { name: 'EPUB', cat: 'document' }, - // Audio - { name: 'MP3', cat: 'audio', popular: true }, - { name: 'WAV', cat: 'audio', popular: true }, - { name: 'OGG', cat: 'audio' }, - { name: 'FLAC', cat: 'audio', popular: true }, - { name: 'AAC', cat: 'audio' }, - { name: 'M4A', cat: 'audio' }, - // Video - { name: 'MP4', cat: 'video', popular: true }, - { name: 'WebM', cat: 'video' }, - { name: 'AVI', cat: 'video' }, - { name: 'MOV', cat: 'video', popular: true }, - { name: 'MKV', cat: 'video', popular: true }, - // Data & Fonts - { name: 'CSV', cat: 'data', popular: true }, - { name: 'JSON', cat: 'data', popular: true }, - { name: 'XML', cat: 'data' }, - { name: 'YAML', cat: 'data', popular: true }, - { name: 'XLSX', cat: 'data', popular: true }, - { name: 'TSV', cat: 'data' }, - { name: 'TOML', cat: 'data' }, - { name: 'INI', cat: 'data' }, - { name: 'NDJSON', cat: 'data' }, - { name: 'SQL', cat: 'data' }, - { name: 'TTF', cat: 'data' }, - { name: 'OTF', cat: 'data' }, - { name: 'WOFF', cat: 'data' }, - { name: 'WOFF2', cat: 'data' }, +const marqueeRows = [ + { + label: 'Images', + color: '#f472b6', + colorLight: 'rgba(244,114,182,0.08)', + formats: ['PNG', 'JPG', 'WebP', 'GIF', 'AVIF', 'SVG', 'PSD', 'HEIC', 'BMP', 'TIFF', 'ICO'], + direction: 'left' as const, + speed: '35s', + }, + { + label: 'Documents', + color: '#60a5fa', + colorLight: 'rgba(96,165,250,0.08)', + formats: ['PDF', 'DOCX', 'MD', 'HTML', 'TXT', 'RTF', 'PPTX', 'EPUB'], + direction: 'right' as const, + speed: '30s', + }, + { + label: 'Audio & Video', + color: '#a78bfa', + colorLight: 'rgba(167,139,250,0.08)', + formats: ['MP3', 'WAV', 'OGG', 'FLAC', 'AAC', 'M4A', 'MP4', 'WebM', 'AVI', 'MOV', 'MKV'], + direction: 'left' as const, + speed: '38s', + }, + { + label: 'Data & Fonts', + color: '#34d399', + colorLight: 'rgba(52,211,153,0.08)', + formats: ['CSV', 'JSON', 'XML', 'YAML', 'XLSX', 'TSV', 'TOML', 'INI', 'SQL', 'NDJSON', 'TTF', 'OTF', 'WOFF', 'WOFF2'], + direction: 'right' as const, + speed: '40s', + }, ]; /* ─── Animation Variants ─── */ @@ -467,13 +440,13 @@ export default function LandingPage() { - {/* ──── FEATURES — FORMAT CLOUD ──── */} + {/* ──── FEATURES — SCROLLING MARQUEE ──── */}
- {/* Category legend */} - - {(Object.entries(categoryMeta) as [FormatCategory, typeof categoryMeta[FormatCategory]][]).map(([key, meta]) => ( -
-
- {meta.label} -
- ))} - + {/* Marquee rows */} +
+ {marqueeRows.map((row, rowIndex) => ( + + {/* Category label — pinned left */} +
+ + {row.label} + +
- {/* Format cloud */} - - {allFormats.map((fmt) => { - const meta = categoryMeta[fmt.cat]; - return ( - - .{fmt.name} - - ); - })} - + {/* Fade edges */} +
+
+ + {/* Scrolling track */} +
+
+ {/* Duplicate the badges for seamless loop */} + {[...row.formats, ...row.formats].map((fmt, i) => ( + + .{fmt} + + ))} +
+
+ + ))} +
{/* Total count callout */}