@bluevolt-tech/lumen 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. package/README.md +286 -0
  2. package/assets/fonts/fonts.css +25 -0
  3. package/assets/icons/.gitkeep +0 -0
  4. package/assets/icons/edit.svg +3 -0
  5. package/assets/images/.gitkeep +0 -0
  6. package/assets/images/bluevolt-logo.png +0 -0
  7. package/dist/assets/fonts/fonts.css +25 -0
  8. package/dist/assets/icons/.gitkeep +0 -0
  9. package/dist/assets/icons/edit.svg +3 -0
  10. package/dist/assets/images/.gitkeep +0 -0
  11. package/dist/assets/images/bluevolt-logo.png +0 -0
  12. package/dist/components/bv-avatar/bv-avatar.d.ts +13 -0
  13. package/dist/components/bv-avatar/bv-avatar.js +81 -0
  14. package/dist/components/bv-badge/bv-badge.d.ts +11 -0
  15. package/dist/components/bv-badge/bv-badge.js +58 -0
  16. package/dist/components/bv-button/bv-button.d.ts +23 -0
  17. package/dist/components/bv-button/bv-button.js +395 -0
  18. package/dist/components/bv-category-pill/bv-category-pill.d.ts +11 -0
  19. package/dist/components/bv-category-pill/bv-category-pill.js +61 -0
  20. package/dist/components/bv-checkbox/bv-checkbox.d.ts +14 -0
  21. package/dist/components/bv-checkbox/bv-checkbox.js +89 -0
  22. package/dist/components/bv-chip/bv-chip.d.ts +11 -0
  23. package/dist/components/bv-chip/bv-chip.js +72 -0
  24. package/dist/components/bv-course-detail/bv-course-detail.d.ts +28 -0
  25. package/dist/components/bv-course-detail/bv-course-detail.js +269 -0
  26. package/dist/components/bv-course-detail-modal/bv-course-detail-modal.d.ts +35 -0
  27. package/dist/components/bv-course-detail-modal/bv-course-detail-modal.js +1455 -0
  28. package/dist/components/bv-course-grid-card/bv-course-grid-card.d.ts +12 -0
  29. package/dist/components/bv-course-grid-card/bv-course-grid-card.js +578 -0
  30. package/dist/components/bv-course-list-card/bv-course-list-card.d.ts +12 -0
  31. package/dist/components/bv-course-list-card/bv-course-list-card.js +585 -0
  32. package/dist/components/bv-course-outline/bv-course-outline.d.ts +49 -0
  33. package/dist/components/bv-course-outline/bv-course-outline.js +488 -0
  34. package/dist/components/bv-empty-state/bv-empty-state.d.ts +10 -0
  35. package/dist/components/bv-empty-state/bv-empty-state.js +69 -0
  36. package/dist/components/bv-filter-dropdown/bv-filter-dropdown.d.ts +26 -0
  37. package/dist/components/bv-filter-dropdown/bv-filter-dropdown.js +164 -0
  38. package/dist/components/bv-filter-panel/bv-filter-panel.d.ts +25 -0
  39. package/dist/components/bv-filter-panel/bv-filter-panel.js +222 -0
  40. package/dist/components/bv-icon/bv-icon.d.ts +10 -0
  41. package/dist/components/bv-icon/bv-icon.js +122 -0
  42. package/dist/components/bv-icon/icons.d.ts +3 -0
  43. package/dist/components/bv-modal/bv-modal.d.ts +13 -0
  44. package/dist/components/bv-modal/bv-modal.js +104 -0
  45. package/dist/components/bv-page-title/bv-page-title.d.ts +4 -0
  46. package/dist/components/bv-page-title/bv-page-title.js +33 -0
  47. package/dist/components/bv-pagination/bv-pagination.d.ts +20 -0
  48. package/dist/components/bv-pagination/bv-pagination.js +139 -0
  49. package/dist/components/bv-portal-header/bv-portal-header.d.ts +12 -0
  50. package/dist/components/bv-portal-header/bv-portal-header.js +854 -0
  51. package/dist/components/bv-portal-layout/bv-portal-layout.d.ts +6 -0
  52. package/dist/components/bv-portal-layout/bv-portal-layout.js +39 -0
  53. package/dist/components/bv-progress-bar/bv-progress-bar.d.ts +11 -0
  54. package/dist/components/bv-progress-bar/bv-progress-bar.js +61 -0
  55. package/dist/components/bv-promo-banner/bv-promo-banner.d.ts +12 -0
  56. package/dist/components/bv-promo-banner/bv-promo-banner.js +79 -0
  57. package/dist/components/bv-radio/bv-radio.d.ts +11 -0
  58. package/dist/components/bv-radio/bv-radio.js +78 -0
  59. package/dist/components/bv-searchbox/bv-searchbox.d.ts +10 -0
  60. package/dist/components/bv-searchbox/bv-searchbox.js +68 -0
  61. package/dist/components/bv-star-rating/bv-star-rating.d.ts +11 -0
  62. package/dist/components/bv-star-rating/bv-star-rating.js +67 -0
  63. package/dist/components/bv-table/bv-table.d.ts +5 -0
  64. package/dist/components/bv-table/bv-table.js +72 -0
  65. package/dist/components/bv-toggle/bv-toggle.d.ts +11 -0
  66. package/dist/components/bv-toggle/bv-toggle.js +72 -0
  67. package/dist/components/bv-user-row/bv-user-row.d.ts +12 -0
  68. package/dist/components/bv-user-row/bv-user-row.js +574 -0
  69. package/dist/components/bv-view-switcher/bv-view-switcher.d.ts +11 -0
  70. package/dist/components/bv-view-switcher/bv-view-switcher.js +91 -0
  71. package/dist/preview/index.html +76 -0
  72. package/dist/storybook/stories/screens/course-catalog.data.d.ts +28 -0
  73. package/dist/storybook/stories/screens/course-catalog.data.js +301 -0
  74. package/dist/themes/base.css +66 -0
  75. package/dist/themes/layouts.css +35 -0
  76. package/package.json +181 -0
  77. package/themes/base.css +66 -0
  78. package/themes/layouts.css +35 -0
@@ -0,0 +1,1455 @@
1
+ // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-course-detail-modal/bv-course-detail-modal.css
2
+ var bv_course_detail_modal_default = ":host {\n display: contents;\n font-family: var(--bv-font-family-base);\n}\n\n/* Ensure hidden attribute works on slotted custom elements */\n[hidden] {\n display: none !important;\n}\n\n.modal-body {\n display: flex;\n flex-direction: column;\n gap: 20px;\n width: 100%;\n}\n";
3
+
4
+ // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-modal/bv-modal.css
5
+ var bv_modal_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 per-instance:\n\n HTML: <bv-modal style="--bv-modal-width: 600px;">\n Angular: <bv-modal [style.--bv-modal-bg]="bgColor">\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 --bv-modal-width: 800px;\n --bv-modal-bg: var(--bv-color-neutral-0);\n --bv-modal-radius: var(--bv-radius-xl);\n --bv-modal-title-color: #101828;\n --bv-modal-backdrop: rgba(16, 24, 40, 0.6);\n --bv-modal-body-max-height: none;\n}\n\ndialog {\n padding: 0;\n border: none;\n border-radius: var(--bv-modal-radius);\n background: transparent;\n width: var(--bv-modal-width);\n max-width: min(var(--bv-modal-width), calc(100vw - 32px));\n outline: none;\n}\n\ndialog::backdrop {\n background: var(--bv-modal-backdrop);\n}\n\n.panel {\n display: flex;\n width: 100%;\n padding: 20px 16px;\n flex-direction: column;\n justify-content: center;\n align-items: flex-start;\n gap: 20px;\n border-radius: var(--bv-modal-radius);\n background: var(--bv-modal-bg);\n box-sizing: border-box;\n}\n\n/* \u2500\u2500 Header \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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.header {\n display: flex;\n width: 100%;\n align-items: center;\n justify-content: space-between;\n}\n\n.title {\n margin: 0;\n color: var(--bv-modal-title-color);\n font-family: var(--bv-font-family-base);\n font-size: 24px;\n font-style: normal;\n font-weight: var(--bv-font-weight-medium);\n line-height: 32px;\n}\n\n.close-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 32px;\n height: 32px;\n padding: 0;\n background: none;\n border: none;\n border-radius: var(--bv-radius-md);\n cursor: pointer;\n color: var(--bv-color-neutral-500);\n font-size: 18px;\n line-height: 1;\n flex-shrink: 0;\n transition:\n color var(--bv-transition-fast),\n background var(--bv-transition-fast);\n}\n\n.close-btn:hover {\n color: var(--bv-color-neutral-800);\n background: var(--bv-color-neutral-100);\n}\n\n/* \u2500\u2500 Separator \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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.separator {\n width: 100%;\n border: none;\n border-top: 1px solid var(--bv-color-neutral-200);\n margin: 0;\n}\n\n/* \u2500\u2500 Body \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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.body {\n width: 100%;\n max-height: var(--bv-modal-body-max-height);\n overflow-y: auto;\n color: var(--bv-color-neutral-600);\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-sm);\n line-height: 20px;\n}\n\n/* \u2500\u2500 Footer \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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.footer {\n width: 100%;\n}\n';
6
+
7
+ // components/bv-modal/bv-modal.ts
8
+ var BvModal = class extends HTMLElement {
9
+ static observedAttributes = ["title", "open"];
10
+ _dialog = null;
11
+ _titleEl = null;
12
+ _rendered = false;
13
+ constructor() {
14
+ super();
15
+ this.attachShadow({ mode: "open" });
16
+ if (typeof CSSStyleSheet !== "undefined" && "replaceSync" in CSSStyleSheet.prototype) {
17
+ const sheet = new CSSStyleSheet();
18
+ sheet.replaceSync(bv_modal_default);
19
+ this.shadowRoot.adoptedStyleSheets = [sheet];
20
+ }
21
+ }
22
+ connectedCallback() {
23
+ this._render();
24
+ }
25
+ disconnectedCallback() {
26
+ var _a;
27
+ (_a = this._dialog) == null ? void 0 : _a.close();
28
+ }
29
+ attributeChangedCallback(name, _old, newVal) {
30
+ if (!this._rendered) return;
31
+ if (name === "title" && this._titleEl) {
32
+ this._titleEl.textContent = newVal ?? "";
33
+ }
34
+ if (name === "open") {
35
+ this._syncOpen();
36
+ }
37
+ }
38
+ _syncOpen() {
39
+ if (!this._dialog) return;
40
+ if (this.hasAttribute("open")) {
41
+ if (!this._dialog.open) this._dialog.showModal();
42
+ } else {
43
+ if (this._dialog.open) this._dialog.close();
44
+ }
45
+ }
46
+ _close() {
47
+ this.removeAttribute("open");
48
+ this.dispatchEvent(new CustomEvent("bv-close", { bubbles: true, composed: true }));
49
+ }
50
+ _render() {
51
+ if (this._rendered) return;
52
+ this._rendered = true;
53
+ const shadow = this.shadowRoot;
54
+ if (!shadow.adoptedStyleSheets.length) {
55
+ const style = document.createElement("style");
56
+ style.textContent = bv_modal_default;
57
+ shadow.appendChild(style);
58
+ }
59
+ const dialog = document.createElement("dialog");
60
+ this._dialog = dialog;
61
+ dialog.addEventListener("click", (e) => {
62
+ if (e.target === dialog) this._close();
63
+ });
64
+ dialog.addEventListener("cancel", (e) => {
65
+ e.preventDefault();
66
+ this._close();
67
+ });
68
+ const panel = document.createElement("div");
69
+ panel.className = "panel";
70
+ const header = document.createElement("div");
71
+ header.className = "header";
72
+ const titleEl = document.createElement("h2");
73
+ titleEl.className = "title";
74
+ titleEl.textContent = this.getAttribute("title") ?? "";
75
+ this._titleEl = titleEl;
76
+ const closeBtn = document.createElement("button");
77
+ closeBtn.className = "close-btn";
78
+ closeBtn.setAttribute("aria-label", "Close");
79
+ closeBtn.textContent = "\u2715";
80
+ closeBtn.addEventListener("click", () => this._close());
81
+ header.append(titleEl, closeBtn);
82
+ const separator = document.createElement("hr");
83
+ separator.className = "separator";
84
+ const body = document.createElement("div");
85
+ body.className = "body";
86
+ body.appendChild(document.createElement("slot"));
87
+ const footer = document.createElement("div");
88
+ footer.className = "footer";
89
+ footer.hidden = true;
90
+ const footerSlot = document.createElement("slot");
91
+ footerSlot.name = "footer";
92
+ footerSlot.addEventListener("slotchange", () => {
93
+ footer.hidden = footerSlot.assignedNodes().length === 0;
94
+ });
95
+ footer.appendChild(footerSlot);
96
+ panel.append(header, separator, body, footer);
97
+ dialog.appendChild(panel);
98
+ shadow.appendChild(dialog);
99
+ this._syncOpen();
100
+ }
101
+ };
102
+ if (!customElements.get("bv-modal")) {
103
+ customElements.define("bv-modal", BvModal);
104
+ }
105
+
106
+ // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-course-detail/bv-course-detail.css
107
+ var bv_course_detail_default = ":host {\n display: block;\n font-family: var(--bv-font-family-base);\n}\n\n[hidden] {\n display: none !important;\n}\n\n/* \u2500\u2500 Root layout \u2500\u2500 */\n\n.course-detail {\n display: flex;\n gap: 20px;\n align-items: flex-start;\n}\n\n/* \u2500\u2500 Thumbnail column \u2500\u2500 */\n\n.thumb-col {\n flex-shrink: 0;\n width: 160px;\n}\n\n.thumb-wrap {\n width: 160px;\n height: 113px;\n background: var(--bv-color-neutral-200);\n border-radius: var(--bv-radius-lg);\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.thumb-img {\n width: 100%;\n height: 100%;\n object-fit: cover;\n display: block;\n}\n\n.thumb-placeholder {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 36px;\n height: 36px;\n}\n\n.thumb-placeholder svg {\n width: 100%;\n height: 100%;\n}\n\n/* \u2500\u2500 Right column \u2500\u2500 */\n\n.right-col {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n/* \u2500\u2500 Top row: pills + title + separator \u2500\u2500 */\n\n.top-row {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.card-header {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n.pills-row {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n.course-title {\n font-size: var(--bv-font-size-xl);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-900);\n line-height: 32px;\n}\n\n.separator {\n height: 0;\n border-top: 0.5px solid var(--bv-color-neutral-300);\n}\n\n/* \u2500\u2500 Description \u2500\u2500 */\n\n.desc-section {\n display: flex;\n flex-direction: column;\n gap: 8px;\n}\n\n.desc-text {\n margin: 0;\n font-size: var(--bv-font-size-xs);\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: 6;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n/* Read More expands the clamp */\n.desc-wrap--expanded .desc-text {\n -webkit-line-clamp: unset;\n}\n\n.read-more-btn {\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-semibold);\n color: var(--bv-color-primary);\n line-height: 24px;\n white-space: nowrap;\n text-align: left;\n}\n\n.read-more-btn:hover {\n text-decoration: underline;\n}\n";
108
+
109
+ // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-category-pill/bv-category-pill.css
110
+ var bv_category_pill_default = ":host {\n display: inline-flex;\n font-family: var(--bv-font-family-base);\n}\n\n.pill {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 4px 6px;\n border: 0.5px solid var(--bv-color-neutral-900);\n border-radius: var(--bv-radius-sm);\n font-size: 10px;\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-700);\n line-height: 1;\n white-space: nowrap;\n}\n";
111
+
112
+ // components/bv-category-pill/bv-category-pill.ts
113
+ var _sheet = null;
114
+ function getSheet() {
115
+ if (!_sheet) {
116
+ _sheet = new CSSStyleSheet();
117
+ _sheet.replaceSync(bv_category_pill_default);
118
+ }
119
+ return _sheet;
120
+ }
121
+ var BvCategoryPill = class extends HTMLElement {
122
+ static observedAttributes = ["label"];
123
+ _rendered = false;
124
+ _labelEl = null;
125
+ constructor() {
126
+ super();
127
+ const shadow = this.attachShadow({ mode: "open" });
128
+ if ("adoptedStyleSheets" in ShadowRoot.prototype) {
129
+ shadow.adoptedStyleSheets = [getSheet()];
130
+ }
131
+ }
132
+ get label() {
133
+ return this.getAttribute("label") ?? "";
134
+ }
135
+ set label(v) {
136
+ this.setAttribute("label", v);
137
+ }
138
+ connectedCallback() {
139
+ this._render();
140
+ }
141
+ attributeChangedCallback(name, _old, val) {
142
+ if (!this._rendered) return;
143
+ if (name === "label" && this._labelEl) this._labelEl.textContent = val ?? "";
144
+ }
145
+ _render() {
146
+ if (this._rendered) return;
147
+ this._rendered = true;
148
+ const shadow = this.shadowRoot;
149
+ if (!shadow.adoptedStyleSheets.length) {
150
+ const s = document.createElement("style");
151
+ s.textContent = bv_category_pill_default;
152
+ shadow.appendChild(s);
153
+ }
154
+ const pill = document.createElement("span");
155
+ pill.className = "pill";
156
+ pill.setAttribute("part", "pill");
157
+ const labelEl = document.createElement("span");
158
+ labelEl.textContent = this.label;
159
+ this._labelEl = labelEl;
160
+ pill.appendChild(labelEl);
161
+ shadow.appendChild(pill);
162
+ }
163
+ };
164
+ if (!customElements.get("bv-category-pill")) {
165
+ customElements.define("bv-category-pill", BvCategoryPill);
166
+ }
167
+
168
+ // components/bv-course-detail/bv-course-detail.ts
169
+ var _sheet2 = null;
170
+ function getSheet2() {
171
+ if (!_sheet2) {
172
+ _sheet2 = new CSSStyleSheet();
173
+ _sheet2.replaceSync(bv_course_detail_default);
174
+ }
175
+ return _sheet2;
176
+ }
177
+ var BvCourseDetail = class extends HTMLElement {
178
+ static observedAttributes = ["thumbnail", "title", "description", "categories"];
179
+ _rendered = false;
180
+ _categories = [];
181
+ _thumbImg = null;
182
+ _thumbPlaceholder = null;
183
+ _pillsRow = null;
184
+ _titleEl = null;
185
+ _descEl = null;
186
+ _descWrap = null;
187
+ _readMoreBtn = null;
188
+ constructor() {
189
+ super();
190
+ const shadow = this.attachShadow({ mode: "open" });
191
+ if ("adoptedStyleSheets" in ShadowRoot.prototype) {
192
+ shadow.adoptedStyleSheets = [getSheet2()];
193
+ }
194
+ }
195
+ get thumbnail() {
196
+ return this.getAttribute("thumbnail") ?? "";
197
+ }
198
+ set thumbnail(v) {
199
+ this.setAttribute("thumbnail", v);
200
+ }
201
+ get title() {
202
+ return this.getAttribute("title") ?? "";
203
+ }
204
+ set title(v) {
205
+ this.setAttribute("title", v);
206
+ }
207
+ get description() {
208
+ return this.getAttribute("description") ?? "";
209
+ }
210
+ set description(v) {
211
+ this.setAttribute("description", v);
212
+ }
213
+ get categories() {
214
+ return this._categories;
215
+ }
216
+ set categories(v) {
217
+ this._categories = v;
218
+ this.setAttribute("categories", JSON.stringify(v));
219
+ if (this._rendered) this._syncPills();
220
+ }
221
+ connectedCallback() {
222
+ this._render();
223
+ }
224
+ attributeChangedCallback(name, _old, val) {
225
+ if (!this._rendered) return;
226
+ switch (name) {
227
+ case "thumbnail":
228
+ this._syncThumbnail(val);
229
+ break;
230
+ case "title":
231
+ if (this._titleEl) this._titleEl.textContent = val ?? "";
232
+ break;
233
+ case "description":
234
+ this._syncDesc(val);
235
+ break;
236
+ case "categories":
237
+ try {
238
+ this._categories = JSON.parse(val ?? "[]");
239
+ } catch {
240
+ this._categories = [];
241
+ }
242
+ this._syncPills();
243
+ break;
244
+ }
245
+ }
246
+ _render() {
247
+ if (this._rendered) return;
248
+ this._rendered = true;
249
+ const attrCats = this.getAttribute("categories");
250
+ if (attrCats) {
251
+ try {
252
+ this._categories = JSON.parse(attrCats);
253
+ } catch {
254
+ this._categories = [];
255
+ }
256
+ }
257
+ const shadow = this.shadowRoot;
258
+ if (!shadow.adoptedStyleSheets.length) {
259
+ const s = document.createElement("style");
260
+ s.textContent = bv_course_detail_default;
261
+ shadow.appendChild(s);
262
+ }
263
+ const root = document.createElement("div");
264
+ root.className = "course-detail";
265
+ const thumbCol = document.createElement("div");
266
+ thumbCol.className = "thumb-col";
267
+ const thumbWrap = document.createElement("div");
268
+ thumbWrap.className = "thumb-wrap";
269
+ const thumbImg = document.createElement("img");
270
+ thumbImg.className = "thumb-img";
271
+ thumbImg.alt = "";
272
+ if (this.thumbnail) thumbImg.src = this.thumbnail;
273
+ thumbImg.hidden = !this.thumbnail;
274
+ this._thumbImg = thumbImg;
275
+ const thumbPlaceholder = document.createElement("div");
276
+ thumbPlaceholder.className = "thumb-placeholder";
277
+ thumbPlaceholder.setAttribute("aria-hidden", "true");
278
+ thumbPlaceholder.innerHTML = `<svg viewBox="0 0 54 54" fill="none" stroke="var(--bv-color-neutral-400)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="1" y="1" width="52" height="52" rx="6"/><circle cx="17" cy="18" r="5"/><path d="M1 38 L18 22 L28 32 L37 23 L53 38"/></svg>`;
279
+ thumbPlaceholder.hidden = !!this.thumbnail;
280
+ this._thumbPlaceholder = thumbPlaceholder;
281
+ thumbWrap.append(thumbImg, thumbPlaceholder);
282
+ thumbCol.appendChild(thumbWrap);
283
+ const rightCol = document.createElement("div");
284
+ rightCol.className = "right-col";
285
+ const topRow = document.createElement("div");
286
+ topRow.className = "top-row";
287
+ const header = document.createElement("div");
288
+ header.className = "card-header";
289
+ const pillsRow = document.createElement("div");
290
+ pillsRow.className = "pills-row";
291
+ this._pillsRow = pillsRow;
292
+ this._syncPills();
293
+ const titleEl = document.createElement("span");
294
+ titleEl.className = "course-title";
295
+ titleEl.textContent = this.title;
296
+ this._titleEl = titleEl;
297
+ header.append(pillsRow, titleEl);
298
+ const sep = document.createElement("div");
299
+ sep.className = "separator";
300
+ sep.setAttribute("role", "separator");
301
+ topRow.append(header, sep);
302
+ const descSection = document.createElement("div");
303
+ descSection.className = "desc-section";
304
+ const descWrap = document.createElement("div");
305
+ descWrap.className = "desc-wrap";
306
+ this._descWrap = descWrap;
307
+ const descEl = document.createElement("p");
308
+ descEl.className = "desc-text";
309
+ descEl.textContent = this.description;
310
+ this._descEl = descEl;
311
+ const readMoreBtn = document.createElement("button");
312
+ readMoreBtn.className = "read-more-btn";
313
+ readMoreBtn.textContent = "Read More";
314
+ readMoreBtn.hidden = true;
315
+ this._readMoreBtn = readMoreBtn;
316
+ readMoreBtn.addEventListener("click", () => {
317
+ const expanded = descWrap.classList.toggle("desc-wrap--expanded");
318
+ readMoreBtn.textContent = expanded ? "Read Less" : "Read More";
319
+ this.dispatchEvent(
320
+ new CustomEvent("bv-read-more", {
321
+ bubbles: true,
322
+ composed: true,
323
+ detail: { expanded }
324
+ })
325
+ );
326
+ });
327
+ requestAnimationFrame(() => {
328
+ readMoreBtn.hidden = descEl.scrollHeight <= descEl.clientHeight;
329
+ });
330
+ descWrap.appendChild(descEl);
331
+ descSection.append(descWrap, readMoreBtn);
332
+ rightCol.append(topRow, descSection);
333
+ root.append(thumbCol, rightCol);
334
+ shadow.appendChild(root);
335
+ }
336
+ _syncThumbnail(src) {
337
+ if (!this._thumbImg || !this._thumbPlaceholder) return;
338
+ if (src) {
339
+ this._thumbImg.src = src;
340
+ this._thumbImg.hidden = false;
341
+ this._thumbPlaceholder.hidden = true;
342
+ } else {
343
+ this._thumbImg.hidden = true;
344
+ this._thumbPlaceholder.hidden = false;
345
+ }
346
+ }
347
+ _syncDesc(val) {
348
+ if (!this._descEl || !this._readMoreBtn || !this._descWrap) return;
349
+ this._descEl.textContent = val ?? "";
350
+ this._descWrap.classList.remove("desc-wrap--expanded");
351
+ this._readMoreBtn.textContent = "Read More";
352
+ requestAnimationFrame(() => {
353
+ if (this._descEl && this._readMoreBtn) {
354
+ this._readMoreBtn.hidden = this._descEl.scrollHeight <= this._descEl.clientHeight;
355
+ }
356
+ });
357
+ }
358
+ _syncPills() {
359
+ if (!this._pillsRow) return;
360
+ this._pillsRow.innerHTML = "";
361
+ this._categories.forEach((cat) => {
362
+ const pill = document.createElement("bv-category-pill");
363
+ pill.setAttribute("label", cat);
364
+ this._pillsRow.appendChild(pill);
365
+ });
366
+ this._pillsRow.hidden = this._categories.length === 0;
367
+ }
368
+ };
369
+ if (!customElements.get("bv-course-detail")) {
370
+ customElements.define("bv-course-detail", BvCourseDetail);
371
+ }
372
+
373
+ // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-course-outline/bv-course-outline.css
374
+ var bv_course_outline_default = ":host {\n display: block;\n font-family: var(--bv-font-family-base);\n}\n\n/* \u2500\u2500 Outer container \u2500\u2500 */\n\n.container {\n border: 0.5px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-xl);\n overflow: hidden;\n}\n\n.container-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n padding: 20px 24px;\n background: #f9fafb;\n border-bottom: 0.5px solid var(--bv-color-neutral-300);\n}\n\n.container-title {\n font-size: var(--bv-font-size-2xl);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-700);\n line-height: 32px;\n}\n\n.expand-all-btn {\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-bold);\n color: var(--bv-color-primary);\n line-height: 24px;\n white-space: nowrap;\n}\n\n.expand-all-btn:hover {\n text-decoration: underline;\n}\n\n.outline {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 24px;\n background: var(--bv-color-neutral-0);\n}\n\n/* \u2500\u2500 Section \u2500\u2500 */\n\n.section {\n background: var(--bv-color-neutral-0);\n border: 0.5px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-xl);\n overflow: hidden;\n}\n\n.section-header {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 16px;\n padding: 20px;\n cursor: pointer;\n user-select: none;\n}\n\n.section-header:hover {\n background: linear-gradient(90deg, #fff, #f9fafb 15% 85%, #fff);\n}\n\n.section-header:focus-visible {\n outline: 2px solid var(--bv-color-primary);\n outline-offset: -2px;\n border-radius: var(--bv-radius-xl);\n}\n\n.section-header-left {\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n flex: 1;\n min-width: 0;\n gap: 12px;\n}\n\n.section-title-row {\n display: flex;\n align-items: center;\n gap: 12px;\n width: 100%;\n}\n\n.section-title {\n font-size: var(--bv-font-size-lg);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-900);\n line-height: 28px;\n}\n\n.section-badge {\n display: inline-flex;\n align-items: center;\n padding: 0 8px;\n border: 1px solid var(--bv-color-neutral-300);\n border-radius: var(--bv-radius-full);\n font-size: 10px;\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-500);\n line-height: 18px;\n white-space: nowrap;\n}\n\n.section-chevron {\n flex-shrink: 0;\n width: 24px;\n height: 24px;\n color: var(--bv-color-neutral-500);\n transition: transform var(--bv-transition-fast);\n}\n\n.section-chevron svg {\n width: 100%;\n height: 100%;\n}\n\n.section--expanded .section-chevron {\n transform: rotate(180deg);\n}\n\n/* \u2500\u2500 Section body \u2500\u2500 */\n\n.section-body {\n display: none;\n border-top: 0.5px solid var(--bv-color-neutral-300);\n}\n\n.section--expanded .section-body {\n display: block;\n}\n\n/* \u2500\u2500 Description \u2500\u2500 */\n\n.section-desc-wrap {\n padding: 16px 20px 20px;\n}\n\n.section-desc {\n margin: 0 0 4px;\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-700);\n line-height: 24px;\n display: -webkit-box;\n -webkit-line-clamp: 3;\n -webkit-box-orient: vertical;\n overflow: hidden;\n}\n\n.section-desc-wrap--expanded .section-desc {\n -webkit-line-clamp: unset;\n}\n\n.read-more {\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\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-primary);\n line-height: 24px;\n}\n\n.read-more:hover {\n text-decoration: underline;\n}\n\n/* \u2500\u2500 Module list \u2500\u2500 */\n\n.module-list {\n padding-left: 20px;\n padding-right: 20px;\n}\n\n.module-sep {\n height: 0;\n border-top: 0.5px solid var(--bv-color-neutral-300);\n margin-left: 20px;\n}\n\n.desc-sep {\n height: 0;\n border-top: 0.5px solid var(--bv-color-neutral-300);\n margin: 0 20px;\n}\n\n.module-row {\n display: flex;\n align-items: center;\n gap: 12px;\n min-height: 72px;\n padding: 0 0 0 20px;\n}\n\n.module-row:hover {\n background: linear-gradient(90deg, #fff, #f9fafb 15% 85%, #fff);\n}\n\n/* \u2500\u2500 Module icon \u2500\u2500 */\n\n.module-icon {\n flex-shrink: 0;\n width: 34px;\n height: 34px;\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.module-icon svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n/* \u2500\u2500 Module content \u2500\u2500 */\n\n.module-content {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 2px;\n}\n\n.module-title-row {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n.module-type-icon {\n flex-shrink: 0;\n width: 18px;\n height: 18px;\n color: var(--bv-color-neutral-500);\n display: flex;\n align-items: center;\n}\n\n.module-type-icon svg {\n width: 100%;\n height: 100%;\n display: block;\n}\n\n.module-title {\n flex: 1;\n min-width: 0;\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-700);\n line-height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n/* \u2500\u2500 Module status \u2500\u2500 */\n\n.module-status {\n display: flex;\n align-items: center;\n gap: 6px;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-bold);\n line-height: 20px;\n}\n\n.module-status span {\n white-space: nowrap;\n}\n\n.status-icon {\n width: 18px;\n height: 18px;\n flex-shrink: 0;\n}\n\n.module-status--completed,\n.module-status--viewed,\n.module-status--pending-review {\n color: var(--bv-color-success-dark);\n}\n\n.module-status--in-progress,\n.module-status--not-started {\n color: var(--bv-color-neutral-700);\n}\n\n.module-status--max-retakes,\n.module-status--rejected {\n color: #f04438;\n}\n\n.module-status--seat-time {\n color: var(--bv-color-primary);\n}\n\n/* \u2500\u2500 Module actions \u2500\u2500 */\n\n.module-actions {\n display: flex;\n align-items: center;\n gap: 16px;\n flex-shrink: 0;\n}\n\n.module-action-btn {\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n font-family: var(--bv-font-family-base);\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-bold);\n color: var(--bv-color-primary);\n line-height: 20px;\n white-space: nowrap;\n}\n\n.module-action-btn:hover {\n text-decoration: underline;\n}\n\n/* \u2500\u2500 Pre-enrollment section \u2500\u2500 */\n\n.section--pre-enrollment .section-header {\n align-items: flex-start;\n}\n\n.pre-title-row {\n display: flex;\n align-items: center;\n gap: 16px;\n width: 100%;\n}\n\n.section-count-text {\n flex-shrink: 0;\n font-size: var(--bv-font-size-sm);\n font-weight: var(--bv-font-weight-regular);\n color: var(--bv-color-neutral-500);\n line-height: 20px;\n white-space: nowrap;\n}\n\n.section--pre-enrollment .section-chevron {\n margin-top: 2px;\n}\n\n.pre-section-desc-wrap {\n width: 100%;\n}\n\n/* \u2500\u2500 Pre-enrollment module list \u2500\u2500 */\n\n.pre-module-list {\n display: flex;\n flex-direction: column;\n padding: 0 20px;\n}\n\n.pre-module-list .module-sep {\n margin-left: 0;\n}\n\n.pre-module-wrap {\n display: flex;\n flex-direction: column;\n gap: 12px;\n}\n\n.pre-module-row {\n display: flex;\n align-items: center;\n gap: 8px;\n min-height: 24px;\n padding: 16px 0;\n}\n\n.pre-module-list > .pre-module-wrap:first-child .pre-module-row {\n padding-top: 16px;\n}\n.pre-module-list > .pre-module-wrap:last-child .pre-module-row {\n padding-bottom: 16px;\n}\n\n.pre-module-row:hover {\n background: linear-gradient(90deg, #fff, #f9fafb 15% 85%, #fff);\n}\n\n.pre-module-title-group {\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n}\n\n.pre-module-title {\n min-width: 0;\n font-size: var(--bv-font-size-md);\n font-weight: var(--bv-font-weight-medium);\n color: var(--bv-color-neutral-700);\n line-height: 24px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.pre-module-badges {\n display: flex;\n gap: 4px;\n align-items: center;\n flex-shrink: 0;\n}\n\n.pre-badge {\n display: inline-flex;\n align-items: center;\n padding: 2px 8px;\n border-radius: var(--bv-radius-full);\n font-size: var(--bv-font-size-xs);\n font-weight: var(--bv-font-weight-medium);\n line-height: 18px;\n white-space: nowrap;\n}\n\n.pre-badge--inactive {\n background: var(--bv-color-neutral-700);\n color: var(--bv-color-neutral-0);\n}\n\n.pre-badge--optional {\n background: var(--bv-color-neutral-100);\n color: var(--bv-color-neutral-700);\n}\n\n.pre-module-toggle {\n flex-shrink: 0;\n width: 24px;\n height: 24px;\n background: none;\n border: none;\n padding: 0;\n cursor: pointer;\n color: var(--bv-color-neutral-700);\n display: flex;\n align-items: center;\n justify-content: center;\n}\n\n.pre-module-toggle:hover {\n color: var(--bv-color-primary);\n}\n\n.pre-module-toggle svg {\n width: 100%;\n height: 100%;\n}\n\n.pre-module-wrap--expanded .pre-module-row {\n padding-bottom: 0;\n}\n\n.pre-module-desc {\n padding: 0 0 16px;\n margin: 0;\n font-size: var(--bv-font-size-sm);\n color: var(--bv-color-neutral-700);\n line-height: 20px;\n}\n\n/* Empty state */\n.pre-section-empty {\n padding: 20px;\n margin: 0;\n font-size: var(--bv-font-size-md);\n color: var(--bv-color-neutral-500);\n line-height: 24px;\n}\n";
375
+
376
+ // components/bv-course-outline/bv-course-outline.ts
377
+ var BvCourseOutline = class extends HTMLElement {
378
+ static observedAttributes = ["sections", "mode"];
379
+ _sections = [];
380
+ _rendered = false;
381
+ _listEl = null;
382
+ _expandBtn = null;
383
+ _mode = "enrolled";
384
+ get sections() {
385
+ return this._sections;
386
+ }
387
+ set sections(val) {
388
+ this._sections = val;
389
+ if (this._rendered) this._flush();
390
+ }
391
+ get mode() {
392
+ return this._mode;
393
+ }
394
+ set mode(v) {
395
+ this._mode = v;
396
+ this.setAttribute("mode", v);
397
+ if (this._rendered) this._flush();
398
+ }
399
+ constructor() {
400
+ super();
401
+ this.attachShadow({ mode: "open" });
402
+ if ("replaceSync" in CSSStyleSheet.prototype) {
403
+ const sheet = new CSSStyleSheet();
404
+ sheet.replaceSync(bv_course_outline_default);
405
+ this.shadowRoot.adoptedStyleSheets = [sheet];
406
+ }
407
+ }
408
+ connectedCallback() {
409
+ this._render();
410
+ }
411
+ attributeChangedCallback(name, _old, val) {
412
+ if (name === "sections") {
413
+ try {
414
+ this._sections = JSON.parse(val ?? "[]");
415
+ } catch {
416
+ this._sections = [];
417
+ }
418
+ if (this._rendered) this._flush();
419
+ }
420
+ if (name === "mode") {
421
+ this._mode = val === "pre-enrollment" ? "pre-enrollment" : "enrolled";
422
+ if (this._rendered) this._flush();
423
+ }
424
+ }
425
+ _render() {
426
+ if (this._rendered) return;
427
+ this._rendered = true;
428
+ const shadow = this.shadowRoot;
429
+ if (!shadow.adoptedStyleSheets.length) {
430
+ const s = document.createElement("style");
431
+ s.textContent = bv_course_outline_default;
432
+ shadow.appendChild(s);
433
+ }
434
+ const attr = this.getAttribute("sections");
435
+ if (attr !== null) {
436
+ try {
437
+ this._sections = JSON.parse(attr);
438
+ } catch {
439
+ this._sections = [];
440
+ }
441
+ }
442
+ const modeAttr = this.getAttribute("mode");
443
+ if (modeAttr === "pre-enrollment") this._mode = "pre-enrollment";
444
+ const container = document.createElement("div");
445
+ container.className = "container";
446
+ const containerHeader = document.createElement("div");
447
+ containerHeader.className = "container-header";
448
+ const containerTitle = document.createElement("span");
449
+ containerTitle.className = "container-title";
450
+ containerTitle.textContent = "Course Outline";
451
+ this._expandBtn = document.createElement("button");
452
+ this._expandBtn.className = "expand-all-btn";
453
+ this._expandBtn.addEventListener("click", () => this._toggleAll());
454
+ this._updateExpandBtn();
455
+ containerHeader.append(containerTitle, this._expandBtn);
456
+ container.appendChild(containerHeader);
457
+ const list = document.createElement("div");
458
+ list.className = "outline";
459
+ this._listEl = list;
460
+ this._flush();
461
+ container.appendChild(list);
462
+ shadow.appendChild(container);
463
+ }
464
+ _updateExpandBtn() {
465
+ if (!this._expandBtn) return;
466
+ const allExpanded = this._sections.length > 0 && this._sections.every((s) => s.expanded);
467
+ this._expandBtn.textContent = allExpanded ? "Collapse All" : "Expand All";
468
+ }
469
+ _toggleAll() {
470
+ const allExpanded = this._sections.every((s) => s.expanded);
471
+ this._sections.forEach((s) => {
472
+ s.expanded = !allExpanded;
473
+ });
474
+ this._flush();
475
+ this._updateExpandBtn();
476
+ this.dispatchEvent(
477
+ new CustomEvent("bv-expand-all", {
478
+ bubbles: true,
479
+ composed: true,
480
+ detail: { expanded: !allExpanded }
481
+ })
482
+ );
483
+ }
484
+ _flush() {
485
+ const el = this._listEl;
486
+ el.innerHTML = "";
487
+ this._sections.forEach((sec, i) => el.appendChild(this._buildSection(sec, i)));
488
+ this._updateExpandBtn();
489
+ }
490
+ // ── Section ────────────────────────────────────────────────────────────────
491
+ _buildSection(sec, sIdx) {
492
+ var _a, _b;
493
+ if (this._mode === "pre-enrollment") return this._buildPreEnrollSection(sec, sIdx);
494
+ const wrap = document.createElement("div");
495
+ wrap.className = "section" + (sec.expanded ? " section--expanded" : "");
496
+ const header = document.createElement("div");
497
+ header.className = "section-header";
498
+ header.setAttribute("role", "button");
499
+ header.setAttribute("tabindex", "0");
500
+ header.setAttribute("aria-expanded", String(!!sec.expanded));
501
+ const left = document.createElement("div");
502
+ left.className = "section-header-left";
503
+ const titleEl = document.createElement("span");
504
+ titleEl.className = "section-title";
505
+ titleEl.textContent = sec.title;
506
+ const badge = document.createElement("span");
507
+ badge.className = "section-badge";
508
+ badge.textContent = `${((_a = sec.modules) == null ? void 0 : _a.length) ?? 0} Modules`;
509
+ const titleRow = document.createElement("div");
510
+ titleRow.className = "section-title-row";
511
+ titleRow.append(titleEl, badge);
512
+ left.appendChild(titleRow);
513
+ if (sec.description) {
514
+ const descWrap = document.createElement("div");
515
+ descWrap.className = "section-desc-wrap";
516
+ const desc = document.createElement("p");
517
+ desc.className = "section-desc";
518
+ desc.textContent = sec.description;
519
+ const readMore = document.createElement("button");
520
+ readMore.className = "read-more";
521
+ readMore.textContent = "Read More";
522
+ readMore.hidden = true;
523
+ readMore.addEventListener("click", (e) => {
524
+ e.stopPropagation();
525
+ const expanded = descWrap.classList.toggle("section-desc-wrap--expanded");
526
+ readMore.textContent = expanded ? "Read Less" : "Read More";
527
+ this.dispatchEvent(
528
+ new CustomEvent("bv-read-more", {
529
+ bubbles: true,
530
+ composed: true,
531
+ detail: { sectionIndex: sIdx }
532
+ })
533
+ );
534
+ });
535
+ requestAnimationFrame(() => {
536
+ readMore.hidden = desc.scrollHeight <= desc.clientHeight;
537
+ });
538
+ descWrap.append(desc, readMore);
539
+ left.appendChild(descWrap);
540
+ }
541
+ const chevron = document.createElement("div");
542
+ chevron.className = "section-chevron";
543
+ chevron.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>`;
544
+ header.append(left, chevron);
545
+ const toggle = () => {
546
+ sec.expanded = !sec.expanded;
547
+ wrap.classList.toggle("section--expanded", sec.expanded);
548
+ header.setAttribute("aria-expanded", String(sec.expanded));
549
+ this._updateExpandBtn();
550
+ this.dispatchEvent(
551
+ new CustomEvent("bv-section-toggle", {
552
+ bubbles: true,
553
+ composed: true,
554
+ detail: { sectionIndex: sIdx, expanded: sec.expanded }
555
+ })
556
+ );
557
+ };
558
+ header.addEventListener("click", toggle);
559
+ header.addEventListener("keydown", (e) => {
560
+ if (e.key === "Enter" || e.key === " ") {
561
+ e.preventDefault();
562
+ toggle();
563
+ }
564
+ });
565
+ wrap.appendChild(header);
566
+ if ((_b = sec.modules) == null ? void 0 : _b.length) {
567
+ const body = document.createElement("div");
568
+ body.className = "section-body";
569
+ const moduleList = document.createElement("div");
570
+ moduleList.className = "module-list";
571
+ sec.modules.forEach((mod, mIdx) => {
572
+ if (mIdx > 0) {
573
+ const sep = document.createElement("div");
574
+ sep.className = "module-sep";
575
+ moduleList.appendChild(sep);
576
+ }
577
+ moduleList.appendChild(this._buildModule(mod, sIdx, mIdx));
578
+ });
579
+ body.appendChild(moduleList);
580
+ wrap.appendChild(body);
581
+ }
582
+ return wrap;
583
+ }
584
+ // ── Module row ─────────────────────────────────────────────────────────────
585
+ _buildModule(mod, sIdx, mIdx) {
586
+ const row = document.createElement("div");
587
+ row.className = "module-row";
588
+ const typeIcon = document.createElement("div");
589
+ typeIcon.className = "module-icon";
590
+ typeIcon.innerHTML = this._bigIcon(mod.type, mod.status ?? "not-started");
591
+ const content = document.createElement("div");
592
+ content.className = "module-content";
593
+ const titleRow = document.createElement("div");
594
+ titleRow.className = "module-title-row";
595
+ const smallIcon = document.createElement("span");
596
+ smallIcon.className = "module-type-icon";
597
+ smallIcon.innerHTML = this._smallIcon(mod.type);
598
+ const titleEl = document.createElement("span");
599
+ titleEl.className = "module-title";
600
+ titleEl.textContent = mod.title;
601
+ titleRow.append(smallIcon, titleEl);
602
+ const status = mod.status ?? "not-started";
603
+ const statusEl = this._buildStatusEl(status, mod.statusLabel);
604
+ content.append(titleRow, statusEl);
605
+ const actionsEl = document.createElement("div");
606
+ actionsEl.className = "module-actions";
607
+ (mod.actions ?? []).forEach((action) => {
608
+ const btn = document.createElement("button");
609
+ btn.className = "module-action-btn";
610
+ btn.textContent = action.label;
611
+ btn.addEventListener("click", (e) => {
612
+ e.stopPropagation();
613
+ this.dispatchEvent(
614
+ new CustomEvent("bv-module-action", {
615
+ bubbles: true,
616
+ composed: true,
617
+ detail: { sectionIndex: sIdx, moduleIndex: mIdx, action: action.key }
618
+ })
619
+ );
620
+ });
621
+ actionsEl.appendChild(btn);
622
+ });
623
+ row.append(typeIcon, content, actionsEl);
624
+ return row;
625
+ }
626
+ // ── Status element ─────────────────────────────────────────────────────────
627
+ _buildStatusEl(status, label) {
628
+ const checkSvg = `<svg class="status-icon" viewBox="0 0 18 13" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 1L6 12L1 7"/></svg>`;
629
+ const clockSvg = `<svg class="status-icon" viewBox="0 0 22 22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M11 5V11L15 13M21 11C21 16.5228 16.5228 21 11 21C5.47715 21 1 16.5228 1 11C1 5.47715 5.47715 1 11 1C16.5228 1 21 5.47715 21 11Z"/></svg>`;
630
+ const defaults = {
631
+ completed: "Completed",
632
+ viewed: "Viewed",
633
+ "in-progress": "In Progress",
634
+ "not-started": "Not Started",
635
+ "max-retakes": "Maximum retakes reached",
636
+ rejected: "Rejected",
637
+ "pending-review": "Pending Review",
638
+ "seat-time": "Seat time required"
639
+ };
640
+ const el = document.createElement("div");
641
+ el.className = `module-status module-status--${status}`;
642
+ const span = document.createElement("span");
643
+ span.textContent = label ?? defaults[status] ?? status;
644
+ el.appendChild(span);
645
+ if (status === "completed" || status === "viewed") {
646
+ el.insertAdjacentHTML("beforeend", checkSvg);
647
+ } else if (status === "pending-review") {
648
+ el.insertAdjacentHTML("beforeend", clockSvg);
649
+ }
650
+ return el;
651
+ }
652
+ // ── Icons ──────────────────────────────────────────────────────────────────
653
+ _bigIcon(type, status) {
654
+ const inactive = status === "completed" || status === "viewed" || status === "max-retakes";
655
+ const primary = "var(--bv-color-primary)";
656
+ if (type === "download") {
657
+ return `<svg viewBox="0 0 34 34" fill="none" aria-hidden="true"><path d="M17 34C26.3888 34 34 26.3888 34 17C34 7.61116 26.3888 0 17 0C7.61116 0 0 7.61116 0 17C0 26.3888 7.61116 34 17 34Z" fill="${primary}"/><path d="M23.8 17L17 23.8L10.2 17M17 23.8V10.2" stroke="white" stroke-width="2.83333" stroke-linecap="round" stroke-linejoin="round"/><circle cx="17" cy="17" r="14.5" stroke="${primary}"/></svg>`;
658
+ }
659
+ if (type === "upload") {
660
+ return `<svg viewBox="0 0 34 34" fill="none" aria-hidden="true"><path d="M17 34C26.3888 34 34 26.3888 34 17C34 7.61116 26.3888 0 17 0C7.61116 0 0 7.61116 0 17C0 26.3888 7.61116 34 17 34Z" fill="${primary}"/><path d="M10.2 17L17 10.2L23.8 17M17 10.2V23.8" stroke="white" stroke-width="2.83333" stroke-linecap="round" stroke-linejoin="round"/><circle cx="17" cy="17" r="14.5" stroke="${primary}"/></svg>`;
661
+ }
662
+ if (type === "link") {
663
+ return `<svg viewBox="0 0 36.8338 36.8338" fill="none" aria-hidden="true"><path d="M29.6472 5.65447C22.5987 -0.547875 11.8568 0.138072 5.65446 7.18657C-0.547874 14.2351 0.138072 24.977 7.18657 31.1793C14.2351 37.3817 24.977 36.6957 31.1793 29.6472C37.3817 22.5987 36.6957 11.8568 29.6472 5.65447Z" fill="${primary}"/><path d="M22.909 13.3119L13.3119 13.9248M22.909 13.3119L23.5219 22.909M22.909 13.3119L13.2216 12.511M7.39696 27.9929L17.3883 17.4428M17.3534 17.481L21.8455 12.3761" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/></svg>`;
664
+ }
665
+ const playPath = `M13 20.6775C13 21.3934 13 21.7514 13.1496 21.9512C13.28 22.1254 13.4796 22.2343 13.6966 22.2498C13.9456 22.2676 14.2467 22.074 14.8489 21.6869L21.9298 17.1349C22.4524 16.7989 22.7137 16.631 22.8039 16.4174C22.8828 16.2308 22.8828 16.0202 22.8039 15.8336C22.7137 15.62 22.4524 15.452 21.9298 15.1161L14.8489 10.5641C14.2467 10.1769 13.9456 9.98334 13.6966 10.0011C13.4796 10.0166 13.28 10.1256 13.1496 10.2997C13 10.4996 13 10.8575 13 11.5735L13 20.6775Z`;
666
+ const opacity = inactive ? ' opacity="0.2"' : "";
667
+ return `<svg viewBox="0 0 32 32" fill="none" aria-hidden="true"><g${opacity}><rect x="1" y="1" width="30" height="30" rx="15" stroke="${primary}" stroke-width="2"/><circle cx="16" cy="16" r="14" fill="${primary}"/><path d="${playPath}" fill="white" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></g></svg>`;
668
+ }
669
+ _smallIcon(type) {
670
+ const icons2 = {
671
+ scorm: `<svg viewBox="0 0 15.03 16.28" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13.9014 4.60034L7.51368 8.14201M7.51368 8.14201L1.126 4.60034M7.51368 8.14201L7.5137 15.267M14.2771 11.1859V5.09812C14.2771 4.84113 14.2771 4.71264 14.2392 4.59804C14.2056 4.49666 14.1508 4.4036 14.0783 4.32508C13.9963 4.23633 13.8838 4.17393 13.6587 4.04913L8.09763 0.965793C7.88451 0.847624 7.77794 0.78854 7.66509 0.765376C7.56521 0.744875 7.46219 0.744875 7.36231 0.765376C7.24946 0.78854 7.1429 0.847624 6.92977 0.965793L1.36873 4.04913C1.14364 4.17393 1.0311 4.23633 0.949147 4.32508C0.876647 4.4036 0.82178 4.49666 0.788217 4.59804C0.750278 4.71264 0.750278 4.84113 0.750278 5.09812V11.1859C0.750278 11.4429 0.750278 11.5714 0.788217 11.686C0.82178 11.7874 0.876647 11.8805 0.949147 11.959C1.0311 12.0477 1.14364 12.1101 1.36873 12.2349L6.92977 15.3183C7.1429 15.4364 7.24946 15.4955 7.36231 15.5187C7.46219 15.5392 7.56521 15.5392 7.66509 15.5187C7.77794 15.4955 7.88451 15.4364 8.09763 15.3183L13.6587 12.2349C13.8838 12.1101 13.9963 12.0477 14.0783 11.959C14.1508 11.8805 14.2056 11.7874 14.2392 11.686C14.2771 11.5714 14.2771 11.4429 14.2771 11.1859Z"/></svg>`,
672
+ assessment: `<svg viewBox="0 0 13.72 16.13" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.507 6.1875V4.1625C12.507 2.90238 12.507 2.27232 12.2629 1.79102C12.0482 1.36766 11.7056 1.02345 11.2841 0.807736C10.8051 0.5625 10.1779 0.5625 8.92364 0.5625H4.14585C2.89156 0.5625 2.26441 0.5625 1.78534 0.807736C1.36393 1.02345 1.02132 1.36766 0.806601 1.79102C0.5625 2.27232 0.5625 2.90238 0.5625 4.1625V11.9625C0.5625 13.2226 0.5625 13.8527 0.806601 14.334C1.02132 14.7573 1.36393 15.1015 1.78534 15.3173C2.26441 15.5625 2.89156 15.5625 4.14585 15.5625H8.0278M8.0278 7.3125H3.54862M5.04168 10.3125H3.54862M9.52086 4.3125H3.54862M9.89413 10.3142C10.0257 9.93852 10.2853 9.62175 10.627 9.41998C10.9688 9.21821 11.3705 9.14445 11.7612 9.21178C12.1519 9.2791 12.5062 9.48315 12.7615 9.7878C13.0168 10.0925 13.1565 10.478 13.1559 10.8763C13.1559 12.0004 11.4775 12.5625 11.4775 12.5625M11.4991 14.8125H11.5066"/></svg>`,
673
+ survey: `<svg viewBox="0 0 14.56 11.63" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 5.8125L5.04168 5.8125M14 1.3125L5.04168 1.3125M14 10.3125L5.04168 10.3125M2.05556 5.8125C2.05556 6.22671 1.72133 6.5625 1.30903 6.5625C0.896733 6.5625 0.5625 6.22671 0.5625 5.8125C0.5625 5.39829 0.896733 5.0625 1.30903 5.0625C1.72133 5.0625 2.05556 5.39829 2.05556 5.8125ZM2.05556 1.3125C2.05556 1.72671 1.72133 2.0625 1.30903 2.0625C0.896733 2.0625 0.5625 1.72671 0.5625 1.3125C0.5625 0.898286 0.896733 0.5625 1.30903 0.5625C1.72133 0.5625 2.05556 0.898286 2.05556 1.3125ZM2.05556 10.3125C2.05556 10.7267 1.72133 11.0625 1.30903 11.0625C0.896733 11.0625 0.5625 10.7267 0.5625 10.3125C0.5625 9.89829 0.896733 9.5625 1.30903 9.5625C1.72133 9.5625 2.05556 9.89829 2.05556 10.3125Z"/></svg>`,
674
+ download: `<svg viewBox="0 0 16.06 14.63" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8.77433 3.56259L7.94155 1.88928C7.70187 1.40769 7.58202 1.16689 7.40323 0.990961C7.24512 0.835387 7.05457 0.717069 6.84535 0.644571C6.60877 0.562589 6.3408 0.562589 5.80485 0.562589H2.9514C2.1152 0.562589 1.69711 0.562589 1.37773 0.726079C1.09679 0.869889 0.868379 1.09936 0.725234 1.3816C0.562501 1.70247 0.562501 2.12251 0.562501 2.96259V3.56259M0.562501 3.56259H11.9098C13.164 3.56259 13.7912 3.56259 14.2703 3.80782C14.6917 4.02354 15.0343 4.36775 15.249 4.79111C15.4931 5.27241 15.4931 5.90247 15.4931 7.16259V10.4626C15.4931 11.7227 15.4931 12.3528 15.249 12.8341C15.0343 13.2574 14.6917 13.6016 14.2703 13.8174C13.7912 14.0626 13.164 14.0626 11.9098 14.0626H4.14585C2.89156 14.0626 2.26441 14.0626 1.78534 13.8174C1.36393 13.6016 1.02132 13.2574 0.806601 12.8341C0.562501 12.3528 0.562501 11.7227 0.562501 10.4626V3.56259ZM10.2674 8.81259L8.0278 11.0626L5.78821 8.81259M8.0278 11.0626V6.56259"/></svg>`,
675
+ link: `<svg viewBox="0 0 15.97 16.03" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6.49261 8.76267C6.81321 9.19327 7.22223 9.54956 7.69194 9.80737C8.16166 10.0652 8.68106 10.2185 9.21494 10.2569C9.74882 10.2953 10.2847 10.2179 10.7862 10.03C11.2876 9.84207 11.743 9.54797 12.1214 9.16767L14.361 6.91767C15.041 6.21041 15.4172 5.26315 15.4087 4.27991C15.4002 3.29668 15.0076 2.35613 14.3156 1.66085C13.6235 0.965569 12.6873 0.571186 11.7086 0.562642C10.7299 0.554098 9.78705 0.932077 9.08307 1.61517L7.79903 2.89767M9.47873 7.26267C9.15813 6.83207 8.7491 6.47578 8.27939 6.21796C7.80968 5.96015 7.29027 5.80683 6.75639 5.76842C6.22252 5.73001 5.68666 5.80739 5.18517 5.99533C4.68369 6.18327 4.2283 6.47737 3.84989 6.85767L1.6103 9.10767C0.930367 9.81493 0.554137 10.7622 0.562641 11.7454C0.571146 12.7287 0.963705 13.6692 1.65577 14.3645C2.34783 15.0598 3.28403 15.4542 4.26272 15.4627C5.24141 15.4712 6.18428 15.0933 6.88827 14.4102L8.16483 13.1277"/></svg>`,
676
+ "adobe-connect": `<svg viewBox="0 0 16.06 14.63" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M11.7605 0.56252L8.0278 3.56252L4.29515 0.56252M4.14585 14.0625H11.9098C13.164 14.0625 13.7912 14.0625 14.2703 13.8173C14.6917 13.6016 15.0343 13.2574 15.249 12.834C15.4931 12.3527 15.4931 11.7226 15.4931 10.4625V7.16252C15.4931 5.9024 15.4931 5.27234 15.249 4.79104C15.0343 4.36768 14.6917 4.02347 14.2703 3.80776C13.7912 3.56252 13.164 3.56252 11.9098 3.56252H4.14585C2.89156 3.56252 2.26441 3.56252 1.78534 3.80776C1.36393 4.02347 1.02132 4.36768 0.806601 4.79104C0.5625 5.27234 0.5625 5.9024 0.5625 7.16252V10.4625C0.5625 11.7226 0.5625 12.3527 0.806601 12.834C1.02132 13.2574 1.36393 13.6016 1.78534 13.8173C2.26441 14.0625 2.89156 14.0625 4.14585 14.0625Z"/></svg>`,
677
+ video: `<svg viewBox="0 0 16.06 11.63" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15.4931 3.51103C15.4931 3.05667 15.4931 2.82949 15.4037 2.72429C15.3261 2.63301 15.2097 2.58457 15.0906 2.59399C14.9533 2.60484 14.7934 2.76548 14.4736 3.08676L11.7605 5.8125L14.4736 8.53824C14.7934 8.85952 14.9533 9.02016 15.0906 9.03101C15.2097 9.04043 15.3261 8.99199 15.4037 8.90071C15.4931 8.79552 15.4931 8.56833 15.4931 8.11397V3.51103ZM0.5625 4.1625C0.5625 2.90238 0.5625 2.27232 0.806601 1.79102C1.02132 1.36766 1.36393 1.02345 1.78534 0.807736C2.26441 0.5625 2.89156 0.5625 4.14585 0.5625H8.17711C9.4314 0.5625 10.0585 0.5625 10.5376 0.807736C10.959 1.02345 11.3016 1.36766 11.5164 1.79102C11.7605 2.27232 11.7605 2.90238 11.7605 4.1625V7.4625C11.7605 8.72262 11.7605 9.35268 11.5164 9.83398C11.3016 10.2573 10.959 10.6015 10.5376 10.8173C10.0585 11.0625 9.4314 11.0625 8.17711 11.0625H4.14584C2.89156 11.0625 2.26441 11.0625 1.78534 10.8173C1.36393 10.6015 1.02132 10.2573 0.806601 9.83398C0.5625 9.35268 0.5625 8.72262 0.5625 7.4625V4.1625Z"/></svg>`,
678
+ upload: `<svg viewBox="0 0 14.75 16.13" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13.39 4.3125V4.1625C13.39 2.90238 13.39 2.27232 13.1278 1.79102C12.8972 1.36766 12.5293 1.02345 12.0767 0.807736C11.5622 0.5625 10.8887 0.5625 9.54172 0.5625H4.41074C3.06373 0.5625 2.39022 0.5625 1.87573 0.807736C1.42318 1.02345 1.05524 1.36766 0.824646 1.79102C0.5625 2.27232 0.5625 2.90238 0.5625 4.1625V11.9625C0.5625 13.2226 0.5625 13.8527 0.824646 14.334C1.05524 14.7573 1.42318 15.1015 1.87573 15.3173C2.39022 15.5625 3.06373 15.5625 4.41074 15.5625H7.37709M7.37709 7.3125H3.76936M6.57537 10.3125H3.76936M10.1831 4.3125H3.76936M11.7865 12.5625V8.4375C11.7865 7.81618 12.3249 7.3125 12.9891 7.3125C13.6533 7.3125 14.1917 7.81618 14.1917 8.4375V12.5625C14.1917 13.8051 13.1149 14.8125 11.7865 14.8125C10.4582 14.8125 9.38138 13.8051 9.38138 12.5625V9.5625"/></svg>`
679
+ };
680
+ return icons2[type] ?? icons2["scorm"];
681
+ }
682
+ // ── Pre-enrollment section ─────────────────────────────────────────────────
683
+ _buildPreEnrollSection(sec, sIdx) {
684
+ var _a;
685
+ const wrap = document.createElement("div");
686
+ wrap.className = "section section--pre-enrollment" + (sec.expanded ? " section--expanded" : "");
687
+ const header = document.createElement("div");
688
+ header.className = "section-header";
689
+ header.setAttribute("role", "button");
690
+ header.setAttribute("tabindex", "0");
691
+ header.setAttribute("aria-expanded", String(!!sec.expanded));
692
+ const left = document.createElement("div");
693
+ left.className = "section-header-left";
694
+ const titleRow = document.createElement("div");
695
+ titleRow.className = "pre-title-row";
696
+ const titleEl = document.createElement("span");
697
+ titleEl.className = "section-title";
698
+ titleEl.textContent = sec.title;
699
+ const count = ((_a = sec.modules) == null ? void 0 : _a.length) ?? 0;
700
+ let countEl = null;
701
+ if (count > 0) {
702
+ countEl = document.createElement("span");
703
+ countEl.className = "section-badge";
704
+ countEl.textContent = `${count} Modules`;
705
+ titleRow.append(titleEl, countEl);
706
+ } else {
707
+ titleRow.appendChild(titleEl);
708
+ }
709
+ left.appendChild(titleRow);
710
+ if (sec.description) {
711
+ const descWrap = document.createElement("div");
712
+ descWrap.className = "pre-section-desc-wrap";
713
+ const desc = document.createElement("p");
714
+ desc.className = "section-desc";
715
+ desc.textContent = sec.description;
716
+ const readMore = document.createElement("button");
717
+ readMore.className = "read-more";
718
+ readMore.textContent = "Read More";
719
+ readMore.hidden = true;
720
+ readMore.addEventListener("click", (e) => {
721
+ e.stopPropagation();
722
+ const expanded = descWrap.classList.toggle("section-desc-wrap--expanded");
723
+ readMore.textContent = expanded ? "Read Less" : "Read More";
724
+ this.dispatchEvent(
725
+ new CustomEvent("bv-read-more", {
726
+ bubbles: true,
727
+ composed: true,
728
+ detail: { sectionIndex: sIdx }
729
+ })
730
+ );
731
+ });
732
+ requestAnimationFrame(() => {
733
+ readMore.hidden = desc.scrollHeight <= desc.clientHeight;
734
+ });
735
+ descWrap.append(desc, readMore);
736
+ left.appendChild(descWrap);
737
+ }
738
+ const chevron = document.createElement("div");
739
+ chevron.className = "section-chevron";
740
+ chevron.setAttribute("aria-hidden", "true");
741
+ chevron.innerHTML = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="6 9 12 15 18 9"/></svg>`;
742
+ header.append(left, chevron);
743
+ const toggle = () => {
744
+ sec.expanded = !sec.expanded;
745
+ wrap.classList.toggle("section--expanded", sec.expanded);
746
+ header.setAttribute("aria-expanded", String(sec.expanded));
747
+ this._updateExpandBtn();
748
+ this.dispatchEvent(
749
+ new CustomEvent("bv-section-toggle", {
750
+ bubbles: true,
751
+ composed: true,
752
+ detail: { sectionIndex: sIdx, expanded: sec.expanded }
753
+ })
754
+ );
755
+ };
756
+ header.addEventListener("click", toggle);
757
+ header.addEventListener("keydown", (e) => {
758
+ if (e.key === "Enter" || e.key === " ") {
759
+ e.preventDefault();
760
+ toggle();
761
+ }
762
+ });
763
+ wrap.appendChild(header);
764
+ const body = document.createElement("div");
765
+ body.className = "section-body";
766
+ if (!count) {
767
+ const empty = document.createElement("p");
768
+ empty.className = "pre-section-empty";
769
+ empty.textContent = "There are no modules in this section yet.";
770
+ body.appendChild(empty);
771
+ } else {
772
+ const moduleList = document.createElement("div");
773
+ moduleList.className = "pre-module-list";
774
+ sec.modules.forEach((mod, mIdx) => {
775
+ if (mIdx > 0) {
776
+ const sep = document.createElement("div");
777
+ sep.className = "module-sep";
778
+ moduleList.appendChild(sep);
779
+ }
780
+ moduleList.appendChild(this._buildPreEnrollModule(mod, sIdx, mIdx));
781
+ });
782
+ body.appendChild(moduleList);
783
+ }
784
+ wrap.appendChild(body);
785
+ return wrap;
786
+ }
787
+ // ── Pre-enrollment module row ──────────────────────────────────────────────
788
+ _buildPreEnrollModule(mod, sIdx, mIdx) {
789
+ const plusSvg = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>`;
790
+ const minusSvg = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><line x1="5" y1="12" x2="19" y2="12"/></svg>`;
791
+ const wrap = document.createElement("div");
792
+ wrap.className = "pre-module-wrap";
793
+ const row = document.createElement("div");
794
+ row.className = "pre-module-row";
795
+ const typeIcon = document.createElement("span");
796
+ typeIcon.className = "module-type-icon";
797
+ typeIcon.innerHTML = this._smallIcon(mod.type);
798
+ const titleEl = document.createElement("span");
799
+ titleEl.className = "pre-module-title";
800
+ titleEl.textContent = mod.title;
801
+ const badges = document.createElement("div");
802
+ badges.className = "pre-module-badges";
803
+ if (mod.inactive) {
804
+ const b = document.createElement("span");
805
+ b.className = "pre-badge pre-badge--inactive";
806
+ b.textContent = "Inactive";
807
+ badges.appendChild(b);
808
+ }
809
+ if (mod.optional) {
810
+ const b = document.createElement("span");
811
+ b.className = "pre-badge pre-badge--optional";
812
+ b.textContent = "Optional";
813
+ badges.appendChild(b);
814
+ }
815
+ let descEl = null;
816
+ if (mod.description) {
817
+ descEl = document.createElement("p");
818
+ descEl.className = "pre-module-desc";
819
+ descEl.textContent = mod.description;
820
+ descEl.hidden = true;
821
+ }
822
+ const titleGroup = document.createElement("div");
823
+ titleGroup.className = "pre-module-title-group";
824
+ titleGroup.append(titleEl, badges);
825
+ row.append(typeIcon, titleGroup);
826
+ if (descEl) {
827
+ const toggleBtn = document.createElement("button");
828
+ toggleBtn.className = "pre-module-toggle";
829
+ toggleBtn.setAttribute("aria-expanded", "false");
830
+ toggleBtn.innerHTML = plusSvg;
831
+ toggleBtn.addEventListener("click", (e) => {
832
+ e.stopPropagation();
833
+ const nowExpanded = toggleBtn.getAttribute("aria-expanded") !== "true";
834
+ toggleBtn.setAttribute("aria-expanded", String(nowExpanded));
835
+ toggleBtn.innerHTML = nowExpanded ? minusSvg : plusSvg;
836
+ descEl.hidden = !nowExpanded;
837
+ wrap.classList.toggle("pre-module-wrap--expanded", nowExpanded);
838
+ this.dispatchEvent(
839
+ new CustomEvent("bv-module-toggle", {
840
+ bubbles: true,
841
+ composed: true,
842
+ detail: { sectionIndex: sIdx, moduleIndex: mIdx, expanded: nowExpanded }
843
+ })
844
+ );
845
+ });
846
+ row.appendChild(toggleBtn);
847
+ wrap.appendChild(row);
848
+ wrap.appendChild(descEl);
849
+ } else {
850
+ wrap.appendChild(row);
851
+ }
852
+ return wrap;
853
+ }
854
+ };
855
+ if (!customElements.get("bv-course-outline")) {
856
+ customElements.define("bv-course-outline", BvCourseOutline);
857
+ }
858
+
859
+ // css-inline:/home/runner/work/BV_lumen/BV_lumen/components/bv-button/bv-button.css
860
+ 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
861
+ Apps can override these three properties per-instance:
862
+
863
+ HTML: <bv-button style="--bv-button-bg: #e53e3e;">
864
+ Angular: <bv-button [style.--bv-button-bg]="brandColor">
865
+ JavaScript: btn.style.setProperty('--bv-button-bg', value)
866
+
867
+ Hover is auto-computed from the base colors via color-mix().
868
+ Override --bv-button-bg-hover / --bv-button-border-color-hover
869
+ if you need explicit control over the hovered state.
870
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
871
+ :host {
872
+ /* Default values \u2014 map to global tokens (primary variant) */
873
+ --bv-button-bg: var(--bv-color-primary);
874
+ --bv-button-bg-hover: color-mix(in srgb, var(--bv-button-bg) 82%, black);
875
+ --bv-button-color: var(--bv-color-neutral-0);
876
+ --bv-button-border-color: var(--bv-color-primary);
877
+ --bv-button-border-color-hover: color-mix(in srgb, var(--bv-button-border-color) 82%, black);
878
+ --bv-button-font-family: var(--bv-font-family-base);
879
+ --bv-button-font-size: var(--bv-font-size-sm);
880
+
881
+ display: inline-block;
882
+ font-family: var(--bv-font-family-base);
883
+ }
884
+
885
+ :host([hidden]) {
886
+ display: none;
887
+ }
888
+
889
+ :host([full-width]) {
890
+ display: block;
891
+ width: 100%;
892
+ }
893
+
894
+ /* \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
895
+ Each variant re-points the component tokens to different global
896
+ tokens. Apps can still override with inline styles \u2014 inline style
897
+ always wins due to higher specificity.
898
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
899
+
900
+ :host([variant='secondary']) {
901
+ --bv-button-bg: var(--bv-color-secondary);
902
+ --bv-button-border-color: var(--bv-color-secondary);
903
+ --bv-button-color: var(--bv-color-secondary-foreground);
904
+ }
905
+
906
+ :host([variant='tertiary']) {
907
+ --bv-button-bg: var(--bv-color-tertiary);
908
+ --bv-button-border-color: var(--bv-color-tertiary);
909
+ }
910
+
911
+ :host([variant='danger']) {
912
+ --bv-button-bg: var(--bv-color-danger);
913
+ --bv-button-border-color: var(--bv-color-danger);
914
+ }
915
+
916
+ :host([variant='ghost']) {
917
+ --bv-button-bg: transparent;
918
+ --bv-button-bg-hover: var(--bv-color-primary-light);
919
+ --bv-button-color: var(--bv-color-primary);
920
+ --bv-button-border-color: transparent;
921
+ --bv-button-border-color-hover: transparent;
922
+ }
923
+
924
+ :host([variant='outline']) {
925
+ --bv-button-bg: transparent;
926
+ --bv-button-bg-hover: var(--bv-color-primary-light);
927
+ --bv-button-color: var(--bv-color-primary);
928
+ --bv-button-border-color: var(--bv-color-primary);
929
+ --bv-button-border-color-hover: var(--bv-color-primary);
930
+ }
931
+
932
+ /* \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
933
+ All visual properties read from the component-level tokens above.
934
+ \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
935
+
936
+ .btn {
937
+ display: inline-flex;
938
+ align-items: center;
939
+ justify-content: center;
940
+ gap: var(--bv-spacing-xs);
941
+ padding: 10px var(--bv-spacing-md);
942
+ min-height: 40px;
943
+ width: auto;
944
+ font-family: var(--bv-button-font-family);
945
+ font-size: var(--bv-button-font-size);
946
+ font-style: normal;
947
+ font-weight: var(--bv-font-weight-semibold);
948
+ line-height: 20px;
949
+ border: 1px solid var(--bv-button-border-color);
950
+ border-radius: var(--bv-radius-lg);
951
+ cursor: pointer;
952
+ transition:
953
+ background var(--bv-transition-fast),
954
+ color var(--bv-transition-fast),
955
+ border-color var(--bv-transition-fast),
956
+ box-shadow var(--bv-transition-fast),
957
+ opacity var(--bv-transition-fast);
958
+ white-space: nowrap;
959
+ user-select: none;
960
+ text-decoration: none;
961
+ outline: none;
962
+ box-sizing: border-box;
963
+ background: var(--bv-button-bg);
964
+ color: var(--bv-button-color);
965
+ box-shadow: var(--bv-shadow-sm);
966
+ }
967
+
968
+ :host([full-width]) .btn {
969
+ width: 100%;
970
+ }
971
+
972
+ .btn:hover:not(:disabled) {
973
+ background: var(--bv-button-bg-hover);
974
+ border-color: var(--bv-button-border-color-hover);
975
+ }
976
+
977
+ .btn:active:not(:disabled) {
978
+ transform: translateY(1px);
979
+ }
980
+
981
+ .btn:focus-visible {
982
+ outline: 2px solid var(--bv-button-border-color);
983
+ outline-offset: 2px;
984
+ }
985
+
986
+ .btn:disabled {
987
+ opacity: 0.5;
988
+ cursor: not-allowed;
989
+ pointer-events: none;
990
+ }
991
+
992
+ /* \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*/
993
+
994
+ :host([size='sm']) .btn {
995
+ padding: 6px 12px;
996
+ min-height: 32px;
997
+ font-size: var(--bv-font-size-sm);
998
+ }
999
+
1000
+ :host([size='lg']) .btn {
1001
+ padding: 12px var(--bv-spacing-lg);
1002
+ min-height: 48px;
1003
+ font-size: var(--bv-font-size-md);
1004
+ }
1005
+
1006
+ /* \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*/
1007
+
1008
+ .btn-icon {
1009
+ display: inline-flex;
1010
+ align-items: center;
1011
+ flex-shrink: 0;
1012
+ line-height: 0;
1013
+ }
1014
+
1015
+ /* \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*/
1016
+
1017
+ .btn-count {
1018
+ opacity: 0.8;
1019
+ font-weight: var(--bv-font-weight-regular);
1020
+ }
1021
+
1022
+ /* \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*/
1023
+
1024
+ .spinner {
1025
+ display: inline-block;
1026
+ width: 1em;
1027
+ height: 1em;
1028
+ border: 2px solid currentColor;
1029
+ border-top-color: transparent;
1030
+ border-radius: 50%;
1031
+ flex-shrink: 0;
1032
+ animation: bv-spin 700ms linear infinite;
1033
+ }
1034
+
1035
+ @keyframes bv-spin {
1036
+ to {
1037
+ transform: rotate(360deg);
1038
+ }
1039
+ }
1040
+ `;
1041
+
1042
+ // components/bv-icon/icons.ts
1043
+ var icons = {
1044
+ // Navigation
1045
+ "chevron-up": `<path d="M18 15l-6-6-6 6"/>`,
1046
+ "chevron-down": `<path d="M6 9l6 6 6-6"/>`,
1047
+ "chevron-left": `<path d="M15 18l-6-6 6-6"/>`,
1048
+ "chevron-right": `<path d="M9 18l6-6-6-6"/>`,
1049
+ "arrow-left": `<path d="M19 12H5M12 19l-7-7 7-7"/>`,
1050
+ "arrow-right": `<path d="M5 12h14M12 5l7 7-7 7"/>`,
1051
+ "external-link": `<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/><polyline points="15,3 21,3 21,9"/><line x1="10" y1="14" x2="21" y2="3"/>`,
1052
+ // Actions
1053
+ search: `<circle cx="11" cy="11" r="8"/><line x1="21" y1="21" x2="16.65" y2="16.65"/>`,
1054
+ edit: `<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>`,
1055
+ download: `<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7,10 12,15 17,10"/><line x1="12" y1="15" x2="12" y2="3"/>`,
1056
+ upload: `<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17,8 12,3 7,8"/><line x1="12" y1="3" x2="12" y2="15"/>`,
1057
+ plus: `<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>`,
1058
+ minus: `<line x1="5" y1="12" x2="19" y2="12"/>`,
1059
+ x: `<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>`,
1060
+ check: `<polyline points="20,6 9,17 4,12"/>`,
1061
+ trash: `<polyline points="3,6 5,6 21,6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6M14 11v6"/><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/>`,
1062
+ copy: `<rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/>`,
1063
+ refresh: `<polyline points="23,4 23,10 17,10"/><polyline points="1,20 1,14 7,14"/><path d="M3.51 9a9 9 0 0 1 14.85-3.36L23 10M1 14l4.64 4.36A9 9 0 0 0 20.49 15"/>`,
1064
+ filter: `<polygon points="22,3 2,3 10,12.46 10,19 14,21 14,12.46 22,3"/>`,
1065
+ // Layout
1066
+ list: `<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>`,
1067
+ grid: `<rect x="3" y="3" width="7" height="7"/><rect x="14" y="3" width="7" height="7"/><rect x="14" y="14" width="7" height="7"/><rect x="3" y="14" width="7" height="7"/>`,
1068
+ // User / profile
1069
+ user: `<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>`,
1070
+ users: `<path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/>`,
1071
+ // Content
1072
+ star: `<polygon points="12,2 15.09,8.26 22,9.27 17,14.14 18.18,21.02 12,17.77 5.82,21.02 7,14.14 2,9.27 8.91,8.26 12,2"/>`,
1073
+ eye: `<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z"/><circle cx="12" cy="12" r="3"/>`,
1074
+ "eye-off": `<path d="M17.94 17.94A10.07 10.07 0 0 1 12 20c-7 0-11-8-11-8a18.45 18.45 0 0 1 5.06-5.94M9.9 4.24A9.12 9.12 0 0 1 12 4c7 0 11 8 11 8a18.5 18.5 0 0 1-2.16 3.19m-6.72-1.07a3 3 0 1 1-4.24-4.24"/><line x1="1" y1="1" x2="23" y2="23"/>`,
1075
+ bookmark: `<path d="M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2z"/>`,
1076
+ tag: `<path d="M20.59 13.41l-7.17 7.17a2 2 0 0 1-2.83 0L2 12V2h10l8.59 8.59a2 2 0 0 1 0 2.82z"/><line x1="7" y1="7" x2="7.01" y2="7"/>`,
1077
+ // Status / feedback
1078
+ info: `<circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/>`,
1079
+ "alert-triangle": `<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>`,
1080
+ "check-circle": `<path d="M22 11.08V12a10 10 0 1 1-5.93-9.14"/><polyline points="22,4 12,14.01 9,11.01"/>`,
1081
+ "x-circle": `<circle cx="12" cy="12" r="10"/><line x1="15" y1="9" x2="9" y2="15"/><line x1="9" y1="9" x2="15" y2="15"/>`,
1082
+ // Files / media
1083
+ file: `<path d="M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z"/><polyline points="13,2 13,9 20,9"/>`,
1084
+ image: `<rect x="3" y="3" width="18" height="18" rx="2" ry="2"/><circle cx="8.5" cy="8.5" r="1.5"/><polyline points="21,15 16,10 5,21"/>`,
1085
+ video: `<polygon points="23,7 16,12 23,17 23,7"/><rect x="1" y="5" width="15" height="14" rx="2" ry="2"/>`,
1086
+ // Settings
1087
+ settings: `<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>`,
1088
+ lock: `<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 10 0v4"/>`,
1089
+ unlock: `<rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0 1 9.9-1"/>`,
1090
+ bell: `<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/>`,
1091
+ mail: `<path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/>`,
1092
+ link: `<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>`
1093
+ };
1094
+ function getIconSvg(name, size = 16) {
1095
+ const raw = rawIcons[name];
1096
+ if (raw)
1097
+ return raw.replace(/width="[^"]*"/, `width="${size}"`).replace(/height="[^"]*"/, `height="${size}"`);
1098
+ const paths = icons[name];
1099
+ if (!paths) return "";
1100
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${size}" height="${size}" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${paths}</svg>`;
1101
+ }
1102
+ var rawIcons = {
1103
+ // Module type (small, ~18px)
1104
+ "module-scorm": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 15.03 16.28" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13.9014 4.60034L7.51368 8.14201M7.51368 8.14201L1.126 4.60034M7.51368 8.14201L7.5137 15.267M14.2771 11.1859V5.09812C14.2771 4.84113 14.2771 4.71264 14.2392 4.59804C14.2056 4.49666 14.1508 4.4036 14.0783 4.32508C13.9963 4.23633 13.8838 4.17393 13.6587 4.04913L8.09763 0.965793C7.88451 0.847624 7.77794 0.78854 7.66509 0.765376C7.56521 0.744875 7.46219 0.744875 7.36231 0.765376C7.24946 0.78854 7.1429 0.847624 6.92977 0.965793L1.36873 4.04913C1.14364 4.17393 1.0311 4.23633 0.949147 4.32508C0.876647 4.4036 0.82178 4.49666 0.788217 4.59804C0.750278 4.71264 0.750278 4.84113 0.750278 5.09812V11.1859C0.750278 11.4429 0.750278 11.5714 0.788217 11.686C0.82178 11.7874 0.876647 11.8805 0.949147 11.959C1.0311 12.0477 1.14364 12.1101 1.36873 12.2349L6.92977 15.3183C7.1429 15.4364 7.24946 15.4955 7.36231 15.5187C7.46219 15.5392 7.56521 15.5392 7.66509 15.5187C7.77794 15.4955 7.88451 15.4364 8.09763 15.3183L13.6587 12.2349C13.8838 12.1101 13.9963 12.0477 14.0783 11.959C14.1508 11.8805 14.2056 11.7874 14.2392 11.686C14.2771 11.5714 14.2771 11.4429 14.2771 11.1859Z"/></svg>`,
1105
+ "module-assessment": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 13.72 16.13" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12.507 6.1875V4.1625C12.507 2.90238 12.507 2.27232 12.2629 1.79102C12.0482 1.36766 11.7056 1.02345 11.2841 0.807736C10.8051 0.5625 10.1779 0.5625 8.92364 0.5625H4.14585C2.89156 0.5625 2.26441 0.5625 1.78534 0.807736C1.36393 1.02345 1.02132 1.36766 0.806601 1.79102C0.5625 2.27232 0.5625 2.90238 0.5625 4.1625V11.9625C0.5625 13.2226 0.5625 13.8527 0.806601 14.334C1.02132 14.7573 1.36393 15.1015 1.78534 15.3173C2.26441 15.5625 2.89156 15.5625 4.14585 15.5625H8.0278M8.0278 7.3125H3.54862M5.04168 10.3125H3.54862M9.52086 4.3125H3.54862M9.89413 10.3142C10.0257 9.93852 10.2853 9.62175 10.627 9.41998C10.9688 9.21821 11.3705 9.14445 11.7612 9.21178C12.1519 9.2791 12.5062 9.48315 12.7615 9.7878C13.0168 10.0925 13.1565 10.478 13.1559 10.8763C13.1559 12.0004 11.4775 12.5625 11.4775 12.5625M11.4991 14.8125H11.5066"/></svg>`,
1106
+ "module-survey": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 14.56 11.63" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 5.8125L5.04168 5.8125M14 1.3125L5.04168 1.3125M14 10.3125L5.04168 10.3125M2.05556 5.8125C2.05556 6.22671 1.72133 6.5625 1.30903 6.5625C0.896733 6.5625 0.5625 6.22671 0.5625 5.8125C0.5625 5.39829 0.896733 5.0625 1.30903 5.0625C1.72133 5.0625 2.05556 5.39829 2.05556 5.8125ZM2.05556 1.3125C2.05556 1.72671 1.72133 2.0625 1.30903 2.0625C0.896733 2.0625 0.5625 1.72671 0.5625 1.3125C0.5625 0.898286 0.896733 0.5625 1.30903 0.5625C1.72133 0.5625 2.05556 0.898286 2.05556 1.3125ZM2.05556 10.3125C2.05556 10.7267 1.72133 11.0625 1.30903 11.0625C0.896733 11.0625 0.5625 10.7267 0.5625 10.3125C0.5625 9.89829 0.896733 9.5625 1.30903 9.5625C1.72133 9.5625 2.05556 9.89829 2.05556 10.3125Z"/></svg>`,
1107
+ "module-download": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16.06 14.63" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8.77433 3.56259L7.94155 1.88928C7.70187 1.40769 7.58202 1.16689 7.40323 0.990961C7.24512 0.835387 7.05457 0.717069 6.84535 0.644571C6.60877 0.562589 6.3408 0.562589 5.80485 0.562589H2.9514C2.1152 0.562589 1.69711 0.562589 1.37773 0.726079C1.09679 0.869889 0.868379 1.09936 0.725234 1.3816C0.562501 1.70247 0.562501 2.12251 0.562501 2.96259V3.56259M0.562501 3.56259H11.9098C13.164 3.56259 13.7912 3.56259 14.2703 3.80782C14.6917 4.02354 15.0343 4.36775 15.249 4.79111C15.4931 5.27241 15.4931 5.90247 15.4931 7.16259V10.4626C15.4931 11.7227 15.4931 12.3528 15.249 12.8341C15.0343 13.2574 14.6917 13.6016 14.2703 13.8174C13.7912 14.0626 13.164 14.0626 11.9098 14.0626H4.14585C2.89156 14.0626 2.26441 14.0626 1.78534 13.8174C1.36393 13.6016 1.02132 13.2574 0.806601 12.8341C0.562501 12.3528 0.562501 11.7227 0.562501 10.4626V3.56259ZM10.2674 8.81259L8.0278 11.0626L5.78821 8.81259M8.0278 11.0626V6.56259"/></svg>`,
1108
+ "module-link": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 15.97 16.03" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M6.49261 8.76267C6.81321 9.19327 7.22223 9.54956 7.69194 9.80737C8.16166 10.0652 8.68106 10.2185 9.21494 10.2569C9.74882 10.2953 10.2847 10.2179 10.7862 10.03C11.2876 9.84207 11.743 9.54797 12.1214 9.16767L14.361 6.91767C15.041 6.21041 15.4172 5.26315 15.4087 4.27991C15.4002 3.29668 15.0076 2.35613 14.3156 1.66085C13.6235 0.965569 12.6873 0.571186 11.7086 0.562642C10.7299 0.554098 9.78705 0.932077 9.08307 1.61517L7.79903 2.89767M9.47873 7.26267C9.15813 6.83207 8.7491 6.47578 8.27939 6.21796C7.80968 5.96015 7.29027 5.80683 6.75639 5.76842C6.22252 5.73001 5.68666 5.80739 5.18517 5.99533C4.68369 6.18327 4.2283 6.47737 3.84989 6.85767L1.6103 9.10767C0.930367 9.81493 0.554137 10.7622 0.562641 11.7454C0.571146 12.7287 0.963705 13.6692 1.65577 14.3645C2.34783 15.0598 3.28403 15.4542 4.26272 15.4627C5.24141 15.4712 6.18428 15.0933 6.88827 14.4102L8.16483 13.1277"/></svg>`,
1109
+ "module-adobe-connect": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16.06 14.63" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M11.7605 0.56252L8.0278 3.56252L4.29515 0.56252M4.14585 14.0625H11.9098C13.164 14.0625 13.7912 14.0625 14.2703 13.8173C14.6917 13.6016 15.0343 13.2574 15.249 12.834C15.4931 12.3527 15.4931 11.7226 15.4931 10.4625V7.16252C15.4931 5.9024 15.4931 5.27234 15.249 4.79104C15.0343 4.36768 14.6917 4.02347 14.2703 3.80776C13.7912 3.56252 13.164 3.56252 11.9098 3.56252H4.14585C2.89156 3.56252 2.26441 3.56252 1.78534 3.80776C1.36393 4.02347 1.02132 4.36768 0.806601 4.79104C0.5625 5.27234 0.5625 5.9024 0.5625 7.16252V10.4625C0.5625 11.7226 0.5625 12.3527 0.806601 12.834C1.02132 13.2574 1.36393 13.6016 1.78534 13.8173C2.26441 14.0625 2.89156 14.0625 4.14585 14.0625Z"/></svg>`,
1110
+ "module-video": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 16.06 11.63" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M15.4931 3.51103C15.4931 3.05667 15.4931 2.82949 15.4037 2.72429C15.3261 2.63301 15.2097 2.58457 15.0906 2.59399C14.9533 2.60484 14.7934 2.76548 14.4736 3.08676L11.7605 5.8125L14.4736 8.53824C14.7934 8.85952 14.9533 9.02016 15.0906 9.03101C15.2097 9.04043 15.3261 8.99199 15.4037 8.90071C15.4931 8.79552 15.4931 8.56833 15.4931 8.11397V3.51103ZM0.5625 4.1625C0.5625 2.90238 0.5625 2.27232 0.806601 1.79102C1.02132 1.36766 1.36393 1.02345 1.78534 0.807736C2.26441 0.5625 2.89156 0.5625 4.14585 0.5625H8.17711C9.4314 0.5625 10.0585 0.5625 10.5376 0.807736C10.959 1.02345 11.3016 1.36766 11.5164 1.79102C11.7605 2.27232 11.7605 2.90238 11.7605 4.1625V7.4625C11.7605 8.72262 11.7605 9.35268 11.5164 9.83398C11.3016 10.2573 10.959 10.6015 10.5376 10.8173C10.0585 11.0625 9.4314 11.0625 8.17711 11.0625H4.14584C2.89156 11.0625 2.26441 11.0625 1.78534 10.8173C1.36393 10.6015 1.02132 10.2573 0.806601 9.83398C0.5625 9.35268 0.5625 8.72262 0.5625 7.4625V4.1625Z"/></svg>`,
1111
+ "module-upload": `<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 14.75 16.13" fill="none" stroke="currentColor" stroke-width="1.125" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M13.39 4.3125V4.1625C13.39 2.90238 13.39 2.27232 13.1278 1.79102C12.8972 1.36766 12.5293 1.02345 12.0767 0.807736C11.5622 0.5625 10.8887 0.5625 9.54172 0.5625H4.41074C3.06373 0.5625 2.39022 0.5625 1.87573 0.807736C1.42318 1.02345 1.05524 1.36766 0.824646 1.79102C0.5625 2.27232 0.5625 2.90238 0.5625 4.1625V11.9625C0.5625 13.2226 0.5625 13.8527 0.824646 14.334C1.05524 14.7573 1.42318 15.1015 1.87573 15.3173C2.39022 15.5625 3.06373 15.5625 4.41074 15.5625H7.37709M7.37709 7.3125H3.76936M6.57537 10.3125H3.76936M10.1831 4.3125H3.76936M11.7865 12.5625V8.4375C11.7865 7.81618 12.3249 7.3125 12.9891 7.3125C13.6533 7.3125 14.1917 7.81618 14.1917 8.4375V12.5625C14.1917 13.8051 13.1149 14.8125 11.7865 14.8125C10.4582 14.8125 9.38138 13.8051 9.38138 12.5625V9.5625"/></svg>`
1112
+ };
1113
+
1114
+ // components/bv-button/bv-button.ts
1115
+ var _sheet3 = null;
1116
+ function getSheet3() {
1117
+ if (!_sheet3) {
1118
+ _sheet3 = new CSSStyleSheet();
1119
+ _sheet3.replaceSync(bv_button_default);
1120
+ }
1121
+ return _sheet3;
1122
+ }
1123
+ var BvButton = class extends HTMLElement {
1124
+ static observedAttributes = [
1125
+ "variant",
1126
+ "size",
1127
+ "disabled",
1128
+ "loading",
1129
+ "type",
1130
+ "full-width",
1131
+ "icon",
1132
+ "icon-position",
1133
+ "count"
1134
+ ];
1135
+ constructor() {
1136
+ super();
1137
+ const shadow = this.attachShadow({ mode: "open" });
1138
+ if ("adoptedStyleSheets" in ShadowRoot.prototype) {
1139
+ shadow.adoptedStyleSheets = [getSheet3()];
1140
+ }
1141
+ }
1142
+ // ── Accessors ────────────────────────────────────────────────
1143
+ get variant() {
1144
+ return this.getAttribute("variant") ?? "primary";
1145
+ }
1146
+ set variant(value) {
1147
+ this.setAttribute("variant", value);
1148
+ }
1149
+ get size() {
1150
+ return this.getAttribute("size") ?? "md";
1151
+ }
1152
+ set size(value) {
1153
+ this.setAttribute("size", value);
1154
+ }
1155
+ get disabled() {
1156
+ return this.hasAttribute("disabled");
1157
+ }
1158
+ set disabled(value) {
1159
+ if (value) this.setAttribute("disabled", "");
1160
+ else this.removeAttribute("disabled");
1161
+ }
1162
+ get loading() {
1163
+ return this.hasAttribute("loading");
1164
+ }
1165
+ set loading(value) {
1166
+ if (value) this.setAttribute("loading", "");
1167
+ else this.removeAttribute("loading");
1168
+ }
1169
+ get type() {
1170
+ const t = this.getAttribute("type");
1171
+ return t === "submit" || t === "reset" ? t : "button";
1172
+ }
1173
+ set type(value) {
1174
+ this.setAttribute("type", value);
1175
+ }
1176
+ get fullWidth() {
1177
+ return this.hasAttribute("full-width");
1178
+ }
1179
+ set fullWidth(value) {
1180
+ if (value) this.setAttribute("full-width", "");
1181
+ else this.removeAttribute("full-width");
1182
+ }
1183
+ // ── Lifecycle ────────────────────────────────────────────────
1184
+ connectedCallback() {
1185
+ this._render();
1186
+ }
1187
+ attributeChangedCallback(_name, oldValue, newValue) {
1188
+ if (oldValue === newValue) return;
1189
+ this._render();
1190
+ }
1191
+ // ── Rendering ────────────────────────────────────────────────
1192
+ _render() {
1193
+ var _a;
1194
+ const shadow = this.shadowRoot;
1195
+ let btn = shadow.querySelector("button");
1196
+ if (!btn) {
1197
+ if (!shadow.adoptedStyleSheets.length) {
1198
+ const styleEl = document.createElement("style");
1199
+ styleEl.textContent = bv_button_default;
1200
+ shadow.appendChild(styleEl);
1201
+ }
1202
+ btn = document.createElement("button");
1203
+ btn.setAttribute("part", "button");
1204
+ btn.appendChild(document.createElement("slot"));
1205
+ shadow.appendChild(btn);
1206
+ }
1207
+ btn.type = this.type;
1208
+ btn.disabled = this.disabled || this.loading;
1209
+ btn.className = "btn";
1210
+ if (this.loading) {
1211
+ btn.setAttribute("aria-busy", "true");
1212
+ if (!btn.querySelector(".spinner")) {
1213
+ const spinner = document.createElement("span");
1214
+ spinner.className = "spinner";
1215
+ spinner.setAttribute("aria-hidden", "true");
1216
+ btn.insertBefore(spinner, btn.querySelector("slot"));
1217
+ }
1218
+ } else {
1219
+ btn.removeAttribute("aria-busy");
1220
+ (_a = btn.querySelector(".spinner")) == null ? void 0 : _a.remove();
1221
+ }
1222
+ btn.querySelectorAll(".btn-icon").forEach((el) => el.remove());
1223
+ const iconName = this.getAttribute("icon");
1224
+ if (iconName) {
1225
+ const svg = getIconSvg(iconName, 16);
1226
+ if (svg) {
1227
+ const iconEl = document.createElement("span");
1228
+ iconEl.className = "btn-icon";
1229
+ iconEl.innerHTML = svg;
1230
+ const slot = btn.querySelector("slot");
1231
+ if (this.getAttribute("icon-position") === "right") {
1232
+ btn.appendChild(iconEl);
1233
+ } else {
1234
+ btn.insertBefore(iconEl, slot);
1235
+ }
1236
+ }
1237
+ }
1238
+ btn.querySelectorAll(".btn-count").forEach((el) => el.remove());
1239
+ const countVal = this.getAttribute("count");
1240
+ if (countVal && Number(countVal) > 0) {
1241
+ const countEl = document.createElement("span");
1242
+ countEl.className = "btn-count";
1243
+ countEl.textContent = `(${countVal})`;
1244
+ btn.appendChild(countEl);
1245
+ }
1246
+ }
1247
+ };
1248
+ if (!customElements.get("bv-button")) {
1249
+ customElements.define("bv-button", BvButton);
1250
+ }
1251
+
1252
+ // components/bv-course-detail-modal/bv-course-detail-modal.ts
1253
+ var _sheet4 = null;
1254
+ function getSheet4() {
1255
+ if (!_sheet4) {
1256
+ _sheet4 = new CSSStyleSheet();
1257
+ _sheet4.replaceSync(bv_course_detail_modal_default);
1258
+ }
1259
+ return _sheet4;
1260
+ }
1261
+ var BvCourseDetailModal = class extends HTMLElement {
1262
+ static observedAttributes = [
1263
+ "open",
1264
+ "title",
1265
+ "course-title",
1266
+ "thumbnail",
1267
+ "description",
1268
+ "categories",
1269
+ "sections",
1270
+ "outline-mode"
1271
+ ];
1272
+ _rendered = false;
1273
+ _categories = [];
1274
+ _sections = [];
1275
+ _modalEl = null;
1276
+ _detailEl = null;
1277
+ _showOutlineBtn = null;
1278
+ _outlineEl = null;
1279
+ constructor() {
1280
+ super();
1281
+ const shadow = this.attachShadow({ mode: "open" });
1282
+ if ("adoptedStyleSheets" in ShadowRoot.prototype) {
1283
+ shadow.adoptedStyleSheets = [getSheet4()];
1284
+ }
1285
+ }
1286
+ get open() {
1287
+ return this.hasAttribute("open");
1288
+ }
1289
+ set open(v) {
1290
+ if (v) this.setAttribute("open", "");
1291
+ else this.removeAttribute("open");
1292
+ }
1293
+ get title() {
1294
+ return this.getAttribute("title") ?? "";
1295
+ }
1296
+ set title(v) {
1297
+ this.setAttribute("title", v);
1298
+ }
1299
+ get courseTitle() {
1300
+ return this.getAttribute("course-title") ?? "";
1301
+ }
1302
+ set courseTitle(v) {
1303
+ this.setAttribute("course-title", v);
1304
+ }
1305
+ get thumbnail() {
1306
+ return this.getAttribute("thumbnail") ?? "";
1307
+ }
1308
+ set thumbnail(v) {
1309
+ this.setAttribute("thumbnail", v);
1310
+ }
1311
+ get description() {
1312
+ return this.getAttribute("description") ?? "";
1313
+ }
1314
+ set description(v) {
1315
+ this.setAttribute("description", v);
1316
+ }
1317
+ get categories() {
1318
+ return this._categories;
1319
+ }
1320
+ set categories(v) {
1321
+ this._categories = v;
1322
+ this.setAttribute("categories", JSON.stringify(v));
1323
+ if (this._rendered && this._detailEl) this._detailEl.categories = v;
1324
+ }
1325
+ get sections() {
1326
+ return this._sections;
1327
+ }
1328
+ set sections(v) {
1329
+ this._sections = v;
1330
+ this.setAttribute("sections", JSON.stringify(v));
1331
+ if (this._rendered && this._outlineEl) this._outlineEl.sections = v;
1332
+ }
1333
+ get outlineMode() {
1334
+ return this.getAttribute("outline-mode") ?? "pre-enrollment";
1335
+ }
1336
+ set outlineMode(v) {
1337
+ this.setAttribute("outline-mode", v);
1338
+ }
1339
+ connectedCallback() {
1340
+ this._render();
1341
+ }
1342
+ attributeChangedCallback(name, _old, val) {
1343
+ var _a, _b, _c, _d, _e, _f;
1344
+ if (!this._rendered) return;
1345
+ switch (name) {
1346
+ case "open":
1347
+ if (this._modalEl) this._modalEl.toggleAttribute("open", this.hasAttribute("open"));
1348
+ if (this.hasAttribute("open") && this._showOutlineBtn && this._outlineEl) {
1349
+ this._showOutlineBtn.hidden = false;
1350
+ this._outlineEl.hidden = true;
1351
+ }
1352
+ break;
1353
+ case "title":
1354
+ (_a = this._modalEl) == null ? void 0 : _a.setAttribute("title", val ?? "");
1355
+ break;
1356
+ case "course-title":
1357
+ (_b = this._detailEl) == null ? void 0 : _b.setAttribute("title", val ?? "");
1358
+ break;
1359
+ case "thumbnail":
1360
+ if (val) (_c = this._detailEl) == null ? void 0 : _c.setAttribute("thumbnail", val);
1361
+ else (_d = this._detailEl) == null ? void 0 : _d.removeAttribute("thumbnail");
1362
+ break;
1363
+ case "description":
1364
+ (_e = this._detailEl) == null ? void 0 : _e.setAttribute("description", val ?? "");
1365
+ break;
1366
+ case "categories":
1367
+ try {
1368
+ this._categories = JSON.parse(val ?? "[]");
1369
+ } catch {
1370
+ this._categories = [];
1371
+ }
1372
+ if (this._detailEl) this._detailEl.categories = this._categories;
1373
+ break;
1374
+ case "sections":
1375
+ try {
1376
+ this._sections = JSON.parse(val ?? "[]");
1377
+ } catch {
1378
+ this._sections = [];
1379
+ }
1380
+ if (this._outlineEl) this._outlineEl.sections = this._sections;
1381
+ break;
1382
+ case "outline-mode":
1383
+ (_f = this._outlineEl) == null ? void 0 : _f.setAttribute("mode", val ?? "pre-enrollment");
1384
+ break;
1385
+ }
1386
+ }
1387
+ _render() {
1388
+ if (this._rendered) return;
1389
+ this._rendered = true;
1390
+ const attrCats = this.getAttribute("categories");
1391
+ if (attrCats) {
1392
+ try {
1393
+ this._categories = JSON.parse(attrCats);
1394
+ } catch {
1395
+ this._categories = [];
1396
+ }
1397
+ }
1398
+ const attrSecs = this.getAttribute("sections");
1399
+ if (attrSecs) {
1400
+ try {
1401
+ this._sections = JSON.parse(attrSecs);
1402
+ } catch {
1403
+ this._sections = [];
1404
+ }
1405
+ }
1406
+ const shadow = this.shadowRoot;
1407
+ if (!shadow.adoptedStyleSheets.length) {
1408
+ const s = document.createElement("style");
1409
+ s.textContent = bv_course_detail_modal_default;
1410
+ shadow.appendChild(s);
1411
+ }
1412
+ const modal = document.createElement("bv-modal");
1413
+ modal.setAttribute("title", this.title);
1414
+ if (this.open) modal.setAttribute("open", "");
1415
+ modal.style.setProperty("--bv-modal-width", "600px");
1416
+ modal.style.setProperty("--bv-modal-body-max-height", "65vh");
1417
+ this._modalEl = modal;
1418
+ modal.addEventListener("bv-close", () => {
1419
+ this.removeAttribute("open");
1420
+ this.dispatchEvent(new CustomEvent("bv-close", { bubbles: true, composed: true }));
1421
+ });
1422
+ const detail = document.createElement("bv-course-detail");
1423
+ detail.setAttribute("title", this.courseTitle);
1424
+ detail.setAttribute("description", this.description);
1425
+ if (this.thumbnail) detail.setAttribute("thumbnail", this.thumbnail);
1426
+ detail.categories = this._categories;
1427
+ this._detailEl = detail;
1428
+ const showBtn = document.createElement("bv-button");
1429
+ showBtn.setAttribute("variant", "secondary");
1430
+ showBtn.setAttribute("full-width", "");
1431
+ showBtn.textContent = "Show Course Outline";
1432
+ this._showOutlineBtn = showBtn;
1433
+ const outline = document.createElement("bv-course-outline");
1434
+ outline.setAttribute("mode", this.outlineMode);
1435
+ outline.sections = this._sections;
1436
+ outline.hidden = true;
1437
+ this._outlineEl = outline;
1438
+ showBtn.addEventListener("click", () => {
1439
+ showBtn.hidden = true;
1440
+ outline.hidden = false;
1441
+ this.dispatchEvent(new CustomEvent("bv-show-outline", { bubbles: true, composed: true }));
1442
+ });
1443
+ const body = document.createElement("div");
1444
+ body.className = "modal-body";
1445
+ body.append(detail, showBtn, outline);
1446
+ modal.appendChild(body);
1447
+ shadow.appendChild(modal);
1448
+ }
1449
+ };
1450
+ if (!customElements.get("bv-course-detail-modal")) {
1451
+ customElements.define("bv-course-detail-modal", BvCourseDetailModal);
1452
+ }
1453
+ export {
1454
+ BvCourseDetailModal
1455
+ };