@repobit/dex-system-design 0.24.8 → 0.24.9
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 +7 -0
- package/package.json +4 -4
- package/src/components/ai-guardian-demo.stories.js +11 -4
- package/src/components/anchor/anchor-nav.css.js +16 -18
- package/src/components/anchor/anchor-nav.js +86 -23
- package/src/components/anchor/anchor.stories.js +87 -4
- package/src/components/cta-banner/cta-banner.stories.js +122 -0
- package/src/components/install-options/install-options.stories.js +219 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
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.24.9](https://github.com/bitdefender/dex-core/compare/@repobit/dex-system-design@0.24.8...@repobit/dex-system-design@0.24.9) (2026-09-08)
|
|
7
|
+
|
|
8
|
+
### Bug Fixes
|
|
9
|
+
|
|
10
|
+
* **DEX-1014:** new AI Bitdefender components and anchor nav changes
|
|
11
|
+
|
|
12
|
+
|
|
6
13
|
## [0.24.8](https://github.com/bitdefender/dex-core/compare/@repobit/dex-system-design@0.24.7...@repobit/dex-system-design@0.24.8) (2026-09-08)
|
|
7
14
|
|
|
8
15
|
### Bug Fixes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@repobit/dex-system-design",
|
|
3
|
-
"version": "0.24.
|
|
3
|
+
"version": "0.24.9",
|
|
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",
|
|
@@ -74,8 +74,8 @@
|
|
|
74
74
|
"url": "https://github.com/bitdefender/dex-core/issues"
|
|
75
75
|
},
|
|
76
76
|
"dependencies": {
|
|
77
|
-
"@repobit/dex-store": "1.6.
|
|
78
|
-
"@repobit/dex-store-elements": "2.0.
|
|
77
|
+
"@repobit/dex-store": "1.6.25",
|
|
78
|
+
"@repobit/dex-store-elements": "2.0.30",
|
|
79
79
|
"lit": "^3.3.2"
|
|
80
80
|
},
|
|
81
81
|
"devDependencies": {
|
|
@@ -92,5 +92,5 @@
|
|
|
92
92
|
"volta": {
|
|
93
93
|
"node": "24.14.0"
|
|
94
94
|
},
|
|
95
|
-
"gitHead": "
|
|
95
|
+
"gitHead": "1f08b0389af256faebe7db77b276d350c9be31ae"
|
|
96
96
|
}
|
|
@@ -93,6 +93,7 @@ function aiGuardianBody() {
|
|
|
93
93
|
aria-label="Page sections"
|
|
94
94
|
cta-label="Download BETA Today"
|
|
95
95
|
cta-href="#download"
|
|
96
|
+
sticky-top="65px"
|
|
96
97
|
.items=${[
|
|
97
98
|
{ title: "Overview" },
|
|
98
99
|
{ title: "Compatibility" },
|
|
@@ -498,6 +499,7 @@ function skillScannerBody() {
|
|
|
498
499
|
<div style="max-width: 1200px; margin: 0 auto;">
|
|
499
500
|
<bd-anchor-nav
|
|
500
501
|
aria-label="Skill Scanner sections"
|
|
502
|
+
sticky-top="65px"
|
|
501
503
|
.items=${[
|
|
502
504
|
{ title: "Install" },
|
|
503
505
|
{ title: "Overview" },
|
|
@@ -1034,11 +1036,15 @@ switches, in place, between two full "pages" without any real navigation —
|
|
|
1034
1036
|
clicking a tab intercepts the anchor click and swaps local state instead of
|
|
1035
1037
|
following the href (which has no route in Storybook and would 404).
|
|
1036
1038
|
|
|
1039
|
+
Both anchor-nav bars use \`sticky-top="65px"\` so they pin themselves *below*
|
|
1040
|
+
the sticky page-switcher instead of overlapping it once scrolled. That value
|
|
1041
|
+
is an estimate — measure bd-page-switcher's real rendered height in DevTools
|
|
1042
|
+
and adjust if the two bars still overlap or leave a gap.
|
|
1043
|
+
|
|
1037
1044
|
**AI Guardian** page: \`bd-header-code\`, \`bd-quick-answer\`, sticky \`bd-anchor-nav\`
|
|
1038
1045
|
(9 items) wrapping \`bd-overview\`, \`bd-compatibility-table\` (default variant), the
|
|
1039
1046
|
"Protections" section (\`bd-bento-grid\` + \`bd-comparison-panel\`), \`bd-process-steps\`,
|
|
1040
|
-
\`bd-compatibility-table\` (\`variant="
|
|
1041
|
-
revealing \`bd-compatibility-table\` (\`variant="risk"\` / \`variant="light"\`), an FAQ
|
|
1047
|
+
\`bd-compatibility-table\` (\`variant="risk"\` / \`variant="light"\`), an FAQ
|
|
1042
1048
|
section (\`bd-accordion-bg\`, 9 questions), \`bd-cta-banner\`, \`bd-agent-endpoints\`,
|
|
1043
1049
|
and \`bd-trust-panel\`.
|
|
1044
1050
|
|
|
@@ -1049,8 +1055,9 @@ Install, Overview, What it detects, How it works, Privacy, FAQ) wrapping
|
|
|
1049
1055
|
a \`bd-compatibility-table\` inside a chevron accordion, a \`bd-bento-grid\` +
|
|
1050
1056
|
\`bd-process-steps\` + another \`bd-compatibility-table\` for "How it works",
|
|
1051
1057
|
another \`bd-install-options\` (generic-slot variant: table + checklist + note)
|
|
1052
|
-
for "Privacy",
|
|
1053
|
-
|
|
1058
|
+
for "Privacy", a \`bd-trust-panel\` + \`bd-accordion-bg\` FAQ (7 questions) under
|
|
1059
|
+
"FAQ", a \`bd-cta-banner\`, and \`bd-agent-endpoints\` with legal copy in its
|
|
1060
|
+
\`rows\` slot.
|
|
1054
1061
|
|
|
1055
1062
|
Both pages share the same \`bd-footer\` at the bottom.
|
|
1056
1063
|
`
|
|
@@ -11,14 +11,17 @@ export const anchorNavStyles = css`
|
|
|
11
11
|
|
|
12
12
|
:host(.is-sticky) {
|
|
13
13
|
position: fixed;
|
|
14
|
-
top: 0;
|
|
14
|
+
top: var(--sticky-top, 0);
|
|
15
15
|
left: var(--sticky-left, 0);
|
|
16
16
|
width: var(--sticky-width, 100%);
|
|
17
17
|
box-shadow: var(--shadow-sm);
|
|
18
18
|
z-index: 1000;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
|
|
21
|
+
:host(.is-sticky) nav {
|
|
22
|
+
background: var(--color-neutral-0);
|
|
23
|
+
}
|
|
24
|
+
|
|
22
25
|
nav {
|
|
23
26
|
display: block;
|
|
24
27
|
margin: var(--spacing-0);
|
|
@@ -29,11 +32,6 @@ export const anchorNavStyles = css`
|
|
|
29
32
|
border-bottom: var(--border-width-1) solid var(--color-neutral-100);
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
/* Când e sticky, păstrăm aceleași border-uri */
|
|
33
|
-
:host(.is-sticky) nav {
|
|
34
|
-
background: var(--color-neutral-0);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
35
|
.bd-anchor-nav__inner {
|
|
38
36
|
display: flex;
|
|
39
37
|
flex-wrap: wrap;
|
|
@@ -48,7 +46,6 @@ export const anchorNavStyles = css`
|
|
|
48
46
|
box-sizing: border-box;
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
/* Restul codului tău CSS rămâne identic de aici în jos */
|
|
52
49
|
|
|
53
50
|
.anchor-link:focus-visible,
|
|
54
51
|
.bd-anchor-nav__cta:focus-visible,
|
|
@@ -118,19 +115,19 @@ export const anchorNavStyles = css`
|
|
|
118
115
|
text-decoration: none !important;
|
|
119
116
|
}
|
|
120
117
|
|
|
121
|
-
|
|
122
|
-
|
|
118
|
+
|
|
119
|
+
.anchor-indicator {
|
|
123
120
|
position: absolute;
|
|
124
|
-
left:
|
|
121
|
+
left: 0;
|
|
125
122
|
bottom: calc(-1 * var(--spacing-14));
|
|
126
|
-
width: 0
|
|
123
|
+
width: 0;
|
|
127
124
|
height: var(--border-width-3);
|
|
128
125
|
background-color: var(--color-blue-500);
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
126
|
+
transform: translateX(0);
|
|
127
|
+
transition:
|
|
128
|
+
transform var(--transition-duration-slow) var(--transition-easing-ease-out),
|
|
129
|
+
width var(--transition-duration-slow) var(--transition-easing-ease-out);
|
|
130
|
+
pointer-events: none;
|
|
134
131
|
}
|
|
135
132
|
|
|
136
133
|
.bd-anchor-nav__dropdown {
|
|
@@ -299,10 +296,11 @@ export const anchorNavStyles = css`
|
|
|
299
296
|
}
|
|
300
297
|
|
|
301
298
|
@media (prefers-reduced-motion: reduce) {
|
|
302
|
-
.anchor-
|
|
299
|
+
.anchor-indicator,
|
|
303
300
|
.bd-anchor-nav__dropdown-chevron,
|
|
304
301
|
.bd-cta,
|
|
305
302
|
.bd-anchor-nav__dropdown-label--swap {
|
|
303
|
+
transition: none !important;
|
|
306
304
|
animation: none !important;
|
|
307
305
|
}
|
|
308
306
|
}
|
|
@@ -33,7 +33,12 @@ class BdAnchorNav extends LitElement {
|
|
|
33
33
|
ctaLabel : { type: String, attribute: "cta-label" },
|
|
34
34
|
ctaHref : { type: String, attribute: "cta-href" },
|
|
35
35
|
items : { type: Array },
|
|
36
|
-
maxWidth : { type: String, attribute: "max-width" }
|
|
36
|
+
maxWidth : { type: String, attribute: "max-width" },
|
|
37
|
+
// How far from the viewport top this nav sticks once pinned — set this
|
|
38
|
+
// to the rendered height of whatever sticky element sits above it (e.g.
|
|
39
|
+
// a page-switcher), so the two don't stack on top of each other at
|
|
40
|
+
// top:0. Accepts any CSS length, e.g. "64px", "4rem".
|
|
41
|
+
stickyTop : { type: String, attribute: "sticky-top" }
|
|
37
42
|
};
|
|
38
43
|
|
|
39
44
|
static styles = [tokens, anchorNavStyles];
|
|
@@ -48,6 +53,7 @@ class BdAnchorNav extends LitElement {
|
|
|
48
53
|
this.ctaHref = "";
|
|
49
54
|
this.items = null;
|
|
50
55
|
this.maxWidth = "";
|
|
56
|
+
this.stickyTop = "0px";
|
|
51
57
|
this._panelId = `bd-anchor-nav-panel-${Math.random().toString(36)
|
|
52
58
|
.slice(2, 11)}`;
|
|
53
59
|
this._onScrollSpy = this._onScrollSpy.bind(this);
|
|
@@ -61,6 +67,10 @@ class BdAnchorNav extends LitElement {
|
|
|
61
67
|
this._stickyPlaceholder = null;
|
|
62
68
|
this._onStickyScroll = null;
|
|
63
69
|
this._handleResize = this._handleResize.bind(this);
|
|
70
|
+
// sliding underline indicator: false until the first successful
|
|
71
|
+
// measurement + placement, so it doesn't visibly animate in from the
|
|
72
|
+
// left edge on first paint.
|
|
73
|
+
this._indicatorReady = false;
|
|
64
74
|
}
|
|
65
75
|
|
|
66
76
|
connectedCallback() {
|
|
@@ -85,8 +95,76 @@ class BdAnchorNav extends LitElement {
|
|
|
85
95
|
this._destroySticky();
|
|
86
96
|
}
|
|
87
97
|
|
|
98
|
+
updated(changedProperties) {
|
|
99
|
+
super.updated(changedProperties);
|
|
100
|
+
|
|
101
|
+
if (changedProperties.has("stickyTop")) {
|
|
102
|
+
this.style.setProperty("--sticky-top", this.stickyTop || "0px");
|
|
103
|
+
// the scroll-spy offset (how far to scroll past the sticky bar when
|
|
104
|
+
// clicking a link) depends on this too, since the nav's own visible
|
|
105
|
+
// top now sits lower than the viewport top while stuck.
|
|
106
|
+
this._runScrollSpy();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (changedProperties.has("activeId") || changedProperties.has("items")) {
|
|
110
|
+
// wait a frame so the .active class has actually painted before
|
|
111
|
+
// measuring its box — requestAnimationFrame is enough here, no need
|
|
112
|
+
// for updateComplete since nothing else in render() depends on this.
|
|
113
|
+
requestAnimationFrame(() => this._updateIndicator());
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
if (!changedProperties.has("activeId")) return;
|
|
117
|
+
const prev = changedProperties.get("activeId");
|
|
118
|
+
if (prev === undefined || prev === "") return;
|
|
119
|
+
if (prev === this.activeId) return;
|
|
120
|
+
queueMicrotask(() => this._playMobileDropdownLabelSwap());
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
firstUpdated() {
|
|
124
|
+
const resolved = this._resolvedItems();
|
|
125
|
+
if (resolved.length) {
|
|
126
|
+
this.activeId = "anchor-1";
|
|
127
|
+
this.requestUpdate();
|
|
128
|
+
}
|
|
129
|
+
queueMicrotask(() => this._runScrollSpy());
|
|
130
|
+
this._handleMobileFullWidth();
|
|
131
|
+
requestAnimationFrame(() => this._updateIndicator());
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// Positions the sliding underline under the currently active desktop
|
|
135
|
+
// link. Reads offsetLeft/offsetWidth directly off the active bd-link —
|
|
136
|
+
// as a flex item it's block-level regardless of its own :host display,
|
|
137
|
+
// so these are reliable without any extra math against a bounding rect.
|
|
138
|
+
_updateIndicator() {
|
|
139
|
+
const indicator = this.renderRoot?.querySelector(".anchor-indicator");
|
|
140
|
+
const activeLink = this.renderRoot?.querySelector(
|
|
141
|
+
".anchor-links--desktop .anchor-link.active"
|
|
142
|
+
);
|
|
143
|
+
if (!indicator || !activeLink) return;
|
|
144
|
+
|
|
145
|
+
const left = activeLink.offsetLeft;
|
|
146
|
+
const width = activeLink.offsetWidth;
|
|
147
|
+
|
|
148
|
+
if (!this._indicatorReady) {
|
|
149
|
+
// first placement: skip the transition so it doesn't slide in from
|
|
150
|
+
// the left edge on initial paint, then re-enable it next frame.
|
|
151
|
+
indicator.style.transition = "none";
|
|
152
|
+
indicator.style.transform = `translateX(${left}px)`;
|
|
153
|
+
indicator.style.width = `${width}px`;
|
|
154
|
+
// force a style flush before removing the transition override
|
|
155
|
+
void indicator.offsetWidth;
|
|
156
|
+
indicator.style.transition = "";
|
|
157
|
+
this._indicatorReady = true;
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
indicator.style.transform = `translateX(${left}px)`;
|
|
162
|
+
indicator.style.width = `${width}px`;
|
|
163
|
+
}
|
|
164
|
+
|
|
88
165
|
_handleResize() {
|
|
89
166
|
this._handleMobileFullWidth();
|
|
167
|
+
this._updateIndicator();
|
|
90
168
|
}
|
|
91
169
|
|
|
92
170
|
_handleMobileFullWidth() {
|
|
@@ -109,6 +187,7 @@ class BdAnchorNav extends LitElement {
|
|
|
109
187
|
|
|
110
188
|
_initSticky() {
|
|
111
189
|
this._stickyOriginalTop = null;
|
|
190
|
+
this.style.setProperty("--sticky-top", this.stickyTop || "0px");
|
|
112
191
|
|
|
113
192
|
this._onStickyScroll = () => {
|
|
114
193
|
const parent = this.parentElement;
|
|
@@ -118,14 +197,15 @@ class BdAnchorNav extends LitElement {
|
|
|
118
197
|
const navHeight = this._stickyPlaceholder
|
|
119
198
|
? this._stickyPlaceholder.offsetHeight
|
|
120
199
|
: this.offsetHeight;
|
|
200
|
+
const stickyTopPx = parseLengthToPx(this.stickyTop) || 0;
|
|
121
201
|
|
|
122
202
|
if (this._stickyOriginalTop === null) {
|
|
123
203
|
const rect = this.getBoundingClientRect();
|
|
124
|
-
this._stickyOriginalTop = rect.top + window.scrollY;
|
|
204
|
+
this._stickyOriginalTop = rect.top + window.scrollY - stickyTopPx;
|
|
125
205
|
}
|
|
126
206
|
|
|
127
207
|
const passedTop = window.scrollY >= this._stickyOriginalTop;
|
|
128
|
-
const parentExited = parentRect.bottom <= navHeight;
|
|
208
|
+
const parentExited = parentRect.bottom <= navHeight + stickyTopPx;
|
|
129
209
|
|
|
130
210
|
if (passedTop && !parentExited) {
|
|
131
211
|
if (!this.classList.contains("is-sticky")) {
|
|
@@ -297,25 +377,6 @@ class BdAnchorNav extends LitElement {
|
|
|
297
377
|
}
|
|
298
378
|
}
|
|
299
379
|
|
|
300
|
-
firstUpdated() {
|
|
301
|
-
const resolved = this._resolvedItems();
|
|
302
|
-
if (resolved.length) {
|
|
303
|
-
this.activeId = "anchor-1";
|
|
304
|
-
this.requestUpdate();
|
|
305
|
-
}
|
|
306
|
-
queueMicrotask(() => this._runScrollSpy());
|
|
307
|
-
this._handleMobileFullWidth();
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
updated(changedProperties) {
|
|
311
|
-
super.updated(changedProperties);
|
|
312
|
-
if (!changedProperties.has("activeId")) return;
|
|
313
|
-
const prev = changedProperties.get("activeId");
|
|
314
|
-
if (prev === undefined || prev === "") return;
|
|
315
|
-
if (prev === this.activeId) return;
|
|
316
|
-
queueMicrotask(() => this._playMobileDropdownLabelSwap());
|
|
317
|
-
}
|
|
318
|
-
|
|
319
380
|
_playMobileDropdownLabelSwap() {
|
|
320
381
|
if (typeof window === "undefined") return;
|
|
321
382
|
if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;
|
|
@@ -334,10 +395,11 @@ class BdAnchorNav extends LitElement {
|
|
|
334
395
|
|
|
335
396
|
_stickyOffsetPx() {
|
|
336
397
|
const barPx = this.offsetHeight;
|
|
398
|
+
const stickyTopPx = parseLengthToPx(this.stickyTop) || 0;
|
|
337
399
|
const insetRaw = getComputedStyle(this).getPropertyValue("--spacing-8")
|
|
338
400
|
.trim();
|
|
339
401
|
const insetPx = parseLengthToPx(insetRaw) || 8;
|
|
340
|
-
if (barPx > 0) return barPx + insetPx;
|
|
402
|
+
if (barPx > 0) return barPx + insetPx + stickyTopPx;
|
|
341
403
|
const fallback = getComputedStyle(this).getPropertyValue("--spacing-128")
|
|
342
404
|
.trim();
|
|
343
405
|
return parseLengthToPx(fallback) || 128;
|
|
@@ -413,6 +475,7 @@ class BdAnchorNav extends LitElement {
|
|
|
413
475
|
>${title}</bd-link>
|
|
414
476
|
`;
|
|
415
477
|
})}
|
|
478
|
+
<span class="anchor-indicator" aria-hidden="true"></span>
|
|
416
479
|
</div>
|
|
417
480
|
`;
|
|
418
481
|
|
|
@@ -27,6 +27,9 @@ prin \`ResizeObserver\` — fără a fi necesară setarea manuală a \`max-width
|
|
|
27
27
|
- Când navul iese din viewport, devine \`position: fixed\` full-width
|
|
28
28
|
- Border-ul și background-ul sunt full-width
|
|
29
29
|
- Conținutul (linkuri + CTA) rămâne centrat și aliniat cu cel mai lat sibling
|
|
30
|
+
- Dacă mai există un alt element sticky **deasupra** lui (ex. un header/page-switcher
|
|
31
|
+
propriu sticky la \`top: 0\`), setează \`sticky-top\` cu înălțimea acelui element —
|
|
32
|
+
altfel cele două se suprapun, fiindcă implicit navul se lipește tot la \`top: 0\`.
|
|
30
33
|
|
|
31
34
|
---
|
|
32
35
|
|
|
@@ -76,6 +79,18 @@ prin \`ResizeObserver\` — fără a fi necesară setarea manuală a \`max-width
|
|
|
76
79
|
></bd-anchor-nav>
|
|
77
80
|
\`\`\`
|
|
78
81
|
|
|
82
|
+
### Utilizare cu \`sticky-top\` (nav secundar sub un header sticky propriu)
|
|
83
|
+
\`\`\`html
|
|
84
|
+
<my-sticky-header></my-sticky-header>
|
|
85
|
+
|
|
86
|
+
<bd-anchor-nav sticky-top="64px" cta-label="Buy now" cta-href="#pricing">
|
|
87
|
+
<bd-anchor-nav-item title="Overview" href="#overview"></bd-anchor-nav-item>
|
|
88
|
+
<bd-anchor-nav-item title="Pricing" href="#pricing"></bd-anchor-nav-item>
|
|
89
|
+
</bd-anchor-nav>
|
|
90
|
+
\`\`\`
|
|
91
|
+
\`64px\` trebuie să fie înălțimea reală (măsurată în DevTools) a elementului sticky de deasupra —
|
|
92
|
+
nu-i o valoare universală, depinde de conținutul acelui header.
|
|
93
|
+
|
|
79
94
|
---
|
|
80
95
|
|
|
81
96
|
### Atribute \`bd-anchor-nav\`
|
|
@@ -85,6 +100,7 @@ prin \`ResizeObserver\` — fără a fi necesară setarea manuală a \`max-width
|
|
|
85
100
|
| \`cta-href\` | String | \`"#section-pricing"\` | href-ul butonului CTA fallback |
|
|
86
101
|
| \`aria-label\` | String | \`"Section navigation"\` | Label accesibil pentru \`<nav>\` |
|
|
87
102
|
| \`items\` | Array | — | \`{ title, href }[]\` — suprascrie child items |
|
|
103
|
+
| \`sticky-top\` | String | \`"0px"\` | Cât de departe de vârful viewport-ului se lipește navul când devine sticky — setează-l la înălțimea oricărui alt element sticky de deasupra, ca să nu se suprapună |
|
|
88
104
|
|
|
89
105
|
### Atribute \`bd-anchor-nav-item\`
|
|
90
106
|
| Atribut | Tip | Descriere |
|
|
@@ -114,6 +130,12 @@ Pe mobile devine automat full-width prin \`::slotted([slot="cta"])\`.
|
|
|
114
130
|
control : "object",
|
|
115
131
|
description: "Array de { title, href } — suprascrie child elements",
|
|
116
132
|
table : { type: { summary: "{ title: string, href: string }[]" }, category: "Content" }
|
|
133
|
+
},
|
|
134
|
+
stickyTop: {
|
|
135
|
+
name : "sticky-top",
|
|
136
|
+
control : "text",
|
|
137
|
+
description: "Cât de departe de vârful viewport-ului se lipește navul când devine sticky — setează-l la înălțimea oricărui element sticky de deasupra (ex. un header propriu), ca sa nu se suprapună la scroll",
|
|
138
|
+
table : { type: { summary: "string" }, defaultValue: { summary: "0px" }, category: "Sticky" }
|
|
117
139
|
}
|
|
118
140
|
}
|
|
119
141
|
};
|
|
@@ -404,6 +426,65 @@ export const WithScrollTargets = {
|
|
|
404
426
|
}
|
|
405
427
|
};
|
|
406
428
|
|
|
429
|
+
export const StickyBelowFixedHeader = {
|
|
430
|
+
name : "Sticky sub un header propriu — sticky-top",
|
|
431
|
+
render: () => html`
|
|
432
|
+
<div>
|
|
433
|
+
<!-- Simuleaza un header sticky separat (ex. bd-page-switcher), la fel
|
|
434
|
+
pozitionat: position: sticky; top: 0. Fara sticky-top pe nav,
|
|
435
|
+
cele doua s-ar suprapune identic la scroll. -->
|
|
436
|
+
<div style="
|
|
437
|
+
position: sticky; top: 0; z-index: 200;
|
|
438
|
+
background: #0a1a2f; color: #fff;
|
|
439
|
+
padding: 16px 24px; box-sizing: border-box;
|
|
440
|
+
font-family: sans-serif; font-weight: 700; font-size: 18px;
|
|
441
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
442
|
+
">
|
|
443
|
+
<span>Mock Header (simulează bd-page-switcher, ~64px înălțime)</span>
|
|
444
|
+
<span style="opacity: .7; font-weight: 400; font-size: 13px;">Tab A · Tab B</span>
|
|
445
|
+
</div>
|
|
446
|
+
|
|
447
|
+
<bd-anchor-nav
|
|
448
|
+
sticky-top="64px"
|
|
449
|
+
cta-label="Buy now"
|
|
450
|
+
cta-href="#anchor-3-section"
|
|
451
|
+
>
|
|
452
|
+
<bd-anchor-nav-item title="Overview" href="#anchor-1-section"></bd-anchor-nav-item>
|
|
453
|
+
<bd-anchor-nav-item title="Features" href="#anchor-2-section"></bd-anchor-nav-item>
|
|
454
|
+
<bd-anchor-nav-item title="Pricing" href="#anchor-3-section"></bd-anchor-nav-item>
|
|
455
|
+
</bd-anchor-nav>
|
|
456
|
+
|
|
457
|
+
<div style="max-width: 800px; margin: 0 auto;">
|
|
458
|
+
<div id="anchor-1-section" style="min-height: 60vh; padding: 80px 24px; background: #EDF9FF;">
|
|
459
|
+
<bd-h as="h2">Overview Section</bd-h>
|
|
460
|
+
<bd-p kind="regular">
|
|
461
|
+
Scroll în jos: mock header-ul de sus rămâne fix la top: 0, iar
|
|
462
|
+
bd-anchor-nav se lipește exact sub el (la 64px), nu peste el.
|
|
463
|
+
</bd-p>
|
|
464
|
+
</div>
|
|
465
|
+
<div id="anchor-2-section" style="min-height: 60vh; padding: 80px 24px; background: #fff;">
|
|
466
|
+
<bd-h as="h2">Features Section</bd-h>
|
|
467
|
+
</div>
|
|
468
|
+
<div id="anchor-3-section" style="min-height: 60vh; padding: 80px 24px; background: #EDF9FF;">
|
|
469
|
+
<bd-h as="h2">Pricing Section</bd-h>
|
|
470
|
+
</div>
|
|
471
|
+
</div>
|
|
472
|
+
</div>
|
|
473
|
+
`,
|
|
474
|
+
parameters: {
|
|
475
|
+
docs: {
|
|
476
|
+
description: {
|
|
477
|
+
story: `Reproduce cazul real din demo-ul AI Guardian / Skill Scanner: un header sticky
|
|
478
|
+
propriu deasupra (aici simulat printr-un \`<div>\`, în producție \`bd-page-switcher\`)
|
|
479
|
+
și \`bd-anchor-nav\` cu \`sticky-top="64px"\`. Fără acest atribut, ambele s-ar
|
|
480
|
+
fixa la \`top: 0\` și s-ar suprapune perfect la scroll. Valoarea \`64px\` trebuie
|
|
481
|
+
să corespundă înălțimii reale a elementului sticky de deasupra — verifică în
|
|
482
|
+
DevTools dacă diferă la tine.`
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
};
|
|
487
|
+
|
|
407
488
|
export const MobileView = {
|
|
408
489
|
name : "Mobile View",
|
|
409
490
|
render : () => renderWithSlotCta(["Overview", "Features", "Reviews", "Pricing"]),
|
|
@@ -420,9 +501,10 @@ export const MobileView = {
|
|
|
420
501
|
export const Playground = {
|
|
421
502
|
name: "Playground",
|
|
422
503
|
args: {
|
|
423
|
-
ctaLabel: "Buy now",
|
|
424
|
-
ctaHref
|
|
425
|
-
|
|
504
|
+
ctaLabel : "Buy now",
|
|
505
|
+
ctaHref : "#section-pricing",
|
|
506
|
+
stickyTop: "0px",
|
|
507
|
+
items : [
|
|
426
508
|
{ title: "Overview", href: "#anchor-1-section" },
|
|
427
509
|
{ title: "Features", href: "#anchor-2-section" },
|
|
428
510
|
{ title: "Reviews", href: "#anchor-3-section" },
|
|
@@ -433,13 +515,14 @@ export const Playground = {
|
|
|
433
515
|
<bd-anchor-nav
|
|
434
516
|
cta-label=${args.ctaLabel}
|
|
435
517
|
cta-href=${args.ctaHref}
|
|
518
|
+
sticky-top=${args.stickyTop}
|
|
436
519
|
.items=${args.items}
|
|
437
520
|
></bd-anchor-nav>
|
|
438
521
|
`,
|
|
439
522
|
parameters: {
|
|
440
523
|
docs: {
|
|
441
524
|
description: {
|
|
442
|
-
story: "Playground interactiv. Editează `items`, `ctaLabel` și `
|
|
525
|
+
story: "Playground interactiv. Editează `items`, `ctaLabel`, `ctaHref` și `sticky-top` din Controls."
|
|
443
526
|
}
|
|
444
527
|
}
|
|
445
528
|
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { html } from "lit";
|
|
2
|
+
import "../button/button.js";
|
|
3
|
+
import "./cta-banner.js";
|
|
4
|
+
|
|
5
|
+
export default {
|
|
6
|
+
title : "Components/CtaBanner",
|
|
7
|
+
tags : ["autodocs"],
|
|
8
|
+
parameters: {
|
|
9
|
+
layout: "fullscreen",
|
|
10
|
+
docs : {
|
|
11
|
+
description: {
|
|
12
|
+
component: `
|
|
13
|
+
Full-width closing call-to-action banner on a blue gradient background —
|
|
14
|
+
centered title, description, one or two buttons, and an optional small
|
|
15
|
+
mono caption underneath.
|
|
16
|
+
|
|
17
|
+
\`\`\`html
|
|
18
|
+
<bd-cta-banner
|
|
19
|
+
title="Run your AI agents with a guardrail"
|
|
20
|
+
description="AI Guardian is in open BETA on macOS. Download the BETA and secure your agentic workflows."
|
|
21
|
+
caption="Downloads the macOS BETA (.dmg). Free during BETA."
|
|
22
|
+
>
|
|
23
|
+
<bd-button-link slot="primary-button" kind="white" strong>Download BETA Today</bd-button-link>
|
|
24
|
+
<bd-button-link slot="secondary-button" kind="outline-white" strong>Read the docs</bd-button-link>
|
|
25
|
+
</bd-cta-banner>
|
|
26
|
+
\`\`\`
|
|
27
|
+
|
|
28
|
+
### Attribute table
|
|
29
|
+
| Attribute / slot | Type | Description |
|
|
30
|
+
|---|---|---|
|
|
31
|
+
| \`title\` / \`slot="title"\` | String | Large centred heading |
|
|
32
|
+
| \`description\` / \`slot="description"\` | String | Paragraph under the title |
|
|
33
|
+
| \`slot="primary-button"\` | — | First button, typically \`kind="white"\` |
|
|
34
|
+
| \`slot="secondary-button"\` | — | Second button, typically \`kind="outline-white"\` |
|
|
35
|
+
| \`caption\` / \`slot="caption"\` | String | Optional small mono line under the buttons |
|
|
36
|
+
|
|
37
|
+
Buttons are expected to use \`bd-button-link\` with \`kind="white"\` /
|
|
38
|
+
\`kind="outline-white"\` and \`strong\`, so they read against the blue
|
|
39
|
+
background — that pairing isn't enforced by the component, just the
|
|
40
|
+
convention used everywhere it's been placed so far.
|
|
41
|
+
`
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// ─── Cu caption (AI Guardian) ──────────────────────────────────────────────
|
|
48
|
+
|
|
49
|
+
export const WithCaption = {
|
|
50
|
+
name : "Cu caption",
|
|
51
|
+
render: () => html`
|
|
52
|
+
<bd-cta-banner
|
|
53
|
+
title="Run your AI agents with a guardrail"
|
|
54
|
+
description="AI Guardian is in open BETA on macOS. Download the BETA and secure your agentic workflows."
|
|
55
|
+
caption="Downloads the macOS BETA (.dmg). Free during BETA."
|
|
56
|
+
>
|
|
57
|
+
<bd-button-link
|
|
58
|
+
slot="primary-button"
|
|
59
|
+
label="Download BETA Today"
|
|
60
|
+
kind="white"
|
|
61
|
+
size="md"
|
|
62
|
+
strong
|
|
63
|
+
>Download BETA Today</bd-button-link>
|
|
64
|
+
|
|
65
|
+
<bd-button-link
|
|
66
|
+
slot="secondary-button"
|
|
67
|
+
label="Read the docs"
|
|
68
|
+
kind="outline-white"
|
|
69
|
+
size="md"
|
|
70
|
+
strong
|
|
71
|
+
>Read the docs</bd-button-link>
|
|
72
|
+
</bd-cta-banner>
|
|
73
|
+
`
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// ─── Fara caption (Skill Scanner) ──────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
export const WithoutCaption = {
|
|
79
|
+
name : "Fără caption",
|
|
80
|
+
render: () => html`
|
|
81
|
+
<bd-cta-banner
|
|
82
|
+
title="Scan before you trust"
|
|
83
|
+
description="A skill is code you hand to your agent. One command stands between you and running it blind."
|
|
84
|
+
>
|
|
85
|
+
<bd-button-link
|
|
86
|
+
slot="primary-button"
|
|
87
|
+
label="Install with npx"
|
|
88
|
+
kind="white"
|
|
89
|
+
size="md"
|
|
90
|
+
strong
|
|
91
|
+
>Install with npx</bd-button-link>
|
|
92
|
+
|
|
93
|
+
<bd-button-link
|
|
94
|
+
slot="secondary-button"
|
|
95
|
+
label="View on GitHub"
|
|
96
|
+
kind="outline-white"
|
|
97
|
+
size="md"
|
|
98
|
+
strong
|
|
99
|
+
>View on GitHub</bd-button-link>
|
|
100
|
+
</bd-cta-banner>
|
|
101
|
+
`
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// ─── Un singur buton ────────────────────────────────────────────────────────
|
|
105
|
+
|
|
106
|
+
export const SingleButton = {
|
|
107
|
+
name : "Un singur buton",
|
|
108
|
+
render: () => html`
|
|
109
|
+
<bd-cta-banner
|
|
110
|
+
title="Ready to get started?"
|
|
111
|
+
description="Free during BETA, no waitlist and no licence key."
|
|
112
|
+
>
|
|
113
|
+
<bd-button-link
|
|
114
|
+
slot="primary-button"
|
|
115
|
+
label="Install now"
|
|
116
|
+
kind="white"
|
|
117
|
+
size="md"
|
|
118
|
+
strong
|
|
119
|
+
>Install now</bd-button-link>
|
|
120
|
+
</bd-cta-banner>
|
|
121
|
+
`
|
|
122
|
+
};
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { html } from "lit";
|
|
2
|
+
import "../compatibility-table/compatibility-table.js";
|
|
3
|
+
import "../heading/heading.js";
|
|
4
|
+
import "../paragraph/paragraph.js";
|
|
5
|
+
import "./install-options.js";
|
|
6
|
+
|
|
7
|
+
export default {
|
|
8
|
+
title : "Components/InstallOptions",
|
|
9
|
+
tags : ["autodocs"],
|
|
10
|
+
parameters: {
|
|
11
|
+
layout: "fullscreen",
|
|
12
|
+
docs : {
|
|
13
|
+
description: {
|
|
14
|
+
component: `
|
|
15
|
+
Section container (eyebrow + title + description on a light blue background)
|
|
16
|
+
for "how to get this" style pages. Three ways to fill it, usable on their
|
|
17
|
+
own or combined:
|
|
18
|
+
|
|
19
|
+
1. **Cards grid** (\`.cards\`) — a row of install-method cards, each with an
|
|
20
|
+
optional badge, a copyable code block, and a link.
|
|
21
|
+
2. **"Then just ask" prompt panel** (\`prompt-panel\` + slots) — a copyable
|
|
22
|
+
prompt block with a label, a warning-style note, and a footer line.
|
|
23
|
+
3. **Generic default slot** — anything else (a table, a checklist, a note)
|
|
24
|
+
that doesn't fit the cards grid, while still getting the shared
|
|
25
|
+
eyebrow/title/description header.
|
|
26
|
+
|
|
27
|
+
\`\`\`html
|
|
28
|
+
<!-- Cards + Works in pills -->
|
|
29
|
+
<bd-install-options
|
|
30
|
+
eyebrow="Get it"
|
|
31
|
+
title="Three ways to install"
|
|
32
|
+
description="..."
|
|
33
|
+
></bd-install-options>
|
|
34
|
+
|
|
35
|
+
<!-- Generic slot instead of cards -->
|
|
36
|
+
<bd-install-options eyebrow="Trust & transparency" title="What leaves your machine">
|
|
37
|
+
<bd-compatibility-table variant="risk" .columns=\${["Mode", "Transmitted"]} .rows=\${[...]}></bd-compatibility-table>
|
|
38
|
+
</bd-install-options>
|
|
39
|
+
\`\`\`
|
|
40
|
+
|
|
41
|
+
### Attribute / property table
|
|
42
|
+
| Name | Type | Default | Description |
|
|
43
|
+
|---|---|---|---|
|
|
44
|
+
| \`eyebrow\` | String | — | Small blue label above the title |
|
|
45
|
+
| \`title\` | String | — | Section heading |
|
|
46
|
+
| \`description\` | String | — | Paragraph under the title |
|
|
47
|
+
| \`.worksIn\` | Array | \`[]\` | \`[{ label, initial, color }]\` — pill row. \`initial\`/\`color\` are placeholders (a letter on a solid circle) until real brand marks are available |
|
|
48
|
+
| \`.cards\` | Array | \`[]\` | \`[{ title, badge, description, code, linkLabel, linkHref }]\` — rendered only if non-empty |
|
|
49
|
+
| *(default slot)* | — | — | Anything else — renders between the description/works-in row and the cards grid |
|
|
50
|
+
| \`prompt-panel\` | Boolean | \`false\` | Shows the "Then just ask" sub-panel below the cards |
|
|
51
|
+
| \`prompt-label\` | String | — | Small mono label above the prompt code block |
|
|
52
|
+
|
|
53
|
+
### Slots (only used when \`prompt-panel\` is set)
|
|
54
|
+
| Slot | Description |
|
|
55
|
+
|---|---|
|
|
56
|
+
| \`prompt-title\` | Heading of the sub-panel |
|
|
57
|
+
| \`prompt-description\` | Paragraph under that heading |
|
|
58
|
+
| \`prompt\` | The copyable prompt text — the Copy button reads this slot's \`textContent\` |
|
|
59
|
+
| \`prompt-note\` | Warning-style note box |
|
|
60
|
+
| \`prompt-footer\` | Closing line (e.g. uninstall instructions) |
|
|
61
|
+
`
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
// ─── Carduri + Works in (cazul principal: "Three ways to install") ────────
|
|
68
|
+
|
|
69
|
+
export const CardsWithWorksIn = {
|
|
70
|
+
name : "Carduri + Works in",
|
|
71
|
+
render: () => html`
|
|
72
|
+
<bd-install-options
|
|
73
|
+
eyebrow="Get it"
|
|
74
|
+
title="Three ways to install"
|
|
75
|
+
description="Agent Skill Scanner installs in under a minute with npx via skills.sh, by cloning the GitHub repository, or as a zip archive you drop into your skills directory. It runs inside your agent harness and installs its own Python dependencies on first use."
|
|
76
|
+
.worksIn=${[
|
|
77
|
+
{ label: "Claude Code", initial: "✻", color: "#d97706" },
|
|
78
|
+
{ label: "Codex", initial: "◒", color: "#111827" },
|
|
79
|
+
{ label: "OpenClaw", initial: "▣", color: "#dc2626" },
|
|
80
|
+
{ label: "opencode", initial: "▪", color: "#111827" },
|
|
81
|
+
{ label: "Hermes Agent", initial: "H", color: "#111827" }
|
|
82
|
+
]}
|
|
83
|
+
.cards=${[
|
|
84
|
+
{
|
|
85
|
+
title : "With npx, from skills.sh",
|
|
86
|
+
badge : "Recommended",
|
|
87
|
+
description: "One command via the skills.sh installer. Works for any supported harness.",
|
|
88
|
+
code : "npx skills add bitdefender/agent-skill-scanner",
|
|
89
|
+
linkLabel : "View on skills.sh",
|
|
90
|
+
linkHref : "#"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
title : "From GitHub",
|
|
94
|
+
description: "Clone the repository and copy the inner agent-skill-scanner/ folder into your skills directory.",
|
|
95
|
+
code : "git clone https://github.com/bitdefender/agent-skill-scanner.git\ncp -r agent-skill-scanner/agent-skill-scanner ~/.claude/skills/",
|
|
96
|
+
linkLabel : "View the repository",
|
|
97
|
+
linkHref : "#"
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
title : "As a zip archive",
|
|
101
|
+
description: "Download the archive, unzip it, and move the inner agent-skill-scanner/ folder into your skills directory.",
|
|
102
|
+
linkLabel : "Download the zip",
|
|
103
|
+
linkHref : "#"
|
|
104
|
+
}
|
|
105
|
+
]}
|
|
106
|
+
></bd-install-options>
|
|
107
|
+
`
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// ─── Carduri + prompt panel ("Then just ask") ──────────────────────────────
|
|
111
|
+
|
|
112
|
+
export const WithPromptPanel = {
|
|
113
|
+
name : "Carduri + prompt panel",
|
|
114
|
+
parameters: {
|
|
115
|
+
docs: {
|
|
116
|
+
description: {
|
|
117
|
+
story: "Aceleași carduri, plus sub-panelul \"Then just ask\" activat prin `prompt-panel`. Butonul Copy citește textul din `slot=\"prompt\"` la click, indiferent de markup."
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
render: () => html`
|
|
122
|
+
<bd-install-options
|
|
123
|
+
eyebrow="Get it"
|
|
124
|
+
title="Three ways to install"
|
|
125
|
+
description="Agent Skill Scanner installs in under a minute with npx via skills.sh, by cloning the GitHub repository, or as a zip archive you drop into your skills directory."
|
|
126
|
+
.cards=${[
|
|
127
|
+
{
|
|
128
|
+
title : "With npx, from skills.sh",
|
|
129
|
+
badge : "Recommended",
|
|
130
|
+
description: "One command via the skills.sh installer.",
|
|
131
|
+
code : "npx skills add bitdefender/agent-skill-scanner",
|
|
132
|
+
linkLabel : "View on skills.sh",
|
|
133
|
+
linkHref : "#"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
title : "From GitHub",
|
|
137
|
+
description: "Clone the repository into your skills directory.",
|
|
138
|
+
code : "git clone https://github.com/bitdefender/agent-skill-scanner.git",
|
|
139
|
+
linkLabel : "View the repository",
|
|
140
|
+
linkHref : "#"
|
|
141
|
+
}
|
|
142
|
+
]}
|
|
143
|
+
prompt-panel
|
|
144
|
+
prompt-label="Prompt for your agent"
|
|
145
|
+
>
|
|
146
|
+
<span slot="prompt-title">Then just ask</span>
|
|
147
|
+
<span slot="prompt-description">There is no command to learn. Once installed, paste this prompt into your agent; it handles invocation, target resolution and update checks.</span>
|
|
148
|
+
<span slot="prompt">Scan the <skill name or path> skill for security risks and show me the report.</span>
|
|
149
|
+
<bd-p slot="prompt-note" kind="small">Requires Python 3.12 or 3.13 (3.13 recommended). Dependencies install on first use.</bd-p>
|
|
150
|
+
<span slot="prompt-footer">To uninstall, delete the agent-skill-scanner folder from your skills directory.</span>
|
|
151
|
+
</bd-install-options>
|
|
152
|
+
`
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
// ─── Slot generic in loc de carduri (tabel + checklist + nota) ────────────
|
|
156
|
+
|
|
157
|
+
export const GenericSlotContent = {
|
|
158
|
+
name : "Slot generic (tabel + checklist + notă)",
|
|
159
|
+
parameters: {
|
|
160
|
+
docs: {
|
|
161
|
+
description: {
|
|
162
|
+
story: "Aceeași secțiune (eyebrow + titlu + descriere pe fundal albastru), dar fără `.cards` deloc — în schimb, orice conținut arbitrar prin slotul generic: aici un `bd-compatibility-table` (variant `risk`, cu antete custom prin `.columns`), o casetă cu checklist, și o notă de avertizare, scrise ca markup simplu în locul consumator."
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
render: () => html`
|
|
167
|
+
<bd-install-options
|
|
168
|
+
eyebrow="Trust & transparency"
|
|
169
|
+
title="What leaves your machine"
|
|
170
|
+
description="Two modes, both agent-driven. Scan is the default: only hashes, extracted indicators and metadata are transmitted, and full files are never uploaded. Submit is opt-in: the complete skill archive is uploaded for deeper analysis, and only when you explicitly ask for it."
|
|
171
|
+
>
|
|
172
|
+
<bd-compatibility-table
|
|
173
|
+
variant="risk"
|
|
174
|
+
.columns=${["Mode", "Transmitted"]}
|
|
175
|
+
.rows=${[
|
|
176
|
+
{
|
|
177
|
+
category: "Scan (default)",
|
|
178
|
+
coverage: "File hashes (SHA-256/MD5), extracted indicators and pattern matches. Full file contents are not transmitted."
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
category: "Submit (opt-in)",
|
|
182
|
+
coverage: "The complete skill archive, uploaded for deep analysis. The agent will not do this unless you explicitly ask."
|
|
183
|
+
}
|
|
184
|
+
]}
|
|
185
|
+
></bd-compatibility-table>
|
|
186
|
+
|
|
187
|
+
<div style="background: var(--color-neutral-0); border: 1px solid var(--color-neutral-100); border-radius: var(--radius-xl); padding: 24px; box-sizing: border-box; margin-top: 24px;">
|
|
188
|
+
<bd-h as="h3" style="margin: 0 0 16px;">The contract the agent is held to</bd-h>
|
|
189
|
+
<ul style="list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 16px;">
|
|
190
|
+
<li style="display: flex; align-items: flex-start; gap: 12px;">
|
|
191
|
+
<span aria-hidden="true" style="flex-shrink: 0; width: 20px; height: 20px; border-radius: 999px; background: var(--color-green-600, #16a34a); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; margin-top: 2px;">✓</span>
|
|
192
|
+
<bd-p kind="regular" style="margin:0;">Scan mode is the default: a casual request never uploads your files.</bd-p>
|
|
193
|
+
</li>
|
|
194
|
+
<li style="display: flex; align-items: flex-start; gap: 12px;">
|
|
195
|
+
<span aria-hidden="true" style="flex-shrink: 0; width: 20px; height: 20px; border-radius: 999px; background: var(--color-green-600, #16a34a); color: #fff; display: flex; align-items: center; justify-content: center; font-size: 12px; font-weight: 700; margin-top: 2px;">✓</span>
|
|
196
|
+
<bd-p kind="regular" style="margin:0;">Submit is opt-in only: the agent won't upload the full archive unless you explicitly ask.</bd-p>
|
|
197
|
+
</li>
|
|
198
|
+
</ul>
|
|
199
|
+
</div>
|
|
200
|
+
|
|
201
|
+
<div style="background: var(--color-yellow-50, #fffbeb); border: 1px solid var(--color-yellow-300, #fcd34d); border-radius: var(--radius-md); padding: 16px 20px; color: var(--color-yellow-800, #92400e); margin-top: 24px;">
|
|
202
|
+
<bd-p kind="small" style="margin:0;">A scan that returns no findings means no known threat patterns were detected — not that the skill is safe.</bd-p>
|
|
203
|
+
</div>
|
|
204
|
+
</bd-install-options>
|
|
205
|
+
`
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
// ─── Doar header, fara carduri si fara slot ────────────────────────────────
|
|
209
|
+
|
|
210
|
+
export const HeaderOnly = {
|
|
211
|
+
name : "Doar header (fără carduri, fără slot)",
|
|
212
|
+
render: () => html`
|
|
213
|
+
<bd-install-options
|
|
214
|
+
eyebrow="Get it"
|
|
215
|
+
title="Coming soon"
|
|
216
|
+
description="Installation instructions will appear here once the package is published."
|
|
217
|
+
></bd-install-options>
|
|
218
|
+
`
|
|
219
|
+
};
|