osi-cards-lib 1.5.35 → 1.5.37
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 +174 -945
- package/fesm2022/osi-cards-lib.mjs +4 -4
- package/fesm2022/osi-cards-lib.mjs.map +1 -1
- package/index.d.ts +3 -3
- package/package.json +2 -2
- package/scripts/setup-angular-styles.js +1 -0
- package/styles/_styles-scoped.scss +24 -1
- package/styles/components/sections/_section-animations.scss +1 -0
- package/styles/core/_bootstrap-reset.scss +181 -4
package/README.md
CHANGED
|
@@ -41,7 +41,7 @@ npm install osi-cards-lib
|
|
|
41
41
|
### Peer Dependencies
|
|
42
42
|
|
|
43
43
|
```bash
|
|
44
|
-
npm install @angular/common@^
|
|
44
|
+
npm install @angular/common@^17.0.0 @angular/core@^17.0.0 @angular/animations@^17.0.0 @angular/platform-browser@^17.0.0 lucide-angular@^0.292.0 rxjs@~7.8.0
|
|
45
45
|
```
|
|
46
46
|
|
|
47
47
|
### Optional Dependencies (for charts and maps)
|
|
@@ -52,7 +52,9 @@ npm install chart.js leaflet
|
|
|
52
52
|
|
|
53
53
|
---
|
|
54
54
|
|
|
55
|
-
##
|
|
55
|
+
## Integration Guide
|
|
56
|
+
|
|
57
|
+
This guide shows you exactly how to integrate OSI Cards into your Angular application, following the proven pattern used in production applications.
|
|
56
58
|
|
|
57
59
|
### Step 1: Configure Providers (Required)
|
|
58
60
|
|
|
@@ -60,70 +62,19 @@ In your `app.config.ts`:
|
|
|
60
62
|
|
|
61
63
|
```typescript
|
|
62
64
|
import { ApplicationConfig } from '@angular/core';
|
|
63
|
-
import {
|
|
65
|
+
import { provideOsiCards } from 'osi-cards-lib';
|
|
64
66
|
|
|
65
67
|
export const appConfig: ApplicationConfig = {
|
|
66
68
|
providers: [
|
|
67
|
-
|
|
69
|
+
provideOsiCards(), // Required for animations and library functionality
|
|
68
70
|
// ... your other providers
|
|
69
71
|
]
|
|
70
72
|
};
|
|
71
73
|
```
|
|
72
74
|
|
|
73
|
-
### Step 2:
|
|
74
|
-
|
|
75
|
-
**🎯 RECOMMENDED: Automatic Setup via angular.json**
|
|
76
|
-
|
|
77
|
-
The most reliable way to include library styles is to add them directly to `angular.json`. This ensures styles are always loaded correctly, regardless of SASS/SCSS import resolution issues.
|
|
78
|
-
|
|
79
|
-
### Quick Setup Script
|
|
80
|
-
|
|
81
|
-
We provide an automated setup script that configures `angular.json` for you:
|
|
82
|
-
|
|
83
|
-
```bash
|
|
84
|
-
npx osi-cards-lib setup:styles
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
Or manually run the script from the library:
|
|
88
|
-
|
|
89
|
-
```bash
|
|
90
|
-
node node_modules/osi-cards-lib/scripts/setup-angular-styles.js
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
This script will:
|
|
94
|
-
- ✅ Add library styles to your `angular.json` styles array
|
|
95
|
-
- ✅ Configure `stylePreprocessorOptions` with correct `includePaths`
|
|
96
|
-
- ✅ Set up SASS deprecation silence
|
|
97
|
-
- ✅ Work with all Angular projects in your workspace
|
|
75
|
+
### Step 2: Add Styles to angular.json
|
|
98
76
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
If you prefer to configure manually, choose one of the following options:
|
|
102
|
-
|
|
103
|
-
#### Option A: Scoped Styles (Recommended for Integration)
|
|
104
|
-
|
|
105
|
-
Use this when integrating into an existing application to prevent style conflicts. Styles are scoped to `.osi-cards-container`.
|
|
106
|
-
|
|
107
|
-
**Method 1: Import in your styles file (Recommended)**
|
|
108
|
-
|
|
109
|
-
In your `src/styles.scss` or `src/styles.sass`:
|
|
110
|
-
|
|
111
|
-
```scss
|
|
112
|
-
// Import at the TOP of your styles file (before other styles)
|
|
113
|
-
@import 'osi-cards-lib/styles/_styles-scoped';
|
|
114
|
-
|
|
115
|
-
// If that doesn't work, try with tilde prefix:
|
|
116
|
-
@import '~osi-cards-lib/styles/_styles-scoped';
|
|
117
|
-
|
|
118
|
-
// Or with explicit .scss extension:
|
|
119
|
-
@import 'osi-cards-lib/styles/_styles-scoped.scss';
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
**Important**: Place the import at the **top** of your styles file, not at the bottom, to ensure proper CSS cascade.
|
|
123
|
-
|
|
124
|
-
**Method 2: Add to angular.json (RECOMMENDED - Most Reliable)**
|
|
125
|
-
|
|
126
|
-
This is the **most reliable method**, especially for SASS files. The styles are automatically included in every build:
|
|
77
|
+
Add the library styles directly to your `angular.json` file. This is the most reliable method and ensures styles are always loaded correctly:
|
|
127
78
|
|
|
128
79
|
```json
|
|
129
80
|
{
|
|
@@ -152,746 +103,240 @@ This is the **most reliable method**, especially for SASS files. The styles are
|
|
|
152
103
|
}
|
|
153
104
|
```
|
|
154
105
|
|
|
155
|
-
**
|
|
156
|
-
-
|
|
157
|
-
-
|
|
158
|
-
-
|
|
159
|
-
|
|
160
|
-
**Important**:
|
|
161
|
-
- ⚠️ **Case sensitive**: Use `osi-cards-lib` (lowercase), NOT `osi-cards-Lib`
|
|
162
|
-
- ⚠️ **REQUIRED**: You must wrap your components in a container. **RECOMMENDED: Use `<osi-cards-container>` component** (automatically handles theme and tilt):
|
|
163
|
-
|
|
164
|
-
```html
|
|
165
|
-
<!-- ✅ RECOMMENDED: Use osi-cards-container component -->
|
|
166
|
-
<osi-cards-container [theme]="'day'">
|
|
167
|
-
<app-ai-card-renderer [cardConfig]="card"></app-ai-card-renderer>
|
|
168
|
-
</osi-cards-container>
|
|
169
|
-
|
|
170
|
-
<!-- ✅ Also works with dynamic theme -->
|
|
171
|
-
<osi-cards-container [theme]="cardTheme" *ngIf="cardConfig">
|
|
172
|
-
<app-ai-card-renderer [cardConfig]="cardConfig"></app-ai-card-renderer>
|
|
173
|
-
</osi-cards-container>
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**Why use the component?**
|
|
177
|
-
- ✅ Automatically sets `data-theme` attribute correctly
|
|
178
|
-
- ✅ Automatically adds `perspective: 1200px` for 3D tilt effects
|
|
179
|
-
- ✅ Preserves 3D transform context (`transform-style: preserve-3d`)
|
|
180
|
-
- ✅ Handles all container styling automatically
|
|
181
|
-
- ✅ More reliable than manual div setup
|
|
182
|
-
|
|
183
|
-
**Alternative (Manual Setup):**
|
|
184
|
-
If you prefer a plain div, you must manually set both the class and `data-theme` attribute:
|
|
185
|
-
|
|
186
|
-
```html
|
|
187
|
-
<!-- ⚠️ Manual setup - requires both class and data-theme -->
|
|
188
|
-
<div class="osi-cards-container" data-theme="day">
|
|
189
|
-
<app-ai-card-renderer [cardConfig]="card"></app-ai-card-renderer>
|
|
190
|
-
</div>
|
|
191
|
-
|
|
192
|
-
<!-- Dynamic theme with manual setup -->
|
|
193
|
-
<div class="osi-cards-container" [attr.data-theme]="theme" *ngIf="cardConfig">
|
|
194
|
-
<app-ai-card-renderer [cardConfig]="cardConfig"></app-ai-card-renderer>
|
|
195
|
-
</div>
|
|
196
|
-
```
|
|
197
|
-
|
|
198
|
-
**The `data-theme` attribute is REQUIRED** - without it, styles will not apply correctly. Use `"day"` for light theme or `"night"` for dark theme. The component handles this automatically.
|
|
199
|
-
|
|
200
|
-
#### Option B: Global Styles (For Standalone Apps)
|
|
201
|
-
|
|
202
|
-
Use this for standalone applications or when you want styles applied globally.
|
|
203
|
-
|
|
204
|
-
In your `src/styles.scss`:
|
|
205
|
-
|
|
206
|
-
```scss
|
|
207
|
-
// Try this first
|
|
208
|
-
@import 'osi-cards-lib/styles/_styles';
|
|
209
|
-
|
|
210
|
-
// If that doesn't work, try with tilde:
|
|
211
|
-
@import '~osi-cards-lib/styles/_styles';
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
**Note**: This applies styles to `:root`, so no container wrapper is needed, but styles may conflict with your existing application styles.
|
|
215
|
-
|
|
216
|
-
### Step 3: Use the Component
|
|
217
|
-
|
|
218
|
-
---
|
|
219
|
-
|
|
220
|
-
## Integration: Streaming vs Static
|
|
106
|
+
**Important Notes:**
|
|
107
|
+
- Place library styles **after** your main styles file in the array
|
|
108
|
+
- The `includePaths` helps Angular resolve relative imports within the library's SCSS files
|
|
109
|
+
- The `silenceDeprecations` setting suppresses SASS `@import` warnings
|
|
221
110
|
|
|
222
|
-
###
|
|
111
|
+
### Step 3: Import Components in Your Module
|
|
223
112
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
**TypeScript:**
|
|
113
|
+
In the module where you want to use the card components, import them from `osi-cards-lib`:
|
|
227
114
|
|
|
228
115
|
```typescript
|
|
229
|
-
import {
|
|
230
|
-
import {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
type: 'info',
|
|
247
|
-
fields: [
|
|
248
|
-
{ label: 'Industry', value: 'Technology' },
|
|
249
|
-
{ label: 'Employees', value: '500+' }
|
|
250
|
-
]
|
|
251
|
-
}
|
|
252
|
-
]
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
onCardAction(event: { action: string; card: AICardConfig }): void {
|
|
256
|
-
console.log('Action:', event);
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
**HTML (RECOMMENDED - using OsiCardsContainerComponent):**
|
|
262
|
-
|
|
263
|
-
```html
|
|
264
|
-
<osi-cards-container [theme]="cardTheme">
|
|
265
|
-
<app-ai-card-renderer
|
|
266
|
-
[cardConfig]="card"
|
|
267
|
-
[streamingStage]="'complete'"
|
|
268
|
-
[showLoadingByDefault]="false"
|
|
269
|
-
[tiltEnabled]="true"
|
|
270
|
-
(cardInteraction)="onCardAction($event)">
|
|
271
|
-
</app-ai-card-renderer>
|
|
272
|
-
</osi-cards-container>
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
**HTML (Alternative - manual div setup):**
|
|
276
|
-
|
|
277
|
-
```html
|
|
278
|
-
<div class="osi-cards-container" [attr.data-theme]="cardTheme">
|
|
279
|
-
<app-ai-card-renderer
|
|
280
|
-
[cardConfig]="card"
|
|
281
|
-
[streamingStage]="'complete'"
|
|
282
|
-
[showLoadingByDefault]="false"
|
|
283
|
-
[tiltEnabled]="true"
|
|
284
|
-
(cardInteraction)="onCardAction($event)">
|
|
285
|
-
</app-ai-card-renderer>
|
|
286
|
-
</div>
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
**Note**: The component approach is recommended because it automatically handles theme, perspective for tilt, and 3D transform context.
|
|
290
|
-
|
|
291
|
-
**Key Settings:**
|
|
292
|
-
- `[streamingStage]="'complete'"` → Card is fully loaded
|
|
293
|
-
- `[showLoadingByDefault]="false"` → No loading spinner
|
|
294
|
-
|
|
295
|
-
---
|
|
296
|
-
|
|
297
|
-
### Option B: With Streaming (AI/LLM Integration)
|
|
298
|
-
|
|
299
|
-
Use this when generating cards progressively from an AI service.
|
|
300
|
-
|
|
301
|
-
**TypeScript:**
|
|
302
|
-
|
|
303
|
-
```typescript
|
|
304
|
-
import { Component } from '@angular/core';
|
|
305
|
-
import { OsiCardsContainerComponent, AICardRendererComponent, AICardConfig, StreamingStage } from 'osi-cards-lib';
|
|
306
|
-
|
|
307
|
-
@Component({
|
|
308
|
-
selector: 'app-streaming-card',
|
|
309
|
-
standalone: true,
|
|
310
|
-
imports: [OsiCardsContainerComponent, AICardRendererComponent],
|
|
311
|
-
templateUrl: './streaming-card.component.html'
|
|
116
|
+
import { NgModule } from '@angular/core';
|
|
117
|
+
import { CommonModule } from '@angular/common';
|
|
118
|
+
import { AICardRendererComponent, OsiCardsContainerComponent } from 'osi-cards-lib';
|
|
119
|
+
|
|
120
|
+
@NgModule({
|
|
121
|
+
declarations: [
|
|
122
|
+
// ... your components
|
|
123
|
+
],
|
|
124
|
+
imports: [
|
|
125
|
+
CommonModule,
|
|
126
|
+
AICardRendererComponent,
|
|
127
|
+
OsiCardsContainerComponent,
|
|
128
|
+
// ... your other imports
|
|
129
|
+
],
|
|
130
|
+
exports: [
|
|
131
|
+
// ... your exports
|
|
132
|
+
]
|
|
312
133
|
})
|
|
313
|
-
export class
|
|
314
|
-
cardTheme: 'day' | 'night' = 'day';
|
|
315
|
-
|
|
316
|
-
// Streaming state
|
|
317
|
-
card: AICardConfig | undefined;
|
|
318
|
-
isStreaming = false;
|
|
319
|
-
streamingStage: StreamingStage = 'idle';
|
|
320
|
-
streamingProgress = 0;
|
|
321
|
-
|
|
322
|
-
// Custom loading messages (optional)
|
|
323
|
-
loadingMessages = [
|
|
324
|
-
'Analyzing data...',
|
|
325
|
-
'Processing request...',
|
|
326
|
-
'Generating insights...'
|
|
327
|
-
];
|
|
328
|
-
|
|
329
|
-
async generateCard(): Promise<void> {
|
|
330
|
-
// Start streaming
|
|
331
|
-
this.card = undefined;
|
|
332
|
-
this.isStreaming = true;
|
|
333
|
-
this.streamingStage = 'thinking';
|
|
334
|
-
this.streamingProgress = 0;
|
|
335
|
-
|
|
336
|
-
// Simulate AI thinking phase
|
|
337
|
-
await this.delay(2000);
|
|
338
|
-
|
|
339
|
-
// Start streaming content
|
|
340
|
-
this.streamingStage = 'streaming';
|
|
341
|
-
this.streamingProgress = 0.2;
|
|
342
|
-
|
|
343
|
-
// Progressive card building (simulate chunks from AI)
|
|
344
|
-
this.card = { cardTitle: 'Analysis Results', sections: [] };
|
|
345
|
-
|
|
346
|
-
await this.delay(800);
|
|
347
|
-
this.streamingProgress = 0.5;
|
|
348
|
-
this.card.sections.push({
|
|
349
|
-
title: 'Summary',
|
|
350
|
-
type: 'info',
|
|
351
|
-
fields: [{ label: 'Status', value: 'Processing...' }]
|
|
352
|
-
});
|
|
353
|
-
|
|
354
|
-
await this.delay(800);
|
|
355
|
-
this.streamingProgress = 0.8;
|
|
356
|
-
this.card.sections.push({
|
|
357
|
-
title: 'Metrics',
|
|
358
|
-
type: 'analytics',
|
|
359
|
-
fields: [{ label: 'Score', value: '92%', trend: 'up' }]
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
await this.delay(500);
|
|
363
|
-
|
|
364
|
-
// Complete
|
|
365
|
-
this.streamingProgress = 1;
|
|
366
|
-
this.streamingStage = 'complete';
|
|
367
|
-
this.isStreaming = false;
|
|
368
|
-
|
|
369
|
-
// Final card state
|
|
370
|
-
this.card.sections[0].fields = [{ label: 'Status', value: 'Complete' }];
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
private delay(ms: number): Promise<void> {
|
|
374
|
-
return new Promise(resolve => setTimeout(resolve, ms));
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
onCardAction(event: { action: string; card: AICardConfig }): void {
|
|
378
|
-
console.log('Action:', event);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
134
|
+
export class YourModule { }
|
|
381
135
|
```
|
|
382
136
|
|
|
383
|
-
|
|
137
|
+
### Step 4: Use the Components in Your Template
|
|
384
138
|
|
|
385
|
-
|
|
386
|
-
<button (click)="generateCard()" [disabled]="isStreaming">
|
|
387
|
-
{{ isStreaming ? 'Generating...' : 'Generate Card' }}
|
|
388
|
-
</button>
|
|
389
|
-
|
|
390
|
-
<osi-cards-container [theme]="cardTheme">
|
|
391
|
-
<app-ai-card-renderer
|
|
392
|
-
[cardConfig]="card"
|
|
393
|
-
[isStreaming]="isStreaming"
|
|
394
|
-
[streamingStage]="streamingStage"
|
|
395
|
-
[streamingProgress]="streamingProgress"
|
|
396
|
-
[showLoadingByDefault]="true"
|
|
397
|
-
[loadingMessages]="loadingMessages"
|
|
398
|
-
[loadingTitle]="'AI Analysis'"
|
|
399
|
-
[tiltEnabled]="true"
|
|
400
|
-
(cardInteraction)="onCardAction($event)">
|
|
401
|
-
</app-ai-card-renderer>
|
|
402
|
-
</osi-cards-container>
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
**HTML (Alternative - manual div setup):**
|
|
139
|
+
Use the `<osi-cards-container>` component to wrap `<app-ai-card-renderer>`. The container component automatically handles theme and tilt effects:
|
|
406
140
|
|
|
407
141
|
```html
|
|
408
|
-
<
|
|
409
|
-
{{ isStreaming ? 'Generating...' : 'Generate Card' }}
|
|
410
|
-
</button>
|
|
411
|
-
|
|
412
|
-
<div class="osi-cards-container" [attr.data-theme]="cardTheme">
|
|
413
|
-
<app-ai-card-renderer
|
|
414
|
-
[cardConfig]="card"
|
|
415
|
-
[isStreaming]="isStreaming"
|
|
416
|
-
[streamingStage]="streamingStage"
|
|
417
|
-
[streamingProgress]="streamingProgress"
|
|
418
|
-
[showLoadingByDefault]="true"
|
|
419
|
-
[loadingMessages]="loadingMessages"
|
|
420
|
-
[loadingTitle]="'AI Analysis'"
|
|
421
|
-
[tiltEnabled]="true"
|
|
422
|
-
(cardInteraction)="onCardAction($event)">
|
|
423
|
-
</app-ai-card-renderer>
|
|
424
|
-
</div>
|
|
425
|
-
```
|
|
426
|
-
|
|
427
|
-
**Key Settings:**
|
|
428
|
-
- `[isStreaming]="isStreaming"` → Controls streaming animation
|
|
429
|
-
- `[streamingStage]="streamingStage"` → `'idle'` | `'thinking'` | `'streaming'` | `'complete'`
|
|
430
|
-
- `[streamingProgress]="streamingProgress"` → Progress bar (0-1)
|
|
431
|
-
- `[showLoadingByDefault]="true"` → Shows loading when no card data
|
|
432
|
-
- `[loadingMessages]` → Custom messages during loading
|
|
433
|
-
|
|
434
|
-
---
|
|
435
|
-
|
|
436
|
-
### Comparison Table
|
|
437
|
-
|
|
438
|
-
| Feature | Static Card | Streaming Card |
|
|
439
|
-
|---------|-------------|----------------|
|
|
440
|
-
| `[cardConfig]` | Always provided | Starts `undefined`, built progressively |
|
|
441
|
-
| `[streamingStage]` | `'complete'` | `'idle'` → `'thinking'` → `'streaming'` → `'complete'` |
|
|
442
|
-
| `[showLoadingByDefault]` | `false` | `true` |
|
|
443
|
-
| `[isStreaming]` | Not needed | `true` during generation |
|
|
444
|
-
| `[streamingProgress]` | Not needed | `0` to `1` |
|
|
445
|
-
| Loading animation | None | Shows animated loading state |
|
|
446
|
-
| Use case | Pre-loaded data | AI/LLM generation |
|
|
447
|
-
|
|
448
|
-
---
|
|
449
|
-
|
|
450
|
-
## Using Container + Renderer Pattern (Recommended for Lists)
|
|
451
|
-
|
|
452
|
-
When displaying cards in lists or needing more control, use `osi-cards-container` with `app-ai-card-renderer`:
|
|
453
|
-
|
|
454
|
-
### TypeScript
|
|
455
|
-
|
|
456
|
-
```typescript
|
|
457
|
-
import { Component } from '@angular/core';
|
|
458
|
-
import {
|
|
459
|
-
OsiCardsContainerComponent,
|
|
460
|
-
AICardRendererComponent,
|
|
461
|
-
AICardConfig
|
|
462
|
-
} from 'osi-cards-lib';
|
|
463
|
-
|
|
464
|
-
@Component({
|
|
465
|
-
selector: 'app-card-list',
|
|
466
|
-
standalone: true,
|
|
467
|
-
imports: [OsiCardsContainerComponent, AICardRendererComponent],
|
|
468
|
-
templateUrl: './card-list.component.html'
|
|
469
|
-
})
|
|
470
|
-
export class CardListComponent {
|
|
471
|
-
cardTheme: 'day' | 'night' = 'day';
|
|
472
|
-
cardContainerWidth = 600; // Optional: explicit width
|
|
473
|
-
|
|
474
|
-
cards: { id: string; card: AICardConfig }[] = [
|
|
475
|
-
{
|
|
476
|
-
id: '1',
|
|
477
|
-
card: {
|
|
478
|
-
cardTitle: 'Card 1',
|
|
479
|
-
sections: [{ title: 'Info', type: 'info', fields: [{ label: 'Status', value: 'Active' }] }]
|
|
480
|
-
}
|
|
481
|
-
},
|
|
482
|
-
{
|
|
483
|
-
id: '2',
|
|
484
|
-
card: {
|
|
485
|
-
cardTitle: 'Card 2',
|
|
486
|
-
sections: [{ title: 'Info', type: 'info', fields: [{ label: 'Status', value: 'Pending' }] }]
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
];
|
|
490
|
-
|
|
491
|
-
onCardActionClick(event: { action: string; card: AICardConfig }): void {
|
|
492
|
-
console.log('Action clicked:', event);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
```
|
|
496
|
-
|
|
497
|
-
### HTML
|
|
498
|
-
|
|
499
|
-
```html
|
|
500
|
-
<!-- Loop through cards -->
|
|
501
|
-
@for (item of cards; track item.id) {
|
|
142
|
+
<div class="col-12 p-0 mb-3" *ngIf="companyCard">
|
|
502
143
|
<osi-cards-container [theme]="cardTheme">
|
|
503
144
|
<app-ai-card-renderer
|
|
504
|
-
[cardConfig]="
|
|
505
|
-
[containerWidth]="cardContainerWidth"
|
|
145
|
+
[cardConfig]="companyCard"
|
|
506
146
|
[streamingStage]="'complete'"
|
|
507
147
|
[showLoadingByDefault]="false"
|
|
508
|
-
|
|
148
|
+
[tiltEnabled]="true">
|
|
509
149
|
</app-ai-card-renderer>
|
|
510
150
|
</osi-cards-container>
|
|
511
|
-
|
|
151
|
+
</div>
|
|
512
152
|
```
|
|
513
153
|
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
-
|
|
517
|
-
-
|
|
518
|
-
-
|
|
519
|
-
-
|
|
520
|
-
- **Complete stage** - `[streamingStage]="'complete'"` marks card as fully loaded
|
|
521
|
-
|
|
522
|
-
---
|
|
523
|
-
|
|
524
|
-
## Using AICardRendererComponent (Lower-Level API)
|
|
154
|
+
**Why use `<osi-cards-container>`?**
|
|
155
|
+
- ✅ Automatically sets `data-theme` attribute correctly
|
|
156
|
+
- ✅ Automatically adds `perspective: 1200px` for 3D tilt effects
|
|
157
|
+
- ✅ Preserves 3D transform context (`transform-style: preserve-3d`)
|
|
158
|
+
- ✅ Handles all container styling automatically
|
|
159
|
+
- ✅ More reliable than manual div setup
|
|
525
160
|
|
|
526
|
-
|
|
161
|
+
### Step 5: Define Your Card Configuration
|
|
527
162
|
|
|
528
|
-
|
|
163
|
+
In your component TypeScript file, define the card configuration:
|
|
529
164
|
|
|
530
165
|
```typescript
|
|
531
166
|
import { Component } from '@angular/core';
|
|
532
|
-
import {
|
|
167
|
+
import { AICardConfig } from 'osi-cards-lib';
|
|
533
168
|
|
|
534
169
|
@Component({
|
|
535
|
-
selector: 'app-
|
|
536
|
-
|
|
537
|
-
imports: [AICardRendererComponent],
|
|
538
|
-
templateUrl: './card-demo.component.html'
|
|
170
|
+
selector: 'app-your-component',
|
|
171
|
+
templateUrl: './your-component.html'
|
|
539
172
|
})
|
|
540
|
-
export class
|
|
541
|
-
|
|
542
|
-
|
|
173
|
+
export class YourComponent {
|
|
174
|
+
cardTheme: 'day' | 'night' = 'night'; // or 'day' for light theme
|
|
175
|
+
|
|
176
|
+
companyCard: AICardConfig = {
|
|
177
|
+
cardTitle: 'Company Profile',
|
|
178
|
+
description: 'Complete company information and insights',
|
|
543
179
|
sections: [
|
|
544
180
|
{
|
|
545
181
|
title: 'Overview',
|
|
546
|
-
type: '
|
|
182
|
+
type: 'info',
|
|
547
183
|
fields: [
|
|
548
|
-
{ label: '
|
|
549
|
-
{ label: '
|
|
184
|
+
{ label: 'Industry', value: 'Technology' },
|
|
185
|
+
{ label: 'Employees', value: '500+' },
|
|
186
|
+
{ label: 'Founded', value: '2010' }
|
|
187
|
+
]
|
|
188
|
+
},
|
|
189
|
+
{
|
|
190
|
+
title: 'Key Metrics',
|
|
191
|
+
type: 'analytics',
|
|
192
|
+
fields: [
|
|
193
|
+
{ label: 'Revenue', value: '$150M', trend: 'up', change: 25 },
|
|
194
|
+
{ label: 'Market Share', value: '18%', trend: 'up', change: 3 }
|
|
550
195
|
]
|
|
551
196
|
}
|
|
197
|
+
],
|
|
198
|
+
actions: [
|
|
199
|
+
{
|
|
200
|
+
type: 'website',
|
|
201
|
+
label: 'Visit Website',
|
|
202
|
+
variant: 'primary',
|
|
203
|
+
url: 'https://example.com'
|
|
204
|
+
}
|
|
552
205
|
]
|
|
553
206
|
};
|
|
554
|
-
|
|
555
|
-
onFieldClick(event: CardFieldInteractionEvent): void {
|
|
556
|
-
console.log('Field clicked:', event);
|
|
557
|
-
}
|
|
558
|
-
|
|
559
|
-
onAgentAction(event: any): void {
|
|
560
|
-
console.log('Agent action triggered:', event);
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
```
|
|
564
|
-
|
|
565
|
-
### HTML
|
|
566
|
-
|
|
567
|
-
```html
|
|
568
|
-
<app-ai-card-renderer
|
|
569
|
-
[cardConfig]="card"
|
|
570
|
-
[tiltEnabled]="true"
|
|
571
|
-
(fieldInteraction)="onFieldClick($event)"
|
|
572
|
-
(agentAction)="onAgentAction($event)">
|
|
573
|
-
</app-ai-card-renderer>
|
|
574
|
-
```
|
|
575
|
-
|
|
576
|
-
---
|
|
577
|
-
|
|
578
|
-
## Usage With Streaming
|
|
579
|
-
|
|
580
|
-
For AI/LLM streaming scenarios:
|
|
581
|
-
|
|
582
|
-
### TypeScript
|
|
583
|
-
|
|
584
|
-
```typescript
|
|
585
|
-
import { Component } from '@angular/core';
|
|
586
|
-
import { OsiCardsComponent, AICardConfig, StreamingStage } from 'osi-cards-lib';
|
|
587
|
-
|
|
588
|
-
@Component({
|
|
589
|
-
selector: 'app-streaming-demo',
|
|
590
|
-
standalone: true,
|
|
591
|
-
imports: [OsiCardsComponent],
|
|
592
|
-
templateUrl: './streaming-demo.component.html'
|
|
593
|
-
})
|
|
594
|
-
export class StreamingDemoComponent {
|
|
595
|
-
card: AICardConfig | undefined;
|
|
596
|
-
isStreaming = false;
|
|
597
|
-
streamingStage: StreamingStage = 'idle';
|
|
598
|
-
streamingProgress = 0;
|
|
599
|
-
|
|
600
|
-
// Custom loading messages (optional)
|
|
601
|
-
loadingMessages = [
|
|
602
|
-
'Analyzing data...',
|
|
603
|
-
'Processing results...',
|
|
604
|
-
'Almost there...'
|
|
605
|
-
];
|
|
606
|
-
|
|
607
|
-
startStreaming(): void {
|
|
608
|
-
this.isStreaming = true;
|
|
609
|
-
this.streamingStage = 'thinking';
|
|
610
|
-
|
|
611
|
-
// Simulate streaming - in real app, this comes from your AI service
|
|
612
|
-
setTimeout(() => {
|
|
613
|
-
this.streamingStage = 'streaming';
|
|
614
|
-
this.simulateCardStreaming();
|
|
615
|
-
}, 2000);
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
private simulateCardStreaming(): void {
|
|
619
|
-
// Progressively build card
|
|
620
|
-
this.streamingProgress = 0.3;
|
|
621
|
-
this.card = {
|
|
622
|
-
cardTitle: 'Generating...',
|
|
623
|
-
sections: []
|
|
624
|
-
};
|
|
625
|
-
|
|
626
|
-
setTimeout(() => {
|
|
627
|
-
this.streamingProgress = 0.7;
|
|
628
|
-
this.card = {
|
|
629
|
-
cardTitle: 'Analysis Results',
|
|
630
|
-
sections: [
|
|
631
|
-
{ title: 'Summary', type: 'info', fields: [{ label: 'Status', value: 'Processing' }] }
|
|
632
|
-
]
|
|
633
|
-
};
|
|
634
|
-
}, 1000);
|
|
635
|
-
|
|
636
|
-
setTimeout(() => {
|
|
637
|
-
this.streamingProgress = 1;
|
|
638
|
-
this.streamingStage = 'complete';
|
|
639
|
-
this.isStreaming = false;
|
|
640
|
-
this.card = {
|
|
641
|
-
cardTitle: 'Analysis Results',
|
|
642
|
-
sections: [
|
|
643
|
-
{ title: 'Summary', type: 'info', fields: [{ label: 'Status', value: 'Complete' }] },
|
|
644
|
-
{ title: 'Metrics', type: 'analytics', fields: [{ label: 'Score', value: '95%' }] }
|
|
645
|
-
]
|
|
646
|
-
};
|
|
647
|
-
}, 2000);
|
|
648
|
-
}
|
|
649
207
|
}
|
|
650
208
|
```
|
|
651
209
|
|
|
652
|
-
### HTML
|
|
653
|
-
|
|
654
|
-
```html
|
|
655
|
-
<button (click)="startStreaming()">Start Analysis</button>
|
|
656
|
-
|
|
657
|
-
<osi-cards
|
|
658
|
-
[card]="card"
|
|
659
|
-
[isStreaming]="isStreaming"
|
|
660
|
-
[streamingStage]="streamingStage"
|
|
661
|
-
[streamingProgress]="streamingProgress"
|
|
662
|
-
[loadingMessages]="loadingMessages"
|
|
663
|
-
[loadingTitle]="'Analyzing...'"
|
|
664
|
-
[showLoadingByDefault]="true">
|
|
665
|
-
</osi-cards>
|
|
666
|
-
```
|
|
667
|
-
|
|
668
210
|
---
|
|
669
211
|
|
|
670
|
-
##
|
|
671
|
-
|
|
672
|
-
**Theme is NOT mandatory.** Cards default to `'day'` (light theme).
|
|
673
|
-
|
|
674
|
-
### Per-Component Theme
|
|
675
|
-
|
|
676
|
-
```html
|
|
677
|
-
<!-- Light theme (default) -->
|
|
678
|
-
<osi-cards [card]="card"></osi-cards>
|
|
679
|
-
|
|
680
|
-
<!-- Explicit light theme -->
|
|
681
|
-
<osi-cards [card]="card" [theme]="'day'"></osi-cards>
|
|
212
|
+
## Complete Example
|
|
682
213
|
|
|
683
|
-
|
|
684
|
-
<osi-cards [card]="card" [theme]="'night'"></osi-cards>
|
|
685
|
-
```
|
|
214
|
+
Here's a complete working example based on a production integration:
|
|
686
215
|
|
|
687
|
-
###
|
|
216
|
+
### `app.config.ts`
|
|
688
217
|
|
|
689
218
|
```typescript
|
|
690
|
-
import { ApplicationConfig } from '@angular/core';
|
|
691
|
-
import {
|
|
219
|
+
import { ApplicationConfig, importProvidersFrom } from '@angular/core';
|
|
220
|
+
import { provideRouter } from '@angular/router';
|
|
221
|
+
import { provideHttpClient } from "@angular/common/http";
|
|
222
|
+
import { provideAnimations } from '@angular/platform-browser/animations';
|
|
223
|
+
import { routes } from './app.routes';
|
|
224
|
+
import { provideOsiCards } from 'osi-cards-lib';
|
|
692
225
|
|
|
693
226
|
export const appConfig: ApplicationConfig = {
|
|
694
227
|
providers: [
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
228
|
+
provideRouter(routes),
|
|
229
|
+
provideHttpClient(),
|
|
230
|
+
provideAnimations(),
|
|
231
|
+
provideOsiCards() // Required for animations and library functionality
|
|
698
232
|
]
|
|
699
233
|
};
|
|
700
234
|
```
|
|
701
235
|
|
|
702
|
-
###
|
|
703
|
-
|
|
704
|
-
```typescript
|
|
705
|
-
import { Component, inject } from '@angular/core';
|
|
706
|
-
import { ThemeService } from 'osi-cards-lib';
|
|
707
|
-
|
|
708
|
-
@Component({...})
|
|
709
|
-
export class MyComponent {
|
|
710
|
-
private themeService = inject(ThemeService);
|
|
236
|
+
### `angular.json` (excerpt)
|
|
711
237
|
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"projects": {
|
|
241
|
+
"your-app": {
|
|
242
|
+
"architect": {
|
|
243
|
+
"build": {
|
|
244
|
+
"options": {
|
|
245
|
+
"styles": [
|
|
246
|
+
"src/styles.sass",
|
|
247
|
+
"node_modules/osi-cards-lib/styles/_styles-scoped.scss"
|
|
248
|
+
],
|
|
249
|
+
"stylePreprocessorOptions": {
|
|
250
|
+
"includePaths": [
|
|
251
|
+
"node_modules/osi-cards-lib/styles"
|
|
252
|
+
],
|
|
253
|
+
"sass": {
|
|
254
|
+
"silenceDeprecations": ["import"]
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
722
261
|
}
|
|
723
262
|
}
|
|
724
263
|
```
|
|
725
264
|
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
## Complete Example
|
|
729
|
-
|
|
730
|
-
### `app.config.ts`
|
|
265
|
+
### `your-module.ts`
|
|
731
266
|
|
|
732
267
|
```typescript
|
|
733
|
-
import {
|
|
734
|
-
import {
|
|
735
|
-
import {
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
268
|
+
import { NgModule } from '@angular/core';
|
|
269
|
+
import { CommonModule } from '@angular/common';
|
|
270
|
+
import { AICardRendererComponent, OsiCardsContainerComponent } from 'osi-cards-lib';
|
|
271
|
+
|
|
272
|
+
@NgModule({
|
|
273
|
+
imports: [
|
|
274
|
+
CommonModule,
|
|
275
|
+
AICardRendererComponent,
|
|
276
|
+
OsiCardsContainerComponent
|
|
741
277
|
]
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
### `styles.scss`
|
|
746
|
-
|
|
747
|
-
```scss
|
|
748
|
-
@import 'osi-cards-lib/styles/_styles';
|
|
749
|
-
|
|
750
|
-
// Optional: Override theme variables
|
|
751
|
-
:root {
|
|
752
|
-
--osi-card-accent: #6366f1;
|
|
753
|
-
}
|
|
278
|
+
})
|
|
279
|
+
export class YourModule { }
|
|
754
280
|
```
|
|
755
281
|
|
|
756
|
-
### `
|
|
282
|
+
### `your-component.ts`
|
|
757
283
|
|
|
758
284
|
```typescript
|
|
759
285
|
import { Component } from '@angular/core';
|
|
760
|
-
import {
|
|
286
|
+
import { AICardConfig } from 'osi-cards-lib';
|
|
761
287
|
|
|
762
288
|
@Component({
|
|
763
|
-
selector: 'app-
|
|
764
|
-
|
|
765
|
-
imports: [OsiCardsComponent],
|
|
766
|
-
template: `
|
|
767
|
-
<div class="page-container">
|
|
768
|
-
<h1>Company Profile</h1>
|
|
769
|
-
|
|
770
|
-
<osi-cards
|
|
771
|
-
[card]="companyCard"
|
|
772
|
-
[tiltEnabled]="true"
|
|
773
|
-
(fieldClick)="handleFieldClick($event)"
|
|
774
|
-
(actionClick)="handleAction($event)">
|
|
775
|
-
</osi-cards>
|
|
776
|
-
</div>
|
|
777
|
-
`,
|
|
778
|
-
styles: [`
|
|
779
|
-
.page-container {
|
|
780
|
-
max-width: 900px;
|
|
781
|
-
margin: 0 auto;
|
|
782
|
-
padding: 2rem;
|
|
783
|
-
}
|
|
784
|
-
`]
|
|
289
|
+
selector: 'app-your-component',
|
|
290
|
+
templateUrl: './your-component.html'
|
|
785
291
|
})
|
|
786
|
-
export class
|
|
292
|
+
export class YourComponent {
|
|
293
|
+
cardTheme: 'day' | 'night' = 'night';
|
|
294
|
+
|
|
787
295
|
companyCard: AICardConfig = {
|
|
788
|
-
cardTitle: '
|
|
789
|
-
|
|
296
|
+
cardTitle: 'Company Profile',
|
|
297
|
+
description: 'Complete company information',
|
|
790
298
|
sections: [
|
|
791
299
|
{
|
|
792
|
-
title: '
|
|
793
|
-
type: '
|
|
794
|
-
fields: [
|
|
795
|
-
{ label: 'Industry', value: 'Enterprise Software' },
|
|
796
|
-
{ label: 'Founded', value: '2010' },
|
|
797
|
-
{ label: 'Headquarters', value: 'San Francisco, CA' },
|
|
798
|
-
{ label: 'Employees', value: '2,500+' }
|
|
799
|
-
]
|
|
800
|
-
},
|
|
801
|
-
{
|
|
802
|
-
title: 'Key Metrics',
|
|
803
|
-
type: 'analytics',
|
|
804
|
-
fields: [
|
|
805
|
-
{ label: 'Annual Revenue', value: '$150M', trend: 'up', change: 25 },
|
|
806
|
-
{ label: 'Market Share', value: '18%', trend: 'up', change: 3 },
|
|
807
|
-
{ label: 'Customer Growth', value: '+340', trend: 'up' },
|
|
808
|
-
{ label: 'NPS Score', value: '72', trend: 'stable' }
|
|
809
|
-
]
|
|
810
|
-
},
|
|
811
|
-
{
|
|
812
|
-
title: 'Leadership Team',
|
|
813
|
-
type: 'contact-card',
|
|
300
|
+
title: 'Overview',
|
|
301
|
+
type: 'info',
|
|
814
302
|
fields: [
|
|
815
|
-
{
|
|
816
|
-
{
|
|
817
|
-
]
|
|
818
|
-
},
|
|
819
|
-
{
|
|
820
|
-
title: 'Products & Services',
|
|
821
|
-
type: 'list',
|
|
822
|
-
items: [
|
|
823
|
-
{ title: 'Enterprise Platform', description: 'Core business solution' },
|
|
824
|
-
{ title: 'Analytics Suite', description: 'Data insights and reporting' },
|
|
825
|
-
{ title: 'Integration Hub', description: 'Connect your tools' }
|
|
303
|
+
{ label: 'Industry', value: 'Technology' },
|
|
304
|
+
{ label: 'Employees', value: '500+' }
|
|
826
305
|
]
|
|
827
306
|
}
|
|
828
|
-
],
|
|
829
|
-
actions: [
|
|
830
|
-
{ type: 'website', label: 'Visit Website', variant: 'primary', url: 'https://acme.com' },
|
|
831
|
-
{ type: 'mail', label: 'Contact Sales', variant: 'outline', email: { contact: { email: 'sales@acme.com' }, subject: 'Inquiry' } },
|
|
832
|
-
{ type: 'agent', label: 'Ask AI Assistant', variant: 'ghost', agentId: 'sales-bot' }
|
|
833
307
|
]
|
|
834
308
|
};
|
|
309
|
+
}
|
|
310
|
+
```
|
|
835
311
|
|
|
836
|
-
|
|
837
|
-
console.log('Field clicked:', event);
|
|
838
|
-
// Handle field interactions
|
|
839
|
-
}
|
|
312
|
+
### `your-component.html`
|
|
840
313
|
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
314
|
+
```html
|
|
315
|
+
<div class="col-12 p-0 mb-3" *ngIf="companyCard">
|
|
316
|
+
<osi-cards-container [theme]="cardTheme">
|
|
317
|
+
<app-ai-card-renderer
|
|
318
|
+
[cardConfig]="companyCard"
|
|
319
|
+
[streamingStage]="'complete'"
|
|
320
|
+
[showLoadingByDefault]="false"
|
|
321
|
+
[tiltEnabled]="true">
|
|
322
|
+
</app-ai-card-renderer>
|
|
323
|
+
</osi-cards-container>
|
|
324
|
+
</div>
|
|
846
325
|
```
|
|
847
326
|
|
|
848
327
|
---
|
|
849
328
|
|
|
850
329
|
## Component API Reference
|
|
851
330
|
|
|
852
|
-
### OsiCardsComponent (`<osi-cards>`)
|
|
853
|
-
|
|
854
|
-
High-level wrapper component with simplified API.
|
|
855
|
-
|
|
856
|
-
**Inputs:**
|
|
857
|
-
|
|
858
|
-
| Input | Type | Default | Required | Description |
|
|
859
|
-
|-------|------|---------|----------|-------------|
|
|
860
|
-
| `card` | `AICardConfig` | `undefined` | No | The card configuration to render |
|
|
861
|
-
| `theme` | `'day' \| 'night'` | `'day'` | No | Theme to apply |
|
|
862
|
-
| `fullscreen` | `boolean` | `false` | No | Display in fullscreen mode |
|
|
863
|
-
| `tiltEnabled` | `boolean` | `true` | No | Enable 3D tilt effect on hover |
|
|
864
|
-
| `containerWidth` | `number` | auto | No | Explicit container width for layout |
|
|
865
|
-
| `isStreaming` | `boolean` | `false` | No | Whether streaming is active |
|
|
866
|
-
| `streamingStage` | `StreamingStage` | `undefined` | No | Current streaming stage |
|
|
867
|
-
| `streamingProgress` | `number` | `0` | No | Streaming progress (0-1) |
|
|
868
|
-
| `showLoadingByDefault` | `boolean` | `true` | No | Show loading state when no card |
|
|
869
|
-
| `loadingMessages` | `string[]` | defaults | No | Custom loading messages |
|
|
870
|
-
| `loadingTitle` | `string` | `'Creating OSI Card'` | No | Loading state title |
|
|
871
|
-
|
|
872
|
-
**Outputs:**
|
|
873
|
-
|
|
874
|
-
| Output | Type | Description |
|
|
875
|
-
|--------|------|-------------|
|
|
876
|
-
| `fieldClick` | `CardFieldInteractionEvent` | Emitted when a field is clicked |
|
|
877
|
-
| `actionClick` | `{ action: string; card: AICardConfig }` | Emitted when an action button is clicked |
|
|
878
|
-
| `fullscreenChange` | `boolean` | Emitted when fullscreen is toggled |
|
|
879
|
-
| `agentAction` | `{ action, card, agentId?, context? }` | Emitted for agent-type actions |
|
|
880
|
-
| `questionAction` | `{ action, card, question? }` | Emitted for question-type actions |
|
|
881
|
-
| `export` | `void` | Emitted when export is requested |
|
|
882
|
-
|
|
883
|
-
---
|
|
884
|
-
|
|
885
331
|
### OsiCardsContainerComponent (`<osi-cards-container>`)
|
|
886
332
|
|
|
887
|
-
Container wrapper for theme and CSS isolation.
|
|
333
|
+
Container wrapper for theme and CSS isolation. **Always use this component** to wrap your card renderer.
|
|
888
334
|
|
|
889
335
|
**Inputs:**
|
|
890
336
|
|
|
891
337
|
| Input | Type | Default | Required | Description |
|
|
892
338
|
|-------|------|---------|----------|-------------|
|
|
893
339
|
| `theme` | `'day' \| 'night'` | `'day'` | No | Theme to apply to container |
|
|
894
|
-
| `strictIsolation` | `boolean` | `false` | No | Enable strict CSS containment |
|
|
895
340
|
|
|
896
341
|
**Usage:**
|
|
897
342
|
|
|
@@ -901,8 +346,6 @@ Container wrapper for theme and CSS isolation.
|
|
|
901
346
|
</osi-cards-container>
|
|
902
347
|
```
|
|
903
348
|
|
|
904
|
-
---
|
|
905
|
-
|
|
906
349
|
### AICardRendererComponent (`<app-ai-card-renderer>`)
|
|
907
350
|
|
|
908
351
|
Core rendering component with full control.
|
|
@@ -912,36 +355,27 @@ Core rendering component with full control.
|
|
|
912
355
|
| Input | Type | Default | Required | Description |
|
|
913
356
|
|-------|------|---------|----------|-------------|
|
|
914
357
|
| `cardConfig` | `AICardConfig` | `undefined` | No | The card configuration |
|
|
915
|
-
| `isFullscreen` | `boolean` | `false` | No | Fullscreen mode |
|
|
916
|
-
| `tiltEnabled` | `boolean` | `true` | No | Enable 3D tilt effect |
|
|
917
358
|
| `streamingStage` | `StreamingStage` | `undefined` | No | `'idle'` \| `'thinking'` \| `'streaming'` \| `'complete'` |
|
|
918
|
-
| `
|
|
919
|
-
| `
|
|
920
|
-
| `showLoadingByDefault` | `boolean` | `true` | No | Show loading when no data |
|
|
921
|
-
| `containerWidth` | `number` | auto | No | Explicit width for masonry |
|
|
922
|
-
| `loadingMessages` | `string[]` | defaults | No | Custom loading messages |
|
|
923
|
-
| `loadingTitle` | `string` | `'Creating OSI Card'` | No | Loading title |
|
|
924
|
-
| `updateSource` | `'stream' \| 'liveEdit'` | `'stream'` | No | Update source mode |
|
|
359
|
+
| `showLoadingByDefault` | `boolean` | `true` | No | Show loading when no card data |
|
|
360
|
+
| `tiltEnabled` | `boolean` | `true` | No | Enable 3D tilt effect on hover |
|
|
925
361
|
|
|
926
362
|
**Outputs:**
|
|
927
363
|
|
|
928
364
|
| Output | Type | Description |
|
|
929
365
|
|--------|------|-------------|
|
|
930
|
-
| `fieldInteraction` | `CardFieldInteractionEvent` | Field clicked |
|
|
931
366
|
| `cardInteraction` | `{ action: string; card: AICardConfig }` | Action button clicked |
|
|
932
|
-
| `
|
|
933
|
-
| `agentAction` | `{ action, card, agentId?, context? }` | Agent action |
|
|
934
|
-
| `questionAction` | `{ action, card, question? }` | Question action |
|
|
935
|
-
| `export` | `void` | Export requested |
|
|
367
|
+
| `fieldInteraction` | `CardFieldInteractionEvent` | Field clicked |
|
|
936
368
|
|
|
937
369
|
**Minimal Usage (Static Card, No Loading):**
|
|
938
370
|
|
|
939
371
|
```html
|
|
940
|
-
<
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
372
|
+
<osi-cards-container [theme]="cardTheme">
|
|
373
|
+
<app-ai-card-renderer
|
|
374
|
+
[cardConfig]="card"
|
|
375
|
+
[streamingStage]="'complete'"
|
|
376
|
+
[showLoadingByDefault]="false">
|
|
377
|
+
</app-ai-card-renderer>
|
|
378
|
+
</osi-cards-container>
|
|
945
379
|
```
|
|
946
380
|
|
|
947
381
|
---
|
|
@@ -970,255 +404,50 @@ Core rendering component with full control.
|
|
|
970
404
|
|
|
971
405
|
---
|
|
972
406
|
|
|
973
|
-
## Card Presets
|
|
974
|
-
|
|
975
|
-
Quickly create common card types:
|
|
976
|
-
|
|
977
|
-
```typescript
|
|
978
|
-
import { PresetFactory } from 'osi-cards-lib';
|
|
979
|
-
|
|
980
|
-
// Company card
|
|
981
|
-
const companyCard = PresetFactory.createCompany({
|
|
982
|
-
name: 'Acme Corp',
|
|
983
|
-
industry: 'Technology',
|
|
984
|
-
employees: '500+',
|
|
985
|
-
websiteUrl: 'https://acme.com'
|
|
986
|
-
});
|
|
987
|
-
|
|
988
|
-
// Analytics dashboard
|
|
989
|
-
const analyticsCard = PresetFactory.createAnalytics({
|
|
990
|
-
title: 'Sales Performance',
|
|
991
|
-
kpis: [
|
|
992
|
-
{ label: 'Revenue', value: '$1.2M', percentage: 105, trend: 'up' }
|
|
993
|
-
]
|
|
994
|
-
});
|
|
995
|
-
|
|
996
|
-
// Contact card
|
|
997
|
-
const contactCard = PresetFactory.createContact({
|
|
998
|
-
name: 'John Doe',
|
|
999
|
-
email: 'john@example.com'
|
|
1000
|
-
});
|
|
1001
|
-
```
|
|
1002
|
-
|
|
1003
|
-
---
|
|
1004
|
-
|
|
1005
407
|
## Troubleshooting
|
|
1006
408
|
|
|
1007
409
|
### Animations not working
|
|
1008
410
|
|
|
1009
|
-
Ensure you've added `
|
|
411
|
+
Ensure you've added `provideOsiCards()` to your `app.config.ts`:
|
|
1010
412
|
|
|
1011
413
|
```typescript
|
|
1012
414
|
providers: [
|
|
1013
|
-
|
|
415
|
+
provideOsiCards() // Required!
|
|
1014
416
|
]
|
|
1015
417
|
```
|
|
1016
418
|
|
|
1017
419
|
### Styles not loading / Library looks unstyled
|
|
1018
420
|
|
|
1019
|
-
**
|
|
1020
|
-
|
|
1021
|
-
**
|
|
1022
|
-
|
|
1023
|
-
**Solution 1: Add to angular.json (RECOMMENDED for SASS files)**
|
|
1024
|
-
|
|
1025
|
-
This is the most reliable method:
|
|
1026
|
-
|
|
1027
|
-
```json
|
|
1028
|
-
{
|
|
1029
|
-
"projects": {
|
|
1030
|
-
"your-app": {
|
|
1031
|
-
"architect": {
|
|
1032
|
-
"build": {
|
|
1033
|
-
"options": {
|
|
1034
|
-
"styles": [
|
|
1035
|
-
"src/styles.sass",
|
|
1036
|
-
"node_modules/osi-cards-lib/styles/_styles-scoped.scss"
|
|
1037
|
-
],
|
|
1038
|
-
"stylePreprocessorOptions": {
|
|
1039
|
-
"includePaths": [
|
|
1040
|
-
"node_modules/osi-cards-lib/styles"
|
|
1041
|
-
],
|
|
1042
|
-
"sass": {
|
|
1043
|
-
"silenceDeprecations": ["import"]
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
```
|
|
1053
|
-
|
|
1054
|
-
Then **remove** the `@import` from your `styles.sass` file.
|
|
1055
|
-
|
|
1056
|
-
**Solution 2: Fix the SASS import**
|
|
1057
|
-
|
|
1058
|
-
If you want to keep the import in your styles file:
|
|
1059
|
-
|
|
1060
|
-
1. **Use tilde prefix**:
|
|
1061
|
-
```sass
|
|
1062
|
-
@import '~osi-cards-lib/styles/_styles-scoped';
|
|
1063
|
-
```
|
|
1064
|
-
|
|
1065
|
-
2. **Or use full path**:
|
|
1066
|
-
```sass
|
|
1067
|
-
@import 'node_modules/osi-cards-lib/styles/_styles-scoped';
|
|
1068
|
-
```
|
|
1069
|
-
|
|
1070
|
-
3. **And add to angular.json**:
|
|
1071
|
-
```json
|
|
1072
|
-
"stylePreprocessorOptions": {
|
|
1073
|
-
"includePaths": ["node_modules"],
|
|
1074
|
-
"sass": {
|
|
1075
|
-
"silenceDeprecations": ["import"]
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
```
|
|
1079
|
-
|
|
1080
|
-
**Solution 3: Verify import path** - Use lowercase `osi-cards-lib` (not `osi-cards-Lib`):
|
|
1081
|
-
```scss
|
|
1082
|
-
@import 'osi-cards-lib/styles/_styles-scoped';
|
|
1083
|
-
```
|
|
1084
|
-
|
|
1085
|
-
2. **Try alternative import methods** if the above doesn't work:
|
|
1086
|
-
|
|
1087
|
-
**Option A: With tilde prefix** (for older Angular versions):
|
|
1088
|
-
```scss
|
|
1089
|
-
@import '~osi-cards-lib/styles/_styles-scoped';
|
|
1090
|
-
```
|
|
1091
|
-
|
|
1092
|
-
**Option B: With explicit extension**:
|
|
1093
|
-
```scss
|
|
1094
|
-
@import 'osi-cards-lib/styles/_styles-scoped.scss';
|
|
1095
|
-
```
|
|
1096
|
-
|
|
1097
|
-
**Option C: Add to angular.json** (if SCSS import fails):
|
|
1098
|
-
```json
|
|
1099
|
-
{
|
|
1100
|
-
"projects": {
|
|
1101
|
-
"your-app": {
|
|
1102
|
-
"architect": {
|
|
1103
|
-
"build": {
|
|
1104
|
-
"options": {
|
|
1105
|
-
"styles": [
|
|
1106
|
-
"node_modules/osi-cards-lib/styles/_styles-scoped.scss",
|
|
1107
|
-
"src/styles.scss"
|
|
1108
|
-
],
|
|
1109
|
-
"stylePreprocessorOptions": {
|
|
1110
|
-
"includePaths": [
|
|
1111
|
-
"node_modules/osi-cards-lib/styles"
|
|
1112
|
-
],
|
|
1113
|
-
"sass": {
|
|
1114
|
-
"silenceDeprecations": ["import"]
|
|
1115
|
-
}
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
}
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
```
|
|
1124
|
-
Then remove the `@import` from your `styles.scss`.
|
|
1125
|
-
|
|
1126
|
-
3. **Wrap components in container** - You MUST wrap your components. **RECOMMENDED: Use `<osi-cards-container>` component** (automatically handles theme and tilt):
|
|
1127
|
-
```html
|
|
1128
|
-
<!-- ✅ RECOMMENDED: Component automatically handles theme and tilt -->
|
|
1129
|
-
<osi-cards-container [theme]="'day'">
|
|
1130
|
-
<app-ai-card-renderer [cardConfig]="card"></app-ai-card-renderer>
|
|
1131
|
-
</osi-cards-container>
|
|
1132
|
-
```
|
|
1133
|
-
|
|
1134
|
-
**Alternative (Manual Setup):**
|
|
1135
|
-
```html
|
|
1136
|
-
<!-- ⚠️ Manual setup - requires both class and data-theme -->
|
|
1137
|
-
<div class="osi-cards-container" data-theme="day">
|
|
1138
|
-
<app-ai-card-renderer [cardConfig]="card"></app-ai-card-renderer>
|
|
1139
|
-
</div>
|
|
1140
|
-
```
|
|
1141
|
-
|
|
1142
|
-
4. **Set theme attribute** - The component handles this automatically via `[theme]` input. For manual setup, add `data-theme="day"` or `data-theme="night"`:
|
|
1143
|
-
```html
|
|
1144
|
-
<div class="osi-cards-container" data-theme="day">
|
|
1145
|
-
```
|
|
1146
|
-
|
|
1147
|
-
5. **Verify package installation**:
|
|
1148
|
-
```bash
|
|
1149
|
-
npm list osi-cards-lib
|
|
1150
|
-
```
|
|
1151
|
-
Should show version `1.5.19` or higher.
|
|
1152
|
-
|
|
1153
|
-
6. **Check browser console** - Look for 404 errors on style files. If you see errors, the import path is incorrect.
|
|
1154
|
-
|
|
1155
|
-
7. **Rebuild your app** after adding the import:
|
|
421
|
+
1. **Verify styles are in angular.json** - Check that `node_modules/osi-cards-lib/styles/_styles-scoped.scss` is in your `styles` array
|
|
422
|
+
2. **Check stylePreprocessorOptions** - Ensure `includePaths` includes `node_modules/osi-cards-lib/styles`
|
|
423
|
+
3. **Use the container component** - Always wrap your card in `<osi-cards-container [theme]="'day'">` or `<osi-cards-container [theme]="'night'">`
|
|
424
|
+
4. **Rebuild your app** after adding the import:
|
|
1156
425
|
```bash
|
|
1157
426
|
ng build
|
|
1158
427
|
# or
|
|
1159
428
|
npm start
|
|
1160
429
|
```
|
|
1161
430
|
|
|
1162
|
-
**If using global styles (`_styles`):**
|
|
1163
|
-
|
|
1164
|
-
Import styles in your `styles.scss`:
|
|
1165
|
-
```scss
|
|
1166
|
-
@import 'osi-cards-lib/styles/_styles';
|
|
1167
|
-
```
|
|
1168
|
-
|
|
1169
|
-
**Common Issues:**
|
|
1170
|
-
- ❌ **Wrong import path**: `@import 'osi-cards-Lib/styles/_styles-scoped'` (wrong casing)
|
|
1171
|
-
- ❌ **Missing container**: Components not wrapped in `.osi-cards-container` or `<osi-cards-container>` component
|
|
1172
|
-
- ❌ **Missing theme**: No `data-theme` attribute on container (use `<osi-cards-container [theme]="'day'">` to fix automatically)
|
|
1173
|
-
- ❌ **Tilt not working**: Missing `perspective` on container (use `<osi-cards-container>` component which adds it automatically)
|
|
1174
|
-
- ❌ **SCSS not compiled**: Check that your build process compiles SCSS files
|
|
1175
|
-
|
|
1176
431
|
### Icons not showing
|
|
1177
432
|
|
|
1178
433
|
Ensure `lucide-angular` is installed:
|
|
1179
434
|
|
|
1180
435
|
```bash
|
|
1181
|
-
npm install lucide-angular@^0.
|
|
436
|
+
npm install lucide-angular@^0.292.0
|
|
1182
437
|
```
|
|
1183
438
|
|
|
1184
|
-
###
|
|
439
|
+
### Theme not applying
|
|
1185
440
|
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
2. **Check theme**: Verify `data-theme` attribute is set correctly
|
|
1190
|
-
3. **Override variables**: You can override variables in your own styles:
|
|
1191
|
-
```scss
|
|
1192
|
-
.osi-cards-container {
|
|
1193
|
-
--color-brand: #ff7900;
|
|
1194
|
-
--background: #ffffff;
|
|
1195
|
-
}
|
|
1196
|
-
```
|
|
441
|
+
- Ensure you're using `<osi-cards-container [theme]="'day'">` or `<osi-cards-container [theme]="'night'">`
|
|
442
|
+
- The `[theme]` input automatically sets the `data-theme` attribute
|
|
443
|
+
- Check browser console for any errors
|
|
1197
444
|
|
|
1198
445
|
---
|
|
1199
446
|
|
|
1200
|
-
## Documentation
|
|
1201
|
-
|
|
1202
|
-
- [Detailed Usage Guide](./USAGE.md)
|
|
1203
|
-
- [Import Examples](./IMPORT_EXAMPLE.md)
|
|
1204
|
-
|
|
1205
447
|
## License
|
|
1206
448
|
|
|
1207
449
|
MIT
|
|
1208
450
|
|
|
1209
451
|
## Version
|
|
1210
452
|
|
|
1211
|
-
1.5.
|
|
1212
|
-
|
|
1213
|
-
---
|
|
1214
|
-
|
|
1215
|
-
## Zero-Gap Packing (Advanced)
|
|
1216
|
-
|
|
1217
|
-
If you need maximum layout density (minimal gaps), you can use the zero-gap packing helper:
|
|
1218
|
-
|
|
1219
|
-
```typescript
|
|
1220
|
-
import { packWithZeroGapsGuarantee } from 'osi-cards-lib';
|
|
1221
|
-
|
|
1222
|
-
const result = packWithZeroGapsGuarantee(sections, 4, 12);
|
|
1223
|
-
// result.positionedSections, result.totalHeight, result.utilization, result.gapCount
|
|
1224
|
-
```
|
|
453
|
+
1.5.37
|