@eldrforge/kodrdriv 0.0.7 → 0.0.10
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 +65 -707
- package/dist/arguments.js +79 -55
- package/dist/arguments.js.map +1 -1
- package/dist/commands/commit.js +28 -16
- package/dist/commands/commit.js.map +1 -1
- package/dist/commands/link.js +19 -18
- package/dist/commands/link.js.map +1 -1
- package/dist/commands/publish.js +170 -93
- package/dist/commands/publish.js.map +1 -1
- package/dist/commands/release.js +8 -0
- package/dist/commands/release.js.map +1 -1
- package/dist/commands/unlink.js +21 -20
- package/dist/commands/unlink.js.map +1 -1
- package/dist/constants.js +4 -2
- package/dist/constants.js.map +1 -1
- package/dist/logging.js +35 -23
- package/dist/logging.js.map +1 -1
- package/dist/main.js +49 -3
- package/dist/main.js.map +1 -1
- package/dist/util/child.js +13 -1
- package/dist/util/child.js.map +1 -1
- package/docs/index.html +17 -0
- package/docs/package.json +36 -0
- package/docs/public/README.md +132 -0
- package/docs/public/advanced-usage.md +188 -0
- package/docs/public/code-icon.svg +4 -0
- package/docs/public/commands.md +116 -0
- package/docs/public/configuration.md +274 -0
- package/docs/public/examples.md +352 -0
- package/docs/public/kodrdriv-logo.svg +62 -0
- package/docs/src/App.css +387 -0
- package/docs/src/App.tsx +60 -0
- package/docs/src/components/DocumentPage.tsx +56 -0
- package/docs/src/components/ErrorMessage.tsx +15 -0
- package/docs/src/components/LoadingSpinner.tsx +14 -0
- package/docs/src/components/MarkdownRenderer.tsx +56 -0
- package/docs/src/components/Navigation.css +73 -0
- package/docs/src/components/Navigation.tsx +36 -0
- package/docs/src/index.css +61 -0
- package/docs/src/main.tsx +10 -0
- package/docs/src/test/setup.ts +1 -0
- package/docs/src/vite-env.d.ts +10 -0
- package/docs/tsconfig.node.json +13 -0
- package/docs/vite.config.ts +15 -0
- package/docs/vitest.config.ts +15 -0
- package/eslint.config.mjs +1 -0
- package/package.json +10 -5
- package/vitest.config.ts +3 -3
package/docs/src/App.css
ADDED
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
/* Reset and base styles */
|
|
2
|
+
* {
|
|
3
|
+
margin: 0;
|
|
4
|
+
padding: 0;
|
|
5
|
+
box-sizing: border-box;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
body {
|
|
9
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
|
|
10
|
+
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
|
|
11
|
+
sans-serif;
|
|
12
|
+
-webkit-font-smoothing: antialiased;
|
|
13
|
+
-moz-osx-font-smoothing: grayscale;
|
|
14
|
+
line-height: 1.6;
|
|
15
|
+
color: #333;
|
|
16
|
+
background: #ffffff;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.app {
|
|
20
|
+
min-height: 100vh;
|
|
21
|
+
display: flex;
|
|
22
|
+
flex-direction: column;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/* Header styles */
|
|
26
|
+
.header {
|
|
27
|
+
background: #000000;
|
|
28
|
+
color: white;
|
|
29
|
+
padding: 4rem 2rem;
|
|
30
|
+
text-align: center;
|
|
31
|
+
position: relative;
|
|
32
|
+
overflow: hidden;
|
|
33
|
+
border-bottom: 3px solid #333333;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
.header::before {
|
|
37
|
+
content: '';
|
|
38
|
+
position: absolute;
|
|
39
|
+
top: 0;
|
|
40
|
+
left: 0;
|
|
41
|
+
right: 0;
|
|
42
|
+
bottom: 0;
|
|
43
|
+
background: url("data:image/svg+xml,%3Csvg width='60' height='60' viewBox='0 0 60 60' xmlns='http://www.w3.org/2000/svg'%3E%3Cg fill='none' fill-rule='evenodd'%3E%3Cg fill='%23ffffff' fill-opacity='0.05'%3E%3Cpath d='M36 34v-4h-2v4h-4v2h4v4h2v-4h4v-2h-4zm0-30V0h-2v4h-4v2h4v4h2V6h4V4h-4zM6 34v-4H4v4H0v2h4v4h2v-4h4v-2H6zM6 4V0H4v4H0v2h4v4h2V6h4V4H6z'/%3E%3C/g%3E%3C/g%3E%3C/svg%3E") repeat;
|
|
44
|
+
opacity: 0.05;
|
|
45
|
+
z-index: 1;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
.header-content {
|
|
49
|
+
position: relative;
|
|
50
|
+
z-index: 2;
|
|
51
|
+
max-width: 800px;
|
|
52
|
+
margin: 0 auto;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.header-main {
|
|
56
|
+
display: flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
gap: 1rem;
|
|
60
|
+
margin-bottom: 1rem;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.icon {
|
|
64
|
+
font-size: 3rem;
|
|
65
|
+
filter: drop-shadow(0 2px 4px rgba(255, 255, 255, 0.2));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.header h1 {
|
|
69
|
+
font-size: 3.5rem;
|
|
70
|
+
font-weight: 700;
|
|
71
|
+
margin: 0;
|
|
72
|
+
color: #ffffff;
|
|
73
|
+
text-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.subtitle {
|
|
77
|
+
font-size: 1.25rem;
|
|
78
|
+
margin-bottom: 2rem;
|
|
79
|
+
opacity: 0.9;
|
|
80
|
+
font-weight: 300;
|
|
81
|
+
color: #cccccc;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.header-links {
|
|
85
|
+
display: flex;
|
|
86
|
+
gap: 2rem;
|
|
87
|
+
justify-content: center;
|
|
88
|
+
flex-wrap: wrap;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.header-links a {
|
|
92
|
+
color: white;
|
|
93
|
+
text-decoration: none;
|
|
94
|
+
font-weight: 500;
|
|
95
|
+
padding: 0.75rem 2rem;
|
|
96
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
97
|
+
border-radius: 50px;
|
|
98
|
+
transition: all 0.3s ease;
|
|
99
|
+
backdrop-filter: blur(10px);
|
|
100
|
+
background: rgba(255, 255, 255, 0.1);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.header-links a:hover {
|
|
104
|
+
background: rgba(255, 255, 255, 0.2);
|
|
105
|
+
border-color: rgba(255, 255, 255, 0.6);
|
|
106
|
+
transform: translateY(-2px);
|
|
107
|
+
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/* Main content */
|
|
111
|
+
.main {
|
|
112
|
+
flex: 1;
|
|
113
|
+
padding: 0;
|
|
114
|
+
background: #ffffff;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
.container {
|
|
118
|
+
width: 100%;
|
|
119
|
+
max-width: none;
|
|
120
|
+
margin: 0;
|
|
121
|
+
background: white;
|
|
122
|
+
border-radius: 0;
|
|
123
|
+
box-shadow: none;
|
|
124
|
+
overflow: visible;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* Markdown content styling */
|
|
128
|
+
.markdown-content {
|
|
129
|
+
padding: 3rem 4rem;
|
|
130
|
+
font-size: 1rem;
|
|
131
|
+
line-height: 1.7;
|
|
132
|
+
color: #374151;
|
|
133
|
+
width: 100%;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
.markdown-content h1,
|
|
137
|
+
.markdown-content h2,
|
|
138
|
+
.markdown-content h3,
|
|
139
|
+
.markdown-content h4,
|
|
140
|
+
.markdown-content h5,
|
|
141
|
+
.markdown-content h6 {
|
|
142
|
+
color: #1f2937;
|
|
143
|
+
font-weight: 600;
|
|
144
|
+
margin-top: 2rem;
|
|
145
|
+
margin-bottom: 1rem;
|
|
146
|
+
line-height: 1.4;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.markdown-content h1 {
|
|
150
|
+
font-size: 2.5rem;
|
|
151
|
+
border-bottom: 3px solid #e5e7eb;
|
|
152
|
+
padding-bottom: 0.5rem;
|
|
153
|
+
margin-top: 0;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
.markdown-content h2 {
|
|
157
|
+
font-size: 2rem;
|
|
158
|
+
border-bottom: 2px solid #e5e7eb;
|
|
159
|
+
padding-bottom: 0.3rem;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.markdown-content h3 {
|
|
163
|
+
font-size: 1.5rem;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.markdown-content h4 {
|
|
167
|
+
font-size: 1.25rem;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.markdown-content p {
|
|
171
|
+
margin-bottom: 1.5rem;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
.markdown-content ul,
|
|
175
|
+
.markdown-content ol {
|
|
176
|
+
margin: 1rem 0;
|
|
177
|
+
padding-left: 2rem;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
.markdown-content li {
|
|
181
|
+
margin-bottom: 0.5rem;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
.markdown-content blockquote {
|
|
185
|
+
border-left: 4px solid #333333;
|
|
186
|
+
background: #f8fafc;
|
|
187
|
+
padding: 1rem 1.5rem;
|
|
188
|
+
margin: 1.5rem 0;
|
|
189
|
+
font-style: italic;
|
|
190
|
+
color: #4b5563;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
.markdown-content code {
|
|
194
|
+
background: #f3f4f6;
|
|
195
|
+
padding: 0.2rem 0.4rem;
|
|
196
|
+
border-radius: 4px;
|
|
197
|
+
font-family: 'Fira Code', 'Monaco', 'Menlo', monospace;
|
|
198
|
+
font-size: 0.875rem;
|
|
199
|
+
color: #000000;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
.markdown-content pre {
|
|
203
|
+
margin: 1.5rem 0;
|
|
204
|
+
border-radius: 8px;
|
|
205
|
+
overflow: hidden;
|
|
206
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
.markdown-content pre code {
|
|
210
|
+
background: none;
|
|
211
|
+
padding: 0;
|
|
212
|
+
color: inherit;
|
|
213
|
+
font-size: 0.875rem;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.markdown-content table {
|
|
217
|
+
width: 100%;
|
|
218
|
+
border-collapse: collapse;
|
|
219
|
+
margin: 1.5rem 0;
|
|
220
|
+
border: 1px solid #e5e7eb;
|
|
221
|
+
border-radius: 8px;
|
|
222
|
+
overflow: hidden;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.markdown-content th,
|
|
226
|
+
.markdown-content td {
|
|
227
|
+
padding: 0.75rem 1rem;
|
|
228
|
+
text-align: left;
|
|
229
|
+
border-bottom: 1px solid #e5e7eb;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
.markdown-content th {
|
|
233
|
+
background: #f9fafb;
|
|
234
|
+
font-weight: 600;
|
|
235
|
+
color: #374151;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.markdown-content a {
|
|
239
|
+
color: #000000;
|
|
240
|
+
text-decoration: none;
|
|
241
|
+
font-weight: 500;
|
|
242
|
+
border-bottom: 1px solid transparent;
|
|
243
|
+
transition: all 0.2s ease;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.markdown-content a:hover {
|
|
247
|
+
color: #333333;
|
|
248
|
+
border-bottom-color: #333333;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
.markdown-content img {
|
|
252
|
+
max-width: 100%;
|
|
253
|
+
height: auto;
|
|
254
|
+
border-radius: 8px;
|
|
255
|
+
margin: 1rem 0;
|
|
256
|
+
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.markdown-content hr {
|
|
260
|
+
border: none;
|
|
261
|
+
height: 2px;
|
|
262
|
+
background: linear-gradient(90deg, transparent, #e5e7eb, transparent);
|
|
263
|
+
margin: 3rem 0;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/* Footer */
|
|
267
|
+
.footer {
|
|
268
|
+
background: #f8f9fa;
|
|
269
|
+
color: #6c757d;
|
|
270
|
+
padding: 2rem;
|
|
271
|
+
text-align: center;
|
|
272
|
+
border-top: 1px solid #e9ecef;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
.footer p {
|
|
276
|
+
margin-bottom: 0.5rem;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
.footer a {
|
|
280
|
+
color: #000000;
|
|
281
|
+
text-decoration: none;
|
|
282
|
+
font-weight: 500;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
.footer a:hover {
|
|
286
|
+
color: #333333;
|
|
287
|
+
text-decoration: underline;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.license {
|
|
291
|
+
font-size: 0.875rem;
|
|
292
|
+
opacity: 0.7;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/* Loading and error states */
|
|
296
|
+
.loading-spinner {
|
|
297
|
+
display: flex;
|
|
298
|
+
flex-direction: column;
|
|
299
|
+
align-items: center;
|
|
300
|
+
justify-content: center;
|
|
301
|
+
min-height: 50vh;
|
|
302
|
+
gap: 2rem;
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
.spinner {
|
|
306
|
+
width: 50px;
|
|
307
|
+
height: 50px;
|
|
308
|
+
border: 4px solid #f3f3f3;
|
|
309
|
+
border-top: 4px solid #000000;
|
|
310
|
+
border-radius: 50%;
|
|
311
|
+
animation: spin 1s linear infinite;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
@keyframes spin {
|
|
315
|
+
0% {
|
|
316
|
+
transform: rotate(0deg);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
100% {
|
|
320
|
+
transform: rotate(360deg);
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
.error-message {
|
|
325
|
+
display: flex;
|
|
326
|
+
flex-direction: column;
|
|
327
|
+
align-items: center;
|
|
328
|
+
justify-content: center;
|
|
329
|
+
min-height: 50vh;
|
|
330
|
+
gap: 1rem;
|
|
331
|
+
text-align: center;
|
|
332
|
+
padding: 2rem;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
.error-message h2 {
|
|
336
|
+
color: #e53e3e;
|
|
337
|
+
font-size: 1.5rem;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.error-message p {
|
|
341
|
+
color: #718096;
|
|
342
|
+
max-width: 400px;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/* Responsive design */
|
|
346
|
+
@media (max-width: 768px) {
|
|
347
|
+
.header {
|
|
348
|
+
padding: 3rem 1rem;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
.header h1 {
|
|
352
|
+
font-size: 2.5rem;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
.header-main {
|
|
356
|
+
flex-direction: column;
|
|
357
|
+
gap: 0.5rem;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
.icon {
|
|
361
|
+
font-size: 2rem;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
.subtitle {
|
|
365
|
+
font-size: 1.1rem;
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
.header-links {
|
|
369
|
+
gap: 1rem;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
.header-links a {
|
|
373
|
+
padding: 0.5rem 1.5rem;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
.markdown-content {
|
|
377
|
+
padding: 1.5rem;
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
.markdown-content h1 {
|
|
381
|
+
font-size: 2rem;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
.markdown-content h2 {
|
|
385
|
+
font-size: 1.5rem;
|
|
386
|
+
}
|
|
387
|
+
}
|
package/docs/src/App.tsx
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom'
|
|
2
|
+
import Navigation from './components/Navigation'
|
|
3
|
+
import DocumentPage from './components/DocumentPage'
|
|
4
|
+
import './App.css'
|
|
5
|
+
|
|
6
|
+
function App() {
|
|
7
|
+
return (
|
|
8
|
+
<Router>
|
|
9
|
+
<div className="app">
|
|
10
|
+
<header className="header">
|
|
11
|
+
<div className="header-content">
|
|
12
|
+
<div className="header-main">
|
|
13
|
+
<img
|
|
14
|
+
src="./kodrdriv-logo.svg"
|
|
15
|
+
alt="KodrDriv Logo"
|
|
16
|
+
width="64"
|
|
17
|
+
height="64"
|
|
18
|
+
style={{ filter: 'invert(1)' }}
|
|
19
|
+
/>
|
|
20
|
+
<h1>KodrDriv</h1>
|
|
21
|
+
</div>
|
|
22
|
+
<p className="subtitle">Intelligent Git Release Notes & Change Logs</p>
|
|
23
|
+
<div className="header-links">
|
|
24
|
+
<a href="https://github.com/calenvarek/kodrdriv" target="_blank" rel="noopener noreferrer">
|
|
25
|
+
GitHub
|
|
26
|
+
</a>
|
|
27
|
+
<a href="https://www.npmjs.com/package/@eldrforge/kodrdriv" target="_blank" rel="noopener noreferrer">
|
|
28
|
+
NPM
|
|
29
|
+
</a>
|
|
30
|
+
</div>
|
|
31
|
+
</div>
|
|
32
|
+
</header>
|
|
33
|
+
|
|
34
|
+
<Navigation />
|
|
35
|
+
|
|
36
|
+
<main className="main">
|
|
37
|
+
<div className="container">
|
|
38
|
+
<Routes>
|
|
39
|
+
<Route path="/*" element={<DocumentPage />} />
|
|
40
|
+
</Routes>
|
|
41
|
+
</div>
|
|
42
|
+
</main>
|
|
43
|
+
|
|
44
|
+
<footer className="footer">
|
|
45
|
+
<div className="container">
|
|
46
|
+
<p>
|
|
47
|
+
Built with ❤️ by{' '}
|
|
48
|
+
<a href="https://github.com/calenvarek" target="_blank" rel="noopener noreferrer">
|
|
49
|
+
Calen Varek
|
|
50
|
+
</a>
|
|
51
|
+
</p>
|
|
52
|
+
<p className="license">Licensed under Apache-2.0</p>
|
|
53
|
+
</div>
|
|
54
|
+
</footer>
|
|
55
|
+
</div>
|
|
56
|
+
</Router>
|
|
57
|
+
)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default App
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { useState, useEffect } from 'react'
|
|
2
|
+
import { useParams } from 'react-router-dom'
|
|
3
|
+
import LoadingSpinner from './LoadingSpinner'
|
|
4
|
+
import ErrorMessage from './ErrorMessage'
|
|
5
|
+
import MarkdownRenderer from './MarkdownRenderer'
|
|
6
|
+
import { navigationItems } from './Navigation'
|
|
7
|
+
|
|
8
|
+
function DocumentPage() {
|
|
9
|
+
const { '*': splat } = useParams()
|
|
10
|
+
const [content, setContent] = useState<string>('')
|
|
11
|
+
const [loading, setLoading] = useState(true)
|
|
12
|
+
const [error, setError] = useState<string | null>(null)
|
|
13
|
+
|
|
14
|
+
// Determine which file to load based on the current path
|
|
15
|
+
const currentPath = splat ? `/${splat}` : '/'
|
|
16
|
+
const currentItem = navigationItems.find(item => item.path === currentPath)
|
|
17
|
+
const fileName = currentItem?.file || 'README.md'
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
setLoading(true)
|
|
21
|
+
setError(null)
|
|
22
|
+
|
|
23
|
+
// Get the base path from the current URL or use the import.meta.env.BASE_URL
|
|
24
|
+
const basePath = import.meta.env.BASE_URL || '/'
|
|
25
|
+
const fileUrl = `${basePath}${fileName}`
|
|
26
|
+
|
|
27
|
+
// Fetch the markdown file from the public directory
|
|
28
|
+
fetch(fileUrl)
|
|
29
|
+
.then(response => {
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
throw new Error(`Failed to fetch ${fileName}: ${response.status}`)
|
|
32
|
+
}
|
|
33
|
+
return response.text()
|
|
34
|
+
})
|
|
35
|
+
.then(text => {
|
|
36
|
+
setContent(text)
|
|
37
|
+
setLoading(false)
|
|
38
|
+
})
|
|
39
|
+
.catch(err => {
|
|
40
|
+
setError(err.message)
|
|
41
|
+
setLoading(false)
|
|
42
|
+
})
|
|
43
|
+
}, [fileName])
|
|
44
|
+
|
|
45
|
+
if (loading) {
|
|
46
|
+
return <LoadingSpinner />
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (error) {
|
|
50
|
+
return <ErrorMessage message={error} />
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return <MarkdownRenderer content={content} />
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default DocumentPage
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
interface ErrorMessageProps {
|
|
2
|
+
message: string
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function ErrorMessage({ message }: ErrorMessageProps) {
|
|
6
|
+
return (
|
|
7
|
+
<div className="error-message">
|
|
8
|
+
<h2>⚠️ Error Loading Documentation</h2>
|
|
9
|
+
<p>{message}</p>
|
|
10
|
+
<p>Please try refreshing the page or check back later.</p>
|
|
11
|
+
</div>
|
|
12
|
+
)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default ErrorMessage
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
interface LoadingSpinnerProps {
|
|
2
|
+
message?: string
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
function LoadingSpinner({ message = "Loading documentation..." }: LoadingSpinnerProps) {
|
|
6
|
+
return (
|
|
7
|
+
<div className="loading-spinner">
|
|
8
|
+
<div className="spinner"></div>
|
|
9
|
+
<p>{message}</p>
|
|
10
|
+
</div>
|
|
11
|
+
)
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export default LoadingSpinner
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import ReactMarkdown from 'react-markdown'
|
|
2
|
+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'
|
|
3
|
+
import { tomorrow } from 'react-syntax-highlighter/dist/esm/styles/prism'
|
|
4
|
+
import remarkGfm from 'remark-gfm'
|
|
5
|
+
|
|
6
|
+
interface MarkdownRendererProps {
|
|
7
|
+
content: string
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function MarkdownRenderer({ content }: MarkdownRendererProps) {
|
|
11
|
+
return (
|
|
12
|
+
<div className="markdown-content">
|
|
13
|
+
<ReactMarkdown
|
|
14
|
+
remarkPlugins={[remarkGfm]}
|
|
15
|
+
components={{
|
|
16
|
+
code({ node, className, children, ...props }: any) {
|
|
17
|
+
const match = /language-(\w+)/.exec(className || '')
|
|
18
|
+
const inline = !match
|
|
19
|
+
return !inline && match ? (
|
|
20
|
+
<SyntaxHighlighter
|
|
21
|
+
style={tomorrow as any}
|
|
22
|
+
language={match[1]}
|
|
23
|
+
PreTag="div"
|
|
24
|
+
{...props}
|
|
25
|
+
>
|
|
26
|
+
{String(children).replace(/\n$/, '')}
|
|
27
|
+
</SyntaxHighlighter>
|
|
28
|
+
) : (
|
|
29
|
+
<code className={className} {...props}>
|
|
30
|
+
{children}
|
|
31
|
+
</code>
|
|
32
|
+
)
|
|
33
|
+
},
|
|
34
|
+
// Customize link behavior to open external links in new tabs
|
|
35
|
+
a({ href, children, ...props }) {
|
|
36
|
+
const isExternal = href?.startsWith('http') || href?.startsWith('//')
|
|
37
|
+
return (
|
|
38
|
+
<a
|
|
39
|
+
href={href}
|
|
40
|
+
target={isExternal ? '_blank' : undefined}
|
|
41
|
+
rel={isExternal ? 'noopener noreferrer' : undefined}
|
|
42
|
+
{...props}
|
|
43
|
+
>
|
|
44
|
+
{children}
|
|
45
|
+
</a>
|
|
46
|
+
)
|
|
47
|
+
},
|
|
48
|
+
}}
|
|
49
|
+
>
|
|
50
|
+
{content}
|
|
51
|
+
</ReactMarkdown>
|
|
52
|
+
</div>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export default MarkdownRenderer
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
.navigation {
|
|
2
|
+
background: #000000;
|
|
3
|
+
padding: 0;
|
|
4
|
+
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
|
5
|
+
position: sticky;
|
|
6
|
+
top: 0;
|
|
7
|
+
z-index: 100;
|
|
8
|
+
border-bottom: 1px solid #333333;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.nav-container {
|
|
12
|
+
width: 100%;
|
|
13
|
+
max-width: none;
|
|
14
|
+
margin: 0;
|
|
15
|
+
padding: 0 2rem;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.nav-list {
|
|
19
|
+
display: flex;
|
|
20
|
+
list-style: none;
|
|
21
|
+
margin: 0;
|
|
22
|
+
padding: 0;
|
|
23
|
+
gap: 0;
|
|
24
|
+
overflow-x: auto;
|
|
25
|
+
scrollbar-width: none;
|
|
26
|
+
-ms-overflow-style: none;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
.nav-list::-webkit-scrollbar {
|
|
30
|
+
display: none;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
.nav-item {
|
|
34
|
+
flex-shrink: 0;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.nav-link {
|
|
38
|
+
display: block;
|
|
39
|
+
padding: 1rem 1.5rem;
|
|
40
|
+
color: rgba(255, 255, 255, 0.9);
|
|
41
|
+
text-decoration: none;
|
|
42
|
+
font-weight: 500;
|
|
43
|
+
font-size: 0.95rem;
|
|
44
|
+
border-radius: 0;
|
|
45
|
+
transition: all 0.2s ease;
|
|
46
|
+
position: relative;
|
|
47
|
+
white-space: nowrap;
|
|
48
|
+
border-bottom: 3px solid transparent;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.nav-link:hover {
|
|
52
|
+
color: white;
|
|
53
|
+
background: #333333;
|
|
54
|
+
border-bottom-color: #666666;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.nav-link.active {
|
|
58
|
+
color: white;
|
|
59
|
+
background: #333333;
|
|
60
|
+
font-weight: 600;
|
|
61
|
+
border-bottom-color: white;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
@media (max-width: 768px) {
|
|
65
|
+
.nav-container {
|
|
66
|
+
padding: 0 1rem;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.nav-link {
|
|
70
|
+
padding: 0.75rem 1rem;
|
|
71
|
+
font-size: 0.9rem;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Link, useLocation } from 'react-router-dom'
|
|
2
|
+
import './Navigation.css'
|
|
3
|
+
|
|
4
|
+
const navigationItems = [
|
|
5
|
+
{ path: '/', label: 'Getting Started', file: 'README.md' },
|
|
6
|
+
{ path: '/commands', label: 'Commands', file: 'commands.md' },
|
|
7
|
+
{ path: '/configuration', label: 'Configuration', file: 'configuration.md' },
|
|
8
|
+
{ path: '/advanced-usage', label: 'Advanced Usage', file: 'advanced-usage.md' },
|
|
9
|
+
{ path: '/examples', label: 'Examples', file: 'examples.md' },
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
function Navigation() {
|
|
13
|
+
const location = useLocation()
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<nav className="navigation">
|
|
17
|
+
<div className="nav-container">
|
|
18
|
+
<ul className="nav-list">
|
|
19
|
+
{navigationItems.map((item) => (
|
|
20
|
+
<li key={item.path} className="nav-item">
|
|
21
|
+
<Link
|
|
22
|
+
to={item.path}
|
|
23
|
+
className={`nav-link ${location.pathname === item.path ? 'active' : ''}`}
|
|
24
|
+
>
|
|
25
|
+
{item.label}
|
|
26
|
+
</Link>
|
|
27
|
+
</li>
|
|
28
|
+
))}
|
|
29
|
+
</ul>
|
|
30
|
+
</div>
|
|
31
|
+
</nav>
|
|
32
|
+
)
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default Navigation
|
|
36
|
+
export { navigationItems }
|