feat: profiles and /set profile, and id cards

* New functionality to set meta data on businesscards.
* Can develop a user profile.
* Business cards link to user profile.
This commit is contained in:
Evan Carroll 2026-01-25 10:50:10 -06:00
parent cd8dfb94a3
commit 710985638f
35 changed files with 4932 additions and 435 deletions

View file

@ -284,6 +284,12 @@
font-size: 0.75rem;
color: #aaa;
text-transform: capitalize;
text-decoration: none;
}
.prop-name:hover {
color: #4ECDC4;
text-decoration: underline;
}
/* Selected prop display */
@ -420,6 +426,11 @@
<div class="prop-items" id="tea-props" role="group" aria-label="Tea props"></div>
</div>
<div class="prop-category">
<h3>Identification</h3>
<div class="prop-items" id="id-props" role="group" aria-label="Identification props"></div>
</div>
<div class="prop-category">
<h3>Misc</h3>
<div class="prop-items" id="misc-props" role="group" aria-label="Miscellaneous props"></div>
@ -557,7 +568,8 @@
coffee: ['espresso', 'latte', 'iced', 'frenchpress', 'pourover', 'turkish', 'cup-empty'],
soda: ['cola', 'lemonlime', 'orange', 'grape', 'rootbeer'],
tea: ['iced', 'pot', 'cup', 'cup-empty', 'bag'],
misc: ['iou', 'signed-dollar', 'thankyou', 'yousuck', 'businesscard'],
misc: ['iou', 'signed-dollar', 'thankyou', 'yousuck'],
id: ['businesscard', 'businesscard-box', 'card', 'dogtags'],
goodpol: ['cccp', 'china', 'palestine'],
screen: ['projector-screen', 'projector-screen-with-stand', 'projector-remote-control'],
keyboard: ['standard']
@ -583,9 +595,12 @@
preview.className = 'prop-preview';
preview.innerHTML = svgText;
const label = document.createElement('span');
const label = document.createElement('a');
label.className = 'prop-name';
label.href = filename;
label.target = '_blank';
label.textContent = name.replace(/([A-Z])/g, ' $1').trim();
label.addEventListener('click', (e) => e.stopPropagation());
card.appendChild(preview);
card.appendChild(label);
@ -620,9 +635,12 @@
preview.className = 'prop-preview';
preview.innerHTML = svgText;
const label = document.createElement('span');
const label = document.createElement('a');
label.className = 'prop-name';
label.href = filename;
label.target = '_blank';
label.textContent = name.replace(/([A-Z])/g, ' $1').trim();
label.addEventListener('click', (e) => e.stopPropagation());
card.appendChild(preview);
card.appendChild(label);
@ -648,6 +666,7 @@
const coffeeContainer = document.getElementById('coffee-props');
const sodaContainer = document.getElementById('soda-props');
const teaContainer = document.getElementById('tea-props');
const idContainer = document.getElementById('id-props');
const miscContainer = document.getElementById('misc-props');
const goodpolContainer = document.getElementById('goodpol-props');
const screenContainer = document.getElementById('screen-props');
@ -665,6 +684,9 @@
for (const name of props.tea) {
await loadPropPreview('tea', name, teaContainer);
}
for (const name of props.id) {
await loadPropPreview('id', name, idContainer);
}
for (const name of props.misc) {
await loadPropPreview('misc', name, miscContainer);
}

View file

@ -1,30 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 120" width="120" height="120">
<g transform="scale(2.5)">
<defs>
<linearGradient id="cardface" x1="0%" y1="0%" x2="100%" y2="100%">
<stop offset="0%" stop-color="#FFFFFF"/>
<stop offset="100%" stop-color="#F0F0F0"/>
</linearGradient>
<filter id="cardshadow" x="-10%" y="-10%" width="120%" height="120%">
<feDropShadow dx="1" dy="2" stdDeviation="1.5" flood-color="#000000" flood-opacity="0.3"/>
</filter>
</defs>
<!-- Business card with slight tilt -->
<g transform="rotate(-3, 24, 24)">
<!-- Card background - standard 3.5:2 ratio scaled -->
<rect x="5" y="12" width="38" height="22" rx="1.5" fill="url(#cardface)" filter="url(#cardshadow)" stroke="#DDD" stroke-width="0.3"/>
<!-- Face silhouette -->
<circle cx="10" cy="16.5" r="2" fill="#555"/>
<ellipse cx="10" cy="21" rx="3" ry="2" fill="#555"/>
<!-- Name text -->
<text x="16" y="18" font-family="Georgia, serif" font-size="4" font-weight="bold" fill="#1a1a2e">John Doe</text>
<!-- Title text -->
<text x="16" y="22" font-family="Arial, sans-serif" font-size="2.5" fill="#555">Software Engineer</text>
<!-- Contact line -->
<line x1="16" y1="25" x2="40" y2="25" stroke="#E0E0E0" stroke-width="0.3"/>
<!-- Email/phone placeholder -->
<text x="16" y="28" font-family="Arial, sans-serif" font-size="2" fill="#777">john@example.com</text>
<text x="16" y="31" font-family="Arial, sans-serif" font-size="2" fill="#777">+1 555-123-4567</text>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB