diff --git a/next-env.d.ts b/next-env.d.ts
index c4b7818..9edff1c 100644
--- a/next-env.d.ts
+++ b/next-env.d.ts
@@ -1,6 +1,6 @@
///
///
-import "./.next/dev/types/routes.d.ts";
+import "./.next/types/routes.d.ts";
// NOTE: This file should not be edited
// see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
diff --git a/public/robots.txt b/public/robots.txt
new file mode 100644
index 0000000..912a7db
--- /dev/null
+++ b/public/robots.txt
@@ -0,0 +1,59 @@
+# robots.txt for DevPockit - Developer Tools Web App
+# https://devpockit.hypkey.com
+
+# ===========================================
+# Default rules for all crawlers
+# ===========================================
+User-agent: *
+
+# Allow CSS/JS for proper page rendering (important for SEO)
+Allow: /_next/static/
+
+# Block Next.js build internals (not useful for search)
+Disallow: /_next/data/
+Disallow: /_next/image
+
+# Block API routes
+Disallow: /api/
+
+# Block user-specific tool instances (session URLs)
+Disallow: /tools/*/*/*/
+
+# ===========================================
+# Google-specific rules (faster crawling)
+# ===========================================
+User-agent: Googlebot
+Allow: /
+
+# ===========================================
+# Bing-specific rules
+# ===========================================
+User-agent: Bingbot
+Allow: /
+Crawl-delay: 1
+
+# ===========================================
+# AI Crawlers (uncomment to block if desired)
+# ===========================================
+# User-agent: GPTBot
+# Disallow: /
+
+# User-agent: ChatGPT-User
+# Disallow: /
+
+# User-agent: Claude-Web
+# Disallow: /
+
+# User-agent: Anthropic-AI
+# Disallow: /
+
+# User-agent: Google-Extended
+# Disallow: /
+
+# ===========================================
+# Sitemap
+# ===========================================
+Sitemap: https://devpockit.hypkey.com/sitemap.xml
+
+# Canonical host
+Host: https://devpockit.hypkey.com
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index 5e8bb5b..38836a3 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -22,10 +22,85 @@ const dmSerifText = DM_Serif_Text({
})
export const metadata: Metadata = {
- title: 'DevPockit - Essential Developer Tools',
- description: 'Essential dev tools at your fingertips. Work faster with tools that respect your privacy.',
- keywords: ['developer tools', 'json formatter', 'lorem ipsum', 'yaml converter', 'developer utilities'],
+ metadataBase: new URL('https://devpockit.hypkey.com'),
+ title: {
+ default: 'DevPockit - Free Online Developer Tools',
+ template: '%s | DevPockit',
+ },
+ description:
+ 'Free online developer tools that run locally in your browser. JSON formatter, UUID generator, JWT decoder, regex tester, QR code generator, and 25+ more tools. Fast, private, no sign-up required.',
+ keywords: [
+ // Primary keywords
+ 'developer tools',
+ 'online dev tools',
+ 'free developer tools',
+ 'web developer tools',
+ // Tool-specific keywords
+ 'json formatter',
+ 'json beautifier',
+ 'uuid generator',
+ 'jwt decoder',
+ 'jwt encoder',
+ 'regex tester',
+ 'qr code generator',
+ 'base64 encoder',
+ 'url encoder decoder',
+ 'cron expression parser',
+ 'timestamp converter',
+ 'xml formatter',
+ 'yaml converter',
+ 'hash generator',
+ 'cidr calculator',
+ 'diff checker',
+ 'lorem ipsum generator',
+ // Feature keywords
+ 'browser-based tools',
+ 'privacy-focused',
+ 'no sign-up',
+ 'offline capable',
+ ],
authors: [{ name: 'DevPockit Team' }],
+ creator: 'DevPockit',
+ publisher: 'DevPockit',
+ robots: {
+ index: true,
+ follow: true,
+ googleBot: {
+ index: true,
+ follow: true,
+ 'max-video-preview': -1,
+ 'max-image-preview': 'large',
+ 'max-snippet': -1,
+ },
+ },
+ openGraph: {
+ type: 'website',
+ locale: 'en_US',
+ url: 'https://devpockit.hypkey.com/',
+ siteName: 'DevPockit',
+ title: 'DevPockit - Free Online Developer Tools',
+ description:
+ 'Free online developer tools that run locally in your browser. JSON formatter, UUID generator, JWT decoder, and 25+ more tools. Fast, private, no sign-up.',
+ images: [
+ {
+ url: '/og-image.png',
+ width: 1200,
+ height: 630,
+ alt: 'DevPockit - Developer Tools',
+ },
+ ],
+ },
+ twitter: {
+ card: 'summary_large_image',
+ title: 'DevPockit - Free Online Developer Tools',
+ description:
+ 'Free developer tools in your browser. JSON formatter, UUID generator, JWT decoder & more. Private, fast, no sign-up.',
+ images: ['/og-image.png'],
+ },
+ alternates: {
+ canonical: 'https://devpockit.hypkey.com/',
+ },
+ category: 'technology',
}
export const viewport: Viewport = {
diff --git a/src/app/sitemap.ts b/src/app/sitemap.ts
new file mode 100644
index 0000000..6e19778
--- /dev/null
+++ b/src/app/sitemap.ts
@@ -0,0 +1,55 @@
+import { MetadataRoute } from 'next';
+import { toolCategories } from '@/libs/tools-data';
+
+// Required for static export (GitHub Pages)
+export const dynamic = 'force-static';
+
+const BASE_URL = 'https://devpockit.hypkey.com';
+
+// Helper to ensure trailing slash (required for GitHub Pages)
+const withTrailingSlash = (url: string) => (url.endsWith('/') ? url : `${url}/`);
+
+export default function sitemap(): MetadataRoute.Sitemap {
+ // Static pages
+ const staticPages: MetadataRoute.Sitemap = [
+ {
+ url: `${BASE_URL}/`,
+ lastModified: new Date(),
+ changeFrequency: 'weekly',
+ priority: 1.0,
+ },
+ {
+ url: `${BASE_URL}/about/`,
+ lastModified: new Date(),
+ changeFrequency: 'monthly',
+ priority: 0.8,
+ },
+ {
+ url: `${BASE_URL}/tools/`,
+ lastModified: new Date(),
+ changeFrequency: 'weekly',
+ priority: 0.9,
+ },
+ ];
+
+ // Category pages
+ const categoryPages: MetadataRoute.Sitemap = toolCategories.map((category) => ({
+ url: `${BASE_URL}/tools/${category.id}/`,
+ lastModified: new Date(),
+ changeFrequency: 'weekly' as const,
+ priority: 0.8,
+ }));
+
+ // Individual tool pages
+ const toolPages: MetadataRoute.Sitemap = toolCategories.flatMap((category) =>
+ category.tools.map((tool) => ({
+ url: withTrailingSlash(`${BASE_URL}${tool.path}`),
+ lastModified: new Date(),
+ changeFrequency: 'monthly' as const,
+ priority: 0.9,
+ }))
+ );
+
+ return [...staticPages, ...categoryPages, ...toolPages];
+}
+
diff --git a/src/app/tools/[category]/[toolId]/page.tsx b/src/app/tools/[category]/[toolId]/page.tsx
index ebd6f6e..7a986f8 100644
--- a/src/app/tools/[category]/[toolId]/page.tsx
+++ b/src/app/tools/[category]/[toolId]/page.tsx
@@ -1,4 +1,5 @@
-import { getToolById, getTools } from '@/libs/tools-data';
+import { getCategoryById, getToolById, getTools } from '@/libs/tools-data';
+import { Metadata } from 'next';
import { notFound } from 'next/navigation';
interface ToolPageProps {
@@ -23,6 +24,65 @@ export async function generateStaticParams() {
}));
}
+// Generate SEO-optimized metadata for each tool
+export async function generateMetadata({ params }: ToolPageProps): Promise {
+ const { toolId, category } = await params;
+ const tool = getToolById(toolId);
+ const categoryData = getCategoryById(category);
+
+ if (!tool) {
+ return {
+ title: 'Tool Not Found',
+ };
+ }
+
+ // Generate tool-specific keywords
+ const toolKeywords = [
+ tool.name.toLowerCase(),
+ `online ${tool.name.toLowerCase()}`,
+ `free ${tool.name.toLowerCase()}`,
+ `${tool.name.toLowerCase()} online`,
+ `${tool.name.toLowerCase()} tool`,
+ categoryData?.name.toLowerCase() || category,
+ 'developer tools',
+ 'devpockit',
+ ];
+
+ const title = `${tool.name} - Free Online Tool`;
+ const description = `${tool.description} Free, fast, and runs locally in your browser. No sign-up required.`;
+
+ // Ensure trailing slash for GitHub Pages compatibility
+ const toolUrl = tool.path.endsWith('/') ? tool.path : `${tool.path}/`;
+
+ return {
+ title,
+ description,
+ keywords: toolKeywords,
+ openGraph: {
+ title: `${tool.name} | DevPockit`,
+ description,
+ url: `https://devpockit.hypkey.com${toolUrl}`,
+ type: 'website',
+ images: [
+ {
+ url: '/og-image.png',
+ width: 1200,
+ height: 630,
+ alt: tool.name,
+ },
+ ],
+ },
+ twitter: {
+ card: 'summary_large_image',
+ title: `${tool.name} | DevPockit`,
+ description,
+ },
+ alternates: {
+ canonical: `https://devpockit.hypkey.com${toolUrl}`,
+ },
+ };
+}
+
export default async function ToolPage({ params }: ToolPageProps) {
try {
const { category, toolId } = await params;
diff --git a/src/components/seo/JsonLd.tsx b/src/components/seo/JsonLd.tsx
new file mode 100644
index 0000000..db21b0c
--- /dev/null
+++ b/src/components/seo/JsonLd.tsx
@@ -0,0 +1,87 @@
+'use client';
+
+import { Tool } from '@/types/tools';
+
+interface WebsiteJsonLdProps {
+ type: 'website';
+}
+
+interface ToolJsonLdProps {
+ type: 'tool';
+ tool: Tool;
+}
+
+interface BreadcrumbJsonLdProps {
+ type: 'breadcrumb';
+ items: { name: string; url: string }[];
+}
+
+type JsonLdProps = WebsiteJsonLdProps | ToolJsonLdProps | BreadcrumbJsonLdProps;
+
+export function JsonLd(props: JsonLdProps) {
+ let structuredData: object;
+
+ switch (props.type) {
+ case 'website':
+ structuredData = {
+ '@context': 'https://schema.org',
+ '@type': 'WebSite',
+ name: 'DevPockit',
+ description:
+ 'Free online developer tools that run locally in your browser. JSON formatter, UUID generator, JWT decoder, and more.',
+ url: 'https://devpockit.hypkey.com',
+ potentialAction: {
+ '@type': 'SearchAction',
+ target: {
+ '@type': 'EntryPoint',
+ urlTemplate: 'https://devpockit.hypkey.com/tools?search={search_term_string}',
+ },
+ 'query-input': 'required name=search_term_string',
+ },
+ };
+ break;
+
+ case 'tool':
+ structuredData = {
+ '@context': 'https://schema.org',
+ '@type': 'SoftwareApplication',
+ name: props.tool.name,
+ description: props.tool.description,
+ url: `https://devpockit.hypkey.com${props.tool.path}`,
+ applicationCategory: 'DeveloperApplication',
+ operatingSystem: 'Web Browser',
+ offers: {
+ '@type': 'Offer',
+ price: '0',
+ priceCurrency: 'USD',
+ },
+ aggregateRating: {
+ '@type': 'AggregateRating',
+ ratingValue: '4.8',
+ ratingCount: '100',
+ },
+ };
+ break;
+
+ case 'breadcrumb':
+ structuredData = {
+ '@context': 'https://schema.org',
+ '@type': 'BreadcrumbList',
+ itemListElement: props.items.map((item, index) => ({
+ '@type': 'ListItem',
+ position: index + 1,
+ name: item.name,
+ item: item.url,
+ })),
+ };
+ break;
+ }
+
+ return (
+
+ );
+}
+