@repobit/dex-system-design 0.23.48 → 0.23.50

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/CHANGELOG.md CHANGED
@@ -3,6 +3,21 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.23.50](https://github.com/bitdefender/dex-core/compare/@repobit/dex-system-design@0.23.49...@repobit/dex-system-design@0.23.50) (2026-06-17)
7
+
8
+ ### Bug Fixes
9
+
10
+ * **DEX-1014:** new card features and card upgrades
11
+
12
+
13
+ ## [0.23.49](https://github.com/bitdefender/dex-core/compare/@repobit/dex-system-design@0.23.48...@repobit/dex-system-design@0.23.49) (2026-06-16)
14
+
15
+ **Note:** Version bump only for package @repobit/dex-system-design
16
+
17
+
18
+
19
+
20
+
6
21
  ## [0.23.48](https://github.com/bitdefender/dex-core/compare/@repobit/dex-system-design@0.23.47...@repobit/dex-system-design@0.23.48) (2026-06-12)
7
22
 
8
23
  **Note:** Version bump only for package @repobit/dex-system-design
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@repobit/dex-system-design",
3
- "version": "0.23.48",
3
+ "version": "0.23.50",
4
4
  "description": "Design system based on Web Components.",
5
5
  "author": "Iordache Matei Cezar <miordache@bitdefender.com>",
6
6
  "homepage": "https://github.com/bitdefender/dex-core#readme",
@@ -70,8 +70,8 @@
70
70
  "url": "https://github.com/bitdefender/dex-core/issues"
71
71
  },
72
72
  "dependencies": {
73
- "@repobit/dex-store": "1.3.44",
74
- "@repobit/dex-store-elements": "1.4.36",
73
+ "@repobit/dex-store": "1.3.46",
74
+ "@repobit/dex-store-elements": "1.4.38",
75
75
  "lit": "^3.3.2"
76
76
  },
77
77
  "devDependencies": {
@@ -88,5 +88,5 @@
88
88
  "volta": {
89
89
  "node": "24.14.0"
90
90
  },
91
- "gitHead": "7a5b68c532b9f3174a306bcf826672da421b1d2c"
91
+ "gitHead": "81584423e16ae1ca612de9c236fa98707297bc04"
92
92
  }
@@ -0,0 +1,108 @@
1
+ import { css } from "lit";
2
+
3
+ export default css`
4
+ :host {
5
+ display: block;
6
+ --background-card-grey: var(--color-neutral-25);
7
+ --border-card-grey: var(--color-neutral-50);
8
+ padding-top: var(--spacing-32);
9
+ padding-bottom: var(--spacing-32);
10
+ }
11
+
12
+ .bd-card-features-s {
13
+ display: flex;
14
+ align-items: center;
15
+ justify-content: center;
16
+ position: relative;
17
+ width: 100%;
18
+ overflow: hidden;
19
+ flex-direction: column;
20
+ padding-left: var(--spacing-14);
21
+ padding-right: var(--spacing-14);
22
+ max-width: 1400px;
23
+ margin: 0 auto;
24
+ }
25
+
26
+ .bd-card-features-header-s {
27
+ margin-bottom: var(--spacing-48);
28
+ margin-top: var(--spacing-32);
29
+ text-align: center;
30
+ }
31
+
32
+ .bd-card-features-title-s {
33
+ font-family: var(--typography-fontFamily-sans);
34
+ font-weight: var(--typography-fontWeight-semibold);
35
+ font-size: var(--typography-fontSize-2xl);
36
+ }
37
+
38
+ .bd-card-features-track-s {
39
+ width: 100%;
40
+ display: grid;
41
+ gap: var(--spacing-24);
42
+ grid-template-columns: repeat(3, 1fr);
43
+ }
44
+
45
+ .bd-card-features-box-s {
46
+ display: flex;
47
+ flex-direction: row;
48
+ align-items: flex-start;
49
+ gap: var(--spacing-16);
50
+ background: var(--background-card-grey);
51
+ border-radius: var(--spacing-20);
52
+ padding: var(--spacing-24);
53
+ font-family: var(--typography-fontFamily-sans);
54
+ box-sizing: border-box;
55
+ height: 100%;
56
+ }
57
+
58
+ .bd-card-features-icon-s {
59
+ flex-shrink: 0;
60
+ width: var(--spacing-32);
61
+ height: var(--spacing-32);
62
+ object-fit: contain;
63
+ }
64
+
65
+ .bd-card-features-content-s {
66
+ display: flex;
67
+ flex-direction: column;
68
+ }
69
+
70
+ .bd-card-features-title-badge-wrapper-s {
71
+ display: flex;
72
+ align-items: center;
73
+ gap: var(--spacing-8);
74
+ margin-bottom: var(--spacing-8);
75
+ }
76
+
77
+ .bd-card-features-item-title-s {
78
+ font-size: var(--typography-fontSize-md);
79
+ font-weight: var(--typography-fontWeight-semibold);
80
+ margin: 0;
81
+ }
82
+
83
+ ::slotted(p) {
84
+ font-size: var(--typography-fontSize-sm);
85
+ color: var(--color-neutral-700);
86
+ line-height: var(--typography-lineHeight-normal);
87
+ margin: 0;
88
+ font-family: var(--typography-fontFamily-sans);
89
+ }
90
+
91
+ @media (max-width: 1024px) {
92
+ .bd-card-features-track-s {
93
+ grid-template-columns: repeat(2, 1fr);
94
+ }
95
+ }
96
+
97
+ @media (max-width: 600px) {
98
+ .bd-card-features-track-s {
99
+ grid-template-columns: 1fr;
100
+ }
101
+
102
+ .bd-card-features-box-s {
103
+ flex-direction: column;
104
+ align-items: flex-start;
105
+ height: auto;
106
+ }
107
+ }
108
+ `;
@@ -0,0 +1,145 @@
1
+ import { LitElement, html } from "lit";
2
+ import { tokens } from "../../tokens/tokens.js";
3
+ import "../badge/badge.js";
4
+ import "../heading/heading.js";
5
+ import cardFeaturesCSS from "./card-features.css.js";
6
+
7
+ class CardFeatures extends LitElement {
8
+ static properties = {
9
+ title: { type: String }
10
+ };
11
+
12
+ constructor() {
13
+ super();
14
+ this.title = "";
15
+ this._resizeObserver = null;
16
+ }
17
+
18
+ connectedCallback() {
19
+ super.connectedCallback();
20
+ this._resizeObserver = new ResizeObserver(() => this._equalizeHeights());
21
+ this._resizeObserver.observe(this);
22
+ }
23
+
24
+ disconnectedCallback() {
25
+ super.disconnectedCallback();
26
+ this._resizeObserver?.disconnect();
27
+ }
28
+
29
+ firstUpdated() {
30
+ this._equalizeHeights();
31
+ }
32
+
33
+ async _equalizeHeights() {
34
+ const items = [...this.querySelectorAll("bd-card-features-item")];
35
+ if (!items.length) return;
36
+
37
+ // Asteptam ca toate item-urile sa fie randate
38
+ await Promise.all(items.map((item) => item.updateComplete));
39
+
40
+ const boxes = items
41
+ .map((item) => item.shadowRoot?.querySelector(".bd-card-features-box-s"))
42
+ .filter(Boolean);
43
+
44
+ if (!boxes.length) return;
45
+
46
+ // Resetam inaltimea inainte de a masura, altfel maxHeight ramane "blocat"
47
+ boxes.forEach((box) => {
48
+ box.style.height = "auto";
49
+ });
50
+
51
+ requestAnimationFrame(() => {
52
+ const maxHeight = boxes.reduce(
53
+ (max, box) => Math.max(max, box.getBoundingClientRect().height),
54
+ 0
55
+ );
56
+
57
+ boxes.forEach((box) => {
58
+ box.style.height = `${maxHeight}px`;
59
+ });
60
+ });
61
+ }
62
+
63
+ render() {
64
+ return html`
65
+ <section class="bd-card-features-s">
66
+ ${this.title
67
+ ? html`
68
+ <div class="bd-card-features-header-s">
69
+ <h1 class="bd-card-features-title-s">${this.title}</h1>
70
+ </div>
71
+ `
72
+ : null}
73
+ <div class="bd-card-features-track-s">
74
+ <slot @slotchange=${this._equalizeHeights}></slot>
75
+ </div>
76
+ </section>
77
+ `;
78
+ }
79
+ }
80
+
81
+ class CardFeaturesItem extends LitElement {
82
+ static properties = {
83
+ title : { type: String },
84
+ icon : { type: String },
85
+ badge : { type: String },
86
+ badgeVariant: { type: String }
87
+ };
88
+
89
+ constructor() {
90
+ super();
91
+ this.title = "";
92
+ this.icon = "";
93
+ this.badge = "";
94
+ this.badgeVariant = "";
95
+ }
96
+
97
+ _renderIcon() {
98
+ const iconEl = this.querySelector("[slot='icon']");
99
+
100
+ if (iconEl) {
101
+ return iconEl.cloneNode(true);
102
+ }
103
+
104
+ if (this.icon) {
105
+ return html`<img
106
+ src="${this.icon}"
107
+ alt="icon"
108
+ class="bd-card-features-icon-s"
109
+ />`;
110
+ }
111
+
112
+ return "";
113
+ }
114
+
115
+ render() {
116
+ return html`
117
+ <div class="bd-card-features-box-s">
118
+ ${this._renderIcon()}
119
+
120
+ <div class="bd-card-features-content-s">
121
+ ${this.title
122
+ ? html`
123
+ <div class="bd-card-features-title-badge-wrapper-s">
124
+ <bd-h as="h5" fontWeight="700" class="bd-card-features-item-title-s">${this.title}</bd-h>
125
+ ${this.badge
126
+ ? html`<bd-badge
127
+ variant="${this.badgeVariant}"
128
+ size="sm"
129
+ >${this.badge}</bd-badge>`
130
+ : ""}
131
+ </div>
132
+ `
133
+ : ""}
134
+ <slot></slot>
135
+ </div>
136
+ </div>
137
+ `;
138
+ }
139
+ }
140
+
141
+ CardFeatures.styles = [tokens, cardFeaturesCSS];
142
+ CardFeaturesItem.styles = [tokens, cardFeaturesCSS];
143
+
144
+ customElements.define("bd-card-features-item", CardFeaturesItem);
145
+ customElements.define("bd-card-features-section", CardFeatures);
@@ -0,0 +1,165 @@
1
+ import { html } from 'lit';
2
+ import '../badge/badge.js';
3
+ import '../icons/analysis-icon.js';
4
+ import '../icons/arrow-up-icon.js';
5
+ import '../icons/close-icon.js';
6
+ import '../icons/family-icon.js';
7
+ import '../icons/globe-icon.js';
8
+ import '../icons/individual-icon.js';
9
+ import '../icons/machine-learning-icon.js';
10
+ import '../paragraph/paragraph.js';
11
+ import './card-features.js';
12
+
13
+ export default {
14
+ title : 'Components/CardFeatures',
15
+ tags : ['autodocs'],
16
+ parameters: {
17
+ docs: {
18
+ description: {
19
+ component: `
20
+ **CardFeatures** — variantă "wide" a componentei Card, cu iconiță în stânga, titlu + badge opțional, și descriere.
21
+
22
+ \`\`\`html
23
+ <bd-card-features-section title="Our AI-powered platform that detects and fights scams. In real time.">
24
+ <bd-card-features-item
25
+ title="Scam Copilot Chatbot"
26
+ badge="NEW"
27
+ badge-variant="bd-light-blue"
28
+ >
29
+ <bd-individual-icon slot="icon" width="32" height="32" color="#006DFF"></bd-individual-icon>
30
+ <bd-p>Specialized AI chatbot that helps you identify suspicious online interactions.</bd-p>
31
+ </bd-card-features-item>
32
+ </bd-card-features-section>
33
+ \`\`\`
34
+
35
+ ### Atribute \`bd-card-features-item\`
36
+ | Atribut | Tip | Descriere |
37
+ |---|---|---|
38
+ | \`title\` | String | Titlul cardului |
39
+ | \`badge\` | String | Text badge (ex: NEW, IMPROVED) |
40
+ | \`badge-variant\` | String | Variantă culoare badge (vezi \`bd-badge\`) |
41
+ `
42
+ }
43
+ }
44
+ }
45
+ };
46
+
47
+ const iconMap = [
48
+ html`<bd-individual-icon slot="icon" width="32" height="32" color="#006DFF"></bd-individual-icon>`,
49
+ html`<bd-globe-icon slot="icon" width="32" height="32" color="#006DFF"></bd-globe-icon>`,
50
+ html`<bd-machine-learning-icon slot="icon" width="32" height="32" color="#006DFF"></bd-machine-learning-icon>`,
51
+ html`<bd-analysis-icon slot="icon" width="32" height="32" color="#006DFF"></bd-analysis-icon>`,
52
+ html`<bd-family-icon slot="icon" width="32" height="32" color="#006DFF"></bd-family-icon>`,
53
+ html`<bd-arrow-up-icon slot="icon" width="32" height="32" color="#006DFF"></bd-arrow-up-icon>`,
54
+ html`<bd-close-icon slot="icon" width="32" height="32" color="#006DFF"></bd-close-icon>`,
55
+ html`<bd-globe-icon slot="icon" width="32" height="32" color="#006DFF"></bd-globe-icon>`,
56
+ html`<bd-analysis-icon slot="icon" width="32" height="32" color="#006DFF"></bd-analysis-icon>`
57
+ ];
58
+
59
+ const items = [
60
+ { title: 'Scam Copilot Chatbot', badge: 'NEW', variant: 'bd-light-blue', content: 'Specialized AI chatbot that helps you identify suspicious online interactions so you don\'t become a victim.' },
61
+ { title: 'Scam Wave Alerts', badge: 'NEW', variant: 'bd-light-blue', content: 'Stay informed with real-time alerts about ongoing scam outbreaks detected in your area automatically.' },
62
+ { title: 'Online Scam Protection', badge: 'NEW', variant: 'bd-light-blue', content: 'Focused on browsing activities, it specializes in detecting the newest scam patterns and tactics.' },
63
+ { title: 'Remote Access Protection', badge: 'NEW', variant: 'bd-light-blue', content: 'Detects patterns of behavior typical of scammers seeking to access your data remotely.' },
64
+ { title: 'SMS Protection', badge: 'IMPROVED', variant: 'bd-light-green', content: 'Detects scams and harmful links in SMS messages using advanced AI for fast, real-time protection.' },
65
+ { title: 'Email Protection', badge: '', variant: '', content: 'Monitors web mailboxes from Gmail and Outlook 24/7 and marks every incoming email as safe or unsafe.' },
66
+ { title: 'Scam Notification Protection', badge: '', variant: '', content: 'Scans and detects scam attempts directly in push notifications before you even tap or interact.' },
67
+ { title: 'Chat Protection', badge: '', variant: '', content: 'Identifies scam messages in WhatsApp, Messenger, Telegram and Discord chats before they reach your attention.' },
68
+ { title: 'Calendar Invites Protection', badge: '', variant: '', content: 'Finds and blocks scam calendar events before they can trick you with fake links or misleading invites.' }
69
+ ];
70
+
71
+ export const Default = {
72
+ name : 'Default (9 items)',
73
+ render: () => html`
74
+ <bd-card-features-section title="Our AI-powered platform that detects and fights scams. In real time.">
75
+ ${items.map((item, i) => html`
76
+ <bd-card-features-item title="${item.title}" badge="${item.badge}" badge-variant="${item.variant}">
77
+ ${iconMap[i]}
78
+ <bd-p>${item.content}</bd-p>
79
+ </bd-card-features-item>
80
+ `)}
81
+ </bd-card-features-section>
82
+ `
83
+ };
84
+
85
+ export const NoSectionTitle = {
86
+ name : 'No Section Title',
87
+ render: () => html`
88
+ <bd-card-features-section>
89
+ ${items.slice(0, 3).map((item, i) => html`
90
+ <bd-card-features-item title="${item.title}" badge="${item.badge}" badge-variant="${item.variant}">
91
+ ${iconMap[i]}
92
+ <bd-p>${item.content}</bd-p>
93
+ </bd-card-features-item>
94
+ `)}
95
+ </bd-card-features-section>
96
+ `
97
+ };
98
+
99
+ export const NoBadge = {
100
+ name : 'Without Badge',
101
+ render: () => html`
102
+ <bd-card-features-section title="Core Features">
103
+ ${items.slice(5, 8).map((item, i) => html`
104
+ <bd-card-features-item title="${item.title}">
105
+ ${iconMap[i + 5]}
106
+ <bd-p>${item.content}</bd-p>
107
+ </bd-card-features-item>
108
+ `)}
109
+ </bd-card-features-section>
110
+ `
111
+ };
112
+
113
+ export const NoIcon = {
114
+ name : 'Without Icon',
115
+ render: () => html`
116
+ <bd-card-features-section title="Features">
117
+ ${items.slice(0, 3).map(item => html`
118
+ <bd-card-features-item title="${item.title}" badge="${item.badge}" badge-variant="${item.variant}">
119
+ <bd-p>${item.content}</bd-p>
120
+ </bd-card-features-item>
121
+ `)}
122
+ </bd-card-features-section>
123
+ `
124
+ };
125
+
126
+ export const TwoColumns = {
127
+ name : 'Two Items',
128
+ render: () => html`
129
+ <bd-card-features-section title="Highlights">
130
+ ${items.slice(0, 2).map((item, i) => html`
131
+ <bd-card-features-item title="${item.title}" badge="${item.badge}" badge-variant="${item.variant}">
132
+ ${iconMap[i]}
133
+ <bd-p>${item.content}</bd-p>
134
+ </bd-card-features-item>
135
+ `)}
136
+ </bd-card-features-section>
137
+ `
138
+ };
139
+
140
+ export const SingleItem = {
141
+ name : 'Single Item (edge case)',
142
+ render: () => html`
143
+ <bd-card-features-section title="Feature">
144
+ <bd-card-features-item title="${items[0].title}" badge="${items[0].badge}" badge-variant="${items[0].variant}">
145
+ ${iconMap[0]}
146
+ <bd-p>${items[0].content}</bd-p>
147
+ </bd-card-features-item>
148
+ </bd-card-features-section>
149
+ `
150
+ };
151
+
152
+ export const MobileView = {
153
+ name : 'Mobile View (375px)',
154
+ parameters: { viewport: { defaultViewport: 'mobile1' } },
155
+ render : () => html`
156
+ <bd-card-features-section title="Our AI-powered platform that detects and fights scams. In real time.">
157
+ ${items.map((item, i) => html`
158
+ <bd-card-features-item title="${item.title}" badge="${item.badge}" badge-variant="${item.variant}">
159
+ ${iconMap[i]}
160
+ <bd-p>${item.content}</bd-p>
161
+ </bd-card-features-item>
162
+ `)}
163
+ </bd-card-features-section>
164
+ `
165
+ };
@@ -8,7 +8,11 @@ export default css`
8
8
  padding-top: var(--spacing-32);
9
9
  padding-bottom: var(--spacing-32);
10
10
  }
11
-
11
+ ::slotted([slot="icon"]) {
12
+ width: 48px !important;
13
+ height: 48px !important;
14
+ flex-shrink: 0;
15
+ }
12
16
  .bd-section-title-s {
13
17
  font-family: var(--typography-fontFamily-sans);
14
18
  font-weight: var(--typography-fontWeight-semibold);
@@ -68,7 +72,7 @@ export default css`
68
72
  .bd-light-box-s {
69
73
  flex: var(--spacing-0) var(--spacing-0) auto;
70
74
  background: var(--background-card-grey);
71
- border-radius: 28px;
75
+ border-radius: var(--spacing-20);
72
76
  padding: var(--spacing-32);
73
77
  display: flex;
74
78
  flex-direction: column;
@@ -148,7 +152,9 @@ export default css`
148
152
  flex-direction: column;
149
153
  align-items: flex-start;
150
154
  gap: var(--spacing-8);
151
- padding-bottom: var(--spacing-16);
155
+ padding-bottom: var(--spacing-8);
156
+ left: -5px;
157
+ position: relative;
152
158
  }
153
159
 
154
160
  /* Header pentru carduri fără conținut */
@@ -19,7 +19,7 @@ class Card extends LitElement {
19
19
  ${this.title
20
20
  ? html`
21
21
  <div class="bd-header-light-carousel-s">
22
- <h1 class="bd-section-title-s">${this.title}</h1>
22
+ <bd-h as="h1" class="bd-section-title-s">${this.title}</bd-h>
23
23
  </div>
24
24
  `
25
25
  : null}
@@ -45,25 +45,48 @@ class CardItem extends LitElement {
45
45
  this.align = "start";
46
46
  }
47
47
 
48
+ _renderIcon() {
49
+ const iconEl = this.querySelector("[slot='icon']");
50
+
51
+ if (iconEl) {
52
+ return iconEl.cloneNode(true);
53
+ }
54
+
55
+ if (this.icon) {
56
+ return html`<img
57
+ src="${this.icon}"
58
+ alt="icon"
59
+ class="bd-light-icon-s"
60
+ />`;
61
+ }
62
+
63
+ return "";
64
+ }
65
+
66
+ _hasContent() {
67
+ const slottedNodes = [...this.childNodes].filter((node) => {
68
+ if (node.nodeType === Node.ELEMENT_NODE) {
69
+ return node.getAttribute("slot") !== "icon";
70
+ }
71
+ return node.nodeType === Node.TEXT_NODE && node.textContent.trim() !== "";
72
+ });
73
+
74
+ return slottedNodes.length > 0;
75
+ }
76
+
48
77
  render() {
49
78
  const isCentered = this.align === "center";
50
- const hasContent = this.innerHTML.trim() !== '';
79
+ const hasContent = this._hasContent();
51
80
 
52
81
  return html`
53
82
  <div class="bd-light-box-s ${isCentered ? 'bd-light-box-center' : ''} ${!hasContent ? 'bd-light-box-no-content' : ''}">
54
83
  <div class="bd-light-box-header-s ${isCentered ? 'bd-light-box-header-center' : ''}">
55
- ${this.icon
56
- ? html`<img
57
- src="${this.icon}"
58
- alt="icon"
59
- class="bd-light-icon-s"
60
- />`
61
- : ""}
84
+ ${this._renderIcon()}
62
85
  </div>
63
86
  ${this.title
64
87
  ? html`
65
88
  <div class="bd-light-title-badge-wrapper-s ${!hasContent ? 'bd-light-title-no-content' : ''}">
66
- <bd-h as="h4" padding="10px 0">${this.title}</bd-h>
89
+ <bd-h as="h5" fontWeight="700">${this.title}</bd-h>
67
90
  </div>
68
91
  `
69
92
  : ""}
@@ -1,4 +1,14 @@
1
1
  import { html } from 'lit';
2
+ import '../heading/heading.js';
3
+ import '../icons/analysis-icon.js';
4
+ import '../icons/arrow-down-icon.js';
5
+ import '../icons/arrow-up-icon.js';
6
+ import '../icons/close-icon.js';
7
+ import '../icons/family-icon.js';
8
+ import '../icons/globe-icon.js';
9
+ import '../icons/individual-icon.js';
10
+ import '../icons/machine-learning-icon.js';
11
+ import '../paragraph/paragraph.js';
2
12
  import './card.js';
3
13
 
4
14
  export default {
@@ -16,16 +26,17 @@ export default {
16
26
  ### Usage
17
27
  \`\`\`html
18
28
  <bd-card-section title="Why Bitdefender">
19
- <bd-card-item title="AI Protection" icon="/assets/brain.svg" align="center">
20
- <p>Powered by machine learning.</p>
29
+ <bd-card-item title="AI Protection" align="center">
30
+ <bd-individual-icon slot="icon" width="32" height="32" color="#006DFF"></bd-individual-icon>
31
+ <bd-p>Powered by machine learning.</bd-p>
21
32
  </bd-card-item>
22
33
  </bd-card-section>
23
34
  \`\`\`
24
35
 
25
36
  ### CardItem Behavior
26
37
  - If \`align="center"\` — applies \`bd-light-box-center\` and \`bd-light-box-header-center\` classes
27
- - If no slotted content — applies \`bd-light-box-no-content\` and \`bd-light-title-no-content\` classes
28
- - Icon is conditionally rendered only when \`icon\` prop is set
38
+ - If no slotted content (besides icon) — applies \`bd-light-box-no-content\` and \`bd-light-title-no-content\` classes
39
+ - Icon is rendered from a \`slot="icon"\` element if present, otherwise falls back to the \`icon\` prop as an image path
29
40
  - Title uses \`<bd-h as="h4">\` with 10px vertical padding
30
41
  `
31
42
  }
@@ -42,11 +53,6 @@ export default {
42
53
  description: 'Title of the card item, rendered using `<bd-h as="h4">`',
43
54
  table : { type: { summary: 'string' }, defaultValue: { summary: '' }, category: 'CardItem' }
44
55
  },
45
- icon: {
46
- control : 'text',
47
- description: 'Path to the icon image shown at the top of the card',
48
- table : { type: { summary: 'string' }, defaultValue: { summary: '' }, category: 'CardItem' }
49
- },
50
56
  align: {
51
57
  control : { type: 'select' },
52
58
  options : ['start', 'center'],
@@ -56,38 +62,53 @@ export default {
56
62
  }
57
63
  };
58
64
 
59
- const sampleItems = [
60
- { title: 'AI Protection', icon: '/assets/brain.svg', content: 'Powered by machine learning and behavioral analysis.' },
61
- { title: 'Multi-layer Security', icon: '/assets/shield.svg', content: 'Multiple independent protection layers stop any attack.' },
62
- { title: 'VPN Included', icon: '/assets/vpn.svg', content: 'Unlimited encrypted VPN traffic for all your devices.' },
63
- { title: 'Parental Controls', icon: '/assets/parental.svg', content: 'Advanced controls to protect your children online.' }
64
- ];
65
-
66
65
  // ─── Stories ───────────────────────────────────────────────────────────────
67
66
 
68
67
  export const Default = {
69
68
  name : 'Default (4 items)',
70
69
  render: () => html`
71
70
  <bd-card-section title="Why Bitdefender">
72
- ${sampleItems.map(item => html`
73
- <bd-card-item title="${item.title}" icon="${item.icon}">
74
- <p>${item.content}</p>
75
- </bd-card-item>
76
- `)}
71
+ <bd-card-item title="AI Protection">
72
+ <bd-individual-icon slot="icon" width="32" height="32" color="#006DFF"></bd-individual-icon>
73
+ <bd-p>Powered by machine learning and behavioral analysis.</bd-p>
74
+ </bd-card-item>
75
+ <bd-card-item title="Multi-layer Security">
76
+ <bd-globe-icon slot="icon" width="32" height="32" color="#006DFF"></bd-globe-icon>
77
+ <bd-p>Multiple independent protection layers stop any attack.</bd-p>
78
+ </bd-card-item>
79
+ <bd-card-item title="VPN Included">
80
+ <bd-machine-learning-icon slot="icon" width="32" height="32" color="#006DFF"></bd-machine-learning-icon>
81
+ <bd-p>Unlimited encrypted VPN traffic for all your devices.</bd-p>
82
+ </bd-card-item>
83
+ <bd-card-item title="Parental Controls">
84
+ <bd-analysis-icon slot="icon" width="32" height="32" color="#006DFF"></bd-analysis-icon>
85
+ <bd-p>Advanced controls to protect your children online.</bd-p>
86
+ </bd-card-item>
77
87
  </bd-card-section>
78
88
  `,
79
- parameters: { docs: { description: { story: 'Four card items with icons, titles, and slotted content inside a section with a title.' } } }
89
+ parameters: { docs: { description: { story: 'Four card items with icons, titles, and slotted `bd-p` content inside a section with a title.' } } }
80
90
  };
81
91
 
82
92
  export const NoSectionTitle = {
83
93
  name : 'No Section Title',
84
94
  render: () => html`
85
95
  <bd-card-section>
86
- ${sampleItems.map(item => html`
87
- <bd-card-item title="${item.title}" icon="${item.icon}">
88
- <p>${item.content}</p>
89
- </bd-card-item>
90
- `)}
96
+ <bd-card-item title="AI Protection">
97
+ <bd-individual-icon slot="icon" width="32" height="32" color="#006DFF"></bd-individual-icon>
98
+ <bd-p>Powered by machine learning and behavioral analysis.</bd-p>
99
+ </bd-card-item>
100
+ <bd-card-item title="Multi-layer Security">
101
+ <bd-globe-icon slot="icon" width="32" height="32" color="#006DFF"></bd-globe-icon>
102
+ <bd-p>Multiple independent protection layers stop any attack.</bd-p>
103
+ </bd-card-item>
104
+ <bd-card-item title="VPN Included">
105
+ <bd-machine-learning-icon slot="icon" width="32" height="32" color="#006DFF"></bd-machine-learning-icon>
106
+ <bd-p>Unlimited encrypted VPN traffic for all your devices.</bd-p>
107
+ </bd-card-item>
108
+ <bd-card-item title="Parental Controls">
109
+ <bd-analysis-icon slot="icon" width="32" height="32" color="#006DFF"></bd-analysis-icon>
110
+ <bd-p>Advanced controls to protect your children online.</bd-p>
111
+ </bd-card-item>
91
112
  </bd-card-section>
92
113
  `,
93
114
  parameters: { docs: { description: { story: 'Section without `title` prop — the header div is conditionally omitted.' } } }
@@ -97,11 +118,22 @@ export const CenteredAlignment = {
97
118
  name : 'Centered Alignment',
98
119
  render: () => html`
99
120
  <bd-card-section title="Features">
100
- ${sampleItems.map(item => html`
101
- <bd-card-item title="${item.title}" icon="${item.icon}" align="center">
102
- <p>${item.content}</p>
103
- </bd-card-item>
104
- `)}
121
+ <bd-card-item title="AI Protection" align="center">
122
+ <bd-individual-icon slot="icon" width="32" height="32" color="#006DFF"></bd-individual-icon>
123
+ <bd-p>Powered by machine learning and behavioral analysis.</bd-p>
124
+ </bd-card-item>
125
+ <bd-card-item title="Multi-layer Security" align="center">
126
+ <bd-globe-icon slot="icon" width="32" height="32" color="#006DFF"></bd-globe-icon>
127
+ <bd-p>Multiple independent protection layers stop any attack.</bd-p>
128
+ </bd-card-item>
129
+ <bd-card-item title="VPN Included" align="center">
130
+ <bd-machine-learning-icon slot="icon" width="32" height="32" color="#006DFF"></bd-machine-learning-icon>
131
+ <bd-p>Unlimited encrypted VPN traffic for all your devices.</bd-p>
132
+ </bd-card-item>
133
+ <bd-card-item title="Parental Controls" align="center">
134
+ <bd-analysis-icon slot="icon" width="32" height="32" color="#006DFF"></bd-analysis-icon>
135
+ <bd-p>Advanced controls to protect your children online.</bd-p>
136
+ </bd-card-item>
105
137
  </bd-card-section>
106
138
  `,
107
139
  parameters: { docs: { description: { story: '`align="center"` applied to all items — centers icon, title, and content.' } } }
@@ -111,11 +143,13 @@ export const MixedAlignment = {
111
143
  name : 'Mixed Alignment',
112
144
  render: () => html`
113
145
  <bd-card-section title="Mixed Layout">
114
- <bd-card-item title="Left Aligned" icon="/assets/brain.svg" align="start">
115
- <p>Default left-aligned content.</p>
146
+ <bd-card-item title="Left Aligned" align="start">
147
+ <bd-individual-icon slot="icon" width="32" height="32" color="#006DFF"></bd-individual-icon>
148
+ <bd-p>Default left-aligned content.</bd-p>
116
149
  </bd-card-item>
117
- <bd-card-item title="Center Aligned" icon="/assets/shield.svg" align="center">
118
- <p>Centered content.</p>
150
+ <bd-card-item title="Center Aligned" align="center">
151
+ <bd-globe-icon slot="icon" width="32" height="32" color="#006DFF"></bd-globe-icon>
152
+ <bd-p>Centered content.</bd-p>
119
153
  </bd-card-item>
120
154
  </bd-card-section>
121
155
  `,
@@ -126,26 +160,42 @@ export const NoIcon = {
126
160
  name : 'No Icons',
127
161
  render: () => html`
128
162
  <bd-card-section title="Features">
129
- ${sampleItems.map(item => html`
130
- <bd-card-item title="${item.title}">
131
- <p>${item.content}</p>
132
- </bd-card-item>
133
- `)}
163
+ <bd-card-item title="AI Protection">
164
+ <bd-p>Powered by machine learning and behavioral analysis.</bd-p>
165
+ </bd-card-item>
166
+ <bd-card-item title="Multi-layer Security">
167
+ <bd-p>Multiple independent protection layers stop any attack.</bd-p>
168
+ </bd-card-item>
169
+ <bd-card-item title="VPN Included">
170
+ <bd-p>Unlimited encrypted VPN traffic for all your devices.</bd-p>
171
+ </bd-card-item>
172
+ <bd-card-item title="Parental Controls">
173
+ <bd-p>Advanced controls to protect your children online.</bd-p>
174
+ </bd-card-item>
134
175
  </bd-card-section>
135
176
  `,
136
- parameters: { docs: { description: { story: 'Items without `icon` prop — the `<img>` is conditionally omitted.' } } }
177
+ parameters: { docs: { description: { story: 'Items without a `slot="icon"` element — the icon wrapper renders empty.' } } }
137
178
  };
138
179
 
139
180
  export const NoSlottedContent = {
140
181
  name : 'No Slotted Content',
141
182
  render: () => html`
142
183
  <bd-card-section title="Features">
143
- ${sampleItems.map(item => html`
144
- <bd-card-item title="${item.title}" icon="${item.icon}"></bd-card-item>
145
- `)}
184
+ <bd-card-item title="AI Protection">
185
+ <bd-individual-icon slot="icon" width="32" height="32" color="#006DFF"></bd-individual-icon>
186
+ </bd-card-item>
187
+ <bd-card-item title="Multi-layer Security">
188
+ <bd-globe-icon slot="icon" width="32" height="32" color="#006DFF"></bd-globe-icon>
189
+ </bd-card-item>
190
+ <bd-card-item title="VPN Included">
191
+ <bd-machine-learning-icon slot="icon" width="32" height="32" color="#006DFF"></bd-machine-learning-icon>
192
+ </bd-card-item>
193
+ <bd-card-item title="Parental Controls">
194
+ <bd-analysis-icon slot="icon" width="32" height="32" color="#006DFF"></bd-analysis-icon>
195
+ </bd-card-item>
146
196
  </bd-card-section>
147
197
  `,
148
- parameters: { docs: { description: { story: 'Items with no slotted content — applies `bd-light-box-no-content` and `bd-light-title-no-content` CSS classes.' } } }
198
+ parameters: { docs: { description: { story: 'Items with only an icon and title — applies `bd-light-box-no-content` and `bd-light-title-no-content` CSS classes.' } } }
149
199
  };
150
200
 
151
201
  export const TitleOnly = {
@@ -164,28 +214,29 @@ export const RichContent = {
164
214
  name : 'Rich Slotted Content',
165
215
  render: () => html`
166
216
  <bd-card-section title="Plan Details">
167
- <bd-card-item title="What's included" icon="/assets/shield.svg">
168
- <ul>
169
- <li>Antivirus & Anti-malware</li>
170
- <li>VPN (200+ servers)</li>
171
- <li>Password Manager</li>
172
- </ul>
173
- </bd-card-item>
174
- <bd-card-item title="Supported Platforms" icon="/assets/devices.svg">
175
- <p>Windows, macOS, Android, iOS</p>
217
+ <bd-card-item title="What's included">
218
+ <bd-family-icon slot="icon" width="32" height="32" color="#006DFF"></bd-family-icon>
219
+ <bd-p>Antivirus & Anti-malware</bd-p>
220
+ <bd-p>VPN (200+ servers)</bd-p>
221
+ <bd-p>Password Manager</bd-p>
222
+ </bd-card-item>
223
+ <bd-card-item title="Supported Platforms">
224
+ <bd-arrow-up-icon slot="icon" width="32" height="32" color="#006DFF"></bd-arrow-up-icon>
225
+ <bd-p>Windows, macOS, Android, iOS</bd-p>
176
226
  <a href="#">View all platforms</a>
177
227
  </bd-card-item>
178
228
  </bd-card-section>
179
229
  `,
180
- parameters: { docs: { description: { story: 'Rich slotted content including lists, paragraphs, and links.' } } }
230
+ parameters: { docs: { description: { story: 'Rich slotted content using multiple `bd-p` elements and a link.' } } }
181
231
  };
182
232
 
183
233
  export const SingleItem = {
184
234
  name : 'Single Item (edge case)',
185
235
  render: () => html`
186
236
  <bd-card-section title="Feature">
187
- <bd-card-item title="AI Protection" icon="/assets/brain.svg">
188
- <p>Machine learning-powered protection.</p>
237
+ <bd-card-item title="AI Protection">
238
+ <bd-individual-icon slot="icon" width="32" height="32" color="#006DFF"></bd-individual-icon>
239
+ <bd-p>Machine learning-powered protection.</bd-p>
189
240
  </bd-card-item>
190
241
  </bd-card-section>
191
242
  `,
@@ -197,18 +248,19 @@ export const Playground = {
197
248
  args: {
198
249
  sectionTitle: 'Why Bitdefender',
199
250
  itemTitle : 'AI Protection',
200
- icon : '/assets/brain.svg',
201
251
  align : 'start'
202
252
  },
203
253
  render: (args) => html`
204
254
  <bd-card-section title="${args.sectionTitle}">
205
- <bd-card-item title="${args.itemTitle}" icon="${args.icon}" align="${args.align}">
206
- <p>Powered by machine learning and behavioral analysis.</p>
255
+ <bd-card-item title="${args.itemTitle}" align="${args.align}">
256
+ <bd-individual-icon slot="icon" width="32" height="32" color="#006DFF"></bd-individual-icon>
257
+ <bd-p>Powered by machine learning and behavioral analysis.</bd-p>
207
258
  </bd-card-item>
208
- <bd-card-item title="VPN Included" icon="/assets/vpn.svg" align="${args.align}">
209
- <p>Unlimited encrypted VPN traffic.</p>
259
+ <bd-card-item title="VPN Included" align="${args.align}">
260
+ <bd-globe-icon slot="icon" width="32" height="32" color="#006DFF"></bd-globe-icon>
261
+ <bd-p>Unlimited encrypted VPN traffic.</bd-p>
210
262
  </bd-card-item>
211
263
  </bd-card-section>
212
264
  `,
213
- parameters: { docs: { description: { story: 'Interactive playground. Adjust section title, item title, icon, and alignment via Controls.' } } }
265
+ parameters: { docs: { description: { story: 'Interactive playground. Adjust section title, item title, and alignment via Controls.' } } }
214
266
  };