Skip to content

Commit

Permalink
Merge pull request #52 from go-andiamo/ui-enhancements
Browse files Browse the repository at this point in the history
UI Enhancements
  • Loading branch information
marrow16 authored May 8, 2024
2 parents aa62a30 + 29ffb24 commit d71cfb1
Show file tree
Hide file tree
Showing 12 changed files with 218 additions and 139 deletions.
68 changes: 63 additions & 5 deletions _examples/multi_ui/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,22 +11,60 @@ func (a *api) SetupRoutes(r chi.Router) error {

var apiDef = chioas.Definition{
DocOptions: chioas.DocOptions{
ServeDocs: true, // makes docs served as interactive UI on /docs/index.htm
UIStyle: chioas.Redoc,
ServeDocs: true, // makes docs served as interactive UI on /docs/index.htm
UIStyle: chioas.Redoc,
StylesOverride: styling,
RedocOptions: chioas.RedocOptions{
HeaderHtml: `<div style="display:flex; margin:10px; justify-content:center;flex-wrap: wrap;">
<a class="chioasbtn" href="../swagger/index.html">Swagger</a>
<a class="chioasbtn" href="../rapidoc/index.html">Rapidoc</a>
</div>`,
},
AlternateUIDocs: chioas.AlternateUIDocs{
"/swagger": {
UIStyle: chioas.Swagger,
UIStyle: chioas.Swagger,
StylesOverride: styling,
SwaggerOptions: chioas.SwaggerOptions{
DeepLinking: true,
HeaderHtml: `<div style="display:flex; margin:10px; justify-content:center;flex-wrap: wrap;">
<a class="chioasbtn" href="../docs/index.html">Redoc</a>
<a class="chioasbtn" href="../rapidoc/index.html">Rapidoc</a>
</div>`,
},
},
"/rapidoc": {
UIStyle: chioas.Rapidoc,
UIStyle: chioas.Rapidoc,
StylesOverride: styling,
RapidocOptions: &chioas.RapidocOptions{
ShowHeader: true,
HeadingText: "Petstore",
Theme: "dark",
ShowMethodInNavBar: "false",
ShowMethodInNavBar: "as-colored-block",
UsePathInNavBar: true,
SchemaStyle: "table",
HeadScript: `
function getRapiDoc(){
return document.getElementById("thedoc");
}
function toggleView() {
let currRender = getRapiDoc().getAttribute('render-style');
let newRender = currRender === "read" ? "view" : "read";
getRapiDoc().setAttribute('render-style', newRender );
}
function toggleTheme(){
if (getRapiDoc().getAttribute('theme') === 'dark'){
getRapiDoc().setAttribute('theme',"light");
}
else{
getRapiDoc().setAttribute('theme',"dark");
}
}`,
InnerHtml: `<div style="display:flex; margin:10px; justify-content:center;flex-wrap: wrap;">
<button class="chioasbtn" onclick="toggleView()">Change View</button>
<button class="chioasbtn" onclick="toggleTheme()" style="margin-right:30px">Change Theme</button>
<a class="chioasbtn" href="../docs/index.html">Redoc</a>
<a class="chioasbtn" href="../swagger/index.html">Swagger</a>
</div>`,
},
},
},
Expand Down Expand Up @@ -80,6 +118,26 @@ Store](https://github.com/swagger-api/swagger-petstore/blob/master/src/main/reso
Components: &components,
}

const styling = `.chioasbtn{
min-width: 100px;
background-color: #47AFE8;
color: #fff;
font-size: 12px;
display: block;
border: none;
margin: 2px;
border-radius: 2px;
cursor: pointer;
outline: none;
text-align: center;
padding: 4px;
text-decoration: none;
font-family: sans-serif;
}
.chioasbtn:visited{
color: #fff;
}`

var components = chioas.Components{
Schemas: chioas.Schemas{
{
Expand Down
64 changes: 14 additions & 50 deletions _examples/petstore/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,24 @@ import (
//go:embed status_schema.yaml petstore-logo.png
var supportFilesFS embed.FS

// we're using our own customized docs html template
//
//go:embed index_template.html
var customizedSwaggerTemplate string

var apiDef = chioas.Definition{
DocOptions: chioas.DocOptions{
ServeDocs: true, // makes docs served as interactive UI on /docs/index.htm
UIStyle: chioas.Swagger,
ServeDocs: true, // makes docs served as interactive UI on /docs/index.htm
UIStyle: chioas.Swagger,
StylesOverride: `.logo img {
padding: inherit;
margin: auto;
width: 200px;
display: block;
}`,
SwaggerOptions: chioas.SwaggerOptions{
HeaderHtml: `<div class="logo" style="align-content: center">
<img src="./petstore-logo.png" alt="pet store logo">
</div>`,
},
SupportFiles: http.FileServer(http.FS(supportFilesFS)),
SupportFilesStripPrefix: true,
DocTemplate: customizedSwaggerTemplate, // customized template to show logo
CheckRefs: true, // make sure that any $ref's are valid!
CheckRefs: true, // make sure that any $ref's are valid!
},
Info: chioas.Info{
Title: "Swagger Petstore - OpenAPI 3.0",
Expand Down Expand Up @@ -126,44 +131,3 @@ func commenter(handlerMethod string, comments ...string) []string {
func (a *api) SetupRoutes(r chi.Router) error {
return a.Definition.SetupRoutes(r, a)
}

/*
// customizing the html template (to show a logo) - copied from chioas/doc_options.go defaultSwaggerTemplate
const customizedSwaggerTemplate = `<!DOCTYPE html>
<html lang="en">
<head>
<title>{{.title}}</title>
<meta charset="utf-8" />
<link rel="stylesheet" type="text/css" href="./swagger-ui.css" />
<link rel="stylesheet" type="text/css" href="./index.css" />
<link rel="icon" type="image/png" href="./favicon-32x32.png" sizes="32x32" />
<link rel="icon" type="image/png" href="./favicon-16x16.png" sizes="16x16" />
<style>{{.stylesOverride}}</style>
<style>
.logo img {
padding: inherit;
margin:auto;
width: 200px;
display: block;
}
</style>
</head>
<body>
<div class="logo">
<img src="petstore-logo.png" alt="pet store logo">
</div>
<div id="swagger-ui"></div>
<script src="./swagger-ui-bundle.js" charset="UTF-8"> </script>
<script src="./swagger-ui-standalone-preset.js" charset="UTF-8"> </script>
<script>
window.onload = function() {
let cfg = {{.swaggeropts}}
{{.swaggerpresets}}
{{.swaggerplugins}}
const ui = SwaggerUIBundle(cfg)
window.ui = ui
}
</script>
</body>
</html>`
*/
38 changes: 0 additions & 38 deletions _examples/petstore/index_template.html

This file was deleted.

23 changes: 22 additions & 1 deletion doc_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -194,26 +194,44 @@ func (d *DocOptions) getTemplateData() (specName string, data map[string]any) {
htmlTagSwaggerPlugins: plugins,
htmlTagFavIcons: optionsFavIcons(d.SwaggerOptions),
}
addHeaderAndScripts(data, swaggerOpts)
case Rapidoc:
data = optionsToMap(d.RapidocOptions)
data[htmlTagTitle] = defValue(d.Title, defaultTitle)
data[htmlTagStylesOverride] = template.CSS(d.StylesOverride)
data[htmlTagSpecName] = specName
data[htmlTagFavIcons] = optionsFavIcons(d.RapidocOptions)
default:
redocOpts := optionsToMap(d.RedocOptions)
data = map[string]any{
htmlTagTitle: defValue(d.Title, defaultTitle),
htmlTagStylesOverride: template.CSS(defValue(d.StylesOverride, defaultRedocStylesOverride)),
htmlTagSpecName: specName,
htmlTagRedocOpts: optionsToMap(d.RedocOptions),
htmlTagRedocOpts: redocOpts,
htmlTagRedocUrl: defValue(d.RedocJsUrl, defaultRedocJsUrl),
htmlTagTryUrl: defValue(d.TryJsUrl, defaultTryJsUrl),
htmlTagFavIcons: optionsFavIcons(d.RedocOptions),
}
addHeaderAndScripts(data, redocOpts)
}
return
}

func addHeaderAndScripts(data, opts map[string]any) {
if v, ok := opts[htmlTagHeaderHtml]; ok {
data[htmlTagHeaderHtml] = v
delete(opts, htmlTagHeaderHtml)
}
if v, ok := opts[htmlTagHeadScript]; ok {
data[htmlTagHeadScript] = v
delete(opts, htmlTagHeadScript)
}
if v, ok := opts[htmlTagBodyScript]; ok {
data[htmlTagBodyScript] = v
delete(opts, htmlTagBodyScript)
}
}

func setupCachedRoutes(def *Definition, asJson bool, specData []byte, docsRoute *chi.Mux, tmp *template.Template, inData map[string]any, indexPage, specName string) (err error) {
indexData, err := buildIndexData(tmp, inData)
if err != nil {
Expand Down Expand Up @@ -385,6 +403,9 @@ const (
htmlTagSwaggerPresets = "swaggerpresets"
htmlTagSwaggerPlugins = "swaggerplugins"
htmlTagFavIcons = "favIcons"
htmlTagHeadScript = "headScript"
htmlTagBodyScript = "bodyScript"
htmlTagHeaderHtml = "headerHtml"
)

func defValue(v, def string) string {
Expand Down
6 changes: 6 additions & 0 deletions doc_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,9 @@ func TestDocOptions_SwaggerOptions(t *testing.T) {
DeepLinking: true,
Plugins: []SwaggerPlugin{"MyPlugin1", "MyPlugin2"},
Presets: []SwaggerPreset{"MyPreset1", "MyPreset2"},
HeaderHtml: `<div>HEADER</div>`,
HeadScript: `head();`,
BodyScript: `body();`,
},
},
}
Expand All @@ -516,6 +519,9 @@ func TestDocOptions_SwaggerOptions(t *testing.T) {
assert.Contains(t, data, `"url":"spec.yaml"`)
assert.Contains(t, data, `cfg.presets = [MyPreset1,MyPreset2]`)
assert.Contains(t, data, `cfg.plugins = [MyPlugin1,MyPlugin2]`)
assert.Contains(t, data, `<div>HEADER</div>`)
assert.Contains(t, data, `<script>head();</script>`)
assert.Contains(t, data, `<script>body();</script>`)

expectedSupportFiles := map[string]string{
"favicon-16x16.png": "image/png",
Expand Down
5 changes: 4 additions & 1 deletion docs_alt_ui.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,22 +108,25 @@ func (d *AlternateUIDoc) getTemplateData() (specName string, data map[string]any
htmlTagSwaggerPlugins: plugins,
htmlTagFavIcons: optionsFavIcons(d.SwaggerOptions),
}
addHeaderAndScripts(data, swaggerOpts)
case Rapidoc:
data = optionsToMap(d.RapidocOptions)
data[htmlTagTitle] = defValue(d.Title, defaultTitle)
data[htmlTagStylesOverride] = template.CSS(d.StylesOverride)
data[htmlTagSpecName] = specName
data[htmlTagFavIcons] = optionsFavIcons(d.RapidocOptions)
default:
redocOpts := optionsToMap(d.RedocOptions)
data = map[string]any{
htmlTagTitle: defValue(d.Title, defaultTitle),
htmlTagStylesOverride: template.CSS(defValue(d.StylesOverride, defaultRedocStylesOverride)),
htmlTagSpecName: specName,
htmlTagRedocOpts: optionsToMap(d.RedocOptions),
htmlTagRedocOpts: redocOpts,
htmlTagRedocUrl: defValue(d.RedocJsUrl, defaultRedocJsUrl),
htmlTagTryUrl: defValue(d.TryJsUrl, defaultTryJsUrl),
htmlTagFavIcons: optionsFavIcons(d.RedocOptions),
}
addHeaderAndScripts(data, redocOpts)
}
return
}
14 changes: 12 additions & 2 deletions ui_rapidoc_options.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ const defaultRapidocTemplate = `<!doctype html>
<script defer="defer" src="rapidoc-min.js"></script>
{{.favIcons}}
<style>{{.stylesOverride}}</style>
{{.headScript}}
</head>
<body>
<rapi-doc id="thedoc" spec-url="{{.specName}}" {{.add_atts}}>
{{.logo}}
{{.innerHtml}}
</rapi-doc>
{{.bodyScript}}
</body>
</html>`

Expand Down Expand Up @@ -58,8 +60,10 @@ type RapidocOptions struct {
// LogoSrc is the src for Rapidoc logo
LogoSrc string
// InnerHtml is any inner HTML for the <rapi-doc> element
InnerHtml template.HTML
FavIcons FavIcons
InnerHtml template.HTML
HeadScript template.JS
BodyScript template.JS
FavIcons FavIcons
// AdditionalAttributes is used to add any rapidoc attributes
// not covered by other options
//
Expand Down Expand Up @@ -166,6 +170,12 @@ func (o RapidocOptions) ToMap() map[string]any {
if o.InnerHtml != "" {
result["innerHtml"] = o.InnerHtml
}
if o.HeadScript != "" {
result[htmlTagHeadScript] = template.HTML(`<script>` + o.HeadScript + `</script>`)
}
if o.BodyScript != "" {
result[htmlTagBodyScript] = template.HTML(`<script>` + o.BodyScript + `</script>`)
}
return result
}

Expand Down
8 changes: 6 additions & 2 deletions ui_rapidoc_options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,16 @@ func TestRapidocOptions_ToMap(t *testing.T) {
<img src="dog.png" style="width:40px; margin-right: 20px"> <span style="color:#fff"> <b>nav-logo</b> slot </span>
</div>`
o = &RapidocOptions{
InnerHtml: testInner,
InnerHtml: testInner,
HeadScript: `head();`,
BodyScript: `body();`,
}
m = o.ToMap()
assert.Equal(t, 2, len(m))
assert.Equal(t, 4, len(m))
inner := m["innerHtml"].(template.HTML)
assert.Equal(t, testInner, string(inner))
assert.Equal(t, template.HTML(`<script>head();</script>`), m[htmlTagHeadScript])
assert.Equal(t, template.HTML(`<script>body();</script>`), m[htmlTagBodyScript])
}

func TestRapidocOptions_OverrideFavIcons(t *testing.T) {
Expand Down
Loading

0 comments on commit d71cfb1

Please sign in to comment.