feat: Group API methods and improve TOC
- Add method grouping by model/actor prefix - Introduce DocMethodGroup struct for grouped methods - Refactor TOC to display methods by groups - Add collapsible sections for method groups and methods - Improve CSS for better presentation of grouped content
This commit is contained in:
@@ -35,4 +35,3 @@ we are in architecture mode
|
|||||||
other requirements
|
other requirements
|
||||||
|
|
||||||
- for encryption/signing primitives use instructions from lib/hero/crypt/readme.md, ONLY USE THESE METHODS NO OTHER VLANG METHODS
|
- for encryption/signing primitives use instructions from lib/hero/crypt/readme.md, ONLY USE THESE METHODS NO OTHER VLANG METHODS
|
||||||
|
|
||||||
|
|||||||
@@ -6,11 +6,20 @@ import incubaid.herolib.schemas.jsonschema
|
|||||||
// DocSpec is the main object passed to the documentation template.
|
// DocSpec is the main object passed to the documentation template.
|
||||||
pub struct DocSpec {
|
pub struct DocSpec {
|
||||||
pub mut:
|
pub mut:
|
||||||
info openrpc.Info
|
info openrpc.Info
|
||||||
methods []DocMethod
|
methods []DocMethod
|
||||||
objects []DocObject
|
objects []DocObject
|
||||||
auth_info AuthDocInfo
|
method_groups []DocMethodGroup // Grouped methods by model/actor prefix
|
||||||
base_url string // Dynamic base URL for examples
|
auth_info AuthDocInfo
|
||||||
|
base_url string // Dynamic base URL for examples
|
||||||
|
}
|
||||||
|
|
||||||
|
// DocMethodGroup represents a group of methods for the same model/actor
|
||||||
|
pub struct DocMethodGroup {
|
||||||
|
pub mut:
|
||||||
|
name string // e.g., "calendar", "calendar_event", "user"
|
||||||
|
display_name string // e.g., "Calendar", "Calendar Event", "User"
|
||||||
|
methods []DocMethod
|
||||||
}
|
}
|
||||||
|
|
||||||
// DocObject represents a logical grouping of methods.
|
// DocObject represents a logical grouping of methods.
|
||||||
@@ -100,6 +109,9 @@ pub fn doc_spec_from_openrpc_with_config(openrpc_spec openrpc.OpenRPC, config Do
|
|||||||
doc_spec.methods << doc_method
|
doc_spec.methods << doc_method
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Group methods by their model/actor prefix
|
||||||
|
doc_spec.method_groups = group_methods_by_prefix(doc_spec.methods)
|
||||||
|
|
||||||
return doc_spec
|
return doc_spec
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,3 +280,62 @@ fn create_auth_info() AuthDocInfo {
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// group_methods_by_prefix groups methods by their model/actor prefix (the part before the dot)
|
||||||
|
// For example: "calendar.get", "calendar.set" -> group "calendar"
|
||||||
|
// "calendar_event.get" -> group "calendar_event"
|
||||||
|
fn group_methods_by_prefix(methods []DocMethod) []DocMethodGroup {
|
||||||
|
mut groups_map := map[string][]DocMethod{}
|
||||||
|
|
||||||
|
// Group methods by prefix
|
||||||
|
for method in methods {
|
||||||
|
prefix := extract_method_prefix(method.name)
|
||||||
|
if prefix !in groups_map {
|
||||||
|
groups_map[prefix] = []DocMethod{}
|
||||||
|
}
|
||||||
|
groups_map[prefix] << method
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert map to array of DocMethodGroup
|
||||||
|
mut groups := []DocMethodGroup{}
|
||||||
|
for prefix, group_methods in groups_map {
|
||||||
|
groups << DocMethodGroup{
|
||||||
|
name: prefix
|
||||||
|
display_name: format_display_name(prefix)
|
||||||
|
methods: group_methods
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort groups alphabetically by name
|
||||||
|
groups.sort(a.name < b.name)
|
||||||
|
|
||||||
|
return groups
|
||||||
|
}
|
||||||
|
|
||||||
|
// extract_method_prefix extracts the model/actor prefix from a method name
|
||||||
|
// Examples: "calendar.get" -> "calendar"
|
||||||
|
// "calendar_event.set" -> "calendar_event"
|
||||||
|
// "user.delete" -> "user"
|
||||||
|
fn extract_method_prefix(method_name string) string {
|
||||||
|
parts := method_name.split('.')
|
||||||
|
if parts.len > 0 {
|
||||||
|
return parts[0]
|
||||||
|
}
|
||||||
|
return method_name
|
||||||
|
}
|
||||||
|
|
||||||
|
// format_display_name converts a prefix to a human-readable display name
|
||||||
|
// Examples: "calendar" -> "Calendar"
|
||||||
|
// "calendar_event" -> "Calendar Event"
|
||||||
|
// "chat_message" -> "Chat Message"
|
||||||
|
fn format_display_name(prefix string) string {
|
||||||
|
// Split by underscore and capitalize each word
|
||||||
|
words := prefix.split('_')
|
||||||
|
mut capitalized := []string{}
|
||||||
|
for word in words {
|
||||||
|
if word.len > 0 {
|
||||||
|
capitalized << word[0].ascii_str().to_upper() + word[1..]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return capitalized.join(' ')
|
||||||
|
}
|
||||||
|
|||||||
@@ -103,6 +103,193 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
padding-right: 4rem;
|
padding-right: 4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.toc-header {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-header:hover {
|
||||||
|
background-color: #e9ecef;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
margin: -0.25rem -0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-toggle-icon {
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-toggle-icon.collapsed {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Reusable collapsible section styles */
|
||||||
|
.collapsible-header {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
transition: background-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsible-header:hover {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsible-toggle {
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
display: inline-block;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.collapsible-toggle.collapsed {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-card .card-header {
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-card .card-header:hover {
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-more-link {
|
||||||
|
cursor: pointer;
|
||||||
|
color: #007bff;
|
||||||
|
text-decoration: none;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.show-more-link:hover {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Equal height for example request/response sections */
|
||||||
|
.examples-row {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.examples-row>[class*='col-'] {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.examples-row .code-block {
|
||||||
|
flex: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.examples-row .code-block pre {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Method group section styles */
|
||||||
|
.method-group-section {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border: 1px solid #dee2e6;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
padding: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-group-header {
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
padding: 0.5rem 0;
|
||||||
|
margin-bottom: 1rem;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
transition: opacity 0.2s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-group-header:hover {
|
||||||
|
opacity: 0.8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-group-header h3 {
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1.25rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #495057;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-group-toggle {
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
font-size: 1.2rem;
|
||||||
|
color: #6c757d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-group-toggle.collapsed {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-group-content {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.method-group-content .method-card {
|
||||||
|
background-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TOC group styles */
|
||||||
|
.toc-group {
|
||||||
|
margin-bottom: 0.75rem;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
border: 1px solid #e9ecef;
|
||||||
|
border-radius: 0.25rem;
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-group-header {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #495057;
|
||||||
|
margin-bottom: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
padding: 0.25rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-group-header:hover {
|
||||||
|
color: #212529;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-group-toggle {
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #6c757d;
|
||||||
|
margin-right: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-group-toggle.collapsed {
|
||||||
|
transform: rotate(-90deg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-group-methods {
|
||||||
|
margin-left: 1.5rem;
|
||||||
|
margin-top: 0.5rem;
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.toc-group-methods li {
|
||||||
|
margin-bottom: 0.25rem;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
@@ -191,117 +378,164 @@
|
|||||||
<div class="row mb-4">
|
<div class="row mb-4">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div class="toc">
|
<div class="toc">
|
||||||
<h5>Table of Contents</h5>
|
<div class="toc-header" aria-expanded="true" aria-controls="tocContent">
|
||||||
@if spec.methods.len > 0
|
<h5 class="mb-0">Table of Contents</h5>
|
||||||
<h6>API Methods</h6>
|
<span class="toc-toggle-icon">▼</span>
|
||||||
<ul>
|
</div>
|
||||||
@for method in spec.methods
|
<div class="collapse show" id="tocContent">
|
||||||
<li><a href="#method-${method.name}">${method.name}</a> - ${method.summary}</li>
|
<div class="mt-3">
|
||||||
@end
|
@if spec.method_groups.len > 0
|
||||||
</ul>
|
<h6>API Methods</h6>
|
||||||
@end
|
@for group_idx, group in spec.method_groups
|
||||||
|
<div class="toc-group">
|
||||||
|
<div class="toc-group-header"
|
||||||
|
onclick="toggleTocGroup('toc-group-methods-${group_idx}')">
|
||||||
|
<div>
|
||||||
|
<span class="toc-group-toggle" id="toc-toggle-${group_idx}">▼</span>
|
||||||
|
${group.display_name} (${group.methods.len})
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="collapse show" id="toc-group-methods-${group_idx}">
|
||||||
|
<ul class="toc-group-methods">
|
||||||
|
@for method in group.methods
|
||||||
|
<li>
|
||||||
|
<a href="#method-${method.name}">${method.name}</a>
|
||||||
|
@if method.summary.len > 0
|
||||||
|
- ${method.summary}
|
||||||
|
@end
|
||||||
|
</li>
|
||||||
|
@end
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
@end
|
||||||
|
@end
|
||||||
|
|
||||||
@if spec.objects.len > 0
|
@if spec.objects.len > 0
|
||||||
<h6>API Objects</h6>
|
<h6>API Objects</h6>
|
||||||
<ul>
|
<ul>
|
||||||
@for object in spec.objects
|
@for object in spec.objects
|
||||||
<li><a href="#object-${object.name}">${object.name.title()}</a> - ${object.description}</li>
|
<li><a href="#object-${object.name}">${object.name.title()}</a> - ${object.description}
|
||||||
@end
|
</li>
|
||||||
</ul>
|
@end
|
||||||
@end
|
</ul>
|
||||||
|
@end
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@end
|
@end
|
||||||
|
|
||||||
<!-- API Methods -->
|
<!-- API Methods (Grouped by Model/Actor) -->
|
||||||
@if spec.methods.len > 0
|
@if spec.method_groups.len > 0
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<h2>API Methods</h2>
|
<h2>API Methods</h2>
|
||||||
<p class="text-muted">Available methods for this service</p>
|
<p class="text-muted">Methods organized by groups</p>
|
||||||
|
|
||||||
@for method in spec.methods
|
@for group_idx, group in spec.method_groups
|
||||||
<div class="card method-card" id="method-${method.name}">
|
<div class="method-group-section">
|
||||||
<div class="card-header">
|
<div class="method-group-header" onclick="toggleMethodGroup('group-${group_idx}')">
|
||||||
<h5 class="mb-0">${method.name}</h5>
|
<h3>${group.display_name}</h3>
|
||||||
<div class="method-endpoint mt-2 mb-2">POST ${method.endpoint_url}</div>
|
<span class="method-group-toggle" id="group-toggle-${group_idx}">▼</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-body">
|
<div class="collapse show method-group-content" id="group-${group_idx}">
|
||||||
@if method.summary.len > 0
|
@for method_idx, method in group.methods
|
||||||
<p class="card-text"><strong>${method.summary}</strong></p>
|
<div class="card method-card mb-3" id="method-${method.name}">
|
||||||
@end
|
<div class="card-header"
|
||||||
@if method.description.len > 0
|
onclick="toggleMethodCard('method-body-${group_idx}-${method_idx}')">
|
||||||
<p class="card-text">${method.description}</p>
|
<div class="d-flex justify-content-between align-items-center">
|
||||||
@end
|
<div>
|
||||||
|
<span class="collapsible-toggle" id="toggle-${group_idx}-${method_idx}">▼</span>
|
||||||
<!-- Parameters -->
|
<h5 class="d-inline mb-0">${method.name}</h5>
|
||||||
@if method.params.len > 0
|
</div>
|
||||||
<h6>Parameters:</h6>
|
</div>
|
||||||
<table class="table table-sm param-table">
|
<div class="method-endpoint mt-2 mb-2">POST ${method.endpoint_url}</div>
|
||||||
<thead>
|
@if method.summary.len > 0
|
||||||
<tr>
|
<p class="mb-0 mt-2 text-muted">${method.summary}</p>
|
||||||
<th>Name</th>
|
|
||||||
<th>Type</th>
|
|
||||||
<th>Required</th>
|
|
||||||
<th>Description</th>
|
|
||||||
<th>Example</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
@for param in method.params
|
|
||||||
<tr>
|
|
||||||
<td><code>${param.name}</code></td>
|
|
||||||
<td><span class="badge bg-secondary">${param.type_info}</span></td>
|
|
||||||
@if param.required
|
|
||||||
<td><span class="badge bg-danger">Required</span></td>
|
|
||||||
@else
|
|
||||||
<td><span class="badge bg-success">Optional</span></td>
|
|
||||||
@end
|
|
||||||
<td>${param.description}</td>
|
|
||||||
<td><code class="text-muted">${param.example}</code></td>
|
|
||||||
</tr>
|
|
||||||
@end
|
@end
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
@end
|
|
||||||
|
|
||||||
<!-- Return Value -->
|
|
||||||
@if method.result.name.len > 0
|
|
||||||
<h6>Returns:</h6>
|
|
||||||
<div class="alert alert-light">
|
|
||||||
<strong>Type:</strong> <span class="badge bg-info">${method.result.type_info}</span><br>
|
|
||||||
<strong>Description:</strong> ${method.result.description}<br>
|
|
||||||
@if method.result.example.len > 0
|
|
||||||
<strong>Example:</strong> <code class="text-muted">${method.result.example}</code>
|
|
||||||
@end
|
|
||||||
</div>
|
|
||||||
@end
|
|
||||||
|
|
||||||
<!-- Examples -->
|
|
||||||
<div class="row mt-3">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h6>Example Request:</h6>
|
|
||||||
<div class="code-block">
|
|
||||||
<pre>${method.example_request}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div class="collapse" id="method-body-${group_idx}-${method_idx}">
|
||||||
<h6>Example Response:</h6>
|
<div class="card-body">
|
||||||
<div class="code-block">
|
@if method.description.len > 0
|
||||||
<pre>${method.example_response}</pre>
|
<p class="card-text">${method.description}</p>
|
||||||
|
@end
|
||||||
|
|
||||||
|
<!-- Parameters -->
|
||||||
|
@if method.params.len > 0
|
||||||
|
<h6>Parameters:</h6>
|
||||||
|
<table class="table table-sm param-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Type</th>
|
||||||
|
<th>Required</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Example</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
@for param in method.params
|
||||||
|
<tr>
|
||||||
|
<td><code>${param.name}</code></td>
|
||||||
|
<td><span class="badge bg-secondary">${param.type_info}</span></td>
|
||||||
|
@if param.required
|
||||||
|
<td><span class="badge bg-danger">Required</span></td>
|
||||||
|
@else
|
||||||
|
<td><span class="badge bg-success">Optional</span></td>
|
||||||
|
@end
|
||||||
|
<td>${param.description}</td>
|
||||||
|
<td><code class="text-muted">${param.example}</code></td>
|
||||||
|
</tr>
|
||||||
|
@end
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
@end
|
||||||
|
|
||||||
|
<!-- Return Value -->
|
||||||
|
@if method.result.name.len > 0
|
||||||
|
<h6>Returns:</h6>
|
||||||
|
<div class="alert alert-light">
|
||||||
|
<strong>Type:</strong> <span
|
||||||
|
class="badge bg-info">${method.result.type_info}</span><br>
|
||||||
|
<strong>Description:</strong> ${method.result.description}<br>
|
||||||
|
@if method.result.example.len > 0
|
||||||
|
<strong>Example:</strong> <code
|
||||||
|
class="text-muted">${method.result.example}</code>
|
||||||
|
@end
|
||||||
|
</div>
|
||||||
|
@end
|
||||||
|
|
||||||
|
<!-- Examples -->
|
||||||
|
<div class="row mt-3 examples-row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h6>Example Request:</h6>
|
||||||
|
<div class="code-block">
|
||||||
|
<pre>${method.example_request}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<h6>Example Response:</h6>
|
||||||
|
<div class="code-block">
|
||||||
|
<pre>${method.example_response}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Curl Example -->
|
||||||
|
<div class="curl-section">
|
||||||
|
<h6>Curl Command:</h6>
|
||||||
|
<button class="copy-button"
|
||||||
|
onclick="copyToClipboard('curl-${method.name}', this)">
|
||||||
|
Copy
|
||||||
|
</button>
|
||||||
|
<pre class="curl-command" id="curl-${method.name}">${method.curl_example}</pre>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@end
|
||||||
<!-- Curl Example -->
|
|
||||||
<div class="curl-section">
|
|
||||||
<h6>Curl Command:</h6>
|
|
||||||
<button class="copy-button" onclick="copyToClipboard('curl-${method.name}', this)">
|
|
||||||
Copy
|
|
||||||
</button>
|
|
||||||
<pre class="curl-command" id="curl-${method.name}">${method.curl_example}</pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@end
|
@end
|
||||||
@@ -414,13 +648,13 @@
|
|||||||
<!-- Footer -->
|
<!-- Footer -->
|
||||||
<footer class="mt-5 py-4 bg-light">
|
<footer class="mt-5 py-4 bg-light">
|
||||||
<div class="container text-center">
|
<div class="container text-center">
|
||||||
<p class="mb-0">Generated from OpenRPC specification • ${spec.info.title} v${spec.info.version}</p>
|
<p class="mb-0">Generated from OpenRPC specification • ${spec.info.title}
|
||||||
|
v${spec.info.version}</p>
|
||||||
</div>
|
</div>
|
||||||
</footer>
|
</footer>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Bootstrap JS -->
|
<!-- Bootstrap JS Bundle (includes Popper) -->
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@@5.3.3/dist/js/bootstrap.min.js"></script>
|
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
|
||||||
|
|
||||||
<!-- Copy to Clipboard Functionality -->
|
<!-- Copy to Clipboard Functionality -->
|
||||||
@@ -476,6 +710,186 @@
|
|||||||
button.classList.remove('copied');
|
button.classList.remove('copied');
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle TOC group sections
|
||||||
|
function toggleTocGroup(groupId) {
|
||||||
|
const group = document.getElementById(groupId);
|
||||||
|
const toggleIcon = document.getElementById('toc-toggle-' + groupId.replace('toc-group-methods-', ''));
|
||||||
|
|
||||||
|
if (group && toggleIcon) {
|
||||||
|
const bsCollapse = bootstrap.Collapse.getOrCreateInstance(group);
|
||||||
|
|
||||||
|
// Check current state and toggle icon immediately
|
||||||
|
if (group.classList.contains('show')) {
|
||||||
|
// Currently expanded, will collapse
|
||||||
|
toggleIcon.classList.add('collapsed');
|
||||||
|
} else {
|
||||||
|
// Currently collapsed, will expand
|
||||||
|
toggleIcon.classList.remove('collapsed');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle the collapse
|
||||||
|
bsCollapse.toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle method group sections
|
||||||
|
function toggleMethodGroup(groupId) {
|
||||||
|
const group = document.getElementById(groupId);
|
||||||
|
const toggleIcon = document.getElementById('group-toggle-' + groupId.replace('group-', ''));
|
||||||
|
|
||||||
|
if (group && toggleIcon) {
|
||||||
|
const bsCollapse = bootstrap.Collapse.getOrCreateInstance(group);
|
||||||
|
|
||||||
|
// Check current state and toggle icon immediately
|
||||||
|
if (group.classList.contains('show')) {
|
||||||
|
// Currently expanded, will collapse
|
||||||
|
toggleIcon.classList.add('collapsed');
|
||||||
|
} else {
|
||||||
|
// Currently collapsed, will expand
|
||||||
|
toggleIcon.classList.remove('collapsed');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle the collapse
|
||||||
|
bsCollapse.toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reusable toggle function for method cards
|
||||||
|
function toggleMethodCard(bodyId) {
|
||||||
|
const body = document.getElementById(bodyId);
|
||||||
|
const toggleIcon = document.getElementById('toggle-' + bodyId.replace('method-body-', ''));
|
||||||
|
|
||||||
|
if (body && toggleIcon) {
|
||||||
|
const bsCollapse = bootstrap.Collapse.getOrCreateInstance(body);
|
||||||
|
|
||||||
|
// Check current state and toggle icon immediately
|
||||||
|
if (body.classList.contains('show')) {
|
||||||
|
// Currently expanded, will collapse
|
||||||
|
toggleIcon.classList.add('collapsed');
|
||||||
|
} else {
|
||||||
|
// Currently collapsed, will expand
|
||||||
|
toggleIcon.classList.remove('collapsed');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle the collapse
|
||||||
|
bsCollapse.toggle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Toggle TOC methods list
|
||||||
|
function toggleTocMethods() {
|
||||||
|
const methodItems = document.querySelectorAll('.toc-method-item');
|
||||||
|
const showMoreLink = document.getElementById('tocShowMore');
|
||||||
|
const isExpanded = showMoreLink.textContent.includes('Show less');
|
||||||
|
|
||||||
|
methodItems.forEach((item, index) => {
|
||||||
|
if (index > 0) {
|
||||||
|
item.style.display = isExpanded ? 'none' : 'list-item';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const totalMethods = methodItems.length;
|
||||||
|
showMoreLink.textContent = isExpanded
|
||||||
|
? 'Show all ' + totalMethods + ' methods ▼'
|
||||||
|
: 'Show less ▲';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Table of Contents toggle functionality
|
||||||
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
|
const tocContent = document.getElementById('tocContent');
|
||||||
|
const tocHeader = document.querySelector('.toc-header');
|
||||||
|
const tocIcon = document.querySelector('.toc-toggle-icon');
|
||||||
|
|
||||||
|
if (tocContent && tocHeader && tocIcon) {
|
||||||
|
// Initialize Bootstrap Collapse
|
||||||
|
const bsCollapse = new bootstrap.Collapse(tocContent, {
|
||||||
|
toggle: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle click on header
|
||||||
|
tocHeader.addEventListener('click', function () {
|
||||||
|
bsCollapse.toggle();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Handle icon rotation on collapse events
|
||||||
|
tocContent.addEventListener('show.bs.collapse', function () {
|
||||||
|
tocIcon.classList.remove('collapsed');
|
||||||
|
tocHeader.setAttribute('aria-expanded', 'true');
|
||||||
|
});
|
||||||
|
|
||||||
|
tocContent.addEventListener('hide.bs.collapse', function () {
|
||||||
|
tocIcon.classList.add('collapsed');
|
||||||
|
tocHeader.setAttribute('aria-expanded', 'false');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize TOC groups - only first group expanded by default
|
||||||
|
const tocGroups = document.querySelectorAll('[id^="toc-group-methods-"]');
|
||||||
|
tocGroups.forEach((group, index) => {
|
||||||
|
const groupId = group.id;
|
||||||
|
const toggleIcon = document.getElementById('toc-toggle-' + groupId.replace('toc-group-methods-', ''));
|
||||||
|
|
||||||
|
if (index === 0) {
|
||||||
|
// First group - keep it expanded
|
||||||
|
if (toggleIcon) {
|
||||||
|
toggleIcon.classList.remove('collapsed');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Other groups - collapse them
|
||||||
|
const bsCollapse = new bootstrap.Collapse(group, { toggle: false });
|
||||||
|
bsCollapse.hide();
|
||||||
|
if (toggleIcon) {
|
||||||
|
toggleIcon.classList.add('collapsed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize method groups - only first group expanded by default
|
||||||
|
const methodGroups = document.querySelectorAll('[id^="group-"]');
|
||||||
|
methodGroups.forEach((group, index) => {
|
||||||
|
const groupId = group.id;
|
||||||
|
const toggleIcon = document.getElementById('group-toggle-' + groupId.replace('group-', ''));
|
||||||
|
|
||||||
|
if (index === 0) {
|
||||||
|
// First group - keep it expanded
|
||||||
|
if (toggleIcon) {
|
||||||
|
toggleIcon.classList.remove('collapsed');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Other groups - collapse them
|
||||||
|
const bsCollapse = new bootstrap.Collapse(group, { toggle: false });
|
||||||
|
bsCollapse.hide();
|
||||||
|
if (toggleIcon) {
|
||||||
|
toggleIcon.classList.add('collapsed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Initialize method cards - expand only the first method in the first group
|
||||||
|
const methodBodies = document.querySelectorAll('[id^="method-body-"]');
|
||||||
|
methodBodies.forEach((body) => {
|
||||||
|
const bodyId = body.id;
|
||||||
|
const parts = bodyId.replace('method-body-', '').split('-');
|
||||||
|
const groupIdx = parts[0];
|
||||||
|
const methodIdx = parts[1];
|
||||||
|
const toggleIcon = document.getElementById('toggle-' + groupIdx + '-' + methodIdx);
|
||||||
|
|
||||||
|
if (groupIdx === '0' && methodIdx === '0') {
|
||||||
|
// First method in first group - expand it
|
||||||
|
const bsCollapse = new bootstrap.Collapse(body, { toggle: false });
|
||||||
|
bsCollapse.show();
|
||||||
|
if (toggleIcon) {
|
||||||
|
toggleIcon.classList.remove('collapsed');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// All other methods - collapse them
|
||||||
|
if (toggleIcon) {
|
||||||
|
toggleIcon.classList.add('collapsed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user