Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions apps/web/src/app/(home)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
import { HomeLayout } from 'fumadocs-ui/layouts/home';
import { baseOptions } from '@/lib/layout.shared';
import type { Metadata } from 'next';

export const metadata: Metadata = {
title: '@deessejs/errors',
description:
'A TypeScript library that brings Python-inspired error handling to JavaScript. Exception chaining, hierarchical inheritance, and rich error semantics through a function-based API.',
openGraph: {
title: '@deessejs/errors',
description: 'TypeScript error handling reimagined.',
url: '/',
siteName: 'DeesseJS Errors',
locale: 'en_US',
type: 'website',
},
twitter: {
card: 'summary_large_image',
title: '@deessejs/errors',
description: 'TypeScript error handling reimagined.',
},
};

export default function Layout({ children }: LayoutProps<'/'>) {
return <HomeLayout {...baseOptions()}>{children}</HomeLayout>;
Expand Down
28 changes: 27 additions & 1 deletion apps/web/src/app/(home)/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { Metadata } from 'next';
import { CodeBlock } from '@/components/code-block';
import { CtaCard } from '@/components/cta-card';
import { Footer } from '@/components/footer';
import { baseUrl } from '@/lib/shared';

export const metadata: Metadata = {
title: '@deessejs/errors — Error Handling, Reimagined',
Expand Down Expand Up @@ -123,9 +124,34 @@ catch (err) {
}`;

export default function HomePage() {
const softwareJsonLd = {
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name: '@deessejs/errors',
description:
'TypeScript error handling library with exception chaining, hierarchical inheritance, and rich error semantics through a function-based API.',
url: baseUrl,
applicationCategory: 'DeveloperApplication',
operatingSystem: 'Node.js 18+',
programmingLanguage: {
'@type': 'ComputerLanguage',
name: 'TypeScript',
},
license: 'MIT',
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
downloadUrl: 'https://www.npmjs.com/package/@deessejs/errors',
};

return (
<>
{/* Blueprint grid background */}
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(softwareJsonLd).replace(/</g, '\\u003c') }}
/>
<div
className="absolute left-0 right-0 top-0 h-[1000px] pointer-events-none overflow-hidden -z-10"
aria-hidden="true"
Expand Down
115 changes: 94 additions & 21 deletions apps/web/src/app/docs/[[...slug]]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { notFound } from 'next/navigation';
import { getMDXComponents } from '@/components/mdx';
import type { Metadata } from 'next';
import { createRelativeLink } from 'fumadocs-ui/mdx';
import { gitConfig, siteUrl } from '@/lib/shared';
import { gitConfig, baseUrl } from '@/lib/shared';

export default async function Page(props: PageProps<'/docs/[[...slug]]'>) {
const params = await props.params;
Expand All @@ -21,26 +21,99 @@ export default async function Page(props: PageProps<'/docs/[[...slug]]'>) {
const MDX = page.data.body;
const markdownUrl = getPageMarkdownUrl(page).url;

// Generate page-specific JSON-LD
const breadcrumbJsonLd = {
'@context': 'https://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{
'@type': 'ListItem',
position: 1,
name: 'Home',
item: baseUrl,
},
{
'@type': 'ListItem',
position: 2,
name: 'Docs',
item: `${baseUrl}/docs`,
},
{
'@type': 'ListItem',
position: 3,
name: page.data.title,
item: `${baseUrl}${page.url}`,
},
],
};

const techArticleJsonLd = {
'@context': 'https://schema.org',
'@type': 'TechArticle',
name: page.data.title,
description: page.data.description,
about: {
'@type': 'SoftwareApplication',
name: '@deessejs/errors',
},
author: {
'@type': 'Organization',
name: 'Nesalia Inc',
},
datePublished: new Date().toISOString(),
keywords: ['TypeScript', 'error handling', 'exceptions'],
};

// Add APIReference schema for API reference page
const isApiReference = params.slug?.join('/') === 'api-reference';
const apiReferenceJsonLd = isApiReference
? {
'@context': 'https://schema.org',
'@type': 'APIReference',
name: '@deessejs/errors API Reference',
description: 'Complete API reference for @deessejs/errors',
assemblyVersion: '1.0.0',
targetPlatform: 'Node.js',
about: {
'@type': 'SoftwareApplication',
name: '@deessejs/errors',
},
author: {
'@type': 'Organization',
name: 'Nesalia Inc',
},
}
: null;

const schemas = isApiReference
? [breadcrumbJsonLd, techArticleJsonLd, apiReferenceJsonLd]
: [breadcrumbJsonLd, techArticleJsonLd];

return (
<DocsPage toc={page.data.toc} full={page.data.full}>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription className="mb-0">{page.data.description}</DocsDescription>
<div className="flex flex-row gap-2 items-center border-b pb-6">
<MarkdownCopyButton markdownUrl={markdownUrl} />
<ViewOptionsPopover
markdownUrl={markdownUrl}
githubUrl={`https://github.com/${gitConfig.user}/${gitConfig.repo}/blob/${gitConfig.branch}/content/docs/${page.path}`}
/>
</div>
<DocsBody>
<MDX
components={getMDXComponents({
// this allows you to link to other pages with relative file paths
a: createRelativeLink(source, page),
})}
/>
</DocsBody>
</DocsPage>
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(schemas).replace(/</g, '\\u003c') }}
/>
<DocsPage toc={page.data.toc} full={page.data.full}>
<DocsTitle>{page.data.title}</DocsTitle>
<DocsDescription className="mb-0">{page.data.description}</DocsDescription>
<div className="flex flex-row gap-2 items-center border-b pb-6">
<MarkdownCopyButton markdownUrl={markdownUrl} />
<ViewOptionsPopover
markdownUrl={markdownUrl}
githubUrl={`https://github.com/${gitConfig.user}/${gitConfig.repo}/blob/${gitConfig.branch}/content/docs/${page.path}`}
/>
</div>
<DocsBody>
<MDX
components={getMDXComponents({
a: createRelativeLink(source, page),
})}
/>
</DocsBody>
</DocsPage>
</>
);
}

Expand All @@ -57,7 +130,7 @@ export async function generateMetadata(props: PageProps<'/docs/[[...slug]]'>): P
title: page.data.title,
description: page.data.description,
alternates: {
canonical: `${siteUrl}${page.url}`,
canonical: `${baseUrl}${page.url}`,
},
openGraph: {
images: getPageImage(page).url,
Expand Down
51 changes: 50 additions & 1 deletion apps/web/src/app/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { RootProvider } from 'fumadocs-ui/provider/next';
import type { Metadata } from 'next';
import { baseUrl, gitConfig } from '@/lib/shared';
import './global.css';
import { Inter } from 'next/font/google';
import { Analytics } from '@vercel/analytics/next';
Expand All @@ -8,16 +10,63 @@ const inter = Inter({
display: 'swap',
});

export const metadata: Metadata = {
metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL || baseUrl),
title: {
template: '%s | @deessejs/errors',
default: '@deessejs/errors — TypeScript Error Handling',
},
};

function JsonLd() {
const websiteJsonLd = {
'@context': 'https://schema.org',
'@type': 'WebSite',
name: '@deessejs/errors',
url: baseUrl,
description: 'TypeScript error handling library with exception chaining and hierarchical inheritance',
potentialAction: {
'@type': 'SearchAction',
target: {
'@type': 'EntryPoint',
urlTemplate: `${baseUrl}/docs?q={search_term_string}`,
},
'query-input': 'required name=search_term_string',
},
};

const organizationJsonLd = {
'@context': 'https://schema.org',
'@type': 'Organization',
name: 'Nesalia Inc',
url: 'https://nesalia.com',
logo: `${baseUrl}/icon.svg`,
sameAs: [
`https://github.com/${gitConfig.user}`,
],
};

return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify([websiteJsonLd, organizationJsonLd]).replace(/</g, '\\u003c'),
}}
/>
);
}

export default function Layout({ children }: LayoutProps<'/'>) {
return (
<html lang="en" className={inter.className} suppressHydrationWarning>
<head>
<link rel="sitemap" type="application/xml" href="/sitemap.xml" />
<JsonLd />
</head>
<body className="flex flex-col min-h-screen">
<RootProvider>{children}</RootProvider>
<Analytics />
</body>
</html>
);
}
}
Loading
Loading