@uniqode/card-templates 1.0.1 โ†’ 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/README.md DELETED
@@ -1,809 +0,0 @@
1
- # @uniqode/card-templates
2
-
3
- [![npm version](https://badge.fury.io/js/@uniqode%2Fcard-templates.svg)](https://badge.fury.io/js/@uniqode%2Fcard-templates)
4
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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
-