feat(web): add comprehensive /publish page with full publishing guide

- Create new /publish page with step-by-step instructions
- Show all 3 metadata tiers (Minimal, Basic, Rich) with examples
- Include quality score explanation and real-world examples
- Add category reference and tips for success
- Update homepage with Publish navigation link
- Add Publish Your Tool promotional section to homepage

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Ajax Davis 2025-11-29 22:19:43 +10:00
parent 7f5d307c0f
commit e38e627a07
2 changed files with 489 additions and 3 deletions

View file

@ -32,9 +32,11 @@ export default function HomePage(): React.ReactElement {
Playground
</Button>
</Link>
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
Documentation
</Button>
<Link href="/publish">
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
Publish
</Button>
</Link>
<Button variant="secondary" size="sm">
Sign In
</Button>
@ -104,6 +106,49 @@ export default function HomePage(): React.ReactElement {
</div>
</Container>
</section>
{/* Publish Your Tool Section */}
<section className="py-16 bg-surface">
<Container size="xl" padding="lg">
<div className="text-center max-w-3xl mx-auto">
<h2 className="text-3xl md:text-4xl font-bold mb-4 text-foreground">
Publish Your AI Tool
</h2>
<p className="text-lg text-foreground-secondary mb-8">
Share your tool with the AI community. Automatic discovery, quality scoring, and
seamless integration with popular AI frameworks.
</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
<div className="p-4">
<div className="text-3xl mb-2">🚀</div>
<h3 className="font-semibold mb-1 text-foreground">Quick Setup</h3>
<p className="text-sm text-foreground-secondary">
Add one keyword to package.json and publish to NPM
</p>
</div>
<div className="p-4">
<div className="text-3xl mb-2"></div>
<h3 className="font-semibold mb-1 text-foreground">Auto Discovery</h3>
<p className="text-sm text-foreground-secondary">
Your tool appears on tpmjs.com within 15 minutes
</p>
</div>
<div className="p-4">
<div className="text-3xl mb-2">📊</div>
<h3 className="font-semibold mb-1 text-foreground">Quality Metrics</h3>
<p className="text-sm text-foreground-secondary">
Automatic scoring based on docs, downloads, and stars
</p>
</div>
</div>
<Link href="/publish">
<Button size="lg" variant="default">
Learn How to Publish
</Button>
</Link>
</div>
</Container>
</section>
</main>
{/* Footer */}

View file

@ -0,0 +1,441 @@
import { Button } from '@tpmjs/ui/Button/Button';
import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
import { Container } from '@tpmjs/ui/Container/Container';
import { Header } from '@tpmjs/ui/Header/Header';
import Link from 'next/link';
import { ThemeToggle } from '../../components/ThemeToggle';
export const metadata = {
title: 'Publish a Tool | TPMJS',
description: 'Learn how to publish your AI tool to the TPMJS registry',
};
export default function PublishPage(): React.ReactElement {
return (
<div className="min-h-screen flex flex-col bg-background">
{/* Header */}
<Header
title={
<Link
href="/"
className="text-foreground hover:text-foreground text-xl md:text-2xl font-bold uppercase tracking-tight"
>
TPMJS
</Link>
}
size="md"
sticky={true}
actions={
<div className="flex items-center gap-4">
<Link href="/tool/tool-search">
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
Tools
</Button>
</Link>
<Link href="/playground">
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
Playground
</Button>
</Link>
<Link href="/publish">
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
Publish
</Button>
</Link>
<ThemeToggle />
</div>
}
/>
<main className="flex-1 py-16">
<Container size="lg" padding="lg">
{/* Hero */}
<div className="text-center mb-16">
<h1 className="text-4xl md:text-5xl font-bold mb-4 text-foreground">
Publish Your AI Tool
</h1>
<p className="text-xl text-foreground-secondary max-w-2xl mx-auto">
Share your tool with the world. Automatic discovery, quality scoring, and AI agent
integration.
</p>
</div>
{/* Quick Start */}
<section className="mb-16">
<h2 className="text-3xl font-bold mb-6 text-foreground">Quick Start</h2>
<div className="prose prose-invert max-w-none">
<ol className="space-y-4 text-foreground-secondary">
<li className="text-lg">Create a new NPM package</li>
<li className="text-lg">
Add{' '}
<code className="text-foreground bg-surface px-2 py-1 rounded">tpmjs-tool</code>{' '}
to keywords
</li>
<li className="text-lg">
Add a <code className="text-foreground bg-surface px-2 py-1 rounded">tpmjs</code>{' '}
field with metadata
</li>
<li className="text-lg">Publish to NPM</li>
<li className="text-lg">
Your tool appears on{' '}
<Link href="/tool/tool-search" className="text-primary hover:underline">
tpmjs.com
</Link>{' '}
within 15 minutes!
</li>
</ol>
</div>
</section>
{/* Step 1: Package.json Setup */}
<section className="mb-16">
<h2 className="text-3xl font-bold mb-6 text-foreground">
Step 1: Add Required Keyword
</h2>
<p className="text-lg text-foreground-secondary mb-6">
Add the{' '}
<code className="text-foreground bg-surface px-2 py-1 rounded">tpmjs-tool</code>{' '}
keyword to your package.json. This is required for automatic discovery.
</p>
<CodeBlock
language="json"
code={`{
"name": "@yourname/my-awesome-tool",
"version": "1.0.0",
"keywords": ["tpmjs-tool", "ai", "text"],
...
}`}
/>
</section>
{/* Step 2: Metadata Tiers */}
<section className="mb-16">
<h2 className="text-3xl font-bold mb-6 text-foreground">Step 2: Add TPMJS Metadata</h2>
<p className="text-lg text-foreground-secondary mb-6">
There are three tiers of metadata. Higher tiers get better visibility and quality
scores.
</p>
{/* Tier 1: Minimal */}
<div className="mb-8 p-6 border border-border rounded-lg bg-surface">
<div className="flex items-center gap-3 mb-4">
<span className="px-3 py-1 bg-foreground/10 rounded text-sm font-medium text-foreground">
Tier 1: Minimal
</span>
<span className="text-foreground-secondary">Required fields only</span>
</div>
<CodeBlock
language="json"
code={`{
"tpmjs": {
"category": "text-analysis",
"description": "A concise description of what your tool does",
"example": "const result = await myTool({ input: 'hello' });"
}
}`}
/>
<p className="mt-4 text-sm text-foreground-secondary">
Quality Score: <strong className="text-foreground">1x base multiplier</strong>
</p>
</div>
{/* Tier 2: Basic */}
<div className="mb-8 p-6 border border-border rounded-lg bg-surface">
<div className="flex items-center gap-3 mb-4">
<span className="px-3 py-1 bg-primary/20 rounded text-sm font-medium text-foreground">
Tier 2: Basic
</span>
<span className="text-foreground-secondary">Add parameter & return info</span>
</div>
<CodeBlock
language="json"
code={`{
"tpmjs": {
"category": "text-analysis",
"description": "Analyzes sentiment in text",
"example": "const result = await analyzeSentiment({ text: 'I love this!' });",
"parameters": [
{
"name": "text",
"type": "string",
"description": "The text to analyze",
"required": true
},
{
"name": "language",
"type": "string",
"description": "Language code (e.g., 'en')",
"required": false,
"default": "en"
}
],
"returns": {
"type": "SentimentResult",
"description": "Object with score and label"
}
}
}`}
/>
<p className="mt-4 text-sm text-foreground-secondary">
Quality Score: <strong className="text-foreground">2x base multiplier</strong>
</p>
</div>
{/* Tier 3: Rich */}
<div className="mb-8 p-6 border border-border rounded-lg bg-surface">
<div className="flex items-center gap-3 mb-4">
<span className="px-3 py-1 bg-success/20 rounded text-sm font-medium text-foreground">
Tier 3: Rich
</span>
<span className="text-foreground-secondary">Full documentation</span>
</div>
<CodeBlock
language="json"
code={`{
"tpmjs": {
"category": "text-analysis",
"description": "Advanced sentiment analysis with emotion detection",
"example": "const result = await analyzeSentiment({ text: 'I love this!', includeEmotions: true });",
"parameters": [...],
"returns": {...},
"authentication": {
"type": "api-key",
"required": true
},
"pricing": {
"model": "pay-per-use",
"cost": "$0.001 per request"
},
"frameworks": ["vercel-ai", "langchain"],
"links": {
"documentation": "https://docs.example.com",
"repository": "https://github.com/yourname/tool",
"homepage": "https://yourwebsite.com"
},
"tags": ["sentiment", "nlp", "emotions"],
"status": "stable",
"aiAgent": {
"useCase": "Use when users need to analyze sentiment or detect emotions",
"limitations": "English and Spanish only. Max 10,000 characters",
"examples": [
"Analyze customer review sentiment",
"Detect emotions in feedback"
]
}
}
}`}
/>
<p className="mt-4 text-sm text-foreground-secondary">
Quality Score: <strong className="text-foreground">4x base multiplier</strong> 🚀
</p>
</div>
</section>
{/* Categories */}
<section className="mb-16">
<h2 className="text-3xl font-bold mb-6 text-foreground">Available Categories</h2>
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
{[
{ name: 'text-analysis', desc: 'NLP, sentiment, summarization' },
{ name: 'code-generation', desc: 'Code generation and transformation' },
{ name: 'data-processing', desc: 'Data manipulation and transformation' },
{ name: 'image-generation', desc: 'Image creation and editing' },
{ name: 'audio-processing', desc: 'Audio/speech processing' },
{ name: 'search', desc: 'Search and retrieval' },
{ name: 'integration', desc: 'Third-party integrations' },
{ name: 'other', desc: 'Anything else' },
].map((cat) => (
<div key={cat.name} className="p-4 border border-border rounded-lg bg-surface">
<code className="text-foreground font-medium">{cat.name}</code>
<p className="text-sm text-foreground-secondary mt-1">{cat.desc}</p>
</div>
))}
</div>
</section>
{/* Step 3: Publish */}
<section className="mb-16">
<h2 className="text-3xl font-bold mb-6 text-foreground">Step 3: Publish to NPM</h2>
<p className="text-lg text-foreground-secondary mb-6">
Build your package and publish it to NPM. Your tool will be automatically discovered
within 15 minutes.
</p>
<CodeBlock
language="bash"
code={`# Build your package
npm run build
# Publish to NPM (use --access public for scoped packages)
npm publish --access public
# That's it! Your tool will appear on tpmjs.com soon`}
/>
</section>
{/* Quality Score */}
<section className="mb-16">
<h2 className="text-3xl font-bold mb-6 text-foreground">Quality Score</h2>
<p className="text-lg text-foreground-secondary mb-6">
Your tool gets a quality score based on three factors:
</p>
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
<div className="p-6 border border-border rounded-lg bg-surface">
<h3 className="text-xl font-semibold mb-3 text-foreground">Tier</h3>
<ul className="space-y-2 text-foreground-secondary">
<li>Rich: 4x multiplier</li>
<li>Basic: 2x multiplier</li>
<li>Minimal: 1x multiplier</li>
</ul>
</div>
<div className="p-6 border border-border rounded-lg bg-surface">
<h3 className="text-xl font-semibold mb-3 text-foreground">Downloads</h3>
<p className="text-foreground-secondary">
Logarithmic scale based on monthly NPM downloads
</p>
</div>
<div className="p-6 border border-border rounded-lg bg-surface">
<h3 className="text-xl font-semibold mb-3 text-foreground">GitHub Stars</h3>
<p className="text-foreground-secondary">
Logarithmic scale based on repository stars
</p>
</div>
</div>
</section>
{/* Real Example */}
<section className="mb-16">
<h2 className="text-3xl font-bold mb-6 text-foreground">Real Example</h2>
<p className="text-lg text-foreground-secondary mb-6">
Here is a complete example from{' '}
<Link
href="/tool/@tpmjs/createblogpost"
className="text-primary hover:underline font-medium"
>
@tpmjs/createblogpost
</Link>
:
</p>
<CodeBlock
language="json"
code={`{
"name": "@tpmjs/createblogpost",
"version": "0.2.0",
"keywords": ["tpmjs-tool", "blog", "content"],
"tpmjs": {
"category": "text-analysis",
"description": "Creates structured blog posts with frontmatter and SEO metadata",
"example": "const post = await createBlogPost({ title: 'My Post', author: 'John', content: 'Hello' });",
"parameters": [
{
"name": "title",
"type": "string",
"description": "The title of the blog post",
"required": true
},
{
"name": "content",
"type": "string",
"description": "The main content",
"required": true
}
],
"returns": {
"type": "BlogPost",
"description": "Structured blog post with frontmatter"
},
"frameworks": ["vercel-ai", "langchain"],
"tags": ["blog", "content", "markdown"],
"status": "stable"
}
}`}
/>
</section>
{/* Tips */}
<section className="mb-16">
<h2 className="text-3xl font-bold mb-6 text-foreground">Tips for Success</h2>
<div className="space-y-4">
{[
{
icon: '📝',
title: 'Use descriptive names',
desc: 'Make your package name clear and searchable',
},
{
icon: '📊',
title: 'Complete metadata',
desc: 'Rich tier tools get 4x better visibility',
},
{
icon: '📚',
title: 'Good documentation',
desc: 'Link to docs in the links.documentation field',
},
{
icon: '🔄',
title: 'Active maintenance',
desc: 'Regular updates boost download counts',
},
{
icon: '🤖',
title: 'AI-friendly descriptions',
desc: 'Write aiAgent.useCase as guidance for AI agents',
},
].map((tip) => (
<div
key={tip.title}
className="flex gap-4 p-6 border border-border rounded-lg bg-surface"
>
<div className="text-4xl">{tip.icon}</div>
<div>
<h3 className="text-xl font-semibold mb-2 text-foreground">{tip.title}</h3>
<p className="text-foreground-secondary">{tip.desc}</p>
</div>
</div>
))}
</div>
</section>
{/* CTA */}
<section className="text-center py-16 px-6 border border-border rounded-lg bg-surface">
<h2 className="text-3xl font-bold mb-4 text-foreground">Ready to Publish?</h2>
<p className="text-xl text-foreground-secondary mb-8 max-w-2xl mx-auto">
Follow the steps above and your tool will be live on TPMJS within 15 minutes.
</p>
<div className="flex flex-col sm:flex-row gap-4 justify-center">
<Link href="/tool/tool-search">
<Button size="lg" variant="default">
Browse Existing Tools
</Button>
</Link>
<a href="https://github.com/tpmjs/tpmjs" target="_blank" rel="noopener noreferrer">
<Button size="lg" variant="outline">
View on GitHub
</Button>
</a>
</div>
</section>
</Container>
</main>
{/* Footer */}
<footer className="border-t border-border py-8">
<Container size="xl" padding="lg">
<div className="text-center text-foreground-secondary">
<p>
Questions?{' '}
<a
href="https://github.com/tpmjs/tpmjs/issues"
className="text-primary hover:underline"
target="_blank"
rel="noopener noreferrer"
>
File an issue on GitHub
</a>
</p>
</div>
</Container>
</footer>
</div>
);
}