My personal website
1import { CardArticle } from '@/components/CardArticle/CardArticle';
2import { Divider } from '@/components/Divider/Divider';
3import { Heading } from '@/components/Heading/Heading';
4import { Aside, Layout, Main } from '@/components/Layout/Layout';
5import { Link } from '@/components/Link/Link';
6import { Paragraph } from '@/components/Paragraph/Paragraph';
7import TLDRProfile from '@/components/TLDRProfile/TLDRProfile';
8import { useLeaflet } from '@/hooks/atproto';
9import type { JSX } from 'react';
10import { Helmet } from 'react-helmet-async';
11
12/**
13 * Writing page component - displays blog posts from AT Protocol PDS
14 *
15 * @returns JSX element with writing page content
16 */
17
18export default function WritingPage(): JSX.Element {
19 const { data: documents, loading, error } = useLeaflet();
20
21 const jsonLd = {
22 '@context': 'https://schema.org',
23 '@type': 'CollectionPage',
24 name: 'Writing by Barry Prendergast',
25 description: 'Articles and writing on design strategy, product design, and design operations.',
26 url: 'https://renderg.host/writing',
27 author: {
28 '@type': 'Person',
29 name: 'Barry Prendergast',
30 url: 'https://renderg.host',
31 },
32 };
33
34 return (
35 <>
36 <Helmet>
37 <title>Writing | Barry Prendergast</title>
38 <meta
39 name="description"
40 content="Articles and writing on design strategy, product design, and design operations by Barry Prendergast."
41 />
42 <script type="application/ld+json" dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }} />
43 </Helmet>
44
45 <Layout theme="default">
46 <Main>
47 <div className="flex flex-col gap-12">
48 <Heading level={2} size="md">
49 writing / <Link href="/">renderg.host</Link>
50 </Heading>
51
52 <Paragraph size="lg">Thoughts on design strategy, product design, and building better products.</Paragraph>
53
54 {loading && <Paragraph size="lg">Loading posts...</Paragraph>}
55
56 {error && <Paragraph size="lg">Error loading posts: {error}</Paragraph>}
57
58 {!loading && !error && (!documents || documents.length === 0) && (
59 <Paragraph size="lg">No posts found.</Paragraph>
60 )}
61
62 {!loading && !error && documents && documents.length > 0 && (
63 <div className="grid grid-cols-1 border-2 border-bones-black-20 dark:border-bones-white-20">
64 {documents.map((doc, index) => (
65 <>
66 <CardArticle
67 key={doc.uri}
68 article={{
69 title: doc.title,
70 subtitle: doc.description || '',
71 coverImage: '',
72 articleUrl: doc.articleUrl,
73 publication: doc.publication.name,
74 publicationIcon: doc.publication.icon,
75 published: doc.publishedAt,
76 }}
77 />
78 {index < documents.length - 1 && <Divider />}
79 </>
80 ))}
81 </div>
82 )}
83
84 <Paragraph size="lg">
85 <Link href="/">← Back to Home</Link>
86 </Paragraph>
87 </div>
88 </Main>
89
90 <Aside>
91 <TLDRProfile />
92 </Aside>
93 </Layout>
94 </>
95 );
96}