Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ yarn-error.log*
# typescript
*.tsbuildinfo
next-env.d.ts
.pnpm-store/

# Sentry Config File
.env.sentry-build-plugin
Expand Down
10 changes: 10 additions & 0 deletions frontend/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -616,3 +616,13 @@
border: 2px solid transparent;
background-clip: padding-box;
}

/* Hide scrollbar utility */
.scrollbar-none {
-ms-overflow-style: none;
scrollbar-width: none;
}

.scrollbar-none::-webkit-scrollbar {
display: none;
}
10 changes: 5 additions & 5 deletions frontend/app/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import BlockSpawner from '../components/block-spawner'
import BlockStateTracker from '@/components/block-state-tracker'

export default function Home() {
return (
<div className="h-screen overflow-hidden text-white font-sans sm:min-h-screen sm:h-auto sm:overflow-visible">
<main className="h-full flex flex-col py-4 px-4 max-w-6xl mx-auto sm:block sm:h-auto sm:py-8 sm:px-6 md:py-12">
<h1 className="text-2xl font-bold mb-4 text-center shrink-0 md:mb-8">
<div className="min-h-screen text-white font-sans">
<main className="py-6 px-4 max-w-5xl mx-auto sm:py-8 sm:px-6 md:py-12">
<h1 className="text-2xl sm:text-3xl font-bold mb-6 text-center md:mb-8 bg-linear-to-r from-indigo-400 via-violet-400 to-purple-400 bg-clip-text text-transparent">
Execution Events SDK Showcase
</h1>
<BlockSpawner />
<BlockStateTracker />
</main>
</div>
)
Expand Down
147 changes: 0 additions & 147 deletions frontend/components/block-spawner.tsx

This file was deleted.

60 changes: 60 additions & 0 deletions frontend/components/block-state-tracker/block-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
'use client'

import { AnimatePresence, motion } from 'framer-motion'
import { BLOCK_STATE_CONFIG } from '@/constants/block-state'
import { cn } from '@/lib/utils'
import type { Block } from '@/types/block'

interface BlockCardProps {
block: Block
className?: string
}

/**
* Individual block card in the blockchain visualization.
* Color and label transition smoothly as the block progresses through states.
*/
export function BlockCard({ block, className }: BlockCardProps) {
const config = BLOCK_STATE_CONFIG[block.state]

return (
<motion.div
layout
initial={{ opacity: 0, scale: 0.8 }}
animate={{ opacity: 1, scale: 1 }}
exit={{
opacity: 0,
scale: 0,
transition: { duration: 0.3, ease: 'easeIn' },
}}
transition={{ duration: 0.3, ease: 'easeOut' }}
style={{
background: config.gradient,
boxShadow: config.shadow,
}}
className={cn(
'flex flex-col items-center justify-center rounded-xl font-semibold',
'select-none cursor-default text-white',
'transition-[background,box-shadow] duration-500 ease-in-out',
'w-20 h-20 text-base sm:w-24 sm:h-24 sm:text-lg',
className,
)}
>
<span className="font-bold drop-shadow-[0_1px_2px_rgba(0,0,0,0.3)]">
#{block.id}
</span>
<AnimatePresence mode="wait">
<motion.span
key={config.label}
initial={{ opacity: 0, y: 4 }}
animate={{ opacity: 0.9, y: 0 }}
exit={{ opacity: 0, y: -4 }}
transition={{ duration: 0.15, ease: 'easeOut' }}
className="text-xs mt-1 sm:text-sm drop-shadow-[0_1px_1px_rgba(0,0,0,0.2)]"
>
{config.label}
</motion.span>
</AnimatePresence>
</motion.div>
)
}
101 changes: 101 additions & 0 deletions frontend/components/block-state-tracker/blockchain.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
'use client'

import { AnimatePresence, motion } from 'framer-motion'
import { Loader2 } from 'lucide-react'
import { useLayoutEffect, useRef } from 'react'
import type { Block } from '@/types/block'
import { BlockCard } from './block-card'

interface BlockchainProps {
blocks: Block[]
}

/**
* Horizontal blockchain visualization.
* Blocks are added from the right and stay in place as their state changes.
* Auto-scrolls to show the newest blocks.
*/
export function Blockchain({ blocks }: BlockchainProps) {
const scrollContainerRef = useRef<HTMLDivElement>(null)
const prevBlockCountRef = useRef(0)

// Sort blocks by ID (oldest on left, newest on right)
const sortedBlocks = [...blocks].sort((a, b) => a.id - b.id)

// Auto-scroll to the right when new blocks are added
useLayoutEffect(() => {
const container = scrollContainerRef.current
if (!container) return

const currentCount = blocks.length
const prevCount = prevBlockCountRef.current

if (currentCount > prevCount && currentCount > 0) {
// Small delay to let the new block render first
requestAnimationFrame(() => {
container.scrollTo({
left: container.scrollWidth,
behavior: 'smooth',
})
})
}

prevBlockCountRef.current = currentCount
}, [blocks.length])

return (
<div className="flex flex-col bg-[#16162a]/80 rounded-xl border border-[#2a2a4a]/50">
<div className="px-4 py-3 border-b border-[#2a2a4a]/50">
<h3 className="text-sm font-semibold uppercase tracking-wider text-[#8888a0]">
Blockchain
</h3>
</div>
<div
ref={scrollContainerRef}
className="flex-1 p-4 overflow-x-auto overflow-y-hidden scrollbar-none"
>
{sortedBlocks.length === 0 ? (
<div className="flex flex-col items-center justify-center gap-3 w-full py-8">
<Loader2 className="text-[#6a6a7a] animate-spin size-12" />
<p className="text-[#6a6a7a] text-sm">Waiting for blocks...</p>
</div>
) : (
<motion.div
className="flex items-center gap-2 min-h-[120px] sm:min-h-[140px] w-fit"
layout
transition={{ layout: { duration: 0.3, ease: 'easeInOut' } }}
>
<AnimatePresence mode="sync">
{sortedBlocks.map((block, index) => (
<motion.div
key={block.id}
className="flex items-center shrink-0"
layout
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.3, ease: 'easeOut' }}
>
{/* Chain connector */}
{index > 0 && (
<motion.div
className="w-3 h-1 bg-[#3a3a5a] rounded-full mr-2 sm:w-4 shrink-0"
initial={{ scaleX: 0 }}
animate={{ scaleX: 1 }}
exit={{
scaleX: 0,
opacity: 0,
transition: { duration: 0.2 },
}}
transition={{ duration: 0.2, delay: 0.1 }}
/>
)}
<BlockCard block={block} />
</motion.div>
))}
</AnimatePresence>
</motion.div>
)}
</div>
</div>
)
}
Loading