Download frontend/src/components/Layout.tsx from stadv/sipracd: direct link, hf CLI and curl.
- Browser
- Download file 4.05 kB
-
https://huggingface.co/spaces/stadv/sipracd/resolve/main/frontend/src/components/Layout.tsx
- Command line
-
hf download hf://spaces/stadv/sipracd/frontend/src/components/Layout.tsx
-
curl -L -o Layout.tsx https://huggingface.co/spaces/stadv/sipracd/resolve/main/frontend/src/components/Layout.tsx
4.05 kB
| import { createContext, useContext, useEffect, useLayoutEffect, useMemo, useState } from "react"; | |
| import { NavLink, useLocation } from "react-router-dom"; | |
| import type { PropsWithChildren, ReactNode } from "react"; | |
| const links = [ | |
| { | |
| to: "/processos", | |
| label: "Processos", | |
| matches: (pathname: string) => | |
| pathname === "/processos" || | |
| pathname === "/backlog" || | |
| pathname.startsWith("/trabalho/"), | |
| }, | |
| { to: "/dashboard", label: "Fluxo de Processos", matches: (pathname: string) => pathname === "/dashboard" }, | |
| { | |
| to: "/inscricoes", | |
| label: "Inscrições", | |
| matches: (pathname: string) => pathname === "/inscricoes" || pathname.startsWith("/inscricoes/"), | |
| }, | |
| { to: "/visao-gs", label: "Visão GS", matches: (pathname: string) => pathname === "/visao-gs" }, | |
| { | |
| to: "/cronogramas", | |
| label: "Cronogramas", | |
| matches: (pathname: string) => | |
| pathname === "/cronogramas" || | |
| pathname === "/equipe" || | |
| pathname === "/metas" || | |
| pathname.startsWith("/avaliadores/"), | |
| }, | |
| { to: "/novo", label: "Novo processo", matches: (pathname: string) => pathname === "/novo" }, | |
| ]; | |
| const PageHeaderActionContext = createContext<((action: ReactNode | null) => void) | null>(null); | |
| export function usePageHeaderAction(action: ReactNode | null) { | |
| const setAction = useContext(PageHeaderActionContext); | |
| useLayoutEffect(() => { | |
| if (!setAction) return; | |
| setAction(action); | |
| return () => setAction(null); | |
| }, [action, setAction]); | |
| } | |
| export function Layout({ children }: PropsWithChildren) { | |
| const location = useLocation(); | |
| const [headerAction, setHeaderAction] = useState<ReactNode | null>(null); | |
| const [headerCollapsed, setHeaderCollapsed] = useState(false); | |
| function pageTitle() { | |
| const { pathname } = location; | |
| if (pathname === "/processos" || pathname === "/backlog") return "Processos"; | |
| if (pathname === "/dashboard") return "Fluxo de Processos"; | |
| if (pathname === "/inscricoes") return "Inscrições"; | |
| if (pathname === "/visao-gs") return "Visão GS"; | |
| if (pathname === "/cronogramas" || pathname === "/equipe" || pathname === "/metas") return "Cronogramas"; | |
| if (pathname === "/novo") return "Novo processo"; | |
| if (pathname.startsWith("/avaliadores/")) return "Avaliador"; | |
| if (pathname.startsWith("/trabalho/") && pathname.endsWith("/editar")) return "Editar processo"; | |
| if (pathname.startsWith("/trabalho/")) return "Processo"; | |
| return "SIPRAC"; | |
| } | |
| const headerContextValue = useMemo(() => setHeaderAction, []); | |
| useEffect(() => { | |
| function handleScroll() { | |
| const currentScrollY = window.scrollY; | |
| setHeaderCollapsed(currentScrollY > 96); | |
| } | |
| handleScroll(); | |
| window.addEventListener("scroll", handleScroll, { passive: true }); | |
| return () => window.removeEventListener("scroll", handleScroll); | |
| }, [location.pathname]); | |
| return ( | |
| <PageHeaderActionContext.Provider value={headerContextValue}> | |
| <div className={`app-shell${headerCollapsed ? " app-shell-header-collapsed" : ""}`}> | |
| <header className="app-header"> | |
| <div className="app-header-inner"> | |
| <div className="sidebar-brand"> | |
| <h1>SIPRAC</h1> | |
| <p className="sidebar-copy">Sistema de Processos, Acompanhamento e Cronogramas</p> | |
| </div> | |
| <nav className="nav"> | |
| {links.map((link) => ( | |
| <NavLink | |
| key={link.to} | |
| to={link.to} | |
| className={() => `nav-link${link.matches(location.pathname) ? " active" : ""}`} | |
| > | |
| {link.label} | |
| </NavLink> | |
| ))} | |
| </nav> | |
| </div> | |
| </header> | |
| <main className="main-content"> | |
| <header className="topbar"> | |
| <h2>{pageTitle()}</h2> | |
| {headerAction ? <div className="topbar-action">{headerAction}</div> : null} | |
| </header> | |
| {children} | |
| </main> | |
| </div> | |
| </PageHeaderActionContext.Provider> | |
| ); | |
| } | |