4c0942d11b
- autogen page.js: wrap engineCall in try/catch (return null on any failure) - /zero page: use Promise.allSettled so one failed source doesn't break page Root cause was ENGINE_URL=host.docker.internal not resolving in coolify net, fixed at env level but defending code too so future quirks degrade gracefully.
79 lines
3.5 KiB
JavaScript
79 lines
3.5 KiB
JavaScript
import Header from '@/components/Header';
|
||
import Footer from '@/components/Footer';
|
||
import ZeroBlock from '@/components/ZeroBlock';
|
||
import { listZeroNotes, getZeroCharacter } from '@/lib/engine';
|
||
import { Coffee } from 'lucide-react';
|
||
|
||
export const dynamic = 'force-dynamic';
|
||
export const metadata = {
|
||
title: 'Заметки от Зеро',
|
||
description: 'Короткие посты от AI-персонажа Зеро — мысли программиста о работе, инструментах и забавных багах',
|
||
};
|
||
|
||
export default async function ZeroPage() {
|
||
// defensive: один битый источник не должен валить страницу
|
||
const results = await Promise.allSettled([
|
||
listZeroNotes({ limit: 100 }),
|
||
getZeroCharacter(),
|
||
]);
|
||
const notes = results[0].status === 'fulfilled' ? results[0].value : [];
|
||
const character = results[1].status === 'fulfilled' ? results[1].value : null;
|
||
|
||
return (
|
||
<>
|
||
<Header />
|
||
<main className="pt-10 pb-16">
|
||
<div className="container-wide mb-10">
|
||
<div
|
||
className="inline-flex items-center gap-2 text-xs accent px-3 py-1.5 rounded-full mb-4"
|
||
style={{ background: 'rgb(var(--accent) / 0.1)', border: '1px solid rgb(var(--accent) / 0.2)' }}
|
||
>
|
||
<Coffee className="w-3.5 h-3.5" /> AI-персонаж
|
||
</div>
|
||
<h1 className="text-3xl sm:text-5xl font-bold ink mb-3 leading-tight">
|
||
Заметки от Зеро
|
||
</h1>
|
||
<p className="mute text-base sm:text-lg max-w-2xl mb-8">
|
||
Короткие посты от первого лица в Telegram-канале{' '}
|
||
<a href="https://t.me/zeropostru" target="_blank" rel="noreferrer" className="accent hover:underline">@zeropostru</a>.
|
||
Программист с многолетним опытом, любит копаться под капотом, постоянно носится с кофе.
|
||
</p>
|
||
|
||
{character?.character?.bio && (
|
||
<div className="rounded-xl border border-amber-200 dark:border-amber-900 bg-amber-50/50 dark:bg-amber-950/20 p-5 sm:p-6 max-w-3xl">
|
||
<div className="flex items-start gap-4">
|
||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||
<img
|
||
src="/uploads/zero-coffee.webp"
|
||
alt="Зеро"
|
||
className="w-16 h-16 rounded-full object-cover bg-amber-100 dark:bg-amber-950/40 ring-2 ring-amber-300 dark:ring-amber-800 shrink-0"
|
||
/>
|
||
<div className="min-w-0">
|
||
<div className="text-sm font-semibold ink mb-2">Кто такой Зеро</div>
|
||
<ul className="space-y-1 text-sm mute">
|
||
{character.character.bio.map((line, i) => (
|
||
<li key={i}>— {line}</li>
|
||
))}
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</div>
|
||
|
||
{notes.length > 0 ? (
|
||
<ZeroBlock notes={notes} />
|
||
) : (
|
||
<div className="container-wide">
|
||
<div className="rounded-xl border border-neutral-200 dark:border-neutral-800 p-10 text-center">
|
||
<Coffee className="w-8 h-8 text-amber-500 mx-auto mb-3" />
|
||
<p className="mute text-sm">Зеро ещё не написал ни одной заметки. Скоро появится.</p>
|
||
</div>
|
||
</div>
|
||
)}
|
||
</main>
|
||
<Footer />
|
||
</>
|
||
);
|
||
}
|