Skip to content

Commit 74bdd6b

Browse files
committed
add swagger tabs to create dev center
1 parent dd8aa57 commit 74bdd6b

File tree

3 files changed

+212
-1
lines changed

3 files changed

+212
-1
lines changed

.vscode/settings.json

+1
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
"stylelintrc",
9393
"thatkookooguy",
9494
"timestamptz",
95+
"Topbar",
9596
"typeorm",
9697
"viewports",
9798
"vivaxy",

server/login-app/swagger-tabs.js

+175
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
document.addEventListener('DOMContentLoaded', function () {
2+
setTimeout(async () => {
3+
console.log('====== test?');
4+
5+
const swaggerTopbar = document.querySelector('.topbar');
6+
const swaggerUi = document.querySelector('div.swagger-ui');
7+
const swaggerContainer = document.querySelector('.swagger-container');
8+
9+
// get the smee url from server
10+
const swaggerResponse = await fetch('/api/swagger');
11+
const swaggerBody = await swaggerResponse.json();
12+
const smeeUrl = swaggerBody.smeeUrl;
13+
const showSwaggerUi = swaggerBody.showSwaggerUi;
14+
const showSwaggerJson = swaggerBody.showSwaggerJson;
15+
const showAsyncDocs = swaggerBody.showAsyncDocs;
16+
const showSmeeClient = swaggerBody.showSmeeClient;
17+
const showNestjsDevTools = swaggerBody.showNestjsDevTools;
18+
19+
20+
const smeeIframe = document.createElement('iframe');
21+
smeeIframe.src = smeeUrl;
22+
smeeIframe.style.display = 'none';
23+
smeeIframe.style.width = '100%';
24+
smeeIframe.style.height = '100%';
25+
smeeIframe.style.border = 'none';
26+
smeeIframe.style.flexGrow = '1';
27+
28+
if (showSmeeClient) {
29+
swaggerContainer.appendChild(smeeIframe);
30+
}
31+
32+
const swaggerJsonIframe = document.createElement('iframe');
33+
swaggerJsonIframe.src = '/api/docs-json';
34+
swaggerJsonIframe.style.display = 'none';
35+
swaggerJsonIframe.style.width = '100%';
36+
swaggerJsonIframe.style.height = '100%';
37+
swaggerJsonIframe.style.border = 'none';
38+
swaggerJsonIframe.style.flexGrow = '1';
39+
40+
if (showSwaggerJson) {
41+
swaggerContainer.appendChild(swaggerJsonIframe);
42+
}
43+
44+
const asyncDocsIframe = document.createElement('iframe');
45+
asyncDocsIframe.src = '/api/docs-async';
46+
asyncDocsIframe.style.display = 'none';
47+
asyncDocsIframe.style.width = '100%';
48+
asyncDocsIframe.style.height = '100%';
49+
asyncDocsIframe.style.border = 'none';
50+
asyncDocsIframe.style.flexGrow = '1';
51+
52+
if (showAsyncDocs) {
53+
swaggerContainer.appendChild(asyncDocsIframe);
54+
}
55+
56+
const nestjsDevToolsIframe = document.createElement('iframe');
57+
nestjsDevToolsIframe.src = 'https://devtools.nestjs.com/';
58+
nestjsDevToolsIframe.style.display = 'none';
59+
nestjsDevToolsIframe.style.width = '100%';
60+
nestjsDevToolsIframe.style.height = '100%';
61+
nestjsDevToolsIframe.style.border = 'none';
62+
nestjsDevToolsIframe.style.flexGrow = '1';
63+
64+
if (showNestjsDevTools) {
65+
swaggerContainer.appendChild(nestjsDevToolsIframe);
66+
}
67+
68+
// add tabs under the topbar
69+
const tabs = document.createElement('div');
70+
// get active tab based on the current url
71+
const activeTab = getCurrentActiveTab();
72+
const allTabsHtml = [];
73+
74+
if (showSwaggerUi) {
75+
allTabsHtml.push('<a id="swagger-ui">Swagger UI</a>');
76+
}
77+
78+
if (showSwaggerJson) {
79+
allTabsHtml.push('<a id="json">Swagger JSON</a>');
80+
}
81+
82+
if (showAsyncDocs) {
83+
allTabsHtml.push('<a id="async">Async Docs</a>');
84+
}
85+
86+
if (showSmeeClient) {
87+
allTabsHtml.push('<a id="smee">Smee webhooks</a>');
88+
}
89+
90+
if (showNestjsDevTools) {
91+
allTabsHtml.push('<a id="nestjs-devtools">NestJs DevTools</a>');
92+
93+
}
94+
95+
tabs.innerHTML = allTabsHtml.join('');
96+
tabs.classList.add('kb-tabs');
97+
98+
tabs.addEventListener('click', setActiveTab);
99+
100+
setActiveTab();
101+
102+
swaggerTopbar.appendChild(tabs);
103+
104+
function setActiveTab(event) {
105+
event = event || getCurrentActiveTab();
106+
const tab = event.target.id;
107+
108+
// remove active class from all tabs
109+
tabs.querySelectorAll('a').forEach((tab) => {
110+
tab.classList.remove('active');
111+
});
112+
113+
// add active class to the clicked tab
114+
event.target.classList.add('active');
115+
116+
if (tab === 'swagger-ui') {
117+
swaggerUi.style.display = 'block';
118+
smeeIframe.style.display = 'none';
119+
swaggerJsonIframe.style.display = 'none';
120+
asyncDocsIframe.style.display = 'none';
121+
nestjsDevToolsIframe.style.display = 'none';
122+
} else if (tab === 'json') {
123+
swaggerUi.style.display = 'none';
124+
smeeIframe.style.display = 'none';
125+
swaggerJsonIframe.style.display = 'block';
126+
asyncDocsIframe.style.display = 'none';
127+
nestjsDevToolsIframe.style.display = 'none';
128+
} else if (tab === 'async') {
129+
swaggerUi.style.display = 'none';
130+
smeeIframe.style.display = 'none';
131+
swaggerJsonIframe.style.display = 'none';
132+
asyncDocsIframe.style.display = 'block';
133+
nestjsDevToolsIframe.style.display = 'none';
134+
} else if (tab === 'smee') {
135+
swaggerUi.style.display = 'none';
136+
smeeIframe.style.display = 'block';
137+
swaggerJsonIframe.style.display = 'none';
138+
asyncDocsIframe.style.display = 'none';
139+
nestjsDevToolsIframe.style.display = 'none';
140+
} else if (tab === 'nestjs-devtools') {
141+
swaggerUi.style.display = 'none';
142+
smeeIframe.style.display = 'none';
143+
swaggerJsonIframe.style.display = 'none';
144+
asyncDocsIframe.style.display = 'none';
145+
nestjsDevToolsIframe.style.display = 'block';
146+
// open a new tab to nestjs devtools
147+
window.open('https://devtools.nestjs.com/', '_blank');
148+
}
149+
}
150+
151+
function getCurrentActiveTab() {
152+
const pathname = window.location.pathname;
153+
const hostname = window.location.hostname;
154+
155+
if (pathname.endsWith('json')) {
156+
return { target: tabs.querySelector('#json') };
157+
}
158+
159+
if (pathname.endsWith('async')) {
160+
return { target: tabs.querySelector('#async') };
161+
}
162+
163+
// check if using smee at smee.kibibit.io
164+
if (hostname === 'smee.kibibit.io') {
165+
return { target: tabs.querySelector('#smee') };
166+
}
167+
168+
if (hostname === 'devtools.nestjs.com') {
169+
return { target: tabs.querySelector('#nestjs-devtools') };
170+
}
171+
172+
return { target: tabs.querySelector('#swagger-ui') };
173+
}
174+
}, 750);
175+
});

server/src/documentation.ts

+36-1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,12 @@ export class Documentation {
162162
mask-image: url(https://simpleicons.org/icons/devdotto.svg);
163163
}
164164
165+
.swagger-ui.swagger-container {
166+
min-height: calc(100dvh - 81.5px);
167+
display: flex;
168+
flex-direction: column;
169+
}
170+
165171
.swagger-ui .opblock .opblock-summary-description {
166172
padding: 1em 1em 1em 0;
167173
}
@@ -176,8 +182,37 @@ export class Documentation {
176182
.swagger-ui .opblock-control-arrow {
177183
width: 50px;
178184
}
185+
186+
.swagger-ui .topbar .kb-tabs {
187+
display: flex;
188+
font-size: 0.7em;
189+
justify-content: center;
190+
align-items: center;
191+
padding: 0.5em 1.7em 0;
192+
text-align: center;
193+
}
194+
195+
.swagger-ui .topbar .kb-tabs a {
196+
display: block;
197+
font-family: 'Comfortaa';
198+
font-weight: 100;
199+
cursor: pointer;
200+
padding-top: 0.5em;
201+
}
202+
203+
.swagger-ui .topbar .kb-tabs a.active {
204+
color: #FF5BF8;
205+
font-weight: 900;
206+
}
207+
208+
.swagger-ui .topbar .topbar-wrapper a::before {
209+
content: 'Dev Center';
210+
}
179211
`.trim(),
180-
customJs: '//kibibit.io/kibibit-assets/swagger/swagger.js',
212+
customJs: [
213+
'//kibibit.io/kibibit-assets/swagger/swagger.js',
214+
'/login/swagger-tabs.js'
215+
],
181216
swaggerOptions: {
182217
docExpansion: 'none',
183218
apisSorter: 'alpha',

0 commit comments

Comments
 (0)