From a659e90720d70bd62693fdcb0dd27b6d1abdf4ba Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Sun, 8 Mar 2026 23:48:16 -0700 Subject: [PATCH 1/7] improvement(docs): align sidebar method badges and polish API reference styling --- apps/docs/app/[lang]/[[...slug]]/page.tsx | 1 + apps/docs/app/global.css | 356 +++++++++-------- apps/docs/lib/source.ts | 5 +- apps/docs/openapi.json | 443 ++++++++++++++-------- 4 files changed, 466 insertions(+), 339 deletions(-) diff --git a/apps/docs/app/[lang]/[[...slug]]/page.tsx b/apps/docs/app/[lang]/[[...slug]]/page.tsx index 81f3311921d..e8f330ee523 100644 --- a/apps/docs/app/[lang]/[[...slug]]/page.tsx +++ b/apps/docs/app/[lang]/[[...slug]]/page.tsx @@ -235,6 +235,7 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l /> input[placeholder="Filter Properties"]) + .text-sm.border-t { } /* Hide "TypeScript Definitions" copy panel on API pages */ -#nd-page:has(.api-page-header) div.not-prose.rounded-xl.border.p-3.mb-4 { +#nd-page.openapi-page div.not-prose.rounded-xl.border.p-3.mb-4 { display: none !important; } -#nd-page:has(.api-page-header) div.not-prose.rounded-xl.border.p-3:has(> div > p.font-medium) { +#nd-page.openapi-page div.not-prose.rounded-xl.border.p-3:has(> div > p.font-medium) { display: none !important; } @@ -719,20 +689,18 @@ div.flex.flex-row.items-start.bg-fd-secondary.border.rounded-lg.text-xs { /* Method+path bar — cleaner, lighter styling like Gumloop. Override bg-fd-card CSS variable directly for reliability. */ -#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose { +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose { --color-fd-card: rgb(249 250 251) !important; background-color: rgb(249 250 251) !important; border-color: rgb(229 231 235) !important; } -html.dark - #nd-page:has(.api-page-header) - div.flex.flex-row.items-center.rounded-xl.border.not-prose { +html.dark #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose { --color-fd-card: rgb(24 24 27) !important; background-color: rgb(24 24 27) !important; border-color: rgb(63 63 70) !important; } /* Method badge inside path bar — cleaner sans-serif, softer colors */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium { font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif !important; @@ -741,56 +709,96 @@ html.dark letter-spacing: 0.025em; text-transform: uppercase; } -/* POST — softer blue */ -#nd-page:has(.api-page-header) +/* Path bar per-method colors (fumadocs renders these, so we match by class) */ +/* GET */ +#nd-page.openapi-page + div.flex.flex-row.items-center.rounded-xl.border.not-prose + span.font-mono.font-medium[class*="text-green"] { + color: rgb(22 163 74) !important; + background-color: rgb(220 252 231 / 0.7) !important; +} +html.dark + #nd-page.openapi-page + div.flex.flex-row.items-center.rounded-xl.border.not-prose + span.font-mono.font-medium[class*="text-green"] { + color: rgb(74 222 128) !important; + background-color: rgb(34 197 94 / 0.15) !important; +} +/* POST */ +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-blue"] { color: rgb(37 99 235) !important; background-color: rgb(219 234 254 / 0.7) !important; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-blue"] { color: rgb(96 165 250) !important; background-color: rgb(59 130 246 / 0.15) !important; } -/* GET — softer green */ -#nd-page:has(.api-page-header) +/* PUT */ +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose - span.font-mono.font-medium[class*="text-green"] { - color: rgb(22 163 74) !important; - background-color: rgb(220 252 231 / 0.7) !important; + span.font-mono.font-medium[class*="text-yellow"] { + color: rgb(161 98 7) !important; + background-color: rgb(254 249 195 / 0.7) !important; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose - span.font-mono.font-medium[class*="text-green"] { - color: rgb(74 222 128) !important; - background-color: rgb(34 197 94 / 0.15) !important; + span.font-mono.font-medium[class*="text-yellow"] { + color: rgb(250 204 21) !important; + background-color: rgb(234 179 8 / 0.15) !important; +} +/* PATCH */ +#nd-page.openapi-page + div.flex.flex-row.items-center.rounded-xl.border.not-prose + span.font-mono.font-medium[class*="text-orange"] { + color: rgb(194 65 12) !important; + background-color: rgb(255 237 213 / 0.7) !important; +} +html.dark + #nd-page.openapi-page + div.flex.flex-row.items-center.rounded-xl.border.not-prose + span.font-mono.font-medium[class*="text-orange"] { + color: rgb(251 146 60) !important; + background-color: rgb(249 115 22 / 0.15) !important; +} +/* DELETE */ +#nd-page.openapi-page + div.flex.flex-row.items-center.rounded-xl.border.not-prose + span.font-mono.font-medium[class*="text-red"] { + color: rgb(185 28 28) !important; + background-color: rgb(254 226 226 / 0.7) !important; +} +html.dark + #nd-page.openapi-page + div.flex.flex-row.items-center.rounded-xl.border.not-prose + span.font-mono.font-medium[class*="text-red"] { + color: rgb(248 113 113) !important; + background-color: rgb(239 68 68 / 0.15) !important; } /* Path text inside method+path bar — monospace, bright like Gumloop */ -#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose code { +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose code { color: rgb(55 65 81) !important; background: none !important; border: none !important; padding: 0 !important; font-size: 0.8125rem !important; } -html.dark - #nd-page:has(.api-page-header) - div.flex.flex-row.items-center.rounded-xl.border.not-prose - code { +html.dark #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose code { color: rgb(229 231 235) !important; } /* Inline code in API pages — neutral color instead of red. Exclude code inside the method+path bar (handled above). */ -#nd-page:has(.api-page-header) .prose :not(pre) > code { +#nd-page.openapi-page .prose :not(pre) > code { color: rgb(79 70 229) !important; } -html.dark #nd-page:has(.api-page-header) .prose :not(pre) > code { +html.dark #nd-page.openapi-page .prose :not(pre) > code { color: rgb(165 180 252) !important; } @@ -953,78 +961,75 @@ html.dark .response-section-dropdown-item:hover { } /* Property row — reorder: name (1) → type badge (2) → required badge (3) */ -#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose { +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose { display: flex; flex-wrap: wrap; align-items: center; } /* Name span — order 1 */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span.font-medium.font-mono.text-fd-primary { order: 1; } -/* Type badge — order 2, grey pill like Mintlify */ -#nd-page:has(.api-page-header) +/* Type badge — order 2, grey pill */ +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { order: 2; - background-color: rgb(240 240 243); - color: rgb(100 100 110); - padding: 0.125rem 0.5rem; + background-color: rgb(241 245 249); + color: rgb(71 85 105); + padding: 0.1875rem 0.5rem; border-radius: 0.375rem; font-size: 0.6875rem; - line-height: 1.25rem; + line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { - background-color: rgb(39 39 42); - color: rgb(212 212 216); + background-color: rgb(51 51 56); + color: rgb(212 212 220); } /* Hide the "*" inside the name span — we'll add "required" as a ::after on the flex row */ -#nd-page:has(.api-page-header) span.font-medium.font-mono.text-fd-primary > span.text-red-400 { +#nd-page.openapi-page span.font-medium.font-mono.text-fd-primary > span.text-red-400 { display: none; } -/* Required badge — order 3, light red pill */ -#nd-page:has(.api-page-header) - .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { +/* Required badge — order 3, red pill */ +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { content: "required"; order: 3; display: inline-flex; align-items: center; - background-color: rgb(254 235 235); - color: rgb(220 38 38); - padding: 0.125rem 0.5rem; + background-color: rgb(254 226 226); + color: rgb(185 28 28); + padding: 0.1875rem 0.5rem; border-radius: 0.375rem; font-size: 0.6875rem; - line-height: 1.25rem; + line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { - background-color: rgb(127 29 29 / 0.2); + background-color: rgb(153 27 27 / 0.3); color: rgb(252 165 165); } /* Optional "?" indicator — hide it */ -#nd-page:has(.api-page-header) - span.font-medium.font-mono.text-fd-primary - > span.text-fd-muted-foreground { +#nd-page.openapi-page span.font-medium.font-mono.text-fd-primary > span.text-fd-muted-foreground { display: none; } /* Hide the auth scheme type label (e.g. "apiKey") next to Authorization heading */ -#nd-page:has(.api-page-header) .flex.items-start.justify-between.gap-2 > div.not-prose { +#nd-page.openapi-page .flex.items-start.justify-between.gap-2 > div.not-prose { display: none !important; } @@ -1032,13 +1037,13 @@ html.dark Auth properties use my-4 (vs py-4 for regular properties). */ /* Auth property flex row — name: order 1, type: order 2, ::before "header": order 3, ::after "required": order 4 */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.font-medium.font-mono.text-fd-primary { order: 1; } -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { @@ -1048,79 +1053,73 @@ html.dark background: none !important; line-height: 0; } -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground::after { content: "string"; font-size: 0.6875rem; - line-height: 1.25rem; + line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; - background-color: rgb(240 240 243); - color: rgb(100 100 110); - padding: 0.125rem 0.5rem; + background-color: rgb(241 245 249); + color: rgb(71 85 105); + padding: 0.1875rem 0.5rem; border-radius: 0.375rem; display: inline-flex; align-items: center; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground::after { - background-color: rgb(39 39 42); - color: rgb(212 212 216); + background-color: rgb(51 51 56); + color: rgb(212 212 220); } /* "header" badge via ::before on the auth flex row */ -#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { +#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { content: "header"; order: 3; display: inline-flex; align-items: center; - background-color: rgb(240 240 243); - color: rgb(100 100 110); - padding: 0.125rem 0.5rem; + background-color: rgb(241 245 249); + color: rgb(71 85 105); + padding: 0.1875rem 0.5rem; border-radius: 0.375rem; font-size: 0.6875rem; - line-height: 1.25rem; + line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark - #nd-page:has(.api-page-header) - div.my-4 - > .flex.flex-wrap.items-center.gap-3.not-prose::before { - background-color: rgb(39 39 42); - color: rgb(212 212 216); +html.dark #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { + background-color: rgb(51 51 56); + color: rgb(212 212 220); } -/* "required" badge via ::after on the auth flex row — light red pill */ -#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { +/* "required" badge via ::after on the auth flex row — red pill */ +#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { content: "required"; order: 4; display: inline-flex; align-items: center; - background-color: rgb(254 235 235); - color: rgb(220 38 38); - padding: 0.125rem 0.5rem; + background-color: rgb(254 226 226); + color: rgb(185 28 28); + padding: 0.1875rem 0.5rem; border-radius: 0.375rem; font-size: 0.6875rem; - line-height: 1.25rem; + line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark - #nd-page:has(.api-page-header) - div.my-4 - > .flex.flex-wrap.items-center.gap-3.not-prose::after { - background-color: rgb(127 29 29 / 0.2); +html.dark #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { + background-color: rgb(153 27 27 / 0.3); color: rgb(252 165 165); } /* Hide "In: header" text below auth property — redundant with the header badge */ -#nd-page:has(.api-page-header) div.my-4 .prose-no-margin p:has(> code) { +#nd-page.openapi-page div.my-4 .prose-no-margin p:has(> code) { display: none !important; } @@ -1135,27 +1134,27 @@ html.dark .api-section-divider { /* Property rows — breathing room like Mintlify. Regular properties use border-t py-4; auth properties use border-t my-4. */ -#nd-page:has(.api-page-header) .text-sm.border-t.py-4 { +#nd-page.openapi-page .text-sm.border-t.py-4 { padding-top: 1.25rem !important; padding-bottom: 1.25rem !important; } -#nd-page:has(.api-page-header) .text-sm.border-t.my-4 { +#nd-page.openapi-page .text-sm.border-t.my-4 { margin-top: 1.25rem !important; margin-bottom: 1.25rem !important; padding-top: 1.25rem; } /* Divider lines between fields — very subtle like Mintlify */ -#nd-page:has(.api-page-header) .text-sm.border-t { +#nd-page.openapi-page .text-sm.border-t { border-color: rgb(229 231 235 / 0.6); } -html.dark #nd-page:has(.api-page-header) .text-sm.border-t { +html.dark #nd-page.openapi-page .text-sm.border-t { border-color: rgb(255 255 255 / 0.07); } /* Body/Callback section "application/json" label — remove inline code styling */ -#nd-page:has(.api-page-header) .flex.gap-2.items-center.justify-between p.not-prose code.text-xs, -#nd-page:has(.api-page-header) .flex.justify-between.gap-2.items-end p.not-prose code.text-xs { +#nd-page.openapi-page .flex.gap-2.items-center.justify-between p.not-prose code.text-xs, +#nd-page.openapi-page .flex.justify-between.gap-2.items-end p.not-prose code.text-xs { background: none !important; border: none !important; padding: 0 !important; @@ -1165,39 +1164,36 @@ html.dark #nd-page:has(.api-page-header) .text-sm.border-t { } /* Object/array type triggers in property rows — order 2 + badge chip styling */ -#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > button, -#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > button, +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { order: 2; - background-color: rgb(240 240 243); - color: rgb(100 100 110); - padding: 0.125rem 0.5rem; + background-color: rgb(241 245 249); + color: rgb(71 85 105); + padding: 0.1875rem 0.5rem; border-radius: 0.375rem; font-size: 0.6875rem; - line-height: 1.25rem; + line-height: 1.125rem; font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark #nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > button, -html.dark - #nd-page:has(.api-page-header) - .flex.flex-wrap.items-center.gap-3.not-prose - > span:has(> button) { - background-color: rgb(39 39 42); - color: rgb(212 212 216); +html.dark #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > button, +html.dark #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { + background-color: rgb(51 51 56); + color: rgb(212 212 220); } /* Section headings (Authorization, Path Parameters, etc.) — consistent top spacing */ -#nd-page:has(.api-page-header) .min-w-0.flex-1 h2 { +#nd-page.openapi-page .min-w-0.flex-1 h2 { margin-top: 1.75rem !important; margin-bottom: 0.25rem !important; } /* Code examples in right column — wrap long lines instead of horizontal scroll */ -#nd-page:has(.api-page-header) pre { +#nd-page.openapi-page pre { white-space: pre-wrap !important; word-break: break-all !important; } -#nd-page:has(.api-page-header) pre code { +#nd-page.openapi-page pre code { width: 100% !important; word-break: break-all !important; overflow-wrap: break-word !important; @@ -1213,11 +1209,11 @@ html.dark /* Footer navigation — constrain to left content column on OpenAPI pages only. Target pages that contain the two-column layout via :has() selector. */ -#nd-page:has(.api-page-header) > div:last-child { +#nd-page.openapi-page > div:last-child { max-width: calc(100% - 400px - 1.5rem); } @media (max-width: 1024px) { - #nd-page:has(.api-page-header) > div:last-child { + #nd-page.openapi-page > div:last-child { max-width: 100%; } } diff --git a/apps/docs/lib/source.ts b/apps/docs/lib/source.ts index 99c5f85e8ff..7dcfc33c8fc 100644 --- a/apps/docs/lib/source.ts +++ b/apps/docs/lib/source.ts @@ -62,7 +62,10 @@ function openapiPluginBadgeLeft() { null, createElement( 'span', - { className: `font-mono font-medium me-1.5 text-[10px] text-nowrap ${colorClass}` }, + { + className: `font-mono font-medium me-1.5 text-[10px] text-nowrap ${colorClass}`, + 'data-method': method.toLowerCase(), + }, method ), node.name diff --git a/apps/docs/openapi.json b/apps/docs/openapi.json index 4034424acae..a87b2e2e0d0 100644 --- a/apps/docs/openapi.json +++ b/apps/docs/openapi.json @@ -284,7 +284,8 @@ "description": "Cursor for fetching the next page of results. null when there are no more results." }, "limits": { - "$ref": "#/components/schemas/Limits" + "$ref": "#/components/schemas/Limits", + "description": "Rate limit and usage information for the current API key." } } } @@ -342,7 +343,8 @@ "$ref": "#/components/schemas/WorkflowDetail" }, "limits": { - "$ref": "#/components/schemas/Limits" + "$ref": "#/components/schemas/Limits", + "description": "Rate limit and usage information for the current API key." } } } @@ -1063,7 +1065,8 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", @@ -1072,13 +1075,15 @@ "type": "array", "items": { "$ref": "#/components/schemas/Table" - } + }, + "description": "Array of tables in the workspace." }, "totalCount": { "type": "integer", "description": "Total number of tables." } - } + }, + "description": "Response payload." } } } @@ -1145,7 +1150,8 @@ "minItems": 1, "description": "Column definitions for the table." } - } + }, + "description": "Table schema definition containing column definitions." } } } @@ -1161,18 +1167,22 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", "properties": { "table": { - "$ref": "#/components/schemas/Table" + "$ref": "#/components/schemas/Table", + "description": "The newly created table." }, "message": { - "type": "string" + "type": "string", + "description": "Confirmation message." } - } + }, + "description": "Response payload." } } } @@ -1238,15 +1248,18 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", "properties": { "table": { - "$ref": "#/components/schemas/Table" + "$ref": "#/components/schemas/Table", + "description": "The requested table with its metadata and schema." } - } + }, + "description": "Response payload." } } } @@ -1313,15 +1326,18 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "description": "Confirmation message." } - } + }, + "description": "Response payload." } } } @@ -1431,7 +1447,8 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", @@ -1440,7 +1457,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/TableRow" - } + }, + "description": "Array of rows matching the query." }, "rowCount": { "type": "integer", @@ -1451,12 +1469,15 @@ "description": "Total rows matching the filter." }, "limit": { - "type": "integer" + "type": "integer", + "description": "The limit that was applied to the query." }, "offset": { - "type": "integer" + "type": "integer", + "description": "The offset that was applied to the query." } - } + }, + "description": "Response payload." } } } @@ -1517,7 +1538,8 @@ "description": "Single row insert.", "properties": { "workspaceId": { - "type": "string" + "type": "string", + "description": "The workspace that owns the table." }, "data": { "type": "object", @@ -1532,7 +1554,8 @@ "description": "Batch insert (up to 1000 rows).", "properties": { "workspaceId": { - "type": "string" + "type": "string", + "description": "The workspace that owns the table." }, "rows": { "type": "array", @@ -1540,7 +1563,8 @@ "type": "object", "additionalProperties": true }, - "maxItems": 1000 + "maxItems": 1000, + "description": "Array of row objects to insert. Each object contains key-value pairs matching the table schema." } } } @@ -1558,27 +1582,33 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", "properties": { "row": { - "$ref": "#/components/schemas/TableRow" + "$ref": "#/components/schemas/TableRow", + "description": "The inserted row (present for single-row inserts)." }, "rows": { "type": "array", "items": { "$ref": "#/components/schemas/TableRow" - } + }, + "description": "Array of inserted rows (present for batch inserts)." }, "insertedCount": { - "type": "integer" + "type": "integer", + "description": "Number of rows successfully inserted." }, "message": { - "type": "string" + "type": "string", + "description": "Confirmation message." } - } + }, + "description": "Response payload." } } } @@ -1623,7 +1653,8 @@ "schema": { "type": "string", "example": "tbl_abc123" - } + }, + "description": "The table to update rows in." } ], "requestBody": { @@ -1635,7 +1666,8 @@ "required": ["workspaceId", "filter", "data"], "properties": { "workspaceId": { - "type": "string" + "type": "string", + "description": "The workspace that owns the table." }, "filter": { "type": "object", @@ -1667,24 +1699,29 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "description": "Confirmation message describing how many rows were updated." }, "updatedCount": { - "type": "integer" + "type": "integer", + "description": "Number of rows that were updated." }, "updatedRowIds": { "type": "array", "items": { "type": "string" - } + }, + "description": "Array of IDs for each row that was updated." } - } + }, + "description": "Response payload." } } } @@ -1729,7 +1766,8 @@ "schema": { "type": "string", "example": "tbl_abc123" - } + }, + "description": "The table to delete rows from." } ], "requestBody": { @@ -1737,44 +1775,33 @@ "content": { "application/json": { "schema": { - "oneOf": [ - { - "type": "object", - "required": ["workspaceId", "filter"], - "description": "Delete by filter.", - "properties": { - "workspaceId": { - "type": "string" - }, - "filter": { - "type": "object", - "additionalProperties": true - }, - "limit": { - "type": "integer", - "minimum": 1, - "maximum": 1000 - } - } + "type": "object", + "required": ["workspaceId"], + "properties": { + "workspaceId": { + "type": "string", + "description": "The workspace that owns the table." }, - { + "filter": { "type": "object", - "required": ["workspaceId", "rowIds"], - "description": "Delete by IDs.", - "properties": { - "workspaceId": { - "type": "string" - }, - "rowIds": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 1000 - } - } + "additionalProperties": true, + "description": "Filter criteria to match rows for deletion. Mutually exclusive with `rowIds`." + }, + "rowIds": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 1000, + "description": "Explicit list of row IDs to delete (max 1000). Mutually exclusive with `filter`." + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 1000, + "description": "Maximum number of rows to delete when using `filter`. Defaults to all matching rows, capped at 1000." } - ] + } } } } @@ -1788,22 +1815,26 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "description": "Confirmation message describing how many rows were deleted." }, "deletedCount": { - "type": "integer" + "type": "integer", + "description": "Number of rows that were deleted." }, "deletedRowIds": { "type": "array", "items": { "type": "string" - } + }, + "description": "Array of IDs for each row that was deleted." }, "requestedCount": { "type": "integer", @@ -1816,7 +1847,8 @@ }, "description": "Row IDs that were requested but not found (only present when deleting by IDs)." } - } + }, + "description": "Response payload." } } } @@ -1863,7 +1895,8 @@ "schema": { "type": "string", "example": "tbl_abc123" - } + }, + "description": "The table the row belongs to." }, { "name": "rowId", @@ -1881,7 +1914,8 @@ "required": true, "schema": { "type": "string" - } + }, + "description": "The workspace that owns the table." } ], "responses": { @@ -1893,15 +1927,18 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", "properties": { "row": { - "$ref": "#/components/schemas/TableRow" + "$ref": "#/components/schemas/TableRow", + "description": "The requested row." } - } + }, + "description": "Response payload." } } } @@ -1946,7 +1983,8 @@ "schema": { "type": "string", "example": "tbl_abc123" - } + }, + "description": "The table the row belongs to." }, { "name": "rowId", @@ -1968,7 +2006,8 @@ "required": ["workspaceId", "data"], "properties": { "workspaceId": { - "type": "string" + "type": "string", + "description": "The workspace that owns the table." }, "data": { "type": "object", @@ -1989,18 +2028,22 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", "properties": { "row": { - "$ref": "#/components/schemas/TableRow" + "$ref": "#/components/schemas/TableRow", + "description": "The updated row with all current field values." }, "message": { - "type": "string" + "type": "string", + "description": "Confirmation message." } - } + }, + "description": "Response payload." } } } @@ -2045,7 +2088,8 @@ "schema": { "type": "string", "example": "tbl_abc123" - } + }, + "description": "The table the row belongs to." }, { "name": "rowId", @@ -2063,7 +2107,8 @@ "required": true, "schema": { "type": "string" - } + }, + "description": "The workspace that owns the table." } ], "responses": { @@ -2075,18 +2120,22 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "description": "Confirmation message." }, "deletedCount": { - "type": "integer" + "type": "integer", + "description": "Number of rows deleted (always 1 for single-row deletion)." } - } + }, + "description": "Response payload." } } } @@ -2133,7 +2182,8 @@ "schema": { "type": "string", "example": "tbl_abc123" - } + }, + "description": "The table to upsert the row into." } ], "requestBody": { @@ -2171,13 +2221,15 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Indicates whether the request was successful." }, "data": { "type": "object", "properties": { "row": { - "$ref": "#/components/schemas/TableRow" + "$ref": "#/components/schemas/TableRow", + "description": "The inserted or updated row." }, "operation": { "type": "string", @@ -2185,9 +2237,11 @@ "description": "Whether the row was inserted or updated." }, "message": { - "type": "string" + "type": "string", + "description": "Confirmation message." } - } + }, + "description": "Response payload." } } } @@ -2246,7 +2300,8 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the request completed successfully." }, "data": { "type": "object", @@ -2255,13 +2310,15 @@ "type": "array", "items": { "$ref": "#/components/schemas/FileMetadata" - } + }, + "description": "Array of file metadata objects in the workspace." }, "totalCount": { "type": "integer", "description": "Total number of files." } - } + }, + "description": "Response payload containing the files list and count." } } } @@ -2326,18 +2383,22 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the upload completed successfully." }, "data": { "type": "object", "properties": { "file": { - "$ref": "#/components/schemas/FileMetadata" + "$ref": "#/components/schemas/FileMetadata", + "description": "Metadata of the newly uploaded file." }, "message": { - "type": "string" + "type": "string", + "description": "Human-readable confirmation message." } - } + }, + "description": "Response payload containing the uploaded file metadata." } } } @@ -2361,7 +2422,8 @@ "type": "object", "properties": { "error": { - "type": "string" + "type": "string", + "description": "Error message indicating a file with the same name already exists in this workspace." } } } @@ -2523,15 +2585,18 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the deletion completed successfully." }, "data": { "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "description": "Human-readable confirmation message." } - } + }, + "description": "Response payload containing the deletion confirmation." } } } @@ -2590,7 +2655,8 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the request was successful." }, "data": { "type": "object", @@ -2599,13 +2665,15 @@ "type": "array", "items": { "$ref": "#/components/schemas/KnowledgeBase" - } + }, + "description": "Array of knowledge base objects in the workspace." }, "totalCount": { "type": "integer", "description": "Total number of knowledge bases." } - } + }, + "description": "Response payload containing the list of knowledge bases." } } } @@ -2662,7 +2730,8 @@ "maxLength": 1000 }, "chunkingConfig": { - "$ref": "#/components/schemas/ChunkingConfig" + "$ref": "#/components/schemas/ChunkingConfig", + "description": "Optional chunking configuration for document processing. Defaults to maxSize=1024, minSize=100, overlap=200 if omitted." } } } @@ -2678,18 +2747,22 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the request was successful." }, "data": { "type": "object", "properties": { "knowledgeBase": { - "$ref": "#/components/schemas/KnowledgeBase" + "$ref": "#/components/schemas/KnowledgeBase", + "description": "The newly created knowledge base object." }, "message": { - "type": "string" + "type": "string", + "description": "Human-readable confirmation message." } - } + }, + "description": "Response payload containing the created knowledge base." } } } @@ -2754,15 +2827,18 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the request was successful." }, "data": { "type": "object", "properties": { "knowledgeBase": { - "$ref": "#/components/schemas/KnowledgeBase" + "$ref": "#/components/schemas/KnowledgeBase", + "description": "The knowledge base object." } - } + }, + "description": "Response payload containing the knowledge base details." } } } @@ -2833,7 +2909,8 @@ "maxLength": 1000 }, "chunkingConfig": { - "$ref": "#/components/schemas/ChunkingConfig" + "$ref": "#/components/schemas/ChunkingConfig", + "description": "Updated chunking configuration. All three fields (maxSize, minSize, overlap) must be provided if included." } } } @@ -2849,18 +2926,22 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the request was successful." }, "data": { "type": "object", "properties": { "knowledgeBase": { - "$ref": "#/components/schemas/KnowledgeBase" + "$ref": "#/components/schemas/KnowledgeBase", + "description": "The updated knowledge base object." }, "message": { - "type": "string" + "type": "string", + "description": "Human-readable confirmation message." } - } + }, + "description": "Response payload containing the updated knowledge base." } } } @@ -2926,15 +3007,18 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the request was successful." }, "data": { "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "description": "Human-readable confirmation message." } - } + }, + "description": "Response payload." } } } @@ -3066,7 +3150,8 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the request was successful." }, "data": { "type": "object", @@ -3075,26 +3160,33 @@ "type": "array", "items": { "$ref": "#/components/schemas/KnowledgeDocument" - } + }, + "description": "Array of document objects in the knowledge base." }, "pagination": { "type": "object", "properties": { "total": { - "type": "integer" + "type": "integer", + "description": "Total number of documents matching the query." }, "limit": { - "type": "integer" + "type": "integer", + "description": "Maximum number of documents returned per page." }, "offset": { - "type": "integer" + "type": "integer", + "description": "Number of documents skipped from the beginning." }, "hasMore": { - "type": "boolean" + "type": "boolean", + "description": "Whether there are more documents beyond the current page." } - } + }, + "description": "Pagination metadata for the document list." } - } + }, + "description": "Response payload containing the documents and pagination info." } } } @@ -3173,18 +3265,22 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the request was successful." }, "data": { "type": "object", "properties": { "document": { - "$ref": "#/components/schemas/KnowledgeDocument" + "$ref": "#/components/schemas/KnowledgeDocument", + "description": "The newly created document object with initial processing status of 'pending'." }, "message": { - "type": "string" + "type": "string", + "description": "Human-readable confirmation message." } - } + }, + "description": "Response payload containing the uploaded document." } } } @@ -3211,7 +3307,8 @@ "type": "object", "properties": { "error": { - "type": "string" + "type": "string", + "description": "Error message indicating a file with the same name already exists." } } } @@ -3226,7 +3323,8 @@ "type": "object", "properties": { "error": { - "type": "string" + "type": "string", + "description": "Error message indicating the workspace storage limit has been exceeded." } } } @@ -3241,7 +3339,8 @@ "type": "object", "properties": { "error": { - "type": "string" + "type": "string", + "description": "Error message indicating the file type is not supported." } } } @@ -3306,15 +3405,18 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the request was successful." }, "data": { "type": "object", "properties": { "document": { - "$ref": "#/components/schemas/KnowledgeDocumentDetail" + "$ref": "#/components/schemas/KnowledgeDocumentDetail", + "description": "Detailed document object including processing and connector information." } - } + }, + "description": "Response payload containing the document details." } } } @@ -3386,15 +3488,18 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the request was successful." }, "data": { "type": "object", "properties": { "message": { - "type": "string" + "type": "string", + "description": "Human-readable confirmation message." } - } + }, + "description": "Response payload." } } } @@ -3455,7 +3560,8 @@ }, "description": "An array of knowledge base IDs to search across." } - ] + ], + "description": "Array of knowledge base IDs to search across." }, "query": { "type": "string", @@ -3489,7 +3595,8 @@ "type": "object", "properties": { "success": { - "type": "boolean" + "type": "boolean", + "description": "Whether the request was successful." }, "data": { "type": "object", @@ -3498,7 +3605,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/SearchResult" - } + }, + "description": "Array of search result objects ranked by similarity." }, "query": { "type": "string", @@ -3519,7 +3627,8 @@ "type": "integer", "description": "Number of results returned." } - } + }, + "description": "Response payload containing the search results and metadata." } } } @@ -3610,7 +3719,8 @@ "type": "array", "items": { "$ref": "#/components/schemas/ColumnDefinition" - } + }, + "description": "Array of column definitions for the table." } } }, @@ -4749,11 +4859,28 @@ "description": "Comparison operator (e.g. eq, neq, gt, lt, gte, lte, contains, between)." }, "value": { - "oneOf": [{ "type": "string" }, { "type": "number" }, { "type": "boolean" }], + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + }, + { + "type": "boolean" + } + ], "description": "Value to filter by." }, "valueTo": { - "oneOf": [{ "type": "string" }, { "type": "number" }], + "oneOf": [ + { + "type": "string" + }, + { + "type": "number" + } + ], "description": "Upper bound value for 'between' operator." } } From 87f5306df004a5bee3d7d4dac123bcb19ecb307c Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Sun, 8 Mar 2026 23:52:10 -0700 Subject: [PATCH 2/7] fix(docs): revert className prop on DocsPage for CI compatibility --- apps/docs/app/[lang]/[[...slug]]/page.tsx | 1 - apps/docs/app/global.css | 145 ++++++++++++---------- 2 files changed, 81 insertions(+), 65 deletions(-) diff --git a/apps/docs/app/[lang]/[[...slug]]/page.tsx b/apps/docs/app/[lang]/[[...slug]]/page.tsx index e8f330ee523..81f3311921d 100644 --- a/apps/docs/app/[lang]/[[...slug]]/page.tsx +++ b/apps/docs/app/[lang]/[[...slug]]/page.tsx @@ -235,7 +235,6 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l /> input[placeholder="Filter Properties"]) + .text-sm.border-t { } /* Hide "TypeScript Definitions" copy panel on API pages */ -#nd-page.openapi-page div.not-prose.rounded-xl.border.p-3.mb-4 { +#nd-page:has(.api-page-header) div.not-prose.rounded-xl.border.p-3.mb-4 { display: none !important; } -#nd-page.openapi-page div.not-prose.rounded-xl.border.p-3:has(> div > p.font-medium) { +#nd-page:has(.api-page-header) div.not-prose.rounded-xl.border.p-3:has(> div > p.font-medium) { display: none !important; } @@ -689,18 +689,20 @@ div.flex.flex-row.items-start.bg-fd-secondary.border.rounded-lg.text-xs { /* Method+path bar — cleaner, lighter styling like Gumloop. Override bg-fd-card CSS variable directly for reliability. */ -#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose { +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose { --color-fd-card: rgb(249 250 251) !important; background-color: rgb(249 250 251) !important; border-color: rgb(229 231 235) !important; } -html.dark #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose { +html.dark + #nd-page:has(.api-page-header) + div.flex.flex-row.items-center.rounded-xl.border.not-prose { --color-fd-card: rgb(24 24 27) !important; background-color: rgb(24 24 27) !important; border-color: rgb(63 63 70) !important; } /* Method badge inside path bar — cleaner sans-serif, softer colors */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium { font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif !important; @@ -711,70 +713,70 @@ html.dark #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border } /* Path bar per-method colors (fumadocs renders these, so we match by class) */ /* GET */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-green"] { color: rgb(22 163 74) !important; background-color: rgb(220 252 231 / 0.7) !important; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-green"] { color: rgb(74 222 128) !important; background-color: rgb(34 197 94 / 0.15) !important; } /* POST */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-blue"] { color: rgb(37 99 235) !important; background-color: rgb(219 234 254 / 0.7) !important; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-blue"] { color: rgb(96 165 250) !important; background-color: rgb(59 130 246 / 0.15) !important; } /* PUT */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-yellow"] { color: rgb(161 98 7) !important; background-color: rgb(254 249 195 / 0.7) !important; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-yellow"] { color: rgb(250 204 21) !important; background-color: rgb(234 179 8 / 0.15) !important; } /* PATCH */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-orange"] { color: rgb(194 65 12) !important; background-color: rgb(255 237 213 / 0.7) !important; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-orange"] { color: rgb(251 146 60) !important; background-color: rgb(249 115 22 / 0.15) !important; } /* DELETE */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-red"] { color: rgb(185 28 28) !important; background-color: rgb(254 226 226 / 0.7) !important; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-red"] { color: rgb(248 113 113) !important; @@ -782,23 +784,26 @@ html.dark } /* Path text inside method+path bar — monospace, bright like Gumloop */ -#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose code { +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose code { color: rgb(55 65 81) !important; background: none !important; border: none !important; padding: 0 !important; font-size: 0.8125rem !important; } -html.dark #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose code { +html.dark + #nd-page:has(.api-page-header) + div.flex.flex-row.items-center.rounded-xl.border.not-prose + code { color: rgb(229 231 235) !important; } /* Inline code in API pages — neutral color instead of red. Exclude code inside the method+path bar (handled above). */ -#nd-page.openapi-page .prose :not(pre) > code { +#nd-page:has(.api-page-header) .prose :not(pre) > code { color: rgb(79 70 229) !important; } -html.dark #nd-page.openapi-page .prose :not(pre) > code { +html.dark #nd-page:has(.api-page-header) .prose :not(pre) > code { color: rgb(165 180 252) !important; } @@ -961,21 +966,21 @@ html.dark .response-section-dropdown-item:hover { } /* Property row — reorder: name (1) → type badge (2) → required badge (3) */ -#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose { +#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose { display: flex; flex-wrap: wrap; align-items: center; } /* Name span — order 1 */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span.font-medium.font-mono.text-fd-primary { order: 1; } /* Type badge — order 2, grey pill */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { order: 2; @@ -989,7 +994,7 @@ html.dark .response-section-dropdown-item:hover { font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { background-color: rgb(51 51 56); @@ -997,12 +1002,13 @@ html.dark } /* Hide the "*" inside the name span — we'll add "required" as a ::after on the flex row */ -#nd-page.openapi-page span.font-medium.font-mono.text-fd-primary > span.text-red-400 { +#nd-page:has(.api-page-header) span.font-medium.font-mono.text-fd-primary > span.text-red-400 { display: none; } /* Required badge — order 3, red pill */ -#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { +#nd-page:has(.api-page-header) + .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { content: "required"; order: 3; display: inline-flex; @@ -1017,19 +1023,21 @@ html.dark font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { background-color: rgb(153 27 27 / 0.3); color: rgb(252 165 165); } /* Optional "?" indicator — hide it */ -#nd-page.openapi-page span.font-medium.font-mono.text-fd-primary > span.text-fd-muted-foreground { +#nd-page:has(.api-page-header) + span.font-medium.font-mono.text-fd-primary + > span.text-fd-muted-foreground { display: none; } /* Hide the auth scheme type label (e.g. "apiKey") next to Authorization heading */ -#nd-page.openapi-page .flex.items-start.justify-between.gap-2 > div.not-prose { +#nd-page:has(.api-page-header) .flex.items-start.justify-between.gap-2 > div.not-prose { display: none !important; } @@ -1037,13 +1045,13 @@ html.dark Auth properties use my-4 (vs py-4 for regular properties). */ /* Auth property flex row — name: order 1, type: order 2, ::before "header": order 3, ::after "required": order 4 */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.font-medium.font-mono.text-fd-primary { order: 1; } -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { @@ -1053,7 +1061,7 @@ html.dark background: none !important; line-height: 0; } -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground::after { @@ -1070,7 +1078,7 @@ html.dark align-items: center; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground::after { @@ -1079,7 +1087,7 @@ html.dark } /* "header" badge via ::before on the auth flex row */ -#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { +#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { content: "header"; order: 3; display: inline-flex; @@ -1093,13 +1101,16 @@ html.dark font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { +html.dark + #nd-page:has(.api-page-header) + div.my-4 + > .flex.flex-wrap.items-center.gap-3.not-prose::before { background-color: rgb(51 51 56); color: rgb(212 212 220); } /* "required" badge via ::after on the auth flex row — red pill */ -#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { +#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { content: "required"; order: 4; display: inline-flex; @@ -1113,13 +1124,16 @@ html.dark #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.no font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { +html.dark + #nd-page:has(.api-page-header) + div.my-4 + > .flex.flex-wrap.items-center.gap-3.not-prose::after { background-color: rgb(153 27 27 / 0.3); color: rgb(252 165 165); } /* Hide "In: header" text below auth property — redundant with the header badge */ -#nd-page.openapi-page div.my-4 .prose-no-margin p:has(> code) { +#nd-page:has(.api-page-header) div.my-4 .prose-no-margin p:has(> code) { display: none !important; } @@ -1134,27 +1148,27 @@ html.dark .api-section-divider { /* Property rows — breathing room like Mintlify. Regular properties use border-t py-4; auth properties use border-t my-4. */ -#nd-page.openapi-page .text-sm.border-t.py-4 { +#nd-page:has(.api-page-header) .text-sm.border-t.py-4 { padding-top: 1.25rem !important; padding-bottom: 1.25rem !important; } -#nd-page.openapi-page .text-sm.border-t.my-4 { +#nd-page:has(.api-page-header) .text-sm.border-t.my-4 { margin-top: 1.25rem !important; margin-bottom: 1.25rem !important; padding-top: 1.25rem; } /* Divider lines between fields — very subtle like Mintlify */ -#nd-page.openapi-page .text-sm.border-t { +#nd-page:has(.api-page-header) .text-sm.border-t { border-color: rgb(229 231 235 / 0.6); } -html.dark #nd-page.openapi-page .text-sm.border-t { +html.dark #nd-page:has(.api-page-header) .text-sm.border-t { border-color: rgb(255 255 255 / 0.07); } /* Body/Callback section "application/json" label — remove inline code styling */ -#nd-page.openapi-page .flex.gap-2.items-center.justify-between p.not-prose code.text-xs, -#nd-page.openapi-page .flex.justify-between.gap-2.items-end p.not-prose code.text-xs { +#nd-page:has(.api-page-header) .flex.gap-2.items-center.justify-between p.not-prose code.text-xs, +#nd-page:has(.api-page-header) .flex.justify-between.gap-2.items-end p.not-prose code.text-xs { background: none !important; border: none !important; padding: 0 !important; @@ -1164,8 +1178,8 @@ html.dark #nd-page.openapi-page .text-sm.border-t { } /* Object/array type triggers in property rows — order 2 + badge chip styling */ -#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > button, -#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { +#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > button, +#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { order: 2; background-color: rgb(241 245 249); color: rgb(71 85 105); @@ -1176,24 +1190,27 @@ html.dark #nd-page.openapi-page .text-sm.border-t { font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > button, -html.dark #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { +html.dark #nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > button, +html.dark + #nd-page:has(.api-page-header) + .flex.flex-wrap.items-center.gap-3.not-prose + > span:has(> button) { background-color: rgb(51 51 56); color: rgb(212 212 220); } /* Section headings (Authorization, Path Parameters, etc.) — consistent top spacing */ -#nd-page.openapi-page .min-w-0.flex-1 h2 { +#nd-page:has(.api-page-header) .min-w-0.flex-1 h2 { margin-top: 1.75rem !important; margin-bottom: 0.25rem !important; } /* Code examples in right column — wrap long lines instead of horizontal scroll */ -#nd-page.openapi-page pre { +#nd-page:has(.api-page-header) pre { white-space: pre-wrap !important; word-break: break-all !important; } -#nd-page.openapi-page pre code { +#nd-page:has(.api-page-header) pre code { width: 100% !important; word-break: break-all !important; overflow-wrap: break-word !important; @@ -1209,11 +1226,11 @@ html.dark #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > s /* Footer navigation — constrain to left content column on OpenAPI pages only. Target pages that contain the two-column layout via :has() selector. */ -#nd-page.openapi-page > div:last-child { +#nd-page:has(.api-page-header) > div:last-child { max-width: calc(100% - 400px - 1.5rem); } @media (max-width: 1024px) { - #nd-page.openapi-page > div:last-child { + #nd-page:has(.api-page-header) > div:last-child { max-width: 100%; } } From 72657c3af42319066776768e1f0d41000476dac8 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Sun, 8 Mar 2026 23:53:28 -0700 Subject: [PATCH 3/7] fix(docs): restore oneOf schema for delete rows and use rem units in CSS --- apps/docs/app/global.css | 10 +++---- apps/docs/openapi.json | 64 +++++++++++++++++++++++++--------------- 2 files changed, 45 insertions(+), 29 deletions(-) diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css index 0a09919e548..bcac45b43a1 100644 --- a/apps/docs/app/global.css +++ b/apps/docs/app/global.css @@ -637,7 +637,7 @@ html.dark span.font-mono.font-medium[data-method="delete"] { #nd-sidebar a:has(span.font-mono.font-medium) { display: flex !important; align-items: center !important; - gap: 6px; + gap: 0.375rem; } /* Sidebar method badges — fixed-width for right-aligned labels */ @@ -645,11 +645,11 @@ html.dark span.font-mono.font-medium[data-method="delete"] { display: inline-flex; align-items: center; justify-content: center; - width: 42px; - font-size: 10px !important; + width: 2.625rem; + font-size: 0.625rem !important; line-height: 1 !important; - padding: 2.5px 4px; - border-radius: 3px; + padding: 0.15625rem 0.25rem; + border-radius: 0.1875rem; flex-shrink: 0; } diff --git a/apps/docs/openapi.json b/apps/docs/openapi.json index a87b2e2e0d0..4ff02aabaed 100644 --- a/apps/docs/openapi.json +++ b/apps/docs/openapi.json @@ -1775,33 +1775,49 @@ "content": { "application/json": { "schema": { - "type": "object", - "required": ["workspaceId"], - "properties": { - "workspaceId": { - "type": "string", - "description": "The workspace that owns the table." - }, - "filter": { + "oneOf": [ + { "type": "object", - "additionalProperties": true, - "description": "Filter criteria to match rows for deletion. Mutually exclusive with `rowIds`." - }, - "rowIds": { - "type": "array", - "items": { - "type": "string" - }, - "maxItems": 1000, - "description": "Explicit list of row IDs to delete (max 1000). Mutually exclusive with `filter`." + "required": ["workspaceId", "filter"], + "description": "Delete by filter.", + "properties": { + "workspaceId": { + "type": "string", + "description": "The workspace that owns the table." + }, + "filter": { + "type": "object", + "additionalProperties": true, + "description": "Filter criteria to match rows for deletion." + }, + "limit": { + "type": "integer", + "minimum": 1, + "maximum": 1000, + "description": "Maximum number of rows to delete. Defaults to all matching rows, capped at 1000." + } + } }, - "limit": { - "type": "integer", - "minimum": 1, - "maximum": 1000, - "description": "Maximum number of rows to delete when using `filter`. Defaults to all matching rows, capped at 1000." + { + "type": "object", + "required": ["workspaceId", "rowIds"], + "description": "Delete by IDs.", + "properties": { + "workspaceId": { + "type": "string", + "description": "The workspace that owns the table." + }, + "rowIds": { + "type": "array", + "items": { + "type": "string" + }, + "maxItems": 1000, + "description": "Explicit list of row IDs to delete (max 1000)." + } + } } - } + ] } } } From 1c2727cb66651baae75aae3d2e13f0e9d20e1511 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Mar 2026 00:07:17 -0700 Subject: [PATCH 4/7] fix(docs): replace :has() selectors with direct className for reliable prod layout The API docs layout was intermittently narrow in production because CSS :has(.api-page-header) selectors are unreliable in Tailwind v4 production builds. Apply className="openapi-page" directly to DocsPage and replace all 64 :has() selectors with .openapi-page class targeting. Co-Authored-By: Claude Opus 4.6 --- apps/docs/app/[lang]/[[...slug]]/page.tsx | 1 + apps/docs/app/global.css | 154 ++++++++++------------ 2 files changed, 67 insertions(+), 88 deletions(-) diff --git a/apps/docs/app/[lang]/[[...slug]]/page.tsx b/apps/docs/app/[lang]/[[...slug]]/page.tsx index 81f3311921d..e8f330ee523 100644 --- a/apps/docs/app/[lang]/[[...slug]]/page.tsx +++ b/apps/docs/app/[lang]/[[...slug]]/page.tsx @@ -235,6 +235,7 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l /> input[placeholder="Filter Properties"]) + .text-sm.border-t { } /* Hide "TypeScript Definitions" copy panel on API pages */ -#nd-page:has(.api-page-header) div.not-prose.rounded-xl.border.p-3.mb-4 { +#nd-page.openapi-page div.not-prose.rounded-xl.border.p-3.mb-4 { display: none !important; } -#nd-page:has(.api-page-header) div.not-prose.rounded-xl.border.p-3:has(> div > p.font-medium) { +#nd-page.openapi-page div.not-prose.rounded-xl.border.p-3:has(> div > p.font-medium) { display: none !important; } @@ -689,20 +682,18 @@ div.flex.flex-row.items-start.bg-fd-secondary.border.rounded-lg.text-xs { /* Method+path bar — cleaner, lighter styling like Gumloop. Override bg-fd-card CSS variable directly for reliability. */ -#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose { +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose { --color-fd-card: rgb(249 250 251) !important; background-color: rgb(249 250 251) !important; border-color: rgb(229 231 235) !important; } -html.dark - #nd-page:has(.api-page-header) - div.flex.flex-row.items-center.rounded-xl.border.not-prose { +html.dark #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose { --color-fd-card: rgb(24 24 27) !important; background-color: rgb(24 24 27) !important; border-color: rgb(63 63 70) !important; } /* Method badge inside path bar — cleaner sans-serif, softer colors */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium { font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif !important; @@ -710,73 +701,75 @@ html.dark font-size: 0.6875rem !important; letter-spacing: 0.025em; text-transform: uppercase; + padding: 0.125rem 0.5rem !important; + border-radius: 0.375rem !important; } /* Path bar per-method colors (fumadocs renders these, so we match by class) */ /* GET */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-green"] { color: rgb(22 163 74) !important; background-color: rgb(220 252 231 / 0.7) !important; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-green"] { color: rgb(74 222 128) !important; background-color: rgb(34 197 94 / 0.15) !important; } /* POST */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-blue"] { color: rgb(37 99 235) !important; background-color: rgb(219 234 254 / 0.7) !important; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-blue"] { color: rgb(96 165 250) !important; background-color: rgb(59 130 246 / 0.15) !important; } /* PUT */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-yellow"] { color: rgb(161 98 7) !important; background-color: rgb(254 249 195 / 0.7) !important; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-yellow"] { color: rgb(250 204 21) !important; background-color: rgb(234 179 8 / 0.15) !important; } /* PATCH */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-orange"] { color: rgb(194 65 12) !important; background-color: rgb(255 237 213 / 0.7) !important; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-orange"] { color: rgb(251 146 60) !important; background-color: rgb(249 115 22 / 0.15) !important; } /* DELETE */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-red"] { color: rgb(185 28 28) !important; background-color: rgb(254 226 226 / 0.7) !important; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-red"] { color: rgb(248 113 113) !important; @@ -784,26 +777,23 @@ html.dark } /* Path text inside method+path bar — monospace, bright like Gumloop */ -#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose code { +#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose code { color: rgb(55 65 81) !important; background: none !important; border: none !important; padding: 0 !important; font-size: 0.8125rem !important; } -html.dark - #nd-page:has(.api-page-header) - div.flex.flex-row.items-center.rounded-xl.border.not-prose - code { +html.dark #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose code { color: rgb(229 231 235) !important; } /* Inline code in API pages — neutral color instead of red. Exclude code inside the method+path bar (handled above). */ -#nd-page:has(.api-page-header) .prose :not(pre) > code { +#nd-page.openapi-page .prose :not(pre) > code { color: rgb(79 70 229) !important; } -html.dark #nd-page:has(.api-page-header) .prose :not(pre) > code { +html.dark #nd-page.openapi-page .prose :not(pre) > code { color: rgb(165 180 252) !important; } @@ -966,21 +956,21 @@ html.dark .response-section-dropdown-item:hover { } /* Property row — reorder: name (1) → type badge (2) → required badge (3) */ -#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose { +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose { display: flex; flex-wrap: wrap; align-items: center; } /* Name span — order 1 */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span.font-medium.font-mono.text-fd-primary { order: 1; } /* Type badge — order 2, grey pill */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { order: 2; @@ -994,7 +984,7 @@ html.dark .response-section-dropdown-item:hover { font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { background-color: rgb(51 51 56); @@ -1002,13 +992,12 @@ html.dark } /* Hide the "*" inside the name span — we'll add "required" as a ::after on the flex row */ -#nd-page:has(.api-page-header) span.font-medium.font-mono.text-fd-primary > span.text-red-400 { +#nd-page.openapi-page span.font-medium.font-mono.text-fd-primary > span.text-red-400 { display: none; } /* Required badge — order 3, red pill */ -#nd-page:has(.api-page-header) - .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { content: "required"; order: 3; display: inline-flex; @@ -1023,21 +1012,19 @@ html.dark font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { background-color: rgb(153 27 27 / 0.3); color: rgb(252 165 165); } /* Optional "?" indicator — hide it */ -#nd-page:has(.api-page-header) - span.font-medium.font-mono.text-fd-primary - > span.text-fd-muted-foreground { +#nd-page.openapi-page span.font-medium.font-mono.text-fd-primary > span.text-fd-muted-foreground { display: none; } /* Hide the auth scheme type label (e.g. "apiKey") next to Authorization heading */ -#nd-page:has(.api-page-header) .flex.items-start.justify-between.gap-2 > div.not-prose { +#nd-page.openapi-page .flex.items-start.justify-between.gap-2 > div.not-prose { display: none !important; } @@ -1045,13 +1032,13 @@ html.dark Auth properties use my-4 (vs py-4 for regular properties). */ /* Auth property flex row — name: order 1, type: order 2, ::before "header": order 3, ::after "required": order 4 */ -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.font-medium.font-mono.text-fd-primary { order: 1; } -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { @@ -1061,7 +1048,7 @@ html.dark background: none !important; line-height: 0; } -#nd-page:has(.api-page-header) +#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground::after { @@ -1078,7 +1065,7 @@ html.dark align-items: center; } html.dark - #nd-page:has(.api-page-header) + #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground::after { @@ -1087,7 +1074,7 @@ html.dark } /* "header" badge via ::before on the auth flex row */ -#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { +#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { content: "header"; order: 3; display: inline-flex; @@ -1101,16 +1088,13 @@ html.dark font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark - #nd-page:has(.api-page-header) - div.my-4 - > .flex.flex-wrap.items-center.gap-3.not-prose::before { +html.dark #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { background-color: rgb(51 51 56); color: rgb(212 212 220); } /* "required" badge via ::after on the auth flex row — red pill */ -#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { +#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { content: "required"; order: 4; display: inline-flex; @@ -1124,16 +1108,13 @@ html.dark font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark - #nd-page:has(.api-page-header) - div.my-4 - > .flex.flex-wrap.items-center.gap-3.not-prose::after { +html.dark #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { background-color: rgb(153 27 27 / 0.3); color: rgb(252 165 165); } /* Hide "In: header" text below auth property — redundant with the header badge */ -#nd-page:has(.api-page-header) div.my-4 .prose-no-margin p:has(> code) { +#nd-page.openapi-page div.my-4 .prose-no-margin p:has(> code) { display: none !important; } @@ -1148,27 +1129,27 @@ html.dark .api-section-divider { /* Property rows — breathing room like Mintlify. Regular properties use border-t py-4; auth properties use border-t my-4. */ -#nd-page:has(.api-page-header) .text-sm.border-t.py-4 { +#nd-page.openapi-page .text-sm.border-t.py-4 { padding-top: 1.25rem !important; padding-bottom: 1.25rem !important; } -#nd-page:has(.api-page-header) .text-sm.border-t.my-4 { +#nd-page.openapi-page .text-sm.border-t.my-4 { margin-top: 1.25rem !important; margin-bottom: 1.25rem !important; padding-top: 1.25rem; } /* Divider lines between fields — very subtle like Mintlify */ -#nd-page:has(.api-page-header) .text-sm.border-t { +#nd-page.openapi-page .text-sm.border-t { border-color: rgb(229 231 235 / 0.6); } -html.dark #nd-page:has(.api-page-header) .text-sm.border-t { +html.dark #nd-page.openapi-page .text-sm.border-t { border-color: rgb(255 255 255 / 0.07); } /* Body/Callback section "application/json" label — remove inline code styling */ -#nd-page:has(.api-page-header) .flex.gap-2.items-center.justify-between p.not-prose code.text-xs, -#nd-page:has(.api-page-header) .flex.justify-between.gap-2.items-end p.not-prose code.text-xs { +#nd-page.openapi-page .flex.gap-2.items-center.justify-between p.not-prose code.text-xs, +#nd-page.openapi-page .flex.justify-between.gap-2.items-end p.not-prose code.text-xs { background: none !important; border: none !important; padding: 0 !important; @@ -1178,8 +1159,8 @@ html.dark #nd-page:has(.api-page-header) .text-sm.border-t { } /* Object/array type triggers in property rows — order 2 + badge chip styling */ -#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > button, -#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > button, +#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { order: 2; background-color: rgb(241 245 249); color: rgb(71 85 105); @@ -1190,27 +1171,24 @@ html.dark #nd-page:has(.api-page-header) .text-sm.border-t { font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark #nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > button, -html.dark - #nd-page:has(.api-page-header) - .flex.flex-wrap.items-center.gap-3.not-prose - > span:has(> button) { +html.dark #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > button, +html.dark #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { background-color: rgb(51 51 56); color: rgb(212 212 220); } /* Section headings (Authorization, Path Parameters, etc.) — consistent top spacing */ -#nd-page:has(.api-page-header) .min-w-0.flex-1 h2 { +#nd-page.openapi-page .min-w-0.flex-1 h2 { margin-top: 1.75rem !important; margin-bottom: 0.25rem !important; } /* Code examples in right column — wrap long lines instead of horizontal scroll */ -#nd-page:has(.api-page-header) pre { +#nd-page.openapi-page pre { white-space: pre-wrap !important; word-break: break-all !important; } -#nd-page:has(.api-page-header) pre code { +#nd-page.openapi-page pre code { width: 100% !important; word-break: break-all !important; overflow-wrap: break-word !important; @@ -1226,11 +1204,11 @@ html.dark /* Footer navigation — constrain to left content column on OpenAPI pages only. Target pages that contain the two-column layout via :has() selector. */ -#nd-page:has(.api-page-header) > div:last-child { +#nd-page.openapi-page > div:last-child { max-width: calc(100% - 400px - 1.5rem); } @media (max-width: 1024px) { - #nd-page:has(.api-page-header) > div:last-child { + #nd-page.openapi-page > div:last-child { max-width: 100%; } } From 5d0b4e9817637572221e514d03d90d18d0873277 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Mar 2026 00:10:39 -0700 Subject: [PATCH 5/7] fix(docs): bypass TypeScript check for className prop on DocsPage Use spread with type assertion to pass className to DocsPage, working around a CI type resolution issue where the prop exists at runtime but is not recognized by TypeScript in the Vercel build environment. Co-Authored-By: Claude Opus 4.6 --- apps/docs/app/[lang]/[[...slug]]/page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/docs/app/[lang]/[[...slug]]/page.tsx b/apps/docs/app/[lang]/[[...slug]]/page.tsx index e8f330ee523..8d0484f72b1 100644 --- a/apps/docs/app/[lang]/[[...slug]]/page.tsx +++ b/apps/docs/app/[lang]/[[...slug]]/page.tsx @@ -235,7 +235,7 @@ export default async function Page(props: { params: Promise<{ slug?: string[]; l /> )} breadcrumb={{ enabled: false, }} From d6573bfc13bfd025799f53460c70c0968618bbb3 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Mar 2026 00:17:21 -0700 Subject: [PATCH 6/7] fix(docs): use inline style tag for grid layout, revert CSS to :has() selectors The className prop on DocsPage doesn't exist in the fumadocs-ui version resolved on Vercel, so .openapi-page was never applied and all 64 CSS rules broke. Revert to :has(.api-page-header) selectors for styling and use an inline )} breadcrumb={{ enabled: false, }} diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css index 004628e7f16..4aec712845d 100644 --- a/apps/docs/app/global.css +++ b/apps/docs/app/global.css @@ -555,13 +555,13 @@ video { The grid has columns: spacer | sidebar | main | toc | spacer. By spanning columns 3-4, the article fills both main and toc areas, while the grid structure stays identical to non-OpenAPI pages (no jitter). */ -#nd-page.openapi-page { +#nd-page:has(.api-page-header) { grid-column: 3 / span 2 !important; max-width: 1400px !important; } /* Hide the empty TOC aside on OpenAPI pages so it doesn't overlay content */ -#nd-docs-layout:has(#nd-page.openapi-page) #nd-toc { +#nd-docs-layout:has(#nd-page:has(.api-page-header)) #nd-toc { display: none; } @@ -577,15 +577,15 @@ video { } /* Ensure API reference pages use the same font as the rest of the docs */ -#nd-page.openapi-page, -#nd-page.openapi-page h2, -#nd-page.openapi-page h3, -#nd-page.openapi-page h4, -#nd-page.openapi-page p, -#nd-page.openapi-page span, -#nd-page.openapi-page div, -#nd-page.openapi-page label, -#nd-page.openapi-page button { +#nd-page:has(.api-page-header), +#nd-page:has(.api-page-header) h2, +#nd-page:has(.api-page-header) h3, +#nd-page:has(.api-page-header) h4, +#nd-page:has(.api-page-header) p, +#nd-page:has(.api-page-header) span, +#nd-page:has(.api-page-header) div, +#nd-page:has(.api-page-header) label, +#nd-page:has(.api-page-header) button { font-family: var(--font-geist-sans), ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; } @@ -647,7 +647,7 @@ html.dark span.font-mono.font-medium[data-method="delete"] { } /* Code block containers — match regular docs styling */ -#nd-page.openapi-page figure.shiki { +#nd-page:has(.api-page-header) figure.shiki { border-radius: 0.75rem !important; background-color: var(--color-fd-card) !important; } @@ -665,10 +665,10 @@ div:has(> input[placeholder="Filter Properties"]) + .text-sm.border-t { } /* Hide "TypeScript Definitions" copy panel on API pages */ -#nd-page.openapi-page div.not-prose.rounded-xl.border.p-3.mb-4 { +#nd-page:has(.api-page-header) div.not-prose.rounded-xl.border.p-3.mb-4 { display: none !important; } -#nd-page.openapi-page div.not-prose.rounded-xl.border.p-3:has(> div > p.font-medium) { +#nd-page:has(.api-page-header) div.not-prose.rounded-xl.border.p-3:has(> div > p.font-medium) { display: none !important; } @@ -682,18 +682,18 @@ div.flex.flex-row.items-start.bg-fd-secondary.border.rounded-lg.text-xs { /* Method+path bar — cleaner, lighter styling like Gumloop. Override bg-fd-card CSS variable directly for reliability. */ -#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose { +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose { --color-fd-card: rgb(249 250 251) !important; background-color: rgb(249 250 251) !important; border-color: rgb(229 231 235) !important; } -html.dark #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose { +html.dark #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose { --color-fd-card: rgb(24 24 27) !important; background-color: rgb(24 24 27) !important; border-color: rgb(63 63 70) !important; } /* Method badge inside path bar — cleaner sans-serif, softer colors */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium { font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif !important; @@ -706,70 +706,70 @@ html.dark #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border } /* Path bar per-method colors (fumadocs renders these, so we match by class) */ /* GET */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-green"] { color: rgb(22 163 74) !important; background-color: rgb(220 252 231 / 0.7) !important; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-green"] { color: rgb(74 222 128) !important; background-color: rgb(34 197 94 / 0.15) !important; } /* POST */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-blue"] { color: rgb(37 99 235) !important; background-color: rgb(219 234 254 / 0.7) !important; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-blue"] { color: rgb(96 165 250) !important; background-color: rgb(59 130 246 / 0.15) !important; } /* PUT */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-yellow"] { color: rgb(161 98 7) !important; background-color: rgb(254 249 195 / 0.7) !important; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-yellow"] { color: rgb(250 204 21) !important; background-color: rgb(234 179 8 / 0.15) !important; } /* PATCH */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-orange"] { color: rgb(194 65 12) !important; background-color: rgb(255 237 213 / 0.7) !important; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-orange"] { color: rgb(251 146 60) !important; background-color: rgb(249 115 22 / 0.15) !important; } /* DELETE */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-red"] { color: rgb(185 28 28) !important; background-color: rgb(254 226 226 / 0.7) !important; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose span.font-mono.font-medium[class*="text-red"] { color: rgb(248 113 113) !important; @@ -777,23 +777,23 @@ html.dark } /* Path text inside method+path bar — monospace, bright like Gumloop */ -#nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose code { +#nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose code { color: rgb(55 65 81) !important; background: none !important; border: none !important; padding: 0 !important; font-size: 0.8125rem !important; } -html.dark #nd-page.openapi-page div.flex.flex-row.items-center.rounded-xl.border.not-prose code { +html.dark #nd-page:has(.api-page-header) div.flex.flex-row.items-center.rounded-xl.border.not-prose code { color: rgb(229 231 235) !important; } /* Inline code in API pages — neutral color instead of red. Exclude code inside the method+path bar (handled above). */ -#nd-page.openapi-page .prose :not(pre) > code { +#nd-page:has(.api-page-header) .prose :not(pre) > code { color: rgb(79 70 229) !important; } -html.dark #nd-page.openapi-page .prose :not(pre) > code { +html.dark #nd-page:has(.api-page-header) .prose :not(pre) > code { color: rgb(165 180 252) !important; } @@ -956,21 +956,21 @@ html.dark .response-section-dropdown-item:hover { } /* Property row — reorder: name (1) → type badge (2) → required badge (3) */ -#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose { +#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose { display: flex; flex-wrap: wrap; align-items: center; } /* Name span — order 1 */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span.font-medium.font-mono.text-fd-primary { order: 1; } /* Type badge — order 2, grey pill */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { order: 2; @@ -984,7 +984,7 @@ html.dark .response-section-dropdown-item:hover { font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { background-color: rgb(51 51 56); @@ -992,12 +992,12 @@ html.dark } /* Hide the "*" inside the name span — we'll add "required" as a ::after on the flex row */ -#nd-page.openapi-page span.font-medium.font-mono.text-fd-primary > span.text-red-400 { +#nd-page:has(.api-page-header) span.font-medium.font-mono.text-fd-primary > span.text-red-400 { display: none; } /* Required badge — order 3, red pill */ -#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { +#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { content: "required"; order: 3; display: inline-flex; @@ -1012,19 +1012,19 @@ html.dark font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose:has(span.text-red-400)::after { background-color: rgb(153 27 27 / 0.3); color: rgb(252 165 165); } /* Optional "?" indicator — hide it */ -#nd-page.openapi-page span.font-medium.font-mono.text-fd-primary > span.text-fd-muted-foreground { +#nd-page:has(.api-page-header) span.font-medium.font-mono.text-fd-primary > span.text-fd-muted-foreground { display: none; } /* Hide the auth scheme type label (e.g. "apiKey") next to Authorization heading */ -#nd-page.openapi-page .flex.items-start.justify-between.gap-2 > div.not-prose { +#nd-page:has(.api-page-header) .flex.items-start.justify-between.gap-2 > div.not-prose { display: none !important; } @@ -1032,13 +1032,13 @@ html.dark Auth properties use my-4 (vs py-4 for regular properties). */ /* Auth property flex row — name: order 1, type: order 2, ::before "header": order 3, ::after "required": order 4 */ -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.font-medium.font-mono.text-fd-primary { order: 1; } -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground { @@ -1048,7 +1048,7 @@ html.dark background: none !important; line-height: 0; } -#nd-page.openapi-page +#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground::after { @@ -1065,7 +1065,7 @@ html.dark align-items: center; } html.dark - #nd-page.openapi-page + #nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose > span.text-sm.font-mono.text-fd-muted-foreground::after { @@ -1074,7 +1074,7 @@ html.dark } /* "header" badge via ::before on the auth flex row */ -#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { +#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { content: "header"; order: 3; display: inline-flex; @@ -1088,13 +1088,13 @@ html.dark font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { +html.dark #nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::before { background-color: rgb(51 51 56); color: rgb(212 212 220); } /* "required" badge via ::after on the auth flex row — red pill */ -#nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { +#nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { content: "required"; order: 4; display: inline-flex; @@ -1108,13 +1108,13 @@ html.dark #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.no font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark #nd-page.openapi-page div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { +html.dark #nd-page:has(.api-page-header) div.my-4 > .flex.flex-wrap.items-center.gap-3.not-prose::after { background-color: rgb(153 27 27 / 0.3); color: rgb(252 165 165); } /* Hide "In: header" text below auth property — redundant with the header badge */ -#nd-page.openapi-page div.my-4 .prose-no-margin p:has(> code) { +#nd-page:has(.api-page-header) div.my-4 .prose-no-margin p:has(> code) { display: none !important; } @@ -1129,27 +1129,27 @@ html.dark .api-section-divider { /* Property rows — breathing room like Mintlify. Regular properties use border-t py-4; auth properties use border-t my-4. */ -#nd-page.openapi-page .text-sm.border-t.py-4 { +#nd-page:has(.api-page-header) .text-sm.border-t.py-4 { padding-top: 1.25rem !important; padding-bottom: 1.25rem !important; } -#nd-page.openapi-page .text-sm.border-t.my-4 { +#nd-page:has(.api-page-header) .text-sm.border-t.my-4 { margin-top: 1.25rem !important; margin-bottom: 1.25rem !important; padding-top: 1.25rem; } /* Divider lines between fields — very subtle like Mintlify */ -#nd-page.openapi-page .text-sm.border-t { +#nd-page:has(.api-page-header) .text-sm.border-t { border-color: rgb(229 231 235 / 0.6); } -html.dark #nd-page.openapi-page .text-sm.border-t { +html.dark #nd-page:has(.api-page-header) .text-sm.border-t { border-color: rgb(255 255 255 / 0.07); } /* Body/Callback section "application/json" label — remove inline code styling */ -#nd-page.openapi-page .flex.gap-2.items-center.justify-between p.not-prose code.text-xs, -#nd-page.openapi-page .flex.justify-between.gap-2.items-end p.not-prose code.text-xs { +#nd-page:has(.api-page-header) .flex.gap-2.items-center.justify-between p.not-prose code.text-xs, +#nd-page:has(.api-page-header) .flex.justify-between.gap-2.items-end p.not-prose code.text-xs { background: none !important; border: none !important; padding: 0 !important; @@ -1159,8 +1159,8 @@ html.dark #nd-page.openapi-page .text-sm.border-t { } /* Object/array type triggers in property rows — order 2 + badge chip styling */ -#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > button, -#nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { +#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > button, +#nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { order: 2; background-color: rgb(241 245 249); color: rgb(71 85 105); @@ -1171,24 +1171,24 @@ html.dark #nd-page.openapi-page .text-sm.border-t { font-weight: 500; font-family: var(--font-geist-sans), ui-sans-serif, system-ui, sans-serif; } -html.dark #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > button, -html.dark #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { +html.dark #nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > button, +html.dark #nd-page:has(.api-page-header) .flex.flex-wrap.items-center.gap-3.not-prose > span:has(> button) { background-color: rgb(51 51 56); color: rgb(212 212 220); } /* Section headings (Authorization, Path Parameters, etc.) — consistent top spacing */ -#nd-page.openapi-page .min-w-0.flex-1 h2 { +#nd-page:has(.api-page-header) .min-w-0.flex-1 h2 { margin-top: 1.75rem !important; margin-bottom: 0.25rem !important; } /* Code examples in right column — wrap long lines instead of horizontal scroll */ -#nd-page.openapi-page pre { +#nd-page:has(.api-page-header) pre { white-space: pre-wrap !important; word-break: break-all !important; } -#nd-page.openapi-page pre code { +#nd-page:has(.api-page-header) pre code { width: 100% !important; word-break: break-all !important; overflow-wrap: break-word !important; @@ -1204,11 +1204,11 @@ html.dark #nd-page.openapi-page .flex.flex-wrap.items-center.gap-3.not-prose > s /* Footer navigation — constrain to left content column on OpenAPI pages only. Target pages that contain the two-column layout via :has() selector. */ -#nd-page.openapi-page > div:last-child { +#nd-page:has(.api-page-header) > div:last-child { max-width: calc(100% - 400px - 1.5rem); } @media (max-width: 1024px) { - #nd-page.openapi-page > div:last-child { + #nd-page:has(.api-page-header) > div:last-child { max-width: 100%; } } From cd625163b540b02b7354a6cba2ff6020979ad0a9 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Mon, 9 Mar 2026 00:19:06 -0700 Subject: [PATCH 7/7] fix(docs): add pill styling to footer navigation method badges The footer nav badges (POST, GET, etc.) had color from data-method rules but lacked the structural pill styling (padding, border-radius, font-size). Co-Authored-By: Claude Opus 4.6 --- apps/docs/app/global.css | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/apps/docs/app/global.css b/apps/docs/app/global.css index 4aec712845d..93b2bdf28d0 100644 --- a/apps/docs/app/global.css +++ b/apps/docs/app/global.css @@ -646,6 +646,17 @@ html.dark span.font-mono.font-medium[data-method="delete"] { flex-shrink: 0; } +/* Footer navigation method badges — pill styling to match sidebar */ +#nd-page span.font-mono.font-medium[data-method] { + display: inline-flex; + align-items: center; + justify-content: center; + font-size: 0.625rem !important; + line-height: 1 !important; + padding: 0.15625rem 0.375rem; + border-radius: 0.1875rem; +} + /* Code block containers — match regular docs styling */ #nd-page:has(.api-page-header) figure.shiki { border-radius: 0.75rem !important;