swagger: add support for oas/swagger documentation #226

basic swagger integration
This commit is contained in:
Sören Weber 2022-03-27 18:42:11 +02:00
parent 5376404039
commit f910477160
No known key found for this signature in database
GPG key ID: 07D17FF580AE7589
17 changed files with 3884 additions and 75 deletions

View file

@ -18,6 +18,7 @@ The theme is a fork of the great [Learn theme](https://github.com/matcornic/hugo
- Attachments files
- List child pages
- Mermaid diagram (flowchart, sequence, gantt)
- Swagger UI for OpenAPI Specifications
- Customizable look and feel
- Predefined (light, dark) and customizable color variants
- Buttons

View file

@ -24,6 +24,7 @@ See [what's new]({{% relref "basics/migration" %}}) within the latest update.
* [Attachments files]({{%relref "shortcodes/attachments" %}})
* [List child pages]({{%relref "shortcodes/children" %}})
* [Mermaid diagram]({{%relref "shortcodes/mermaid" %}}) (flowchart, sequence, gantt)
* [Swagger UI]({{%relref "shortcodes/swagger" %}}) for OpenAPI Specifications
* [Customizable look and feel]({{%relref "basics/customization"%}})
* [Predefined (light, dark) and customizable color variants]({{%relref "basics/generator" %}})
* [Buttons]({{%relref "shortcodes/button" %}})

View file

@ -52,9 +52,13 @@ Note that some of these parameters are explained in details in other sections of
# If set to false, load the Mermaid module on every page regardless if a Mermaid shortcode or Mermaid codefence is present
disableMermaid = false
# Specifies the remote location of the Mermaid js
customMermaidURL = "https://unpkg.com/mermaid@8.8.0/dist/mermaid.min.js"
customMermaidURL = "https://unpkg.com/mermaid/dist/mermaid.min.js"
# Initialization parameter for Mermaid, see Mermaid documentation
mermaidInitialize = "{ \"theme\": \"default\" }"
# Specifies the remote location of the RapiDoc js
customSwaggerURL = ""https://unpkg.com/rapidoc/dist/rapidoc-min.js"
# Initialization parameter for Swagger, see RapiDoc documentation
swaggerInitialize = "{ \"theme\": \"light\" }"
# Hide Next and Previous page buttons normally displayed full height beside content
disableNextPrev = true
# Order sections in menu by "weight" or "title". Default to "weight";

View file

@ -14,6 +14,12 @@ This document shows you what's new in the latest release. For a detailed list of
---
## 3.3.0
- **New**: The new shortcode `swagger` is available to include a UI for REST OpenAPI Specifications. See the [`documentation`]({{% relref "shortcodes/swagger" %}}) for available features.
---
## 3.2.0
- **Change**: In this release the Mermaid JavaScript library will only be loaded on demand if the page contains a Mermaid shortcode or is using Mermaid codefences. This changes the behavior of `disableMermaid` config option as follows: If a Mermaid shortcode or codefence is found, the option will be ignored and Mermaid will be loaded regardlessly.

View file

@ -22,6 +22,7 @@ Many thanks to [Andy Miller](https://github.com/rhukster) for initially creating
* [Lunr](https://lunrjs.com) - Enables a great search experience without the need for external, server-side, search services
* [Mermaid](https://mermaid-js.github.io/mermaid) - Generation of diagram and flowchart from text in a similar manner as markdown
* [Perfect Scrollbar](https://perfectscrollbar.com) - A minimalistic but perfect custom scrollbar plugin
* [RapiDoc](https://mrin9.github.io/RapiDoc) - Create beautiful, customizable, interactive API documentation from OpenAPI Specifications
## Tooling

View file

@ -211,7 +211,7 @@ The JSON object of your `config.toml` / frontmatter is forwarded into Mermaid's
See [Mermaid documentation](http://mermaid-js.github.io/mermaid/#/Setup?id=mermaidapi-configuration-defaults) for all allowed settings.
The `theme` setting is somewhat special as it can be set by your used color variant. This will be the sitewide default and can - again - be overridden by your settings in `config.toml`, frontmatter or diagram directives.
The `theme` setting can also be set by your used color variant. This will be the sitewide default and can - again - be overridden by your settings in `config.toml`, frontmatter or diagram directives.
{{% notice note %}}
If you want to use mermaid codefences, you have to turn off `guessSyntax` for the `markup.highlight` setting.

View file

@ -0,0 +1,35 @@
---
description: "Adds UI for your Swagger / OpenAPI Specifications"
title: "Swagger"
---
This shortcode uses the [RapiDoc](https://mrin9.github.io/RapiDoc) library to display your OpenAPI Specifications.
## Configuration
Swagger is configured with default settings. You can customize Swagger's default settings for all of your files thru a JSON object in your `config.toml` or override these settings per page thru your pages frontmatter.
The JSON object of your `config.toml` / frontmatter is forwarded into Swagger's initialization. At the moment, only the `theme` setting is supported.
The `theme` setting can also be set by your used color variant. This will be the sitewide default and can - again - be overridden by your settings in `config.toml`, or frontmatter.
### Example
````toml
[params]
swaggerInitialize = "{ \"theme\": \"dark\" }"
````
## Usage
Just insert your Mermaid code in the `mermaid` shortcode like this:
````go
{{</* swagger src="https://petstore3.swagger.io/api/v3/openapi.json" */>}}
````
The `src` parameter is mandatory and can be either an absolute URL or a relative one pointing into your Hugo file system.
## Example
{{< swagger src="https://petstore3.swagger.io/api/v3/openapi.json" >}}

View file

@ -0,0 +1,5 @@
---
description: "Adds UI fer yer Swaggerrr / OpenAPI files"
title: "Swaggerrr"
---
{{< piratify >}}

View file

@ -28,14 +28,41 @@
{{- $.Scratch.Set "mermaidInitialize" "{}" }}
{{- end }}
<script>
if (typeof mermaid != 'undefined' && typeof mermaid.mermaidAPI != 'undefined') {
var config = JSON.parse({{ $.Scratch.Get "mermaidInitialize" }});
mermaid.initialize( Object.assign( { "securityLevel": "antiscript", "startOnLoad": false }, config ) );
if( config.theme ){
var write_style = variants.findLoadedStylesheet( 'variant-style' );
write_style.setProperty( '--CONFIG-MERMAID-theme', config.theme );
function useMermaid( config ){
if (typeof mermaid != 'undefined' && typeof mermaid.mermaidAPI != 'undefined') {
mermaid.initialize( Object.assign( { "securityLevel": "antiscript", "startOnLoad": false }, config ) );
if( config.theme ){
var write_style = variants.findLoadedStylesheet( 'variant-style' );
write_style.setProperty( '--CONFIG-MERMAID-theme', config.theme );
}
}
}
useMermaid( JSON.parse({{ $.Scratch.Get "mermaidInitialize" }}) );
</script>
{{- end }}
{{- if (or (.Page.Store.Get "hasSwagger") (and (ne .Params.disableSwagger nil) (not .Params.disableSwagger)) (and (ne .Site.Params.disableSwagger nil) (not .Site.Params.disableSwagger)) ) }}
{{- if isset .Params "customswaggerurl" }}
<script src="{{ .Params.customSwaggerURL }}"></script>
{{- else if isset .Site.Params "customswaggerurl" }}
<script src="{{ .Site.Params.customSwaggerURL }}"></script>
{{- else }}
<script src="{{ "/js/rapidoc-min.js" | relURL }}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}"></script>
{{- end }}
{{- if isset .Params "swaggerinitialize" }}
{{- $.Scratch.Set "swaggerInitialize" .Params.swaggerInitialize }}
{{- else if isset .Site.Params "swaggerinitialize" }}
{{- $.Scratch.Set "swaggerInitialize" .Site.Params.swaggerInitialize }}
{{- else }}
{{- $.Scratch.Set "swaggerInitialize" "{}" }}
{{- end }}
<script>
function useSwagger( config ){
if( config.theme ){
var write_style = variants.findLoadedStylesheet( 'variant-style' );
write_style.setProperty( '--CONFIG-SWAGGER-theme', config.theme );
}
}
useSwagger( JSON.parse({{ $.Scratch.Get "swaggerInitialize" }}) );
</script>
{{- end }}
<script src="{{"js/theme.js" | relURL}}{{ if not .Site.Params.disableAssetsBusting }}?{{ now.Unix }}{{ end }}"></script>

View file

@ -0,0 +1,17 @@
{{- $original := .Get "src" }}
<rapi-doc
allow-spec-file-download="true"
d-bg-color=""
default-schema-tab="example"
layout="column"
d-primary-color=""
render-style="view"
schema-description-expanded="true"
schema-style="table"
show-header="false"
spec-url = "{{ $original | relURL }}"
sort-tags="true"
d-text-color=""
theme="light"
></rapi-doc>
{{- .Page.Store.Set "hasSwagger" true }}

View file

@ -27,7 +27,8 @@
--CODE-INLINE-BG-color: #282a36; /* color for inline code background */
--CODE-INLINE-BORDER-color: #464646; /* color of inline code border */
--MERMAID-theme: dark; /* name of the default mermaid theme for this variant, can be overridden in config.toml */
--MERMAID-theme: dark; /* name of the default Mermaid theme for this variant, can be overridden in config.toml */
--SWAGGER-theme: dark; /* name of the default Swagger theme for this variant, can be overridden in config.toml */
--TAG-BG-color: #04d1b5; /* Background color of menu header */

View file

@ -22,7 +22,8 @@
--CODE-INLINE-BG-color: #2d2d2d; /* color for inline code background */
--CODE-INLINE-BORDER-color: #464646; /* color of inline code border */
--MERMAID-theme: dark; /* name of the default mermaid theme for this variant, can be overridden in config.toml */
--MERMAID-theme: dark; /* name of the default Mermaid theme for this variant, can be overridden in config.toml */
--SWAGGER-theme: dark; /* name of the default Swagger theme for this variant, can be overridden in config.toml */
--MENU-HOME-LINK-color: #323232; /* Color of the home button text */
--MENU-HOME-LINK-HOVER-color: #5e5e5e; /* Color of the hovered home button text */

View file

@ -22,6 +22,7 @@
--INTERNAL-CODE-INLINE-BORDER-color: var(--CODE-INLINE-BORDER-color, #fbf0cb);
--INTERNAL-MERMAID-theme: var(--CONFIG-MERMAID-theme, var(--MERMAID-theme, default));
--INTERNAL-SWAGGER-theme: var(--CONFIG-SWAGGER-theme, var(--SWAGGER-theme, light));
--INTERNAL-TAG-BG-color: var(--TAG-BG-color, var(--INTERNAL-MENU-HEADER-BG-color));

3670
static/js/rapidoc-min.js vendored Normal file

File diff suppressed because one or more lines are too long

View file

@ -1,3 +1,4 @@
var theme = true;
var isIE = /*@cc_on!@*/false || !!document.documentMode;
if( isIE ){
// we don't support sidebar flyout in IE
@ -61,39 +62,110 @@ function restoreTabSelections() {
}
}
function initMermaid() {
if (typeof mermaid != 'undefined' && typeof mermaid.mermaidAPI != 'undefined') {
function initMermaid( update ) {
// we are either in update or initialization mode;
// during initialization, we want to edit the DOM;
// during update we only want to execute if something chanegd
var decodeHTML = function( html ){
var txt = document.createElement( 'textarea' );
txt.innerHTML = html;
return txt.value;
};
var parseGraph = function( graph ){
var d = /^\s*(%%\s*\{\s*\w+\s*:([^%]*?)%%\s*\n?)/g;
var m = d.exec( graph );
var dir = {};
var content = graph;
if( m && m.length == 3 ){
dir = JSON.parse( '{ "dummy": ' + m[2] ).dummy;
content = graph.substring( d.lastIndex );
}
return { dir: dir, content: content };
};
var serializeGraph = function( graph ){
return '%%{init: ' + JSON.stringify( graph.dir ) + '}%%\n' + graph.content;
};
var init_func = function(){
state.is_initialized = true;
var is_initialized = false;
var theme = variants.getColorValue( 'MERMAID-theme' );
document.querySelectorAll('.mermaid').forEach( function( element ){
var content = element.innerHTML.replace(/&amp;/g, '&').trim();
var parse = parseGraph( decodeHTML( element.innerHTML ) );
var d = /^(%%\s*\{\s*\w+\s*:([^%]*?)%%\s*\n?)/g;
var m = d.exec( content );
var dir = {};
if( m && m.length == 3 ){
dir = JSON.parse( '{ "dummy": ' + m[2] ).dummy;
content = content.substring( d.lastIndex );
if( parse.dir.theme ){
parse.dir.relearn_user_theme = true;
}
if( !parse.dir.relearn_user_theme ){
parse.dir.theme = theme;
}
is_initialized = true;
if( dir.theme ){
dir.relearn_user_theme = true;
}
if( !dir.relearn_user_theme ){
dir.theme = getComputedStyle( document.documentElement ).getPropertyValue( '--INTERNAL-MERMAID-theme' ).replace( /\s/g, "" );
}
dir.relearn_initialized = true;
content = '%%{init: ' + JSON.stringify( dir ) + '}%%\n' + content;
element.innerHTML = content;
var graph = serializeGraph( parse );
element.innerHTML = graph;
var new_element = document.createElement( 'div' );
new_element.classList.add( 'mermaid-container' );
new_element.innerHTML = '<div class="mermaid-code">' + content + '</div>' + element.outerHTML;
new_element.innerHTML = '<div class="mermaid-code">' + graph + '</div>' + element.outerHTML;
element.parentNode.replaceChild( new_element, element );
});
return is_initialized;
}
var update_func = function(){
var is_initialized = false;
var theme = variants.getColorValue( 'MERMAID-theme' );
document.querySelectorAll( '.mermaid-container' ).forEach( function( e ){
var element = e.querySelector( '.mermaid' );
var code = e.querySelector( '.mermaid-code' );
var parse = parseGraph( decodeHTML( code.innerHTML ) );
if( parse.dir.relearn_user_theme ){
return;
}
if( parse.dir.theme == theme ){
return;
}
is_initialized = true;
parse.dir.theme = theme;
var graph = serializeGraph( parse );
element.removeAttribute('data-processed');
element.innerHTML = graph;
code.innerHTML = graph;
});
return is_initialized;
};
var state = this;
if( update && !state.is_initialized ){
return;
}
if( typeof variants == 'undefined' ){
return;
}
if( typeof mermaid == 'undefined' || typeof mermaid.mermaidAPI == 'undefined' ){
return;
}
var is_initialized = ( update ? update_func() : init_func() );
if( is_initialized ){
mermaid.init();
$(".mermaid svg").svgPanZoom({});
}
}
function initSwagger( update ){
if( typeof variants == 'undefined' ){
return;
}
var theme = variants.getColorValue( 'SWAGGER-theme' );
document.querySelectorAll( 'rapi-doc' ).forEach( function( e ){
e.setAttribute( 'theme', theme );
});
}
function initAnchorClipboard(){
document.querySelectorAll( 'h1~h2,h1~h3,h1~h4,h1~h5,h1~h6').forEach( function( element ){
var url = encodeURI(document.location.origin + document.location.pathname);
@ -454,6 +526,7 @@ var getUrlParameter = function getUrlParameter(sPageURL) {
jQuery(function() {
initArrowNav();
initMermaid();
initSwagger();
initMenuScrollbar();
scrollToActiveMenu();
initLightbox();

View file

@ -36,45 +36,11 @@ var variants = {
select.value = variant;
}
setTimeout( function(){
if( typeof mermaid != 'undefined' && typeof mermaid.mermaidAPI != 'undefined' && document.querySelector( '.mermaid > svg' ) ){
var is_intialized = false;
var theme = this.getColorValue( 'MERMAID-theme' );
document.querySelectorAll( '.mermaid-container' ).forEach( function( e ){
var element = e.querySelector( '.mermaid' );
var code = e.querySelector( '.mermaid-code' );
var content = this.decodeHTML( code.innerHTML );
var d = /^(%%\s*\{\s*\w+\s*:([^%]*?)%%\s*\n?)/g;
var m = d.exec( content );
var dir = {};
if( m && m.length == 3 ){
dir = JSON.parse( '{ "dummy": ' + m[2] ).dummy;
content = content.substring( d.lastIndex );
}
if( !dir.relearn_initialized ){
return;
}
is_initialized = true;
if( dir.relearn_user_theme ){
return;
}
if( dir.theme != theme ){
dir.theme = theme;
content = '%%{init: ' + JSON.stringify( dir ) + '}%%\n' + content;
element.removeAttribute('data-processed');
element.innerHTML = content;
code.innerHTML = content;
}
}.bind( this ) );
if( is_initialized ){
mermaid.init();
$(".mermaid svg").svgPanZoom({});
}
if( window.theme ){
initMermaid( true );
initSwagger( true );
}
}.bind( this ), 25 );
// remove selection, because if some uses an arrow navigation"
// by pressing the left or right cursor key, we will automatically
// select a different style
@ -244,12 +210,6 @@ var variants = {
a.click();
},
decodeHTML: function( html ){
var txt = document.createElement( 'textarea' );
txt.innerHTML = html;
return txt.value;
},
getStylesheet: function(){
this.download( this.generateStylesheet(), 'text/css', 'theme-' + this.customvariantname + '.css' );
},
@ -416,6 +376,7 @@ var variants = {
this.styleGraphGroup( '#mainheadings', 'MAIN-BG-color' );
this.styleGraphGroup( '#inlinecode', 'CODE-INLINE-BG-color' );
this.styleGraphGroup( '#blockcode', 'CODE-BLOCK-BG-color' );
this.styleGraphGroup( '#thirdparty', 'MAIN-BG-color' );
this.styleGraphGroup( '#coloredboxes', 'BOX-BG-color' );
this.styleGraphGroup( '#menu', 'MENU-SECTIONS-BG-color' );
this.styleGraphGroup( '#menuheader', 'MENU-HEADER-BG-color' );
@ -479,6 +440,10 @@ var variants = {
' direction LR\n' +
g_groups[ 'code blocks' ].reduce( function( a, e ){ return a + ' ' + this.generateGraphGroupedEdge( e ) + '\n'; }.bind( this ), '' ) +
' end\n' +
' subgraph thirdparty["3rd party"]\n' +
' direction LR\n' +
g_groups[ '3rd party' ].reduce( function( a, e ){ return a + ' ' + this.generateGraphGroupedEdge( e ) + '\n'; }.bind( this ), '' ) +
' end\n' +
' subgraph coloredboxes["colored boxes"]\n' +
' direction LR\n' +
g_groups[ 'colored boxes' ].reduce( function( a, e ){ return a + ' ' + this.generateGraphGroupedEdge( e ) + '\n'; }.bind( this ), '' ) +
@ -515,7 +480,8 @@ var variants = {
{ name: 'CODE-INLINE-BG-color', group: 'inline code', default: '#fffae9', tooltip: 'background color of inline code', },
{ name: 'CODE-INLINE-BORDER-color', group: 'inline code', default: '#fbf0cb', tooltip: 'border color of inline code', },
{ name: 'MERMAID-theme', group: 'mermaid', default: 'default', tooltip: 'name of the default mermaid theme for this variant, can be overridden in config.toml', },
{ name: 'MERMAID-theme', group: '3rd party', default: 'default', tooltip: 'name of the default Mermaid theme for this variant, can be overridden in config.toml', },
{ name: 'SWAGGER-theme', group: '3rd party', default: 'default', tooltip: 'name of the default Swagger theme for this variant, can be overridden in config.toml', },
{ name: 'MENU-HEADER-BG-color', group: 'header', default: '#7dc903', tooltip: 'background color of menu header', },
{ name: 'MENU-HEADER-BORDER-color', group: 'header', fallback: 'MENU-HEADER-BG-color', tooltip: 'separator color of menu header', },

View file

@ -5,7 +5,7 @@ description = "A theme for Hugo designed for documentation"
homepage = "https://github.com/McShelby/hugo-theme-relearn"
demosite = "https://mcshelby.github.io/hugo-theme-relearn"
tags = ["dark", "dark mode", "docs", "light", "multilingual", "responsive"]
features = ["dark mode", "documentation", "expand", "include", "light mode", "menu", "mermaid", "multilingual", "nested sections", "notice", "search", "tabs", "themeable"]
features = ["dark mode", "documentation", "expand", "include", "light mode", "menu", "mermaid", "multilingual", "nested sections", "notice", "oas", "search", "swagger", "tabs", "themeable"]
[module]
[module.hugoVersion]