vipcare 0.6.4 โ 0.7.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.
- package/lib/card.js +110 -22
- package/package.json +1 -1
package/lib/card.js
CHANGED
|
@@ -49,6 +49,25 @@ export function generateCards(profiles, outputPath) {
|
|
|
49
49
|
if (noteLines.length) lastConnection = noteLines[noteLines.length - 1];
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
+
// Extract Recent Activity section
|
|
53
|
+
const recentMatch = content.match(/## Recent Activity\n([\s\S]*?)(?=\n---|\n## [A-Z])/);
|
|
54
|
+
const recentActivity = recentMatch ? recentMatch[1].trim() : '';
|
|
55
|
+
|
|
56
|
+
// Extract Key Quotes section
|
|
57
|
+
const quotesMatch = content.match(/## Key Quotes\n([\s\S]*?)(?=\n---|\n## [A-Z])/);
|
|
58
|
+
const rawQuotes = quotesMatch ? quotesMatch[1].trim() : '';
|
|
59
|
+
|
|
60
|
+
// Extract Core Philosophy section
|
|
61
|
+
const philoMatch = content.match(/## Core Philosophy\n([\s\S]*?)(?=\n---|\n## [A-Z])/);
|
|
62
|
+
const rawPhilosophy = philoMatch ? philoMatch[1].trim() : '';
|
|
63
|
+
|
|
64
|
+
// Load raw Twitter data if available
|
|
65
|
+
const twitterRawFile = path.join(path.dirname(p.path), '.raw', p.slug, `twitter_${twitterHandle || p.slug}.md`);
|
|
66
|
+
let rawTweets = '';
|
|
67
|
+
if (fs.existsSync(twitterRawFile)) {
|
|
68
|
+
rawTweets = fs.readFileSync(twitterRawFile, 'utf-8');
|
|
69
|
+
}
|
|
70
|
+
|
|
52
71
|
const data = extractVipData(content);
|
|
53
72
|
if (!data) {
|
|
54
73
|
const nameMatch = content.match(/^# (.+)$/m);
|
|
@@ -78,6 +97,10 @@ export function generateCards(profiles, outputPath) {
|
|
|
78
97
|
updated: p.updated,
|
|
79
98
|
annotations,
|
|
80
99
|
last_connection: lastConnection,
|
|
100
|
+
recent_activity: recentActivity,
|
|
101
|
+
raw_quotes: rawQuotes,
|
|
102
|
+
raw_philosophy: rawPhilosophy,
|
|
103
|
+
raw_tweets: rawTweets,
|
|
81
104
|
});
|
|
82
105
|
continue;
|
|
83
106
|
}
|
|
@@ -87,6 +110,10 @@ export function generateCards(profiles, outputPath) {
|
|
|
87
110
|
data.twitter_handle = data.twitter_handle || twitterHandle;
|
|
88
111
|
data.annotations = annotations;
|
|
89
112
|
data.last_connection = lastConnection;
|
|
113
|
+
data.recent_activity = recentActivity;
|
|
114
|
+
data.raw_quotes = rawQuotes;
|
|
115
|
+
data.raw_philosophy = rawPhilosophy;
|
|
116
|
+
data.raw_tweets = rawTweets;
|
|
90
117
|
cards.push(data);
|
|
91
118
|
}
|
|
92
119
|
|
|
@@ -222,6 +249,16 @@ header .count { color: #94a3b8; font-size: 0.85em; }
|
|
|
222
249
|
.panel p, .panel li { color: #475569; font-size: 0.85em; line-height: 1.6; }
|
|
223
250
|
.panel ul { padding-left: 16px; }
|
|
224
251
|
.panel blockquote { border-left: 3px solid #2563eb; padding: 4px 12px; margin: 6px 0; color: #475569; font-style: italic; font-size: 0.85em; }
|
|
252
|
+
.tabs { display: flex; border-bottom: 2px solid #e2e8f0; margin: 0 -24px 16px; padding: 0 24px; }
|
|
253
|
+
.tab { padding: 8px 16px; font-size: 0.85em; font-weight: 600; color: #94a3b8; cursor: pointer; border-bottom: 2px solid transparent; margin-bottom: -2px; transition: all 0.2s; }
|
|
254
|
+
.tab:hover { color: #475569; }
|
|
255
|
+
.tab.active { color: #2563eb; border-bottom-color: #2563eb; }
|
|
256
|
+
.tab-content { display: none; }
|
|
257
|
+
.tab-content.active { display: block; }
|
|
258
|
+
.tweet { background: #f8fafc; border: 1px solid #e2e8f0; border-radius: 8px; padding: 10px 12px; margin: 8px 0; font-size: 0.8em; color: #475569; line-height: 1.5; }
|
|
259
|
+
.tweet-date { font-size: 0.7em; color: #94a3b8; margin-top: 4px; }
|
|
260
|
+
.activity-item { padding: 8px 0; border-bottom: 1px solid #f1f5f9; font-size: 0.85em; }
|
|
261
|
+
.activity-date { font-size: 0.75em; color: #94a3b8; }
|
|
225
262
|
.radar { max-width: 100%; }
|
|
226
263
|
|
|
227
264
|
/* Mobile */
|
|
@@ -346,13 +383,46 @@ function openPanel(index) {
|
|
|
346
383
|
const panel = document.getElementById('panel-content');
|
|
347
384
|
const avatarUrl = \`https://unavatar.io/twitter/\${card.twitter_handle || card.slug || 'unknown'}\`;
|
|
348
385
|
|
|
386
|
+
// Parse raw tweets into individual tweet objects
|
|
387
|
+
const tweets = [];
|
|
388
|
+
if (card.raw_tweets) {
|
|
389
|
+
const tweetBlocks = card.raw_tweets.split(/โ{5,}/);
|
|
390
|
+
for (const block of tweetBlocks) {
|
|
391
|
+
const textMatch = block.match(/:\n([\s\S]*?)(?=๐
|$)/);
|
|
392
|
+
const dateMatch = block.match(/๐
\s*(.+)/);
|
|
393
|
+
const linkMatch = block.match(/๐\s*(https?:\/\/\S+)/);
|
|
394
|
+
if (textMatch && textMatch[1].trim()) {
|
|
395
|
+
tweets.push({
|
|
396
|
+
text: textMatch[1].trim().substring(0, 280),
|
|
397
|
+
date: dateMatch ? dateMatch[1].trim() : '',
|
|
398
|
+
link: linkMatch ? linkMatch[1] : '',
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
// Parse recent activity into items
|
|
405
|
+
const activityItems = [];
|
|
406
|
+
if (card.recent_activity) {
|
|
407
|
+
const lines = card.recent_activity.split('\n').filter(l => l.trim());
|
|
408
|
+
for (const line of lines) {
|
|
409
|
+
const dateMatch = line.match(/###?\s*(\d{4}-\d{2}-\d{2}|\w+\s+\d+)/);
|
|
410
|
+
if (dateMatch) {
|
|
411
|
+
activityItems.push({ date: dateMatch[1], text: '' });
|
|
412
|
+
} else if (activityItems.length) {
|
|
413
|
+
activityItems[activityItems.length - 1].text += line.replace(/^[-โข*]\s*/, '').trim() + ' ';
|
|
414
|
+
} else {
|
|
415
|
+
activityItems.push({ date: '', text: line.replace(/^[-โข*]\s*/, '').trim() });
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
349
420
|
panel.innerHTML = \`
|
|
350
|
-
<div style="display:flex;gap:14px;align-items:center;margin-bottom:
|
|
421
|
+
<div style="display:flex;gap:14px;align-items:center;margin-bottom:12px">
|
|
351
422
|
<img src="\${avatarUrl}" alt="" style="width:56px;height:56px;border-radius:50%;object-fit:cover;border:2px solid #e2e8f0" onerror="this.style.display='none'">
|
|
352
423
|
<div>
|
|
353
424
|
<div style="font-size:1.3em;font-weight:700;color:#0f172a">\${card.name}</div>
|
|
354
425
|
<div style="font-size:0.85em;color:#64748b">\${card.title || ''}\${card.company ? ' @ ' + card.company : ''}</div>
|
|
355
|
-
\${card.previous_role ? \`<div style="font-size:0.75em;color:#94a3b8">Previously: \${card.previous_role}</div>\` : ''}
|
|
356
426
|
<div style="margin-top:4px">
|
|
357
427
|
\${card.twitter_handle ? \`<a href="https://twitter.com/\${card.twitter_handle}" target="_blank" style="color:#2563eb;font-size:0.8em;text-decoration:none;margin-right:8px">@\${card.twitter_handle}</a>\` : ''}
|
|
358
428
|
<span class="badge \${mbtiClass(card.mbti)}" title="\${card.mbti_reason || ''}">\${card.mbti || '?'}</span>
|
|
@@ -360,34 +430,45 @@ function openPanel(index) {
|
|
|
360
430
|
</div>
|
|
361
431
|
</div>
|
|
362
432
|
|
|
363
|
-
|
|
433
|
+
<div class="tabs">
|
|
434
|
+
<div class="tab active" onclick="switchTab('recent',this)">Latest</div>
|
|
435
|
+
<div class="tab" onclick="switchTab('facts',this)">Facts & Approach</div>
|
|
436
|
+
</div>
|
|
437
|
+
|
|
438
|
+
<!-- RECENT TAB -->
|
|
439
|
+
<div class="tab-content active" id="tab-recent">
|
|
440
|
+
\${card.latest_news ? \`<div class="news-chip" style="margin-bottom:12px">๐ฐ \${card.latest_news}</div>\` : ''}
|
|
441
|
+
|
|
442
|
+
\${tweets.length ? \`<h2>Latest Tweets</h2>\${tweets.slice(0,5).map(t => \`<div class="tweet">\${t.text}\${t.date ? \`<div class="tweet-date">\${t.date}\${t.link ? \` ยท <a href="\${t.link}" target="_blank" style="color:#2563eb">link</a>\` : ''}</div>\` : ''}</div>\`).join('')}\` : ''}
|
|
443
|
+
|
|
444
|
+
\${activityItems.length ? \`<h2>Recent Moves</h2>\${activityItems.slice(0,8).map(a => \`<div class="activity-item">\${a.date ? \`<span class="activity-date">\${a.date}</span> ยท \` : ''}\${a.text.trim()}</div>\`).join('')}\` : ''}
|
|
364
445
|
|
|
365
|
-
|
|
366
|
-
\${card.current_focus ? \`<p>๐ฏ \${card.current_focus}</p>\` : ''}
|
|
367
|
-
\${card.wants ? \`<p>๐ \${card.wants}</p>\` : ''}
|
|
446
|
+
\${card.key_quotes?.length ? \`<h2>In Their Words</h2>\${card.key_quotes.map(q => \`<blockquote>"\${q}"</blockquote>\`).join('')}\` : ''}
|
|
368
447
|
|
|
369
|
-
|
|
448
|
+
\${card.annotations?.length ? \`<h2>Your Notes</h2>\${card.annotations.map(a => \`<p style="font-size:0.8em;color:#64748b">๐ \${a}</p>\`).join('')}\` : ''}
|
|
449
|
+
</div>
|
|
370
450
|
|
|
371
|
-
|
|
451
|
+
<!-- FACTS TAB -->
|
|
452
|
+
<div class="tab-content" id="tab-facts">
|
|
453
|
+
<h2>Focus & Goals</h2>
|
|
454
|
+
\${card.current_focus ? \`<p>๐ฏ \${card.current_focus}</p>\` : ''}
|
|
455
|
+
\${card.wants ? \`<p>๐ \${card.wants}</p>\` : ''}
|
|
372
456
|
|
|
373
|
-
|
|
374
|
-
\${card.last_connection ? \`<p>๐ค <strong>Last:</strong> \${card.last_connection}</p>\` : '<p style="color:#94a3b8">No interactions yet</p>'}
|
|
375
|
-
\${card.dos?.length || card.donts?.length ? \`<div class="do-dont">\${card.dos?.length ? \`<div class="do-box"><strong>โ
Do</strong><br>\${card.dos.join('<br>')}</div>\` : ''}\${card.donts?.length ? \`<div class="dont-box"><strong>โ Don't</strong><br>\${card.donts.join('<br>')}</div>\` : ''}</div>\` : ''}
|
|
376
|
-
\${card.gifts?.length ? \`<p style="font-size:0.85em">๐ \${card.gifts.join(', ')}</p>\` : ''}
|
|
457
|
+
\${card.philosophy?.length ? \`<h2>Philosophy</h2>\${card.philosophy.map(p => \`<blockquote>"\${p}"</blockquote>\`).join('')}\` : ''}
|
|
377
458
|
|
|
378
|
-
|
|
379
|
-
\${card.allies?.length ? \`<div style="margin-bottom:8px">\${card.allies.map(a => \`<p style="font-size:0.85em;color:#166534">๐ <strong>\${a.name || a}</strong>\${a.reason ? \` โ \${a.reason}\` : ''}</p>\`).join('')}</div>\` : ''}
|
|
380
|
-
\${card.rivals?.length ? \`<div>\${card.rivals.map(r => \`<p style="font-size:0.85em;color:#991b1b">๐ <strong>\${r.name || r}</strong>\${r.reason ? \` โ \${r.reason}\` : ''}</p>\`).join('')}</div>\` : ''}
|
|
381
|
-
\` : ''}
|
|
459
|
+
\${card.talking_points?.length ? \`<h2>Talking Points</h2><ul>\${card.talking_points.map(t => \`<li>\${t}</li>\`).join('')}</ul>\` : ''}
|
|
382
460
|
|
|
383
|
-
|
|
461
|
+
<h2>Approach</h2>
|
|
462
|
+
\${card.last_connection ? \`<p>๐ค <strong>Last:</strong> \${card.last_connection}</p>\` : '<p style="color:#94a3b8">No interactions yet</p>'}
|
|
463
|
+
\${card.dos?.length || card.donts?.length ? \`<div class="do-dont">\${card.dos?.length ? \`<div class="do-box"><strong>โ
Do</strong><br>\${card.dos.join('<br>')}</div>\` : ''}\${card.donts?.length ? \`<div class="dont-box"><strong>โ Don't</strong><br>\${card.donts.join('<br>')}</div>\` : ''}</div>\` : ''}
|
|
464
|
+
\${card.gifts?.length ? \`<p style="font-size:0.85em">๐ \${card.gifts.join(', ')}</p>\` : ''}
|
|
384
465
|
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
466
|
+
\${card.allies?.length || card.rivals?.length ? \`<h2>Relationships</h2>
|
|
467
|
+
\${card.allies?.length ? \`<div style="margin-bottom:8px">\${card.allies.map(a => \`<p style="font-size:0.85em;color:#166534">๐ <strong>\${a.name || a}</strong>\${a.reason ? \` โ \${a.reason}\` : ''}</p>\`).join('')}</div>\` : ''}
|
|
468
|
+
\${card.rivals?.length ? \`<div>\${card.rivals.map(r => \`<p style="font-size:0.85em;color:#991b1b">๐ <strong>\${r.name || r}</strong>\${r.reason ? \` โ \${r.reason}\` : ''}</p>\`).join('')}</div>\` : ''}
|
|
469
|
+
\` : ''}
|
|
389
470
|
|
|
390
|
-
|
|
471
|
+
</div>
|
|
391
472
|
|
|
392
473
|
<div style="display:flex;gap:8px;margin-top:20px">
|
|
393
474
|
\${card.slug ? \`<a href="\${card.slug}.html" style="flex:1;text-align:center;color:#2563eb;text-decoration:none;padding:8px;border:1px solid #2563eb;border-radius:6px;font-size:0.85em">Full Profile</a>\` : ''}
|
|
@@ -399,6 +480,13 @@ function openPanel(index) {
|
|
|
399
480
|
document.getElementById('main').classList.add('panel-open');
|
|
400
481
|
}
|
|
401
482
|
|
|
483
|
+
function switchTab(tabId, el) {
|
|
484
|
+
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
|
485
|
+
document.querySelectorAll('.tab-content').forEach(t => t.classList.remove('active'));
|
|
486
|
+
el.classList.add('active');
|
|
487
|
+
document.getElementById('tab-' + tabId).classList.add('active');
|
|
488
|
+
}
|
|
489
|
+
|
|
402
490
|
function closePanel() {
|
|
403
491
|
document.getElementById('panel').classList.remove('open');
|
|
404
492
|
document.getElementById('main').classList.remove('panel-open');
|