Enhance OpenAPI UI components and styling

This commit is contained in:
Alexander Shabarshov 2025-04-08 15:24:28 +01:00
parent c1cac17c6b
commit 77ed16b75f
8 changed files with 52 additions and 18 deletions

View File

@ -42,6 +42,5 @@
[Parameter]
public OpenApiComponents? Value { get; set; }
private IList<OpenApiParameter> ToList(OpenApiParameter val)
=> new List<OpenApiParameter>() { val };
private IList<OpenApiParameter> ToList(OpenApiParameter val) => new List<OpenApiParameter>() { val };
}

View File

@ -1,8 +1,8 @@
<CascadingValue Name="OpenAPIUI_TOC_Parent" Value="_anchor">
<div id="@_anchor" class="expander @Class">
<div class="ex-header @HeaderClass">
<div class="ex-header @HeaderClass" onclick="@(() => Toggle())">
@Title
<div onclick="@(() => Toggle())">
<div>
@if (Collapsed)
{
<svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">

View File

@ -54,9 +54,9 @@
var example = GenerateExampleData();
if (!string.IsNullOrWhiteSpace(example))
{
<div class="example-data">
<h3>Example Data</h3>
<pre>@GenerateExampleData()</pre>
<div class="example">
<h3 class="e-title">Example Data</h3>
<pre class="e-item">@GenerateExampleData()</pre>
</div>
}
@ -133,7 +133,9 @@
}
else
{
exampleData[content.Key] = GenerateExampleFromSchema(content.Value.Schema);
var ex = GenerateExampleFromSchema(content.Value.Schema);
if ( ex != null )
exampleData[content.Key] = ex;
}
}
}
@ -144,32 +146,39 @@
;
}
private object GenerateExampleFromSchema(OpenApiSchema? schema)
private object? GenerateExampleFromSchema(OpenApiSchema? schema)
{
if (schema == null)
{
return new object();
return null;
}
if (schema.Type == "object" && schema.Properties != null)
{
var obj = new Dictionary<string, object>();
var obj = new Dictionary<string, object?>();
foreach (var property in schema.Properties)
{
obj[property.Key] = GenerateExampleFromSchema(property.Value);
var ex = GenerateExampleFromSchema(property.Value);
if (ex != null)
obj[property.Key] = ex;
}
if ( obj.Count == 0 )
return null;
return obj;
}
if (schema.Type == "array" && schema.Items != null)
{
return new[] { GenerateExampleFromSchema(schema.Items) };
var ex = GenerateExampleFromSchema(schema.Items);
if (ex == null)
return null;
return new[] { ex };
}
return schema.Default ?? schema.Example ?? GetDefaultValueForType(schema.Type);
}
private object GetDefaultValueForType(string? type)
private object? GetDefaultValueForType(string? type)
{
return type switch
{
@ -177,7 +186,7 @@
"integer" => 0,
"number" => 0.0,
"boolean" => false,
_ => new object()
_ => null
};
}
}

View File

@ -2,7 +2,7 @@
@implements IDisposable
<div class="@Class">
<a @onclick="(async() => await ScrolltoAnchor())">@Title</a>
<a class="toc-text" @onclick="(async() => await ScrolltoAnchor())">@Title</a>
@foreach (var child in Tree.GetChildren(Anchor))
{
<TableOfContents Title="@child.Name" Anchor="@child.Anchor" class="toc-level" Tree="@Tree"/>

View File

@ -20,6 +20,7 @@ public interface ITableOfContentsTree
{
public event EventHandler Changed;
void Clear();
void Add(string name, string anchor, string parentAnchor, bool collapsed);
void Collapse(string anchor, bool collapsed);
bool IsCollapsed(string anchor);

View File

@ -13,7 +13,9 @@
<CascadingValue Value="@_api" IsFixed="true">
<CascadingValue Name="OpenAPIUI_TOC" Value="@_tree" IsFixed="true">
<Expander Title="Contents" Collapsed="true" HeaderClass="h1">
<TableOfContents Tree="@_tree" />
</Expander>
<HeaderControl Value="@_api.Info" DownloadUrl="@Url" />
<ServersControl Value="@_api.Servers" />
@ -70,6 +72,9 @@
if (loadedFromUrl || loadedFromJson)
return;
_tree.Clear();
if (!string.IsNullOrWhiteSpace(Json))
LoadFromJson();
else if (!string.IsNullOrWhiteSpace(Url))

View File

@ -11,6 +11,12 @@ internal class TableOfContentsTree : ITableOfContentsTree
public event EventHandler Changed;
public void Clear()
{
_nodes.Clear();
_order.Clear();
}
public void Add(string name, string anchor, string parentAnchor, bool collapsed)
{
if (_nodes.ContainsKey(anchor))

View File

@ -2,11 +2,23 @@
margin-left: 20px;
}
.toc-text {
cursor: pointer;
}
.toc-text:hover {
text-decoration: underline !important;
}
.descriminator {
}
.example {}
.e-item {}
.e-item {
font-family: monospace;
font-size: var(--oa-font-small);
color: lightseagreen;
}
.e-name {}
.e-title {}
@ -18,6 +30,7 @@
.ex-header {
display: flex;
flex-direction: row;
cursor: pointer;
}
.header {}
@ -73,6 +86,7 @@
padding: 5px;
border-radius: 5px;
color: var(--oa-fg-lighter);
cursor: pointer;
}
.op-summary {
width: 100%;