feat: add mobile responsiveness across all pages
- Add hamburger menu icon and MobileMenu slide-out drawer component - Update AppHeader with responsive nav (hidden on mobile, hamburger shown) - Apply responsive styles to all 14 pages: - Responsive headings (text-2xl sm:text-3xl md:text-4xl) - Responsive grid gaps (gap-4 md:gap-6) - Explicit mobile grid columns (grid-cols-1 md:grid-cols-X) - Flex stacking on mobile (flex-col sm:flex-row) - Add mobile nav dropdown to docs page - Update README to correctly frame TPMJS as a discovery registry first, with agent integration as secondary/optional
This commit is contained in:
parent
6cc8c5bdcf
commit
a3cf662b1c
17 changed files with 583 additions and 233 deletions
52
README.md
52
README.md
|
|
@ -2,38 +2,21 @@
|
|||
|
||||
[](https://github.com/tpmjs/tpmjs/actions/workflows/ci.yml)
|
||||
|
||||
**TPMJS is a registry that lets AI agents discover and use npm packages as tools at runtime.**
|
||||
**TPMJS is a registry for discovering AI tools published to npm.**
|
||||
|
||||
Instead of manually importing and configuring tools, agents search by description and load what they need on-demand. Publish your npm package with the `tpmjs-tool` keyword—it appears on [tpmjs.com](https://tpmjs.com) within 15 minutes.
|
||||
Browse, search, and find tools at [tpmjs.com](https://tpmjs.com). Publish your tool by adding the `tpmjs-tool` keyword to your package.json—it appears in the registry within 15 minutes.
|
||||
|
||||
## Why TPMJS?
|
||||
|
||||
- **No config files** - Agents discover tools by describing what they need
|
||||
- **Always up-to-date** - Tools load from npm at runtime, no manual updates
|
||||
- **Works with any agent** - Compatible with Vercel AI SDK, LangChain, OpenAI, Claude, etc.
|
||||
- **Publish once** - Add one keyword to package.json, publish to npm, done
|
||||
- **Discover tools** - Search and browse AI tools by category, quality score, and popularity
|
||||
- **Publish easily** - Add one keyword to package.json, publish to npm, done
|
||||
- **Quality metrics** - Tools are scored based on documentation, downloads, and metadata completeness
|
||||
- **Agent integration** - Optional SDK for agents to search and execute tools at runtime
|
||||
|
||||
## Quick Start
|
||||
|
||||
**For AI agent developers:**
|
||||
```bash
|
||||
npm install @tpmjs/sdk
|
||||
```
|
||||
### Publishing a Tool
|
||||
|
||||
```typescript
|
||||
import { searchRegistry, executeRegistry } from '@tpmjs/sdk';
|
||||
|
||||
// Find tools by description
|
||||
const tools = await searchRegistry({ query: 'parse PDF documents' });
|
||||
|
||||
// Execute a tool
|
||||
const result = await executeRegistry({
|
||||
toolId: 'pdf-parser/extractText',
|
||||
input: { url: 'https://example.com/doc.pdf' }
|
||||
});
|
||||
```
|
||||
|
||||
**For tool publishers:**
|
||||
```bash
|
||||
npx @tpmjs/create-basic-tools
|
||||
```
|
||||
|
|
@ -43,14 +26,31 @@ Or add manually to your package.json:
|
|||
{
|
||||
"keywords": ["tpmjs-tool"],
|
||||
"tpmjs": {
|
||||
"category": "text-analysis",
|
||||
"description": "What your tool does"
|
||||
"category": "text-analysis"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Publish to npm and your tool appears on [tpmjs.com](https://tpmjs.com) within 15 minutes.
|
||||
|
||||
See [HOW_TO_PUBLISH_A_TOOL.md](./HOW_TO_PUBLISH_A_TOOL.md) for the full guide.
|
||||
|
||||
### For AI Agents (Optional)
|
||||
|
||||
Agents can search and execute tools from the registry:
|
||||
|
||||
```bash
|
||||
npm install @tpmjs/registry-search @tpmjs/registry-execute
|
||||
```
|
||||
|
||||
```typescript
|
||||
import { registrySearchTool } from '@tpmjs/registry-search';
|
||||
import { registryExecuteTool } from '@tpmjs/registry-execute';
|
||||
|
||||
// Add to your agent's tools
|
||||
const tools = [registrySearchTool, registryExecuteTool];
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Monorepo Structure
|
||||
|
|
|
|||
|
|
@ -198,7 +198,9 @@ export default function ChangelogPage() {
|
|||
<div className="max-w-4xl mx-auto px-4 py-16">
|
||||
{/* Header */}
|
||||
<div className="text-center mb-16">
|
||||
<h1 className="text-4xl md:text-5xl font-bold text-foreground mb-4">Changelog</h1>
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold text-foreground mb-4">
|
||||
Changelog
|
||||
</h1>
|
||||
<p className="text-lg text-foreground-secondary max-w-2xl mx-auto">
|
||||
Release history for all published TPMJS packages. Track new features, improvements,
|
||||
and fixes across our SDK and tools.
|
||||
|
|
@ -206,7 +208,7 @@ export default function ChangelogPage() {
|
|||
</div>
|
||||
|
||||
{/* Legend */}
|
||||
<div className="flex items-center justify-center gap-6 mb-12 p-4 bg-background-secondary rounded-lg border border-border-secondary">
|
||||
<div className="flex flex-col sm:flex-row items-center justify-center gap-3 sm:gap-6 mb-12 p-4 bg-background-secondary rounded-lg border border-border-secondary">
|
||||
<div className="flex items-center gap-2">
|
||||
<VersionBadge type="major" />
|
||||
<span className="text-sm text-foreground-secondary">Breaking changes</span>
|
||||
|
|
|
|||
|
|
@ -195,6 +195,7 @@ function InfoCard({
|
|||
|
||||
export default function DocsPage(): React.ReactElement {
|
||||
const [activeSection, setActiveSection] = useState('introduction');
|
||||
const [mobileNavOpen, setMobileNavOpen] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
const observer = new IntersectionObserver(
|
||||
|
|
@ -222,6 +223,7 @@ export default function DocsPage(): React.ReactElement {
|
|||
const element = document.getElementById(id);
|
||||
if (element) {
|
||||
element.scrollIntoView({ behavior: 'smooth' });
|
||||
setMobileNavOpen(false);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -229,8 +231,26 @@ export default function DocsPage(): React.ReactElement {
|
|||
<div className="min-h-screen flex flex-col bg-background">
|
||||
<AppHeader />
|
||||
|
||||
<div className="flex-1 flex">
|
||||
{/* Sidebar */}
|
||||
<div className="flex-1 flex flex-col lg:flex-row">
|
||||
{/* Mobile Navigation Toggle */}
|
||||
<div className="lg:hidden sticky top-0 z-30 bg-background border-b border-border px-4 py-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setMobileNavOpen(!mobileNavOpen)}
|
||||
className="flex items-center gap-2 text-sm font-medium text-foreground"
|
||||
>
|
||||
<span className="text-lg">{mobileNavOpen ? '✕' : '☰'}</span>
|
||||
<span>Documentation Menu</span>
|
||||
</button>
|
||||
{/* Mobile Nav Dropdown */}
|
||||
{mobileNavOpen && (
|
||||
<div className="absolute left-0 right-0 top-full bg-background border-b border-border shadow-lg max-h-[70vh] overflow-y-auto px-4 py-4">
|
||||
<SidebarNav activeSection={activeSection} onSectionClick={scrollToSection} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Desktop Sidebar */}
|
||||
<aside className="hidden lg:block w-64 flex-shrink-0 border-r border-border bg-surface/50">
|
||||
<div className="sticky top-0 h-screen overflow-y-auto py-8 px-4">
|
||||
<div className="mb-6">
|
||||
|
|
@ -243,10 +263,12 @@ export default function DocsPage(): React.ReactElement {
|
|||
|
||||
{/* Main Content */}
|
||||
<main className="flex-1 min-w-0">
|
||||
<div className="max-w-4xl mx-auto px-6 py-12">
|
||||
<div className="max-w-4xl mx-auto px-4 sm:px-6 py-8 sm:py-12">
|
||||
{/* Hero */}
|
||||
<div className="mb-12">
|
||||
<h1 className="text-4xl font-bold mb-4 text-foreground">TPMJS Documentation</h1>
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl font-bold mb-4 text-foreground">
|
||||
TPMJS Documentation
|
||||
</h1>
|
||||
<p className="text-xl text-foreground-secondary mb-6">
|
||||
The complete guide to using TPMJS - the registry for AI tools.
|
||||
</p>
|
||||
|
|
@ -280,7 +302,7 @@ export default function DocsPage(): React.ReactElement {
|
|||
AI tools. It enables AI agents to dynamically discover, load, and execute tools from
|
||||
npm packages at runtime.
|
||||
</p>
|
||||
<div className="grid md:grid-cols-3 gap-4 mb-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
|
||||
<InfoCard icon="🔍" title="Discover">
|
||||
Search thousands of AI tools from the npm ecosystem
|
||||
</InfoCard>
|
||||
|
|
@ -808,7 +830,7 @@ while (true) {
|
|||
Publishing a tool to TPMJS is as simple as publishing to npm with standardized
|
||||
metadata.
|
||||
</p>
|
||||
<div className="grid md:grid-cols-4 gap-4 mb-8">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
|
||||
{[
|
||||
{ step: '1', label: 'Add tpmjs-tool keyword' },
|
||||
{ step: '2', label: 'Add tpmjs field' },
|
||||
|
|
@ -1070,7 +1092,7 @@ export TPMJS_EXECUTOR_URL=https://executor.mycompany.com`}
|
|||
<p className="text-foreground-secondary mb-6">
|
||||
TPMJS is designed with security in mind.
|
||||
</p>
|
||||
<div className="grid md:grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<InfoCard icon="🏝️" title="Sandboxed Execution">
|
||||
All tools run in an isolated Deno runtime. They cannot access your local
|
||||
filesystem or environment.
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ export default function FAQPage(): React.ReactElement {
|
|||
<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">
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold mb-4 text-foreground">
|
||||
Frequently Asked Questions
|
||||
</h1>
|
||||
<p className="text-xl text-foreground-secondary max-w-2xl mx-auto">
|
||||
|
|
|
|||
|
|
@ -19,7 +19,9 @@ export default function HowItWorksPage(): React.ReactElement {
|
|||
<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">How TPMJS Works</h1>
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold mb-4 text-foreground">
|
||||
How TPMJS Works
|
||||
</h1>
|
||||
<p className="text-xl text-foreground-secondary max-w-2xl mx-auto">
|
||||
The complete journey from npm package to AI-powered tool execution
|
||||
</p>
|
||||
|
|
@ -27,7 +29,9 @@ export default function HowItWorksPage(): React.ReactElement {
|
|||
|
||||
{/* Overview */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">What is TPMJS?</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
What is TPMJS?
|
||||
</h2>
|
||||
<div className="prose max-w-none text-foreground-secondary text-lg space-y-4">
|
||||
<p>
|
||||
TPMJS (Tool Package Manager for JavaScript) is a{' '}
|
||||
|
|
@ -43,7 +47,7 @@ export default function HowItWorksPage(): React.ReactElement {
|
|||
<span className="text-foreground font-semibold">reusable tool packages</span>{' '}
|
||||
published to npm.
|
||||
</p>
|
||||
<div className="grid md:grid-cols-3 gap-6 mt-8">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-6 mt-8">
|
||||
<div className="p-6 border border-border rounded-lg bg-surface">
|
||||
<div className="text-2xl mb-2">🔍</div>
|
||||
<h3 className="font-semibold mb-2 text-foreground">Automatic Discovery</h3>
|
||||
|
|
@ -71,7 +75,9 @@ export default function HowItWorksPage(): React.ReactElement {
|
|||
|
||||
{/* For Developers */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">For Tool Developers</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
For Tool Developers
|
||||
</h2>
|
||||
<div className="space-y-6">
|
||||
<p className="text-lg text-foreground-secondary">
|
||||
Publishing a tool to TPMJS is as simple as publishing to npm with a standardized
|
||||
|
|
@ -136,7 +142,9 @@ export default function HowItWorksPage(): React.ReactElement {
|
|||
|
||||
{/* For AI Agents */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">For AI Agents</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
For AI Agents
|
||||
</h2>
|
||||
<div className="space-y-6">
|
||||
<p className="text-lg text-foreground-secondary">
|
||||
AI agents can search, discover, and execute tools through the TPMJS API.
|
||||
|
|
@ -192,7 +200,9 @@ const result = await streamText({
|
|||
|
||||
{/* The Magic Behind the Scenes */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">The Magic Behind the Scenes</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
The Magic Behind the Scenes
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
{/* 1. Discovery */}
|
||||
<div>
|
||||
|
|
@ -202,7 +212,7 @@ const result = await streamText({
|
|||
<p className="text-lg text-foreground-secondary mb-4">
|
||||
TPMJS uses three parallel mechanisms to discover tools from npm:
|
||||
</p>
|
||||
<div className="grid md:grid-cols-3 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-6">
|
||||
<div className="p-4 border border-border rounded-lg bg-surface">
|
||||
<h4 className="font-semibold mb-2 text-foreground">Changes Feed</h4>
|
||||
<p className="text-sm text-foreground-secondary">
|
||||
|
|
@ -302,7 +312,7 @@ const result = await streamText({
|
|||
<p className="text-lg text-foreground-secondary mb-4">
|
||||
Every tool is tested to ensure it works correctly:
|
||||
</p>
|
||||
<div className="grid md:grid-cols-2 gap-4">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6">
|
||||
<div className="p-4 border border-border rounded-lg bg-surface">
|
||||
<h4 className="font-semibold mb-2 text-foreground">Import Health</h4>
|
||||
<ul className="text-sm text-foreground-secondary space-y-1">
|
||||
|
|
@ -357,7 +367,9 @@ const result = await streamText({
|
|||
|
||||
{/* Architecture Diagram */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">System Architecture</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
System Architecture
|
||||
</h2>
|
||||
<div className="p-8 border border-border rounded-lg bg-surface">
|
||||
<ArchitectureDiagram />
|
||||
</div>
|
||||
|
|
@ -365,7 +377,9 @@ const result = await streamText({
|
|||
|
||||
{/* Data Flow */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">From Publish to Execution</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
From Publish to Execution
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-start gap-4 p-4 border border-border rounded-lg bg-surface">
|
||||
<span className="flex-shrink-0 flex items-center justify-center w-8 h-8 rounded-full bg-primary/10 text-primary font-bold">
|
||||
|
|
@ -457,7 +471,9 @@ const result = await streamText({
|
|||
<span className="px-3 py-1 text-sm font-semibold bg-primary/10 text-primary rounded-full">
|
||||
🧪 Beta
|
||||
</span>
|
||||
<h2 className="text-3xl font-bold text-foreground">Dynamic Tool Loading</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold text-foreground">
|
||||
Dynamic Tool Loading
|
||||
</h2>
|
||||
</div>
|
||||
|
||||
<div className="space-y-6">
|
||||
|
|
@ -622,7 +638,9 @@ const result = await streamText({
|
|||
|
||||
{/* CTA */}
|
||||
<section className="text-center py-12 border border-border rounded-lg bg-surface">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">Ready to Get Started?</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-8 max-w-2xl mx-auto">
|
||||
Whether you're building AI tools or integrating them into your agent, TPMJS makes
|
||||
it simple.
|
||||
|
|
|
|||
|
|
@ -96,7 +96,7 @@ export default async function HomePage(): Promise<React.ReactElement> {
|
|||
</div>
|
||||
|
||||
{data.featuredTools.length > 0 ? (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6 mb-12">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6 mb-12">
|
||||
{data.featuredTools.map((tool) => (
|
||||
<Link
|
||||
key={tool.id}
|
||||
|
|
@ -178,8 +178,8 @@ export default async function HomePage(): Promise<React.ReactElement> {
|
|||
|
||||
{/* Generator Highlight Box */}
|
||||
<div className="mb-12 p-6 border-2 border-primary/50 rounded-lg bg-primary/5 text-left">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="text-4xl">✨</div>
|
||||
<div className="flex flex-col sm:flex-row items-start gap-4">
|
||||
<div className="text-3xl sm:text-4xl">✨</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-xl font-bold mb-2 text-foreground">
|
||||
Start with Our Package Generator
|
||||
|
|
@ -206,7 +206,7 @@ export default async function HomePage(): Promise<React.ReactElement> {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6 mb-8">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 md: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>
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export default function PlaygroundPage() {
|
|||
<div className="space-y-16">
|
||||
{/* Page Title */}
|
||||
<div className="text-center space-y-4">
|
||||
<h1 className="text-4xl font-bold">Component Playground</h1>
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl font-bold">Component Playground</h1>
|
||||
<p className="text-lg text-foreground-secondary">
|
||||
Explore and test all TPMJS UI components in one place
|
||||
</p>
|
||||
|
|
@ -64,7 +64,9 @@ export default function PlaygroundPage() {
|
|||
|
||||
{/* Buttons Section */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-3xl font-semibold border-b border-border pb-2">Buttons</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-xl sm:text-2xl md:text-3xl font-semibold border-b border-border pb-2">
|
||||
Buttons
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
{/* Button Variants */}
|
||||
<div className="space-y-4">
|
||||
|
|
@ -103,7 +105,9 @@ export default function PlaygroundPage() {
|
|||
|
||||
{/* Badges Section */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-3xl font-semibold border-b border-border pb-2">Badges</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-semibold border-b border-border pb-2">
|
||||
Badges
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
{/* Badge Variants */}
|
||||
<div className="space-y-4">
|
||||
|
|
@ -133,7 +137,9 @@ export default function PlaygroundPage() {
|
|||
|
||||
{/* Icons Section */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-3xl font-semibold border-b border-border pb-2">Icons</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-semibold border-b border-border pb-2">
|
||||
Icons
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
{/* Icon Sizes */}
|
||||
<div className="space-y-4">
|
||||
|
|
@ -157,7 +163,7 @@ export default function PlaygroundPage() {
|
|||
{/* Icon Gallery */}
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-xl font-medium">Available Icons</h3>
|
||||
<div className="grid grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-6">
|
||||
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-8 gap-4 md:gap-6">
|
||||
{(
|
||||
[
|
||||
'check',
|
||||
|
|
@ -185,12 +191,14 @@ export default function PlaygroundPage() {
|
|||
|
||||
{/* Cards Section */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-3xl font-semibold border-b border-border pb-2">Cards</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-semibold border-b border-border pb-2">
|
||||
Cards
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
{/* Card Variants */}
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-xl font-medium">Variants</h3>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-6">
|
||||
<Card variant="default">
|
||||
<CardHeader>
|
||||
<CardTitle>Default Card</CardTitle>
|
||||
|
|
@ -236,7 +244,9 @@ export default function PlaygroundPage() {
|
|||
|
||||
{/* Inputs Section */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-3xl font-semibold border-b border-border pb-2">Inputs</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-semibold border-b border-border pb-2">
|
||||
Inputs
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
{/* Input Sizes */}
|
||||
<div className="space-y-4">
|
||||
|
|
@ -275,7 +285,9 @@ export default function PlaygroundPage() {
|
|||
|
||||
{/* Progress Bars Section */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-3xl font-semibold border-b border-border pb-2">Progress Bars</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-semibold border-b border-border pb-2">
|
||||
Progress Bars
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
{/* Progress Bar Variants */}
|
||||
<div className="space-y-4">
|
||||
|
|
@ -343,7 +355,9 @@ export default function PlaygroundPage() {
|
|||
|
||||
{/* Tabs Section */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-3xl font-semibold border-b border-border pb-2">Tabs</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-semibold border-b border-border pb-2">
|
||||
Tabs
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-xl font-medium">Interactive Tabs</h3>
|
||||
|
|
@ -372,7 +386,9 @@ export default function PlaygroundPage() {
|
|||
|
||||
{/* Code Block Section */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-3xl font-semibold border-b border-border pb-2">Code Block</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-semibold border-b border-border pb-2">
|
||||
Code Block
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-xl font-medium">Example Code</h3>
|
||||
|
|
@ -406,7 +422,9 @@ export default function Example() {
|
|||
|
||||
{/* Containers Section */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-3xl font-semibold border-b border-border pb-2">Containers</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-semibold border-b border-border pb-2">
|
||||
Containers
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-xl font-medium">Container Sizes</h3>
|
||||
|
|
@ -446,7 +464,7 @@ export default function Example() {
|
|||
|
||||
{/* Forms Section */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-3xl font-semibold border-b border-border pb-2">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-semibold border-b border-border pb-2">
|
||||
Form Components
|
||||
</h2>
|
||||
|
||||
|
|
@ -683,7 +701,9 @@ export default function Example() {
|
|||
|
||||
{/* Labels Section */}
|
||||
<section className="space-y-6">
|
||||
<h2 className="text-3xl font-semibold border-b border-border pb-2">Labels</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-semibold border-b border-border pb-2">
|
||||
Labels
|
||||
</h2>
|
||||
<div className="space-y-8">
|
||||
<div className="space-y-4">
|
||||
<h3 className="text-xl font-medium">Form Labels</h3>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,9 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
<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">Privacy Policy</h1>
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold mb-4 text-foreground">
|
||||
Privacy Policy
|
||||
</h1>
|
||||
<p className="text-xl text-foreground-secondary max-w-2xl mx-auto">
|
||||
How we collect, use, and protect your data
|
||||
</p>
|
||||
|
|
@ -34,7 +36,9 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
|
||||
{/* Data We Collect */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">What Data We Collect</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
What Data We Collect
|
||||
</h2>
|
||||
|
||||
<div className="space-y-6">
|
||||
{/* Public NPM Data */}
|
||||
|
|
@ -145,7 +149,9 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
|
||||
{/* What We Don't Collect */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">What We Don't Collect</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
What We Don't Collect
|
||||
</h2>
|
||||
<div className="p-6 border border-success/20 rounded-lg bg-success/5">
|
||||
<ul className="space-y-3 text-foreground-secondary">
|
||||
<li className="flex items-start gap-2">
|
||||
|
|
@ -184,7 +190,9 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
|
||||
{/* How We Use Data */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">How We Use Your Data</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
How We Use Your Data
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
<div className="p-6 border border-border rounded-lg bg-surface">
|
||||
<h3 className="text-xl font-semibold mb-3 text-foreground">
|
||||
|
|
@ -252,7 +260,9 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
|
||||
{/* Third-Party Services */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Third-Party Services</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Third-Party Services
|
||||
</h2>
|
||||
<p className="text-foreground-secondary mb-6">
|
||||
TPMJS relies on the following third-party services to operate:
|
||||
</p>
|
||||
|
|
@ -354,7 +364,9 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
|
||||
{/* Data Retention */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Data Retention</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Data Retention
|
||||
</h2>
|
||||
<div className="space-y-4 text-foreground-secondary">
|
||||
<div className="p-6 border border-border rounded-lg bg-surface">
|
||||
<h3 className="text-lg font-semibold mb-2 text-foreground">NPM Package Metadata</h3>
|
||||
|
|
@ -381,7 +393,7 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
|
||||
{/* Your Rights (GDPR) */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Your Rights (GDPR Compliance)
|
||||
</h2>
|
||||
<p className="text-foreground-secondary mb-6">
|
||||
|
|
@ -441,7 +453,9 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
|
||||
{/* Cookies */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Cookies & Local Storage</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Cookies & Local Storage
|
||||
</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
TPMJS uses minimal cookies and local storage:
|
||||
</p>
|
||||
|
|
@ -474,7 +488,9 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
|
||||
{/* Data Security */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Data Security</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Data Security
|
||||
</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
We take reasonable measures to protect data from unauthorized access:
|
||||
</p>
|
||||
|
|
@ -509,7 +525,9 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
|
||||
{/* Children's Privacy */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Children's Privacy</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Children's Privacy
|
||||
</h2>
|
||||
<p className="text-foreground-secondary">
|
||||
TPMJS does not knowingly collect information from children under 13. The service is
|
||||
intended for developers and AI practitioners. If you believe we have inadvertently
|
||||
|
|
@ -519,7 +537,9 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
|
||||
{/* Changes to Policy */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Changes to This Policy</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Changes to This Policy
|
||||
</h2>
|
||||
<p className="text-foreground-secondary">
|
||||
We may update this Privacy Policy from time to time. Changes will be posted on this
|
||||
page with an updated "Last updated" date. Continued use of TPMJS after
|
||||
|
|
@ -529,7 +549,9 @@ export default function PrivacyPage(): React.ReactElement {
|
|||
|
||||
{/* Contact */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Contact Us</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Contact Us
|
||||
</h2>
|
||||
<p className="text-foreground-secondary mb-4">
|
||||
If you have questions or concerns about this Privacy Policy or how we handle your
|
||||
data, please contact us:
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ export default function PublishPage(): React.ReactElement {
|
|||
<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">
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl lg: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">
|
||||
|
|
@ -29,10 +29,10 @@ export default function PublishPage(): React.ReactElement {
|
|||
|
||||
{/* Generator Callout */}
|
||||
<section className="mb-16 p-8 border-2 border-primary/50 rounded-lg bg-primary/5">
|
||||
<div className="flex items-start gap-6">
|
||||
<div className="text-6xl">🚀</div>
|
||||
<div className="flex flex-col sm:flex-row items-start gap-4 sm:gap-6">
|
||||
<div className="text-4xl sm:text-6xl">🚀</div>
|
||||
<div className="flex-1">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
Use Our Package Generator
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-6">
|
||||
|
|
@ -67,7 +67,9 @@ export default function PublishPage(): React.ReactElement {
|
|||
|
||||
{/* Quick Start */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Manual Setup</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Manual Setup
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-6">
|
||||
Prefer to set up manually? Follow these steps:
|
||||
</p>
|
||||
|
|
@ -97,7 +99,7 @@ export default function PublishPage(): React.ReactElement {
|
|||
|
||||
{/* Step 1: Package.json Setup */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Step 1: Add Required Keyword
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-6">
|
||||
|
|
@ -118,7 +120,9 @@ export default function PublishPage(): React.ReactElement {
|
|||
|
||||
{/* Step 2: Metadata */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Step 2: Add TPMJS Metadata</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Step 2: Add TPMJS Metadata
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-6">
|
||||
Add a <code className="text-foreground bg-surface px-2 py-1 rounded">tpmjs</code>{' '}
|
||||
field to your package.json. TPMJS automatically extracts parameter schemas from your
|
||||
|
|
@ -228,8 +232,10 @@ export default function PublishPage(): React.ReactElement {
|
|||
|
||||
{/* 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">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Available Categories
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6">
|
||||
{[
|
||||
{ name: 'text-analysis', desc: 'NLP, sentiment, summarization' },
|
||||
{ name: 'code-generation', desc: 'Code generation and transformation' },
|
||||
|
|
@ -250,7 +256,9 @@ export default function PublishPage(): React.ReactElement {
|
|||
|
||||
{/* Step 3: Publish */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Step 3: Publish to NPM</h2>
|
||||
<h2 className="text-xl sm:text-2xl md: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.
|
||||
|
|
@ -269,11 +277,13 @@ npm publish --access public
|
|||
|
||||
{/* Quality Score */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Quality Score</h2>
|
||||
<h2 className="text-xl sm:text-2xl md: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="grid grid-cols-1 md:grid-cols-3 gap-4 md: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">
|
||||
|
|
@ -299,7 +309,9 @@ npm publish --access public
|
|||
|
||||
{/* Real Example */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Real Example</h2>
|
||||
<h2 className="text-xl sm:text-2xl md: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
|
||||
|
|
@ -336,7 +348,9 @@ npm publish --access public
|
|||
|
||||
{/* Tips */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Tips for Success</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Tips for Success
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
{[
|
||||
{
|
||||
|
|
@ -381,7 +395,9 @@ npm publish --access public
|
|||
|
||||
{/* 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>
|
||||
<h2 className="text-xl sm:text-2xl md: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>
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export default function SDKPage(): React.ReactElement {
|
|||
New
|
||||
</span>
|
||||
</div>
|
||||
<h1 className="text-4xl md:text-5xl font-bold mb-4 text-foreground">
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold mb-4 text-foreground">
|
||||
Give Your Agent Access to Every Tool
|
||||
</h1>
|
||||
<p className="text-xl text-foreground-secondary max-w-3xl mx-auto mb-8">
|
||||
|
|
@ -72,7 +72,9 @@ export default function SDKPage(): React.ReactElement {
|
|||
|
||||
{/* Quick Start */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Quick Start</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Quick Start
|
||||
</h2>
|
||||
<div className="space-y-6">
|
||||
{/* Install */}
|
||||
<div className="p-6 border border-border rounded-lg bg-surface">
|
||||
|
|
@ -168,14 +170,18 @@ Use registrySearch to find tools, then registryExecute to run them.\`,
|
|||
|
||||
{/* How It Works */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">How It Works</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
How It Works
|
||||
</h2>
|
||||
<SDKFlowDiagram />
|
||||
</section>
|
||||
|
||||
{/* registrySearchTool */}
|
||||
<section className="mb-16">
|
||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mb-6">
|
||||
<h2 className="text-3xl font-bold text-foreground">registrySearchTool</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold text-foreground">
|
||||
registrySearchTool
|
||||
</h2>
|
||||
<div className="flex items-center gap-3">
|
||||
<a
|
||||
href="https://www.npmjs.com/package/@tpmjs/registry-search"
|
||||
|
|
@ -301,7 +307,9 @@ Use registrySearch to find tools, then registryExecute to run them.\`,
|
|||
{/* registryExecuteTool */}
|
||||
<section className="mb-16">
|
||||
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4 mb-6">
|
||||
<h2 className="text-3xl font-bold text-foreground">registryExecuteTool</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold text-foreground">
|
||||
registryExecuteTool
|
||||
</h2>
|
||||
<div className="flex items-center gap-3">
|
||||
<a
|
||||
href="https://www.npmjs.com/package/@tpmjs/registry-execute"
|
||||
|
|
@ -410,7 +418,9 @@ const result = await registryExecuteTool.execute({
|
|||
|
||||
{/* Environment Variables */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Environment Variables</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Environment Variables
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-6">
|
||||
Both packages support self-hosted registries via environment variables. This is useful
|
||||
for enterprise deployments or running your own tool registry.
|
||||
|
|
@ -455,7 +465,9 @@ export TPMJS_EXECUTOR_URL=https://executor.mycompany.com`}
|
|||
|
||||
{/* Passing API Keys */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Passing API Keys</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Passing API Keys
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-6">
|
||||
Many tools require API keys (e.g., Firecrawl, Exa). The recommended approach is to
|
||||
wrap <code className="text-primary">registryExecuteTool</code> with your
|
||||
|
|
@ -534,8 +546,10 @@ Use registrySearch to find tools, then registryExecute to run them.\`,
|
|||
|
||||
{/* Security */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Security</h2>
|
||||
<div className="grid md:grid-cols-2 gap-6">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Security
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4 md:gap-6">
|
||||
<div className="p-6 border border-border rounded-lg bg-surface">
|
||||
<div className="text-2xl mb-2">🏝️</div>
|
||||
<h3 className="font-semibold mb-2 text-foreground">Sandboxed Execution</h3>
|
||||
|
|
@ -573,7 +587,9 @@ Use registrySearch to find tools, then registryExecute to run them.\`,
|
|||
|
||||
{/* Vision & Future */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">The Vision</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
The Vision
|
||||
</h2>
|
||||
<div className="prose max-w-none text-foreground-secondary text-lg space-y-4 mb-8">
|
||||
<p>
|
||||
We're building the{' '}
|
||||
|
|
@ -677,7 +693,9 @@ const tools = await tpmjs.loadCollection('my-company/internal-tools');`}
|
|||
|
||||
{/* CTA */}
|
||||
<section className="text-center py-12 border border-border rounded-lg bg-surface">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">Ready to Get Started?</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
Ready to Get Started?
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-8 max-w-2xl mx-auto">
|
||||
Give your AI agent access to thousands of tools in minutes.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export default function SpecPage(): React.ReactElement {
|
|||
<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">
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold mb-4 text-foreground">
|
||||
TPMJS Specification
|
||||
</h1>
|
||||
<p className="text-xl text-foreground-secondary max-w-2xl mx-auto">
|
||||
|
|
@ -32,7 +32,9 @@ export default function SpecPage(): React.ReactElement {
|
|||
|
||||
{/* What is TPMJS */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">What is TPMJS?</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
What is TPMJS?
|
||||
</h2>
|
||||
<div className="prose prose-invert max-w-none">
|
||||
<p className="text-lg text-foreground-secondary mb-4">
|
||||
TPMJS (Tool Package Manager for JavaScript) is an open standard and registry for AI
|
||||
|
|
@ -62,8 +64,10 @@ export default function SpecPage(): React.ReactElement {
|
|||
|
||||
{/* How it Works */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">How it Works</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
How it Works
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<div className="text-3xl mb-2">📦</div>
|
||||
|
|
@ -110,7 +114,9 @@ export default function SpecPage(): React.ReactElement {
|
|||
|
||||
{/* The Specification */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">The Specification</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
The Specification
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-8">
|
||||
The TPMJS specification defines a{' '}
|
||||
<code className="text-foreground bg-surface px-2 py-1 rounded">tpmjs</code> field in
|
||||
|
|
@ -173,7 +179,7 @@ export default function SpecPage(): React.ReactElement {
|
|||
<p className="text-sm text-foreground-secondary mb-3">
|
||||
Tool category for organization. Must be one of the following:
|
||||
</p>
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 gap-2">
|
||||
<div className="grid grid-cols-2 sm:grid-cols-3 gap-2">
|
||||
{TPMJS_CATEGORIES.map((cat) => (
|
||||
<Badge key={cat} variant="secondary" size="sm">
|
||||
{cat}
|
||||
|
|
@ -398,7 +404,9 @@ export default function SpecPage(): React.ReactElement {
|
|||
|
||||
{/* Schema Extraction */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Schema Extraction</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Schema Extraction
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-6">
|
||||
When TPMJS syncs your package, it automatically extracts your tool's inputSchema
|
||||
by loading and inspecting your tool in a sandboxed environment.
|
||||
|
|
@ -459,7 +467,9 @@ export default function SpecPage(): React.ReactElement {
|
|||
|
||||
{/* Field Reference Table */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Field Reference</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Field Reference
|
||||
</h2>
|
||||
<Card>
|
||||
<CardContent className="pt-6">
|
||||
<div className="overflow-x-auto">
|
||||
|
|
@ -561,7 +571,9 @@ export default function SpecPage(): React.ReactElement {
|
|||
|
||||
{/* Quality Score */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Quality Score</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Quality Score
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-6">
|
||||
Tools are ranked by quality score, calculated from three factors:
|
||||
</p>
|
||||
|
|
@ -631,11 +643,13 @@ export default function SpecPage(): React.ReactElement {
|
|||
|
||||
{/* Discovery & Sync */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Discovery & Sync</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Discovery & Sync
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-6">
|
||||
TPMJS automatically discovers and updates tools using three strategies:
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 md:gap-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Changes Feed</CardTitle>
|
||||
|
|
@ -684,7 +698,9 @@ export default function SpecPage(): React.ReactElement {
|
|||
|
||||
{/* Validation */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Validation</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Validation
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-6">
|
||||
The TPMJS specification is validated using Zod schemas. The validation logic is
|
||||
available in the{' '}
|
||||
|
|
@ -723,11 +739,13 @@ export default function SpecPage(): React.ReactElement {
|
|||
|
||||
{/* Publishing Your Tool */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Publishing Your Tool</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Publishing Your Tool
|
||||
</h2>
|
||||
<p className="text-lg text-foreground-secondary mb-6">
|
||||
Publishing a tool to TPMJS is simple:
|
||||
</p>
|
||||
<div className="grid grid-cols-1 md:grid-cols-4 gap-4 mb-8">
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 mb-8">
|
||||
<Card>
|
||||
<CardContent className="pt-6 text-center">
|
||||
<div className="text-3xl mb-2">1️⃣</div>
|
||||
|
|
@ -771,8 +789,10 @@ export default function SpecPage(): React.ReactElement {
|
|||
|
||||
{/* Support & Resources */}
|
||||
<section className="mb-16">
|
||||
<h2 className="text-3xl font-bold mb-6 text-foreground">Support & Resources</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-6 text-foreground">
|
||||
Support & Resources
|
||||
</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4 md:gap-6">
|
||||
<Card>
|
||||
<CardHeader>
|
||||
<CardTitle>Documentation</CardTitle>
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ export default function TermsPage(): React.ReactElement {
|
|||
<Container size="lg" padding="lg">
|
||||
{/* Header */}
|
||||
<div className="mb-12">
|
||||
<h1 className="text-4xl md:text-5xl font-bold mb-4 text-foreground">
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl lg:text-5xl font-bold mb-4 text-foreground">
|
||||
Terms of Service
|
||||
</h1>
|
||||
<p className="text-lg text-foreground-secondary">Last updated: December 2024</p>
|
||||
|
|
@ -26,7 +26,9 @@ export default function TermsPage(): React.ReactElement {
|
|||
<div className="prose prose-invert max-w-none">
|
||||
{/* 1. Introduction */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">1. Introduction</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
1. Introduction
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p>
|
||||
Welcome to TPMJS (Tool Package Manager for JavaScript). By accessing or using
|
||||
|
|
@ -44,10 +46,12 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 2. Service Description */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">2. Service Description</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
2. Service Description
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p>TPMJS provides the following services:</p>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<ul className="list-disc pl-4 sm:pl-6 space-y-2">
|
||||
<li>
|
||||
Automatic discovery and indexing of npm packages with the{' '}
|
||||
<code className="text-foreground bg-surface px-2 py-1 rounded">tpmjs-tool</code>{' '}
|
||||
|
|
@ -69,7 +73,7 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 3. User Responsibilities */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
3. User Responsibilities When Publishing Tools
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
|
|
@ -77,7 +81,7 @@ export default function TermsPage(): React.ReactElement {
|
|||
If you publish a tool package to npm with the intention of it being indexed by
|
||||
TPMJS, you agree to:
|
||||
</p>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<ul className="list-disc pl-4 sm:pl-6 space-y-2">
|
||||
<li>
|
||||
Provide accurate and complete metadata in the{' '}
|
||||
<code className="text-foreground bg-surface px-2 py-1 rounded">tpmjs</code>{' '}
|
||||
|
|
@ -111,7 +115,7 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 4. No Warranties on Third-Party Tools */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
4. No Warranties on Third-Party Tools
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
|
|
@ -126,7 +130,7 @@ export default function TermsPage(): React.ReactElement {
|
|||
of any kind.
|
||||
</p>
|
||||
<p>We make no representations or warranties regarding:</p>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<ul className="list-disc pl-4 sm:pl-6 space-y-2">
|
||||
<li>The functionality, quality, or reliability of third-party tools</li>
|
||||
<li>The accuracy or completeness of tool descriptions and metadata</li>
|
||||
<li>The security or safety of executing third-party tools</li>
|
||||
|
|
@ -149,7 +153,7 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 5. Limitation of Liability */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
5. Limitation of Liability
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
|
|
@ -159,7 +163,7 @@ export default function TermsPage(): React.ReactElement {
|
|||
THROUGH THE SERVICE.
|
||||
</p>
|
||||
<p>This includes, but is not limited to:</p>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<ul className="list-disc pl-4 sm:pl-6 space-y-2">
|
||||
<li>Direct, indirect, incidental, special, consequential, or punitive damages</li>
|
||||
<li>Loss of profits, revenue, data, or business opportunities</li>
|
||||
<li>
|
||||
|
|
@ -186,10 +190,12 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 6. Acceptable Use Policy */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">6. Acceptable Use Policy</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
6. Acceptable Use Policy
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p>You agree not to use the Service to:</p>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<ul className="list-disc pl-4 sm:pl-6 space-y-2">
|
||||
<li>Violate any applicable laws, regulations, or third-party rights</li>
|
||||
<li>Distribute malware, viruses, or other harmful code</li>
|
||||
<li>
|
||||
|
|
@ -221,7 +227,9 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 7. Intellectual Property */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">7. Intellectual Property</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
7. Intellectual Property
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p>
|
||||
The TPMJS Service, including its design, code, and documentation, is protected by
|
||||
|
|
@ -233,7 +241,7 @@ export default function TermsPage(): React.ReactElement {
|
|||
<code className="text-foreground bg-surface px-2 py-1 rounded">tpmjs-tool</code>{' '}
|
||||
keyword, you grant TPMJS a non-exclusive, worldwide, royalty-free license to:
|
||||
</p>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<ul className="list-disc pl-4 sm:pl-6 space-y-2">
|
||||
<li>Index and display your tool's metadata on tpmjs.com</li>
|
||||
<li>
|
||||
Execute your tool in our sandbox environment for testing and demonstration
|
||||
|
|
@ -249,12 +257,14 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 8. Privacy and Data */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">8. Privacy and Data</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
8. Privacy and Data
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p>
|
||||
TPMJS collects and processes data necessary to operate the Service, including:
|
||||
</p>
|
||||
<ul className="list-disc pl-6 space-y-2">
|
||||
<ul className="list-disc pl-4 sm:pl-6 space-y-2">
|
||||
<li>Package metadata from npm (names, versions, descriptions, etc.)</li>
|
||||
<li>Download statistics and quality metrics from public npm registries</li>
|
||||
<li>Tool execution results and health check data</li>
|
||||
|
|
@ -270,7 +280,7 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 9. Modifications to the Service */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
9. Modifications to the Service
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
|
|
@ -289,7 +299,9 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 10. Termination */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">10. Termination</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
10. Termination
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p>
|
||||
TPMJS reserves the right to terminate or suspend your access to the Service at any
|
||||
|
|
@ -308,7 +320,9 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 11. Governing Law */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">11. Governing Law</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
11. Governing Law
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p>
|
||||
These Terms shall be governed by and construed in accordance with the laws of the
|
||||
|
|
@ -324,7 +338,9 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 12. Disclaimer */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">12. Disclaimer</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
12. Disclaimer
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p className="font-semibold text-foreground">
|
||||
THE SERVICE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT
|
||||
|
|
@ -342,7 +358,9 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 13. Open Source */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">13. Open Source</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
13. Open Source
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p>
|
||||
TPMJS is open source and available on{' '}
|
||||
|
|
@ -365,7 +383,9 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 14. Contact */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">14. Contact</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
14. Contact
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p>
|
||||
If you have any questions about these Terms or the Service, please contact us at:
|
||||
|
|
@ -383,7 +403,9 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 15. Severability */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">15. Severability</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
15. Severability
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p>
|
||||
If any provision of these Terms is found to be invalid or unenforceable, the
|
||||
|
|
@ -396,7 +418,9 @@ export default function TermsPage(): React.ReactElement {
|
|||
|
||||
{/* 16. Entire Agreement */}
|
||||
<section className="mb-12">
|
||||
<h2 className="text-3xl font-bold mb-4 text-foreground">16. Entire Agreement</h2>
|
||||
<h2 className="text-xl sm:text-2xl md:text-3xl font-bold mb-4 text-foreground">
|
||||
16. Entire Agreement
|
||||
</h2>
|
||||
<div className="space-y-4 text-lg text-foreground-secondary">
|
||||
<p>
|
||||
These Terms constitute the entire agreement between you and TPMJS regarding your
|
||||
|
|
|
|||
|
|
@ -272,9 +272,11 @@ export default function ToolDetailPage({
|
|||
|
||||
{/* Title section */}
|
||||
<div className="mb-8">
|
||||
<div className="flex items-start justify-between mb-4">
|
||||
<div className="flex flex-col sm:flex-row sm:items-start sm:justify-between gap-4 mb-4">
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold text-foreground mb-2">{tool.name}</h1>
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl font-bold text-foreground mb-2">
|
||||
{tool.name}
|
||||
</h1>
|
||||
<p className="text-sm text-foreground-tertiary font-mono mb-2">
|
||||
{pkg.npmPackageName}
|
||||
</p>
|
||||
|
|
@ -374,9 +376,9 @@ export default function ToolDetailPage({
|
|||
)}
|
||||
|
||||
{/* Main grid */}
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-6">
|
||||
<div className="grid grid-cols-1 lg:grid-cols-3 gap-4 md:gap-6">
|
||||
{/* Left column - Main content */}
|
||||
<div className="lg:col-span-2 space-y-6">
|
||||
<div className="lg:col-span-2 space-y-4 md:space-y-6">
|
||||
{/* Interactive Playground */}
|
||||
{/* biome-ignore lint/suspicious/noExplicitAny: Prisma Tool type compatibility with component props */}
|
||||
<ToolPlayground tool={tool as any} />
|
||||
|
|
@ -598,7 +600,7 @@ console.log(result.text);`}
|
|||
</div>
|
||||
|
||||
{/* Right column - Sidebar */}
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-4 md:space-y-6">
|
||||
{/* Stats */}
|
||||
<Card>
|
||||
<CardHeader>
|
||||
|
|
|
|||
|
|
@ -136,7 +136,9 @@ export default function ToolSearchPage(): React.ReactElement {
|
|||
<Container size="xl" padding="md" className="py-8">
|
||||
{/* Page header */}
|
||||
<div className="space-y-4 mb-8">
|
||||
<h1 className="text-4xl font-bold text-foreground">Tool Registry</h1>
|
||||
<h1 className="text-2xl sm:text-3xl md:text-4xl font-bold text-foreground">
|
||||
Tool Registry
|
||||
</h1>
|
||||
<p className="text-lg text-foreground-secondary">
|
||||
Search npm packages indexed as AI agent tools. Filter by category, health status, or
|
||||
keyword.
|
||||
|
|
@ -153,14 +155,17 @@ export default function ToolSearchPage(): React.ReactElement {
|
|||
/>
|
||||
|
||||
{/* Filter row */}
|
||||
<div className="flex flex-wrap gap-4">
|
||||
<div className="flex flex-col sm:flex-row flex-wrap gap-3 sm:gap-4">
|
||||
{/* Category filter */}
|
||||
<div className="flex items-center gap-2 min-w-[200px]">
|
||||
<span className="text-sm font-medium text-foreground-secondary">Category:</span>
|
||||
<div className="flex items-center gap-2 w-full sm:w-auto">
|
||||
<span className="text-sm font-medium text-foreground-secondary whitespace-nowrap">
|
||||
Category:
|
||||
</span>
|
||||
<Select
|
||||
value={categoryFilter}
|
||||
onChange={(e) => setCategoryFilter(e.target.value)}
|
||||
size="sm"
|
||||
className="flex-1 sm:flex-none sm:min-w-[150px]"
|
||||
options={[
|
||||
{ value: 'all', label: 'All Categories' },
|
||||
...availableCategories.map((cat) => ({
|
||||
|
|
@ -172,12 +177,15 @@ export default function ToolSearchPage(): React.ReactElement {
|
|||
</div>
|
||||
|
||||
{/* Health filter */}
|
||||
<div className="flex items-center gap-2 min-w-[200px]">
|
||||
<span className="text-sm font-medium text-foreground-secondary">Health:</span>
|
||||
<div className="flex items-center gap-2 w-full sm:w-auto">
|
||||
<span className="text-sm font-medium text-foreground-secondary whitespace-nowrap">
|
||||
Health:
|
||||
</span>
|
||||
<Select
|
||||
value={healthFilter}
|
||||
onChange={(e) => setHealthFilter(e.target.value)}
|
||||
size="sm"
|
||||
className="flex-1 sm:flex-none sm:min-w-[130px]"
|
||||
options={[
|
||||
{ value: 'all', label: 'All Tools' },
|
||||
{ value: 'healthy', label: 'Healthy Only' },
|
||||
|
|
@ -187,12 +195,15 @@ export default function ToolSearchPage(): React.ReactElement {
|
|||
</div>
|
||||
|
||||
{/* Sort dropdown */}
|
||||
<div className="flex items-center gap-2 min-w-[200px]">
|
||||
<span className="text-sm font-medium text-foreground-secondary">Sort:</span>
|
||||
<div className="flex items-center gap-2 w-full sm:w-auto">
|
||||
<span className="text-sm font-medium text-foreground-secondary whitespace-nowrap">
|
||||
Sort:
|
||||
</span>
|
||||
<Select
|
||||
value={sortBy}
|
||||
onChange={(e) => setSortBy(e.target.value as SortOption)}
|
||||
size="sm"
|
||||
className="flex-1 sm:flex-none sm:min-w-[150px]"
|
||||
options={[
|
||||
{ value: 'downloads', label: 'Most Downloaded' },
|
||||
{ value: 'recent', label: 'Recent' },
|
||||
|
|
@ -231,7 +242,7 @@ export default function ToolSearchPage(): React.ReactElement {
|
|||
|
||||
{/* Tool grid */}
|
||||
{!loading && !error && tools.length > 0 && (
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 md:gap-6">
|
||||
{tools.map((tool) => {
|
||||
const isBroken = tool.importHealth === 'BROKEN' || tool.executionHealth === 'BROKEN';
|
||||
const qualityPercent = Math.round(Number.parseFloat(tool.qualityScore) * 100);
|
||||
|
|
|
|||
|
|
@ -4,88 +4,111 @@ import { Button } from '@tpmjs/ui/Button/Button';
|
|||
import { Header } from '@tpmjs/ui/Header/Header';
|
||||
import { Icon } from '@tpmjs/ui/Icon/Icon';
|
||||
import Link from 'next/link';
|
||||
import { useState } from 'react';
|
||||
import { MobileMenu } from './MobileMenu';
|
||||
|
||||
/**
|
||||
* Shared application header used across all pages
|
||||
*/
|
||||
export function AppHeader(): React.ReactElement {
|
||||
const [mobileMenuOpen, setMobileMenuOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<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="/docs">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
Docs
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/how-it-works">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
How It Works
|
||||
</Button>
|
||||
</Link>
|
||||
<a href="https://playground.tpmjs.com" target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
Playground
|
||||
</Button>
|
||||
</a>
|
||||
<Link href="/spec">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
Spec
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/sdk">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
SDK
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/faq">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
FAQ
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/changelog">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
Changelog
|
||||
</Button>
|
||||
</Link>
|
||||
<a
|
||||
href="https://discord.gg/KuJRBCn89c"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-foreground hover:text-foreground transition-colors"
|
||||
<>
|
||||
<Header
|
||||
title={
|
||||
<Link
|
||||
href="/"
|
||||
className="text-foreground hover:text-foreground text-xl md:text-2xl font-bold uppercase tracking-tight"
|
||||
>
|
||||
<Icon icon="discord" size="md" />
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/tpmjs/tpmjs"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
<Icon icon="github" size="md" />
|
||||
</a>
|
||||
<Link href="/publish">
|
||||
<Button variant="default" size="sm">
|
||||
Publish Tool
|
||||
</Button>
|
||||
TPMJS
|
||||
</Link>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
}
|
||||
size="md"
|
||||
sticky={true}
|
||||
actions={
|
||||
<>
|
||||
{/* Desktop Navigation - hidden on mobile */}
|
||||
<div className="hidden md: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="/docs">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
Docs
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/how-it-works">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
How It Works
|
||||
</Button>
|
||||
</Link>
|
||||
<a href="https://playground.tpmjs.com" target="_blank" rel="noopener noreferrer">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
Playground
|
||||
</Button>
|
||||
</a>
|
||||
<Link href="/spec">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
Spec
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/sdk">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
SDK
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/faq">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
FAQ
|
||||
</Button>
|
||||
</Link>
|
||||
<Link href="/changelog">
|
||||
<Button variant="ghost" size="sm" className="text-foreground hover:text-foreground">
|
||||
Changelog
|
||||
</Button>
|
||||
</Link>
|
||||
<a
|
||||
href="https://discord.gg/KuJRBCn89c"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
<Icon icon="discord" size="md" />
|
||||
</a>
|
||||
<a
|
||||
href="https://github.com/tpmjs/tpmjs"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-foreground hover:text-foreground transition-colors"
|
||||
>
|
||||
<Icon icon="github" size="md" />
|
||||
</a>
|
||||
<Link href="/publish">
|
||||
<Button variant="default" size="sm">
|
||||
Publish Tool
|
||||
</Button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{/* Mobile Hamburger Button - shown on mobile only */}
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="flex md:hidden text-foreground"
|
||||
onClick={() => setMobileMenuOpen(true)}
|
||||
aria-label="Open menu"
|
||||
>
|
||||
<Icon icon="menu" size="md" />
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
|
||||
{/* Mobile Menu Drawer */}
|
||||
<MobileMenu isOpen={mobileMenuOpen} onClose={() => setMobileMenuOpen(false)} />
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
148
apps/web/src/components/MobileMenu.tsx
Normal file
148
apps/web/src/components/MobileMenu.tsx
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
'use client';
|
||||
|
||||
import { Button } from '@tpmjs/ui/Button/Button';
|
||||
import { Icon } from '@tpmjs/ui/Icon/Icon';
|
||||
import Link from 'next/link';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
interface MobileMenuProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
const navLinks = [
|
||||
{ href: '/tool/tool-search', label: 'Tools' },
|
||||
{ href: '/docs', label: 'Docs' },
|
||||
{ href: '/how-it-works', label: 'How It Works' },
|
||||
{ href: 'https://playground.tpmjs.com', label: 'Playground', external: true },
|
||||
{ href: '/spec', label: 'Spec' },
|
||||
{ href: '/sdk', label: 'SDK' },
|
||||
{ href: '/faq', label: 'FAQ' },
|
||||
{ href: '/changelog', label: 'Changelog' },
|
||||
];
|
||||
|
||||
const socialLinks = [
|
||||
{ href: 'https://discord.gg/KuJRBCn89c', icon: 'discord' as const, label: 'Discord' },
|
||||
{ href: 'https://github.com/tpmjs/tpmjs', icon: 'github' as const, label: 'GitHub' },
|
||||
];
|
||||
|
||||
export function MobileMenu({ isOpen, onClose }: MobileMenuProps): React.ReactElement | null {
|
||||
// Lock body scroll when menu is open
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
document.body.style.overflow = 'hidden';
|
||||
} else {
|
||||
document.body.style.overflow = '';
|
||||
}
|
||||
return () => {
|
||||
document.body.style.overflow = '';
|
||||
};
|
||||
}, [isOpen]);
|
||||
|
||||
// Close on escape key
|
||||
useEffect(() => {
|
||||
const handleEscape = (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
onClose();
|
||||
}
|
||||
};
|
||||
if (isOpen) {
|
||||
document.addEventListener('keydown', handleEscape);
|
||||
}
|
||||
return () => {
|
||||
document.removeEventListener('keydown', handleEscape);
|
||||
};
|
||||
}, [isOpen, onClose]);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Backdrop */}
|
||||
<div
|
||||
className={`fixed inset-0 z-40 bg-black/50 transition-opacity duration-300 ${
|
||||
isOpen ? 'opacity-100' : 'opacity-0 pointer-events-none'
|
||||
}`}
|
||||
onClick={onClose}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
|
||||
{/* Slide-out drawer */}
|
||||
<div
|
||||
className={`fixed top-0 right-0 z-50 h-full w-72 bg-background border-l border-border shadow-xl transform transition-transform duration-300 ease-out ${
|
||||
isOpen ? 'translate-x-0' : 'translate-x-full'
|
||||
}`}
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label="Mobile navigation menu"
|
||||
>
|
||||
{/* Header with close button */}
|
||||
<div className="flex items-center justify-between p-4 border-b border-border">
|
||||
<span className="font-bold text-lg text-foreground">Menu</span>
|
||||
<Button variant="ghost" size="sm" onClick={onClose} aria-label="Close menu">
|
||||
<Icon icon="x" size="md" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Navigation links */}
|
||||
<nav className="p-4">
|
||||
<ul className="space-y-1">
|
||||
{navLinks.map((link) => (
|
||||
<li key={link.href}>
|
||||
{link.external ? (
|
||||
<a
|
||||
href={link.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-2 px-3 py-3 text-foreground hover:bg-surface rounded-md transition-colors"
|
||||
onClick={onClose}
|
||||
>
|
||||
{link.label}
|
||||
<Icon icon="externalLink" size="sm" className="text-foreground-tertiary" />
|
||||
</a>
|
||||
) : (
|
||||
<Link
|
||||
href={link.href}
|
||||
className="block px-3 py-3 text-foreground hover:bg-surface rounded-md transition-colors"
|
||||
onClick={onClose}
|
||||
>
|
||||
{link.label}
|
||||
</Link>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
{/* Divider */}
|
||||
<div className="my-4 border-t border-border" />
|
||||
|
||||
{/* Social links */}
|
||||
<ul className="space-y-1">
|
||||
{socialLinks.map((link) => (
|
||||
<li key={link.href}>
|
||||
<a
|
||||
href={link.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center gap-3 px-3 py-3 text-foreground hover:bg-surface rounded-md transition-colors"
|
||||
onClick={onClose}
|
||||
>
|
||||
<Icon icon={link.icon} size="md" />
|
||||
{link.label}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
|
||||
{/* Divider */}
|
||||
<div className="my-4 border-t border-border" />
|
||||
|
||||
{/* Publish button */}
|
||||
<Link href="/publish" onClick={onClose}>
|
||||
<Button variant="default" size="lg" className="w-full">
|
||||
Publish Tool
|
||||
</Button>
|
||||
</Link>
|
||||
</nav>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
@ -40,6 +40,10 @@ export const icons = {
|
|||
viewBox: '0 0 24 24',
|
||||
path: 'M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028 14.09 14.09 0 0 0 1.226-1.994.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z',
|
||||
},
|
||||
menu: {
|
||||
viewBox: '0 0 24 24',
|
||||
path: 'M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z',
|
||||
},
|
||||
} as const;
|
||||
|
||||
export type IconName = keyof typeof icons;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue