mirror of
https://github.com/anomalyco/opencode.git
synced 2026-08-27 15:11:55 +00:00
feat(www): restore native API reference
This commit is contained in:
parent
575bbd6ea1
commit
563943c52e
7 changed files with 907 additions and 25 deletions
151
packages/www/src/docs/components/OpenApiReference.astro
Normal file
151
packages/www/src/docs/components/OpenApiReference.astro
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
---
|
||||
import openapi from "../../../openapi.json"
|
||||
import type { OpenApiOperation, OpenApiSchema } from "../lib/openapi"
|
||||
import { openApiSchemaLabel } from "../lib/openapi"
|
||||
import OpenApiSchemaView from "./OpenApiSchema.astro"
|
||||
|
||||
const methods = ["get", "post", "put", "patch", "delete", "options", "head"] as const
|
||||
type Method = (typeof methods)[number]
|
||||
|
||||
const paths = openapi.paths as unknown as Record<string, Partial<Record<Method, OpenApiOperation>>>
|
||||
const operations = Object.entries(paths).flatMap(([path, item]) =>
|
||||
methods.flatMap((method) => {
|
||||
const operation = item[method]
|
||||
if (!operation) return []
|
||||
return [{ ...operation, path, method, id: operation.operationId ?? `${method}-${path}`.replace(/[^a-z0-9]+/gi, "-") }]
|
||||
}),
|
||||
)
|
||||
const groups = [...new Set(operations.map((operation) => operation.tags?.[0] ?? "other"))].map((tag) => ({
|
||||
tag,
|
||||
id: `tag-${tag.replace(/[^a-z0-9]+/gi, "-").toLowerCase()}`,
|
||||
description: openapi.tags.find((item) => item.name === tag)?.description,
|
||||
operations: operations.filter((operation) => (operation.tags?.[0] ?? "other") === tag),
|
||||
}))
|
||||
const schemas = Object.entries(openapi.components.schemas) as [string, OpenApiSchema][]
|
||||
---
|
||||
|
||||
<div class="api-reference">
|
||||
<nav class="api-navigation" aria-label="API endpoints">
|
||||
<strong>API reference</strong>
|
||||
<a class="api-navigation-overview" href="#overview">Overview</a>
|
||||
{
|
||||
groups.map((group) => (
|
||||
<details class="api-navigation-group">
|
||||
<summary><span>{group.tag}</span><small>{group.operations.length}</small></summary>
|
||||
{group.operations.map((operation) => (
|
||||
<a href={`#${operation.id}`}>
|
||||
<span class:list={["api-navigation-method", `api-navigation-method-${operation.method}`]}>{operation.method}</span>
|
||||
<span>{operation.summary}</span>
|
||||
</a>
|
||||
))}
|
||||
</details>
|
||||
))
|
||||
}
|
||||
<a class="api-navigation-overview" href="#schemas"><span>Schemas</span><small>{schemas.length}</small></a>
|
||||
</nav>
|
||||
|
||||
<article class="api-content" id="overview" data-pagefind-body data-pagefind-meta="title:API">
|
||||
<header class="api-intro">
|
||||
<p class="api-eyebrow">OpenAPI {openapi.openapi}</p>
|
||||
<h1>HTTP API</h1>
|
||||
<p>{openapi.info.description}</p>
|
||||
<div class="api-meta">
|
||||
<span>{operations.length} operations</span>
|
||||
<span>{schemas.length} schemas</span>
|
||||
<a href={`${import.meta.env.BASE_URL}openapi.json`}>OpenAPI JSON</a>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{
|
||||
groups.map((group) => (
|
||||
<section class="api-group" id={group.id}>
|
||||
<header>
|
||||
<p class="api-eyebrow">Resource</p>
|
||||
<h2>{group.tag}</h2>
|
||||
{group.description && <p>{group.description}</p>}
|
||||
</header>
|
||||
<div class="api-operations">
|
||||
{group.operations.map((operation) => (
|
||||
<details class="api-operation" id={operation.id}>
|
||||
<summary>
|
||||
<span class:list={["api-method", `api-method-${operation.method}`]}>{operation.method}</span>
|
||||
<code>{operation.path}</code>
|
||||
<span>{operation.summary}</span>
|
||||
</summary>
|
||||
<div class="api-operation-body">
|
||||
{operation.description && <p>{operation.description}</p>}
|
||||
<p class="api-operation-id"><span>Operation ID</span><code>{operation.operationId}</code></p>
|
||||
{!!operation.parameters?.length && (
|
||||
<section class="api-block">
|
||||
<h3>Parameters</h3>
|
||||
<div class="api-table-scroll">
|
||||
<table>
|
||||
<thead><tr><th>Name</th><th>Location</th><th>Type</th><th>Description</th></tr></thead>
|
||||
<tbody>
|
||||
{operation.parameters.map((parameter) => (
|
||||
<tr>
|
||||
<td><code>{parameter.name}</code>{parameter.required && <span class="api-required">required</span>}</td>
|
||||
<td>{parameter.in}</td>
|
||||
<td><OpenApiSchemaView schema={parameter.schema} /></td>
|
||||
<td>{parameter.description ?? <span class="api-muted">No description</span>}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
{operation.requestBody && (
|
||||
<section class="api-block">
|
||||
<h3>Request body {operation.requestBody.required && <span class="api-required">required</span>}</h3>
|
||||
{operation.requestBody.description && <p>{operation.requestBody.description}</p>}
|
||||
<div class="api-content-schemas">
|
||||
{Object.entries(operation.requestBody.content ?? {}).map(([mediaType, content]) => (
|
||||
<div><code class="api-media-type">{mediaType}</code><OpenApiSchemaView schema={content.schema} /></div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
)}
|
||||
<section class="api-block">
|
||||
<h3>Responses</h3>
|
||||
<div class="api-responses">
|
||||
{Object.entries(operation.responses ?? {}).map(([status, response]) => (
|
||||
<div class="api-response">
|
||||
<div class="api-response-heading">
|
||||
<code class:list={["api-status", status.startsWith("2") && "api-status-success"]}>{status}</code>
|
||||
<span>{response.description ?? "Response"}</span>
|
||||
</div>
|
||||
{Object.entries(response.content ?? {}).map(([mediaType, content]) => (
|
||||
<div class="api-response-schema"><code class="api-media-type">{mediaType}</code><OpenApiSchemaView schema={content.schema} /></div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
</div>
|
||||
</details>
|
||||
))}
|
||||
</div>
|
||||
</section>
|
||||
))
|
||||
}
|
||||
|
||||
<section class="api-group api-schemas" id="schemas">
|
||||
<header>
|
||||
<p class="api-eyebrow">Components</p>
|
||||
<h2>Schemas</h2>
|
||||
<p>Reusable data types referenced by API operations.</p>
|
||||
</header>
|
||||
<div class="api-operations">
|
||||
{
|
||||
schemas.map(([name, schema]) => (
|
||||
<details class="api-schema" id={`schema-${name}`}>
|
||||
<summary><code>{name}</code><span>{openApiSchemaLabel(schema)}</span></summary>
|
||||
<div class="api-schema-body"><OpenApiSchemaView schema={schema} /></div>
|
||||
</details>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
</article>
|
||||
</div>
|
||||
69
packages/www/src/docs/components/OpenApiSchema.astro
Normal file
69
packages/www/src/docs/components/OpenApiSchema.astro
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
import { formatOpenApiValue, openApiSchemaLabel, type OpenApiSchema } from "../lib/openapi"
|
||||
|
||||
interface Props {
|
||||
schema?: OpenApiSchema
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
const schema = Astro.props.schema
|
||||
const reference = schema?.$ref?.split("/").at(-1)
|
||||
const variants = schema?.anyOf ?? schema?.oneOf ?? schema?.allOf
|
||||
const variantOperator = schema?.allOf ? "and" : "or"
|
||||
const constraints = schema
|
||||
? [
|
||||
schema.pattern && `pattern ${schema.pattern}`,
|
||||
schema.minimum !== undefined && `min ${schema.minimum}`,
|
||||
schema.maximum !== undefined && `max ${schema.maximum}`,
|
||||
schema.exclusiveMinimum !== undefined && `> ${schema.exclusiveMinimum}`,
|
||||
schema.exclusiveMaximum !== undefined && `< ${schema.exclusiveMaximum}`,
|
||||
schema.minLength !== undefined && `min length ${schema.minLength}`,
|
||||
schema.maxLength !== undefined && `max length ${schema.maxLength}`,
|
||||
schema.minItems !== undefined && `min items ${schema.minItems}`,
|
||||
schema.maxItems !== undefined && `max items ${schema.maxItems}`,
|
||||
].filter((value): value is string => typeof value === "string")
|
||||
: []
|
||||
---
|
||||
|
||||
{
|
||||
reference ? (
|
||||
<a class="api-schema-link" href={`#schema-${reference}`}>{reference}</a>
|
||||
) : (
|
||||
<div class="api-schema-node">
|
||||
<div class="api-schema-heading">
|
||||
<code>{openApiSchemaLabel(schema)}</code>
|
||||
{Astro.props.required && <span class="api-required">required</span>}
|
||||
{schema?.deprecated && <span class="api-deprecated">deprecated</span>}
|
||||
</div>
|
||||
{schema?.description && <p>{schema.description}</p>}
|
||||
{schema?.enum && <div class="api-schema-values"><span>Values</span><code>{schema.enum.map(formatOpenApiValue).join(" | ")}</code></div>}
|
||||
{schema?.const !== undefined && <div class="api-schema-values"><span>Constant</span><code>{formatOpenApiValue(schema.const)}</code></div>}
|
||||
{schema?.default !== undefined && <div class="api-schema-values"><span>Default</span><code>{formatOpenApiValue(schema.default)}</code></div>}
|
||||
{constraints.length > 0 && <div class="api-schema-constraints">{constraints.join(", ")}</div>}
|
||||
{variants && (
|
||||
<div class="api-schema-variants">
|
||||
{variants.map((variant, index) => (
|
||||
<div>
|
||||
{index > 0 && <span class="api-schema-operator">{variantOperator}</span>}
|
||||
<Astro.self schema={variant} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{schema?.type === "array" && schema.items && <div class="api-schema-items"><span>Items</span><Astro.self schema={schema.items} /></div>}
|
||||
{schema?.properties && (
|
||||
<div class="api-schema-properties">
|
||||
{Object.entries(schema.properties).map(([name, property]) => (
|
||||
<div class="api-schema-property">
|
||||
<code>{name}</code>
|
||||
<Astro.self schema={property} required={schema.required?.includes(name)} />
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{typeof schema?.additionalProperties === "object" && (
|
||||
<div class="api-schema-items"><span>Additional properties</span><Astro.self schema={schema.additionalProperties} /></div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -13,9 +13,11 @@ interface Props {
|
|||
currentSlug: string
|
||||
headings: MarkdownHeading[]
|
||||
showTableOfContents?: boolean
|
||||
fullWidth?: boolean
|
||||
}
|
||||
|
||||
const section = getDocsSection(Astro.props.currentSlug)
|
||||
const fullWidth = Astro.props.fullWidth ?? false
|
||||
const description = Astro.props.description ?? `${Astro.props.title} documentation for OpenCode.`
|
||||
const canonical = new URL(Astro.url.pathname, "https://opencode.ai").href
|
||||
---
|
||||
|
|
@ -35,24 +37,34 @@ const canonical = new URL(Astro.url.pathname, "https://opencode.ai").href
|
|||
<body>
|
||||
<a class="skip-link" href="#docs-content">Skip to content</a>
|
||||
<DocsHeader currentSlug={Astro.props.currentSlug} />
|
||||
<details class="mobile-navigation">
|
||||
<summary>{section.title} navigation</summary>
|
||||
<DocsSidebar groups={section.groups} currentSlug={Astro.props.currentSlug} />
|
||||
</details>
|
||||
<div class="docs-frame">
|
||||
<aside class="sidebar-column">
|
||||
<DocsSidebar groups={section.groups} currentSlug={Astro.props.currentSlug} />
|
||||
</aside>
|
||||
<main id="docs-content">
|
||||
<article class="prose" data-pagefind-body data-pagefind-meta={`title:${Astro.props.title}`}>
|
||||
<h1>{Astro.props.title}</h1>
|
||||
{
|
||||
fullWidth ? (
|
||||
<main id="docs-content" class="full-width-content">
|
||||
<slot />
|
||||
</article>
|
||||
</main>
|
||||
<aside class="toc-column">
|
||||
{Astro.props.showTableOfContents !== false && <DocsTableOfContents headings={Astro.props.headings} />}
|
||||
</aside>
|
||||
</div>
|
||||
</main>
|
||||
) : (
|
||||
<>
|
||||
<details class="mobile-navigation">
|
||||
<summary>{section.title} navigation</summary>
|
||||
<DocsSidebar groups={section.groups} currentSlug={Astro.props.currentSlug} />
|
||||
</details>
|
||||
<div class="docs-frame">
|
||||
<aside class="sidebar-column">
|
||||
<DocsSidebar groups={section.groups} currentSlug={Astro.props.currentSlug} />
|
||||
</aside>
|
||||
<main id="docs-content">
|
||||
<article class="prose" data-pagefind-body data-pagefind-meta={`title:${Astro.props.title}`}>
|
||||
<h1>{Astro.props.title}</h1>
|
||||
<slot />
|
||||
</article>
|
||||
</main>
|
||||
<aside class="toc-column">
|
||||
{Astro.props.showTableOfContents !== false && <DocsTableOfContents headings={Astro.props.headings} />}
|
||||
</aside>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
<script is:inline>
|
||||
const addHeadingAnchors = () => {
|
||||
for (const heading of document.querySelectorAll(".prose :is(h2, h3)[id]")) {
|
||||
|
|
|
|||
|
|
@ -88,12 +88,11 @@ export const docsSections: DocsSection[] = [
|
|||
landingSlug: "build",
|
||||
groups: [
|
||||
{
|
||||
title: "Build",
|
||||
items: [
|
||||
{ title: "SDK", slug: "build/sdk" },
|
||||
{ title: "Build", slug: "build" },
|
||||
{ title: "Client", slug: "build/client" },
|
||||
{ title: "Plugins", slug: "build/plugins" },
|
||||
{ title: "Client", slug: "build/client" },
|
||||
{ title: "SDK", slug: "build/sdk" },
|
||||
],
|
||||
},
|
||||
],
|
||||
|
|
|
|||
67
packages/www/src/docs/lib/openapi.ts
Normal file
67
packages/www/src/docs/lib/openapi.ts
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
export type OpenApiSchema = {
|
||||
$ref?: string
|
||||
type?: string | string[]
|
||||
title?: string
|
||||
description?: string
|
||||
format?: string
|
||||
deprecated?: boolean
|
||||
enum?: unknown[]
|
||||
const?: unknown
|
||||
default?: unknown
|
||||
anyOf?: OpenApiSchema[]
|
||||
oneOf?: OpenApiSchema[]
|
||||
allOf?: OpenApiSchema[]
|
||||
items?: OpenApiSchema
|
||||
properties?: Record<string, OpenApiSchema>
|
||||
required?: string[]
|
||||
additionalProperties?: boolean | OpenApiSchema
|
||||
pattern?: string
|
||||
minimum?: number
|
||||
maximum?: number
|
||||
exclusiveMinimum?: number
|
||||
exclusiveMaximum?: number
|
||||
minLength?: number
|
||||
maxLength?: number
|
||||
minItems?: number
|
||||
maxItems?: number
|
||||
}
|
||||
|
||||
export type OpenApiContent = Record<string, { schema?: OpenApiSchema }>
|
||||
|
||||
export type OpenApiParameter = {
|
||||
name: string
|
||||
in: string
|
||||
description?: string
|
||||
required?: boolean
|
||||
schema?: OpenApiSchema
|
||||
}
|
||||
|
||||
export type OpenApiOperation = {
|
||||
tags?: string[]
|
||||
operationId?: string
|
||||
summary?: string
|
||||
description?: string
|
||||
parameters?: OpenApiParameter[]
|
||||
requestBody?: {
|
||||
description?: string
|
||||
required?: boolean
|
||||
content?: OpenApiContent
|
||||
}
|
||||
responses?: Record<string, { description?: string; content?: OpenApiContent }>
|
||||
}
|
||||
|
||||
export function openApiSchemaLabel(schema?: OpenApiSchema): string {
|
||||
if (!schema) return "empty"
|
||||
if (schema.$ref) return schema.$ref.split("/").at(-1) ?? schema.$ref
|
||||
if (schema.enum) return schema.enum.map(formatOpenApiValue).join(" | ")
|
||||
if (schema.anyOf) return schema.anyOf.map(openApiSchemaLabel).join(" | ")
|
||||
if (schema.oneOf) return schema.oneOf.map(openApiSchemaLabel).join(" | ")
|
||||
if (schema.allOf) return schema.allOf.map(openApiSchemaLabel).join(" & ")
|
||||
const type = Array.isArray(schema.type) ? schema.type.join(" | ") : (schema.type ?? "object")
|
||||
if (type === "array") return `${openApiSchemaLabel(schema.items)}[]`
|
||||
return schema.format ? `${type}<${schema.format}>` : type
|
||||
}
|
||||
|
||||
export function formatOpenApiValue(value: unknown) {
|
||||
return typeof value === "string" ? JSON.stringify(value) : JSON.stringify(value) ?? String(value)
|
||||
}
|
||||
|
|
@ -47,6 +47,18 @@
|
|||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
scrollbar-color: var(--border) transparent;
|
||||
scrollbar-width: thin;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar-thumb {
|
||||
border-radius: 999px;
|
||||
background: var(--border);
|
||||
}
|
||||
|
||||
::view-transition-group(*),
|
||||
|
|
@ -244,6 +256,502 @@ main {
|
|||
padding: 3rem clamp(2rem, 4vw, 4rem) 5rem;
|
||||
}
|
||||
|
||||
.full-width-content {
|
||||
min-height: calc(100vh - var(--header-height));
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.api-reference {
|
||||
display: grid;
|
||||
width: min(100%, var(--frame-width));
|
||||
min-height: calc(100vh - var(--header-height));
|
||||
margin-inline: auto;
|
||||
grid-template-columns: 17rem minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.api-navigation {
|
||||
position: sticky;
|
||||
top: var(--header-height);
|
||||
height: calc(100vh - var(--header-height));
|
||||
padding: 2rem var(--gutter) 3rem;
|
||||
border-right: 1px solid var(--border);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.api-navigation > strong {
|
||||
display: block;
|
||||
margin-bottom: 1rem;
|
||||
font-size: 0.75rem;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.api-navigation-overview,
|
||||
.api-navigation-group summary {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
padding: 0.375rem 0;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.api-navigation-overview:hover,
|
||||
.api-navigation-group summary:hover {
|
||||
color: var(--foreground);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.api-navigation-overview small,
|
||||
.api-navigation-group small {
|
||||
color: var(--muted);
|
||||
font: inherit;
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.api-navigation-group {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.api-navigation-group summary {
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.api-navigation-group summary::-webkit-details-marker,
|
||||
.api-operation > summary::-webkit-details-marker,
|
||||
.api-schema > summary::-webkit-details-marker {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.api-navigation-group[open] summary {
|
||||
color: var(--foreground);
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.api-navigation-group > a {
|
||||
display: grid;
|
||||
padding: 0.25rem 0 0.25rem 0.625rem;
|
||||
grid-template-columns: 2.75rem minmax(0, 1fr);
|
||||
align-items: baseline;
|
||||
gap: 0.5rem;
|
||||
color: var(--muted);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.api-navigation-group > a:hover {
|
||||
color: var(--foreground);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.api-navigation-group > a > span:last-child {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.api-navigation-method {
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 700;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.api-navigation-method-get {
|
||||
color: #73a7ff;
|
||||
}
|
||||
|
||||
.api-navigation-method-post {
|
||||
color: #70c997;
|
||||
}
|
||||
|
||||
.api-navigation-method-put,
|
||||
.api-navigation-method-patch {
|
||||
color: #e0af68;
|
||||
}
|
||||
|
||||
.api-navigation-method-delete {
|
||||
color: #e67c7c;
|
||||
}
|
||||
|
||||
.api-content {
|
||||
min-width: 0;
|
||||
padding: 4rem clamp(2rem, 5vw, 5rem) 7rem;
|
||||
}
|
||||
|
||||
.api-intro,
|
||||
.api-group {
|
||||
max-width: 58rem;
|
||||
margin-inline: auto;
|
||||
}
|
||||
|
||||
.api-intro {
|
||||
padding-bottom: 4rem;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.api-eyebrow {
|
||||
margin: 0 0 0.625rem;
|
||||
color: var(--muted);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.06em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.api-intro h1,
|
||||
.api-group h2 {
|
||||
margin: 0;
|
||||
font-weight: 700;
|
||||
line-height: 1.2;
|
||||
}
|
||||
|
||||
.api-intro h1 {
|
||||
font-size: clamp(2rem, 5vw, 3.25rem);
|
||||
}
|
||||
|
||||
.api-intro > p:not(.api-eyebrow),
|
||||
.api-group > header > p:not(.api-eyebrow) {
|
||||
max-width: 46rem;
|
||||
margin: 1rem 0 0;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.api-meta {
|
||||
display: flex;
|
||||
margin-top: 2rem;
|
||||
flex-wrap: wrap;
|
||||
gap: 0.625rem;
|
||||
}
|
||||
|
||||
.api-meta > * {
|
||||
padding: 0.375rem 0.625rem;
|
||||
border: 1px solid var(--border);
|
||||
color: var(--muted);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.api-meta a {
|
||||
color: var(--link);
|
||||
}
|
||||
|
||||
.api-group {
|
||||
padding-top: 4.5rem;
|
||||
scroll-margin-top: calc(var(--header-height) + 1rem);
|
||||
}
|
||||
|
||||
.api-group h2 {
|
||||
font-size: 1.5rem;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.api-operations {
|
||||
margin-top: 1.5rem;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.api-operation,
|
||||
.api-schema {
|
||||
border-bottom: 1px solid var(--border);
|
||||
scroll-margin-top: calc(var(--header-height) + 1rem);
|
||||
}
|
||||
|
||||
.api-operation:target,
|
||||
.api-schema:target {
|
||||
background: var(--surface);
|
||||
outline: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.api-operation > summary,
|
||||
.api-schema > summary {
|
||||
position: relative;
|
||||
display: grid;
|
||||
min-height: 4rem;
|
||||
padding: 0.875rem 2.5rem 0.875rem 0.75rem;
|
||||
cursor: pointer;
|
||||
list-style: none;
|
||||
align-items: center;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.api-operation > summary {
|
||||
grid-template-columns: 4.25rem minmax(11rem, 1fr) minmax(11rem, 1fr);
|
||||
}
|
||||
|
||||
.api-operation > summary::after,
|
||||
.api-schema > summary::after {
|
||||
position: absolute;
|
||||
right: 0.75rem;
|
||||
content: "+";
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.api-operation[open] > summary::after,
|
||||
.api-schema[open] > summary::after {
|
||||
content: "-";
|
||||
}
|
||||
|
||||
.api-operation > summary:hover,
|
||||
.api-schema > summary:hover {
|
||||
background: var(--surface);
|
||||
}
|
||||
|
||||
.api-operation > summary > code {
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.api-operation > summary > span:last-of-type,
|
||||
.api-schema > summary > span {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.api-method {
|
||||
display: inline-flex;
|
||||
width: 4.25rem;
|
||||
height: 1.625rem;
|
||||
border: 1px solid currentColor;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.04em;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.api-method-get {
|
||||
color: #73a7ff;
|
||||
}
|
||||
|
||||
.api-method-post {
|
||||
color: #70c997;
|
||||
}
|
||||
|
||||
.api-method-put,
|
||||
.api-method-patch {
|
||||
color: #e0af68;
|
||||
}
|
||||
|
||||
.api-method-delete {
|
||||
color: #e67c7c;
|
||||
}
|
||||
|
||||
.api-operation-body,
|
||||
.api-schema-body {
|
||||
padding: 1.5rem 1.25rem 2rem;
|
||||
border-top: 1px solid var(--border);
|
||||
background: color-mix(in srgb, var(--surface) 55%, transparent);
|
||||
}
|
||||
|
||||
.api-operation-body > p {
|
||||
margin: 0 0 1.5rem;
|
||||
}
|
||||
|
||||
.api-operation-id {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.api-operation-id span,
|
||||
.api-media-type,
|
||||
.api-schema-items > span,
|
||||
.api-schema-values > span {
|
||||
color: var(--muted);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.api-block {
|
||||
margin-top: 2rem;
|
||||
}
|
||||
|
||||
.api-block h3 {
|
||||
margin: 0 0 0.75rem;
|
||||
font-size: 0.875rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.api-block > p {
|
||||
margin: 0 0 1rem;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.api-table-scroll {
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
.api-table-scroll table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.api-table-scroll th,
|
||||
.api-table-scroll td {
|
||||
min-width: 7rem;
|
||||
padding: 0.625rem 1rem 0.625rem 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
text-align: left;
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
.api-table-scroll th {
|
||||
color: var(--muted);
|
||||
font-size: 0.75rem;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.api-required,
|
||||
.api-deprecated {
|
||||
display: inline-block;
|
||||
margin-left: 0.5rem;
|
||||
color: #e0af68;
|
||||
font-size: 0.6875rem;
|
||||
font-weight: 400;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.api-deprecated {
|
||||
color: #e67c7c;
|
||||
}
|
||||
|
||||
.api-muted {
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.api-content-schemas > div,
|
||||
.api-response-schema {
|
||||
display: grid;
|
||||
grid-template-columns: minmax(8rem, auto) minmax(0, 1fr);
|
||||
align-items: start;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.api-content-schemas > div + div,
|
||||
.api-response-schema + .api-response-schema {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.api-responses {
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.api-response {
|
||||
padding: 0.75rem 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.api-response-heading {
|
||||
display: grid;
|
||||
grid-template-columns: 3.5rem minmax(0, 1fr);
|
||||
align-items: baseline;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.api-response-schema {
|
||||
margin: 0.625rem 0 0 4.25rem;
|
||||
}
|
||||
|
||||
.api-status {
|
||||
color: #e0af68;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.api-status-success {
|
||||
color: #70c997;
|
||||
}
|
||||
|
||||
.api-schema-link {
|
||||
color: var(--link);
|
||||
text-decoration: underline;
|
||||
text-decoration-color: color-mix(in srgb, var(--link) 45%, transparent);
|
||||
text-underline-offset: 0.15em;
|
||||
}
|
||||
|
||||
.api-schema-node {
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.api-schema-heading {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.api-schema-node > p {
|
||||
margin: 0.375rem 0 0;
|
||||
color: var(--muted);
|
||||
font-size: 0.8125rem;
|
||||
}
|
||||
|
||||
.api-schema-values,
|
||||
.api-schema-items {
|
||||
display: grid;
|
||||
margin-top: 0.5rem;
|
||||
grid-template-columns: 7rem minmax(0, 1fr);
|
||||
align-items: baseline;
|
||||
gap: 0.75rem;
|
||||
}
|
||||
|
||||
.api-schema-values code {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.api-schema-constraints {
|
||||
margin-top: 0.375rem;
|
||||
color: var(--muted);
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.api-schema-variants {
|
||||
margin-top: 0.625rem;
|
||||
padding-left: 0.75rem;
|
||||
border-left: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.api-schema-variants > div {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.api-schema-variants > div + div {
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
.api-schema-operator {
|
||||
display: block;
|
||||
margin-bottom: 0.25rem;
|
||||
color: var(--muted);
|
||||
font-size: 0.6875rem;
|
||||
text-transform: uppercase;
|
||||
}
|
||||
|
||||
.api-schema-properties {
|
||||
margin-top: 0.75rem;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.api-schema-property {
|
||||
display: grid;
|
||||
padding: 0.625rem 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
grid-template-columns: minmax(8rem, 0.35fr) minmax(0, 1fr);
|
||||
align-items: start;
|
||||
gap: 1rem;
|
||||
}
|
||||
|
||||
.api-schema-property > code {
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.api-schema > summary {
|
||||
grid-template-columns: minmax(12rem, 1fr) minmax(10rem, 1fr);
|
||||
}
|
||||
|
||||
.api-schema > summary > code,
|
||||
.api-schema > summary > span {
|
||||
min-width: 0;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
.toc-column {
|
||||
padding: 3rem var(--gutter) 3rem 2rem;
|
||||
}
|
||||
|
|
@ -561,6 +1069,18 @@ main {
|
|||
grid-template-columns: 14rem minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.api-reference {
|
||||
grid-template-columns: 14rem minmax(0, 1fr);
|
||||
}
|
||||
|
||||
.api-content {
|
||||
padding-inline: 2rem;
|
||||
}
|
||||
|
||||
.api-operation > summary {
|
||||
grid-template-columns: 4.25rem minmax(9rem, 1fr) minmax(9rem, 1fr);
|
||||
}
|
||||
|
||||
.toc-column {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -626,4 +1146,70 @@ main {
|
|||
.docs-card-group {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
|
||||
.api-reference {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.api-navigation {
|
||||
position: relative;
|
||||
top: auto;
|
||||
height: auto;
|
||||
max-height: 20rem;
|
||||
padding: 1.25rem var(--gutter);
|
||||
border-right: 0;
|
||||
border-bottom: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.api-navigation > strong {
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
|
||||
.api-content {
|
||||
padding: 2.5rem var(--gutter) 5rem;
|
||||
}
|
||||
|
||||
.api-intro {
|
||||
padding-bottom: 3rem;
|
||||
}
|
||||
|
||||
.api-group {
|
||||
padding-top: 3.5rem;
|
||||
}
|
||||
|
||||
.api-operation > summary {
|
||||
grid-template-columns: 4.25rem minmax(0, 1fr);
|
||||
gap: 0.625rem 0.75rem;
|
||||
}
|
||||
|
||||
.api-operation > summary > span:last-of-type {
|
||||
grid-column: 1 / -1;
|
||||
}
|
||||
|
||||
.api-operation-body,
|
||||
.api-schema-body {
|
||||
padding-inline: 0.75rem;
|
||||
}
|
||||
|
||||
.api-content-schemas > div,
|
||||
.api-response-schema,
|
||||
.api-schema-values,
|
||||
.api-schema-items {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
|
||||
.api-response-schema {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.api-schema-property {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 0.375rem;
|
||||
}
|
||||
|
||||
.api-schema > summary {
|
||||
grid-template-columns: minmax(0, 1fr);
|
||||
gap: 0.25rem;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
---
|
||||
import OpenApiReference from "../../../docs/components/OpenApiReference.astro"
|
||||
import DocsLayout from "../../../docs/layouts/DocsLayout.astro"
|
||||
|
||||
export const prerender = true
|
||||
|
|
@ -10,10 +11,7 @@ export const prerender = true
|
|||
currentSlug="api"
|
||||
headings={[]}
|
||||
showTableOfContents={false}
|
||||
fullWidth
|
||||
>
|
||||
<p>
|
||||
OpenCode exposes an HTTP API from its server. Use <code>opencode2 api</code> for authenticated local requests, or
|
||||
build against the generated OpenAPI specification.
|
||||
</p>
|
||||
<p><a href={`${import.meta.env.BASE_URL}openapi.json`}>View the OpenAPI specification</a>.</p>
|
||||
<OpenApiReference />
|
||||
</DocsLayout>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue