@prauga/flexdoc-backend 2.1.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.
- package/README.md +227 -0
- package/dist/flexdoc.module.d.ts +14 -0
- package/dist/flexdoc.module.js +77 -0
- package/dist/flexdoc.module.js.map +1 -0
- package/dist/flexdoc.module.test.d.ts +1 -0
- package/dist/flexdoc.module.test.js +72 -0
- package/dist/flexdoc.module.test.js.map +1 -0
- package/dist/flexdoc.service.d.ts +5 -0
- package/dist/flexdoc.service.js +24 -0
- package/dist/flexdoc.service.js.map +1 -0
- package/dist/framework-adapters.d.ts +25 -0
- package/dist/framework-adapters.js +163 -0
- package/dist/framework-adapters.js.map +1 -0
- package/dist/framework-adapters.test.d.ts +1 -0
- package/dist/framework-adapters.test.js +37 -0
- package/dist/framework-adapters.test.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces.d.ts +169 -0
- package/dist/interfaces.js +3 -0
- package/dist/interfaces.js.map +1 -0
- package/dist/renderer/flexdoc.standalone.css +1 -0
- package/dist/renderer/flexdoc.standalone.js +200 -0
- package/dist/renderer-assets.d.ts +5 -0
- package/dist/renderer-assets.js +60 -0
- package/dist/renderer-assets.js.map +1 -0
- package/dist/scripts/generate-auth.d.ts +2 -0
- package/dist/scripts/generate-auth.js +107 -0
- package/dist/scripts/generate-auth.js.map +1 -0
- package/dist/setup.d.ts +6 -0
- package/dist/setup.js +220 -0
- package/dist/setup.js.map +1 -0
- package/dist/setup.test.d.ts +1 -0
- package/dist/setup.test.js +89 -0
- package/dist/setup.test.js.map +1 -0
- package/dist/template.d.ts +15 -0
- package/dist/template.js +64 -0
- package/dist/template.js.map +1 -0
- package/dist/template.test.d.ts +1 -0
- package/dist/template.test.js +38 -0
- package/dist/template.test.js.map +1 -0
- package/dist/templates/code-examples.njk +106 -0
- package/dist/templates/content.njk +272 -0
- package/dist/templates/footer.njk +38 -0
- package/dist/templates/header.njk +57 -0
- package/dist/templates/layout.njk +647 -0
- package/dist/templates/parameters.njk +64 -0
- package/dist/templates/request-body.njk +63 -0
- package/dist/templates/responses.njk +78 -0
- package/dist/templates/sidebar.njk +117 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +34 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{% if operation.parameters and operation.parameters.length > 0 %}
|
|
2
|
+
<div class="mb-8">
|
|
3
|
+
<button class="flex items-center gap-2 text-lg font-semibold text-gray-900 dark:text-white mb-4 hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
|
|
4
|
+
data-toggle="parameters-{{ getOperationId(path, method, operation) }}">
|
|
5
|
+
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
|
6
|
+
Parameters
|
|
7
|
+
</button>
|
|
8
|
+
|
|
9
|
+
<div id="parameters-{{ getOperationId(path, method, operation) }}" class="collapsible-content expanded">
|
|
10
|
+
<div class="bg-gray-50 dark:bg-gray-700/50 rounded-xl p-6 border border-gray-200 dark:border-gray-600">
|
|
11
|
+
<div class="space-y-4">
|
|
12
|
+
{% for param in operation.parameters %}
|
|
13
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg p-4 border border-gray-200 dark:border-gray-700">
|
|
14
|
+
<div class="flex items-center gap-2 mb-2">
|
|
15
|
+
<code class="font-mono font-medium text-gray-900 dark:text-white">{{ param.name }}</code>
|
|
16
|
+
<span class="px-2 py-1 text-xs font-medium rounded-md
|
|
17
|
+
{% if param.in == 'path' %}bg-purple-100 text-purple-700 dark:bg-purple-900 dark:text-purple-300
|
|
18
|
+
{% elif param.in == 'query' %}bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300
|
|
19
|
+
{% elif param.in == 'header' %}bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300
|
|
20
|
+
{% else %}bg-gray-100 text-gray-700 dark:bg-gray-700 dark:text-gray-300{% endif %}">
|
|
21
|
+
{{ param.in }}
|
|
22
|
+
</span>
|
|
23
|
+
{% if param.required %}
|
|
24
|
+
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300 rounded-md">
|
|
25
|
+
required
|
|
26
|
+
</span>
|
|
27
|
+
{% endif %}
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
{% if param.description %}
|
|
31
|
+
<p class="text-sm text-gray-600 dark:text-gray-400 mb-3">{{ param.description }}</p>
|
|
32
|
+
{% endif %}
|
|
33
|
+
|
|
34
|
+
{% if param.schema %}
|
|
35
|
+
<div class="flex items-center gap-2 text-sm">
|
|
36
|
+
<span class="text-gray-500 dark:text-gray-400">Type:</span>
|
|
37
|
+
<code class="bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded text-gray-900 dark:text-white">
|
|
38
|
+
{{ param.schema.type }}{% if param.schema.format %} ({{ param.schema.format }}){% endif %}
|
|
39
|
+
</code>
|
|
40
|
+
{% if param.schema.enum %}
|
|
41
|
+
<span class="text-gray-500 dark:text-gray-400">•</span>
|
|
42
|
+
<span class="text-gray-500 dark:text-gray-400">Enum:</span>
|
|
43
|
+
<code class="bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded text-gray-900 dark:text-white">
|
|
44
|
+
{{ param.schema.enum | join(', ') }}
|
|
45
|
+
</code>
|
|
46
|
+
{% endif %}
|
|
47
|
+
</div>
|
|
48
|
+
{% endif %}
|
|
49
|
+
|
|
50
|
+
{% if param.schema and param.schema.example %}
|
|
51
|
+
<div class="mt-3">
|
|
52
|
+
<span class="text-sm text-gray-500 dark:text-gray-400 mb-1 block">Example:</span>
|
|
53
|
+
<code class="bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded text-gray-900 dark:text-white text-sm">
|
|
54
|
+
{{ param.schema.example }}
|
|
55
|
+
</code>
|
|
56
|
+
</div>
|
|
57
|
+
{% endif %}
|
|
58
|
+
</div>
|
|
59
|
+
{% endfor %}
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
</div>
|
|
64
|
+
{% endif %}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{% if operation.requestBody %}
|
|
2
|
+
<div class="mb-8">
|
|
3
|
+
<button class="flex items-center gap-2 text-lg font-semibold text-gray-900 dark:text-white mb-4 hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
|
|
4
|
+
data-toggle="request-body-{{ getOperationId(path, method, operation) }}">
|
|
5
|
+
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
|
6
|
+
Request Body
|
|
7
|
+
{% if operation.requestBody.required %}
|
|
8
|
+
<span class="px-2 py-1 text-xs font-medium bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300 rounded-md">
|
|
9
|
+
required
|
|
10
|
+
</span>
|
|
11
|
+
{% endif %}
|
|
12
|
+
</button>
|
|
13
|
+
|
|
14
|
+
<div id="request-body-{{ getOperationId(path, method, operation) }}" class="collapsible-content">
|
|
15
|
+
<div class="bg-gray-50 dark:bg-gray-700/50 rounded-xl p-6 border border-gray-200 dark:border-gray-600">
|
|
16
|
+
{% if operation.requestBody.description %}
|
|
17
|
+
<p class="text-gray-600 dark:text-gray-400 mb-4">{{ operation.requestBody.description }}</p>
|
|
18
|
+
{% endif %}
|
|
19
|
+
|
|
20
|
+
{% if operation.requestBody.content %}
|
|
21
|
+
<div class="space-y-4">
|
|
22
|
+
{% for contentType, content in operation.requestBody.content %}
|
|
23
|
+
<div class="bg-white dark:bg-gray-800 rounded-lg border border-gray-200 dark:border-gray-700 overflow-hidden">
|
|
24
|
+
<div class="px-4 py-3 bg-gray-50 dark:bg-gray-700 border-b border-gray-200 dark:border-gray-600">
|
|
25
|
+
<div class="flex items-center gap-2">
|
|
26
|
+
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Content Type:</span>
|
|
27
|
+
<code class="bg-gray-100 dark:bg-gray-600 px-2 py-1 rounded text-sm text-gray-900 dark:text-white">
|
|
28
|
+
{{ contentType }}
|
|
29
|
+
</code>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
|
|
33
|
+
<div class="p-4">
|
|
34
|
+
{% if content.schema %}
|
|
35
|
+
<div class="code-block">
|
|
36
|
+
<pre class="text-gray-300">{{ renderSchema(content.schema) | safe }}</pre>
|
|
37
|
+
</div>
|
|
38
|
+
{% endif %}
|
|
39
|
+
|
|
40
|
+
{% if content.example %}
|
|
41
|
+
<div class="mt-4">
|
|
42
|
+
<div class="flex items-center justify-between mb-2">
|
|
43
|
+
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Example:</span>
|
|
44
|
+
<button class="text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
|
|
45
|
+
data-copy="{{ renderExample(content.example) }}">
|
|
46
|
+
<i data-lucide="copy" class="w-3 h-3 inline mr-1"></i>
|
|
47
|
+
Copy
|
|
48
|
+
</button>
|
|
49
|
+
</div>
|
|
50
|
+
<div class="code-block">
|
|
51
|
+
<pre class="text-gray-300">{{ renderExample(content.example) | safe }}</pre>
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
{% endif %}
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
{% endfor %}
|
|
58
|
+
</div>
|
|
59
|
+
{% endif %}
|
|
60
|
+
</div>
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
{% endif %}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{% if operation.responses %}
|
|
2
|
+
<div class="mb-8">
|
|
3
|
+
<button class="flex items-center gap-2 text-lg font-semibold text-gray-900 dark:text-white mb-4 hover:text-primary-600 dark:hover:text-primary-400 transition-colors"
|
|
4
|
+
data-toggle="responses-{{ getOperationId(path, method, operation) }}">
|
|
5
|
+
<i data-lucide="chevron-down" class="w-5 h-5"></i>
|
|
6
|
+
Responses
|
|
7
|
+
</button>
|
|
8
|
+
|
|
9
|
+
<div id="responses-{{ getOperationId(path, method, operation) }}" class="collapsible-content">
|
|
10
|
+
<div class="space-y-4">
|
|
11
|
+
{% for statusCode, response in operation.responses %}
|
|
12
|
+
<div class="bg-white dark:bg-gray-800 rounded-xl border border-gray-200 dark:border-gray-700 overflow-hidden">
|
|
13
|
+
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-700/50 border-b border-gray-200 dark:border-gray-600">
|
|
14
|
+
<div class="flex items-center gap-3">
|
|
15
|
+
<span class="px-3 py-1 text-sm font-bold rounded-lg border {{ getStatusCodeClass(statusCode) }}">
|
|
16
|
+
{{ statusCode }}
|
|
17
|
+
</span>
|
|
18
|
+
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">
|
|
19
|
+
{{ getStatusText(statusCode) }}
|
|
20
|
+
</span>
|
|
21
|
+
{% if response.description %}
|
|
22
|
+
<span class="text-sm text-gray-600 dark:text-gray-400">• {{ response.description }}</span>
|
|
23
|
+
{% endif %}
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
|
|
27
|
+
{% if response.content %}
|
|
28
|
+
<div class="p-6">
|
|
29
|
+
{% for contentType, content in response.content %}
|
|
30
|
+
<div class="mb-4 last:mb-0">
|
|
31
|
+
<div class="flex items-center gap-2 mb-3">
|
|
32
|
+
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Content Type:</span>
|
|
33
|
+
<code class="bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded text-sm text-gray-900 dark:text-white">
|
|
34
|
+
{{ contentType }}
|
|
35
|
+
</code>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
{% if content.schema %}
|
|
39
|
+
<div class="mb-4">
|
|
40
|
+
<div class="flex items-center justify-between mb-2">
|
|
41
|
+
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Schema:</span>
|
|
42
|
+
<button class="text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
|
|
43
|
+
data-copy="{{ renderSchema(content.schema) }}">
|
|
44
|
+
<i data-lucide="copy" class="w-3 h-3 inline mr-1"></i>
|
|
45
|
+
Copy
|
|
46
|
+
</button>
|
|
47
|
+
</div>
|
|
48
|
+
<div class="code-block">
|
|
49
|
+
<pre class="text-gray-300">{{ renderSchema(content.schema) | safe }}</pre>
|
|
50
|
+
</div>
|
|
51
|
+
</div>
|
|
52
|
+
{% endif %}
|
|
53
|
+
|
|
54
|
+
{% if content.example %}
|
|
55
|
+
<div>
|
|
56
|
+
<div class="flex items-center justify-between mb-2">
|
|
57
|
+
<span class="text-sm font-medium text-gray-700 dark:text-gray-300">Example:</span>
|
|
58
|
+
<button class="text-xs text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-300 transition-colors"
|
|
59
|
+
data-copy="{{ renderExample(content.example) }}">
|
|
60
|
+
<i data-lucide="copy" class="w-3 h-3 inline mr-1"></i>
|
|
61
|
+
Copy
|
|
62
|
+
</button>
|
|
63
|
+
</div>
|
|
64
|
+
<div class="code-block">
|
|
65
|
+
<pre class="text-gray-300">{{ renderExample(content.example) | safe }}</pre>
|
|
66
|
+
</div>
|
|
67
|
+
</div>
|
|
68
|
+
{% endif %}
|
|
69
|
+
</div>
|
|
70
|
+
{% endfor %}
|
|
71
|
+
</div>
|
|
72
|
+
{% endif %}
|
|
73
|
+
</div>
|
|
74
|
+
{% endfor %}
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
{% endif %}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
<aside class="sidebar w-80 border-r flex flex-col fixed top-0 left-0 z-10 pt-16 h-screen overflow-y-auto pb-16">
|
|
2
|
+
<div class="px-6 pt-4 pb-2">
|
|
3
|
+
<!-- Search -->
|
|
4
|
+
<div class="relative mb-6">
|
|
5
|
+
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
|
|
6
|
+
<i data-lucide="search" class="h-4 w-4 text-gray-400"></i>
|
|
7
|
+
</div>
|
|
8
|
+
<input id="search-input"
|
|
9
|
+
type="text"
|
|
10
|
+
class="block w-full pl-10 pr-3 py-2 border border-gray-300 dark:border-gray-600 rounded-lg bg-white dark:bg-gray-700 text-gray-900 dark:text-white placeholder-gray-500 dark:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-primary-500 focus:border-transparent text-sm"
|
|
11
|
+
placeholder="Search endpoints...">
|
|
12
|
+
</div>
|
|
13
|
+
|
|
14
|
+
<!-- API Info -->
|
|
15
|
+
{% if currentSpec and currentSpec.info %}
|
|
16
|
+
<div class="mb-6">
|
|
17
|
+
<div class="bg-gradient-to-br from-primary-50 to-primary-100 dark:from-primary-900/20 dark:to-primary-800/20 rounded-xl p-4 border border-primary-200 dark:border-primary-800">
|
|
18
|
+
<h3 class="font-semibold text-primary-900 dark:text-primary-100 mb-2">{{ currentSpec.info.title }}</h3>
|
|
19
|
+
{% if altDescription %}
|
|
20
|
+
<p class="text-sm text-primary-700 dark:text-primary-300 mb-3">{{ altDescription }}</p>
|
|
21
|
+
{% elif currentSpec.info.description %}
|
|
22
|
+
<p class="text-sm text-primary-700 dark:text-primary-300 mb-3">{{ currentSpec.info.description }}</p>
|
|
23
|
+
{% endif %}
|
|
24
|
+
|
|
25
|
+
<div class="flex items-center justify-between text-xs">
|
|
26
|
+
<span class="text-primary-600 dark:text-primary-400">Version {{ currentSpec.info.version }}</span>
|
|
27
|
+
{% if currentSpec.servers and currentSpec.servers.length > 0 %}
|
|
28
|
+
<span class="text-primary-600 dark:text-primary-400">{{ currentSpec.servers.length }} server{{ 's' if currentSpec.servers.length > 1 else '' }}</span>
|
|
29
|
+
{% endif %}
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
{% endif %}
|
|
34
|
+
|
|
35
|
+
<!-- Servers -->
|
|
36
|
+
{% if showServersInSidebar and currentSpec and currentSpec.servers and currentSpec.servers.length > 0 %}
|
|
37
|
+
<div class="mb-2">
|
|
38
|
+
<button class="tag-toggle flex items-center justify-between w-full text-left mb-3" data-target="servers">
|
|
39
|
+
<h3 class="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Servers</h3>
|
|
40
|
+
<i data-lucide="chevron-right" class="w-4 h-4 text-gray-500"></i>
|
|
41
|
+
</button>
|
|
42
|
+
<div id="servers" class="collapsible-content">
|
|
43
|
+
<div class="space-y-2 max-h-40 overflow-auto pr-1 py-2">
|
|
44
|
+
{% for server in currentSpec.servers %}
|
|
45
|
+
<div class="bg-gray-50 dark:bg-gray-700 rounded-lg p-3">
|
|
46
|
+
<code class="text-sm text-primary-600 dark:text-primary-400 font-mono">{{ server.url }}</code>
|
|
47
|
+
{% if server.description %}
|
|
48
|
+
<p class="text-xs text-gray-600 dark:text-gray-400 mt-1">{{ server.description }}</p>
|
|
49
|
+
{% endif %}
|
|
50
|
+
</div>
|
|
51
|
+
{% endfor %}
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
{% endif %}
|
|
56
|
+
</div>
|
|
57
|
+
|
|
58
|
+
<!-- Navigation -->
|
|
59
|
+
<nav class="px-4 pb-6 flex-1 overflow-y-auto min-h-0">
|
|
60
|
+
<button class="tag-toggle flex items-center justify-between w-full px-2 text-left mb-3" data-target="endpoints-list">
|
|
61
|
+
<h3 class="text-xs font-semibold text-gray-500 dark:text-gray-400 uppercase tracking-wider">Endpoints</h3>
|
|
62
|
+
<i data-lucide="chevron-down" class="w-4 h-4 text-gray-500"></i>
|
|
63
|
+
</button>
|
|
64
|
+
|
|
65
|
+
<div id="endpoints-list" class="collapsible-content expanded">
|
|
66
|
+
|
|
67
|
+
{% for tag, paths in taggedPaths %}
|
|
68
|
+
<div class="tag-section mb-4">
|
|
69
|
+
<button class="tag-toggle flex items-center justify-between w-full px-2 py-2 text-left hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
|
|
70
|
+
data-target="tag-{{ tag | lower | replace(' ', '-') }}">
|
|
71
|
+
<div class="flex items-center gap-2">
|
|
72
|
+
<i data-lucide="chevron-right" class="w-4 h-4 text-gray-500"></i>
|
|
73
|
+
<h4 class="text-sm font-medium text-gray-900 dark:text-white capitalize">
|
|
74
|
+
{% if tagGroups[tag] %}{{ tagGroups[tag] }}{% elseif tag == 'default' %}General{% else %}{{ tag }}{% endif %}
|
|
75
|
+
</h4>
|
|
76
|
+
</div>
|
|
77
|
+
<span class="text-xs text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-700 px-2 py-1 rounded-full">
|
|
78
|
+
{% set count = 0 %}
|
|
79
|
+
{% for path, methods in paths %}
|
|
80
|
+
{% for method, operation in methods %}
|
|
81
|
+
{% set count = count + 1 %}
|
|
82
|
+
{% endfor %}
|
|
83
|
+
{% endfor %}
|
|
84
|
+
{{ count }}
|
|
85
|
+
</span>
|
|
86
|
+
</button>
|
|
87
|
+
|
|
88
|
+
<div id="tag-{{ tag | lower | replace(' ', '-') }}" class="collapsible-content ml-6 mt-2">
|
|
89
|
+
<div class="space-y-1">
|
|
90
|
+
{% for path, methods in paths %}
|
|
91
|
+
{% for method, operation in methods %}
|
|
92
|
+
<a href="#{{ getOperationId(path, method, operation) }}"
|
|
93
|
+
class="endpoint-item endpoint-link group flex items-start px-2 py-2 text-sm rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 transition-colors"
|
|
94
|
+
data-endpoint="{{ getOperationId(path, method, operation) }}">
|
|
95
|
+
<span class="flex-shrink-0 mr-3 mt-0.5 px-2 py-1 text-xs font-bold rounded border method-{{ method }}">
|
|
96
|
+
{{ method | upper }}
|
|
97
|
+
</span>
|
|
98
|
+
<div class="flex-1 min-w-0">
|
|
99
|
+
<div class="font-mono text-sm text-gray-900 dark:text-white truncate group-hover:text-primary-600 dark:group-hover:text-primary-400 transition-colors">
|
|
100
|
+
{{ path }}
|
|
101
|
+
</div>
|
|
102
|
+
{% if operation.summary %}
|
|
103
|
+
<div class="text-xs text-gray-500 dark:text-gray-400 mt-1 line-clamp-2">
|
|
104
|
+
{{ operation.summary }}
|
|
105
|
+
</div>
|
|
106
|
+
{% endif %}
|
|
107
|
+
</div>
|
|
108
|
+
</a>
|
|
109
|
+
{% endfor %}
|
|
110
|
+
{% endfor %}
|
|
111
|
+
</div>
|
|
112
|
+
</div>
|
|
113
|
+
</div>
|
|
114
|
+
{% endfor %}
|
|
115
|
+
</div>
|
|
116
|
+
</nav>
|
|
117
|
+
</aside>
|