docula 0.50.0 → 0.90.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -7,6 +7,7 @@
7
7
  </head>
8
8
 
9
9
  <body>
10
+ {{#if githubPath}}
10
11
  <a href="https://github.com/{{ githubPath }}" class="github-corner" aria-label="View source on GitHub"><svg width="80"
11
12
  height="80" viewBox="0 0 250 250" style="color:#fff; position: absolute; top: 0; border: 0; right: 0;"
12
13
  aria-hidden="true">
@@ -51,6 +52,7 @@
51
52
  }
52
53
  }
53
54
  </style>
55
+ {{/if}}
54
56
  <main class="layout">
55
57
  {{> multipage/header }}
56
58
  {{> multipage/sidebar }}
@@ -7,6 +7,7 @@
7
7
  </head>
8
8
 
9
9
  <body>
10
+ {{#if githubPath}}
10
11
  <a href="https://github.com/{{ githubPath }}" class="github-corner" aria-label="View source on GitHub"><svg width="80"
11
12
  height="80" viewBox="0 0 250 250" style="color:#fff; position: absolute; top: 0; border: 0; right: 0;"
12
13
  aria-hidden="true">
@@ -51,6 +52,7 @@
51
52
  }
52
53
  }
53
54
  </style>
55
+ {{/if}}
54
56
  {{#if content}}
55
57
  {{> singlepage/hero }}
56
58
  {{> singlepage/content }}
@@ -0,0 +1,61 @@
1
+ <div class="api-try-it" data-method="{{this.methodUpper}}" data-path="{{this.path}}"{{#if this.requestBody}} data-content-type="{{this.requestBody.contentType}}"{{/if}}>
2
+ <span class="api-try-it__title">Test Request</span>
3
+
4
+ <div class="api-try-it__url-bar">
5
+ <span class="method-badge method-badge--{{this.method}}">{{this.methodUpper}}</span>
6
+ <div class="api-try-it__url-display">
7
+ <select class="api-try-it__server-select" data-try-server>
8
+ {{#each @root.apiSpec.servers}}
9
+ <option value="{{this.url}}">{{this.url}}</option>
10
+ {{/each}}
11
+ </select>
12
+ <span class="api-try-it__path-display">{{this.path}}</span>
13
+ </div>
14
+ </div>
15
+
16
+ {{#if this.parameters.length}}
17
+ <div class="api-try-it__section">
18
+ <div class="api-try-it__section-label">Parameters</div>
19
+ {{#each this.parameters}}
20
+ <div class="api-try-it__param-row" data-param-in="{{this.in}}" data-param-name="{{this.name}}">
21
+ <div class="api-try-it__param-info">
22
+ <span class="api-try-it__param-name">{{this.name}}</span>
23
+ <span class="api-try-it__param-in">{{this.in}}</span>
24
+ {{#if this.required}}<span class="api-param-required">*</span>{{/if}}
25
+ </div>
26
+ {{#if (eq this.in "cookie")}}
27
+ <input type="text" class="api-try-it__param-input" placeholder="Not supported in browser" disabled data-try-param />
28
+ {{else}}
29
+ <input type="text" class="api-try-it__param-input" placeholder="{{this.type}}" data-try-param />
30
+ {{/if}}
31
+ </div>
32
+ {{/each}}
33
+ </div>
34
+ {{/if}}
35
+
36
+ {{#if this.requestBody}}
37
+ <div class="api-try-it__section">
38
+ <div class="api-try-it__section-label">Body</div>
39
+ <textarea class="api-try-it__body-editor" data-try-body rows="8">{{this.requestBody.example}}</textarea>
40
+ </div>
41
+ {{/if}}
42
+
43
+ <button class="api-try-it__send-btn" data-try-send>Send Request</button>
44
+
45
+ <div class="api-try-it__response api-try-it__response--hidden" data-try-response>
46
+ <div class="api-try-it__response-meta">
47
+ <span class="api-try-it__response-status" data-try-status></span>
48
+ <span class="api-try-it__response-time" data-try-time></span>
49
+ </div>
50
+ <div class="api-try-it__response-tabs">
51
+ <button class="api-try-it__rtab api-try-it__rtab--active" data-try-rtab="body">Body</button>
52
+ <button class="api-try-it__rtab" data-try-rtab="headers">Headers</button>
53
+ </div>
54
+ <div class="api-try-it__rpanel api-try-it__rpanel--active" data-try-rpanel="body">
55
+ <pre><code data-try-response-body></code></pre>
56
+ </div>
57
+ <div class="api-try-it__rpanel" data-try-rpanel="headers">
58
+ <pre><code data-try-response-headers></code></pre>
59
+ </div>
60
+ </div>
61
+ </div>
@@ -0,0 +1,282 @@
1
+ document.addEventListener('DOMContentLoaded', function() {
2
+ // Toggle operations
3
+ document.querySelectorAll('[data-toggle="operation"]').forEach(function(header) {
4
+ header.addEventListener('click', function() {
5
+ this.closest('.api-operation').classList.toggle('api-operation--collapsed');
6
+ });
7
+ });
8
+
9
+ // Toggle sidebar groups
10
+ document.querySelectorAll('.api-sidebar__group-toggle').forEach(function(btn) {
11
+ btn.addEventListener('click', function() {
12
+ this.closest('.api-sidebar__group').classList.toggle('api-sidebar__group--collapsed');
13
+ });
14
+ });
15
+
16
+ // Code example tabs
17
+ document.querySelectorAll('.api-code-tabs').forEach(function(tabs) {
18
+ var container = tabs.closest('.api-code-examples');
19
+ tabs.querySelectorAll('.api-code-tab').forEach(function(tab) {
20
+ tab.addEventListener('click', function() {
21
+ var target = this.getAttribute('data-tab');
22
+ container.querySelectorAll('.api-code-tab').forEach(function(t) { t.classList.remove('api-code-tab--active'); });
23
+ container.querySelectorAll('.api-code-panel').forEach(function(p) { p.classList.remove('api-code-panel--active'); });
24
+ this.classList.add('api-code-tab--active');
25
+ var panel = container.querySelector('[data-panel="' + target + '"]');
26
+ if (panel) panel.classList.add('api-code-panel--active');
27
+ });
28
+ });
29
+ });
30
+
31
+ // Copy to clipboard
32
+ document.querySelectorAll('[data-copy]').forEach(function(btn) {
33
+ btn.addEventListener('click', function() {
34
+ var code = this.closest('.api-code-panel').querySelector('code');
35
+ if (code) {
36
+ navigator.clipboard.writeText(code.textContent).then(function() {
37
+ btn.textContent = 'Copied!';
38
+ setTimeout(function() { btn.textContent = 'Copy'; }, 2000);
39
+ });
40
+ }
41
+ });
42
+ });
43
+
44
+ // Search
45
+ var searchInput = document.getElementById('api-search');
46
+ if (searchInput) {
47
+ searchInput.addEventListener('input', function() {
48
+ var query = this.value.toLowerCase();
49
+ document.querySelectorAll('.api-sidebar__item').forEach(function(item) {
50
+ var path = (item.getAttribute('data-path') || '').toLowerCase();
51
+ var method = (item.getAttribute('data-method') || '').toLowerCase();
52
+ var match = !query || path.indexOf(query) !== -1 || method.indexOf(query) !== -1 || item.textContent.toLowerCase().indexOf(query) !== -1;
53
+ item.style.display = match ? '' : 'none';
54
+ });
55
+ document.querySelectorAll('.api-operation').forEach(function(op) {
56
+ var path = (op.querySelector('.api-operation__path') || {}).textContent || '';
57
+ var method = (op.querySelector('.method-badge') || {}).textContent || '';
58
+ var match = !query || path.toLowerCase().indexOf(query) !== -1 || method.toLowerCase().indexOf(query) !== -1;
59
+ op.style.display = match ? '' : 'none';
60
+ });
61
+ document.querySelectorAll('.api-group').forEach(function(group) {
62
+ var visible = group.querySelectorAll('.api-operation:not([style*="display: none"])');
63
+ group.style.display = visible.length > 0 || !query ? '' : 'none';
64
+ });
65
+ });
66
+ }
67
+
68
+ // Mobile sidebar toggle
69
+ var sidebarToggle = document.getElementById('api-sidebar-toggle');
70
+ var sidebar = document.getElementById('api-sidebar');
71
+ if (sidebarToggle && sidebar) {
72
+ sidebarToggle.addEventListener('click', function() {
73
+ sidebar.classList.toggle('api-sidebar--mobile-open');
74
+ });
75
+ sidebar.querySelectorAll('.api-sidebar__item').forEach(function(link) {
76
+ link.addEventListener('click', function() {
77
+ sidebar.classList.remove('api-sidebar--mobile-open');
78
+ });
79
+ });
80
+ }
81
+
82
+ // Collapse all sidebar groups by default
83
+ document.querySelectorAll('.api-sidebar__group').forEach(function(group) {
84
+ group.classList.add('api-sidebar__group--collapsed');
85
+ });
86
+
87
+ // Auth type selector: show/hide value input
88
+ var authTypeSelect = document.getElementById('api-auth-type');
89
+ var authValueInput = document.getElementById('api-auth-value');
90
+ if (authTypeSelect && authValueInput) {
91
+ authTypeSelect.addEventListener('change', function() {
92
+ if (this.value === 'none') {
93
+ authValueInput.classList.add('api-auth__value--hidden');
94
+ authValueInput.value = '';
95
+ } else {
96
+ authValueInput.classList.remove('api-auth__value--hidden');
97
+ authValueInput.placeholder = this.value === 'apikey' ? 'Enter API key...' : 'Enter token...';
98
+ }
99
+ });
100
+ }
101
+
102
+ // Helper: expand an operation and its corresponding sidebar group
103
+ function expandOperationAndGroup(operationEl) {
104
+ if (!operationEl) return;
105
+ operationEl.classList.remove('api-operation--collapsed');
106
+ var contentGroup = operationEl.closest('.api-group');
107
+ if (contentGroup) {
108
+ var groupId = contentGroup.id.replace(/^group-/, '');
109
+ var sidebarGroup = document.querySelector('.api-sidebar__group[data-group="' + groupId + '"]');
110
+ if (sidebarGroup) sidebarGroup.classList.remove('api-sidebar__group--collapsed');
111
+ }
112
+ }
113
+
114
+ // Expand operation via hash, or expand the first operation by default
115
+ if (window.location.hash) {
116
+ var target = document.querySelector(window.location.hash);
117
+ if (target && target.classList.contains('api-operation')) {
118
+ expandOperationAndGroup(target);
119
+ }
120
+ } else {
121
+ expandOperationAndGroup(document.querySelector('.api-operation'));
122
+ }
123
+
124
+ window.addEventListener('hashchange', function() {
125
+ if (window.location.hash) {
126
+ var target = document.querySelector(window.location.hash);
127
+ if (target && target.classList.contains('api-operation')) {
128
+ expandOperationAndGroup(target);
129
+ }
130
+ }
131
+ });
132
+
133
+ // Try It - Response tab switching
134
+ document.querySelectorAll('.api-try-it__response-tabs').forEach(function(tabs) {
135
+ var container = tabs.closest('.api-try-it__response');
136
+ tabs.querySelectorAll('.api-try-it__rtab').forEach(function(tab) {
137
+ tab.addEventListener('click', function() {
138
+ var target = this.getAttribute('data-try-rtab');
139
+ container.querySelectorAll('.api-try-it__rtab').forEach(function(t) { t.classList.remove('api-try-it__rtab--active'); });
140
+ container.querySelectorAll('.api-try-it__rpanel').forEach(function(p) { p.classList.remove('api-try-it__rpanel--active'); });
141
+ this.classList.add('api-try-it__rtab--active');
142
+ var panel = container.querySelector('[data-try-rpanel="' + target + '"]');
143
+ if (panel) panel.classList.add('api-try-it__rpanel--active');
144
+ });
145
+ });
146
+ });
147
+
148
+ // Try It - Helpers
149
+ function getStatusClass(status) {
150
+ if (status >= 200 && status < 300) return '2xx';
151
+ if (status >= 300 && status < 400) return '3xx';
152
+ if (status >= 400 && status < 500) return '4xx';
153
+ if (status >= 500) return '5xx';
154
+ return 'error';
155
+ }
156
+
157
+ function formatBody(text, contentType) {
158
+ if (contentType && contentType.indexOf('json') !== -1) {
159
+ try { return JSON.stringify(JSON.parse(text), null, 2); } catch(e) { /* ignore */ }
160
+ }
161
+ return text;
162
+ }
163
+
164
+ function resetResponseTabs(responseArea) {
165
+ var tabs = responseArea.querySelectorAll('.api-try-it__rtab');
166
+ var panels = responseArea.querySelectorAll('.api-try-it__rpanel');
167
+ tabs.forEach(function(t) { t.classList.remove('api-try-it__rtab--active'); });
168
+ panels.forEach(function(p) { p.classList.remove('api-try-it__rpanel--active'); });
169
+ tabs[0].classList.add('api-try-it__rtab--active');
170
+ panels[0].classList.add('api-try-it__rpanel--active');
171
+ }
172
+
173
+ // Try It - Send request
174
+ document.querySelectorAll('[data-try-send]').forEach(function(btn) {
175
+ btn.addEventListener('click', function() {
176
+ var tryIt = this.closest('.api-try-it');
177
+ var method = tryIt.getAttribute('data-method');
178
+ var pathTemplate = tryIt.getAttribute('data-path');
179
+ var serverSelect = tryIt.querySelector('[data-try-server]');
180
+ var baseUrl = serverSelect ? serverSelect.value : '';
181
+
182
+ // Substitute path params
183
+ var path = pathTemplate;
184
+ tryIt.querySelectorAll('[data-param-in="path"]').forEach(function(row) {
185
+ var name = row.getAttribute('data-param-name');
186
+ var value = row.querySelector('[data-try-param]').value;
187
+ if (value) {
188
+ path = path.replace('{' + name + '}', encodeURIComponent(value));
189
+ }
190
+ });
191
+
192
+ // Build query string
193
+ var queryParts = [];
194
+ tryIt.querySelectorAll('[data-param-in="query"]').forEach(function(row) {
195
+ var name = row.getAttribute('data-param-name');
196
+ var value = row.querySelector('[data-try-param]').value;
197
+ if (value) queryParts.push(encodeURIComponent(name) + '=' + encodeURIComponent(value));
198
+ });
199
+ var queryString = queryParts.length ? '?' + queryParts.join('&') : '';
200
+
201
+ // Build headers
202
+ var headers = {};
203
+ tryIt.querySelectorAll('[data-param-in="header"]').forEach(function(row) {
204
+ var name = row.getAttribute('data-param-name');
205
+ var value = row.querySelector('[data-try-param]').value;
206
+ if (value) headers[name] = value;
207
+ });
208
+
209
+ // Inject global auth header
210
+ var authType = document.getElementById('api-auth-type');
211
+ var authValue = document.getElementById('api-auth-value');
212
+ if (authType && authValue) {
213
+ var authVal = authValue.value.trim();
214
+ if (authVal) {
215
+ if (authType.value === 'apikey') {
216
+ headers['x-api-key'] = authVal;
217
+ } else if (authType.value === 'bearer') {
218
+ headers['Authorization'] = 'Bearer ' + authVal;
219
+ }
220
+ }
221
+ }
222
+
223
+ // Body
224
+ var bodyTextarea = tryIt.querySelector('[data-try-body]');
225
+ var body = bodyTextarea ? bodyTextarea.value.trim() : '';
226
+ if (body && !headers['Content-Type']) {
227
+ headers['Content-Type'] = tryIt.getAttribute('data-content-type') || 'application/json';
228
+ }
229
+
230
+ var url = baseUrl + path + queryString;
231
+ var fetchOptions = { method: method, headers: headers };
232
+ if (body && method !== 'GET' && method !== 'HEAD') {
233
+ fetchOptions.body = body;
234
+ }
235
+
236
+ // Loading state
237
+ btn.disabled = true;
238
+ btn.textContent = 'Sending...';
239
+ var startTime = performance.now();
240
+
241
+ var responseArea = tryIt.querySelector('[data-try-response]');
242
+ var statusEl = tryIt.querySelector('[data-try-status]');
243
+ var timeEl = tryIt.querySelector('[data-try-time]');
244
+ var bodyEl = tryIt.querySelector('[data-try-response-body]');
245
+ var headersEl = tryIt.querySelector('[data-try-response-headers]');
246
+
247
+ fetch(url, fetchOptions).then(function(response) {
248
+ var elapsed = Math.round(performance.now() - startTime);
249
+ var statusClass = getStatusClass(response.status);
250
+
251
+ statusEl.textContent = response.status + ' ' + response.statusText;
252
+ statusEl.className = 'api-try-it__response-status api-try-it__response-status--' + statusClass;
253
+ timeEl.textContent = elapsed + 'ms';
254
+
255
+ // Collect response headers
256
+ var headerLines = [];
257
+ response.headers.forEach(function(value, key) {
258
+ headerLines.push(key + ': ' + value);
259
+ });
260
+ headersEl.textContent = headerLines.join('\n') || 'No headers';
261
+
262
+ var ct = response.headers.get('content-type') || '';
263
+ return response.text().then(function(text) {
264
+ bodyEl.textContent = formatBody(text, ct);
265
+ responseArea.classList.remove('api-try-it__response--hidden');
266
+ resetResponseTabs(responseArea);
267
+ });
268
+ }).catch(function(err) {
269
+ statusEl.textContent = 'Error';
270
+ statusEl.className = 'api-try-it__response-status api-try-it__response-status--error';
271
+ timeEl.textContent = '';
272
+ headersEl.textContent = '';
273
+ bodyEl.textContent = 'Request failed: ' + err.message + '\n\nThis may be caused by CORS restrictions. The API server must include appropriate CORS headers to allow browser requests.';
274
+ responseArea.classList.remove('api-try-it__response--hidden');
275
+ resetResponseTabs(responseArea);
276
+ }).finally(function() {
277
+ btn.disabled = false;
278
+ btn.textContent = 'Send Request';
279
+ });
280
+ });
281
+ });
282
+ });
@@ -3,28 +3,213 @@
3
3
 
4
4
  <head>
5
5
  {{> header }}
6
- <title>API Documentation - {{ siteTitle }}</title>
7
- <meta name="description" content="API Documentation for {{ siteTitle }}" />
8
- <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@docutopia/react/dist/browser/docutopia.css" />
9
- <style>
10
- body {
11
- margin: 0;
12
- padding: 0;
13
- }
14
- </style>
6
+ <link rel="stylesheet" href="/css/api.css">
7
+ <title>API Reference - {{ siteTitle }}</title>
8
+ <meta name="description" content="API Reference for {{ siteTitle }}" />
15
9
  </head>
16
10
 
17
11
  <body>
18
- <div id="docs" style="height: 100vh;"></div>
19
-
20
- <script src="https://cdn.jsdelivr.net/npm/@docutopia/react/dist/browser/docutopia.js"></script>
21
- <script>
22
- Docutopia.render('docs', {
23
- specUrl: '{{ specUrl }}',
24
- basename: '/api',
25
- });
26
- </script>
12
+ {{> header-bar }}
13
+
14
+ {{#if apiSpec}}
15
+ <div class="api-mobile-toggle">
16
+ <button id="api-sidebar-toggle">
17
+ <span>API Navigation</span>
18
+ <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m7 15 5 5 5-5"/><path d="m7 9 5-5 5 5"/></svg>
19
+ </button>
20
+ </div>
21
+
22
+ <div class="api-reference">
23
+ <aside class="api-sidebar" id="api-sidebar">
24
+ <input type="text" class="api-search" id="api-search" placeholder="Search endpoints..." />
25
+
26
+ {{#each apiSpec.groups}}
27
+ <div class="api-sidebar__group" data-group="{{this.id}}">
28
+ <button class="api-sidebar__group-toggle">
29
+ <span>{{this.name}}</span>
30
+ <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
31
+ </button>
32
+ <div class="api-sidebar__group-items">
33
+ {{#each this.operations}}
34
+ <a href="#{{this.id}}" class="api-sidebar__item" data-method="{{this.method}}" data-path="{{this.path}}">
35
+ <span class="method-badge method-badge--{{this.method}}">{{this.methodUpper}}</span>
36
+ <span class="api-sidebar__item-path">{{this.path}}</span>
37
+ </a>
38
+ {{/each}}
39
+ </div>
40
+ </div>
41
+ {{/each}}
42
+ </aside>
43
+
44
+ <main class="api-content">
45
+ <section class="api-info">
46
+ <h1 class="api-info__title">{{apiSpec.info.title}}</h1>
47
+ {{#if apiSpec.info.version}}
48
+ <span class="api-info__version">v{{apiSpec.info.version}}</span>
49
+ {{/if}}
50
+ {{#if apiSpec.info.description}}
51
+ <div class="api-info__description">{{{apiSpec.info.description}}}</div>
52
+ {{/if}}
53
+ {{#if apiSpec.servers}}
54
+ <div class="api-info__servers">
55
+ <div class="api-info__server-label">Server</div>
56
+ {{#each apiSpec.servers}}
57
+ <code class="api-info__server-url">{{this.url}}</code>
58
+ {{/each}}
59
+ </div>
60
+ {{/if}}
61
+ <div class="api-auth">
62
+ <div class="api-auth__label">Authorization</div>
63
+ <div class="api-auth__controls">
64
+ <select class="api-auth__type" id="api-auth-type">
65
+ <option value="none">None</option>
66
+ <option value="apikey">API Key (x-api-key)</option>
67
+ <option value="bearer">Bearer Token</option>
68
+ </select>
69
+ <input type="password" class="api-auth__value api-auth__value--hidden" id="api-auth-value" placeholder="Enter value..." />
70
+ </div>
71
+ </div>
72
+ </section>
73
+
74
+ {{#each apiSpec.groups}}
75
+ <div class="api-group" id="group-{{this.id}}">
76
+ <div class="api-group__header">
77
+ <h2 class="api-group__title">{{this.name}}</h2>
78
+ {{#if this.description}}
79
+ <div class="api-group__description">{{{this.description}}}</div>
80
+ {{/if}}
81
+ </div>
82
+
83
+ {{#each this.operations}}
84
+ <div class="api-operation api-operation--collapsed" id="{{this.id}}">
85
+ <div class="api-operation__header" data-toggle="operation">
86
+ <span class="method-badge method-badge--{{this.method}}">{{this.methodUpper}}</span>
87
+ <span class="api-operation__path">{{this.path}}</span>
88
+ {{#if this.summary}}
89
+ <span class="api-operation__summary">{{this.summary}}</span>
90
+ {{/if}}
91
+ <svg class="api-operation__toggle-icon" xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"/></svg>
92
+ </div>
93
+ <div class="api-operation__body">
94
+ <div class="api-operation__docs">
95
+ {{#if this.description}}
96
+ <div class="api-operation__description">{{{this.description}}}</div>
97
+ {{/if}}
98
+
99
+ {{#if this.parameters.length}}
100
+ <div class="api-section-title">Parameters</div>
101
+ <table class="api-params-table">
102
+ <thead>
103
+ <tr>
104
+ <th>Name</th>
105
+ <th>Type</th>
106
+ <th>In</th>
107
+ <th>Description</th>
108
+ </tr>
109
+ </thead>
110
+ <tbody>
111
+ {{#each this.parameters}}
112
+ <tr>
113
+ <td>
114
+ <span class="api-param-name">{{this.name}}</span>
115
+ {{#if this.required}}<span class="api-param-required">*</span>{{/if}}
116
+ </td>
117
+ <td><span class="api-param-type">{{this.type}}</span></td>
118
+ <td><span class="api-param-in">{{this.in}}</span></td>
119
+ <td><span class="api-param-desc">{{this.description}}</span></td>
120
+ </tr>
121
+ {{/each}}
122
+ </tbody>
123
+ </table>
124
+ {{/if}}
125
+
126
+ {{#if this.requestBody}}
127
+ <div class="api-section-title">Request Body <span class="api-param-type">{{this.requestBody.contentType}}</span></div>
128
+ {{#if this.requestBody.schemaProperties.length}}
129
+ <div class="api-schema">
130
+ <div class="api-schema-props">
131
+ {{#each this.requestBody.schemaProperties}}
132
+ <div class="api-schema-prop">
133
+ <span class="api-schema-prop-name">{{this.name}}{{#if this.required}}<span class="api-param-required">*</span>{{/if}}</span>
134
+ <span class="api-schema-prop-type">{{this.type}}</span>
135
+ <span class="api-schema-prop-desc">{{this.description}}</span>
136
+ </div>
137
+ {{/each}}
138
+ </div>
139
+ </div>
140
+ {{/if}}
141
+ {{#if this.requestBody.example}}
142
+ <div class="api-response__example">
143
+ <pre><code>{{this.requestBody.example}}</code></pre>
144
+ </div>
145
+ {{/if}}
146
+ {{/if}}
147
+
148
+ {{#if this.responses.length}}
149
+ <div class="api-section-title">Responses</div>
150
+ {{#each this.responses}}
151
+ <div class="api-response">
152
+ <div class="api-response__status">
153
+ <span class="api-status-code api-status-code--{{this.statusClass}}">{{this.statusCode}}</span>
154
+ <span class="api-response__desc">{{this.description}}</span>
155
+ </div>
156
+ {{#if this.schemaProperties.length}}
157
+ <div class="api-schema">
158
+ <div class="api-schema-props">
159
+ {{#each this.schemaProperties}}
160
+ <div class="api-schema-prop">
161
+ <span class="api-schema-prop-name">{{this.name}}</span>
162
+ <span class="api-schema-prop-type">{{this.type}}</span>
163
+ <span class="api-schema-prop-desc">{{this.description}}</span>
164
+ </div>
165
+ {{/each}}
166
+ </div>
167
+ </div>
168
+ {{/if}}
169
+ {{#if this.example}}
170
+ <div class="api-response__example">
171
+ <pre><code>{{this.example}}</code></pre>
172
+ </div>
173
+ {{/if}}
174
+ </div>
175
+ {{/each}}
176
+ {{/if}}
177
+
178
+ <div class="api-code-examples">
179
+ <div class="api-code-tabs">
180
+ <button class="api-code-tab api-code-tab--active" data-tab="curl">cURL</button>
181
+ <button class="api-code-tab" data-tab="javascript">JavaScript</button>
182
+ <button class="api-code-tab" data-tab="python">Python</button>
183
+ </div>
184
+ <div class="api-code-panel api-code-panel--active" data-panel="curl">
185
+ <button class="api-copy-btn" data-copy>Copy</button>
186
+ <pre><code>{{this.codeExamples.curl}}</code></pre>
187
+ </div>
188
+ <div class="api-code-panel" data-panel="javascript">
189
+ <button class="api-copy-btn" data-copy>Copy</button>
190
+ <pre><code>{{this.codeExamples.javascript}}</code></pre>
191
+ </div>
192
+ <div class="api-code-panel" data-panel="python">
193
+ <button class="api-copy-btn" data-copy>Copy</button>
194
+ <pre><code>{{this.codeExamples.python}}</code></pre>
195
+ </div>
196
+ </div>
197
+ </div>
198
+
199
+ {{> api-try-it }}
200
+ </div>
201
+ </div>
202
+ {{/each}}
203
+ </div>
204
+ {{/each}}
205
+ </main>
206
+ </div>
207
+ {{/if}}
208
+
209
+ {{> footer }}
27
210
  {{> scripts }}
211
+
212
+ <script src="/js/api.js"></script>
28
213
  </body>
29
214
 
30
215
  </html>