@uniqode/card-templates 1.0.0 โ 1.0.2
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/dist/card-layout-12.js +1 -1
- package/dist/card-layout-13.js +1 -0
- package/dist/index.js +1 -1
- package/dist/types/index.d.ts +12 -12
- package/package.json +1 -1
- package/README.md +0 -809
package/README.md
DELETED
|
@@ -1,809 +0,0 @@
|
|
|
1
|
-
# @uniqode/card-templates
|
|
2
|
-
|
|
3
|
-
[](https://badge.fury.io/js/@uniqode%2Fcard-templates)
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
|
|
6
|
-
> Production-grade Web Components library for digital business card templates. Framework-agnostic, data-driven, and battle-tested.
|
|
7
|
-
|
|
8
|
-
## ๐ฏ Overview
|
|
9
|
-
|
|
10
|
-
`@uniqode/card-templates` provides professionally designed digital business card layouts as framework-agnostic Web Components. Built with modern web standards, it works seamlessly with any framework (React, Angular, Vue, Django, plain JavaScript) and offers production-grade data handling with comprehensive event system.
|
|
11
|
-
|
|
12
|
-
## โจ Key Features
|
|
13
|
-
|
|
14
|
-
- **๐ Framework Agnostic** - Works with React, Angular, Vue, Django, Express, or vanilla JavaScript
|
|
15
|
-
- **๐ Data-Driven Rendering** - Pass data declaratively via properties or attributes
|
|
16
|
-
- **๐ญ Production-Grade Events** - Comprehensive event system with `preventDefault` support
|
|
17
|
-
- **๐ Shadow DOM Encapsulation** - No style conflicts with your application
|
|
18
|
-
- **โก Lightweight** - Individual components (~30KB) or full bundle
|
|
19
|
-
- **๐จ Fully Customizable** - Colors, fonts, styling, and data fields
|
|
20
|
-
- **๐ฑ Responsive Design** - Mobile-first approach with perfect scaling
|
|
21
|
-
- **๐ญ TypeScript Ready** - Full type definitions included
|
|
22
|
-
- **โฟ Accessible** - WCAG compliant components
|
|
23
|
-
- **๐ Production Ready** - Used in production by Uniqode/Beaconstac
|
|
24
|
-
|
|
25
|
-
## ๐ฆ Installation
|
|
26
|
-
|
|
27
|
-
```bash
|
|
28
|
-
# Using npm
|
|
29
|
-
npm install @uniqode/card-templates
|
|
30
|
-
|
|
31
|
-
# Using yarn
|
|
32
|
-
yarn add @uniqode/card-templates
|
|
33
|
-
|
|
34
|
-
# Using pnpm
|
|
35
|
-
pnpm add @uniqode/card-templates
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
## โ๏ธ Shadow DOM Configuration
|
|
39
|
-
|
|
40
|
-
The library uses Shadow DOM for perfect style encapsulation. Choose the mode based on your environment:
|
|
41
|
-
|
|
42
|
-
- **`closed` (default)**: Web frameworks (React, Angular, Vue) - Maximum encapsulation
|
|
43
|
-
- **`open`**: Server environments with analytics (Django, Express) - Allows tracking
|
|
44
|
-
|
|
45
|
-
### For Web Frameworks (Default - No Config Needed)
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
// Just import and use - defaults to 'closed' mode
|
|
49
|
-
import '@uniqode/card-templates';
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### For Server Environments (With Analytics)
|
|
53
|
-
|
|
54
|
-
```html
|
|
55
|
-
<head>
|
|
56
|
-
<!-- โ ๏ธ CRITICAL: Set BEFORE loading components -->
|
|
57
|
-
<script>
|
|
58
|
-
window.UniqodeCardConfig = { shadowMode: 'open' };
|
|
59
|
-
</script>
|
|
60
|
-
|
|
61
|
-
<!-- Then load components -->
|
|
62
|
-
<script type="module" src="/static/js/card-layout-12.js"></script>
|
|
63
|
-
</head>
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
๐ **[Full Shadow DOM Configuration Guide โ](./SHADOW_DOM_CONFIGURATION.md)**
|
|
67
|
-
|
|
68
|
-
---
|
|
69
|
-
|
|
70
|
-
## ๐ Quick Start
|
|
71
|
-
|
|
72
|
-
### Vanilla JavaScript / HTML
|
|
73
|
-
|
|
74
|
-
```html
|
|
75
|
-
<!DOCTYPE html>
|
|
76
|
-
<html>
|
|
77
|
-
<head>
|
|
78
|
-
<script type="module" src="https://unpkg.com/@uniqode/card-templates@latest/dist/card-layout-12.js"></script>
|
|
79
|
-
</head>
|
|
80
|
-
<body>
|
|
81
|
-
<uniqode-layout-12 id="myCard"></uniqode-layout-12>
|
|
82
|
-
|
|
83
|
-
<script>
|
|
84
|
-
// Wait for component to be defined
|
|
85
|
-
customElements.whenDefined('uniqode-layout-12').then(() => {
|
|
86
|
-
const card = document.getElementById('myCard');
|
|
87
|
-
|
|
88
|
-
// Set data via property (recommended)
|
|
89
|
-
card.cardData = {
|
|
90
|
-
first_name: 'John',
|
|
91
|
-
last_name: 'Doe',
|
|
92
|
-
designation: 'Software Engineer',
|
|
93
|
-
company: 'Tech Corp',
|
|
94
|
-
email_v2: [{ value: 'john@techcorp.com', label: 'Work' }],
|
|
95
|
-
phone_v2: [{ value: '+1 (555) 123-4567', label: 'Mobile' }],
|
|
96
|
-
user_image_url: 'https://i.pravatar.cc/300',
|
|
97
|
-
customizations: {
|
|
98
|
-
background_color: '#131A40',
|
|
99
|
-
primary_color: '#84E9F1',
|
|
100
|
-
button_color: '#6366F1'
|
|
101
|
-
}
|
|
102
|
-
};
|
|
103
|
-
|
|
104
|
-
// Listen for events
|
|
105
|
-
card.addEventListener('contact-click', (e) => {
|
|
106
|
-
console.log('Contact clicked:', e.detail);
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
card.addEventListener('share', (e) => {
|
|
110
|
-
console.log('Share clicked:', e.detail);
|
|
111
|
-
// e.preventDefault(); // Prevent default share action
|
|
112
|
-
});
|
|
113
|
-
});
|
|
114
|
-
</script>
|
|
115
|
-
</body>
|
|
116
|
-
</html>
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### React
|
|
120
|
-
|
|
121
|
-
```jsx
|
|
122
|
-
import { useEffect, useRef } from 'react';
|
|
123
|
-
import '@uniqode/card-templates';
|
|
124
|
-
|
|
125
|
-
function BusinessCard({ cardData }) {
|
|
126
|
-
const cardRef = useRef(null);
|
|
127
|
-
|
|
128
|
-
useEffect(() => {
|
|
129
|
-
const element = cardRef.current;
|
|
130
|
-
if (!element) return;
|
|
131
|
-
|
|
132
|
-
// Set data via property (declarative)
|
|
133
|
-
element.cardData = cardData;
|
|
134
|
-
|
|
135
|
-
// Attach event listeners
|
|
136
|
-
const handleContactClick = (e) => {
|
|
137
|
-
console.log('Contact clicked:', e.detail);
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const handleShare = (e) => {
|
|
141
|
-
console.log('Share clicked:', e.detail);
|
|
142
|
-
// e.preventDefault(); // Optional: override default behavior
|
|
143
|
-
};
|
|
144
|
-
|
|
145
|
-
element.addEventListener('contact-click', handleContactClick);
|
|
146
|
-
element.addEventListener('share', handleShare);
|
|
147
|
-
|
|
148
|
-
// Cleanup
|
|
149
|
-
return () => {
|
|
150
|
-
element.removeEventListener('contact-click', handleContactClick);
|
|
151
|
-
element.removeEventListener('share', handleShare);
|
|
152
|
-
};
|
|
153
|
-
}, [cardData]);
|
|
154
|
-
|
|
155
|
-
return <uniqode-layout-12 ref={cardRef} />;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// TypeScript support: Add to global.d.ts
|
|
159
|
-
declare global {
|
|
160
|
-
namespace JSX {
|
|
161
|
-
interface IntrinsicElements {
|
|
162
|
-
'uniqode-layout-12': React.HTMLAttributes<HTMLElement> & { ref?: React.Ref<any> };
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
### Angular
|
|
169
|
-
|
|
170
|
-
```typescript
|
|
171
|
-
// app.module.ts
|
|
172
|
-
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
|
|
173
|
-
import '@uniqode/card-templates';
|
|
174
|
-
|
|
175
|
-
@NgModule({
|
|
176
|
-
schemas: [CUSTOM_ELEMENTS_SCHEMA]
|
|
177
|
-
})
|
|
178
|
-
|
|
179
|
-
// component.ts
|
|
180
|
-
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
|
|
181
|
-
|
|
182
|
-
@Component({
|
|
183
|
-
selector: 'app-business-card',
|
|
184
|
-
template: '<uniqode-layout-12 #card></uniqode-layout-12>'
|
|
185
|
-
})
|
|
186
|
-
export class BusinessCardComponent implements AfterViewInit {
|
|
187
|
-
@ViewChild('card') cardElement!: ElementRef;
|
|
188
|
-
|
|
189
|
-
ngAfterViewInit() {
|
|
190
|
-
const card = this.cardElement.nativeElement;
|
|
191
|
-
|
|
192
|
-
// Set data
|
|
193
|
-
card.cardData = {
|
|
194
|
-
first_name: 'John',
|
|
195
|
-
last_name: 'Doe',
|
|
196
|
-
// ... more data
|
|
197
|
-
};
|
|
198
|
-
|
|
199
|
-
// Listen for events
|
|
200
|
-
card.addEventListener('contact-click', (e: any) => {
|
|
201
|
-
console.log('Contact clicked:', e.detail);
|
|
202
|
-
});
|
|
203
|
-
}
|
|
204
|
-
}
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### Vue 3
|
|
208
|
-
|
|
209
|
-
```vue
|
|
210
|
-
<template>
|
|
211
|
-
<uniqode-layout-12 ref="cardRef"></uniqode-layout-12>
|
|
212
|
-
</template>
|
|
213
|
-
|
|
214
|
-
<script setup>
|
|
215
|
-
import { ref, onMounted } from 'vue';
|
|
216
|
-
import '@uniqode/card-templates';
|
|
217
|
-
|
|
218
|
-
const cardRef = ref(null);
|
|
219
|
-
|
|
220
|
-
const cardData = {
|
|
221
|
-
first_name: 'John',
|
|
222
|
-
last_name: 'Doe',
|
|
223
|
-
designation: 'Software Engineer',
|
|
224
|
-
// ... more data
|
|
225
|
-
};
|
|
226
|
-
|
|
227
|
-
onMounted(() => {
|
|
228
|
-
const card = cardRef.value;
|
|
229
|
-
|
|
230
|
-
// Set data
|
|
231
|
-
card.cardData = cardData;
|
|
232
|
-
|
|
233
|
-
// Listen for events
|
|
234
|
-
card.addEventListener('contact-click', (e) => {
|
|
235
|
-
console.log('Contact clicked:', e.detail);
|
|
236
|
-
});
|
|
237
|
-
});
|
|
238
|
-
</script>
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
### Django (Server-Side)
|
|
242
|
-
|
|
243
|
-
#### Method 1: Data Island Pattern (Recommended)
|
|
244
|
-
|
|
245
|
-
```django
|
|
246
|
-
{% load static %}
|
|
247
|
-
|
|
248
|
-
<!DOCTYPE html>
|
|
249
|
-
<html>
|
|
250
|
-
<head>
|
|
251
|
-
<script type="module" src="{% static 'js/uniqode-card-templates/card-layout-12.js' %}"></script>
|
|
252
|
-
</head>
|
|
253
|
-
<body>
|
|
254
|
-
<!-- Web Component -->
|
|
255
|
-
<uniqode-layout-12 data-source="#card-data"></uniqode-layout-12>
|
|
256
|
-
|
|
257
|
-
<!-- Data Island (JSON) -->
|
|
258
|
-
{{ card_data|json_script:"card-data" }}
|
|
259
|
-
|
|
260
|
-
<script>
|
|
261
|
-
// Listen for events
|
|
262
|
-
document.querySelector('uniqode-layout-12').addEventListener('contact-click', (e) => {
|
|
263
|
-
console.log('Contact clicked:', e.detail);
|
|
264
|
-
|
|
265
|
-
// Send to backend
|
|
266
|
-
fetch('/api/track-contact-click/', {
|
|
267
|
-
method: 'POST',
|
|
268
|
-
headers: { 'Content-Type': 'application/json' },
|
|
269
|
-
body: JSON.stringify(e.detail)
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
</script>
|
|
273
|
-
</body>
|
|
274
|
-
</html>
|
|
275
|
-
```
|
|
276
|
-
|
|
277
|
-
```python
|
|
278
|
-
# views.py
|
|
279
|
-
from django.shortcuts import render
|
|
280
|
-
from django.http import JsonResponse
|
|
281
|
-
|
|
282
|
-
def card_view(request, card_id):
|
|
283
|
-
# Fetch card data from database
|
|
284
|
-
card = DigitalCard.objects.get(id=card_id)
|
|
285
|
-
|
|
286
|
-
# Transform to component format
|
|
287
|
-
card_data = {
|
|
288
|
-
'first_name': card.first_name,
|
|
289
|
-
'last_name': card.last_name,
|
|
290
|
-
'designation': card.designation,
|
|
291
|
-
'company': card.company,
|
|
292
|
-
'email_v2': [{'value': e.email, 'label': e.label} for e in card.emails.all()],
|
|
293
|
-
'phone_v2': [{'value': p.phone, 'label': p.label} for p in card.phones.all()],
|
|
294
|
-
'user_image_url': card.profile_image.url if card.profile_image else None,
|
|
295
|
-
'customizations': card.get_customizations(),
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
return render(request, 'card_template.html', {'card_data': card_data})
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
#### Method 2: Direct Property Setting
|
|
302
|
-
|
|
303
|
-
```django
|
|
304
|
-
<!DOCTYPE html>
|
|
305
|
-
<html>
|
|
306
|
-
<head>
|
|
307
|
-
<script type="module" src="{% static 'js/uniqode-card-templates/card-layout-12.js' %}"></script>
|
|
308
|
-
</head>
|
|
309
|
-
<body>
|
|
310
|
-
<uniqode-layout-12 id="card"></uniqode-layout-12>
|
|
311
|
-
|
|
312
|
-
<script>
|
|
313
|
-
window.addEventListener('DOMContentLoaded', () => {
|
|
314
|
-
customElements.whenDefined('uniqode-layout-12').then(() => {
|
|
315
|
-
const card = document.getElementById('card');
|
|
316
|
-
|
|
317
|
-
// Set data from Django template context
|
|
318
|
-
card.cardData = {{ card_data|safe }};
|
|
319
|
-
|
|
320
|
-
// Event handlers
|
|
321
|
-
card.addEventListener('contact-click', (e) => {
|
|
322
|
-
console.log('Contact clicked:', e.detail);
|
|
323
|
-
});
|
|
324
|
-
});
|
|
325
|
-
});
|
|
326
|
-
</script>
|
|
327
|
-
</body>
|
|
328
|
-
</html>
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
### Express.js / Node.js (Server-Side)
|
|
332
|
-
|
|
333
|
-
```javascript
|
|
334
|
-
// server.js
|
|
335
|
-
import express from 'express';
|
|
336
|
-
import fs from 'fs';
|
|
337
|
-
import path from 'path';
|
|
338
|
-
|
|
339
|
-
const app = express();
|
|
340
|
-
|
|
341
|
-
// Serve the Web Component bundle
|
|
342
|
-
app.use('/static', express.static('node_modules/@uniqode/card-templates/dist'));
|
|
343
|
-
|
|
344
|
-
app.get('/card/:id', async (req, res) => {
|
|
345
|
-
// Fetch card data from database
|
|
346
|
-
const cardData = await db.getCard(req.params.id);
|
|
347
|
-
|
|
348
|
-
// Render HTML with embedded data
|
|
349
|
-
res.send(`
|
|
350
|
-
<!DOCTYPE html>
|
|
351
|
-
<html>
|
|
352
|
-
<head>
|
|
353
|
-
<script type="module" src="/static/card-layout-12.js"></script>
|
|
354
|
-
</head>
|
|
355
|
-
<body>
|
|
356
|
-
<uniqode-layout-12 id="card"></uniqode-layout-12>
|
|
357
|
-
|
|
358
|
-
<script>
|
|
359
|
-
customElements.whenDefined('uniqode-layout-12').then(() => {
|
|
360
|
-
document.getElementById('card').cardData = ${JSON.stringify(cardData)};
|
|
361
|
-
});
|
|
362
|
-
</script>
|
|
363
|
-
</body>
|
|
364
|
-
</html>
|
|
365
|
-
`);
|
|
366
|
-
});
|
|
367
|
-
|
|
368
|
-
app.listen(3000);
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
## ๐ Data Structure
|
|
372
|
-
|
|
373
|
-
```javascript
|
|
374
|
-
const cardData = {
|
|
375
|
-
// Personal Information
|
|
376
|
-
first_name: 'John',
|
|
377
|
-
last_name: 'Doe',
|
|
378
|
-
prefix: 'Mr.',
|
|
379
|
-
suffix: 'Jr.',
|
|
380
|
-
pronouns_v2: 'he/him',
|
|
381
|
-
designation: 'Software Engineer',
|
|
382
|
-
company: 'Tech Corp',
|
|
383
|
-
department: 'Engineering',
|
|
384
|
-
summary: 'Passionate software engineer...',
|
|
385
|
-
|
|
386
|
-
// Contact Information (arrays for multiple entries)
|
|
387
|
-
phone_v2: [
|
|
388
|
-
{ value: '+1 (555) 123-4567', label: 'Mobile' },
|
|
389
|
-
{ value: '+1 (555) 987-6543', label: 'Work' }
|
|
390
|
-
],
|
|
391
|
-
email_v2: [
|
|
392
|
-
{ value: 'john@techcorp.com', label: 'Work' },
|
|
393
|
-
{ value: 'john.doe@gmail.com', label: 'Personal' }
|
|
394
|
-
],
|
|
395
|
-
website_v2: [
|
|
396
|
-
{ value: 'https://johndoe.dev', label: 'Portfolio' }
|
|
397
|
-
],
|
|
398
|
-
|
|
399
|
-
// Address
|
|
400
|
-
address_v2: '123 Tech Street, San Francisco, CA 94105',
|
|
401
|
-
|
|
402
|
-
// Social Media Links
|
|
403
|
-
social_links: {
|
|
404
|
-
linkedin: 'https://linkedin.com/in/johndoe',
|
|
405
|
-
twitter: 'https://twitter.com/johndoe',
|
|
406
|
-
instagram: 'https://instagram.com/johndoe',
|
|
407
|
-
facebook: 'https://facebook.com/johndoe',
|
|
408
|
-
github: 'https://github.com/johndoe',
|
|
409
|
-
youtube: 'https://youtube.com/@johndoe',
|
|
410
|
-
twitch: 'https://twitch.tv/johndoe',
|
|
411
|
-
discord: 'https://discord.gg/johndoe'
|
|
412
|
-
},
|
|
413
|
-
|
|
414
|
-
// Media
|
|
415
|
-
user_image_url: 'https://example.com/profile.jpg',
|
|
416
|
-
logo_url: 'https://example.com/logo.png',
|
|
417
|
-
|
|
418
|
-
// Customization
|
|
419
|
-
customizations: {
|
|
420
|
-
background_color: '#131A40',
|
|
421
|
-
primary_color: '#84E9F1',
|
|
422
|
-
button_color: '#6366F1',
|
|
423
|
-
icon_color: '#84E9F1',
|
|
424
|
-
font_style: 'Roboto, sans-serif'
|
|
425
|
-
},
|
|
426
|
-
|
|
427
|
-
// Ordering
|
|
428
|
-
contact_info_ordering: ['phone_v2', 'email_v2', 'website_v2', 'address_v2'],
|
|
429
|
-
social_links_ordering: ['linkedin', 'twitter', 'github']
|
|
430
|
-
};
|
|
431
|
-
```
|
|
432
|
-
|
|
433
|
-
## ๐ช Event System
|
|
434
|
-
|
|
435
|
-
All components emit custom events for user interactions with full `preventDefault` support:
|
|
436
|
-
|
|
437
|
-
```javascript
|
|
438
|
-
const card = document.querySelector('uniqode-layout-12');
|
|
439
|
-
|
|
440
|
-
// 1. Contact Click Event
|
|
441
|
-
card.addEventListener('contact-click', (event) => {
|
|
442
|
-
const { type, value, label } = event.detail;
|
|
443
|
-
console.log(`Contact clicked: ${type} - ${value}`);
|
|
444
|
-
|
|
445
|
-
// Optional: Prevent default action (e.g., opening email client)
|
|
446
|
-
event.preventDefault();
|
|
447
|
-
|
|
448
|
-
// Custom handler
|
|
449
|
-
openCustomModal(type, value);
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
// 2. Share Event
|
|
453
|
-
card.addEventListener('share', (event) => {
|
|
454
|
-
const { cardData } = event.detail;
|
|
455
|
-
console.log('Card share requested');
|
|
456
|
-
|
|
457
|
-
// Optional: Prevent default share dialog
|
|
458
|
-
event.preventDefault();
|
|
459
|
-
|
|
460
|
-
// Custom share implementation
|
|
461
|
-
openCustomShareDialog(cardData);
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
// 3. Save Contact Event (vCard download)
|
|
465
|
-
card.addEventListener('save-contact', (event) => {
|
|
466
|
-
const { cardData, vcard } = event.detail;
|
|
467
|
-
console.log('Save contact triggered');
|
|
468
|
-
|
|
469
|
-
// Optional: Prevent default vCard download
|
|
470
|
-
event.preventDefault();
|
|
471
|
-
|
|
472
|
-
// Track in analytics
|
|
473
|
-
analytics.track('contact_saved', { card_id: cardData.id });
|
|
474
|
-
});
|
|
475
|
-
|
|
476
|
-
// 4. Lead Collect Event
|
|
477
|
-
card.addEventListener('lead-collect', (event) => {
|
|
478
|
-
const { cardData } = event.detail;
|
|
479
|
-
console.log('Lead collection triggered');
|
|
480
|
-
|
|
481
|
-
// Send to backend
|
|
482
|
-
fetch('/api/collect-lead/', {
|
|
483
|
-
method: 'POST',
|
|
484
|
-
body: JSON.stringify({ card_id: cardData.id })
|
|
485
|
-
});
|
|
486
|
-
});
|
|
487
|
-
|
|
488
|
-
// 5. Social Link Click Event
|
|
489
|
-
card.addEventListener('social-click', (event) => {
|
|
490
|
-
const { platform, url } = event.detail;
|
|
491
|
-
console.log(`Social link clicked: ${platform}`);
|
|
492
|
-
|
|
493
|
-
// Track social clicks
|
|
494
|
-
analytics.track('social_click', { platform });
|
|
495
|
-
});
|
|
496
|
-
|
|
497
|
-
// 6. Card Ready Event
|
|
498
|
-
card.addEventListener('card-ready', (event) => {
|
|
499
|
-
console.log('Card rendered and ready');
|
|
500
|
-
|
|
501
|
-
// Hide loading spinner
|
|
502
|
-
document.querySelector('.loader').style.display = 'none';
|
|
503
|
-
});
|
|
504
|
-
```
|
|
505
|
-
|
|
506
|
-
### Event Details
|
|
507
|
-
|
|
508
|
-
| Event | Detail | Cancelable | Description |
|
|
509
|
-
|-------|--------|-----------|-------------|
|
|
510
|
-
| `contact-click` | `{ type, value, label }` | โ
Yes | User clicked phone/email/website |
|
|
511
|
-
| `share` | `{ cardData }` | โ
Yes | User clicked share button |
|
|
512
|
-
| `save-contact` | `{ cardData, vcard }` | โ
Yes | User clicked save to contacts |
|
|
513
|
-
| `lead-collect` | `{ cardData }` | โ
Yes | User clicked lead collection CTA |
|
|
514
|
-
| `social-click` | `{ platform, url }` | โ
Yes | User clicked social media link |
|
|
515
|
-
| `card-ready` | `{ layoutId }` | โ No | Card finished rendering |
|
|
516
|
-
|
|
517
|
-
## ๐จ Available Layouts
|
|
518
|
-
|
|
519
|
-
Currently available layout:
|
|
520
|
-
|
|
521
|
-
| Layout | Description | Best For |
|
|
522
|
-
|--------|-------------|----------|
|
|
523
|
-
| `uniqode-layout-12` | Modern gaming/tech card with dark theme | Gaming, Tech, Creative professionals |
|
|
524
|
-
|
|
525
|
-
*More layouts coming soon! The architecture supports easy addition of new layouts.*
|
|
526
|
-
|
|
527
|
-
## ๐๏ธ Customization
|
|
528
|
-
|
|
529
|
-
### Colors
|
|
530
|
-
|
|
531
|
-
```javascript
|
|
532
|
-
customizations: {
|
|
533
|
-
background_color: '#131A40', // Primary background
|
|
534
|
-
primary_color: '#84E9F1', // Accent/header color
|
|
535
|
-
button_color: '#6366F1', // Action button color
|
|
536
|
-
icon_color: '#84E9F1', // Icon color
|
|
537
|
-
font_style: 'Roboto, sans-serif' // Font family
|
|
538
|
-
}
|
|
539
|
-
```
|
|
540
|
-
|
|
541
|
-
### Typography
|
|
542
|
-
|
|
543
|
-
```javascript
|
|
544
|
-
customizations: {
|
|
545
|
-
font_style: 'Inter, system-ui, sans-serif',
|
|
546
|
-
typography: {
|
|
547
|
-
user_info: {
|
|
548
|
-
google_font_size: 24,
|
|
549
|
-
google_font_colour: '#333'
|
|
550
|
-
},
|
|
551
|
-
company_details: {
|
|
552
|
-
google_font_size: 16
|
|
553
|
-
},
|
|
554
|
-
contact_details: {
|
|
555
|
-
google_font_size: 14
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
```
|
|
560
|
-
|
|
561
|
-
## ๐๏ธ Architecture
|
|
562
|
-
|
|
563
|
-
### Component Structure
|
|
564
|
-
|
|
565
|
-
```
|
|
566
|
-
CardLayout12 (Web Component)
|
|
567
|
-
โ
|
|
568
|
-
BaseCard (Enhanced base class)
|
|
569
|
-
โโโ Data Loading (properties, attributes, data islands)
|
|
570
|
-
โโโ Event System (preventDefault support)
|
|
571
|
-
โโโ Rendering Engine
|
|
572
|
-
โโโ Utility Methods (vCard, share, etc.)
|
|
573
|
-
```
|
|
574
|
-
|
|
575
|
-
### CSS Architecture
|
|
576
|
-
|
|
577
|
-
Components use **CSS-in-JS with Shadow DOM** for true style encapsulation:
|
|
578
|
-
|
|
579
|
-
```javascript
|
|
580
|
-
// styles.js - Separate CSS module
|
|
581
|
-
export const styles = `
|
|
582
|
-
:host { display: block; }
|
|
583
|
-
.card-container { /* ... */ }
|
|
584
|
-
`;
|
|
585
|
-
|
|
586
|
-
// CardLayout12.js - Component imports styles
|
|
587
|
-
import { styles } from './styles.js';
|
|
588
|
-
|
|
589
|
-
getTemplate() {
|
|
590
|
-
return `<style>${styles}</style><div>...</div>`;
|
|
591
|
-
}
|
|
592
|
-
```
|
|
593
|
-
|
|
594
|
-
**Benefits:**
|
|
595
|
-
- โ
True encapsulation via Shadow DOM
|
|
596
|
-
- โ
No style conflicts with consumer app
|
|
597
|
-
- โ
Single bundle distribution
|
|
598
|
-
- โ
Maintainable separated CSS
|
|
599
|
-
- โ
Framework-agnostic
|
|
600
|
-
|
|
601
|
-
## ๐ง Development
|
|
602
|
-
|
|
603
|
-
### Prerequisites
|
|
604
|
-
|
|
605
|
-
- Node.js >= 16.0.0
|
|
606
|
-
- npm >= 8.0.0
|
|
607
|
-
|
|
608
|
-
### Setup
|
|
609
|
-
|
|
610
|
-
```bash
|
|
611
|
-
# Clone the repository
|
|
612
|
-
git clone https://github.com/uniqode/card-templates.git
|
|
613
|
-
cd card-templates
|
|
614
|
-
|
|
615
|
-
# Install dependencies
|
|
616
|
-
npm install
|
|
617
|
-
|
|
618
|
-
# Start development server (Storybook)
|
|
619
|
-
npm run dev
|
|
620
|
-
```
|
|
621
|
-
|
|
622
|
-
### Available Scripts
|
|
623
|
-
|
|
624
|
-
```bash
|
|
625
|
-
# Development
|
|
626
|
-
npm run dev # Start Storybook (http://localhost:6006)
|
|
627
|
-
npm start # Alias for npm run dev
|
|
628
|
-
npm run build:dev # Build in watch mode
|
|
629
|
-
|
|
630
|
-
# Building
|
|
631
|
-
npm run build:lib # Build Web Components (outputs to dist/)
|
|
632
|
-
npm run build:storybook # Build Storybook static site
|
|
633
|
-
npm run build # Build both
|
|
634
|
-
|
|
635
|
-
# Testing & Quality
|
|
636
|
-
npm run test:integration # Run integration tests
|
|
637
|
-
npm run lint # Lint source code
|
|
638
|
-
npm run lint:fix # Fix linting issues
|
|
639
|
-
|
|
640
|
-
# Utilities
|
|
641
|
-
npm run size # Check bundle sizes
|
|
642
|
-
npm run clean # Clean build artifacts
|
|
643
|
-
```
|
|
644
|
-
|
|
645
|
-
### Project Structure
|
|
646
|
-
|
|
647
|
-
```
|
|
648
|
-
uniqode-card-templates/
|
|
649
|
-
โโโ src/
|
|
650
|
-
โ โโโ components/
|
|
651
|
-
โ โ โโโ base/
|
|
652
|
-
โ โ โ โโโ BaseCard.js # Enhanced base class
|
|
653
|
-
โ โ โโโ card-layout-12/
|
|
654
|
-
โ โ โโโ CardLayout12.js # Component logic
|
|
655
|
-
โ โ โโโ styles.js # Separate CSS module
|
|
656
|
-
โ โ โโโ CardLayout12.stories.js
|
|
657
|
-
โ โโโ shared/
|
|
658
|
-
โ โ โโโ utils/ # Utility functions
|
|
659
|
-
โ โโโ types/ # TypeScript definitions
|
|
660
|
-
โ โโโ index.js # Main entry point
|
|
661
|
-
โ โโโ Introduction.stories.js # Storybook welcome
|
|
662
|
-
โโโ dist/ # Built files
|
|
663
|
-
โ โโโ card-layout-12.js # Individual bundle
|
|
664
|
-
โ โโโ index.js # Full bundle
|
|
665
|
-
โ โโโ index.d.ts # TypeScript definitions
|
|
666
|
-
โโโ test/ # Integration tests
|
|
667
|
-
โโโ .storybook/ # Storybook config
|
|
668
|
-
โโโ webpack.config.js # Webpack config
|
|
669
|
-
โโโ package.json
|
|
670
|
-
```
|
|
671
|
-
|
|
672
|
-
## ๐ Bundle Sizes
|
|
673
|
-
|
|
674
|
-
| Bundle | Size | Description |
|
|
675
|
-
|--------|------|-------------|
|
|
676
|
-
| `card-layout-12.js` | ~30KB | Individual Layout 12 component |
|
|
677
|
-
| `index.js` | ~35KB | Full bundle with all layouts |
|
|
678
|
-
|
|
679
|
-
### Tree Shaking
|
|
680
|
-
|
|
681
|
-
Import only what you need:
|
|
682
|
-
|
|
683
|
-
```javascript
|
|
684
|
-
// Import specific component (recommended)
|
|
685
|
-
import '@uniqode/card-templates/dist/card-layout-12.js';
|
|
686
|
-
|
|
687
|
-
// Import all components
|
|
688
|
-
import '@uniqode/card-templates';
|
|
689
|
-
```
|
|
690
|
-
|
|
691
|
-
## ๐ Browser Support
|
|
692
|
-
|
|
693
|
-
- Chrome >= 63
|
|
694
|
-
- Firefox >= 63
|
|
695
|
-
- Safari >= 13
|
|
696
|
-
- Edge >= 79
|
|
697
|
-
- Mobile browsers with Web Components support
|
|
698
|
-
|
|
699
|
-
For older browsers, include the Web Components polyfill:
|
|
700
|
-
|
|
701
|
-
```html
|
|
702
|
-
<script src="https://unpkg.com/@webcomponents/webcomponentsjs@2/webcomponents-bundle.js"></script>
|
|
703
|
-
```
|
|
704
|
-
|
|
705
|
-
## ๐ CDN Usage
|
|
706
|
-
|
|
707
|
-
```html
|
|
708
|
-
<!-- Full bundle -->
|
|
709
|
-
<script type="module" src="https://unpkg.com/@uniqode/card-templates@latest/dist/index.js"></script>
|
|
710
|
-
|
|
711
|
-
<!-- Individual component (recommended) -->
|
|
712
|
-
<script type="module" src="https://unpkg.com/@uniqode/card-templates@latest/dist/card-layout-12.js"></script>
|
|
713
|
-
```
|
|
714
|
-
|
|
715
|
-
## ๐ Production Deployment
|
|
716
|
-
|
|
717
|
-
### Django Static Files
|
|
718
|
-
|
|
719
|
-
```bash
|
|
720
|
-
# Copy built files to Django static directory
|
|
721
|
-
cp node_modules/@uniqode/card-templates/dist/*.js \
|
|
722
|
-
your_project/static/js/uniqode-card-templates/
|
|
723
|
-
|
|
724
|
-
# Collect static
|
|
725
|
-
python manage.py collectstatic --noinput
|
|
726
|
-
```
|
|
727
|
-
|
|
728
|
-
### CDN Integration
|
|
729
|
-
|
|
730
|
-
```python
|
|
731
|
-
# settings.py
|
|
732
|
-
UNIQODE_TEMPLATES_VERSION = "1.0.0"
|
|
733
|
-
UNIQODE_TEMPLATES_CDN = f"https://cdn.example.com/uniqode-templates/{UNIQODE_TEMPLATES_VERSION}"
|
|
734
|
-
|
|
735
|
-
# template.html
|
|
736
|
-
<script type="module" src="{{ UNIQODE_TEMPLATES_CDN }}/card-layout-12.js"></script>
|
|
737
|
-
```
|
|
738
|
-
|
|
739
|
-
### Security Considerations
|
|
740
|
-
|
|
741
|
-
```html
|
|
742
|
-
<!-- Subresource Integrity (SRI) -->
|
|
743
|
-
<script
|
|
744
|
-
type="module"
|
|
745
|
-
src="https://cdn.example.com/card-layout-12.js"
|
|
746
|
-
integrity="sha384-..."
|
|
747
|
-
crossorigin="anonymous"
|
|
748
|
-
></script>
|
|
749
|
-
```
|
|
750
|
-
|
|
751
|
-
## ๐งช Testing
|
|
752
|
-
|
|
753
|
-
```bash
|
|
754
|
-
# Run integration tests
|
|
755
|
-
npm run test:integration
|
|
756
|
-
|
|
757
|
-
# Test in Storybook
|
|
758
|
-
npm run dev
|
|
759
|
-
# Visit http://localhost:6006
|
|
760
|
-
```
|
|
761
|
-
|
|
762
|
-
## ๐ API Reference
|
|
763
|
-
|
|
764
|
-
### Properties
|
|
765
|
-
|
|
766
|
-
| Property | Type | Description |
|
|
767
|
-
|----------|------|-------------|
|
|
768
|
-
| `cardData` | `Object` | Card data (see Data Structure) |
|
|
769
|
-
| `config` | `Object` | Component configuration |
|
|
770
|
-
|
|
771
|
-
### Methods
|
|
772
|
-
|
|
773
|
-
| Method | Description |
|
|
774
|
-
|--------|-------------|
|
|
775
|
-
| `render()` | Force re-render with current data |
|
|
776
|
-
| `getAttribute(name)` | Get attribute value |
|
|
777
|
-
| `setAttribute(name, value)` | Set attribute value |
|
|
778
|
-
|
|
779
|
-
### Attributes
|
|
780
|
-
|
|
781
|
-
| Attribute | Type | Description |
|
|
782
|
-
|-----------|------|-------------|
|
|
783
|
-
| `card-data` | `String` | JSON string of card data |
|
|
784
|
-
| `data-source` | `String` | CSS selector for data island |
|
|
785
|
-
| `config` | `String` | JSON string of config |
|
|
786
|
-
|
|
787
|
-
## ๐ค Contributing
|
|
788
|
-
|
|
789
|
-
We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for details.
|
|
790
|
-
|
|
791
|
-
1. Fork the repository
|
|
792
|
-
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
|
|
793
|
-
3. Commit your changes (`git commit -m 'Add amazing feature'`)
|
|
794
|
-
4. Push to the branch (`git push origin feature/amazing-feature`)
|
|
795
|
-
5. Open a Pull Request
|
|
796
|
-
|
|
797
|
-
## ๐ License
|
|
798
|
-
|
|
799
|
-
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
|
800
|
-
|
|
801
|
-
## ๐ Acknowledgments
|
|
802
|
-
|
|
803
|
-
- Built with [Web Components](https://developer.mozilla.org/en-US/docs/Web/Web_Components)
|
|
804
|
-
- Developed with [Storybook](https://storybook.js.org/)
|
|
805
|
-
- Bundled with [Webpack](https://webpack.js.org/)
|
|
806
|
-
- Production-tested by [Uniqode](https://uniqode.com) / [Beaconstac](https://beaconstac.com)
|
|
807
|
-
|
|
808
|
-
---
|
|
809
|
-
|