create-claudeportal 0.1.0

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.
Files changed (39) hide show
  1. package/bin/cli.js +37 -0
  2. package/dist/assets/index-BBU5K5iA.js +132 -0
  3. package/dist/assets/index-fNmv07eE.css +1 -0
  4. package/dist/index.html +13 -0
  5. package/index.html +12 -0
  6. package/mockups/01-chat-conversation-v2.html +803 -0
  7. package/mockups/01-chat-conversation.html +592 -0
  8. package/mockups/02-activity-feed.html +648 -0
  9. package/mockups/03-focused-workspace.html +680 -0
  10. package/mockups/04-documents-mode.html +1556 -0
  11. package/package.json +54 -0
  12. package/server/index.js +140 -0
  13. package/server/lib/detect-tools.js +93 -0
  14. package/server/lib/file-scanner.js +46 -0
  15. package/server/lib/file-watcher.js +45 -0
  16. package/server/lib/fix-npm-prefix.js +61 -0
  17. package/server/lib/folder-scanner.js +43 -0
  18. package/server/lib/install-tools.js +122 -0
  19. package/server/lib/platform.js +18 -0
  20. package/server/lib/sse-manager.js +36 -0
  21. package/server/lib/terminal.js +95 -0
  22. package/server/lib/validate-folder-path.js +17 -0
  23. package/server/lib/validate-path.js +13 -0
  24. package/server/routes/detect.js +64 -0
  25. package/server/routes/doc-events.js +94 -0
  26. package/server/routes/events.js +37 -0
  27. package/server/routes/folder.js +195 -0
  28. package/server/routes/github.js +21 -0
  29. package/server/routes/health.js +16 -0
  30. package/server/routes/install.js +102 -0
  31. package/server/routes/project.js +18 -0
  32. package/server/routes/scaffold.js +45 -0
  33. package/skills-lock.json +15 -0
  34. package/tsconfig.app.json +17 -0
  35. package/tsconfig.node.json +11 -0
  36. package/tsconfig.tsbuildinfo +1 -0
  37. package/ui/app.js +747 -0
  38. package/ui/index.html +272 -0
  39. package/ui/styles.css +788 -0
@@ -0,0 +1,648 @@
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>Mockup 2: Activity Feed</title>
7
+ <style>
8
+ * { margin: 0; padding: 0; box-sizing: border-box; }
9
+
10
+ body {
11
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
12
+ background: #f5f5f0;
13
+ color: #1a1a2e;
14
+ height: 100vh;
15
+ display: flex;
16
+ }
17
+
18
+ /* ---- LEFT: ACTIVITY FEED ---- */
19
+ .feed-area {
20
+ flex: 1;
21
+ display: flex;
22
+ flex-direction: column;
23
+ min-width: 0;
24
+ }
25
+
26
+ .feed-header {
27
+ padding: 20px 32px;
28
+ background: #fff;
29
+ border-bottom: 1px solid #e5e7eb;
30
+ display: flex;
31
+ align-items: center;
32
+ justify-content: space-between;
33
+ }
34
+
35
+ .feed-header-left {
36
+ display: flex;
37
+ align-items: center;
38
+ gap: 14px;
39
+ }
40
+
41
+ .project-badge {
42
+ display: flex;
43
+ align-items: center;
44
+ gap: 8px;
45
+ padding: 6px 14px;
46
+ background: #f0fdf4;
47
+ border: 1px solid #bbf7d0;
48
+ border-radius: 100px;
49
+ font-size: 13px;
50
+ font-weight: 600;
51
+ color: #166534;
52
+ }
53
+
54
+ .project-badge .dot {
55
+ width: 8px;
56
+ height: 8px;
57
+ border-radius: 50%;
58
+ background: #22c55e;
59
+ animation: blink 2s ease infinite;
60
+ }
61
+
62
+ @keyframes blink {
63
+ 0%, 100% { opacity: 1; }
64
+ 50% { opacity: 0.3; }
65
+ }
66
+
67
+ .feed-header h1 {
68
+ font-size: 20px;
69
+ font-weight: 700;
70
+ }
71
+
72
+ .overall-progress {
73
+ display: flex;
74
+ align-items: center;
75
+ gap: 12px;
76
+ }
77
+
78
+ .progress-bar-bg {
79
+ width: 200px;
80
+ height: 8px;
81
+ background: #e5e7eb;
82
+ border-radius: 100px;
83
+ overflow: hidden;
84
+ }
85
+
86
+ .progress-bar-fill {
87
+ height: 100%;
88
+ background: linear-gradient(90deg, #22c55e, #4ade80);
89
+ border-radius: 100px;
90
+ width: 65%;
91
+ transition: width 0.5s ease;
92
+ }
93
+
94
+ .progress-label {
95
+ font-size: 13px;
96
+ color: #6b7280;
97
+ font-weight: 500;
98
+ }
99
+
100
+ /* Feed content */
101
+ .feed-scroll {
102
+ flex: 1;
103
+ overflow-y: auto;
104
+ padding: 24px 32px;
105
+ }
106
+
107
+ .feed-timeline {
108
+ position: relative;
109
+ padding-left: 36px;
110
+ }
111
+
112
+ .feed-timeline::before {
113
+ content: '';
114
+ position: absolute;
115
+ left: 15px;
116
+ top: 0;
117
+ bottom: 0;
118
+ width: 2px;
119
+ background: #e5e7eb;
120
+ }
121
+
122
+ /* Activity cards */
123
+ .activity {
124
+ position: relative;
125
+ margin-bottom: 20px;
126
+ animation: slideIn 0.4s ease;
127
+ }
128
+
129
+ @keyframes slideIn {
130
+ from { opacity: 0; transform: translateX(-12px); }
131
+ to { opacity: 1; transform: translateX(0); }
132
+ }
133
+
134
+ .activity-dot {
135
+ position: absolute;
136
+ left: -36px;
137
+ top: 16px;
138
+ width: 32px;
139
+ height: 32px;
140
+ border-radius: 50%;
141
+ display: flex;
142
+ align-items: center;
143
+ justify-content: center;
144
+ font-size: 14px;
145
+ z-index: 1;
146
+ }
147
+
148
+ .dot-done { background: #dcfce7; }
149
+ .dot-active { background: #dbeafe; animation: pulse 1.5s ease infinite; }
150
+ .dot-plan { background: #f3f4f6; }
151
+
152
+ @keyframes pulse {
153
+ 0%, 100% { box-shadow: 0 0 0 0 rgba(59,130,246,0.3); }
154
+ 50% { box-shadow: 0 0 0 6px rgba(59,130,246,0); }
155
+ }
156
+
157
+ .activity-card {
158
+ background: #fff;
159
+ border: 1px solid #e5e7eb;
160
+ border-radius: 14px;
161
+ overflow: hidden;
162
+ transition: box-shadow 0.2s;
163
+ }
164
+
165
+ .activity-card:hover {
166
+ box-shadow: 0 2px 12px rgba(0,0,0,0.04);
167
+ }
168
+
169
+ .activity-card.active {
170
+ border-color: #93c5fd;
171
+ box-shadow: 0 0 0 3px rgba(59,130,246,0.08);
172
+ }
173
+
174
+ .activity-main {
175
+ padding: 16px 20px;
176
+ }
177
+
178
+ .activity-top {
179
+ display: flex;
180
+ align-items: center;
181
+ justify-content: space-between;
182
+ margin-bottom: 6px;
183
+ }
184
+
185
+ .activity-title {
186
+ font-size: 15px;
187
+ font-weight: 600;
188
+ }
189
+
190
+ .activity-time {
191
+ font-size: 11px;
192
+ color: #9ca3af;
193
+ }
194
+
195
+ .activity-desc {
196
+ font-size: 13px;
197
+ color: #6b7280;
198
+ line-height: 1.5;
199
+ }
200
+
201
+ .activity-tags {
202
+ display: flex;
203
+ gap: 6px;
204
+ margin-top: 10px;
205
+ flex-wrap: wrap;
206
+ }
207
+
208
+ .tag {
209
+ font-size: 11px;
210
+ padding: 3px 10px;
211
+ border-radius: 100px;
212
+ font-weight: 500;
213
+ }
214
+
215
+ .tag-file { background: #f0f9ff; color: #0369a1; }
216
+ .tag-style { background: #fdf4ff; color: #a21caf; }
217
+ .tag-feature { background: #f0fdf4; color: #166534; }
218
+ .tag-config { background: #fffbeb; color: #92400e; }
219
+
220
+ /* Expandable details */
221
+ .activity-details {
222
+ border-top: 1px solid #f3f4f6;
223
+ padding: 12px 20px;
224
+ background: #fafaf8;
225
+ }
226
+
227
+ .detail-toggle {
228
+ font-size: 12px;
229
+ color: #9ca3af;
230
+ cursor: pointer;
231
+ border: none;
232
+ background: none;
233
+ font-family: inherit;
234
+ padding: 4px 0;
235
+ display: flex;
236
+ align-items: center;
237
+ gap: 6px;
238
+ }
239
+
240
+ .detail-toggle:hover {
241
+ color: #6b7280;
242
+ }
243
+
244
+ .detail-content {
245
+ margin-top: 8px;
246
+ font-family: 'SF Mono', 'Fira Code', monospace;
247
+ font-size: 12px;
248
+ line-height: 1.7;
249
+ color: #374151;
250
+ background: #fff;
251
+ border: 1px solid #e5e7eb;
252
+ border-radius: 8px;
253
+ padding: 10px 14px;
254
+ max-height: 140px;
255
+ overflow-y: auto;
256
+ }
257
+
258
+ .detail-line-add { color: #16a34a; }
259
+ .detail-line-dim { color: #9ca3af; }
260
+
261
+ /* Files changed summary */
262
+ .files-changed {
263
+ display: flex;
264
+ gap: 6px;
265
+ margin-top: 10px;
266
+ }
267
+
268
+ .file-chip {
269
+ font-size: 11px;
270
+ padding: 4px 10px;
271
+ background: #f3f4f6;
272
+ border-radius: 6px;
273
+ font-family: 'SF Mono', monospace;
274
+ color: #6b7280;
275
+ }
276
+
277
+ /* ---- INPUT BAR ---- */
278
+ .input-bar {
279
+ padding: 16px 32px;
280
+ background: #fff;
281
+ border-top: 1px solid #e5e7eb;
282
+ }
283
+
284
+ .input-row {
285
+ display: flex;
286
+ gap: 10px;
287
+ align-items: center;
288
+ }
289
+
290
+ .input-field {
291
+ flex: 1;
292
+ padding: 14px 18px;
293
+ border: 2px solid #e5e7eb;
294
+ border-radius: 14px;
295
+ font-size: 14px;
296
+ font-family: inherit;
297
+ outline: none;
298
+ transition: border-color 0.2s;
299
+ }
300
+
301
+ .input-field:focus {
302
+ border-color: #22c55e;
303
+ box-shadow: 0 0 0 3px rgba(34,197,94,0.1);
304
+ }
305
+
306
+ .send-btn {
307
+ width: 48px;
308
+ height: 48px;
309
+ border-radius: 14px;
310
+ border: none;
311
+ background: #22c55e;
312
+ color: white;
313
+ font-size: 18px;
314
+ cursor: pointer;
315
+ display: flex;
316
+ align-items: center;
317
+ justify-content: center;
318
+ transition: background 0.15s;
319
+ flex-shrink: 0;
320
+ }
321
+
322
+ .send-btn:hover { background: #16a34a; }
323
+
324
+ /* ---- RIGHT: OUTPUT / PREVIEW ---- */
325
+ .output-panel {
326
+ width: 420px;
327
+ background: #fff;
328
+ border-left: 1px solid #e5e7eb;
329
+ display: flex;
330
+ flex-direction: column;
331
+ flex-shrink: 0;
332
+ }
333
+
334
+ .output-tabs {
335
+ display: flex;
336
+ border-bottom: 1px solid #e5e7eb;
337
+ }
338
+
339
+ .output-tab {
340
+ flex: 1;
341
+ padding: 14px;
342
+ border: none;
343
+ background: transparent;
344
+ font-size: 13px;
345
+ font-weight: 600;
346
+ font-family: inherit;
347
+ cursor: pointer;
348
+ color: #9ca3af;
349
+ border-bottom: 2px solid transparent;
350
+ transition: all 0.15s;
351
+ }
352
+
353
+ .output-tab.active {
354
+ color: #1a1a2e;
355
+ border-bottom-color: #22c55e;
356
+ }
357
+
358
+ .output-body {
359
+ flex: 1;
360
+ display: flex;
361
+ flex-direction: column;
362
+ }
363
+
364
+ .file-tree {
365
+ padding: 16px;
366
+ flex: 1;
367
+ }
368
+
369
+ .tree-item {
370
+ display: flex;
371
+ align-items: center;
372
+ gap: 8px;
373
+ padding: 8px 12px;
374
+ border-radius: 8px;
375
+ font-size: 13px;
376
+ cursor: pointer;
377
+ color: #374151;
378
+ }
379
+
380
+ .tree-item:hover { background: #f5f5f0; }
381
+
382
+ .tree-icon { font-size: 15px; opacity: 0.6; }
383
+
384
+ .tree-indent { padding-left: 28px; }
385
+
386
+ .tree-badge {
387
+ margin-left: auto;
388
+ font-size: 10px;
389
+ padding: 2px 8px;
390
+ border-radius: 100px;
391
+ font-weight: 600;
392
+ }
393
+
394
+ .badge-new { background: #dcfce7; color: #166534; }
395
+ .badge-modified { background: #fef3c7; color: #92400e; }
396
+
397
+ .file-preview {
398
+ border-top: 1px solid #e5e7eb;
399
+ padding: 16px;
400
+ background: #fafaf8;
401
+ max-height: 300px;
402
+ overflow-y: auto;
403
+ }
404
+
405
+ .file-preview-header {
406
+ font-size: 12px;
407
+ font-weight: 600;
408
+ color: #6b7280;
409
+ margin-bottom: 8px;
410
+ display: flex;
411
+ align-items: center;
412
+ gap: 6px;
413
+ }
414
+
415
+ .file-preview code {
416
+ display: block;
417
+ font-family: 'SF Mono', 'Fira Code', monospace;
418
+ font-size: 12px;
419
+ line-height: 1.7;
420
+ color: #374151;
421
+ white-space: pre;
422
+ }
423
+ </style>
424
+ </head>
425
+ <body>
426
+ <!-- MAIN FEED AREA -->
427
+ <div class="feed-area">
428
+ <div class="feed-header">
429
+ <div class="feed-header-left">
430
+ <h1>my-portfolio</h1>
431
+ <div class="project-badge">
432
+ <span class="dot"></span>
433
+ Claude is building
434
+ </div>
435
+ </div>
436
+ <div class="overall-progress">
437
+ <div class="progress-bar-bg">
438
+ <div class="progress-bar-fill"></div>
439
+ </div>
440
+ <span class="progress-label">4 of 6 steps done</span>
441
+ </div>
442
+ </div>
443
+
444
+ <div class="feed-scroll">
445
+ <div class="feed-timeline">
446
+
447
+ <!-- Step 1: Done -->
448
+ <div class="activity">
449
+ <div class="activity-dot dot-done">✓</div>
450
+ <div class="activity-card">
451
+ <div class="activity-main">
452
+ <div class="activity-top">
453
+ <span class="activity-title">Set up the project</span>
454
+ <span class="activity-time">2 min ago</span>
455
+ </div>
456
+ <div class="activity-desc">Created the folder structure and installed the tools needed to build your site.</div>
457
+ <div class="activity-tags">
458
+ <span class="tag tag-config">package.json</span>
459
+ <span class="tag tag-config">vite.config.js</span>
460
+ </div>
461
+ </div>
462
+ </div>
463
+ </div>
464
+
465
+ <!-- Step 2: Done -->
466
+ <div class="activity">
467
+ <div class="activity-dot dot-done">✓</div>
468
+ <div class="activity-card">
469
+ <div class="activity-main">
470
+ <div class="activity-top">
471
+ <span class="activity-title">Built the homepage</span>
472
+ <span class="activity-time">1 min ago</span>
473
+ </div>
474
+ <div class="activity-desc">Created a clean hero section with your name, tagline, and a full-width cover photo.</div>
475
+ <div class="activity-tags">
476
+ <span class="tag tag-feature">Hero section</span>
477
+ <span class="tag tag-style">Typography</span>
478
+ </div>
479
+ </div>
480
+ <div class="activity-details">
481
+ <button class="detail-toggle">📄 Show what changed <span>▾</span></button>
482
+ </div>
483
+ </div>
484
+ </div>
485
+
486
+ <!-- Step 3: Done -->
487
+ <div class="activity">
488
+ <div class="activity-dot dot-done">✓</div>
489
+ <div class="activity-card">
490
+ <div class="activity-main">
491
+ <div class="activity-top">
492
+ <span class="activity-title">Built the photo gallery</span>
493
+ <span class="activity-time">45 sec ago</span>
494
+ </div>
495
+ <div class="activity-desc">Added a masonry grid layout that looks great on all screen sizes. Click any photo to see it full-screen.</div>
496
+ <div class="activity-tags">
497
+ <span class="tag tag-feature">Gallery grid</span>
498
+ <span class="tag tag-feature">Lightbox</span>
499
+ <span class="tag tag-style">Responsive</span>
500
+ </div>
501
+ </div>
502
+ <div class="activity-details">
503
+ <button class="detail-toggle">📄 Show what changed <span>▾</span></button>
504
+ <div class="detail-content">
505
+ <div class="detail-line-dim">// src/components/Gallery.jsx</div>
506
+ <div class="detail-line-add">+ export function Gallery({ photos }) {</div>
507
+ <div class="detail-line-add">+ const [selected, setSelected] = useState(null)</div>
508
+ <div class="detail-line-add">+ return (</div>
509
+ <div class="detail-line-add">+ &lt;section className="gallery"&gt;</div>
510
+ <div class="detail-line-add">+ &lt;div className="masonry-grid"&gt;</div>
511
+ <div class="detail-line-add">+ {photos.map(p =&gt; ...</div>
512
+ <div class="detail-line-add">+ &lt;/div&gt;</div>
513
+ <div class="detail-line-add">+ &lt;/section&gt;</div>
514
+ <div class="detail-line-add">+ )</div>
515
+ <div class="detail-line-add">+ }</div>
516
+ </div>
517
+ </div>
518
+ </div>
519
+ </div>
520
+
521
+ <!-- Step 4: Active -->
522
+ <div class="activity">
523
+ <div class="activity-dot dot-active">⚡</div>
524
+ <div class="activity-card active">
525
+ <div class="activity-main">
526
+ <div class="activity-top">
527
+ <span class="activity-title">Adding the contact form</span>
528
+ <span class="activity-time">now</span>
529
+ </div>
530
+ <div class="activity-desc">Building a form with name, email, and message fields. It'll validate input and show a confirmation when sent.</div>
531
+ <div class="activity-tags">
532
+ <span class="tag tag-feature">Contact form</span>
533
+ <span class="tag tag-feature">Validation</span>
534
+ </div>
535
+ </div>
536
+ </div>
537
+ </div>
538
+
539
+ <!-- Step 5: Upcoming -->
540
+ <div class="activity">
541
+ <div class="activity-dot dot-plan">○</div>
542
+ <div class="activity-card" style="opacity: 0.6;">
543
+ <div class="activity-main">
544
+ <div class="activity-top">
545
+ <span class="activity-title">About page</span>
546
+ </div>
547
+ <div class="activity-desc">Your story, experience, and a professional headshot section.</div>
548
+ </div>
549
+ </div>
550
+ </div>
551
+
552
+ <!-- Step 6: Upcoming -->
553
+ <div class="activity">
554
+ <div class="activity-dot dot-plan">○</div>
555
+ <div class="activity-card" style="opacity: 0.6;">
556
+ <div class="activity-main">
557
+ <div class="activity-top">
558
+ <span class="activity-title">Final polish</span>
559
+ </div>
560
+ <div class="activity-desc">Navigation, footer, mobile tweaks, and making sure everything looks great together.</div>
561
+ </div>
562
+ </div>
563
+ </div>
564
+
565
+ </div>
566
+ </div>
567
+
568
+ <!-- Input -->
569
+ <div class="input-bar">
570
+ <div class="input-row">
571
+ <input class="input-field" placeholder="Ask Claude to change something or add a feature..." />
572
+ <button class="send-btn">↑</button>
573
+ </div>
574
+ </div>
575
+ </div>
576
+
577
+ <!-- RIGHT: FILE TREE + PREVIEW -->
578
+ <div class="output-panel">
579
+ <div class="output-tabs">
580
+ <button class="output-tab active">Files</button>
581
+ <button class="output-tab">Preview</button>
582
+ </div>
583
+ <div class="output-body">
584
+ <div class="file-tree">
585
+ <div class="tree-item">
586
+ <span class="tree-icon">📁</span> src/
587
+ </div>
588
+ <div class="tree-item tree-indent">
589
+ <span class="tree-icon">📁</span> components/
590
+ </div>
591
+ <div class="tree-item tree-indent" style="padding-left: 52px;">
592
+ <span class="tree-icon">⚛️</span> Gallery.jsx
593
+ <span class="tree-badge badge-new">new</span>
594
+ </div>
595
+ <div class="tree-item tree-indent" style="padding-left: 52px;">
596
+ <span class="tree-icon">⚛️</span> Hero.jsx
597
+ <span class="tree-badge badge-new">new</span>
598
+ </div>
599
+ <div class="tree-item tree-indent" style="padding-left: 52px;">
600
+ <span class="tree-icon">⚛️</span> Contact.jsx
601
+ <span class="tree-badge badge-modified">writing...</span>
602
+ </div>
603
+ <div class="tree-item tree-indent">
604
+ <span class="tree-icon">⚛️</span> App.jsx
605
+ <span class="tree-badge badge-new">new</span>
606
+ </div>
607
+ <div class="tree-item tree-indent">
608
+ <span class="tree-icon">🎨</span> styles.css
609
+ <span class="tree-badge badge-new">new</span>
610
+ </div>
611
+ <div class="tree-item">
612
+ <span class="tree-icon">📄</span> index.html
613
+ <span class="tree-badge badge-new">new</span>
614
+ </div>
615
+ <div class="tree-item">
616
+ <span class="tree-icon">📦</span> package.json
617
+ <span class="tree-badge badge-new">new</span>
618
+ </div>
619
+ </div>
620
+ <div class="file-preview">
621
+ <div class="file-preview-header">
622
+ <span>⚛️</span> Gallery.jsx
623
+ </div>
624
+ <code>import { useState } from 'react'
625
+
626
+ export function Gallery({ photos }) {
627
+ const [selected, setSelected] = useState(null)
628
+
629
+ return (
630
+ &lt;section className="gallery"&gt;
631
+ &lt;h2&gt;Portfolio&lt;/h2&gt;
632
+ &lt;div className="masonry-grid"&gt;
633
+ {photos.map(photo =&gt; (
634
+ &lt;img
635
+ key={photo.id}
636
+ src={photo.url}
637
+ onClick={() =&gt; setSelected(photo)}
638
+ /&gt;
639
+ ))}
640
+ &lt;/div&gt;
641
+ &lt;/section&gt;
642
+ )
643
+ }</code>
644
+ </div>
645
+ </div>
646
+ </div>
647
+ </body>
648
+ </html>