codedocent 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,538 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="utf-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1">
6
+ <title>codedocent — {{ root.name }}</title>
7
+ <script>
8
+ if (localStorage.getItem('cd-theme') === 'light')
9
+ document.documentElement.classList.add('light-mode');
10
+ </script>
11
+ <style>
12
+ :root {
13
+ --bg-body: #1a1a2e;
14
+ --bg-header: #12122a;
15
+ --bg-node: #222240;
16
+ --bg-imports: #1e1e38;
17
+ --bg-pseudocode: #1e2a38;
18
+ --bg-source: #0d0d1a;
19
+ --bg-badge: #2e2e50;
20
+ --bg-btn: #2e2e50;
21
+ --bg-btn-hover: #3a3a5a;
22
+ --bg-btn-active: #4466aa;
23
+ --bg-breadcrumb: #1e1e38;
24
+ --bg-header-hover: #2a2a48;
25
+
26
+ --text-primary: #e0e0e0;
27
+ --text-body: #e0e0e0;
28
+ --text-name: #e0e0f0;
29
+ --text-badge: #aaaacc;
30
+ --text-lines: #8888aa;
31
+ --text-range: #8888aa;
32
+ --text-warning: #FFD700;
33
+ --text-imports-label: #8888aa;
34
+ --text-imports-item: #bbbbcc;
35
+ --text-summary: #bbbbcc;
36
+ --text-placeholder: #666688;
37
+ --text-pseudocode-label: #8888aa;
38
+ --text-pseudocode: #ccccdd;
39
+ --text-btn: #bbbbcc;
40
+ --text-link: #7799ee;
41
+ --text-toggle: #8888aa;
42
+ --text-analyzing: #8888aa;
43
+ --text-breadcrumb-sep: #666688;
44
+ --text-breadcrumb-current: #e0e0e0;
45
+ --text-source: #D4D4D4;
46
+
47
+ --border-node: #3a3a5a;
48
+ --border-imports: #3a3a5a;
49
+ --border-pseudocode: #3a4a5a;
50
+ --border-btn: #4a4a6a;
51
+ --border-breadcrumb: #3a3a5a;
52
+ --border-textarea: #555;
53
+
54
+ --shadow-node: rgba(0, 0, 0, 0.3);
55
+ }
56
+
57
+ :root.light-mode {
58
+ --bg-body: #F5F5F5;
59
+ --bg-header: #1A1A2E;
60
+ --bg-node: #FFFFFF;
61
+ --bg-imports: #F9F9F9;
62
+ --bg-pseudocode: #F0F4F8;
63
+ --bg-source: #1E1E2E;
64
+ --bg-badge: #EEEEEE;
65
+ --bg-btn: #F5F5F5;
66
+ --bg-btn-hover: #E8E8E8;
67
+ --bg-btn-active: #1A1A2E;
68
+ --bg-breadcrumb: #EDEDF0;
69
+ --bg-header-hover: #FAFAFA;
70
+
71
+ --text-primary: #333;
72
+ --text-body: #333;
73
+ --text-name: #1A1A2E;
74
+ --text-badge: #666666;
75
+ --text-lines: #888888;
76
+ --text-range: #AAAAAA;
77
+ --text-warning: #B8860B;
78
+ --text-imports-label: #999999;
79
+ --text-imports-item: #555555;
80
+ --text-summary: #555555;
81
+ --text-placeholder: #AAAAAA;
82
+ --text-pseudocode-label: #999999;
83
+ --text-pseudocode: #444444;
84
+ --text-btn: #555;
85
+ --text-link: #5566DD;
86
+ --text-toggle: #888;
87
+ --text-analyzing: #888;
88
+ --text-breadcrumb-sep: #999;
89
+ --text-breadcrumb-current: #333;
90
+ --text-source: #D4D4D4;
91
+
92
+ --border-node: #E0E0E0;
93
+ --border-imports: #E8E8E8;
94
+ --border-pseudocode: #D0D8E0;
95
+ --border-btn: #D0D0D0;
96
+ --border-breadcrumb: #D8D8DC;
97
+ --border-textarea: #555;
98
+
99
+ --shadow-node: rgba(0, 0, 0, 0.06);
100
+ }
101
+
102
+ *, *::before, *::after {
103
+ box-sizing: border-box;
104
+ }
105
+
106
+ body {
107
+ margin: 0;
108
+ padding: 0;
109
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
110
+ background: var(--bg-body);
111
+ color: var(--text-body);
112
+ line-height: 1.5;
113
+ }
114
+
115
+ .cd-header {
116
+ background: var(--bg-header);
117
+ color: #FFFFFF;
118
+ padding: 16px 24px;
119
+ margin-bottom: 24px;
120
+ display: flex;
121
+ justify-content: space-between;
122
+ align-items: center;
123
+ }
124
+
125
+ .cd-header__title {
126
+ margin: 0;
127
+ font-size: 20px;
128
+ font-family: "SF Mono", "Fira Code", "Consolas", monospace;
129
+ font-weight: 700;
130
+ }
131
+
132
+ .cd-header__path {
133
+ margin: 4px 0 0;
134
+ font-size: 13px;
135
+ opacity: 0.7;
136
+ font-family: "SF Mono", "Fira Code", "Consolas", monospace;
137
+ }
138
+
139
+ .cd-theme-toggle {
140
+ background: none;
141
+ border: 1px solid rgba(255,255,255,0.3);
142
+ border-radius: 8px;
143
+ font-size: 20px;
144
+ cursor: pointer;
145
+ padding: 4px 8px;
146
+ color: #FFF;
147
+ line-height: 1;
148
+ }
149
+
150
+ .cd-theme-toggle:hover {
151
+ border-color: rgba(255,255,255,0.6);
152
+ }
153
+
154
+ .cd-main {
155
+ max-width: 960px;
156
+ margin: 0 auto;
157
+ padding: 0 16px 48px;
158
+ }
159
+
160
+ .cd-node {
161
+ background: var(--bg-node);
162
+ border: 1px solid var(--border-node);
163
+ border-radius: 8px;
164
+ box-shadow: 0 1px 3px var(--shadow-node);
165
+ margin-bottom: 12px;
166
+ border-left-width: 5px;
167
+ border-left-style: solid;
168
+ border-left-color: var(--node-color, #CCCCCC);
169
+ }
170
+
171
+ .cd-node__header {
172
+ display: flex;
173
+ flex-wrap: wrap;
174
+ align-items: center;
175
+ gap: 8px;
176
+ padding: 10px 14px;
177
+ }
178
+
179
+ .cd-node__icon {
180
+ font-size: 16px;
181
+ flex-shrink: 0;
182
+ }
183
+
184
+ .cd-node__name {
185
+ font-family: "SF Mono", "Fira Code", "Consolas", monospace;
186
+ font-weight: 700;
187
+ font-size: 14px;
188
+ color: var(--text-name);
189
+ }
190
+
191
+ .cd-node__badge {
192
+ display: inline-block;
193
+ font-size: 10px;
194
+ font-weight: 600;
195
+ text-transform: uppercase;
196
+ letter-spacing: 0.05em;
197
+ padding: 2px 8px;
198
+ border-radius: 10px;
199
+ background: var(--bg-badge);
200
+ color: var(--text-badge);
201
+ }
202
+
203
+ .cd-node__lines {
204
+ font-size: 12px;
205
+ color: var(--text-lines);
206
+ }
207
+
208
+ .cd-node__range {
209
+ font-size: 12px;
210
+ color: var(--text-range);
211
+ font-family: "SF Mono", "Fira Code", "Consolas", monospace;
212
+ }
213
+
214
+ .cd-node__quality {
215
+ font-size: 14px;
216
+ flex-shrink: 0;
217
+ }
218
+
219
+ .cd-node__warning-text {
220
+ font-size: 11px;
221
+ color: var(--text-warning);
222
+ font-style: italic;
223
+ }
224
+
225
+ .cd-node__body {
226
+ padding: 0 14px 10px;
227
+ }
228
+
229
+ .cd-imports {
230
+ background: var(--bg-imports);
231
+ border: 1px solid var(--border-imports);
232
+ border-radius: 6px;
233
+ padding: 8px 12px;
234
+ margin-bottom: 8px;
235
+ }
236
+
237
+ .cd-imports__label {
238
+ font-size: 10px;
239
+ font-weight: 700;
240
+ text-transform: uppercase;
241
+ letter-spacing: 0.08em;
242
+ color: var(--text-imports-label);
243
+ margin-bottom: 4px;
244
+ }
245
+
246
+ .cd-imports__item {
247
+ font-family: "SF Mono", "Fira Code", "Consolas", monospace;
248
+ font-size: 13px;
249
+ color: var(--text-imports-item);
250
+ padding: 1px 0;
251
+ }
252
+
253
+ .cd-summary {
254
+ color: var(--text-summary);
255
+ font-size: 13px;
256
+ margin-bottom: 8px;
257
+ }
258
+
259
+ .cd-summary--placeholder {
260
+ font-style: italic;
261
+ color: var(--text-placeholder);
262
+ }
263
+
264
+ .cd-pseudocode {
265
+ background: var(--bg-pseudocode);
266
+ border: 1px solid var(--border-pseudocode);
267
+ border-radius: 6px;
268
+ padding: 8px 12px;
269
+ margin-bottom: 8px;
270
+ }
271
+
272
+ .cd-pseudocode__label {
273
+ font-size: 10px;
274
+ font-weight: 700;
275
+ text-transform: uppercase;
276
+ letter-spacing: 0.08em;
277
+ color: var(--text-pseudocode-label);
278
+ margin-bottom: 4px;
279
+ }
280
+
281
+ .cd-pseudocode__code {
282
+ font-family: "SF Mono", "Fira Code", "Consolas", monospace;
283
+ font-size: 13px;
284
+ color: var(--text-pseudocode);
285
+ margin: 0;
286
+ white-space: pre-wrap;
287
+ }
288
+
289
+ .cd-warnings {
290
+ margin-bottom: 8px;
291
+ }
292
+
293
+ .cd-warnings__item {
294
+ font-size: 13px;
295
+ color: var(--text-warning);
296
+ padding: 2px 0;
297
+ }
298
+
299
+ .cd-node__children {
300
+ padding-left: 16px;
301
+ }
302
+
303
+ .cd-code-actions {
304
+ display: flex;
305
+ flex-wrap: wrap;
306
+ gap: 6px;
307
+ margin-bottom: 8px;
308
+ }
309
+
310
+ .cd-code-btn {
311
+ font-size: 12px;
312
+ font-weight: 600;
313
+ padding: 4px 12px;
314
+ border-radius: 14px;
315
+ border: 1px solid var(--border-btn);
316
+ background: var(--bg-btn);
317
+ color: var(--text-btn);
318
+ cursor: pointer;
319
+ transition: background 0.15s, color 0.15s;
320
+ }
321
+
322
+ .cd-code-btn:hover {
323
+ background: var(--bg-btn-hover);
324
+ }
325
+
326
+ .cd-code-btn--active {
327
+ background: var(--bg-btn-active);
328
+ color: #FFF;
329
+ border-color: var(--bg-btn-active);
330
+ }
331
+
332
+ .cd-code-btn--copied {
333
+ background: #2E7D32;
334
+ color: #FFF;
335
+ border-color: #2E7D32;
336
+ }
337
+
338
+ .cd-source-display {
339
+ display: none;
340
+ background: var(--bg-source);
341
+ color: var(--text-source);
342
+ border-radius: 6px;
343
+ padding: 12px;
344
+ margin-bottom: 8px;
345
+ font-family: "SF Mono", "Fira Code", "Consolas", monospace;
346
+ font-size: 13px;
347
+ overflow-x: auto;
348
+ white-space: pre;
349
+ line-height: 1.5;
350
+ margin-top: 0;
351
+ }
352
+
353
+ .cd-source-display--open {
354
+ display: block;
355
+ }
356
+
357
+ @media (max-width: 600px) {
358
+ .cd-header {
359
+ padding: 12px 12px;
360
+ }
361
+ .cd-main {
362
+ padding: 0 8px 32px;
363
+ }
364
+ .cd-node__header {
365
+ padding: 8px 10px;
366
+ }
367
+ .cd-node__body {
368
+ padding: 0 10px 8px;
369
+ }
370
+ .cd-node__children {
371
+ padding-left: 8px;
372
+ }
373
+ }
374
+ </style>
375
+ </head>
376
+ <body>
377
+
378
+ {% macro render_node(node) %}
379
+ <div class="cd-node cd-node--{{ node.node_type }}" style="--node-color: {{ get_color(node) }};">
380
+ <div class="cd-node__header">
381
+ <span class="cd-node__icon">{{ NODE_ICONS.get(node.node_type, '') }}</span>
382
+ <span class="cd-node__name">{{ node.name }}</span>
383
+ <span class="cd-node__badge">{{ node.node_type }}</span>
384
+ <span class="cd-node__lines">{{ node.line_count }} lines</span>
385
+ {% if node.node_type in ('function', 'method') and node.start_line and node.end_line %}
386
+ <span class="cd-node__range">L{{ node.start_line }}–{{ node.end_line }}</span>
387
+ {% endif %}
388
+ {% if node.quality == 'warning' %}
389
+ <span class="cd-node__quality">🔴</span>
390
+ {% elif node.quality == 'complex' %}
391
+ <span class="cd-node__quality">🟡</span>
392
+ {% else %}
393
+ <span class="cd-node__quality">🟢</span>
394
+ {% endif %}
395
+ {% if node.warnings %}
396
+ <span class="cd-node__warning-text">{{ node.warnings | join('; ') }}</span>
397
+ {% endif %}
398
+ </div>
399
+ <div class="cd-node__body">
400
+ {% if node.imports %}
401
+ <div class="cd-imports">
402
+ <div class="cd-imports__label">IMPORTS</div>
403
+ {% for imp in node.imports %}
404
+ <div class="cd-imports__item">→ {{ imp }}</div>
405
+ {% endfor %}
406
+ </div>
407
+ {% endif %}
408
+ {% if node.summary %}
409
+ <div class="cd-summary">{{ node.summary }}</div>
410
+ {% elif node.node_type != 'directory' %}
411
+ <div class="cd-summary cd-summary--placeholder">AI summary pending...</div>
412
+ {% endif %}
413
+ {% if node.pseudocode and node.node_type in ('function', 'method') %}
414
+ <div class="cd-pseudocode">
415
+ <div class="cd-pseudocode__label">PSEUDOCODE</div>
416
+ <pre class="cd-pseudocode__code">{{ node.pseudocode }}</pre>
417
+ </div>
418
+ {% endif %}
419
+ {% if node.warnings %}
420
+ <div class="cd-warnings">
421
+ {% for w in node.warnings %}
422
+ <div class="cd-warnings__item">⚠️ {{ w }}</div>
423
+ {% endfor %}
424
+ </div>
425
+ {% endif %}
426
+ {% if node.node_type != 'directory' and node.source %}
427
+ <div class="cd-code-actions">
428
+ <button class="cd-code-btn" onclick="cdToggleSource(this)">Show Code</button>
429
+ <button class="cd-code-btn" onclick="cdExportCode(this)">Export Code</button>
430
+ <button class="cd-code-btn" onclick="cdCopyForAI(this)">Copy for AI</button>
431
+ </div>
432
+ <pre class="cd-source-display"
433
+ data-node-type="{{ node.node_type }}"
434
+ data-node-name="{{ node.name }}"
435
+ data-filepath="{{ node.filepath }}"
436
+ data-language="{{ node.language or '' }}">{{ node.source }}</pre>
437
+ {% endif %}
438
+ {% if node.children %}
439
+ <div class="cd-node__children">
440
+ {% for child in node.children %}
441
+ {{ render_node(child) }}
442
+ {% endfor %}
443
+ </div>
444
+ {% endif %}
445
+ </div>
446
+ </div>
447
+ {% endmacro %}
448
+
449
+ <header class="cd-header">
450
+ <div class="cd-header__text">
451
+ <h1 class="cd-header__title">codedocent</h1>
452
+ <p class="cd-header__path">{{ root.filepath or root.name }}</p>
453
+ </div>
454
+ <button class="cd-theme-toggle" id="cd-theme-toggle"
455
+ onclick="cdToggleTheme()" aria-label="Toggle theme"></button>
456
+ </header>
457
+
458
+ <main class="cd-main">
459
+ {{ render_node(root) }}
460
+ </main>
461
+
462
+ <script>
463
+ function cdToggleTheme() {
464
+ var isLight = document.documentElement.classList.toggle('light-mode');
465
+ localStorage.setItem('cd-theme', isLight ? 'light' : 'dark');
466
+ document.getElementById('cd-theme-toggle').textContent = isLight ? '\u{1F319}' : '\u2600\uFE0F';
467
+ }
468
+ (function() {
469
+ var btn = document.getElementById('cd-theme-toggle');
470
+ if (btn) btn.textContent = document.documentElement.classList.contains('light-mode') ? '\u{1F319}' : '\u2600\uFE0F';
471
+ })();
472
+
473
+ function cdToggleSource(btn) {
474
+ var pre = btn.closest('.cd-node__body').querySelector('.cd-source-display');
475
+ var isOpen = pre.classList.contains('cd-source-display--open');
476
+ if (isOpen) {
477
+ pre.classList.remove('cd-source-display--open');
478
+ btn.classList.remove('cd-code-btn--active');
479
+ btn.textContent = 'Show Code';
480
+ } else {
481
+ pre.classList.add('cd-source-display--open');
482
+ btn.classList.add('cd-code-btn--active');
483
+ btn.textContent = 'Hide Code';
484
+ }
485
+ }
486
+
487
+ function cdExportCode(btn) {
488
+ var pre = btn.closest('.cd-node__body').querySelector('.cd-source-display');
489
+ cdCopyToClipboard(pre.textContent, btn);
490
+ }
491
+
492
+ function cdCopyForAI(btn) {
493
+ var pre = btn.closest('.cd-node__body').querySelector('.cd-source-display');
494
+ var nodeType = pre.dataset.nodeType;
495
+ var nodeName = pre.dataset.nodeName;
496
+ var filepath = pre.dataset.filepath;
497
+ var language = pre.dataset.language;
498
+ var text = 'This is the ' + nodeType + ' `' + nodeName + '` from `' + filepath + '`:\n\n```' + language + '\n' + pre.textContent + '\n```';
499
+ cdCopyToClipboard(text, btn);
500
+ }
501
+
502
+ function cdCopyToClipboard(text, btn) {
503
+ if (navigator.clipboard && navigator.clipboard.writeText) {
504
+ navigator.clipboard.writeText(text).then(function() {
505
+ cdShowCopied(btn);
506
+ }, function() {
507
+ cdFallbackCopy(text, btn);
508
+ });
509
+ } else {
510
+ cdFallbackCopy(text, btn);
511
+ }
512
+ }
513
+
514
+ function cdFallbackCopy(text, btn) {
515
+ var ta = document.createElement('textarea');
516
+ ta.value = text;
517
+ ta.style.position = 'fixed';
518
+ ta.style.left = '-9999px';
519
+ document.body.appendChild(ta);
520
+ ta.select();
521
+ try { document.execCommand('copy'); cdShowCopied(btn); }
522
+ catch(e) {}
523
+ document.body.removeChild(ta);
524
+ }
525
+
526
+ function cdShowCopied(btn) {
527
+ var orig = btn.textContent;
528
+ btn.textContent = 'Copied!';
529
+ btn.classList.add('cd-code-btn--copied');
530
+ setTimeout(function() {
531
+ btn.textContent = orig;
532
+ btn.classList.remove('cd-code-btn--copied');
533
+ }, 1500);
534
+ }
535
+ </script>
536
+
537
+ </body>
538
+ </html>