feat(web): real 3-step wizard, settings, audit, docs, marketing pages
Sprint 3.5: close every dead link and replace the single-step wizard with the spec-mandated 3-step flow. Wizard: - Step 1 collects prompt + name + slug, calls /v1/servers/preview. - Step 2 renders parsed tools (name, description, input schema as copyable JSON) + a credential field per requiredSecret Claude actually identified. Self-contained servers see 'No credentials needed' instead of generic Notion placeholders. - Step 3 streams the live build over WebSocket and shows install snippets. New dashboard pages: - /settings — org, plan/usage, members table, API keys + billing stubs (Sprint 4), encryption status. Reads /v1/me/org. - /audit — filterable table over /v1/audit with action pills, resource refs, IP, metadata JSON. Docs site (/docs + 6 sub-pages): - Sticky 240px sidebar, max-w-prose article column, shared DocsTitle/H2/Code primitives. - Quickstart, MCP concepts, OAuth 2.1 flow (full walkthrough with curl), Authoring tools, Self-hosting, API reference, FAQ. Marketing pages: - /changelog with tagged release timeline. - /security with 8 pillars + disclosure. - /privacy with GDPR-aware sections. - /terms (10 clauses). - /pricing full page (nav now points here instead of /#pricing anchor). - /status with live 10s probes against /api/health and /login. Footer 'system status' badge now links to /status. All 20 routes 200 OK in smoke crawl. Typecheck clean across packages.
This commit is contained in:
75
apps/web/components/docs-page.tsx
Normal file
75
apps/web/components/docs-page.tsx
Normal file
@@ -0,0 +1,75 @@
|
||||
import type { ReactNode } from 'react';
|
||||
import { CodeBlock } from './code-block';
|
||||
|
||||
export function DocsTitle({ children, kicker }: { children: ReactNode; kicker?: string }) {
|
||||
return (
|
||||
<header className="mb-6">
|
||||
{kicker && (
|
||||
<div className="mb-2 text-[11px] uppercase tracking-[0.16em] text-[--color-fg-subtle]">
|
||||
{kicker}
|
||||
</div>
|
||||
)}
|
||||
<h1 className="text-[28px] font-semibold leading-tight tracking-tight">{children}</h1>
|
||||
</header>
|
||||
);
|
||||
}
|
||||
|
||||
export function DocsLead({ children }: { children: ReactNode }) {
|
||||
return <p className="mb-8 text-[15px] leading-relaxed text-[--color-fg-muted]">{children}</p>;
|
||||
}
|
||||
|
||||
export function DocsH2({ children, id }: { children: ReactNode; id?: string }) {
|
||||
return (
|
||||
<h2 id={id} className="mt-10 mb-3 text-[18px] font-semibold tracking-tight">
|
||||
{children}
|
||||
</h2>
|
||||
);
|
||||
}
|
||||
|
||||
export function DocsH3({ children }: { children: ReactNode }) {
|
||||
return <h3 className="mt-6 mb-2 text-[14px] font-semibold tracking-tight">{children}</h3>;
|
||||
}
|
||||
|
||||
export function DocsP({ children }: { children: ReactNode }) {
|
||||
return <p className="mb-4 text-[13.5px] leading-relaxed text-[--color-fg]">{children}</p>;
|
||||
}
|
||||
|
||||
export function DocsList({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<ul className="mb-4 space-y-1.5 pl-4 text-[13.5px] leading-relaxed text-[--color-fg]">
|
||||
{children}
|
||||
</ul>
|
||||
);
|
||||
}
|
||||
|
||||
export function DocsLi({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<li className="relative pl-2 before:absolute before:left-[-12px] before:top-2 before:size-1 before:rounded-full before:bg-[--color-fg-subtle]">
|
||||
{children}
|
||||
</li>
|
||||
);
|
||||
}
|
||||
|
||||
export function Mono({ children }: { children: ReactNode }) {
|
||||
return (
|
||||
<code className="mono rounded-sm bg-[--color-bg-subtle] px-1.5 py-0.5 text-[12.5px] text-[--color-fg]">
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
}
|
||||
|
||||
export function DocsCode({
|
||||
label,
|
||||
code,
|
||||
language,
|
||||
}: {
|
||||
label?: string;
|
||||
code: string;
|
||||
language?: string;
|
||||
}) {
|
||||
return (
|
||||
<div className="my-4">
|
||||
<CodeBlock label={label} code={code} language={language} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user