fix: mobile UI bugs and documentation improvements
- docs: add clarifying comment for AI SDK provider imports on /docs and /sdk pages - fix: remove duplicate footer on /docs page (was rendered in both page and root layout) - fix: prevent "Official" badge from overflowing on mobile tool cards (/home) - fix: center Specification/Full Example toggle buttons on mobile (/spec) - fix: ecosystem diagram layout on mobile - increase height and reposition legend (/integrations)
This commit is contained in:
parent
114798ce9e
commit
b8b4e44b50
5 changed files with 66 additions and 37 deletions
|
|
@ -6,7 +6,6 @@ import { Button } from '@tpmjs/ui/Button/Button';
|
|||
import { CodeBlock } from '@tpmjs/ui/CodeBlock/CodeBlock';
|
||||
import Link from 'next/link';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { AppFooter } from '~/components/AppFooter';
|
||||
import { AppHeader } from '~/components/AppHeader';
|
||||
|
||||
const NAV_SECTIONS = [
|
||||
|
|
@ -351,6 +350,7 @@ export default function DocsPage(): React.ReactElement {
|
|||
<CodeBlock
|
||||
language="typescript"
|
||||
code={`import { streamText } from 'ai';
|
||||
// Import AI SDK provider for your selected model (OpenAI, Anthropic, Google, etc.)
|
||||
import { anthropic } from '@ai-sdk/anthropic';
|
||||
import { registrySearchTool } from '@tpmjs/registry-search';
|
||||
import { registryExecuteTool } from '@tpmjs/registry-execute';
|
||||
|
|
@ -591,6 +591,8 @@ export const registryExecute = tool({
|
|||
<CodeBlock
|
||||
language="typescript"
|
||||
code={`import { streamText } from 'ai';
|
||||
// Import AI SDK provider for your selected model (OpenAI, Anthropic, Google, etc.)
|
||||
import { anthropic } from '@ai-sdk/anthropic';
|
||||
import { registrySearchTool } from '@tpmjs/registry-search';
|
||||
import { registryExecute } from './tools'; // Your wrapped version
|
||||
|
||||
|
|
@ -1443,7 +1445,6 @@ export TPMJS_EXECUTOR_URL=https://executor.mycompany.com`}
|
|||
</div>
|
||||
</main>
|
||||
</div>
|
||||
<AppFooter />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -104,15 +104,15 @@ export default async function HomePage(): Promise<React.ReactElement> {
|
|||
className="group"
|
||||
>
|
||||
<div className="p-6 border border-border rounded-lg bg-surface hover:border-foreground transition-colors h-full flex flex-col">
|
||||
<div className="flex items-start justify-between mb-3">
|
||||
<h3 className="text-lg font-semibold text-foreground group-hover:text-brutalist-accent transition-colors">
|
||||
<div className="flex items-start justify-between gap-2 mb-3">
|
||||
<h3 className="text-lg font-semibold text-foreground group-hover:text-brutalist-accent transition-colors min-w-0 break-words">
|
||||
{tool.package.npmPackageName}
|
||||
<span className="text-xs text-foreground-tertiary ml-2">
|
||||
({tool.name})
|
||||
</span>
|
||||
</h3>
|
||||
{tool.package.isOfficial && (
|
||||
<Badge variant="default" size="sm">
|
||||
<Badge variant="default" size="sm" className="flex-shrink-0">
|
||||
Official
|
||||
</Badge>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -117,6 +117,7 @@ export default function SDKPage(): React.ReactElement {
|
|||
<CodeBlock
|
||||
language="typescript"
|
||||
code={`import { streamText } from 'ai';
|
||||
// Import AI SDK provider for your selected model (OpenAI, Anthropic, Google, etc.)
|
||||
import { anthropic } from '@ai-sdk/anthropic';
|
||||
import { registrySearchTool } from '@tpmjs/registry-search';
|
||||
import { registryExecuteTool } from '@tpmjs/registry-execute';
|
||||
|
|
@ -518,6 +519,7 @@ export const registryExecute = tool({
|
|||
<CodeBlock
|
||||
language="typescript"
|
||||
code={`import { streamText } from 'ai';
|
||||
// Import AI SDK provider for your selected model (OpenAI, Anthropic, Google, etc.)
|
||||
import { anthropic } from '@ai-sdk/anthropic';
|
||||
import { registrySearchTool } from '@tpmjs/registry-search';
|
||||
import { registryExecute } from './tools'; // Your wrapped version
|
||||
|
|
|
|||
|
|
@ -121,7 +121,7 @@ export default function SpecPage(): React.ReactElement {
|
|||
</div>
|
||||
|
||||
{/* View Toggle */}
|
||||
<div className="flex gap-1 p-1 bg-surface rounded-lg border border-border">
|
||||
<div className="flex gap-1 p-1 bg-surface rounded-lg border border-border self-center md:self-auto">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setView('spec')}
|
||||
|
|
|
|||
|
|
@ -76,7 +76,9 @@ export function EcosystemDiagram(): React.ReactElement {
|
|||
const updateDimensions = () => {
|
||||
if (containerRef.current) {
|
||||
const width = containerRef.current.clientWidth;
|
||||
const height = Math.min(500, Math.max(400, width * 0.5));
|
||||
const isMobile = width < 600;
|
||||
// Mobile needs more height for vertical layout (5 nodes stacked)
|
||||
const height = isMobile ? 480 : Math.min(500, Math.max(400, width * 0.5));
|
||||
setDimensions({ width, height });
|
||||
}
|
||||
};
|
||||
|
|
@ -414,47 +416,71 @@ export function EcosystemDiagram(): React.ReactElement {
|
|||
});
|
||||
});
|
||||
|
||||
// Add legend
|
||||
const legend = svg.append('g').attr('transform', `translate(${width - 160}, 20)`);
|
||||
|
||||
// Add legend - positioned differently for mobile vs desktop
|
||||
const legendItems = [
|
||||
{ label: 'BlocksAI', color: colors.blocksai },
|
||||
{ label: 'TPMJS', color: colors.tpmjs },
|
||||
{ label: 'HLLM', color: colors.hllm },
|
||||
];
|
||||
|
||||
legendItems.forEach((item, i) => {
|
||||
const y = i * 22;
|
||||
legend
|
||||
.append('rect')
|
||||
.attr('x', 0)
|
||||
.attr('y', y)
|
||||
.attr('width', 14)
|
||||
.attr('height', 14)
|
||||
.attr('rx', 3)
|
||||
.attr('fill', item.color.fill)
|
||||
.attr('stroke', item.color.stroke)
|
||||
.attr('stroke-width', 1.5);
|
||||
if (isMobile) {
|
||||
// Mobile: horizontal legend at bottom
|
||||
const legend = svg
|
||||
.append('g')
|
||||
.attr('transform', `translate(${width / 2 - 100}, ${height - 30})`);
|
||||
|
||||
legend
|
||||
.append('text')
|
||||
.attr('x', 20)
|
||||
.attr('y', y + 11)
|
||||
.attr('font-size', '11px')
|
||||
.attr('fill', '#64748b')
|
||||
.text(item.label);
|
||||
});
|
||||
legendItems.forEach((item, i) => {
|
||||
const x = i * 70;
|
||||
legend
|
||||
.append('rect')
|
||||
.attr('x', x)
|
||||
.attr('y', 0)
|
||||
.attr('width', 12)
|
||||
.attr('height', 12)
|
||||
.attr('rx', 3)
|
||||
.attr('fill', item.color.fill)
|
||||
.attr('stroke', item.color.stroke)
|
||||
.attr('stroke-width', 1.5);
|
||||
|
||||
legend
|
||||
.append('text')
|
||||
.attr('x', x + 16)
|
||||
.attr('y', 10)
|
||||
.attr('font-size', '10px')
|
||||
.attr('fill', '#64748b')
|
||||
.text(item.label);
|
||||
});
|
||||
} else {
|
||||
// Desktop: vertical legend at top right
|
||||
const legend = svg.append('g').attr('transform', `translate(${width - 160}, 20)`);
|
||||
|
||||
legendItems.forEach((item, i) => {
|
||||
const y = i * 22;
|
||||
legend
|
||||
.append('rect')
|
||||
.attr('x', 0)
|
||||
.attr('y', y)
|
||||
.attr('width', 14)
|
||||
.attr('height', 14)
|
||||
.attr('rx', 3)
|
||||
.attr('fill', item.color.fill)
|
||||
.attr('stroke', item.color.stroke)
|
||||
.attr('stroke-width', 1.5);
|
||||
|
||||
legend
|
||||
.append('text')
|
||||
.attr('x', 20)
|
||||
.attr('y', y + 11)
|
||||
.attr('font-size', '11px')
|
||||
.attr('fill', '#64748b')
|
||||
.text(item.label);
|
||||
});
|
||||
}
|
||||
}, [dimensions]);
|
||||
|
||||
return (
|
||||
<div ref={containerRef} className="relative w-full">
|
||||
<svg
|
||||
ref={svgRef}
|
||||
width={dimensions.width}
|
||||
height={dimensions.height}
|
||||
className="w-full"
|
||||
style={{ minHeight: '400px' }}
|
||||
/>
|
||||
<svg ref={svgRef} width={dimensions.width} height={dimensions.height} className="w-full" />
|
||||
|
||||
{/* Tooltip */}
|
||||
{tooltip.visible && (
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue