import {
CRITICALITY_CONFIG,
isCriticalityBreaking,
isCriticalityDangerous,
isCriticalitySafe,
} from '#lib/graphql-change/criticality'
import type { GraphqlChangeset } from '#lib/graphql-changeset/index'
import { Box, Flex, Text } from '@radix-ui/themes'
import type React from 'react'
import { useEffect, useState } from 'react'
import { renderDate } from './Changelog.js'
interface ChangelogLayoutProps {
children: React.ReactNode
versions: GraphqlChangeset.ChangeSet[]
}
interface VersionCounts {
breaking: number
dangerous: number
safe: number
}
const calculateCounts = (version: GraphqlChangeset.ChangeSet): VersionCounts => {
return {
breaking: version.changes.filter(isCriticalityBreaking).length,
dangerous: version.changes.filter(isCriticalityDangerous).length,
safe: version.changes.filter(isCriticalitySafe).length,
}
}
const SidebarEntry: React.FC<{
version: GraphqlChangeset.ChangeSet
counts: VersionCounts
isActive: boolean
}> = ({ version, counts, isActive }) => {
const dateId = version.date.toISOString()
return (
{
e.preventDefault()
document.getElementById(dateId)?.scrollIntoView({ behavior: 'smooth' })
}}
>
{renderDate(version.date)}
{counts.breaking > 0 && (
{counts.breaking}
)}
{counts.dangerous > 0 && (
{counts.dangerous}
)}
{counts.safe > 0 && (
{counts.safe}
)}
)
}
export const ChangelogLayout: React.FC = ({ children, versions }) => {
const [activeVersion, setActiveVersion] = useState(null)
// Calculate counts for all versions (SSR-safe)
const versionsWithCounts = versions.map(version => ({
version,
counts: calculateCounts(version),
}))
// Set up scroll spy after hydration
useEffect(() => {
const handleScroll = () => {
const scrollPosition = window.scrollY + 100 // Offset for header
// Find the current version based on scroll position
let currentVersion: string | null = null
for (const { version } of versionsWithCounts) {
const element = document.getElementById(version.date.toISOString())
if (element) {
const { top } = element.getBoundingClientRect()
if (top <= 100) {
currentVersion = version.date.toISOString()
}
}
}
setActiveVersion(currentVersion)
}
// Initial check
handleScroll()
// Add scroll listener
window.addEventListener('scroll', handleScroll, { passive: true })
return () => {
window.removeEventListener('scroll', handleScroll)
}
}, [versionsWithCounts])
return (
{/* Sidebar */}
Releases
{versionsWithCounts.map(({ version, counts }) => (
))}
{/* Main content */}
{children}
)
}