1- ` ` ` bash
21#! /bin/bash
32
43# Script to generate HTML documentation from all API specs using Redocly
@@ -38,6 +37,7 @@ success_count=0
3837error_count=0
3938> " $ERROR_LOG "
4039
40+
4141convert_spec_to_html () {
4242 local spec_file=" $1 "
4343 local relative_path=" ${spec_file# $SPECS_DIR / } "
@@ -64,139 +64,49 @@ for spec_file in "${spec_files[@]}"; do
6464 convert_spec_to_html " $spec_file " || true
6565done
6666
67+
68+
6769# Generate index.html
6870cat > " $INDEX_FILE " << 'EOF '
6971<!DOCTYPE html>
7072<html lang="en">
7173<head>
72- <meta charset="UTF-8">
73- <meta name="viewport" content="width=device-width, initial-scale=1.0">
74- <title>Devtron API Documentation</title>
75- <style>
76- /* General body and container styles */
77- body {
78- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
79- margin: 0;
80- padding: 0;
81- background-color: #f0f2f5;
82- color: #2c3e50;
83- }
84- .container {
85- max-width: 1200px;
86- margin: 20px auto;
87- padding: 0 20px;
88- }
89- /* Header styles */
90- .header {
91- background-color: #ffffff;
92- padding: 20px;
93- border-bottom: 1px solid #dfe3e8;
94- text-align: center;
95- box-shadow: 0 2px 4px rgba(0,0,0,0.05);
96- }
97- .header-title {
98- font-size: 2.5rem;
99- font-weight: 600;
100- color: #3b5998;
101- margin: 0;
102- display: flex;
103- align-items: center;
104- justify-content: center;
105- }
106- .header-title img {
107- height: 40px;
108- margin-right: 10px;
109- }
110- .header-subtitle {
111- font-size: 1rem;
112- color: #606770;
113- margin-top: 10px;
114- }
115- /* Grid and card styles */
116- .grid {
117- display: grid;
118- grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
119- gap: 20px;
120- margin-top: 20px;
121- }
122- .card {
123- background-color: #ffffff;
124- border-radius: 8px;
125- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
126- overflow: hidden;
127- padding: 20px;
128- }
129- .card-header {
130- font-size: 1.25rem;
131- font-weight: 600;
132- color: #3b5998;
133- padding-bottom: 10px;
134- margin-bottom: 15px;
135- border-bottom: 2px solid #3b5998;
136- }
137- .card-list {
138- list-style: none;
139- padding: 0;
140- margin: 0;
141- }
142- .card-list li {
143- margin-bottom: 10px;
144- }
145- .card-list a {
146- text-decoration: none;
147- color: #1877f2;
148- font-size: 1rem;
149- transition: color 0.2s ease-in-out;
150- }
151- .card-list a:hover {
152- color: #3b5998;
153- text-decoration: underline;
154- }
155- /* Footer styles */
156- .footer {
157- margin-top: 40px;
158- padding: 20px 0;
159- text-align: center;
160- border-top: 1px solid #dfe3e8;
161- color: #606770;
162- }
163- .footer a {
164- color: #1877f2;
165- text-decoration: none;
166- }
167- .footer a:hover {
168- text-decoration: underline;
169- }
170- .timestamp {
171- font-style: italic;
172- font-size: 0.9rem;
173- color: #8d949e;
174- }
175- </style>
74+ <meta charset="UTF-8">
75+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
76+ <title>Devtron API Documentation</title>
77+ <style>
78+ body { font-family: Arial, sans-serif; margin: 20px; background: #f8f9fa; color: #333; }
79+ h1 { text-align: center; color: #2c3e50; }
80+ h2 { text-align: center; margin-top: 40px; color: #34495e; }
81+ .container { max-width: 1200px; margin: auto; }
82+ .grid { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px; margin-top: 20px; }
83+ .card { background: #fff; border-radius: 8px; padding: 15px; width: calc(25% - 20px); box-shadow: 0 2px 6px rgba(0,0,0,0.1); text-align: center; }
84+ .card a { text-decoration: none; color: #1a73e8; font-weight: bold; }
85+ .card a:hover { text-decoration: underline; }
86+ .footer { margin-top: 40px; font-size: 0.9rem; color: #666; text-align: center; }
87+ .footer a { color: #1a73e8; text-decoration: none; }
88+ .footer a:hover { text-decoration: underline; }
89+ .timestamp { font-style: italic; }
90+ @media(max-width: 1024px){ .card { width: calc(33.33% - 20px); } }
91+ @media(max-width: 768px){ .card { width: calc(50% - 20px); } }
92+ @media(max-width: 480px){ .card { width: 100%; } }
93+ </style>
17694</head>
17795<body>
178- <div class="header">
179- <h1 class="header-title">
180- <img src="https://devtron.ai/assets/icons/logo-full.svg" alt="Devtron Logo">
181- Devtron API Documentation
182- </h1>
183- <p class="header-subtitle">Comprehensive API documentation for Devtron - Kubernetes-native software delivery platform</p>
184- </div>
185- <div class="container">
186- <div class="grid" id="categories"></div>
187- <div class="footer">
188- <p>
189- <a href="https://devtron.ai/" target="_blank">Devtron</a> |
190- <a href="https://docs.devtron.ai/" target="_blank">Documentation</a> |
191- <a href="https://github.com/devtron-labs/devtron" target="_blank">GitHub</a>
192- </p>
193- <p class="timestamp">Last updated: <span id="timestamp"></span></p>
194- </div>
195- </div>
196- <script>
197- const apiData = {
96+ <div class="container">
97+ <h1>🚀 Devtron API Documentation</h1>
98+ <div id="categories"></div>
99+ <div class="footer">
100+ <p><a href="https://devtron.ai/" target="_blank">Devtron</a></p>
101+ <p class="timestamp">Last updated: <span id="timestamp"></span></p>
102+ </div>
103+ </div>
104+ <script>
105+ const apiData = {
198106EOF
199107
108+
109+
200110# Populate apiData preserving folder structure
201111for spec_file in " ${spec_files[@]} " ; do
202112 relative_path=" ${spec_file# $SPECS_DIR / } "
@@ -208,58 +118,60 @@ for spec_file in "${spec_files[@]}"; do
208118 title=$( grep -m 1 ' ^[[:space:]]*title:' " $spec_file " | sed ' s/^[[:space:]]*title:[[:space:]]*//' | tr -d ' "' || echo " ${relative_path% .* } " )
209119
210120 if [[ -f " $OUTPUT_DIR /$html_file " ]]; then
211- echo " \" ${category} _$( basename " ${relative_path% .* } " ) \" : {\" category\" : \" ${display_category} \" , \" title\" : \" ${title} \" , \" filename\" : \" ${html_file} \" }," >> " $INDEX_FILE "
121+ echo " \" ${category} _$( basename " ${relative_path% .* } " ) \" : {\" category\" : \" ${display_category} \" , \" title\" : \" ${title} \" , \" filename\" : \" ${html_file} \" }," >> " $INDEX_FILE "
212122 fi
213123done
214124
215125sed -i ' $ s/,$//' " $INDEX_FILE "
216126
127+
128+
217129cat >> " $INDEX_FILE " << 'EOF '
218- };
219-
220- function populatePage() {
221- const container = document.getElementById('categories');
222- const categories = {};
223-
224- Object.values(apiData).forEach(api => {
225- if (!categories[api.category]) categories[api.category] = [];
226- categories[api.category].push(api);
227- });
228-
229- Object.keys(categories).sort().forEach(cat => {
230- const card = document.createElement('div');
231- card.className = "card";
232-
233- const cardHeader = document.createElement('div');
234- cardHeader.className = "card-header";
235- cardHeader.textContent = cat;
236- card.appendChild(cardHeader);
237-
238- const list = document.createElement('ul');
239- list.className = "card-list";
240-
241- categories[cat].sort((a, b) => a.title.localeCompare(b.title)).forEach(api => {
242- const listItem = document.createElement('li');
243- const a = document.createElement('a');
244- a.href = api.filename;
245- a.textContent = api.title;
246- listItem.appendChild(a);
247- list.appendChild(listItem);
248- });
249-
250- card.appendChild(list);
251- container.appendChild(card);
252- });
253-
254- document.getElementById('timestamp').textContent = new Date().toLocaleString();
255- }
130+ };
131+
132+ function populatePage() {
133+ const container = document.getElementById('categories');
134+ const categories = {};
135+
136+ Object.values(apiData).forEach(api => {
137+ if (!categories[api.category]) categories[api.category] = [];
138+ categories[api.category].push(api);
139+ });
140+
141+ Object.keys(categories).sort().forEach(cat => {
142+ const heading = document.createElement('h2');
143+ heading.textContent = cat;
144+ container.appendChild(heading);
256145
257- document.addEventListener('DOMContentLoaded', populatePage);
258- </script>
146+ const grid = document.createElement('div');
147+ grid.className = "grid";
148+
149+ categories[cat].sort((a,b)=>a.title.localeCompare(b.title)).forEach(api => {
150+ const card = document.createElement('div');
151+ card.className = "card";
152+
153+ const a = document.createElement('a');
154+ a.href = api.filename;
155+ a.textContent = api.title;
156+
157+ card.appendChild(a);
158+ grid.appendChild(card);
159+ });
160+
161+ container.appendChild(grid);
162+ });
163+
164+ document.getElementById('timestamp').textContent = new Date().toLocaleString();
165+ }
166+
167+ document.addEventListener('DOMContentLoaded', populatePage);
168+ </script>
259169</body>
260170</html>
261171EOF
262172
173+
174+
263175echo -e " ${GREEN} ✅ Card-based index page generated: $INDEX_FILE ${NC} "
264176
265177# === SUMMARY ===
@@ -274,9 +186,9 @@ echo -e "${BLUE}🌐 Main index: $INDEX_FILE${NC}"
274186# === CREATE README ===
275187cat > " $OUTPUT_DIR /README.md" << 'EOF '
276188# Devtron API Documentation
189+
277190This folder contains the HTML documentation generated from the OpenAPI specs in the `specs` directory.
278191EOF
279192
280193echo -e " ${GREEN} ✅ README created: $OUTPUT_DIR /README.md${NC} "
281- echo -e " ${GREEN} 🎉 API documentation generation complete!${NC} "
282- ` ` `
194+ echo -e " ${GREEN} 🎉 API documentation generation complete!${NC} "
0 commit comments