@bluevolt-tech/lumen 1.3.2 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/bv-button/bv-button.js +2 -182
- package/dist/components/bv-course-detail-modal/bv-course-detail-modal.js +2 -182
- package/dist/components/bv-course-grid-card/bv-course-grid-card.d.ts +12 -0
- package/dist/components/bv-course-grid-card/bv-course-grid-card.js +87 -185
- package/dist/components/bv-course-list-card/bv-course-list-card.d.ts +11 -0
- package/dist/components/bv-course-list-card/bv-course-list-card.js +77 -185
- package/dist/components/bv-empty-state/bv-empty-state.d.ts +22 -1
- package/dist/components/bv-empty-state/bv-empty-state.js +410 -5
- package/dist/components/bv-empty-state/illustrations.d.ts +3 -0
- package/dist/components/bv-filter-panel/bv-filter-panel.d.ts +4 -0
- package/dist/components/bv-filter-panel/bv-filter-panel.js +30 -3
- package/dist/components/bv-portal-header/bv-portal-header.d.ts +1 -0
- package/dist/components/bv-portal-header/bv-portal-header.js +99 -195
- package/dist/components/bv-promo-banner/bv-promo-banner.d.ts +4 -0
- package/dist/components/bv-promo-banner/bv-promo-banner.js +16 -1
- package/dist/components/bv-user-row/bv-user-row.d.ts +6 -0
- package/dist/components/bv-user-row/bv-user-row.js +59 -193
- package/dist/storybook/stories/screens/course-catalog.data.js +1842 -153
- package/dist/themes/base.css +1 -1
- package/package.json +1 -1
- package/themes/base.css +1 -1
|
@@ -1,188 +1,8 @@
|
|
|
1
1
|
// css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-course-grid-card/bv-course-grid-card.css
|
|
2
|
-
var bv_course_grid_card_default = ":host {\n display: block;\n}\n\n.card {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-sm);\n padding: 12px;\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-xl);\n box-shadow: var(--bv-shadow-sm);\n cursor: pointer;\n transition:\n background var(--bv-transition-fast),\n border-color var(--bv-transition-fast),\n box-shadow var(--bv-transition-fast);\n}\n\n:host([selected]) .card {\n background: var(--bv-color-primary-50);\n border-color: var(--bv-color-primary);\n box-shadow: none;\n}\n\n/* Thumbnail */\n.thumbnail-wrap {\n position: relative;\n width: 100%;\n height: 153px;\n border-radius: var(--bv-radius-lg);\n overflow: hidden;\n background: var(--bv-color-neutral-200);\n flex-shrink: 0;\n}\n\n.thumbnail {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.status-badge {\n position: absolute;\n top: 6px;\n right: 6px;\n padding: 0 var(--bv-spacing-sm);\n border-radius: var(--bv-radius-sm);\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n line-height: 18px;\n background: var(--bv-color-success-light);\n color: var(--bv-color-success-dark);\n}\n\n/* Content */\n.content {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n min-width: 0;\n}\n\n.title {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-900);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.publisher {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-500);\n}\n\n.publisher strong {\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-900);\n}\n\n.description {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-700);\n line-height: 20px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n margin: 0;\n}\n\n.info-row {\n display: flex;\n gap: var(--bv-spacing-md);\n margin-top: 2px;\n}\n\n.info-item {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-900);\n}\n\n.info-item strong {\n font-weight: var(--bv-font-weight-bold);\n}\n\n/* Actions */\n.actions {\n display: flex;\n gap: var(--bv-spacing-sm);\n align-items: stretch;\n}\n\n.primary-action {\n display: block;\n flex: 1;\n min-width: 0;\n}\n\n.secondary-action {\n display: block;\n width: 48px;\n flex-shrink: 0;\n}\n";
|
|
2
|
+
var bv_course_grid_card_default = ":host {\n display: block;\n}\n\n.card {\n display: flex;\n flex-direction: column;\n gap: var(--bv-spacing-sm);\n padding: 12px;\n background: var(--bv-color-neutral-0);\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-xl);\n box-shadow: var(--bv-shadow-sm);\n cursor: pointer;\n transition:\n background var(--bv-transition-fast),\n border-color var(--bv-transition-fast),\n box-shadow var(--bv-transition-fast);\n}\n\n:host([selected]) .card {\n background: var(--bv-color-primary-50);\n border-color: var(--bv-color-primary);\n box-shadow: none;\n}\n\n/* Thumbnail */\n.thumbnail-wrap {\n position: relative;\n width: 100%;\n height: 153px;\n border-radius: var(--bv-radius-lg);\n overflow: hidden;\n background: var(--bv-color-neutral-200);\n flex-shrink: 0;\n}\n\n.thumbnail {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.status-badge {\n position: absolute;\n top: 6px;\n right: 6px;\n padding: 0 var(--bv-spacing-sm);\n border-radius: var(--bv-radius-sm);\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n line-height: 18px;\n background: var(--bv-color-success-light);\n color: var(--bv-color-success-dark);\n}\n\n/* Content */\n.content {\n display: flex;\n flex-direction: column;\n gap: 4px;\n flex: 1;\n min-width: 0;\n}\n\n.title {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-neutral-900);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.publisher {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-500);\n}\n\n.publisher strong {\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-900);\n}\n\n.description {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-700);\n line-height: 20px;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n overflow: hidden;\n margin: 0;\n}\n\n.info-row {\n display: flex;\n gap: var(--bv-spacing-md);\n margin-top: 2px;\n}\n\n.info-item {\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-900);\n}\n\n.info-item strong {\n font-weight: var(--bv-font-weight-bold);\n}\n\n/* Actions */\n.actions {\n display: flex;\n gap: var(--bv-spacing-sm);\n align-items: stretch;\n}\n\n.primary-action {\n display: block;\n flex: 1;\n min-width: 0;\n}\n\n.secondary-action {\n display: block;\n width: 48px;\n flex-shrink: 0;\n}\n\n/* Disabled selection: card body is no longer interactive */\n:host([disable-selection]) .card {\n cursor: default;\n}\n\n/* Loading skeleton */\n.skeleton {\n display: none;\n flex-direction: column;\n gap: var(--bv-spacing-sm);\n flex: 1;\n min-width: 0;\n}\n\n:host([loading]) .card {\n cursor: default;\n}\n\n:host([loading]) .thumbnail-wrap,\n:host([loading]) .content,\n:host([loading]) .actions {\n display: none;\n}\n\n:host([loading]) .skeleton {\n display: flex;\n}\n\n.skeleton-thumb {\n width: 100%;\n height: 153px;\n border-radius: var(--bv-radius-lg);\n background: var(--bv-color-neutral-200);\n animation: bv-skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-line {\n height: 12px;\n border-radius: var(--bv-radius-sm);\n background: var(--bv-color-neutral-200);\n animation: bv-skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-title-line {\n height: 20px;\n width: 70%;\n}\n\n.skeleton-short-line {\n width: 45%;\n}\n\n.skeleton-actions {\n display: flex;\n gap: var(--bv-spacing-sm);\n align-items: stretch;\n margin-top: 2px;\n}\n\n.skeleton-button {\n height: 44px;\n border-radius: var(--bv-radius-md);\n background: var(--bv-color-neutral-200);\n animation: bv-skeleton-shimmer 1.5s ease-in-out infinite;\n}\n\n.skeleton-primary {\n flex: 1;\n min-width: 0;\n}\n\n.skeleton-icon-btn {\n width: 48px;\n flex-shrink: 0;\n}\n\n@keyframes bv-skeleton-shimmer {\n 0%,\n 100% {\n opacity: 1;\n }\n 50% {\n opacity: 0.5;\n }\n}\n";
|
|
3
3
|
|
|
4
4
|
// css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-button/bv-button.css
|
|
5
|
-
var bv_button_default =
|
|
6
|
-
Apps can override these three properties per-instance:
|
|
7
|
-
|
|
8
|
-
HTML: <bv-button style="--bv-button-bg: #e53e3e;">
|
|
9
|
-
Angular: <bv-button [style.--bv-button-bg]="brandColor">
|
|
10
|
-
JavaScript: btn.style.setProperty('--bv-button-bg', value)
|
|
11
|
-
|
|
12
|
-
Hover is auto-computed from the base colors via color-mix().
|
|
13
|
-
Override --bv-button-bg-hover / --bv-button-border-color-hover
|
|
14
|
-
if you need explicit control over the hovered state.
|
|
15
|
-
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
16
|
-
:host {
|
|
17
|
-
/* Default values \u2014 map to global tokens (primary variant) */
|
|
18
|
-
--bv-button-bg: var(--bv-color-primary);
|
|
19
|
-
--bv-button-bg-hover: color-mix(in srgb, var(--bv-button-bg) 82%, black);
|
|
20
|
-
--bv-button-color: var(--bv-color-neutral-0);
|
|
21
|
-
--bv-button-border-color: var(--bv-color-primary);
|
|
22
|
-
--bv-button-border-color-hover: color-mix(in srgb, var(--bv-button-border-color) 82%, black);
|
|
23
|
-
--bv-button-font-family: var(--bv-font-family-base);
|
|
24
|
-
--bv-button-font-size: var(--bv-font-size-sm);
|
|
25
|
-
|
|
26
|
-
display: inline-block;
|
|
27
|
-
font-family: var(--bv-font-family-base);
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
:host([hidden]) {
|
|
31
|
-
display: none;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
:host([full-width]) {
|
|
35
|
-
display: block;
|
|
36
|
-
width: 100%;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/* \u2500\u2500 Variant tokens \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
40
|
-
Each variant re-points the component tokens to different global
|
|
41
|
-
tokens. Apps can still override with inline styles \u2014 inline style
|
|
42
|
-
always wins due to higher specificity.
|
|
43
|
-
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
44
|
-
|
|
45
|
-
:host([variant='secondary']) {
|
|
46
|
-
--bv-button-bg: var(--bv-color-secondary);
|
|
47
|
-
--bv-button-border-color: var(--bv-color-secondary);
|
|
48
|
-
--bv-button-color: var(--bv-color-secondary-foreground);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
:host([variant='tertiary']) {
|
|
52
|
-
--bv-button-bg: var(--bv-color-tertiary);
|
|
53
|
-
--bv-button-border-color: var(--bv-color-tertiary);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
:host([variant='danger']) {
|
|
57
|
-
--bv-button-bg: var(--bv-color-danger);
|
|
58
|
-
--bv-button-border-color: var(--bv-color-danger);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
:host([variant='ghost']) {
|
|
62
|
-
--bv-button-bg: transparent;
|
|
63
|
-
--bv-button-bg-hover: var(--bv-color-primary-light);
|
|
64
|
-
--bv-button-color: var(--bv-color-primary);
|
|
65
|
-
--bv-button-border-color: transparent;
|
|
66
|
-
--bv-button-border-color-hover: transparent;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
:host([variant='outline']) {
|
|
70
|
-
--bv-button-bg: transparent;
|
|
71
|
-
--bv-button-bg-hover: var(--bv-color-primary-light);
|
|
72
|
-
--bv-button-color: var(--bv-color-primary);
|
|
73
|
-
--bv-button-border-color: var(--bv-color-primary);
|
|
74
|
-
--bv-button-border-color-hover: var(--bv-color-primary);
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/* \u2500\u2500 Base button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
|
|
78
|
-
All visual properties read from the component-level tokens above.
|
|
79
|
-
\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
|
|
80
|
-
|
|
81
|
-
.btn {
|
|
82
|
-
display: inline-flex;
|
|
83
|
-
align-items: center;
|
|
84
|
-
justify-content: center;
|
|
85
|
-
gap: var(--bv-spacing-xs);
|
|
86
|
-
padding: 10px var(--bv-spacing-md);
|
|
87
|
-
min-height: 40px;
|
|
88
|
-
width: auto;
|
|
89
|
-
font-family: var(--bv-button-font-family);
|
|
90
|
-
font-size: var(--bv-button-font-size);
|
|
91
|
-
font-style: normal;
|
|
92
|
-
font-weight: var(--bv-font-weight-semibold);
|
|
93
|
-
line-height: 20px;
|
|
94
|
-
border: 1px solid var(--bv-button-border-color);
|
|
95
|
-
border-radius: var(--bv-radius-lg);
|
|
96
|
-
cursor: pointer;
|
|
97
|
-
transition:
|
|
98
|
-
background var(--bv-transition-fast),
|
|
99
|
-
color var(--bv-transition-fast),
|
|
100
|
-
border-color var(--bv-transition-fast),
|
|
101
|
-
box-shadow var(--bv-transition-fast),
|
|
102
|
-
opacity var(--bv-transition-fast);
|
|
103
|
-
white-space: nowrap;
|
|
104
|
-
user-select: none;
|
|
105
|
-
text-decoration: none;
|
|
106
|
-
outline: none;
|
|
107
|
-
box-sizing: border-box;
|
|
108
|
-
background: var(--bv-button-bg);
|
|
109
|
-
color: var(--bv-button-color);
|
|
110
|
-
box-shadow: var(--bv-shadow-sm);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
:host([full-width]) .btn {
|
|
114
|
-
width: 100%;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
.btn:hover:not(:disabled) {
|
|
118
|
-
background: var(--bv-button-bg-hover);
|
|
119
|
-
border-color: var(--bv-button-border-color-hover);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
.btn:active:not(:disabled) {
|
|
123
|
-
transform: translateY(1px);
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
.btn:focus-visible {
|
|
127
|
-
outline: 2px solid var(--bv-button-border-color);
|
|
128
|
-
outline-offset: 2px;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
.btn:disabled {
|
|
132
|
-
opacity: 0.5;
|
|
133
|
-
cursor: not-allowed;
|
|
134
|
-
pointer-events: none;
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
/* \u2500\u2500 Sizes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500*/
|
|
138
|
-
|
|
139
|
-
:host([size='sm']) .btn {
|
|
140
|
-
padding: 6px 12px;
|
|
141
|
-
min-height: 32px;
|
|
142
|
-
font-size: var(--bv-font-size-sm);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
:host([size='lg']) .btn {
|
|
146
|
-
padding: 12px var(--bv-spacing-lg);
|
|
147
|
-
min-height: 48px;
|
|
148
|
-
font-size: var(--bv-font-size-md);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
/* \u2500\u2500 Icon \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500*/
|
|
152
|
-
|
|
153
|
-
.btn-icon {
|
|
154
|
-
display: inline-flex;
|
|
155
|
-
align-items: center;
|
|
156
|
-
flex-shrink: 0;
|
|
157
|
-
line-height: 0;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/* \u2500\u2500 Count badge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500*/
|
|
161
|
-
|
|
162
|
-
.btn-count {
|
|
163
|
-
opacity: 0.8;
|
|
164
|
-
font-weight: var(--bv-font-weight-regular);
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/* \u2500\u2500 Loading spinner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500*/
|
|
168
|
-
|
|
169
|
-
.spinner {
|
|
170
|
-
display: inline-block;
|
|
171
|
-
width: 1em;
|
|
172
|
-
height: 1em;
|
|
173
|
-
border: 2px solid currentColor;
|
|
174
|
-
border-top-color: transparent;
|
|
175
|
-
border-radius: 50%;
|
|
176
|
-
flex-shrink: 0;
|
|
177
|
-
animation: bv-spin 700ms linear infinite;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
@keyframes bv-spin {
|
|
181
|
-
to {
|
|
182
|
-
transform: rotate(360deg);
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
`;
|
|
5
|
+
var bv_button_default = "/* \u2500\u2500 Public theming API \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Apps can override these three properties per-instance:\n\n HTML: <bv-button style=\"--bv-button-bg: #e53e3e;\">\n Angular: <bv-button [style.--bv-button-bg]=\"brandColor\">\n JavaScript: btn.style.setProperty('--bv-button-bg', value)\n\n Hover is auto-computed from the base colors via color-mix().\n Override --bv-button-bg-hover / --bv-button-border-color-hover\n if you need explicit control over the hovered state.\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n:host {\n /* Default values \u2014 map to global tokens (primary variant) */\n --bv-button-bg: var(--bv-color-primary);\n --bv-button-bg-hover: color-mix(in srgb, var(--bv-button-bg) 82%, black);\n --bv-button-color: var(--bv-color-neutral-0);\n --bv-button-border-color: var(--bv-color-primary);\n --bv-button-border-color-hover: color-mix(in srgb, var(--bv-button-border-color) 82%, black);\n --bv-button-font-family: var(--bv-font-family-base);\n --bv-button-font-size: var(--bv-font-size-sm);\n\n display: inline-block;\n font-family: var(--bv-font-family-base);\n}\n\n:host([hidden]) {\n /* `!important` so `hidden` always wins over :host([full-width]) / other display rules. */\n display: none !important;\n}\n\n:host([full-width]) {\n display: block;\n width: 100%;\n}\n\n/* \u2500\u2500 Variant tokens \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Each variant re-points the component tokens to different global\n tokens. Apps can still override with inline styles \u2014 inline style\n always wins due to higher specificity.\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n:host([variant='secondary']) {\n --bv-button-bg: var(--bv-color-secondary);\n --bv-button-border-color: var(--bv-color-secondary);\n --bv-button-color: var(--bv-color-secondary-foreground);\n}\n\n:host([variant='tertiary']) {\n --bv-button-bg: var(--bv-color-tertiary);\n --bv-button-border-color: var(--bv-color-tertiary);\n}\n\n:host([variant='danger']) {\n --bv-button-bg: var(--bv-color-danger);\n --bv-button-border-color: var(--bv-color-danger);\n}\n\n:host([variant='ghost']) {\n --bv-button-bg: transparent;\n --bv-button-bg-hover: var(--bv-color-primary-light);\n --bv-button-color: var(--bv-color-primary);\n --bv-button-border-color: transparent;\n --bv-button-border-color-hover: transparent;\n}\n\n:host([variant='outline']) {\n --bv-button-bg: transparent;\n --bv-button-bg-hover: var(--bv-color-primary-light);\n --bv-button-color: var(--bv-color-primary);\n --bv-button-border-color: var(--bv-color-primary);\n --bv-button-border-color-hover: var(--bv-color-primary);\n}\n\n/* \u2500\u2500 Base button \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n All visual properties read from the component-level tokens above.\n\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: var(--bv-spacing-xs);\n padding: 10px var(--bv-spacing-md);\n min-height: 40px;\n width: auto;\n font-family: var(--bv-button-font-family);\n font-size: var(--bv-button-font-size);\n font-style: normal;\n font-weight: var(--bv-font-weight-semibold);\n line-height: 20px;\n border: 1px solid var(--bv-button-border-color);\n border-radius: var(--bv-radius-lg);\n cursor: pointer;\n transition:\n background var(--bv-transition-fast),\n color var(--bv-transition-fast),\n border-color var(--bv-transition-fast),\n box-shadow var(--bv-transition-fast),\n opacity var(--bv-transition-fast);\n white-space: nowrap;\n user-select: none;\n text-decoration: none;\n outline: none;\n box-sizing: border-box;\n background: var(--bv-button-bg);\n color: var(--bv-button-color);\n box-shadow: var(--bv-shadow-sm);\n}\n\n:host([full-width]) .btn {\n width: 100%;\n}\n\n.btn:hover:not(:disabled) {\n background: var(--bv-button-bg-hover);\n border-color: var(--bv-button-border-color-hover);\n}\n\n.btn:active:not(:disabled) {\n transform: translateY(1px);\n}\n\n.btn:focus-visible {\n outline: 2px solid var(--bv-button-border-color);\n outline-offset: 2px;\n}\n\n.btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n pointer-events: none;\n}\n\n/* \u2500\u2500 Sizes \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500*/\n\n:host([size='sm']) .btn {\n padding: 6px 12px;\n min-height: 32px;\n font-size: var(--bv-font-size-sm);\n}\n\n:host([size='lg']) .btn {\n padding: 12px var(--bv-spacing-lg);\n min-height: 48px;\n font-size: var(--bv-font-size-md);\n}\n\n/* \u2500\u2500 Icon \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500*/\n\n.btn-icon {\n display: inline-flex;\n align-items: center;\n flex-shrink: 0;\n line-height: 0;\n}\n\n/* \u2500\u2500 Count badge \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500*/\n\n.btn-count {\n opacity: 0.8;\n font-weight: var(--bv-font-weight-regular);\n}\n\n/* \u2500\u2500 Loading spinner \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500*/\n\n.spinner {\n display: inline-block;\n width: 1em;\n height: 1em;\n border: 2px solid currentColor;\n border-top-color: transparent;\n border-radius: 50%;\n flex-shrink: 0;\n animation: bv-spin 700ms linear infinite;\n}\n\n@keyframes bv-spin {\n to {\n transform: rotate(360deg);\n }\n}\n";
|
|
186
6
|
|
|
187
7
|
// components/bv-icon/icons.ts
|
|
188
8
|
var icons = {
|
|
@@ -366,7 +186,7 @@ var BvButton = class extends HTMLElement {
|
|
|
366
186
|
}
|
|
367
187
|
btn.querySelectorAll(".btn-icon").forEach((el) => el.remove());
|
|
368
188
|
const iconName = this.getAttribute("icon");
|
|
369
|
-
if (iconName) {
|
|
189
|
+
if (iconName && !this.loading) {
|
|
370
190
|
const svg = getIconSvg(iconName, 16);
|
|
371
191
|
if (svg) {
|
|
372
192
|
const iconEl = document.createElement("span");
|
|
@@ -407,8 +227,14 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
407
227
|
"primary-label",
|
|
408
228
|
"primary-variant",
|
|
409
229
|
"primary-icon",
|
|
230
|
+
"primary-loading",
|
|
231
|
+
"primary-disabled",
|
|
232
|
+
"secondary-label",
|
|
410
233
|
"secondary-icon",
|
|
411
|
-
"selected"
|
|
234
|
+
"selected",
|
|
235
|
+
"disable-selection",
|
|
236
|
+
"hide-secondary",
|
|
237
|
+
"loading"
|
|
412
238
|
];
|
|
413
239
|
get selected() {
|
|
414
240
|
return this.hasAttribute("selected");
|
|
@@ -417,6 +243,41 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
417
243
|
if (v) this.setAttribute("selected", "");
|
|
418
244
|
else this.removeAttribute("selected");
|
|
419
245
|
}
|
|
246
|
+
get disableSelection() {
|
|
247
|
+
return this.hasAttribute("disable-selection");
|
|
248
|
+
}
|
|
249
|
+
set disableSelection(v) {
|
|
250
|
+
if (v) this.setAttribute("disable-selection", "");
|
|
251
|
+
else this.removeAttribute("disable-selection");
|
|
252
|
+
}
|
|
253
|
+
get hideSecondary() {
|
|
254
|
+
return this.hasAttribute("hide-secondary");
|
|
255
|
+
}
|
|
256
|
+
set hideSecondary(v) {
|
|
257
|
+
if (v) this.setAttribute("hide-secondary", "");
|
|
258
|
+
else this.removeAttribute("hide-secondary");
|
|
259
|
+
}
|
|
260
|
+
get primaryLoading() {
|
|
261
|
+
return this.hasAttribute("primary-loading");
|
|
262
|
+
}
|
|
263
|
+
set primaryLoading(v) {
|
|
264
|
+
if (v) this.setAttribute("primary-loading", "");
|
|
265
|
+
else this.removeAttribute("primary-loading");
|
|
266
|
+
}
|
|
267
|
+
get primaryDisabled() {
|
|
268
|
+
return this.hasAttribute("primary-disabled");
|
|
269
|
+
}
|
|
270
|
+
set primaryDisabled(v) {
|
|
271
|
+
if (v) this.setAttribute("primary-disabled", "");
|
|
272
|
+
else this.removeAttribute("primary-disabled");
|
|
273
|
+
}
|
|
274
|
+
get loading() {
|
|
275
|
+
return this.hasAttribute("loading");
|
|
276
|
+
}
|
|
277
|
+
set loading(v) {
|
|
278
|
+
if (v) this.setAttribute("loading", "");
|
|
279
|
+
else this.removeAttribute("loading");
|
|
280
|
+
}
|
|
420
281
|
_rendered = false;
|
|
421
282
|
_els = {};
|
|
422
283
|
constructor() {
|
|
@@ -472,9 +333,28 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
472
333
|
var _a2;
|
|
473
334
|
(_a2 = this._els.primaryBtn) == null ? void 0 : _a2.setAttribute("icon", val ?? "");
|
|
474
335
|
},
|
|
336
|
+
"primary-loading": () => {
|
|
337
|
+
var _a2, _b;
|
|
338
|
+
if (val === null) (_a2 = this._els.primaryBtn) == null ? void 0 : _a2.removeAttribute("loading");
|
|
339
|
+
else (_b = this._els.primaryBtn) == null ? void 0 : _b.setAttribute("loading", "");
|
|
340
|
+
},
|
|
341
|
+
"primary-disabled": () => {
|
|
342
|
+
var _a2, _b;
|
|
343
|
+
if (val === null) (_a2 = this._els.primaryBtn) == null ? void 0 : _a2.removeAttribute("disabled");
|
|
344
|
+
else (_b = this._els.primaryBtn) == null ? void 0 : _b.setAttribute("disabled", "");
|
|
345
|
+
},
|
|
346
|
+
"secondary-label": () => {
|
|
347
|
+
this._syncSecondaryLabel();
|
|
348
|
+
},
|
|
475
349
|
"secondary-icon": () => {
|
|
476
350
|
var _a2;
|
|
477
351
|
(_a2 = this._els.secondaryBtn) == null ? void 0 : _a2.setAttribute("icon", val ?? "");
|
|
352
|
+
},
|
|
353
|
+
"hide-secondary": () => {
|
|
354
|
+
if (this._els.secondaryBtn) this._els.secondaryBtn.hidden = this.hideSecondary;
|
|
355
|
+
},
|
|
356
|
+
loading: () => {
|
|
357
|
+
this._syncLoading();
|
|
478
358
|
}
|
|
479
359
|
};
|
|
480
360
|
(_a = map[name]) == null ? void 0 : _a.call(map);
|
|
@@ -490,6 +370,7 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
490
370
|
}
|
|
491
371
|
const card = document.createElement("div");
|
|
492
372
|
card.className = "card";
|
|
373
|
+
this._els.card = card;
|
|
493
374
|
const thumbWrap = document.createElement("div");
|
|
494
375
|
thumbWrap.className = "thumbnail-wrap";
|
|
495
376
|
const thumb = document.createElement("img");
|
|
@@ -539,6 +420,8 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
539
420
|
primaryBtn.setAttribute("full-width", "");
|
|
540
421
|
primaryBtn.className = "primary-action";
|
|
541
422
|
primaryBtn.textContent = this.getAttribute("primary-label") ?? "Enroll Now";
|
|
423
|
+
if (this.primaryLoading) primaryBtn.setAttribute("loading", "");
|
|
424
|
+
if (this.primaryDisabled) primaryBtn.setAttribute("disabled", "");
|
|
542
425
|
primaryBtn.addEventListener("click", () => {
|
|
543
426
|
this.dispatchEvent(new CustomEvent("bv-primary-action", { bubbles: true, composed: true }));
|
|
544
427
|
});
|
|
@@ -549,15 +432,24 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
549
432
|
secondaryBtn.setAttribute("size", "lg");
|
|
550
433
|
secondaryBtn.setAttribute("full-width", "");
|
|
551
434
|
secondaryBtn.className = "secondary-action";
|
|
435
|
+
secondaryBtn.hidden = this.hideSecondary;
|
|
552
436
|
secondaryBtn.addEventListener("click", () => {
|
|
553
437
|
this.dispatchEvent(new CustomEvent("bv-secondary-action", { bubbles: true, composed: true }));
|
|
554
438
|
});
|
|
555
439
|
this._els.secondaryBtn = secondaryBtn;
|
|
440
|
+
this._syncSecondaryLabel();
|
|
556
441
|
actions.append(primaryBtn, secondaryBtn);
|
|
557
442
|
this._els.actions = actions;
|
|
558
|
-
|
|
443
|
+
const skeleton = document.createElement("div");
|
|
444
|
+
skeleton.className = "skeleton";
|
|
445
|
+
skeleton.setAttribute("aria-hidden", "true");
|
|
446
|
+
skeleton.innerHTML = '<div class="skeleton-thumb"></div><div class="skeleton-line skeleton-title-line"></div><div class="skeleton-line skeleton-short-line"></div><div class="skeleton-line"></div><div class="skeleton-line skeleton-short-line"></div><div class="skeleton-actions"><div class="skeleton-button skeleton-primary"></div><div class="skeleton-button skeleton-icon-btn"></div></div>';
|
|
447
|
+
this._els.skeleton = skeleton;
|
|
448
|
+
card.append(thumbWrap, content, actions, skeleton);
|
|
559
449
|
shadow.appendChild(card);
|
|
450
|
+
this._syncLoading();
|
|
560
451
|
card.addEventListener("click", (e) => {
|
|
452
|
+
if (this.disableSelection || this.loading) return;
|
|
561
453
|
if (e.composedPath().includes(this._els.actions)) return;
|
|
562
454
|
this.selected = !this.selected;
|
|
563
455
|
this.dispatchEvent(
|
|
@@ -569,6 +461,16 @@ var BvCourseGridCard = class extends HTMLElement {
|
|
|
569
461
|
);
|
|
570
462
|
});
|
|
571
463
|
}
|
|
464
|
+
_syncSecondaryLabel() {
|
|
465
|
+
if (!this._els.secondaryBtn) return;
|
|
466
|
+
const label = this.getAttribute("secondary-label");
|
|
467
|
+
this._els.secondaryBtn.textContent = label ?? "";
|
|
468
|
+
}
|
|
469
|
+
_syncLoading() {
|
|
470
|
+
var _a;
|
|
471
|
+
const loading = this.loading;
|
|
472
|
+
(_a = this._els.card) == null ? void 0 : _a.setAttribute("aria-busy", loading ? "true" : "false");
|
|
473
|
+
}
|
|
572
474
|
};
|
|
573
475
|
if (!customElements.get("bv-course-grid-card")) {
|
|
574
476
|
customElements.define("bv-course-grid-card", BvCourseGridCard);
|
|
@@ -3,10 +3,21 @@ export declare class BvCourseListCard extends HTMLElement {
|
|
|
3
3
|
static readonly observedAttributes: string[];
|
|
4
4
|
get selected(): boolean;
|
|
5
5
|
set selected(v: boolean);
|
|
6
|
+
get disableSelection(): boolean;
|
|
7
|
+
set disableSelection(v: boolean);
|
|
8
|
+
get hideSecondary(): boolean;
|
|
9
|
+
set hideSecondary(v: boolean);
|
|
10
|
+
get primaryLoading(): boolean;
|
|
11
|
+
set primaryLoading(v: boolean);
|
|
12
|
+
get primaryDisabled(): boolean;
|
|
13
|
+
set primaryDisabled(v: boolean);
|
|
14
|
+
get loading(): boolean;
|
|
15
|
+
set loading(v: boolean);
|
|
6
16
|
private _rendered;
|
|
7
17
|
private _els;
|
|
8
18
|
constructor();
|
|
9
19
|
connectedCallback(): void;
|
|
10
20
|
attributeChangedCallback(name: string, _old: string | null, val: string | null): void;
|
|
11
21
|
private _render;
|
|
22
|
+
private _syncLoading;
|
|
12
23
|
}
|