From 870a8103f7a4ac432d0b6ee95d0c299bfcf3c6fd Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 09:50:34 -0500 Subject: [PATCH 01/23] Initial implementation --- assets/css/custom.css | 420 +++++++++++++++++++++++ content/en/building/reference/openapi.md | 10 + layouts/shortcodes/swagger.html | 32 ++ 3 files changed, 462 insertions(+) create mode 100644 content/en/building/reference/openapi.md create mode 100644 layouts/shortcodes/swagger.html diff --git a/assets/css/custom.css b/assets/css/custom.css index b7a2121ec0..4a6dc74e35 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -256,3 +256,423 @@ a.broken { border: 2px solid #f00; padding: 0.1em 0.2em; } + +/* ------------------------- + OpenAPI / Swagger UI +------------------------- */ + +#swagger-ui { + height: calc(100vh - var(--navbar-height)); + min-height: 600px; + width: 100%; + } + + /* Dark theme adaptations for Swagger UI */ + html[class~="dark"] .swagger-ui { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .info .title { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .info .description, + html[class~="dark"] .swagger-ui .info .description p { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .opblock .opblock-summary-description, + html[class~="dark"] .swagger-ui .opblock .opblock-summary-path, + html[class~="dark"] .swagger-ui .opblock-description-wrapper p { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .opblock-tag { + color: rgb(243 244 246); + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .parameter__name { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .parameter__type { + color: rgb(156 163 175); + } + + html[class~="dark"] .swagger-ui table thead tr td, + html[class~="dark"] .swagger-ui table thead tr th { + color: rgb(243 244 246); + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .model-title { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .prop-type { + color: rgb(156 163 175); + } + + html[class~="dark"] .swagger-ui .prop-name { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .response-col_status { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .response-col_description { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .renderedMarkdown p { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .markdown p, + html[class~="dark"] .swagger-ui .markdown pre { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model .property { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model .property-row { + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui textarea { + background-color: rgb(31 41 55); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui input[type=text], + html[class~="dark"] .swagger-ui input[type=password], + html[class~="dark"] .swagger-ui input[type=search], + html[class~="dark"] .swagger-ui input[type=email], + html[class~="dark"] .swagger-ui input[type=url] { + background-color: rgb(31 41 55); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .opblock .opblock-summary { + color: rgb(243 244 246); + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .opblock .opblock-summary .opblock-summary-method { + background: rgb(55 65 81); + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .opblock.opblock-get .opblock-summary-method { + background: rgb(34 197 94); + } + + html[class~="dark"] .swagger-ui .opblock.opblock-post .opblock-summary-method { + background: rgb(59 130 246); + } + + html[class~="dark"] .swagger-ui .opblock.opblock-put .opblock-summary-method { + background: rgb(245 158 11); + } + + html[class~="dark"] .swagger-ui .opblock.opblock-delete .opblock-summary-method { + background: rgb(239 68 68); + } + + html[class~="dark"] .swagger-ui .opblock.opblock-patch .opblock-summary-method { + background: rgb(168 85 247); + } + + html[class~="dark"] .swagger-ui .opblock .opblock-summary-path__deprecated { + color: rgb(156 163 175); + text-decoration: line-through; + } + + html[class~="dark"] .swagger-ui .opblock-body { + background: rgb(17 24 39); + } + + html[class~="dark"] .swagger-ui .opblock-description-wrapper p, + html[class~="dark"] .swagger-ui .opblock-external-docs-wrapper p { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .parameters-container { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .parameter-item { + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .parameter-item .parameter-item-content { + background: transparent; + } + + html[class~="dark"] .swagger-ui .responses-wrapper { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .response { + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .btn { + background: rgb(55 65 81); + color: rgb(243 244 246); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .btn:hover { + background: rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .btn.authorize { + background: rgb(59 130 246); + border-color: rgb(59 130 246); + } + + html[class~="dark"] .swagger-ui .btn.authorize:hover { + background: rgb(37 99 235); + } + + html[class~="dark"] .swagger-ui .btn.execute { + background: rgb(34 197 94); + border-color: rgb(34 197 94); + } + + html[class~="dark"] .swagger-ui .btn.execute:hover { + background: rgb(22 163 74); + } + + html[class~="dark"] .swagger-ui .btn.cancel { + background: rgb(239 68 68); + border-color: rgb(239 68 68); + } + + html[class~="dark"] .swagger-ui .btn.cancel:hover { + background: rgb(220 38 38); + } + + html[class~="dark"] .swagger-ui select { + background: rgb(31 41 55); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .curl-command { + background: rgb(17 24 39); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .copy-to-clipboard { + background: rgb(55 65 81); + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .copy-to-clipboard:hover { + background: rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .model-box { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .model-toggle { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model-toggle:hover { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .model-jump-to-path { + color: rgb(59 130 246); + } + + html[class~="dark"] .swagger-ui .model-jump-to-path:hover { + color: rgb(37 99 235); + } + + html[class~="dark"] .swagger-ui .auth-wrapper { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .auth-container .auth-wrapper h4 { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .auth-container .auth-wrapper .auth-btn-wrapper { + background: transparent; + } + + html[class~="dark"] .swagger-ui .scheme-container .schemes > label { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .loading-container .loading::after { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .topbar .download-url-wrapper input[type=text] { + background: rgb(31 41 55); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .topbar .download-url-wrapper .download-url-button { + background: rgb(55 65 81); + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .servers > label { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .servers > .servers-title { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .servers .server-url { + background: rgb(31 41 55); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .servers .server-description { + color: rgb(156 163 175); + } + + html[class~="dark"] .swagger-ui .filter-container { + background: rgb(31 41 55); + border-top: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .filter .operation-filter-input { + background: rgb(17 24 39); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .filter .operation-filter-input:focus { + border-color: rgb(59 130 246); + box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2); + } + + html[class~="dark"] .swagger-ui .filter .operation-filter-input::placeholder { + color: rgb(107 114 128); + } + + html[class~="dark"] .swagger-ui .errors-wrapper { + background: rgb(127 29 29); + border: 1px solid rgb(185 28 28); + color: rgb(254 226 226); + } + + html[class~="dark"] .swagger-ui .errors-wrapper .error-wrapper { + background: transparent; + } + + html[class~="dark"] .swagger-ui .global-server-container { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .global-server-container .servers-title { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .info .base-url { + color: rgb(156 163 175); + } + + html[class~="dark"] .swagger-ui .scheme-container { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .scheme-container .schemes-title { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .scheme-container select { + background: rgb(17 24 39); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .highlight-code { + background: rgb(17 24 39); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .highlight-code .hljs { + background: rgb(17 24 39); + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control svg { + fill: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .expand-operation svg, + html[class~="dark"] .swagger-ui .collapse-operation svg { + fill: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model-toggle::after { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model-box-control { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model-box-control svg { + fill: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .prop-toggle { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .prop-toggle svg { + fill: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui select { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23D1D5DB' d='m8 10.293 3.146-3.147.708.708L8 11.707 4.146 7.854l.708-.708L8 10.293z'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: right 16px center !important; + background-size: 14px 14px !important; + padding-right: 40px !important; + } + + html[class~="dark"] .swagger-ui .btn svg, + html[class~="dark"] .swagger-ui button svg { + fill: currentColor; + } + + html[class~="dark"] .swagger-ui .parameters-container .parameter-item .parameter-item-header .parameter-item-toggle svg { + fill: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .responses-wrapper .response-header .response-toggle svg { + fill: rgb(209 213 219); + } diff --git a/content/en/building/reference/openapi.md b/content/en/building/reference/openapi.md new file mode 100644 index 0000000000..65104d75cd --- /dev/null +++ b/content/en/building/reference/openapi.md @@ -0,0 +1,10 @@ +--- +title: "OpenAPI Documentation" +linkTitle: "OpenAPI" +weight: 2 +toc: false +description: > + Interactive API reference for the CHT generated from the OpenAPI specification +--- + +{{< swagger url="/openapi.json" >}} diff --git a/layouts/shortcodes/swagger.html b/layouts/shortcodes/swagger.html new file mode 100644 index 0000000000..d0f0379d07 --- /dev/null +++ b/layouts/shortcodes/swagger.html @@ -0,0 +1,32 @@ +{{- $url := .Get "url" | default "/openapi.json" -}} +{{- $filter := .Get "filter" | default "true" -}} +{{- $operationsSorter := .Get "operationsSorter" | default "alpha" -}} +{{- $tagsSorter := .Get "tagsSorter" | default "alpha" -}} +{{- $docExpansion := .Get "docExpansion" | default "list" -}} +{{- $id := .Get "id" | default "swagger-ui" -}} + + + + + + + +
+ + + + + From bc5da0357ea0bb17df08341ce730ed67d1beded7 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 09:53:40 -0500 Subject: [PATCH 02/23] Fix footer overlap --- assets/css/custom.css | 2 -- 1 file changed, 2 deletions(-) diff --git a/assets/css/custom.css b/assets/css/custom.css index 4a6dc74e35..19f0e06624 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -262,8 +262,6 @@ a.broken { ------------------------- */ #swagger-ui { - height: calc(100vh - var(--navbar-height)); - min-height: 600px; width: 100%; } From da82da27c98689322b8c95d95c0122f6847a0def Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 09:56:50 -0500 Subject: [PATCH 03/23] Move css to swagger file --- assets/css/custom.css | 418 -------------------------------- assets/css/swagger.css | 417 +++++++++++++++++++++++++++++++ layouts/shortcodes/swagger.html | 2 + 3 files changed, 419 insertions(+), 418 deletions(-) create mode 100644 assets/css/swagger.css diff --git a/assets/css/custom.css b/assets/css/custom.css index 19f0e06624..b7a2121ec0 100644 --- a/assets/css/custom.css +++ b/assets/css/custom.css @@ -256,421 +256,3 @@ a.broken { border: 2px solid #f00; padding: 0.1em 0.2em; } - -/* ------------------------- - OpenAPI / Swagger UI -------------------------- */ - -#swagger-ui { - width: 100%; - } - - /* Dark theme adaptations for Swagger UI */ - html[class~="dark"] .swagger-ui { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .info .title { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .info .description, - html[class~="dark"] .swagger-ui .info .description p { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .opblock .opblock-summary-description, - html[class~="dark"] .swagger-ui .opblock .opblock-summary-path, - html[class~="dark"] .swagger-ui .opblock-description-wrapper p { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .opblock-tag { - color: rgb(243 244 246); - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .parameter__name { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .parameter__type { - color: rgb(156 163 175); - } - - html[class~="dark"] .swagger-ui table thead tr td, - html[class~="dark"] .swagger-ui table thead tr th { - color: rgb(243 244 246); - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .model-title { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .prop-type { - color: rgb(156 163 175); - } - - html[class~="dark"] .swagger-ui .prop-name { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .response-col_status { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .response-col_description { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .renderedMarkdown p { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .markdown p, - html[class~="dark"] .swagger-ui .markdown pre { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model .property { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model .property-row { - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui textarea { - background-color: rgb(31 41 55); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui input[type=text], - html[class~="dark"] .swagger-ui input[type=password], - html[class~="dark"] .swagger-ui input[type=search], - html[class~="dark"] .swagger-ui input[type=email], - html[class~="dark"] .swagger-ui input[type=url] { - background-color: rgb(31 41 55); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .opblock .opblock-summary { - color: rgb(243 244 246); - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .opblock .opblock-summary .opblock-summary-method { - background: rgb(55 65 81); - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .opblock.opblock-get .opblock-summary-method { - background: rgb(34 197 94); - } - - html[class~="dark"] .swagger-ui .opblock.opblock-post .opblock-summary-method { - background: rgb(59 130 246); - } - - html[class~="dark"] .swagger-ui .opblock.opblock-put .opblock-summary-method { - background: rgb(245 158 11); - } - - html[class~="dark"] .swagger-ui .opblock.opblock-delete .opblock-summary-method { - background: rgb(239 68 68); - } - - html[class~="dark"] .swagger-ui .opblock.opblock-patch .opblock-summary-method { - background: rgb(168 85 247); - } - - html[class~="dark"] .swagger-ui .opblock .opblock-summary-path__deprecated { - color: rgb(156 163 175); - text-decoration: line-through; - } - - html[class~="dark"] .swagger-ui .opblock-body { - background: rgb(17 24 39); - } - - html[class~="dark"] .swagger-ui .opblock-description-wrapper p, - html[class~="dark"] .swagger-ui .opblock-external-docs-wrapper p { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .parameters-container { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .parameter-item { - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .parameter-item .parameter-item-content { - background: transparent; - } - - html[class~="dark"] .swagger-ui .responses-wrapper { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .response { - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .btn { - background: rgb(55 65 81); - color: rgb(243 244 246); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .btn:hover { - background: rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .btn.authorize { - background: rgb(59 130 246); - border-color: rgb(59 130 246); - } - - html[class~="dark"] .swagger-ui .btn.authorize:hover { - background: rgb(37 99 235); - } - - html[class~="dark"] .swagger-ui .btn.execute { - background: rgb(34 197 94); - border-color: rgb(34 197 94); - } - - html[class~="dark"] .swagger-ui .btn.execute:hover { - background: rgb(22 163 74); - } - - html[class~="dark"] .swagger-ui .btn.cancel { - background: rgb(239 68 68); - border-color: rgb(239 68 68); - } - - html[class~="dark"] .swagger-ui .btn.cancel:hover { - background: rgb(220 38 38); - } - - html[class~="dark"] .swagger-ui select { - background: rgb(31 41 55); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .curl-command { - background: rgb(17 24 39); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .copy-to-clipboard { - background: rgb(55 65 81); - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .copy-to-clipboard:hover { - background: rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .model-box { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .model-toggle { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model-toggle:hover { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .model-jump-to-path { - color: rgb(59 130 246); - } - - html[class~="dark"] .swagger-ui .model-jump-to-path:hover { - color: rgb(37 99 235); - } - - html[class~="dark"] .swagger-ui .auth-wrapper { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .auth-container .auth-wrapper h4 { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .auth-container .auth-wrapper .auth-btn-wrapper { - background: transparent; - } - - html[class~="dark"] .swagger-ui .scheme-container .schemes > label { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .loading-container .loading::after { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .topbar .download-url-wrapper input[type=text] { - background: rgb(31 41 55); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .topbar .download-url-wrapper .download-url-button { - background: rgb(55 65 81); - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .servers > label { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .servers > .servers-title { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .servers .server-url { - background: rgb(31 41 55); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .servers .server-description { - color: rgb(156 163 175); - } - - html[class~="dark"] .swagger-ui .filter-container { - background: rgb(31 41 55); - border-top: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .filter .operation-filter-input { - background: rgb(17 24 39); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .filter .operation-filter-input:focus { - border-color: rgb(59 130 246); - box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2); - } - - html[class~="dark"] .swagger-ui .filter .operation-filter-input::placeholder { - color: rgb(107 114 128); - } - - html[class~="dark"] .swagger-ui .errors-wrapper { - background: rgb(127 29 29); - border: 1px solid rgb(185 28 28); - color: rgb(254 226 226); - } - - html[class~="dark"] .swagger-ui .errors-wrapper .error-wrapper { - background: transparent; - } - - html[class~="dark"] .swagger-ui .global-server-container { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .global-server-container .servers-title { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .info .base-url { - color: rgb(156 163 175); - } - - html[class~="dark"] .swagger-ui .scheme-container { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .scheme-container .schemes-title { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .scheme-container select { - background: rgb(17 24 39); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .highlight-code { - background: rgb(17 24 39); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .highlight-code .hljs { - background: rgb(17 24 39); - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control svg { - fill: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .expand-operation svg, - html[class~="dark"] .swagger-ui .collapse-operation svg { - fill: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model-toggle::after { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model-box-control { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model-box-control svg { - fill: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .prop-toggle { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .prop-toggle svg { - fill: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui select { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23D1D5DB' d='m8 10.293 3.146-3.147.708.708L8 11.707 4.146 7.854l.708-.708L8 10.293z'/%3E%3C/svg%3E") !important; - background-repeat: no-repeat !important; - background-position: right 16px center !important; - background-size: 14px 14px !important; - padding-right: 40px !important; - } - - html[class~="dark"] .swagger-ui .btn svg, - html[class~="dark"] .swagger-ui button svg { - fill: currentColor; - } - - html[class~="dark"] .swagger-ui .parameters-container .parameter-item .parameter-item-header .parameter-item-toggle svg { - fill: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .responses-wrapper .response-header .response-toggle svg { - fill: rgb(209 213 219); - } diff --git a/assets/css/swagger.css b/assets/css/swagger.css new file mode 100644 index 0000000000..6bcf657296 --- /dev/null +++ b/assets/css/swagger.css @@ -0,0 +1,417 @@ +/* ------------------------- + OpenAPI / Swagger UI +------------------------- */ + +#swagger-ui { + width: 100%; + } + + /* Dark theme adaptations for Swagger UI */ + html[class~="dark"] .swagger-ui { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .info .title { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .info .description, + html[class~="dark"] .swagger-ui .info .description p { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .opblock .opblock-summary-description, + html[class~="dark"] .swagger-ui .opblock .opblock-summary-path, + html[class~="dark"] .swagger-ui .opblock-description-wrapper p { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .opblock-tag { + color: rgb(243 244 246); + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .parameter__name { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .parameter__type { + color: rgb(156 163 175); + } + + html[class~="dark"] .swagger-ui table thead tr td, + html[class~="dark"] .swagger-ui table thead tr th { + color: rgb(243 244 246); + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .model-title { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .prop-type { + color: rgb(156 163 175); + } + + html[class~="dark"] .swagger-ui .prop-name { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .response-col_status { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .response-col_description { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .renderedMarkdown p { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .markdown p, + html[class~="dark"] .swagger-ui .markdown pre { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model .property { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model .property-row { + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui textarea { + background-color: rgb(31 41 55); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui input[type=text], + html[class~="dark"] .swagger-ui input[type=password], + html[class~="dark"] .swagger-ui input[type=search], + html[class~="dark"] .swagger-ui input[type=email], + html[class~="dark"] .swagger-ui input[type=url] { + background-color: rgb(31 41 55); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .opblock .opblock-summary { + color: rgb(243 244 246); + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .opblock .opblock-summary .opblock-summary-method { + background: rgb(55 65 81); + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .opblock.opblock-get .opblock-summary-method { + background: rgb(34 197 94); + } + + html[class~="dark"] .swagger-ui .opblock.opblock-post .opblock-summary-method { + background: rgb(59 130 246); + } + + html[class~="dark"] .swagger-ui .opblock.opblock-put .opblock-summary-method { + background: rgb(245 158 11); + } + + html[class~="dark"] .swagger-ui .opblock.opblock-delete .opblock-summary-method { + background: rgb(239 68 68); + } + + html[class~="dark"] .swagger-ui .opblock.opblock-patch .opblock-summary-method { + background: rgb(168 85 247); + } + + html[class~="dark"] .swagger-ui .opblock .opblock-summary-path__deprecated { + color: rgb(156 163 175); + text-decoration: line-through; + } + + html[class~="dark"] .swagger-ui .opblock-body { + background: rgb(17 24 39); + } + + html[class~="dark"] .swagger-ui .opblock-description-wrapper p, + html[class~="dark"] .swagger-ui .opblock-external-docs-wrapper p { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .parameters-container { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .parameter-item { + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .parameter-item .parameter-item-content { + background: transparent; + } + + html[class~="dark"] .swagger-ui .responses-wrapper { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .response { + border-bottom: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .btn { + background: rgb(55 65 81); + color: rgb(243 244 246); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .btn:hover { + background: rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .btn.authorize { + background: rgb(59 130 246); + border-color: rgb(59 130 246); + } + + html[class~="dark"] .swagger-ui .btn.authorize:hover { + background: rgb(37 99 235); + } + + html[class~="dark"] .swagger-ui .btn.execute { + background: rgb(34 197 94); + border-color: rgb(34 197 94); + } + + html[class~="dark"] .swagger-ui .btn.execute:hover { + background: rgb(22 163 74); + } + + html[class~="dark"] .swagger-ui .btn.cancel { + background: rgb(239 68 68); + border-color: rgb(239 68 68); + } + + html[class~="dark"] .swagger-ui .btn.cancel:hover { + background: rgb(220 38 38); + } + + html[class~="dark"] .swagger-ui select { + background: rgb(31 41 55); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .curl-command { + background: rgb(17 24 39); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .copy-to-clipboard { + background: rgb(55 65 81); + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .copy-to-clipboard:hover { + background: rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .model-box { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .model-toggle { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model-toggle:hover { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .model-jump-to-path { + color: rgb(59 130 246); + } + + html[class~="dark"] .swagger-ui .model-jump-to-path:hover { + color: rgb(37 99 235); + } + + html[class~="dark"] .swagger-ui .auth-wrapper { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .auth-container .auth-wrapper h4 { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .auth-container .auth-wrapper .auth-btn-wrapper { + background: transparent; + } + + html[class~="dark"] .swagger-ui .scheme-container .schemes > label { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .loading-container .loading::after { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .topbar .download-url-wrapper input[type=text] { + background: rgb(31 41 55); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .topbar .download-url-wrapper .download-url-button { + background: rgb(55 65 81); + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .servers > label { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .servers > .servers-title { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .servers .server-url { + background: rgb(31 41 55); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .servers .server-description { + color: rgb(156 163 175); + } + + html[class~="dark"] .swagger-ui .filter-container { + background: rgb(31 41 55); + border-top: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .filter .operation-filter-input { + background: rgb(17 24 39); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .filter .operation-filter-input:focus { + border-color: rgb(59 130 246); + box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2); + } + + html[class~="dark"] .swagger-ui .filter .operation-filter-input::placeholder { + color: rgb(107 114 128); + } + + html[class~="dark"] .swagger-ui .errors-wrapper { + background: rgb(127 29 29); + border: 1px solid rgb(185 28 28); + color: rgb(254 226 226); + } + + html[class~="dark"] .swagger-ui .errors-wrapper .error-wrapper { + background: transparent; + } + + html[class~="dark"] .swagger-ui .global-server-container { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .global-server-container .servers-title { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .info .base-url { + color: rgb(156 163 175); + } + + html[class~="dark"] .swagger-ui .scheme-container { + background: rgb(31 41 55); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .scheme-container .schemes-title { + color: rgb(243 244 246); + } + + html[class~="dark"] .swagger-ui .scheme-container select { + background: rgb(17 24 39); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .highlight-code { + background: rgb(17 24 39); + color: rgb(209 213 219); + border: 1px solid rgb(75 85 99); + } + + html[class~="dark"] .swagger-ui .highlight-code .hljs { + background: rgb(17 24 39); + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control svg { + fill: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .expand-operation svg, + html[class~="dark"] .swagger-ui .collapse-operation svg { + fill: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model-toggle::after { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model-box-control { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .model-box-control svg { + fill: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .prop-toggle { + color: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .prop-toggle svg { + fill: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui select { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23D1D5DB' d='m8 10.293 3.146-3.147.708.708L8 11.707 4.146 7.854l.708-.708L8 10.293z'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: right 16px center !important; + background-size: 14px 14px !important; + padding-right: 40px !important; + } + + html[class~="dark"] .swagger-ui .btn svg, + html[class~="dark"] .swagger-ui button svg { + fill: currentColor; + } + + html[class~="dark"] .swagger-ui .parameters-container .parameter-item .parameter-item-header .parameter-item-toggle svg { + fill: rgb(209 213 219); + } + + html[class~="dark"] .swagger-ui .responses-wrapper .response-header .response-toggle svg { + fill: rgb(209 213 219); + } diff --git a/layouts/shortcodes/swagger.html b/layouts/shortcodes/swagger.html index d0f0379d07..c6b9e2a314 100644 --- a/layouts/shortcodes/swagger.html +++ b/layouts/shortcodes/swagger.html @@ -10,6 +10,8 @@ +{{- $swaggerCss := resources.Get "css/swagger.css" -}} +
From dfcb8a067a2af6d6ab52c26572d6e7fb55eab04e Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 10:01:13 -0500 Subject: [PATCH 04/23] Hide "Try it out" --- layouts/shortcodes/swagger.html | 1 + 1 file changed, 1 insertion(+) diff --git a/layouts/shortcodes/swagger.html b/layouts/shortcodes/swagger.html index c6b9e2a314..2de18fbccc 100644 --- a/layouts/shortcodes/swagger.html +++ b/layouts/shortcodes/swagger.html @@ -29,6 +29,7 @@ tagsSorter: {{ $tagsSorter }}, docExpansion: {{ $docExpansion }}, deepLinking: true, + supportedSubmitMethods: [], }); }); From badc302f93ba2cf7019ec071809a93c9a62a1dd7 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 10:19:02 -0500 Subject: [PATCH 05/23] Improve dark theming --- assets/css/swagger.css | 991 +++++++++++++---------- content/en/building/reference/openapi.md | 2 - 2 files changed, 578 insertions(+), 415 deletions(-) diff --git a/assets/css/swagger.css b/assets/css/swagger.css index 6bcf657296..4bec164a33 100644 --- a/assets/css/swagger.css +++ b/assets/css/swagger.css @@ -1,417 +1,582 @@ /* ------------------------- - OpenAPI / Swagger UI + OpenAPI / Swagger UI ------------------------- */ #swagger-ui { - width: 100%; - } - - /* Dark theme adaptations for Swagger UI */ - html[class~="dark"] .swagger-ui { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .info .title { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .info .description, - html[class~="dark"] .swagger-ui .info .description p { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .opblock .opblock-summary-description, - html[class~="dark"] .swagger-ui .opblock .opblock-summary-path, - html[class~="dark"] .swagger-ui .opblock-description-wrapper p { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .opblock-tag { - color: rgb(243 244 246); - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .parameter__name { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .parameter__type { - color: rgb(156 163 175); - } - - html[class~="dark"] .swagger-ui table thead tr td, - html[class~="dark"] .swagger-ui table thead tr th { - color: rgb(243 244 246); - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .model-title { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .prop-type { - color: rgb(156 163 175); - } - - html[class~="dark"] .swagger-ui .prop-name { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .response-col_status { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .response-col_description { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .renderedMarkdown p { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .markdown p, - html[class~="dark"] .swagger-ui .markdown pre { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model .property { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model .property-row { - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui textarea { - background-color: rgb(31 41 55); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui input[type=text], - html[class~="dark"] .swagger-ui input[type=password], - html[class~="dark"] .swagger-ui input[type=search], - html[class~="dark"] .swagger-ui input[type=email], - html[class~="dark"] .swagger-ui input[type=url] { - background-color: rgb(31 41 55); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .opblock .opblock-summary { - color: rgb(243 244 246); - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .opblock .opblock-summary .opblock-summary-method { - background: rgb(55 65 81); - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .opblock.opblock-get .opblock-summary-method { - background: rgb(34 197 94); - } - - html[class~="dark"] .swagger-ui .opblock.opblock-post .opblock-summary-method { - background: rgb(59 130 246); - } - - html[class~="dark"] .swagger-ui .opblock.opblock-put .opblock-summary-method { - background: rgb(245 158 11); - } - - html[class~="dark"] .swagger-ui .opblock.opblock-delete .opblock-summary-method { - background: rgb(239 68 68); - } - - html[class~="dark"] .swagger-ui .opblock.opblock-patch .opblock-summary-method { - background: rgb(168 85 247); - } - - html[class~="dark"] .swagger-ui .opblock .opblock-summary-path__deprecated { - color: rgb(156 163 175); - text-decoration: line-through; - } - - html[class~="dark"] .swagger-ui .opblock-body { - background: rgb(17 24 39); - } - - html[class~="dark"] .swagger-ui .opblock-description-wrapper p, - html[class~="dark"] .swagger-ui .opblock-external-docs-wrapper p { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .parameters-container { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .parameter-item { - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .parameter-item .parameter-item-content { - background: transparent; - } - - html[class~="dark"] .swagger-ui .responses-wrapper { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .response { - border-bottom: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .btn { - background: rgb(55 65 81); - color: rgb(243 244 246); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .btn:hover { - background: rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .btn.authorize { - background: rgb(59 130 246); - border-color: rgb(59 130 246); - } - - html[class~="dark"] .swagger-ui .btn.authorize:hover { - background: rgb(37 99 235); - } - - html[class~="dark"] .swagger-ui .btn.execute { - background: rgb(34 197 94); - border-color: rgb(34 197 94); - } - - html[class~="dark"] .swagger-ui .btn.execute:hover { - background: rgb(22 163 74); - } - - html[class~="dark"] .swagger-ui .btn.cancel { - background: rgb(239 68 68); - border-color: rgb(239 68 68); - } - - html[class~="dark"] .swagger-ui .btn.cancel:hover { - background: rgb(220 38 38); - } - - html[class~="dark"] .swagger-ui select { - background: rgb(31 41 55); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .curl-command { - background: rgb(17 24 39); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .copy-to-clipboard { - background: rgb(55 65 81); - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .copy-to-clipboard:hover { - background: rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .model-box { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .model-toggle { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model-toggle:hover { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .model-jump-to-path { - color: rgb(59 130 246); - } - - html[class~="dark"] .swagger-ui .model-jump-to-path:hover { - color: rgb(37 99 235); - } - - html[class~="dark"] .swagger-ui .auth-wrapper { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .auth-container .auth-wrapper h4 { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .auth-container .auth-wrapper .auth-btn-wrapper { - background: transparent; - } - - html[class~="dark"] .swagger-ui .scheme-container .schemes > label { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .loading-container .loading::after { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .topbar .download-url-wrapper input[type=text] { - background: rgb(31 41 55); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .topbar .download-url-wrapper .download-url-button { - background: rgb(55 65 81); - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .servers > label { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .servers > .servers-title { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .servers .server-url { - background: rgb(31 41 55); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .servers .server-description { - color: rgb(156 163 175); - } - - html[class~="dark"] .swagger-ui .filter-container { - background: rgb(31 41 55); - border-top: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .filter .operation-filter-input { - background: rgb(17 24 39); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .filter .operation-filter-input:focus { - border-color: rgb(59 130 246); - box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.2); - } - - html[class~="dark"] .swagger-ui .filter .operation-filter-input::placeholder { - color: rgb(107 114 128); - } - - html[class~="dark"] .swagger-ui .errors-wrapper { - background: rgb(127 29 29); - border: 1px solid rgb(185 28 28); - color: rgb(254 226 226); - } - - html[class~="dark"] .swagger-ui .errors-wrapper .error-wrapper { - background: transparent; - } - - html[class~="dark"] .swagger-ui .global-server-container { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .global-server-container .servers-title { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .info .base-url { - color: rgb(156 163 175); - } - - html[class~="dark"] .swagger-ui .scheme-container { - background: rgb(31 41 55); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .scheme-container .schemes-title { - color: rgb(243 244 246); - } - - html[class~="dark"] .swagger-ui .scheme-container select { - background: rgb(17 24 39); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .highlight-code { - background: rgb(17 24 39); - color: rgb(209 213 219); - border: 1px solid rgb(75 85 99); - } - - html[class~="dark"] .swagger-ui .highlight-code .hljs { - background: rgb(17 24 39); - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control svg { - fill: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .expand-operation svg, - html[class~="dark"] .swagger-ui .collapse-operation svg { - fill: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model-toggle::after { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model-box-control { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .model-box-control svg { - fill: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .prop-toggle { - color: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .prop-toggle svg { - fill: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui select { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23D1D5DB' d='m8 10.293 3.146-3.147.708.708L8 11.707 4.146 7.854l.708-.708L8 10.293z'/%3E%3C/svg%3E") !important; - background-repeat: no-repeat !important; - background-position: right 16px center !important; - background-size: 14px 14px !important; - padding-right: 40px !important; - } - - html[class~="dark"] .swagger-ui .btn svg, - html[class~="dark"] .swagger-ui button svg { - fill: currentColor; - } - - html[class~="dark"] .swagger-ui .parameters-container .parameter-item .parameter-item-header .parameter-item-toggle svg { - fill: rgb(209 213 219); - } - - html[class~="dark"] .swagger-ui .responses-wrapper .response-header .response-toggle svg { - fill: rgb(209 213 219); - } + width: 100%; +} + +/* =========================================== + Dark theme — aligned to Hextra's palette + Hextra dark bg: #111, borders: #262626/#404040 + Text: #f3f4f6 (primary), #d1d5db (body), #9ca3af (muted) + =========================================== */ + +/* --- Base text & background --- */ + +html[class~="dark"] .swagger-ui { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .wrapper { + background: transparent; +} + +/* --- Info header --- */ + +html[class~="dark"] .swagger-ui .info .title { + color: #f3f4f6; +} + +html[class~="dark"] .swagger-ui .info .base-url { + color: #9ca3af; +} + +html[class~="dark"] .swagger-ui .info .description, +html[class~="dark"] .swagger-ui .info .description p { + color: #d1d5db; +} + +/* --- Tag groups --- */ + +html[class~="dark"] .swagger-ui .opblock-tag { + color: #f3f4f6; + border-bottom: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .opblock-tag:hover { + background: rgba(255, 255, 255, 0.03); +} + +/* --- Operation blocks (endpoints) --- */ + +html[class~="dark"] .swagger-ui .opblock { + background: #171717; + border-color: #262626; +} + +html[class~="dark"] .swagger-ui .opblock .opblock-summary { + border-bottom: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .opblock .opblock-summary-description, +html[class~="dark"] .swagger-ui .opblock .opblock-summary-path { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .opblock .opblock-summary-path__deprecated { + color: #9ca3af; + text-decoration: line-through; +} + +html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control svg { + fill: #d1d5db; +} + +/* HTTP method badges */ +html[class~="dark"] .swagger-ui .opblock .opblock-summary .opblock-summary-method { + background: #404040; + color: #f3f4f6; +} + +html[class~="dark"] .swagger-ui .opblock.opblock-get .opblock-summary-method { + background: #16a34a; +} + +html[class~="dark"] .swagger-ui .opblock.opblock-post .opblock-summary-method { + background: #2563eb; +} + +html[class~="dark"] .swagger-ui .opblock.opblock-put .opblock-summary-method { + background: #d97706; +} + +html[class~="dark"] .swagger-ui .opblock.opblock-delete .opblock-summary-method { + background: #dc2626; +} + +html[class~="dark"] .swagger-ui .opblock.opblock-patch .opblock-summary-method { + background: #9333ea; +} + +/* Tinted opblock backgrounds per method */ +html[class~="dark"] .swagger-ui .opblock.opblock-get { + background: rgba(22, 163, 74, 0.05); + border-color: rgba(22, 163, 74, 0.3); +} + +html[class~="dark"] .swagger-ui .opblock.opblock-post { + background: rgba(37, 99, 235, 0.05); + border-color: rgba(37, 99, 235, 0.3); +} + +html[class~="dark"] .swagger-ui .opblock.opblock-put { + background: rgba(217, 119, 6, 0.05); + border-color: rgba(217, 119, 6, 0.3); +} + +html[class~="dark"] .swagger-ui .opblock.opblock-delete { + background: rgba(220, 38, 38, 0.05); + border-color: rgba(220, 38, 38, 0.3); +} + +html[class~="dark"] .swagger-ui .opblock.opblock-patch { + background: rgba(147, 51, 234, 0.05); + border-color: rgba(147, 51, 234, 0.3); +} + +/* --- Expanded operation body --- */ + +html[class~="dark"] .swagger-ui .opblock-body { + background: #111; +} + +html[class~="dark"] .swagger-ui .opblock-body pre.microlight { + background: #0a0a0a !important; + color: #d1d5db !important; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .opblock-description-wrapper, +html[class~="dark"] .swagger-ui .opblock-external-docs-wrapper { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .opblock-description-wrapper p, +html[class~="dark"] .swagger-ui .opblock-external-docs-wrapper p { + color: #d1d5db; +} + +/* Section headers ("Parameters", "Request body", "Responses") */ +html[class~="dark"] .swagger-ui .opblock-section-header { + background: #1a1a1a; + border-bottom: 1px solid #262626; + box-shadow: none; +} + +html[class~="dark"] .swagger-ui .opblock-section-header h4, +html[class~="dark"] .swagger-ui .opblock-section-header label { + color: #f3f4f6; +} + +/* --- Parameters --- */ + +html[class~="dark"] .swagger-ui .parameters-container { + background: transparent; + border: none; +} + +html[class~="dark"] .swagger-ui .parameter__name { + color: #f3f4f6; +} + +html[class~="dark"] .swagger-ui .parameter__type { + color: #9ca3af; +} + +html[class~="dark"] .swagger-ui .parameter__in { + color: #9ca3af; +} + +/* --- Tables (parameters, responses) --- */ + +html[class~="dark"] .swagger-ui table thead tr td, +html[class~="dark"] .swagger-ui table thead tr th { + color: #f3f4f6; + border-bottom: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui table tbody tr td { + color: #d1d5db; + border-bottom: 1px solid #1a1a1a; +} + +html[class~="dark"] .swagger-ui .parameters col:last-child { + background: transparent; +} + +html[class~="dark"] .swagger-ui table.headers td { + color: #d1d5db; +} + +/* --- Responses --- */ + +html[class~="dark"] .swagger-ui .responses-wrapper { + background: transparent; + border: none; +} + +html[class~="dark"] .swagger-ui .responses-inner { + background: transparent; +} + +html[class~="dark"] .swagger-ui .response-col_status { + color: #f3f4f6; +} + +html[class~="dark"] .swagger-ui .response-col_description { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .response-col_links { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .response { + border-bottom: 1px solid #1a1a1a; +} + +html[class~="dark"] .swagger-ui .response-control-media-type__accept-message { + color: #9ca3af; +} + +/* --- Tabs (Example Value / Schema) --- */ + +html[class~="dark"] .swagger-ui .tab li { + color: #9ca3af; +} + +html[class~="dark"] .swagger-ui .tab li.active { + color: #f3f4f6; +} + +html[class~="dark"] .swagger-ui .tab li button.tablinks { + color: inherit; + background: transparent; +} + +/* --- Markdown / rendered content --- */ + +html[class~="dark"] .swagger-ui .renderedMarkdown p { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .markdown p, +html[class~="dark"] .swagger-ui .markdown pre { + color: #d1d5db; +} + +/* --- Models / Schemas --- */ + +html[class~="dark"] .swagger-ui .model-title { + color: #f3f4f6; +} + +html[class~="dark"] .swagger-ui .model { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .model .property { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .model .property-row { + border-bottom: 1px solid #1a1a1a; +} + +html[class~="dark"] .swagger-ui .prop-type { + color: #9ca3af; +} + +html[class~="dark"] .swagger-ui .prop-name { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .model-box { + background: #171717; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .model-toggle { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .model-toggle:hover { + color: #f3f4f6; +} + +html[class~="dark"] .swagger-ui .model-toggle::after { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .model-box-control { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .model-box-control svg { + fill: #d1d5db; +} + +html[class~="dark"] .swagger-ui .model-jump-to-path { + color: hsl(var(--primary-hue) var(--primary-saturation) var(--primary-lightness)); +} + +html[class~="dark"] .swagger-ui .model-jump-to-path:hover { + opacity: 0.8; +} + +html[class~="dark"] .swagger-ui section.models { + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui section.models h4 { + color: #f3f4f6; +} + +html[class~="dark"] .swagger-ui section.models .model-container { + background: #171717; + border-bottom: 1px solid #262626; +} + +/* --- Expand / collapse icons --- */ + +html[class~="dark"] .swagger-ui .expand-operation svg, +html[class~="dark"] .swagger-ui .collapse-operation svg { + fill: #d1d5db; +} + +html[class~="dark"] .swagger-ui .prop-toggle { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .prop-toggle svg { + fill: #d1d5db; +} + +/* --- Buttons --- */ + +html[class~="dark"] .swagger-ui .btn { + background: #262626; + color: #f3f4f6; + border: 1px solid #404040; +} + +html[class~="dark"] .swagger-ui .btn:hover { + background: #404040; +} + +html[class~="dark"] .swagger-ui .btn.authorize { + background: #2563eb; + border-color: #2563eb; + color: #fff; +} + +html[class~="dark"] .swagger-ui .btn.authorize:hover { + background: #1d4ed8; +} + +html[class~="dark"] .swagger-ui .btn.execute { + background: #16a34a; + border-color: #16a34a; + color: #fff; +} + +html[class~="dark"] .swagger-ui .btn.execute:hover { + background: #15803d; +} + +html[class~="dark"] .swagger-ui .btn.cancel { + background: #dc2626; + border-color: #dc2626; + color: #fff; +} + +html[class~="dark"] .swagger-ui .btn.cancel:hover { + background: #b91c1c; +} + +html[class~="dark"] .swagger-ui .btn svg, +html[class~="dark"] .swagger-ui button svg { + fill: currentColor; +} + +/* --- Form controls --- */ + +html[class~="dark"] .swagger-ui textarea { + background-color: #0a0a0a; + color: #d1d5db; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui input[type=text], +html[class~="dark"] .swagger-ui input[type=password], +html[class~="dark"] .swagger-ui input[type=search], +html[class~="dark"] .swagger-ui input[type=email], +html[class~="dark"] .swagger-ui input[type=url] { + background-color: #0a0a0a; + color: #d1d5db; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui select { + background: #0a0a0a; + color: #d1d5db; + border: 1px solid #262626; + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23D1D5DB' d='m8 10.293 3.146-3.147.708.708L8 11.707 4.146 7.854l.708-.708L8 10.293z'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: right 16px center !important; + background-size: 14px 14px !important; + padding-right: 40px !important; +} + +/* --- Code / highlight blocks --- */ + +html[class~="dark"] .swagger-ui .highlight-code { + background: #0a0a0a; + color: #d1d5db; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .highlight-code .hljs { + background: #0a0a0a; + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .curl-command { + background: #0a0a0a; + color: #d1d5db; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .copy-to-clipboard { + background: #262626; + color: #f3f4f6; +} + +html[class~="dark"] .swagger-ui .copy-to-clipboard:hover { + background: #404040; +} + +/* --- Scheme & server selectors --- */ + +html[class~="dark"] .swagger-ui .scheme-container { + background: #171717; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .scheme-container .schemes-title, +html[class~="dark"] .swagger-ui .scheme-container .schemes > label { + color: #d1d5db; +} + +html[class~="dark"] .swagger-ui .scheme-container select { + background: #0a0a0a; + color: #d1d5db; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .servers > label, +html[class~="dark"] .swagger-ui .servers > .servers-title { + color: #f3f4f6; +} + +html[class~="dark"] .swagger-ui .servers .server-url { + background: #0a0a0a; + color: #d1d5db; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .servers .server-description { + color: #9ca3af; +} + +html[class~="dark"] .swagger-ui .global-server-container { + background: #171717; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .global-server-container .servers-title { + color: #f3f4f6; +} + +/* --- Auth --- */ + +html[class~="dark"] .swagger-ui .auth-wrapper { + background: #171717; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .auth-container .auth-wrapper h4 { + color: #f3f4f6; +} + +html[class~="dark"] .swagger-ui .auth-container .auth-wrapper .auth-btn-wrapper { + background: transparent; +} + +/* --- Filter bar --- */ + +html[class~="dark"] .swagger-ui .filter-container { + background: #171717; + border-top: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .filter .operation-filter-input { + background: #0a0a0a; + color: #d1d5db; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .filter .operation-filter-input:focus { + border-color: hsl(var(--primary-hue) var(--primary-saturation) var(--primary-lightness)); + box-shadow: 0 0 0 2px hsla(var(--primary-hue) var(--primary-saturation) var(--primary-lightness) / 0.2); +} + +html[class~="dark"] .swagger-ui .filter .operation-filter-input::placeholder { + color: #6b7280; +} + +/* --- Download bar --- */ + +html[class~="dark"] .swagger-ui .topbar .download-url-wrapper input[type=text] { + background: #0a0a0a; + color: #d1d5db; + border: 1px solid #262626; +} + +html[class~="dark"] .swagger-ui .topbar .download-url-wrapper .download-url-button { + background: #262626; + color: #f3f4f6; +} + +/* --- Errors --- */ + +html[class~="dark"] .swagger-ui .errors-wrapper { + background: rgba(220, 38, 38, 0.1); + border: 1px solid rgba(220, 38, 38, 0.4); + color: #fca5a5; +} + +html[class~="dark"] .swagger-ui .errors-wrapper .error-wrapper { + background: transparent; +} + +/* --- Loading --- */ + +html[class~="dark"] .swagger-ui .loading-container .loading::after { + color: #d1d5db; +} + +/* --- SVG fills for interactive controls --- */ + +html[class~="dark"] .swagger-ui .parameters-container .parameter-item .parameter-item-header .parameter-item-toggle svg { + fill: #d1d5db; +} + +html[class~="dark"] .swagger-ui .responses-wrapper .response-header .response-toggle svg { + fill: #d1d5db; +} + +/* --- Links --- */ + +html[class~="dark"] .swagger-ui a { + color: hsl(var(--primary-hue) var(--primary-saturation) var(--primary-lightness)); +} + +html[class~="dark"] .swagger-ui a:hover { + opacity: 0.8; +} diff --git a/content/en/building/reference/openapi.md b/content/en/building/reference/openapi.md index 65104d75cd..f998bbd88f 100644 --- a/content/en/building/reference/openapi.md +++ b/content/en/building/reference/openapi.md @@ -3,8 +3,6 @@ title: "OpenAPI Documentation" linkTitle: "OpenAPI" weight: 2 toc: false -description: > - Interactive API reference for the CHT generated from the OpenAPI specification --- {{< swagger url="/openapi.json" >}} From d9827b00568726a03ee72930727339d13c2d9960 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 10:28:22 -0500 Subject: [PATCH 06/23] Simplify the css --- assets/css/swagger.css | 571 +++++++---------------------------------- 1 file changed, 93 insertions(+), 478 deletions(-) diff --git a/assets/css/swagger.css b/assets/css/swagger.css index 4bec164a33..b061eb4715 100644 --- a/assets/css/swagger.css +++ b/assets/css/swagger.css @@ -1,350 +1,156 @@ /* ------------------------- OpenAPI / Swagger UI + Hextra dark: #111 bg, neutral grays ------------------------- */ #swagger-ui { width: 100%; } -/* =========================================== - Dark theme — aligned to Hextra's palette - Hextra dark bg: #111, borders: #262626/#404040 - Text: #f3f4f6 (primary), #d1d5db (body), #9ca3af (muted) - =========================================== */ - -/* --- Base text & background --- */ +/* --- Base text --- */ html[class~="dark"] .swagger-ui { color: #d1d5db; } -html[class~="dark"] .swagger-ui .wrapper { - background: transparent; -} - -/* --- Info header --- */ - -html[class~="dark"] .swagger-ui .info .title { +/* Bright text — headings, labels, active tabs */ +html[class~="dark"] .swagger-ui .info .title, +html[class~="dark"] .swagger-ui .opblock-tag, +html[class~="dark"] .swagger-ui .opblock-section-header h4, +html[class~="dark"] .swagger-ui .opblock-section-header label, +html[class~="dark"] .swagger-ui .parameter__name, +html[class~="dark"] .swagger-ui .response-col_status, +html[class~="dark"] .swagger-ui .model-title, +html[class~="dark"] .swagger-ui table thead tr th, +html[class~="dark"] .swagger-ui table thead tr td, +html[class~="dark"] .swagger-ui section.models h4, +html[class~="dark"] .swagger-ui .tab li.active { color: #f3f4f6; } -html[class~="dark"] .swagger-ui .info .base-url { +/* Muted text — types, secondary info, inactive tabs */ +html[class~="dark"] .swagger-ui .info .base-url, +html[class~="dark"] .swagger-ui .parameter__type, +html[class~="dark"] .swagger-ui .parameter__in, +html[class~="dark"] .swagger-ui .prop-type, +html[class~="dark"] .swagger-ui .tab li { color: #9ca3af; } -html[class~="dark"] .swagger-ui .info .description, -html[class~="dark"] .swagger-ui .info .description p { +/* Body text — override Swagger's dark-on-light defaults */ +html[class~="dark"] .swagger-ui .opblock-summary-description, +html[class~="dark"] .swagger-ui .opblock-summary-path, +html[class~="dark"] .swagger-ui .opblock-description-wrapper p, +html[class~="dark"] .swagger-ui .renderedMarkdown p, +html[class~="dark"] .swagger-ui .markdown p, +html[class~="dark"] .swagger-ui .markdown pre, +html[class~="dark"] .swagger-ui .response-col_description, +html[class~="dark"] .swagger-ui .model, +html[class~="dark"] .swagger-ui table tbody tr td { color: #d1d5db; } -/* --- Tag groups --- */ - -html[class~="dark"] .swagger-ui .opblock-tag { - color: #f3f4f6; - border-bottom: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .opblock-tag:hover { - background: rgba(255, 255, 255, 0.03); -} - -/* --- Operation blocks (endpoints) --- */ +/* --- Backgrounds --- */ html[class~="dark"] .swagger-ui .opblock { background: #171717; border-color: #262626; } -html[class~="dark"] .swagger-ui .opblock .opblock-summary { - border-bottom: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .opblock .opblock-summary-description, -html[class~="dark"] .swagger-ui .opblock .opblock-summary-path { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .opblock .opblock-summary-path__deprecated { - color: #9ca3af; - text-decoration: line-through; -} - -html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .opblock-summary .opblock-summary-control svg { - fill: #d1d5db; -} - -/* HTTP method badges */ -html[class~="dark"] .swagger-ui .opblock .opblock-summary .opblock-summary-method { - background: #404040; - color: #f3f4f6; -} - -html[class~="dark"] .swagger-ui .opblock.opblock-get .opblock-summary-method { - background: #16a34a; -} - -html[class~="dark"] .swagger-ui .opblock.opblock-post .opblock-summary-method { - background: #2563eb; -} - -html[class~="dark"] .swagger-ui .opblock.opblock-put .opblock-summary-method { - background: #d97706; -} - -html[class~="dark"] .swagger-ui .opblock.opblock-delete .opblock-summary-method { - background: #dc2626; -} - -html[class~="dark"] .swagger-ui .opblock.opblock-patch .opblock-summary-method { - background: #9333ea; -} - -/* Tinted opblock backgrounds per method */ -html[class~="dark"] .swagger-ui .opblock.opblock-get { - background: rgba(22, 163, 74, 0.05); - border-color: rgba(22, 163, 74, 0.3); -} - -html[class~="dark"] .swagger-ui .opblock.opblock-post { - background: rgba(37, 99, 235, 0.05); - border-color: rgba(37, 99, 235, 0.3); -} - -html[class~="dark"] .swagger-ui .opblock.opblock-put { - background: rgba(217, 119, 6, 0.05); - border-color: rgba(217, 119, 6, 0.3); -} - -html[class~="dark"] .swagger-ui .opblock.opblock-delete { - background: rgba(220, 38, 38, 0.05); - border-color: rgba(220, 38, 38, 0.3); -} - -html[class~="dark"] .swagger-ui .opblock.opblock-patch { - background: rgba(147, 51, 234, 0.05); - border-color: rgba(147, 51, 234, 0.3); -} - -/* --- Expanded operation body --- */ - html[class~="dark"] .swagger-ui .opblock-body { background: #111; } -html[class~="dark"] .swagger-ui .opblock-body pre.microlight { - background: #0a0a0a !important; - color: #d1d5db !important; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .opblock-description-wrapper, -html[class~="dark"] .swagger-ui .opblock-external-docs-wrapper { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .opblock-description-wrapper p, -html[class~="dark"] .swagger-ui .opblock-external-docs-wrapper p { - color: #d1d5db; -} - -/* Section headers ("Parameters", "Request body", "Responses") */ html[class~="dark"] .swagger-ui .opblock-section-header { background: #1a1a1a; border-bottom: 1px solid #262626; box-shadow: none; } -html[class~="dark"] .swagger-ui .opblock-section-header h4, -html[class~="dark"] .swagger-ui .opblock-section-header label { - color: #f3f4f6; -} - -/* --- Parameters --- */ - -html[class~="dark"] .swagger-ui .parameters-container { - background: transparent; - border: none; -} - -html[class~="dark"] .swagger-ui .parameter__name { - color: #f3f4f6; -} - -html[class~="dark"] .swagger-ui .parameter__type { - color: #9ca3af; -} +/* Tinted per-method backgrounds */ +html[class~="dark"] .swagger-ui .opblock.opblock-get { background: rgba(22, 163, 74, 0.05); border-color: rgba(22, 163, 74, 0.3); } +html[class~="dark"] .swagger-ui .opblock.opblock-post { background: rgba(37, 99, 235, 0.05); border-color: rgba(37, 99, 235, 0.3); } +html[class~="dark"] .swagger-ui .opblock.opblock-put { background: rgba(217, 119, 6, 0.05); border-color: rgba(217, 119, 6, 0.3); } +html[class~="dark"] .swagger-ui .opblock.opblock-delete { background: rgba(220, 38, 38, 0.05); border-color: rgba(220, 38, 38, 0.3); } +html[class~="dark"] .swagger-ui .opblock.opblock-patch { background: rgba(147, 51, 234, 0.05); border-color: rgba(147, 51, 234, 0.3); } -html[class~="dark"] .swagger-ui .parameter__in { - color: #9ca3af; -} - -/* --- Tables (parameters, responses) --- */ - -html[class~="dark"] .swagger-ui table thead tr td, -html[class~="dark"] .swagger-ui table thead tr th { - color: #f3f4f6; - border-bottom: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui table tbody tr td { - color: #d1d5db; - border-bottom: 1px solid #1a1a1a; -} - -html[class~="dark"] .swagger-ui .parameters col:last-child { - background: transparent; -} - -html[class~="dark"] .swagger-ui table.headers td { - color: #d1d5db; -} - -/* --- Responses --- */ - -html[class~="dark"] .swagger-ui .responses-wrapper { - background: transparent; - border: none; -} - -html[class~="dark"] .swagger-ui .responses-inner { - background: transparent; -} - -html[class~="dark"] .swagger-ui .response-col_status { - color: #f3f4f6; -} - -html[class~="dark"] .swagger-ui .response-col_description { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .response-col_links { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .response { - border-bottom: 1px solid #1a1a1a; -} - -html[class~="dark"] .swagger-ui .response-control-media-type__accept-message { - color: #9ca3af; -} - -/* --- Tabs (Example Value / Schema) --- */ - -html[class~="dark"] .swagger-ui .tab li { - color: #9ca3af; +/* Containers sharing the same treatment */ +html[class~="dark"] .swagger-ui .scheme-container, +html[class~="dark"] .swagger-ui .model-box, +html[class~="dark"] .swagger-ui section.models .model-container, +html[class~="dark"] .swagger-ui .filter-container { + background: #171717; + border-color: #262626; } -html[class~="dark"] .swagger-ui .tab li.active { - color: #f3f4f6; +html[class~="dark"] .swagger-ui section.models { + border-color: #262626; } -html[class~="dark"] .swagger-ui .tab li button.tablinks { - color: inherit; +/* Clear default white backgrounds */ +html[class~="dark"] .swagger-ui .responses-wrapper, +html[class~="dark"] .swagger-ui .responses-inner, +html[class~="dark"] .swagger-ui .parameters-container { background: transparent; } -/* --- Markdown / rendered content --- */ - -html[class~="dark"] .swagger-ui .renderedMarkdown p { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .markdown p, -html[class~="dark"] .swagger-ui .markdown pre { - color: #d1d5db; -} - -/* --- Models / Schemas --- */ - -html[class~="dark"] .swagger-ui .model-title { - color: #f3f4f6; -} - -html[class~="dark"] .swagger-ui .model { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .model .property { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .model .property-row { - border-bottom: 1px solid #1a1a1a; -} - -html[class~="dark"] .swagger-ui .prop-type { - color: #9ca3af; -} - -html[class~="dark"] .swagger-ui .prop-name { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .model-box { - background: #171717; +/* Code blocks and inline examples */ +html[class~="dark"] .swagger-ui .opblock-body pre.microlight { + background: #0a0a0a !important; + color: #d1d5db !important; border: 1px solid #262626; } -html[class~="dark"] .swagger-ui .model-toggle { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .model-toggle:hover { - color: #f3f4f6; -} - -html[class~="dark"] .swagger-ui .model-toggle::after { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .model-box-control { +html[class~="dark"] .swagger-ui .highlight-code, +html[class~="dark"] .swagger-ui .highlight-code .hljs { + background: #0a0a0a; color: #d1d5db; } -html[class~="dark"] .swagger-ui .model-box-control svg { - fill: #d1d5db; -} +/* --- Borders --- */ -html[class~="dark"] .swagger-ui .model-jump-to-path { - color: hsl(var(--primary-hue) var(--primary-saturation) var(--primary-lightness)); +html[class~="dark"] .swagger-ui .opblock-tag, +html[class~="dark"] .swagger-ui .opblock .opblock-summary, +html[class~="dark"] .swagger-ui table thead tr th, +html[class~="dark"] .swagger-ui table thead tr td { + border-bottom-color: #262626; } -html[class~="dark"] .swagger-ui .model-jump-to-path:hover { - opacity: 0.8; +html[class~="dark"] .swagger-ui table tbody tr td, +html[class~="dark"] .swagger-ui .response { + border-bottom-color: #1a1a1a; } -html[class~="dark"] .swagger-ui section.models { - border: 1px solid #262626; -} +/* --- HTTP method badges --- */ -html[class~="dark"] .swagger-ui section.models h4 { +html[class~="dark"] .swagger-ui .opblock .opblock-summary-method { color: #f3f4f6; } -html[class~="dark"] .swagger-ui section.models .model-container { - background: #171717; - border-bottom: 1px solid #262626; -} - -/* --- Expand / collapse icons --- */ +html[class~="dark"] .swagger-ui .opblock.opblock-get .opblock-summary-method { background: #16a34a; } +html[class~="dark"] .swagger-ui .opblock.opblock-post .opblock-summary-method { background: #2563eb; } +html[class~="dark"] .swagger-ui .opblock.opblock-put .opblock-summary-method { background: #d97706; } +html[class~="dark"] .swagger-ui .opblock.opblock-delete .opblock-summary-method { background: #dc2626; } +html[class~="dark"] .swagger-ui .opblock.opblock-patch .opblock-summary-method { background: #9333ea; } -html[class~="dark"] .swagger-ui .expand-operation svg, -html[class~="dark"] .swagger-ui .collapse-operation svg { - fill: #d1d5db; -} +/* --- Form controls --- */ -html[class~="dark"] .swagger-ui .prop-toggle { +html[class~="dark"] .swagger-ui select, +html[class~="dark"] .swagger-ui textarea, +html[class~="dark"] .swagger-ui input[type=text], +html[class~="dark"] .swagger-ui input[type=password], +html[class~="dark"] .swagger-ui input[type=search] { + background: #0a0a0a; color: #d1d5db; + border: 1px solid #262626; } -html[class~="dark"] .swagger-ui .prop-toggle svg { - fill: #d1d5db; +html[class~="dark"] .swagger-ui select { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23D1D5DB' d='m8 10.293 3.146-3.147.708.708L8 11.707 4.146 7.854l.708-.708L8 10.293z'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: right 16px center !important; + background-size: 14px 14px !important; + padding-right: 40px !important; } /* --- Buttons --- */ @@ -369,214 +175,23 @@ html[class~="dark"] .swagger-ui .btn.authorize:hover { background: #1d4ed8; } -html[class~="dark"] .swagger-ui .btn.execute { - background: #16a34a; - border-color: #16a34a; - color: #fff; -} - -html[class~="dark"] .swagger-ui .btn.execute:hover { - background: #15803d; -} - -html[class~="dark"] .swagger-ui .btn.cancel { - background: #dc2626; - border-color: #dc2626; - color: #fff; -} +/* --- SVG icons & tab buttons --- */ -html[class~="dark"] .swagger-ui .btn.cancel:hover { - background: #b91c1c; +html[class~="dark"] .swagger-ui svg { + fill: #d1d5db; } -html[class~="dark"] .swagger-ui .btn svg, -html[class~="dark"] .swagger-ui button svg { +html[class~="dark"] .swagger-ui .btn svg { fill: currentColor; } -/* --- Form controls --- */ - -html[class~="dark"] .swagger-ui textarea { - background-color: #0a0a0a; - color: #d1d5db; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui input[type=text], -html[class~="dark"] .swagger-ui input[type=password], -html[class~="dark"] .swagger-ui input[type=search], -html[class~="dark"] .swagger-ui input[type=email], -html[class~="dark"] .swagger-ui input[type=url] { - background-color: #0a0a0a; - color: #d1d5db; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui select { - background: #0a0a0a; - color: #d1d5db; - border: 1px solid #262626; - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23D1D5DB' d='m8 10.293 3.146-3.147.708.708L8 11.707 4.146 7.854l.708-.708L8 10.293z'/%3E%3C/svg%3E") !important; - background-repeat: no-repeat !important; - background-position: right 16px center !important; - background-size: 14px 14px !important; - padding-right: 40px !important; -} - -/* --- Code / highlight blocks --- */ - -html[class~="dark"] .swagger-ui .highlight-code { - background: #0a0a0a; - color: #d1d5db; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .highlight-code .hljs { - background: #0a0a0a; - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .curl-command { - background: #0a0a0a; - color: #d1d5db; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .copy-to-clipboard { - background: #262626; - color: #f3f4f6; -} - -html[class~="dark"] .swagger-ui .copy-to-clipboard:hover { - background: #404040; -} - -/* --- Scheme & server selectors --- */ - -html[class~="dark"] .swagger-ui .scheme-container { - background: #171717; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .scheme-container .schemes-title, -html[class~="dark"] .swagger-ui .scheme-container .schemes > label { - color: #d1d5db; -} - -html[class~="dark"] .swagger-ui .scheme-container select { - background: #0a0a0a; - color: #d1d5db; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .servers > label, -html[class~="dark"] .swagger-ui .servers > .servers-title { - color: #f3f4f6; -} - -html[class~="dark"] .swagger-ui .servers .server-url { - background: #0a0a0a; - color: #d1d5db; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .servers .server-description { - color: #9ca3af; -} - -html[class~="dark"] .swagger-ui .global-server-container { - background: #171717; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .global-server-container .servers-title { - color: #f3f4f6; -} - -/* --- Auth --- */ - -html[class~="dark"] .swagger-ui .auth-wrapper { - background: #171717; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .auth-container .auth-wrapper h4 { - color: #f3f4f6; -} - -html[class~="dark"] .swagger-ui .auth-container .auth-wrapper .auth-btn-wrapper { - background: transparent; -} - -/* --- Filter bar --- */ - -html[class~="dark"] .swagger-ui .filter-container { - background: #171717; - border-top: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .filter .operation-filter-input { - background: #0a0a0a; - color: #d1d5db; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .filter .operation-filter-input:focus { - border-color: hsl(var(--primary-hue) var(--primary-saturation) var(--primary-lightness)); - box-shadow: 0 0 0 2px hsla(var(--primary-hue) var(--primary-saturation) var(--primary-lightness) / 0.2); -} - -html[class~="dark"] .swagger-ui .filter .operation-filter-input::placeholder { - color: #6b7280; -} - -/* --- Download bar --- */ - -html[class~="dark"] .swagger-ui .topbar .download-url-wrapper input[type=text] { - background: #0a0a0a; - color: #d1d5db; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .topbar .download-url-wrapper .download-url-button { - background: #262626; - color: #f3f4f6; -} - -/* --- Errors --- */ - -html[class~="dark"] .swagger-ui .errors-wrapper { - background: rgba(220, 38, 38, 0.1); - border: 1px solid rgba(220, 38, 38, 0.4); - color: #fca5a5; -} - -html[class~="dark"] .swagger-ui .errors-wrapper .error-wrapper { +html[class~="dark"] .swagger-ui .tab li button.tablinks { + color: inherit; background: transparent; } -/* --- Loading --- */ - -html[class~="dark"] .swagger-ui .loading-container .loading::after { - color: #d1d5db; -} - -/* --- SVG fills for interactive controls --- */ - -html[class~="dark"] .swagger-ui .parameters-container .parameter-item .parameter-item-header .parameter-item-toggle svg { - fill: #d1d5db; -} - -html[class~="dark"] .swagger-ui .responses-wrapper .response-header .response-toggle svg { - fill: #d1d5db; -} - /* --- Links --- */ html[class~="dark"] .swagger-ui a { color: hsl(var(--primary-hue) var(--primary-saturation) var(--primary-lightness)); } - -html[class~="dark"] .swagger-ui a:hover { - opacity: 0.8; -} From 3d3b7ddbee77d93b7c92bf53f1483092bd765fe8 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 10:36:00 -0500 Subject: [PATCH 07/23] Fix button outline color in darkmode --- assets/css/swagger.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/assets/css/swagger.css b/assets/css/swagger.css index b061eb4715..d23221660d 100644 --- a/assets/css/swagger.css +++ b/assets/css/swagger.css @@ -190,6 +190,12 @@ html[class~="dark"] .swagger-ui .tab li button.tablinks { background: transparent; } +/* --- Button focus outline --- */ + +html[class~="dark"] .swagger-ui button:focus { + outline: 1px solid #404040; +} + /* --- Links --- */ html[class~="dark"] .swagger-ui a { From 9bd9e4c12c5f811c90c8d72ed362e2351e58df9c Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 11:22:31 -0500 Subject: [PATCH 08/23] Clean up dark mode --- assets/css/swagger.css | 83 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 72 insertions(+), 11 deletions(-) diff --git a/assets/css/swagger.css b/assets/css/swagger.css index d23221660d..f2784a2247 100644 --- a/assets/css/swagger.css +++ b/assets/css/swagger.css @@ -94,17 +94,13 @@ html[class~="dark"] .swagger-ui .parameters-container { background: transparent; } -/* Code blocks and inline examples */ -html[class~="dark"] .swagger-ui .opblock-body pre.microlight { - background: #0a0a0a !important; - color: #d1d5db !important; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui .highlight-code, -html[class~="dark"] .swagger-ui .highlight-code .hljs { - background: #0a0a0a; - color: #d1d5db; +/* Code blocks — prevent hextra's pre/code styles from interfering + with Swagger's own microlight syntax highlighting */ +.swagger-ui pre, +.swagger-ui code { + background-color: unset; + border: unset; + color: unset; } /* --- Borders --- */ @@ -196,6 +192,71 @@ html[class~="dark"] .swagger-ui button:focus { outline: 1px solid #404040; } +/* --- JSON Schema 2020-12 (schema view in Swagger UI) --- */ + +/* Container background */ +html[class~="dark"] .swagger-ui .json-schema-2020-12 { + background-color: rgba(255, 255, 255, 0.03); +} + +html[class~="dark"] .swagger-ui .model-box .json-schema-2020-12, +html[class~="dark"] .swagger-ui .json-schema-2020-12--embedded { + background-color: transparent; +} + +/* Titles and labels */ +html[class~="dark"] .swagger-ui .json-schema-2020-12__title, +html[class~="dark"] .swagger-ui .json-schema-2020-12-expand-deep-button { + color: #f3f4f6; +} + +/* Primary text (property names, values) */ +html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__name--primary, +html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__value--primary, +html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__name--primary, +html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__value--primary, +html[class~="dark"] .swagger-ui .json-schema-2020-12__attribute, +html[class~="dark"] .swagger-ui .json-schema-2020-12-property .json-schema-2020-12__title { + color: #d1d5db; +} + +/* Secondary / muted text */ +html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__name--secondary, +html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__value, +html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__value--secondary, +html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__name--secondary, +html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__value, +html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__value--secondary, +html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword--description { + color: #9ca3af; +} + +/* Extension text */ +html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__name--extension, +html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__value--extension, +html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__name--extension, +html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__value--extension { + color: #6b7280; +} + +/* Primary attribute (type labels) */ +html[class~="dark"] .swagger-ui .json-schema-2020-12__attribute--primary { + color: #60a5fa; +} + +/* Dashed borders */ +html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__children, +html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__children, +html[class~="dark"] .swagger-ui .json-schema-2020-12-body, +html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword--$vocabulary ul { + border-left-color: rgba(255, 255, 255, 0.1); +} + +/* Accordion buttons */ +html[class~="dark"] .swagger-ui .json-schema-2020-12-accordion { + background-color: transparent; +} + /* --- Links --- */ html[class~="dark"] .swagger-ui a { From a4383282dec2baa951b149ade03cf0ef7fab24cd Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 11:23:08 -0500 Subject: [PATCH 09/23] Clear title --- content/en/building/reference/openapi.md | 1 - 1 file changed, 1 deletion(-) diff --git a/content/en/building/reference/openapi.md b/content/en/building/reference/openapi.md index f998bbd88f..fcad6c7360 100644 --- a/content/en/building/reference/openapi.md +++ b/content/en/building/reference/openapi.md @@ -1,5 +1,4 @@ --- -title: "OpenAPI Documentation" linkTitle: "OpenAPI" weight: 2 toc: false From 03b98a7f1b916a902d864b109d06540492ccb4b2 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 14:02:43 -0500 Subject: [PATCH 10/23] Update to load openapi.json from remote gist (temp solution) --- content/en/building/reference/openapi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/building/reference/openapi.md b/content/en/building/reference/openapi.md index fcad6c7360..acdb5c9c90 100644 --- a/content/en/building/reference/openapi.md +++ b/content/en/building/reference/openapi.md @@ -4,4 +4,4 @@ weight: 2 toc: false --- -{{< swagger url="/openapi.json" >}} +{{< swagger url="https://gist.githubusercontent.com/jkuester/a738de6aa6f96e5957b1f4ce56a3692a/raw/8be02e092acd4f0b3ab4cd456e28d6351a204b16/openapi.json" >}} From b47cfba48ab77af4ad83f3513f52c58201c11a6b Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 14:09:13 -0500 Subject: [PATCH 11/23] Hide unnecessary swagger ui elements --- assets/css/swagger.css | 5 +++++ content/en/building/reference/openapi.md | 3 +++ 2 files changed, 8 insertions(+) diff --git a/assets/css/swagger.css b/assets/css/swagger.css index f2784a2247..c1bfb6029e 100644 --- a/assets/css/swagger.css +++ b/assets/css/swagger.css @@ -7,6 +7,11 @@ width: 100%; } +/* Hide info */ +#swagger-ui .information-container,.scheme-container,.filter-container { + display: none; +} + /* --- Base text --- */ html[class~="dark"] .swagger-ui { diff --git a/content/en/building/reference/openapi.md b/content/en/building/reference/openapi.md index acdb5c9c90..d2caf9d952 100644 --- a/content/en/building/reference/openapi.md +++ b/content/en/building/reference/openapi.md @@ -1,4 +1,7 @@ --- +title: "REST API to interact with CHT Applications" +description: > + RESTful Application Programming Interfaces for integrating with CHT applications linkTitle: "OpenAPI" weight: 2 toc: false From 3c03eb21aa67dba3ad3bce019183d04032814397 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 17:21:24 -0500 Subject: [PATCH 12/23] Add badge for permissions --- assets/css/swagger.css | 42 ++++++++++++++++++++++++++++ layouts/shortcodes/swagger.html | 49 ++++++++++++++++++++++++++++++++- 2 files changed, 90 insertions(+), 1 deletion(-) diff --git a/assets/css/swagger.css b/assets/css/swagger.css index c1bfb6029e..ff426c0b6e 100644 --- a/assets/css/swagger.css +++ b/assets/css/swagger.css @@ -262,6 +262,48 @@ html[class~="dark"] .swagger-ui .json-schema-2020-12-accordion { background-color: transparent; } +/* --- x-permissions badges --- */ + +.x-permissions { + margin: 0.75rem 1.25rem 1rem; + padding: 0.625rem 0.875rem; + background: #eff6ff; + border: 1px solid #bfdbfe; + border-radius: 6px; + font-size: 0.8125rem; + line-height: 1.6; + color: #1e3a8a; +} + +.x-permissions__line { + display: block; +} + +.x-permissions__label { + font-weight: 600; +} + +.swagger-ui .x-permissions__pill { + display: inline-block; + padding: 0.1em 0.5em; + margin: 0.1em 0.25em; + background: #dbeafe; + border: 1px solid #93c5fd; + border-radius: 4px; + font-family: ui-monospace, SFMono-Regular, Menlo, monospace; +} + +html[class~="dark"] .x-permissions { + background: rgba(99, 102, 241, 0.08); + border-color: rgba(99, 102, 241, 0.25); + color: #c7d2fe; +} + +html[class~="dark"] .swagger-ui .x-permissions__pill { + background: rgba(99, 102, 241, 0.15); + border-color: rgba(99, 102, 241, 0.3); +} + /* --- Links --- */ html[class~="dark"] .swagger-ui a { diff --git a/layouts/shortcodes/swagger.html b/layouts/shortcodes/swagger.html index 2de18fbccc..244f1691f2 100644 --- a/layouts/shortcodes/swagger.html +++ b/layouts/shortcodes/swagger.html @@ -19,17 +19,64 @@ From 297e3b5adcc204abe72ba854d7951caa36c89865 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Fri, 13 Mar 2026 17:37:41 -0500 Subject: [PATCH 13/23] Update permissions badge layout. --- layouts/shortcodes/swagger.html | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/layouts/shortcodes/swagger.html b/layouts/shortcodes/swagger.html index 244f1691f2..090a69255f 100644 --- a/layouts/shortcodes/swagger.html +++ b/layouts/shortcodes/swagger.html @@ -20,22 +20,18 @@ - +{{- $swaggerJs := resources.Get "js/swagger.js" -}} + From 53eb55708b855db661fe84cd311f2fa6d6fa88b8 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Mon, 16 Mar 2026 14:34:53 -0500 Subject: [PATCH 16/23] Fix constrast for deprecated elements. --- assets/css/swagger.css | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/assets/css/swagger.css b/assets/css/swagger.css index ae948b4a52..d03afd149f 100644 --- a/assets/css/swagger.css +++ b/assets/css/swagger.css @@ -134,6 +134,11 @@ html[class~="dark"] .swagger-ui .opblock.opblock-put .opblock-summary-method { b html[class~="dark"] .swagger-ui .opblock.opblock-delete .opblock-summary-method { background: #dc2626; } html[class~="dark"] .swagger-ui .opblock.opblock-patch .opblock-summary-method { background: #9333ea; } +/* Deprecated method badge — darker gray for better contrast */ +.swagger-ui .opblock.opblock-deprecated .opblock-summary-method { + background: #525252; +} + /* --- Form controls --- */ html[class~="dark"] .swagger-ui select, From d83e8230f4ca21306900f8b799102bc6d70b959a Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Mon, 16 Mar 2026 14:49:27 -0500 Subject: [PATCH 17/23] Fix badge alignment --- assets/css/swagger.css | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/assets/css/swagger.css b/assets/css/swagger.css index d03afd149f..77f58bb9ec 100644 --- a/assets/css/swagger.css +++ b/assets/css/swagger.css @@ -282,7 +282,7 @@ html[class~="dark"] .swagger-ui .json-schema-2020-12-accordion { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 6px; - font-size: 0.8125rem; + font-size: 0.8rem; font-weight: 600; color: #166534; } @@ -294,12 +294,11 @@ html[class~="dark"] .x-since { } .x-permissions { - padding: 0.625rem 0.875rem; + padding: calc(0.625rem - 1px) 0.875rem; background: #eff6ff; border: 1px solid #bfdbfe; border-radius: 6px; - font-size: 0.8125rem; - line-height: 1.6; + font-size: 0.8rem; color: #1e3a8a; } @@ -313,8 +312,8 @@ html[class~="dark"] .x-since { .swagger-ui .x-permissions__pill { display: inline-block; - padding: 0.1em 0.5em; - margin: 0.1em 0.25em; + padding: 0 0.5em; + margin: 0 0.25em; background: #dbeafe; border: 1px solid #93c5fd; border-radius: 4px; From f397b325ce47e3971b5691d6d6f0986fcc79e2c6 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Mon, 16 Mar 2026 14:52:35 -0500 Subject: [PATCH 18/23] Just load data from latest version of gist --- content/en/building/reference/openapi.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/en/building/reference/openapi.md b/content/en/building/reference/openapi.md index be702a4863..695008cc6e 100644 --- a/content/en/building/reference/openapi.md +++ b/content/en/building/reference/openapi.md @@ -7,4 +7,4 @@ weight: 2 toc: false --- -{{< swagger url="https://gist.githubusercontent.com/jkuester/a738de6aa6f96e5957b1f4ce56a3692a/raw/be63e446cbee0a58fbd64176fa6f28ee5c0527c0/openapi.json" >}} +{{< swagger url="https://gist.githubusercontent.com/jkuester/a738de6aa6f96e5957b1f4ce56a3692a/raw/openapi.json" >}} From 1e6e21ea6493582dcc252de7dd7a0e62a37044b6 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Thu, 19 Mar 2026 11:32:03 -0500 Subject: [PATCH 19/23] Clean everything up --- assets/css/swagger.css | 6 ++++ assets/js/swagger.js | 17 ++++++----- .../reference/app-settings/token_login.md | 29 +++++++++++++++++++ content/en/building/reference/openapi.md | 2 +- layouts/shortcodes/swagger.html | 14 +-------- 5 files changed, 46 insertions(+), 22 deletions(-) diff --git a/assets/css/swagger.css b/assets/css/swagger.css index 77f58bb9ec..548f88341a 100644 --- a/assets/css/swagger.css +++ b/assets/css/swagger.css @@ -139,6 +139,12 @@ html[class~="dark"] .swagger-ui .opblock.opblock-patch .opblock-summary-method { background: #525252; } +/* Hide parameter inputs (no live server connection) */ +.swagger-ui .parameters-container input, +.swagger-ui .parameters-container select { + display: none; +} + /* --- Form controls --- */ html[class~="dark"] .swagger-ui select, diff --git a/assets/js/swagger.js b/assets/js/swagger.js index 6d2f9ed255..67ef4994fa 100644 --- a/assets/js/swagger.js +++ b/assets/js/swagger.js @@ -55,17 +55,18 @@ const XExtensionsPlugin = () => ({ }); window.addEventListener('DOMContentLoaded', () => { - const el = document.querySelector('[data-swagger-ui]'); SwaggerUIBundle({ - dom_id: `#${el.id}`, - url: el.dataset.url, + dom_id: '#swagger-ui', + url: 'https://gist.githubusercontent.com/jkuester/a738de6aa6f96e5957b1f4ce56a3692a/raw/openapi.json', presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset], plugins: [XExtensionsPlugin], - filter: el.dataset.filter === 'true', - operationsSorter: el.dataset.operationsSorter, - tagsSorter: el.dataset.tagsSorter, - docExpansion: el.dataset.docExpansion, + filter: true, + operationsSorter: 'alpha', + tagsSorter: 'alpha', + docExpansion: 'none', deepLinking: true, - supportedSubmitMethods: [] + supportedSubmitMethods: [], + defaultModelsExpandDepth: -1, + defaultModelExpandDepth: 3 }); }); diff --git a/content/en/building/reference/app-settings/token_login.md b/content/en/building/reference/app-settings/token_login.md index 018a4bc1a5..ed0f76ca90 100644 --- a/content/en/building/reference/app-settings/token_login.md +++ b/content/en/building/reference/app-settings/token_login.md @@ -11,6 +11,35 @@ aliases: - /apps/reference/app-settings/token_login --- +When creating or updating a user, sending a truthy value for the field `token_login` will enable Login by SMS for this user. +This action resets the user's password to an unknown string and generates a complex 64 character token, that is used to generate a token-login URL. +The URL is sent to the user's phone number by SMS, along with another (configurable) SMS that can contain additional information. +Accessing this link, before its expiration time, will log the user in directly - without the need of any other credentials. +The link can only be accessed once, the token becomes invalid after being used for one login. +The token expires in 24 hours, after which logging in is only possible by either generating a new token, or disabling `token_login` and manually setting a password. + +The SMS messages are stored in a doc of type `login_token`. These docs cannot be viewed as reports from the webapp, and can only be edited by admins, but their messages are visible in the Admin Message Queue page. + +To disable login by SMS for a user, update the user sending `token_login` with a `false` value. +To regenerate the token, update the user sending `token_login` with a `true` value. + +| `token_login` | user state | action | +|---------------|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------| +| undefined | new | None | +| undefined | existent, no token | None | +| undefined | existent, with token | None. Login by SMS remains enabled. Token is unchanged. | +| true | new | Login by SMS enabled. Token is generated and SMS is sent. | +| true | existent, no token | Password is reset. Login by SMS enabled. Token is generated and SMS is sent. Existent sessions are invalidated. | +| true | existent, with token | Password is reset. Login by SMS enabled. New token is generated and SMS is sent. Old token is invalid. Existent sessions are invalidated. | +| false | new | None. | +| false | existent, no token | None. | +| false | existent, with token | Request requires a password. Login by SMS is disabled. Old token is invalidated. Existent sessions are invalidated. | + + +{{< see-also page="building/login" anchor="remote-login" >}} + +## Configuration + Login via SMS settings are defined under the `token_login` key, as an object supporting the following properties: {{< callout >}} diff --git a/content/en/building/reference/openapi.md b/content/en/building/reference/openapi.md index 695008cc6e..58d9aa1594 100644 --- a/content/en/building/reference/openapi.md +++ b/content/en/building/reference/openapi.md @@ -7,4 +7,4 @@ weight: 2 toc: false --- -{{< swagger url="https://gist.githubusercontent.com/jkuester/a738de6aa6f96e5957b1f4ce56a3692a/raw/openapi.json" >}} +{{< swagger >}} diff --git a/layouts/shortcodes/swagger.html b/layouts/shortcodes/swagger.html index 3e4bc260d9..86e90693f0 100644 --- a/layouts/shortcodes/swagger.html +++ b/layouts/shortcodes/swagger.html @@ -1,10 +1,3 @@ -{{- $url := .Get "url" | default "/openapi.json" -}} -{{- $filter := .Get "filter" | default "true" -}} -{{- $operationsSorter := .Get "operationsSorter" | default "alpha" -}} -{{- $tagsSorter := .Get "tagsSorter" | default "alpha" -}} -{{- $docExpansion := .Get "docExpansion" | default "list" -}} -{{- $id := .Get "id" | default "swagger-ui" -}} - @@ -13,12 +6,7 @@ {{- $swaggerCss := resources.Get "css/swagger.css" -}} -
+
From 18516aa7d0984cf9cab98f1df5ddcd6f491102d8 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Wed, 25 Mar 2026 16:59:26 -0500 Subject: [PATCH 20/23] Clean up css --- assets/css/swagger.css | 577 ++++++++++++++++++++++------------------- 1 file changed, 305 insertions(+), 272 deletions(-) diff --git a/assets/css/swagger.css b/assets/css/swagger.css index 548f88341a..feea67c29c 100644 --- a/assets/css/swagger.css +++ b/assets/css/swagger.css @@ -3,103 +3,49 @@ Hextra dark: #111 bg, neutral grays ------------------------- */ +/* --- Color palette (dark mode) --- */ +.dark .swagger-ui { + --sw-text: #d1d5db; + --sw-text-bright: #f3f4f6; + --sw-text-muted: #9ca3af; + --sw-text-faint: #6b7280; + --sw-bg-panel: #171717; + --sw-bg-deep: #111; + --sw-bg-raised: #1a1a1a; + --sw-bg-input: #0a0a0a; + --sw-border: #262626; + --sw-border-faint: #1a1a1a; + --sw-border-strong: #404040; + --sw-accent: #2563eb; + --sw-accent-hover: #1d4ed8; +} + +/* --- Per-method colors --- */ +.dark .swagger-ui .opblock-get { --method: 22, 163, 74; } +.dark .swagger-ui .opblock-post { --method: 37, 99, 235; } +.dark .swagger-ui .opblock-put { --method: 217, 119, 6; } +.dark .swagger-ui .opblock-delete { --method: 220, 38, 38; } +.dark .swagger-ui .opblock-patch { --method: 147, 51, 234; } + +/* --- Layout & hidden sections --- */ + #swagger-ui { width: 100%; } -/* Hide info */ -#swagger-ui .information-container,.scheme-container,.filter-container { +#swagger-ui .information-container, +.scheme-container, +.filter-container { display: none; } -/* --- Base text --- */ - -html[class~="dark"] .swagger-ui { - color: #d1d5db; -} - -/* Bright text — headings, labels, active tabs */ -html[class~="dark"] .swagger-ui .info .title, -html[class~="dark"] .swagger-ui .opblock-tag, -html[class~="dark"] .swagger-ui .opblock-section-header h4, -html[class~="dark"] .swagger-ui .opblock-section-header label, -html[class~="dark"] .swagger-ui .parameter__name, -html[class~="dark"] .swagger-ui .response-col_status, -html[class~="dark"] .swagger-ui .model-title, -html[class~="dark"] .swagger-ui table thead tr th, -html[class~="dark"] .swagger-ui table thead tr td, -html[class~="dark"] .swagger-ui section.models h4, -html[class~="dark"] .swagger-ui .tab li.active { - color: #f3f4f6; -} - -/* Muted text — types, secondary info, inactive tabs */ -html[class~="dark"] .swagger-ui .info .base-url, -html[class~="dark"] .swagger-ui .parameter__type, -html[class~="dark"] .swagger-ui .parameter__in, -html[class~="dark"] .swagger-ui .prop-type, -html[class~="dark"] .swagger-ui .tab li { - color: #9ca3af; -} - -/* Body text — override Swagger's dark-on-light defaults */ -html[class~="dark"] .swagger-ui .opblock-summary-description, -html[class~="dark"] .swagger-ui .opblock-summary-path, -html[class~="dark"] .swagger-ui .opblock-description-wrapper p, -html[class~="dark"] .swagger-ui .renderedMarkdown p, -html[class~="dark"] .swagger-ui .markdown p, -html[class~="dark"] .swagger-ui .markdown pre, -html[class~="dark"] .swagger-ui .response-col_description, -html[class~="dark"] .swagger-ui .model, -html[class~="dark"] .swagger-ui table tbody tr td { - color: #d1d5db; -} - -/* --- Backgrounds --- */ - -html[class~="dark"] .swagger-ui .opblock { - background: #171717; - border-color: #262626; -} - -html[class~="dark"] .swagger-ui .opblock-body { - background: #111; -} - -html[class~="dark"] .swagger-ui .opblock-section-header { - background: #1a1a1a; - border-bottom: 1px solid #262626; - box-shadow: none; -} - -/* Tinted per-method backgrounds */ -html[class~="dark"] .swagger-ui .opblock.opblock-get { background: rgba(22, 163, 74, 0.05); border-color: rgba(22, 163, 74, 0.3); } -html[class~="dark"] .swagger-ui .opblock.opblock-post { background: rgba(37, 99, 235, 0.05); border-color: rgba(37, 99, 235, 0.3); } -html[class~="dark"] .swagger-ui .opblock.opblock-put { background: rgba(217, 119, 6, 0.05); border-color: rgba(217, 119, 6, 0.3); } -html[class~="dark"] .swagger-ui .opblock.opblock-delete { background: rgba(220, 38, 38, 0.05); border-color: rgba(220, 38, 38, 0.3); } -html[class~="dark"] .swagger-ui .opblock.opblock-patch { background: rgba(147, 51, 234, 0.05); border-color: rgba(147, 51, 234, 0.3); } - -/* Containers sharing the same treatment */ -html[class~="dark"] .swagger-ui .scheme-container, -html[class~="dark"] .swagger-ui .model-box, -html[class~="dark"] .swagger-ui section.models .model-container, -html[class~="dark"] .swagger-ui .filter-container { - background: #171717; - border-color: #262626; -} - -html[class~="dark"] .swagger-ui section.models { - border-color: #262626; -} - -/* Clear default white backgrounds */ -html[class~="dark"] .swagger-ui .responses-wrapper, -html[class~="dark"] .swagger-ui .responses-inner, -html[class~="dark"] .swagger-ui .parameters-container { - background: transparent; +/* Hide parameter inputs (no live server connection) */ +.swagger-ui .parameters-container input, +.swagger-ui .parameters-container select { + display: none; } -/* Code blocks — prevent hextra's pre/code styles from interfering +/* Code blocks — prevent Hextra's pre/code styles from interfering with Swagger's own microlight syntax highlighting */ .swagger-ui pre, .swagger-ui code { @@ -108,172 +54,282 @@ html[class~="dark"] .swagger-ui .parameters-container { color: unset; } -/* --- Borders --- */ - -html[class~="dark"] .swagger-ui .opblock-tag, -html[class~="dark"] .swagger-ui .opblock .opblock-summary, -html[class~="dark"] .swagger-ui table thead tr th, -html[class~="dark"] .swagger-ui table thead tr td { - border-bottom-color: #262626; -} - -html[class~="dark"] .swagger-ui table tbody tr td, -html[class~="dark"] .swagger-ui .response { - border-bottom-color: #1a1a1a; -} - -/* --- HTTP method badges --- */ - -html[class~="dark"] .swagger-ui .opblock .opblock-summary-method { - color: #f3f4f6; -} - -html[class~="dark"] .swagger-ui .opblock.opblock-get .opblock-summary-method { background: #16a34a; } -html[class~="dark"] .swagger-ui .opblock.opblock-post .opblock-summary-method { background: #2563eb; } -html[class~="dark"] .swagger-ui .opblock.opblock-put .opblock-summary-method { background: #d97706; } -html[class~="dark"] .swagger-ui .opblock.opblock-delete .opblock-summary-method { background: #dc2626; } -html[class~="dark"] .swagger-ui .opblock.opblock-patch .opblock-summary-method { background: #9333ea; } - /* Deprecated method badge — darker gray for better contrast */ .swagger-ui .opblock.opblock-deprecated .opblock-summary-method { background: #525252; } -/* Hide parameter inputs (no live server connection) */ -.swagger-ui .parameters-container input, -.swagger-ui .parameters-container select { - display: none; -} - -/* --- Form controls --- */ - -html[class~="dark"] .swagger-ui select, -html[class~="dark"] .swagger-ui textarea, -html[class~="dark"] .swagger-ui input[type=text], -html[class~="dark"] .swagger-ui input[type=password], -html[class~="dark"] .swagger-ui input[type=search] { - background: #0a0a0a; - color: #d1d5db; - border: 1px solid #262626; -} - -html[class~="dark"] .swagger-ui select { - background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23D1D5DB' d='m8 10.293 3.146-3.147.708.708L8 11.707 4.146 7.854l.708-.708L8 10.293z'/%3E%3C/svg%3E") !important; - background-repeat: no-repeat !important; - background-position: right 16px center !important; - background-size: 14px 14px !important; - padding-right: 40px !important; -} - -/* --- Buttons --- */ - -html[class~="dark"] .swagger-ui .btn { - background: #262626; - color: #f3f4f6; - border: 1px solid #404040; -} - -html[class~="dark"] .swagger-ui .btn:hover { - background: #404040; -} - -html[class~="dark"] .swagger-ui .btn.authorize { - background: #2563eb; - border-color: #2563eb; - color: #fff; -} - -html[class~="dark"] .swagger-ui .btn.authorize:hover { - background: #1d4ed8; -} - -/* --- SVG icons & tab buttons --- */ - -html[class~="dark"] .swagger-ui svg { - fill: #d1d5db; -} - -html[class~="dark"] .swagger-ui .btn svg { - fill: currentColor; -} - -html[class~="dark"] .swagger-ui .tab li button.tablinks { - color: inherit; - background: transparent; -} - -/* --- Button focus outline --- */ - -html[class~="dark"] .swagger-ui button:focus { - outline: 1px solid #404040; -} - -/* --- JSON Schema 2020-12 (schema view in Swagger UI) --- */ - -/* Container background */ -html[class~="dark"] .swagger-ui .json-schema-2020-12 { - background-color: rgba(255, 255, 255, 0.03); -} - -html[class~="dark"] .swagger-ui .model-box .json-schema-2020-12, -html[class~="dark"] .swagger-ui .json-schema-2020-12--embedded { - background-color: transparent; -} - -/* Titles and labels */ -html[class~="dark"] .swagger-ui .json-schema-2020-12__title, -html[class~="dark"] .swagger-ui .json-schema-2020-12-expand-deep-button { - color: #f3f4f6; -} - -/* Primary text (property names, values) */ -html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__name--primary, -html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__value--primary, -html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__name--primary, -html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__value--primary, -html[class~="dark"] .swagger-ui .json-schema-2020-12__attribute, -html[class~="dark"] .swagger-ui .json-schema-2020-12-property .json-schema-2020-12__title { - color: #d1d5db; -} - -/* Secondary / muted text */ -html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__name--secondary, -html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__value, -html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__value--secondary, -html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__name--secondary, -html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__value, -html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__value--secondary, -html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword--description { - color: #9ca3af; -} - -/* Extension text */ -html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__name--extension, -html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__value--extension, -html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__name--extension, -html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__value--extension { - color: #6b7280; -} - -/* Primary attribute (type labels) */ -html[class~="dark"] .swagger-ui .json-schema-2020-12__attribute--primary { - color: #60a5fa; -} - -/* Dashed borders */ -html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword__children, -html[class~="dark"] .swagger-ui .json-schema-2020-12-json-viewer__children, -html[class~="dark"] .swagger-ui .json-schema-2020-12-body, -html[class~="dark"] .swagger-ui .json-schema-2020-12-keyword--$vocabulary ul { - border-left-color: rgba(255, 255, 255, 0.1); -} - -/* Accordion buttons */ -html[class~="dark"] .swagger-ui .json-schema-2020-12-accordion { - background-color: transparent; -} - -/* --- x-extensions badges --- */ +/* --- Dark mode (nested) --- */ + +.dark .swagger-ui { + color: var(--sw-text); + + /* Bright text — headings, labels, active tabs */ + & .info .title, + & .opblock-tag, + & .opblock-section-header h4, + & .opblock-section-header label, + & .parameter__name, + & .response-col_status, + & .model-title, + & table thead tr th, + & table thead tr td, + & section.models h4, + & .tab li.active { + color: var(--sw-text-bright); + } + + /* Muted text — types, secondary info, inactive tabs */ + & .info .base-url, + & .parameter__type, + & .parameter__in, + & .prop-type, + & .tab li { + color: var(--sw-text-muted); + } + + /* Body text — override Swagger's dark-on-light defaults */ + & .opblock-summary-description, + & .opblock-summary-path, + & .opblock-description-wrapper p, + & .renderedMarkdown p, + & .markdown p, + & .markdown pre, + & .response-col_description, + & .model, + & table tbody tr td { + color: var(--sw-text); + } + + /* --- Backgrounds --- */ + + & .opblock { + background: var(--sw-bg-panel); + border-color: var(--sw-border); + } + + & .opblock-body { + background: var(--sw-bg-deep); + } + + & .opblock-section-header { + background: var(--sw-bg-raised); + border-bottom: 1px solid var(--sw-border); + box-shadow: none; + } + + /* Tinted per-method backgrounds */ + & .opblock.opblock-get, + & .opblock.opblock-post, + & .opblock.opblock-put, + & .opblock.opblock-delete, + & .opblock.opblock-patch { + background: rgba(var(--method), 0.05); + border-color: rgba(var(--method), 0.3); + } + + /* Containers sharing the same treatment */ + & .scheme-container, + & .model-box, + & section.models .model-container, + & .filter-container { + background: var(--sw-bg-panel); + border-color: var(--sw-border); + } + + & section.models { + border-color: var(--sw-border); + } + + /* Clear default white backgrounds */ + & .responses-wrapper, + & .responses-inner, + & .parameters-container { + background: transparent; + } + + /* --- Borders --- */ + + & .opblock-tag, + & .opblock .opblock-summary, + & table thead tr th, + & table thead tr td { + border-bottom-color: var(--sw-border); + } + + & table tbody tr td, + & .response { + border-bottom-color: var(--sw-border-faint); + } + + /* --- HTTP method badges --- */ + + & .opblock .opblock-summary-method { + color: var(--sw-text-bright); + } + + & .opblock.opblock-get .opblock-summary-method, + & .opblock.opblock-post .opblock-summary-method, + & .opblock.opblock-put .opblock-summary-method, + & .opblock.opblock-delete .opblock-summary-method, + & .opblock.opblock-patch .opblock-summary-method { + background: rgb(var(--method)); + } + + /* --- Form controls --- */ + + & select, + & textarea, + & input[type=text], + & input[type=password], + & input[type=search] { + background: var(--sw-bg-input); + color: var(--sw-text); + border: 1px solid var(--sw-border); + } + + & select { + background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='%23D1D5DB' d='m8 10.293 3.146-3.147.708.708L8 11.707 4.146 7.854l.708-.708L8 10.293z'/%3E%3C/svg%3E") !important; + background-repeat: no-repeat !important; + background-position: right 16px center !important; + background-size: 14px 14px !important; + padding-right: 40px !important; + } + + /* --- Buttons --- */ + + & .btn { + background: var(--sw-border); + color: var(--sw-text-bright); + border: 1px solid var(--sw-border-strong); + } + + & .btn:hover { + background: var(--sw-border-strong); + } + + & .btn.authorize { + background: var(--sw-accent); + border-color: var(--sw-accent); + color: #fff; + } + + & .btn.authorize:hover { + background: var(--sw-accent-hover); + } + + /* --- SVG icons & tab buttons --- */ + + & svg { + fill: var(--sw-text); + } + + & .btn svg { + fill: currentColor; + } + + & .tab li button.tablinks { + color: inherit; + background: transparent; + } + + /* --- Button focus outline --- */ + + & button:focus { + outline: 1px solid var(--sw-border-strong); + } + + /* --- JSON Schema 2020-12 --- */ + + & .json-schema-2020-12 { + background-color: rgba(255, 255, 255, 0.03); + } + + & .model-box .json-schema-2020-12, + & .json-schema-2020-12--embedded { + background-color: transparent; + } + + /* Titles and labels */ + & .json-schema-2020-12__title, + & .json-schema-2020-12-expand-deep-button { + color: var(--sw-text-bright); + } + + /* Primary text (property names, values) */ + & .json-schema-2020-12-keyword__name--primary, + & .json-schema-2020-12-keyword__value--primary, + & .json-schema-2020-12-json-viewer__name--primary, + & .json-schema-2020-12-json-viewer__value--primary, + & .json-schema-2020-12__attribute, + & .json-schema-2020-12-property .json-schema-2020-12__title { + color: var(--sw-text); + } + + /* Secondary / muted text */ + & .json-schema-2020-12-keyword__name--secondary, + & .json-schema-2020-12-keyword__value, + & .json-schema-2020-12-keyword__value--secondary, + & .json-schema-2020-12-json-viewer__name--secondary, + & .json-schema-2020-12-json-viewer__value, + & .json-schema-2020-12-json-viewer__value--secondary, + & .json-schema-2020-12-keyword--description { + color: var(--sw-text-muted); + } + + /* Extension text */ + & .json-schema-2020-12-keyword__name--extension, + & .json-schema-2020-12-keyword__value--extension, + & .json-schema-2020-12-json-viewer__name--extension, + & .json-schema-2020-12-json-viewer__value--extension { + color: var(--sw-text-faint); + } + + /* Primary attribute (type labels) */ + & .json-schema-2020-12__attribute--primary { + color: #60a5fa; + } + + /* Dashed borders */ + & .json-schema-2020-12-keyword__children, + & .json-schema-2020-12-json-viewer__children, + & .json-schema-2020-12-body, + & .json-schema-2020-12-keyword--$vocabulary ul { + border-left-color: rgba(255, 255, 255, 0.1); + } + + /* Accordion buttons */ + & .json-schema-2020-12-accordion { + background-color: transparent; + } + + /* --- Links --- */ + + & a { + color: hsl(var(--primary-hue) var(--primary-saturation) var(--primary-lightness)); + } + + /* --- x-extensions (dark) --- */ + + & .x-since { + background: rgba(34, 197, 94, 0.08); + border-color: rgba(34, 197, 94, 0.25); + color: #86efac; + } + + & .x-permissions { + background: rgba(99, 102, 241, 0.08); + border-color: rgba(99, 102, 241, 0.25); + color: #c7d2fe; + } + + & .x-permissions__pill { + background: rgba(99, 102, 241, 0.15); + border-color: rgba(99, 102, 241, 0.3); + } +} + +/* --- x-extensions (light) --- */ .x-extensions { display: flex; @@ -293,12 +349,6 @@ html[class~="dark"] .swagger-ui .json-schema-2020-12-accordion { color: #166534; } -html[class~="dark"] .x-since { - background: rgba(34, 197, 94, 0.08); - border-color: rgba(34, 197, 94, 0.25); - color: #86efac; -} - .x-permissions { padding: calc(0.625rem - 1px) 0.875rem; background: #eff6ff; @@ -325,20 +375,3 @@ html[class~="dark"] .x-since { border-radius: 4px; font-family: ui-monospace, SFMono-Regular, Menlo, monospace; } - -html[class~="dark"] .x-permissions { - background: rgba(99, 102, 241, 0.08); - border-color: rgba(99, 102, 241, 0.25); - color: #c7d2fe; -} - -html[class~="dark"] .swagger-ui .x-permissions__pill { - background: rgba(99, 102, 241, 0.15); - border-color: rgba(99, 102, 241, 0.3); -} - -/* --- Links --- */ - -html[class~="dark"] .swagger-ui a { - color: hsl(var(--primary-hue) var(--primary-saturation) var(--primary-lightness)); -} From 19d2b086495254febc67f200dbd955febc177f9f Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Wed, 25 Mar 2026 17:03:57 -0500 Subject: [PATCH 21/23] Clean up css --- assets/css/swagger.css | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/assets/css/swagger.css b/assets/css/swagger.css index feea67c29c..fe4e48d911 100644 --- a/assets/css/swagger.css +++ b/assets/css/swagger.css @@ -27,19 +27,15 @@ .dark .swagger-ui .opblock-delete { --method: 220, 38, 38; } .dark .swagger-ui .opblock-patch { --method: 147, 51, 234; } -/* --- Layout & hidden sections --- */ - -#swagger-ui { - width: 100%; +/* Deprecated method badge — darker gray for better contrast */ +.swagger-ui .opblock.opblock-deprecated .opblock-summary-method { + background: #525252; } +/* --- Hidden elements (no live server connection) --- */ #swagger-ui .information-container, .scheme-container, -.filter-container { - display: none; -} - -/* Hide parameter inputs (no live server connection) */ +.filter-container, .swagger-ui .parameters-container input, .swagger-ui .parameters-container select { display: none; @@ -54,11 +50,6 @@ color: unset; } -/* Deprecated method badge — darker gray for better contrast */ -.swagger-ui .opblock.opblock-deprecated .opblock-summary-method { - background: #525252; -} - /* --- Dark mode (nested) --- */ .dark .swagger-ui { From 496b073be7c979121a4aa6eeab4abf9cc3e73c50 Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Wed, 25 Mar 2026 17:10:11 -0500 Subject: [PATCH 22/23] Clean up js --- assets/js/swagger.js | 41 ++++++++++++++++++++++------------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/assets/js/swagger.js b/assets/js/swagger.js index 67ef4994fa..c521095c49 100644 --- a/assets/js/swagger.js +++ b/assets/js/swagger.js @@ -1,4 +1,6 @@ -const buildPermissionsPills = (items = []) => items.map(p => `${p}`).join(''); +const buildPermissionsPills = (items = []) => items + .map(p => `${p}`) + .join(''); const buildPermissionsBadge = (perms) => { const badge = document.createElement('div'); @@ -20,6 +22,23 @@ const buildSinceBadge = (version) => { return badge; }; +const extendDescriptionBlock = (perms, since) => (node) => { + const descWrapper = node?.querySelector('.opblock-description-wrapper'); + if (!descWrapper || descWrapper.querySelector('.x-extensions')) { + return; + } + + const container = document.createElement('div'); + container.className = 'x-extensions'; + if (since) { + container.appendChild(buildSinceBadge(since)); + } + if (perms) { + container.appendChild(buildPermissionsBadge(perms)); + } + descWrapper.prepend(container); +}; + const XExtensionsPlugin = () => ({ wrapComponents: { operation: (Original, system) => (props) => { @@ -32,24 +51,7 @@ const XExtensionsPlugin = () => ({ return h(Original, props); } - const ref = (node) => { - const descWrapper = node?.querySelector('.opblock-description-wrapper'); - if (!descWrapper || descWrapper.querySelector('.x-extensions')) { - return; - } - - const container = document.createElement('div'); - container.className = 'x-extensions'; - if (since) { - container.appendChild(buildSinceBadge(since)); - } - if (perms) { - container.appendChild(buildPermissionsBadge(perms)); - } - descWrapper.prepend(container); - }; - - return h('div', { ref }, h(Original, props)); + return h('div', { ref: extendDescriptionBlock(perms, since) }, h(Original, props)); } } }); @@ -57,6 +59,7 @@ const XExtensionsPlugin = () => ({ window.addEventListener('DOMContentLoaded', () => { SwaggerUIBundle({ dom_id: '#swagger-ui', + // TODO Update url: 'https://gist.githubusercontent.com/jkuester/a738de6aa6f96e5957b1f4ce56a3692a/raw/openapi.json', presets: [SwaggerUIBundle.presets.apis, SwaggerUIStandalonePreset], plugins: [XExtensionsPlugin], From 6dff597426134e6ddc8261d633e7d7b7c8c8b03d Mon Sep 17 00:00:00 2001 From: Joshua Kuestersteffen Date: Thu, 26 Mar 2026 07:57:44 -0500 Subject: [PATCH 23/23] Apply claude review changes --- assets/js/swagger.js | 27 +++++++++++----- .../reference/app-settings/token_login.md | 31 +++++++++---------- content/en/building/reference/openapi.md | 3 +- layouts/shortcodes/swagger.html | 6 ++-- 4 files changed, 39 insertions(+), 28 deletions(-) diff --git a/assets/js/swagger.js b/assets/js/swagger.js index c521095c49..7c994cc9fd 100644 --- a/assets/js/swagger.js +++ b/assets/js/swagger.js @@ -1,16 +1,29 @@ -const buildPermissionsPills = (items = []) => items - .map(p => `${p}`) - .join(''); +const buildPermissionPill = (text) => { + const pill = document.createElement('code'); + pill.className = 'x-permissions__pill'; + pill.textContent = text; + return pill; +}; const buildPermissionsBadge = (perms) => { const badge = document.createElement('div'); badge.className = 'x-permissions'; - const hasAllPills = buildPermissionsPills(perms.hasAll); - const hasAnyPills = buildPermissionsPills(perms.hasAny); - const hasAnyContent = hasAnyPills ? ` any of: (${hasAnyPills})` : ''; const line = document.createElement('span'); line.className = 'x-permissions__line'; - line.innerHTML = `Permissions - ${hasAllPills}${hasAnyContent}`; + + const label = document.createElement('span'); + label.className = 'x-permissions__label'; + label.textContent = 'Permissions - '; + line.appendChild(label); + + (perms.hasAll || []).forEach(p => line.appendChild(buildPermissionPill(p))); + + if (perms.hasAny?.length) { + line.appendChild(document.createTextNode(' any of: (')); + perms.hasAny.forEach(p => line.appendChild(buildPermissionPill(p))); + line.appendChild(document.createTextNode(')')); + } + badge.appendChild(line); return badge; }; diff --git a/content/en/building/reference/app-settings/token_login.md b/content/en/building/reference/app-settings/token_login.md index ed0f76ca90..eb72897995 100644 --- a/content/en/building/reference/app-settings/token_login.md +++ b/content/en/building/reference/app-settings/token_login.md @@ -11,11 +11,11 @@ aliases: - /apps/reference/app-settings/token_login --- -When creating or updating a user, sending a truthy value for the field `token_login` will enable Login by SMS for this user. -This action resets the user's password to an unknown string and generates a complex 64 character token, that is used to generate a token-login URL. +When creating or updating a user, sending a truthy value for the field `token_login` enables Login by SMS for this user. +This action resets the user's password to an unknown string and generates a complex 64-character token, used to generate a token-login URL. The URL is sent to the user's phone number by SMS, along with another (configurable) SMS that can contain additional information. -Accessing this link, before its expiration time, will log the user in directly - without the need of any other credentials. -The link can only be accessed once, the token becomes invalid after being used for one login. +Accessing this link before its expiration time logs the user in directly - without the need of any other credentials. +The link can only be accessed once, and the token becomes invalid after one login. The token expires in 24 hours, after which logging in is only possible by either generating a new token, or disabling `token_login` and manually setting a password. The SMS messages are stored in a doc of type `login_token`. These docs cannot be viewed as reports from the webapp, and can only be edited by admins, but their messages are visible in the Admin Message Queue page. @@ -23,18 +23,17 @@ The SMS messages are stored in a doc of type `login_token`. These docs cannot be To disable login by SMS for a user, update the user sending `token_login` with a `false` value. To regenerate the token, update the user sending `token_login` with a `true` value. -| `token_login` | user state | action | -|---------------|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------| -| undefined | new | None | -| undefined | existent, no token | None | -| undefined | existent, with token | None. Login by SMS remains enabled. Token is unchanged. | -| true | new | Login by SMS enabled. Token is generated and SMS is sent. | -| true | existent, no token | Password is reset. Login by SMS enabled. Token is generated and SMS is sent. Existent sessions are invalidated. | -| true | existent, with token | Password is reset. Login by SMS enabled. New token is generated and SMS is sent. Old token is invalid. Existent sessions are invalidated. | -| false | new | None. | -| false | existent, no token | None. | -| false | existent, with token | Request requires a password. Login by SMS is disabled. Old token is invalidated. Existent sessions are invalidated. | - +| `token_login` | user state | action | +|---------------|----------------------|------------------------------------------------------------------------------------------------------------------------| +| undefined | new | None | +| undefined | existing, no token | None | +| undefined | existing, with token | None. Login by SMS remains enabled. Token is unchanged. | +| true | new | Enables Login by SMS. Generates token and sends SMS. | +| true | existing, no token | Resets password. Enables Login by SMS. Generates token and sends SMS. Invalidates existing sessions. | +| true | existing, with token | Resets password. Enables Login by SMS. Generates new token and sends SMS. Invalidates old token and existing sessions. | +| false | new | None | +| false | existing, no token | None | +| false | existing, with token | Requires a password. Disables Login by SMS. Invalidates old token and existing sessions. | {{< see-also page="building/login" anchor="remote-login" >}} diff --git a/content/en/building/reference/openapi.md b/content/en/building/reference/openapi.md index 58d9aa1594..6c36924606 100644 --- a/content/en/building/reference/openapi.md +++ b/content/en/building/reference/openapi.md @@ -1,7 +1,6 @@ --- title: "REST API to interact with CHT Applications" -description: > - RESTful Application Programming Interfaces for integrating with CHT applications +description: RESTful Application Programming Interfaces for integrating with CHT applications linkTitle: "OpenAPI" weight: 2 toc: false diff --git a/layouts/shortcodes/swagger.html b/layouts/shortcodes/swagger.html index 86e90693f0..506d952d12 100644 --- a/layouts/shortcodes/swagger.html +++ b/layouts/shortcodes/swagger.html @@ -2,14 +2,14 @@ - + {{- $swaggerCss := resources.Get "css/swagger.css" -}}
- - + + {{- $swaggerJs := resources.Get "js/swagger.js" -}}