"use client"; import Image from "next/image"; import { useEffect, useRef, useState } from "react"; import type { NotebookProject } from "./notebookProjects"; import type { NotebookFrame } from "./notebookTimeline"; export type NotebookBrowserProps = { projects: NotebookProject[]; activeIndex: number; frame: Pick< NotebookFrame, "cursorVisible" | "cursorX" | "cursorY" | "cursorClicking" >; onSelectTab: (index: number) => void; interactive?: boolean; }; function clampIndex(index: number, length: number): number { if (length < 1) return -1; return Math.min(Math.max(index, 0), length - 1); } function toDomId(value: string): string { return value.replace(/[^a-zA-Z0-9_-]/g, "-"); } export default function NotebookBrowser({ projects, activeIndex, frame, onSelectTab, interactive = true, }: NotebookBrowserProps) { const selectedIndex = clampIndex(activeIndex, projects.length); const selectedProject = selectedIndex >= 0 ? projects[selectedIndex] : undefined; const previousIndexRef = useRef(selectedIndex); const [outgoingIndex, setOutgoingIndex] = useState(null); useEffect(() => { const previousIndex = previousIndexRef.current; if (previousIndex === selectedIndex) return undefined; previousIndexRef.current = selectedIndex; setOutgoingIndex(previousIndex >= 0 ? previousIndex : null); const timeout = window.setTimeout(() => setOutgoingIndex(null), 180); return () => window.clearTimeout(timeout); }, [selectedIndex]); const outgoingProject = outgoingIndex !== null ? projects[outgoingIndex] : undefined; const nextProject = selectedIndex >= 0 && projects.length > 1 ? projects[(selectedIndex + 1) % projects.length] : undefined; const interactionProps = interactive ? {} : { "aria-hidden": true, inert: true, }; function handleTabKeyDown( event: React.KeyboardEvent, index: number, ) { if (projects.length < 1) return; let nextIndex: number | null = null; if (event.key === "ArrowRight" || event.key === "ArrowDown") { nextIndex = Math.min(index + 1, projects.length - 1); } else if (event.key === "ArrowLeft" || event.key === "ArrowUp") { nextIndex = Math.max(index - 1, 0); } else if (event.key === "Home") { nextIndex = 0; } else if (event.key === "End") { nextIndex = projects.length - 1; } if (nextIndex === null) return; event.preventDefault(); event.currentTarget.parentElement ?.querySelectorAll('[role="tab"]') [nextIndex]?.focus(); onSelectTab(nextIndex); } if (!selectedProject) { return (

Nenhum projeto disponível para esta cena.

); } const selectedId = toDomId(selectedProject.id); const panelId = `notebook-panel-${selectedId}`; return (
Projetos em produção {String(selectedIndex + 1).padStart(2, "0")} /{" "} {String(projects.length).padStart(2, "0")}
Projeto ativo: {selectedProject.title}
{projects.map((project, index) => { const tabId = `notebook-tab-${toDomId(project.id)}`; const isSelected = index === selectedIndex; return ( ); })}

{selectedProject.title}

{selectedProject.subtitle}

    {selectedProject.technologies.slice(0, 4).map((technology) => (
  • {technology}
  • ))}
Abrir projeto
{outgoingProject ? ( ) : null} {`Captura {nextProject ? ( ) : null} {frame.cursorVisible ? (
); }