Enhance API documentation layout and interactivity: implement collapsible sections for methods, parameters, returns, and examples

This commit is contained in:
Eduardo Silva
2026-02-11 17:06:40 -03:00
parent 1dcf94518f
commit 8c7deb9f88

View File

@@ -2,88 +2,151 @@
{% load i18n %} {% load i18n %}
{% block content %} {% block content %}
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
<h2 class="mb-4">{% trans 'API Documentation' %}</h2> <h2 class="mb-4">{% trans 'API Documentation' %}</h2>
{% for doc in docs %} <div id="accordion">
<div class="card mb-4"> {% for doc in docs %}
<div class="card-header"> <div class="card mb-2">
<h5 class="mb-0"> <div class="card-header" id="heading-{{ forloop.counter }}">
{% for method in doc.methods %} <h5 class="mb-0">
<span class="badge badge-primary mr-2">{{ method }}</span> <button class="btn btn-link btn-block text-left collapsed d-flex align-items-center"
{% endfor %} type="button" data-toggle="collapse" data-target="#collapse-{{ forloop.counter }}"
<code>/api/v2/{{ doc.url_pattern }}</code> aria-expanded="false" aria-controls="collapse-{{ forloop.counter }}"
</h5> style="text-decoration: none; color: inherit;">
</div> <i class="fas fa-chevron-right mr-3 text-muted"></i>
<div class="card-body"> <div class="mr-auto">
<p class="lead">{{ doc.summary }}</p> {% for method in doc.methods %}
<span class="badge badge-primary mr-2">{{ method }}</span>
{% endfor %}
<code>/api/v2/{{ doc.url_pattern }}</code>
</div>
<small class="text-muted ml-3 d-none d-md-block">{{ doc.summary|truncatechars:100 }}</small>
</button>
</h5>
</div>
<p><strong>{% trans 'Authentication' %}:</strong> {{ doc.auth }}</p> <div id="collapse-{{ forloop.counter }}" class="collapse"
aria-labelledby="heading-{{ forloop.counter }}" data-parent="#accordion">
<div class="card-body">
<p class="lead">{{ doc.summary }}</p>
{% if doc.params %} <p><strong>{% trans 'Authentication' %}:</strong> {{ doc.auth }}</p>
<h6 class="mt-3">{% trans 'Parameters' %}</h6>
<table class="table table-sm table-bordered"> <!-- Parameters Section -->
<thead> {% if doc.params %}
<tr> <div class="mt-3">
<th>{% trans 'Name' %}</th> <h6 class="mb-0 pointer" data-toggle="collapse" data-target="#params-{{ forloop.counter }}"
<th>{% trans 'In' %}</th> aria-expanded="false" aria-controls="params-{{ forloop.counter }}"
<th>{% trans 'Type' %}</th> style="cursor: pointer;">
<th>{% trans 'Required' %}</th> <i class="fas fa-chevron-right mr-2 text-muted"></i> {% trans 'Parameters' %}
<th>{% trans 'Description' %}</th> </h6>
</tr> <div id="params-{{ forloop.counter }}" class="collapse mt-2">
</thead> <table class="table table-sm table-bordered">
<tbody> <thead>
{% for param in doc.params %} <tr>
<tr> <th>{% trans 'Name' %}</th>
<td><code>{{ param.name }}</code></td> <th>{% trans 'In' %}</th>
<td>{{ param.in }}</td> <th>{% trans 'Type' %}</th>
<td>{{ param.type }}</td> <th>{% trans 'Required' %}</th>
<td> <th>{% trans 'Description' %}</th>
{% if param.required %} </tr>
<span class="badge badge-danger">{% trans 'Yes' %}</span> </thead>
{% else %} <tbody>
<span class="badge badge-secondary">{% trans 'No' %}</span> {% for param in doc.params %}
<tr>
<td><code>{{ param.name }}</code></td>
<td>{{ param.in }}</td>
<td>{{ param.type }}</td>
<td>
{% if param.required %}
<span class="badge badge-danger">{% trans 'Yes' %}</span>
{% else %}
<span class="badge badge-secondary">{% trans 'No' %}</span>
{% endif %}
</td>
<td>
{{ param.description }}
{% if param.example %}
<br><small class="text-muted">{% trans 'Example' %}: {{ param.example }}</small>
{% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endif %} {% endif %}
</td>
<td> <!-- Returns Section -->
{{ param.description }} {% if doc.returns %}
{% if param.example %} <div class="mt-3">
<br><small class="text-muted">{% trans 'Example' %}: {{ param.example }}</small> <h6 class="mb-0 pointer" data-toggle="collapse" data-target="#returns-{{ forloop.counter }}"
aria-expanded="false" aria-controls="returns-{{ forloop.counter }}"
style="cursor: pointer;">
<i class="fas fa-chevron-right mr-2 text-muted"></i> {% trans 'Returns' %}
</h6>
<div id="returns-{{ forloop.counter }}" class="collapse mt-2">
<ul class="list-group">
{% for ret in doc.returns %}
<li class="list-group-item">
<strong>{{ ret.status }}</strong>
<pre class="bg-light p-2 mt-2"><code>{{ ret.body|pprint }}</code></pre>
</li>
{% endfor %}
</ul>
</div>
</div>
{% endif %} {% endif %}
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% if doc.returns %} <!-- Examples Section -->
<h6 class="mt-3">{% trans 'Returns' %}</h6> {% if doc.examples %}
<ul class="list-group"> <div class="mt-3">
{% for ret in doc.returns %} <h6 class="mb-0 pointer" data-toggle="collapse"
<li class="list-group-item"> data-target="#examples-{{ forloop.counter }}" aria-expanded="false"
<strong>{{ ret.status }}</strong> aria-controls="examples-{{ forloop.counter }}" style="cursor: pointer;">
<pre class="bg-light p-2 mt-2"><code>{{ ret.body|pprint }}</code></pre> <i class="fas fa-chevron-right mr-2 text-muted"></i> {% trans 'Examples' %}
</li> </h6>
{% endfor %} <div id="examples-{{ forloop.counter }}" class="collapse mt-2">
</ul> {% for key, example in doc.examples.items %}
{% endif %} <div class="card bg-light mb-2">
<div class="card-body p-2">
{% if doc.examples %} <strong>{{ key }}</strong>
<h6 class="mt-3">{% trans 'Examples' %}</h6> <pre class="mb-0"><code>{{ example|pprint }}</code></pre>
{% for key, example in doc.examples.items %} </div>
<div class="card bg-light mb-2"> </div>
<div class="card-body p-2"> {% endfor %}
<strong>{{ key }}</strong> </div>
<pre class="mb-0"><code>{{ example|pprint }}</code></pre> </div>
{% endif %}
</div>
</div>
</div> </div>
</div>
{% endfor %} {% endfor %}
{% endif %}
</div> </div>
</div> </div>
{% endfor %}
</div> </div>
</div>
<script>
document.addEventListener("DOMContentLoaded", function () {
// Function to toggle icon class on collapse events
function setupIconToggle(collapseId, iconSelector) {
$('#' + collapseId).on('show.bs.collapse', function () {
var trigger = $('[data-target="#' + collapseId + '"]');
trigger.find(iconSelector).first().removeClass('fa-chevron-right').addClass('fa-chevron-down');
}).on('hide.bs.collapse', function () {
var trigger = $('[data-target="#' + collapseId + '"]');
trigger.find(iconSelector).first().removeClass('fa-chevron-down').addClass('fa-chevron-right');
});
}
// Setup for all collapsible elements
$('.collapse').each(function () {
var id = $(this).attr('id');
setupIconToggle(id, '.fa-chevron-right, .fa-chevron-down');
});
});
</script>
{% endblock %} {% endblock %}