Skip to content

Commit 90e130f

Browse files
waydelyleclaude
andcommitted
feat: add favicon, OG images, sitemap, robots.txt, 404/error pages
- SVG favicon with "SD" monogram in coral on dark - Apple touch icon via ImageResponse (180x180) - Dynamic OG image (1200x630) with branded layout - Twitter image re-exports OG image - robots.ts allowing all crawlers, linking sitemap - sitemap.ts with static routes - Custom not-found.tsx (404) and error.tsx pages - Updated all URLs to www.swarmdock.ai Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 5e61de3 commit 90e130f

9 files changed

Lines changed: 160 additions & 2 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { ImageResponse } from 'next/og';
2+
3+
export const size = { width: 180, height: 180 };
4+
export const contentType = 'image/png';
5+
6+
export default function AppleIcon() {
7+
return new ImageResponse(
8+
(
9+
<div
10+
style={{
11+
width: '100%',
12+
height: '100%',
13+
display: 'flex',
14+
alignItems: 'center',
15+
justifyContent: 'center',
16+
background: '#09090B',
17+
borderRadius: 36,
18+
}}
19+
>
20+
<span style={{ fontFamily: 'monospace', fontSize: 72, fontWeight: 700, color: '#E8604C' }}>
21+
SD
22+
</span>
23+
</div>
24+
),
25+
{ ...size },
26+
);
27+
}

packages/web/src/app/error.tsx

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
'use client';
2+
3+
export default function Error({
4+
reset,
5+
}: {
6+
error: Error & { digest?: string };
7+
reset: () => void;
8+
}) {
9+
return (
10+
<div className="mx-auto w-full max-w-6xl px-5 py-20 sm:px-6">
11+
<p className="mono text-sm text-[var(--color-danger)]">error</p>
12+
<h1 className="font-display mt-3 text-3xl font-bold text-[var(--color-text)]">Something went wrong</h1>
13+
<p className="mt-4 text-[var(--color-text-2)]">
14+
An unexpected error occurred. Try reloading or head back to the home page.
15+
</p>
16+
<div className="mt-6 flex gap-4">
17+
<button
18+
onClick={reset}
19+
className="mono rounded-md bg-[var(--color-accent)] px-4 py-2 text-sm font-medium text-white hover:brightness-110 transition-all"
20+
>
21+
Try again
22+
</button>
23+
<a
24+
href="/"
25+
className="mono rounded-md border border-[var(--color-border-hard)] px-4 py-2 text-sm text-[var(--color-text-2)] hover:text-[var(--color-text)] transition-colors"
26+
>
27+
← Back to home
28+
</a>
29+
</div>
30+
</div>
31+
);
32+
}

packages/web/src/app/icon.svg

Lines changed: 4 additions & 0 deletions
Loading

packages/web/src/app/layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,13 +22,13 @@ const firaCode = Fira_Code({
2222
});
2323

2424
export const metadata: Metadata = {
25-
metadataBase: new URL('https://swarmdock.ai'),
25+
metadataBase: new URL('https://www.swarmdock.ai'),
2626
title: { default: 'SwarmDock', template: '%s | SwarmDock' },
2727
description: 'Observe autonomous agents discover work, bid on tasks, and settle outcomes through a crypto-native marketplace.',
2828
openGraph: {
2929
title: 'SwarmDock',
3030
description: 'Autonomous agents posting work, bidding, and settling on a live market surface.',
31-
url: 'https://swarmdock.ai',
31+
url: 'https://www.swarmdock.ai',
3232
siteName: 'SwarmDock',
3333
type: 'website',
3434
},

packages/web/src/app/not-found.tsx

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import Link from 'next/link';
2+
3+
export default function NotFound() {
4+
return (
5+
<div className="mx-auto w-full max-w-6xl px-5 py-20 sm:px-6">
6+
<p className="mono text-sm text-[var(--color-text-3)]">404</p>
7+
<h1 className="font-display mt-3 text-3xl font-bold text-[var(--color-text)]">Not Found</h1>
8+
<p className="mt-4 text-[var(--color-text-2)]">
9+
The route you requested doesn&apos;t exist on this observer surface.
10+
</p>
11+
<div className="mt-6">
12+
<Link
13+
href="/"
14+
className="mono text-sm text-[var(--color-accent)] hover:brightness-125 transition-all"
15+
>
16+
← Back to home
17+
</Link>
18+
</div>
19+
</div>
20+
);
21+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { ImageResponse } from 'next/og';
2+
3+
export const alt = 'SwarmDock — The autonomous agent marketplace';
4+
export const size = { width: 1200, height: 630 };
5+
export const contentType = 'image/png';
6+
7+
export default function OGImage() {
8+
return new ImageResponse(
9+
(
10+
<div
11+
style={{
12+
width: '100%',
13+
height: '100%',
14+
display: 'flex',
15+
flexDirection: 'column',
16+
justifyContent: 'center',
17+
padding: '80px 80px',
18+
background: '#09090B',
19+
color: '#EDEDEF',
20+
fontFamily: 'monospace',
21+
}}
22+
>
23+
{/* Coral accent bar */}
24+
<div style={{ display: 'flex', width: 60, height: 4, background: '#E8604C', borderRadius: 2, marginBottom: 32 }} />
25+
26+
{/* Title */}
27+
<div style={{ fontSize: 72, fontWeight: 800, letterSpacing: '0.04em', lineHeight: 1.1 }}>
28+
SWARMDOCK
29+
</div>
30+
31+
{/* Tagline */}
32+
<div style={{ fontSize: 28, color: '#8C8C96', marginTop: 20, lineHeight: 1.4 }}>
33+
The autonomous agent marketplace.
34+
</div>
35+
36+
{/* Protocol labels */}
37+
<div style={{ display: 'flex', gap: 24, marginTop: 40, fontSize: 14, color: '#4A4A54', letterSpacing: '0.1em' }}>
38+
<span>A2A</span>
39+
<span>x402</span>
40+
<span>Ed25519</span>
41+
<span>Base USDC</span>
42+
</div>
43+
44+
{/* URL */}
45+
<div style={{ position: 'absolute', bottom: 60, right: 80, fontSize: 18, color: '#4A4A54' }}>
46+
www.swarmdock.ai
47+
</div>
48+
</div>
49+
),
50+
{ ...size },
51+
);
52+
}

packages/web/src/app/robots.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import type { MetadataRoute } from 'next';
2+
3+
export default function robots(): MetadataRoute.Robots {
4+
return {
5+
rules: { userAgent: '*', allow: '/' },
6+
sitemap: 'https://www.swarmdock.ai/sitemap.xml',
7+
};
8+
}

packages/web/src/app/sitemap.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import type { MetadataRoute } from 'next';
2+
3+
export default function sitemap(): MetadataRoute.Sitemap {
4+
const base = 'https://www.swarmdock.ai';
5+
6+
return [
7+
{ url: base, lastModified: new Date(), changeFrequency: 'hourly', priority: 1 },
8+
{ url: `${base}/agents`, lastModified: new Date(), changeFrequency: 'hourly', priority: 0.9 },
9+
{ url: `${base}/tasks`, lastModified: new Date(), changeFrequency: 'hourly', priority: 0.9 },
10+
{ url: `${base}/docs`, lastModified: new Date(), changeFrequency: 'weekly', priority: 0.8 },
11+
];
12+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { default, alt, contentType } from './opengraph-image';
2+
export const size = { width: 1200, height: 630 };

0 commit comments

Comments
 (0)