cyclecad 0.1.3 → 0.1.4

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,337 @@
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.0">
6
+ <title>DUO Manifest Viewer</title>
7
+ <style>
8
+ body {
9
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
10
+ margin: 0;
11
+ padding: 20px;
12
+ background: #f5f5f5;
13
+ color: #333;
14
+ }
15
+ .container {
16
+ max-width: 1200px;
17
+ margin: 0 auto;
18
+ background: white;
19
+ padding: 20px;
20
+ border-radius: 8px;
21
+ box-shadow: 0 2px 8px rgba(0,0,0,0.1);
22
+ }
23
+ h1 {
24
+ margin-top: 0;
25
+ color: #0066cc;
26
+ }
27
+ .stats {
28
+ display: grid;
29
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
30
+ gap: 20px;
31
+ margin: 20px 0;
32
+ }
33
+ .stat-box {
34
+ background: #f9f9f9;
35
+ border-left: 4px solid #0066cc;
36
+ padding: 15px;
37
+ border-radius: 4px;
38
+ }
39
+ .stat-box h3 {
40
+ margin: 0 0 10px 0;
41
+ color: #666;
42
+ font-size: 12px;
43
+ text-transform: uppercase;
44
+ letter-spacing: 0.5px;
45
+ }
46
+ .stat-box .value {
47
+ font-size: 32px;
48
+ font-weight: bold;
49
+ color: #0066cc;
50
+ }
51
+ .stat-box .sublabel {
52
+ font-size: 12px;
53
+ color: #999;
54
+ margin-top: 5px;
55
+ }
56
+ .tabs {
57
+ display: flex;
58
+ gap: 0;
59
+ border-bottom: 2px solid #eee;
60
+ margin: 20px 0;
61
+ }
62
+ .tab-btn {
63
+ padding: 10px 20px;
64
+ background: none;
65
+ border: none;
66
+ cursor: pointer;
67
+ font-size: 14px;
68
+ color: #666;
69
+ border-bottom: 2px solid transparent;
70
+ margin-bottom: -2px;
71
+ transition: all 0.2s;
72
+ }
73
+ .tab-btn:hover {
74
+ color: #0066cc;
75
+ }
76
+ .tab-btn.active {
77
+ color: #0066cc;
78
+ border-bottom-color: #0066cc;
79
+ }
80
+ .tab-content {
81
+ display: none;
82
+ }
83
+ .tab-content.active {
84
+ display: block;
85
+ }
86
+ table {
87
+ width: 100%;
88
+ border-collapse: collapse;
89
+ font-size: 13px;
90
+ }
91
+ th {
92
+ background: #f5f5f5;
93
+ padding: 10px;
94
+ text-align: left;
95
+ font-weight: 600;
96
+ border-bottom: 1px solid #ddd;
97
+ }
98
+ td {
99
+ padding: 10px;
100
+ border-bottom: 1px solid #eee;
101
+ }
102
+ tr:hover {
103
+ background: #fafafa;
104
+ }
105
+ .category-badge {
106
+ display: inline-block;
107
+ padding: 2px 8px;
108
+ border-radius: 3px;
109
+ font-size: 11px;
110
+ font-weight: 600;
111
+ text-transform: uppercase;
112
+ letter-spacing: 0.3px;
113
+ }
114
+ .category-badge.custom {
115
+ background: #e3f2fd;
116
+ color: #1976d2;
117
+ }
118
+ .category-badge.standard {
119
+ background: #f3e5f5;
120
+ color: #7b1fa2;
121
+ }
122
+ .category-badge.vendor {
123
+ background: #fff3e0;
124
+ color: #e65100;
125
+ }
126
+ .tree-view {
127
+ margin: 20px 0;
128
+ }
129
+ .tree-item {
130
+ margin-left: 20px;
131
+ padding: 5px 0;
132
+ font-size: 13px;
133
+ }
134
+ .tree-folder {
135
+ font-weight: 600;
136
+ color: #0066cc;
137
+ margin-top: 10px;
138
+ }
139
+ .file-size {
140
+ color: #999;
141
+ font-size: 12px;
142
+ }
143
+ .loading {
144
+ text-align: center;
145
+ color: #999;
146
+ padding: 40px;
147
+ }
148
+ .error {
149
+ background: #ffebee;
150
+ color: #c62828;
151
+ padding: 15px;
152
+ border-radius: 4px;
153
+ margin: 20px 0;
154
+ }
155
+ </style>
156
+ </head>
157
+ <body>
158
+ <div class="container">
159
+ <h1>DUO Durchgehend Inventor — Manifest Viewer</h1>
160
+ <div class="loading">Loading manifest...</div>
161
+ </div>
162
+
163
+ <script>
164
+ async function loadManifest() {
165
+ try {
166
+ const response = await fetch('./duo-manifest.json');
167
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
168
+
169
+ const manifest = await response.json();
170
+ renderManifest(manifest);
171
+ } catch (error) {
172
+ document.querySelector('.container').innerHTML = `
173
+ <h1>DUO Durchgehend Inventor — Manifest Viewer</h1>
174
+ <div class="error">Error loading manifest: ${error.message}</div>
175
+ `;
176
+ }
177
+ }
178
+
179
+ function formatSize(bytes) {
180
+ if (bytes === 0) return '0 B';
181
+ const k = 1024;
182
+ const sizes = ['B', 'KB', 'MB', 'GB'];
183
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
184
+ return Math.round(bytes / Math.pow(k, i) * 100) / 100 + ' ' + sizes[i];
185
+ }
186
+
187
+ function renderManifest(manifest) {
188
+ const s = manifest.stats;
189
+ const html = `
190
+ <h1>${manifest.name}</h1>
191
+ <p><strong>${manifest.description}</strong></p>
192
+
193
+ <div class="stats">
194
+ <div class="stat-box">
195
+ <h3>Total Files</h3>
196
+ <div class="value">${s.total}</div>
197
+ </div>
198
+ <div class="stat-box">
199
+ <h3>Parts (.ipt)</h3>
200
+ <div class="value">${s.parts}</div>
201
+ <div class="sublabel">Custom: ${s.custom} • Standard: ${s.standard} • Vendor: ${s.vendor}</div>
202
+ </div>
203
+ <div class="stat-box">
204
+ <h3>Assemblies (.iam)</h3>
205
+ <div class="value">${s.assemblies}</div>
206
+ </div>
207
+ </div>
208
+
209
+ <div class="tabs">
210
+ <button class="tab-btn active" data-tab="project">Project Info</button>
211
+ <button class="tab-btn" data-tab="assemblies">Assemblies</button>
212
+ <button class="tab-btn" data-tab="parts">Parts</button>
213
+ <button class="tab-btn" data-tab="tree">Folder Tree</button>
214
+ </div>
215
+
216
+ <div id="project" class="tab-content active">
217
+ <table>
218
+ <tr>
219
+ <th>Property</th>
220
+ <th>Value</th>
221
+ </tr>
222
+ <tr>
223
+ <td>Project File</td>
224
+ <td><code>${manifest.ipj}</code></td>
225
+ </tr>
226
+ <tr>
227
+ <td>Workspace</td>
228
+ <td><code>${manifest.workspace}</code></td>
229
+ </tr>
230
+ <tr>
231
+ <td>Content Center</td>
232
+ <td><code>${manifest.contentCenter}</code></td>
233
+ </tr>
234
+ <tr>
235
+ <td>Total Components</td>
236
+ <td>${s.total}</td>
237
+ </tr>
238
+ <tr>
239
+ <td>Main Assembly</td>
240
+ <td><code>${manifest.assemblies.find(a => a.isMain)?.path || 'N/A'}</code></td>
241
+ </tr>
242
+ </table>
243
+ </div>
244
+
245
+ <div id="assemblies" class="tab-content">
246
+ <table>
247
+ <tr>
248
+ <th>Assembly Name</th>
249
+ <th>Path</th>
250
+ <th>Size</th>
251
+ <th></th>
252
+ </tr>
253
+ ${manifest.assemblies.map(a => `
254
+ <tr>
255
+ <td><strong>${a.name}</strong></td>
256
+ <td><code style="font-size: 11px">${a.path}</code></td>
257
+ <td>${formatSize(a.size)}</td>
258
+ <td>${a.isMain ? '<span style="color: #d32f2f; font-weight: 600;">● MAIN</span>' : ''}</td>
259
+ </tr>
260
+ `).join('')}
261
+ </table>
262
+ </div>
263
+
264
+ <div id="parts" class="tab-content">
265
+ <table>
266
+ <tr>
267
+ <th>Part Name</th>
268
+ <th>Category</th>
269
+ <th>Path</th>
270
+ <th>Size</th>
271
+ </tr>
272
+ ${manifest.parts.slice(0, 50).map(p => `
273
+ <tr>
274
+ <td>${p.name}</td>
275
+ <td><span class="category-badge ${p.category}">${p.category}</span></td>
276
+ <td><code style="font-size: 11px">${p.path}</code></td>
277
+ <td>${formatSize(p.size)}</td>
278
+ </tr>
279
+ `).join('')}
280
+ <tr>
281
+ <td colspan="4" style="text-align: center; color: #999; font-size: 12px;">
282
+ Showing 50 of ${manifest.parts.length} parts
283
+ </td>
284
+ </tr>
285
+ </table>
286
+ </div>
287
+
288
+ <div id="tree" class="tab-content">
289
+ <div class="tree-view">
290
+ ${renderTree(manifest.tree, 0)}
291
+ </div>
292
+ </div>
293
+ `;
294
+
295
+ document.querySelector('.container').innerHTML = html;
296
+
297
+ // Tab switching
298
+ document.querySelectorAll('.tab-btn').forEach(btn => {
299
+ btn.addEventListener('click', (e) => {
300
+ document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
301
+ document.querySelectorAll('.tab-content').forEach(c => c.classList.remove('active'));
302
+ e.target.classList.add('active');
303
+ document.getElementById(e.target.dataset.tab).classList.add('active');
304
+ });
305
+ });
306
+ }
307
+
308
+ function renderTree(node, depth, limit = 100, count = { n: 0 }) {
309
+ if (count.n >= limit) return '';
310
+ count.n++;
311
+
312
+ if (node.type === 'folder') {
313
+ const margin = depth * 20;
314
+ const items = (node.children || []).slice(0, 50);
315
+ return `
316
+ <div class="tree-item" style="margin-left: ${margin}px; font-weight: 600; color: #0066cc;">
317
+ 📁 ${node.name}
318
+ </div>
319
+ ${items.map(child => renderTree(child, depth + 1, limit, count)).join('')}
320
+ ${(node.children || []).length > 50 ? `<div class="tree-item" style="margin-left: ${(depth+1)*20}px; color: #999;">... and ${node.children.length - 50} more</div>` : ''}
321
+ `;
322
+ } else {
323
+ const margin = depth * 20;
324
+ const badge = node.category ? `<span class="category-badge ${node.category}" style="margin-left: 10px">${node.category}</span>` : '';
325
+ return `
326
+ <div class="tree-item" style="margin-left: ${margin}px;">
327
+ 📄 ${node.name} <span class="file-size">${formatSize(node.size)}</span>${badge}
328
+ </div>
329
+ `;
330
+ }
331
+ }
332
+
333
+ // Load on page load
334
+ loadManifest();
335
+ </script>
336
+ </body>
337
+ </html>