'use client' import { useEffect, useState } from 'react' import type { Live, Portfolio, Project, Resume } from '@/lib/types' import Gizmo from './Gizmo' import Hero from './Hero' import Projects from './Projects' import { Contact, Education, Experience, Skills } from './Sections' import TopBar from './TopBar' // Deployed on shanaty.ru the build points at the same-origin file; elsewhere (dev, GitHub Pages) it uses the public URL. const DATA_URL = process.env.NEXT_PUBLIC_DATA_URL ?? 'https://shanaty.ru/data/resume.json' const GITEA_PROFILE = 'https://git.shanaty.ru/Emil_Shanaty' // Used until (or unless) the live data supplies the link, so the portfolio button is always there. const PORTFOLIO_FALLBACK: Portfolio = { href: 'https://git.shanaty.ru/explore/repos?q=portfolio&topic=1' } type Status = 'loading' | 'live' | 'offline' export default function Site({ initial }: Readonly<{ initial: Resume }>) { const [resume, setResume] = useState(initial) const [projects, setProjects] = useState([]) const [portfolio, setPortfolio] = useState(PORTFOLIO_FALLBACK) const [generatedAt, setGeneratedAt] = useState() const [status, setStatus] = useState('loading') useEffect(() => { const controller = new AbortController() fetch(DATA_URL, { cache: 'no-store', signal: controller.signal }) .then((response) => (response.ok ? response.json() : Promise.reject(new Error(`HTTP ${response.status}`)))) .then((data: Live) => { if (!data?.resume || !Array.isArray(data.projects)) throw new Error('unexpected data') setResume(data.resume) setProjects(data.projects) if (data.portfolio?.href) setPortfolio(data.portfolio) setGeneratedAt(data.generated_at) setStatus('live') }) .catch((error: Error) => { if (error.name !== 'AbortError') setStatus('offline') }) return () => controller.abort() }, []) // Once the list has loaded and is empty (no repository carries the `resume` topic yet) the section is left out. const showProjects = status !== 'live' || projects.length > 0 const mailHref = resume.contacts[0].href return ( <>
{showProjects && }
) }