@hotstaq/admin-panel 0.3.18 → 0.4.1

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 (43) hide show
  1. package/assets/css/freelight-panel.css +174 -0
  2. package/build/WebExport.d.ts.map +1 -1
  3. package/build/WebExport.js +7 -1
  4. package/build/WebExport.js.map +1 -1
  5. package/build/components/admin-add-panel.d.ts +56 -0
  6. package/build/components/admin-add-panel.d.ts.map +1 -0
  7. package/build/components/admin-add-panel.js +177 -0
  8. package/build/components/admin-add-panel.js.map +1 -0
  9. package/build/components/admin-card-table.d.ts +55 -0
  10. package/build/components/admin-card-table.d.ts.map +1 -0
  11. package/build/components/admin-card-table.js +149 -0
  12. package/build/components/admin-card-table.js.map +1 -0
  13. package/build/components/admin-detail-page.d.ts +68 -0
  14. package/build/components/admin-detail-page.d.ts.map +1 -0
  15. package/build/components/admin-detail-page.js +247 -0
  16. package/build/components/admin-detail-page.js.map +1 -0
  17. package/build/components/admin-disclaimer.d.ts +21 -0
  18. package/build/components/admin-disclaimer.d.ts.map +1 -0
  19. package/build/components/admin-disclaimer.js +37 -0
  20. package/build/components/admin-disclaimer.js.map +1 -0
  21. package/build/components/admin-eyebrow-heading.d.ts +23 -0
  22. package/build/components/admin-eyebrow-heading.d.ts.map +1 -0
  23. package/build/components/admin-eyebrow-heading.js +40 -0
  24. package/build/components/admin-eyebrow-heading.js.map +1 -0
  25. package/build/components/admin-form-field.d.ts +69 -0
  26. package/build/components/admin-form-field.d.ts.map +1 -0
  27. package/build/components/admin-form-field.js +117 -0
  28. package/build/components/admin-form-field.js.map +1 -0
  29. package/build/index.d.ts +7 -1
  30. package/build/index.d.ts.map +1 -1
  31. package/build/index.js +16 -1
  32. package/build/index.js.map +1 -1
  33. package/build/tsconfig.tsbuildinfo +1 -1
  34. package/build-web/AdminPanelComponents.js +2 -2
  35. package/package.json +1 -1
  36. package/src/WebExport.ts +7 -1
  37. package/src/components/admin-add-panel.ts +210 -0
  38. package/src/components/admin-card-table.ts +183 -0
  39. package/src/components/admin-detail-page.ts +270 -0
  40. package/src/components/admin-disclaimer.ts +43 -0
  41. package/src/components/admin-eyebrow-heading.ts +50 -0
  42. package/src/components/admin-form-field.ts +166 -0
  43. package/src/index.ts +18 -2
@@ -0,0 +1,174 @@
1
+ /* ==============================================================
2
+ Freelight-style admin-panel theme (admin-panel 0.4.0+).
3
+ Visual styling for the new card/detail-page/add-panel components.
4
+ ============================================================== */
5
+
6
+ /* ---- shared tokens ---- */
7
+ :root {
8
+ --flap-text: #1f2937;
9
+ --flap-text-muted: #6b7280;
10
+ --flap-border: #e5e7eb;
11
+ --flap-surface: #ffffff;
12
+ --flap-surface-2: #f8fafc;
13
+ --flap-surface-3: #f1f5f9;
14
+ --flap-hover: #eef2ff;
15
+ --flap-accent: #4f46e5;
16
+ --flap-accent-soft: rgba(79, 70, 229, 0.08);
17
+ --flap-danger: #dc2626;
18
+ --flap-success: #16a34a;
19
+ }
20
+
21
+ [data-theme="dark"] {
22
+ --flap-text: #e2e8f0;
23
+ --flap-text-muted: #94a3b8;
24
+ --flap-border: #1e293b;
25
+ --flap-surface: #0f172a;
26
+ --flap-surface-2: #111827;
27
+ --flap-surface-3: #1f2937;
28
+ --flap-hover: #1e1b4b;
29
+ --flap-accent: #6366f1;
30
+ --flap-accent-soft: rgba(99, 102, 241, 0.18);
31
+ }
32
+
33
+ /* ---- admin-card-table ---- */
34
+ .fl-card-table {
35
+ border-color: var(--flap-border);
36
+ }
37
+
38
+ .fl-card-table .card-header {
39
+ background: var(--flap-surface-2);
40
+ border-bottom: 1px solid var(--flap-border);
41
+ font-weight: 600;
42
+ color: var(--flap-text);
43
+ }
44
+
45
+ .fl-card-list .fl-card-row {
46
+ display: flex;
47
+ align-items: center;
48
+ gap: 1rem;
49
+ padding: 0.9rem 1.1rem;
50
+ border-color: var(--flap-border);
51
+ color: var(--flap-text);
52
+ text-decoration: none;
53
+ }
54
+
55
+ .fl-card-list .fl-card-row-link:hover,
56
+ .fl-card-list .fl-card-row-link:focus {
57
+ background: var(--flap-hover);
58
+ color: var(--flap-text);
59
+ }
60
+
61
+ .fl-card-list .fl-card-row-main {
62
+ flex: 1 1 auto;
63
+ min-width: 0;
64
+ }
65
+
66
+ .fl-card-list .fl-card-row-label {
67
+ font-weight: 600;
68
+ color: var(--flap-text);
69
+ overflow: hidden;
70
+ text-overflow: ellipsis;
71
+ white-space: nowrap;
72
+ }
73
+
74
+ .fl-card-list .fl-card-row-sub {
75
+ color: var(--flap-text-muted);
76
+ font-size: 0.85rem;
77
+ margin-top: 0.15rem;
78
+ overflow: hidden;
79
+ text-overflow: ellipsis;
80
+ white-space: nowrap;
81
+ }
82
+
83
+ .fl-card-list .fl-card-row-actions {
84
+ flex: 0 0 auto;
85
+ display: flex;
86
+ gap: 0.4rem;
87
+ }
88
+
89
+ /* Mobile: stack the action area below the label so labels keep
90
+ their width and buttons don't fight for room. */
91
+ @media (max-width: 575.98px) {
92
+ .fl-card-list .fl-card-row {
93
+ flex-direction: column;
94
+ align-items: stretch;
95
+ }
96
+ .fl-card-list .fl-card-row-actions {
97
+ margin-top: 0.5rem;
98
+ }
99
+ }
100
+
101
+ /* ---- admin-add-panel ---- */
102
+ .fl-add-panel-body {
103
+ border-top: 1px solid var(--flap-border);
104
+ background: var(--flap-surface-2);
105
+ }
106
+
107
+ .fl-add-panel-title {
108
+ color: var(--flap-text);
109
+ letter-spacing: 0.01em;
110
+ }
111
+
112
+ .fl-add-panel-form .form-label {
113
+ color: var(--flap-text);
114
+ margin-bottom: 0.25rem;
115
+ }
116
+
117
+ /* ---- admin-detail-page ---- */
118
+ .fl-detail-page .card {
119
+ border-color: var(--flap-border);
120
+ }
121
+
122
+ .fl-detail-page .card-body {
123
+ background: var(--flap-surface);
124
+ }
125
+
126
+ .fl-detail-page .form-label {
127
+ color: var(--flap-text);
128
+ margin-bottom: 0.25rem;
129
+ }
130
+
131
+ .fl-detail-feedback {
132
+ margin-bottom: 1rem;
133
+ }
134
+
135
+ .fl-detail-feedback.d-none {
136
+ margin-bottom: 0;
137
+ }
138
+
139
+ /* Sticky save bar — sits at the bottom of the viewport while the user
140
+ edits, so Save is always reachable on long forms. */
141
+ .fl-detail-save-bar {
142
+ position: fixed;
143
+ bottom: 0;
144
+ left: 0;
145
+ right: 0;
146
+ padding: 0.9rem 0;
147
+ background: var(--flap-surface);
148
+ border-top: 1px solid var(--flap-border);
149
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.04);
150
+ z-index: 50;
151
+ }
152
+
153
+ [data-theme="dark"] .fl-detail-save-bar {
154
+ box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.35);
155
+ }
156
+
157
+ /* ---- admin-disclaimer ---- */
158
+ .fl-disclaimer {
159
+ border-color: var(--flap-border);
160
+ }
161
+
162
+ .fl-disclaimer .card-body {
163
+ background: var(--flap-accent-soft);
164
+ }
165
+
166
+ /* ---- admin-eyebrow-heading ---- */
167
+ .fl-eyebrow-heading {
168
+ margin-top: 0.25rem;
169
+ }
170
+
171
+ .fl-eyebrow-heading h1 {
172
+ color: var(--flap-text);
173
+ letter-spacing: -0.01em;
174
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"WebExport.d.ts","sourceRoot":"","sources":["../src/WebExport.ts"],"names":[],"mappings":"AAAA,iBAAe,WAAW,IAAK,OAAO,CAAC,GAAG,CAAC,CA2B1C;AAED,OAAO,EACN,WAAW,EACX,CAAC"}
1
+ {"version":3,"file":"WebExport.d.ts","sourceRoot":"","sources":["../src/WebExport.ts"],"names":[],"mappings":"AAAA,iBAAe,WAAW,IAAK,OAAO,CAAC,GAAG,CAAC,CAiC1C;AAED,OAAO,EACN,WAAW,EACX,CAAC"}
@@ -35,7 +35,13 @@ function buildAssets() {
35
35
  "AdminTable",
36
36
  "AdminTableField",
37
37
  "AdminTableRow",
38
- "AdminText"
38
+ "AdminText",
39
+ "AdminFormField",
40
+ "AdminAddPanel",
41
+ "AdminCardTable",
42
+ "AdminDetailPage",
43
+ "AdminDisclaimer",
44
+ "AdminEyebrowHeading"
39
45
  ]
40
46
  });
41
47
  });
@@ -1 +1 @@
1
- {"version":3,"file":"WebExport.js","sourceRoot":"","sources":["../src/WebExport.ts"],"names":[],"mappings":";;;;;;;;;;;AA8BC,kCAAW;AA9BZ,SAAe,WAAW;;QAEzB,OAAO,CAAC;YACN,MAAM,EAAE,CAAC,gBAAgB;gBACxB,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,eAAe,CAAC,EAAE;gBAC5C,eAAe;gBACf,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,EAAE;gBACvE,gBAAgB;gBAChB,oBAAoB;gBACpB,+BAA+B;gBAC/B,6BAA6B;gBAC7B,kCAAkC;gBAClC,2BAA2B,CAAC;YAC7B,IAAI,EAAE,CAAC,mBAAmB,CAAC;YAC3B,GAAG,EAAE,CAAC,kBAAkB,CAAC;YACzB,EAAE,EAAE,CAAC,iBAAiB,EAAE,qCAAqC,CAAC;YAC9D,gBAAgB,EAAE,yBAAyB;YAC3C,UAAU,EAAE;gBACX,gBAAgB;gBAChB,WAAW;gBACX,aAAa;gBACb,eAAe;gBACf,YAAY;gBACZ,iBAAiB;gBACjB,eAAe;gBACf,WAAW;aAAC;SACb,CAAC,CAAC;IACL,CAAC;CAAA"}
1
+ {"version":3,"file":"WebExport.js","sourceRoot":"","sources":["../src/WebExport.ts"],"names":[],"mappings":";;;;;;;;;;;AAoCC,kCAAW;AApCZ,SAAe,WAAW;;QAEzB,OAAO,CAAC;YACN,MAAM,EAAE,CAAC,gBAAgB;gBACxB,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,eAAe,CAAC,EAAE;gBAC5C,eAAe;gBACf,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC,kBAAkB,EAAE,mBAAmB,CAAC,EAAE;gBACvE,gBAAgB;gBAChB,oBAAoB;gBACpB,+BAA+B;gBAC/B,6BAA6B;gBAC7B,kCAAkC;gBAClC,2BAA2B,CAAC;YAC7B,IAAI,EAAE,CAAC,mBAAmB,CAAC;YAC3B,GAAG,EAAE,CAAC,kBAAkB,CAAC;YACzB,EAAE,EAAE,CAAC,iBAAiB,EAAE,qCAAqC,CAAC;YAC9D,gBAAgB,EAAE,yBAAyB;YAC3C,UAAU,EAAE;gBACX,gBAAgB;gBAChB,WAAW;gBACX,aAAa;gBACb,eAAe;gBACf,YAAY;gBACZ,iBAAiB;gBACjB,eAAe;gBACf,WAAW;gBACX,gBAAgB;gBAChB,eAAe;gBACf,gBAAgB;gBAChB,iBAAiB;gBACjB,iBAAiB;gBACjB,qBAAqB;aAAC;SACvB,CAAC,CAAC;IACL,CAAC;CAAA"}
@@ -0,0 +1,56 @@
1
+ import { HotStaq, HotAPI, HotComponent, HotComponentOutput } from "hotstaq";
2
+ /**
3
+ * Self-contained inline add form. Replaces the modal opened by
4
+ * <admin-edit hot-type="add"> with a Bootstrap-collapse card that
5
+ * lives directly on the page — header carries the "+ Add" toggle,
6
+ * body holds the form fields. No cross-component DOM injection.
7
+ *
8
+ * Place this above an <admin-card-table>; when the user clicks the
9
+ * header toggle, the form panel slides down. On Save, the paired
10
+ * table is asked to refresh via `attached_list`.
11
+ *
12
+ * Usage:
13
+ * <admin-add-panel name="bankAccountsAdd"
14
+ * hot-title="Add a bank account"
15
+ * hot-attached_list="bankAccountsList"
16
+ * hot-add_text="+ Add bank account"
17
+ * hot-button_title="Create"
18
+ * hot-onsave="<(values) => {...}Ra>">
19
+ * <admin-form-field hot-field="name" hot-label="Name" hot-required="1"
20
+ * hot-col="col-md-6"></admin-form-field>
21
+ * <admin-form-field hot-field="bankSyncAPIType" hot-label="Sync type"
22
+ * hot-control="select"
23
+ * hot-options="paypal_webhooks:PayPal Webhooks"
24
+ * hot-col="col-md-6"></admin-form-field>
25
+ * </admin-add-panel>
26
+ */
27
+ export declare class AdminAddPanel extends HotComponent {
28
+ /** Title shown in the card header (next to the toggle button). */
29
+ title: string;
30
+ /** Submit button label. */
31
+ button_title: string;
32
+ /** Cancel button label. Empty hides the cancel button. */
33
+ cancel_text: string;
34
+ /** Optional id of the partner <admin-card-table>; refreshList() is called after a successful save. */
35
+ attached_list: string;
36
+ /** Text shown on the header toggle button. */
37
+ add_text: string;
38
+ /** "1" / "true" → panel starts expanded. */
39
+ start_open: string;
40
+ /** What to run when the user clicks Save. Receives a values object built from hot-field inputs. Return false to keep the panel open. */
41
+ onsave: (values: any) => Promise<boolean | void>;
42
+ protected panelId: string;
43
+ protected formId: string;
44
+ constructor(copy: HotComponent | HotStaq, api: HotAPI);
45
+ /**
46
+ * Wire submit + cancel handlers after the DOM is in place.
47
+ * Bootstrap's data-bs-toggle handles open/close automatically.
48
+ */
49
+ onPostPlace(parentHtmlElement: HTMLElement, htmlElement: HTMLElement): HTMLElement;
50
+ protected collectFieldValues(root: HTMLElement): any;
51
+ protected resetFields(root: HTMLElement): void;
52
+ protected collapsePanel(): void;
53
+ protected refreshAttachedList(): void;
54
+ output(): string | HotComponentOutput[];
55
+ }
56
+ //# sourceMappingURL=admin-add-panel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-add-panel.d.ts","sourceRoot":"","sources":["../../src/components/admin-add-panel.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAO,MAAM,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,aAAc,SAAQ,YAAY;IAE9C,kEAAkE;IAClE,KAAK,EAAE,MAAM,CAAC;IACd,2BAA2B;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAC;IACpB,sGAAsG;IACtG,aAAa,EAAE,MAAM,CAAC;IACtB,8CAA8C;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,wIAAwI;IACxI,MAAM,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAC;IAEjD,SAAS,CAAC,OAAO,EAAE,MAAM,CAAC;IAC1B,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,IAAI,EAAE,YAAY,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM;IActD;;;OAGG;IACH,WAAW,CAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,GAAG,WAAW;IAsDnF,SAAS,CAAC,kBAAkB,CAAE,IAAI,EAAE,WAAW,GAAG,GAAG;IAoBrD,SAAS,CAAC,WAAW,CAAE,IAAI,EAAE,WAAW,GAAG,IAAI;IAY/C,SAAS,CAAC,aAAa,IAAK,IAAI;IAShC,SAAS,CAAC,mBAAmB,IAAK,IAAI;IAQtC,MAAM,IAAK,MAAM,GAAG,kBAAkB,EAAE;CAyCxC"}
@@ -0,0 +1,177 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AdminAddPanel = void 0;
13
+ const hotstaq_1 = require("hotstaq");
14
+ /**
15
+ * Self-contained inline add form. Replaces the modal opened by
16
+ * <admin-edit hot-type="add"> with a Bootstrap-collapse card that
17
+ * lives directly on the page — header carries the "+ Add" toggle,
18
+ * body holds the form fields. No cross-component DOM injection.
19
+ *
20
+ * Place this above an <admin-card-table>; when the user clicks the
21
+ * header toggle, the form panel slides down. On Save, the paired
22
+ * table is asked to refresh via `attached_list`.
23
+ *
24
+ * Usage:
25
+ * <admin-add-panel name="bankAccountsAdd"
26
+ * hot-title="Add a bank account"
27
+ * hot-attached_list="bankAccountsList"
28
+ * hot-add_text="+ Add bank account"
29
+ * hot-button_title="Create"
30
+ * hot-onsave="<(values) => {...}Ra>">
31
+ * <admin-form-field hot-field="name" hot-label="Name" hot-required="1"
32
+ * hot-col="col-md-6"></admin-form-field>
33
+ * <admin-form-field hot-field="bankSyncAPIType" hot-label="Sync type"
34
+ * hot-control="select"
35
+ * hot-options="paypal_webhooks:PayPal Webhooks"
36
+ * hot-col="col-md-6"></admin-form-field>
37
+ * </admin-add-panel>
38
+ */
39
+ class AdminAddPanel extends hotstaq_1.HotComponent {
40
+ constructor(copy, api) {
41
+ super(copy, api);
42
+ this.tag = "admin-add-panel";
43
+ this.title = "";
44
+ this.button_title = "Save";
45
+ this.cancel_text = "Cancel";
46
+ this.attached_list = "";
47
+ this.add_text = "+ Add";
48
+ this.start_open = "0";
49
+ this.onsave = null;
50
+ }
51
+ /**
52
+ * Wire submit + cancel handlers after the DOM is in place.
53
+ * Bootstrap's data-bs-toggle handles open/close automatically.
54
+ */
55
+ onPostPlace(parentHtmlElement, htmlElement) {
56
+ const self = this;
57
+ const root = document.getElementById(this.name);
58
+ if (root == null)
59
+ return (null);
60
+ const submitBtn = root.querySelector(".fl-add-panel-submit");
61
+ const cancelBtn = root.querySelector(".fl-add-panel-cancel");
62
+ if (submitBtn != null) {
63
+ submitBtn.addEventListener("click", (e) => __awaiter(this, void 0, void 0, function* () {
64
+ e.preventDefault();
65
+ const values = self.collectFieldValues(root);
66
+ submitBtn.disabled = true;
67
+ try {
68
+ let keepOpen = false;
69
+ if (typeof self.onsave === "function")
70
+ keepOpen = yield self.onsave(values);
71
+ if (keepOpen === false || keepOpen == null) {
72
+ self.resetFields(root);
73
+ self.collapsePanel();
74
+ self.refreshAttachedList();
75
+ }
76
+ }
77
+ catch (ex) {
78
+ console.error("admin-add-panel onsave threw:", ex);
79
+ }
80
+ finally {
81
+ submitBtn.disabled = false;
82
+ }
83
+ }));
84
+ }
85
+ if (cancelBtn != null) {
86
+ cancelBtn.addEventListener("click", (e) => {
87
+ e.preventDefault();
88
+ self.resetFields(root);
89
+ self.collapsePanel();
90
+ });
91
+ }
92
+ return (null);
93
+ }
94
+ collectFieldValues(root) {
95
+ const out = {};
96
+ const nodes = root.querySelectorAll("[hot-field]");
97
+ for (let i = 0; i < nodes.length; i++) {
98
+ const el = nodes[i];
99
+ const field = el.getAttribute("hot-field");
100
+ if (field == null || field === "")
101
+ continue;
102
+ if (el instanceof HTMLInputElement && el.type === "checkbox")
103
+ out[field] = el.checked;
104
+ else if (el instanceof HTMLInputElement && el.type === "number")
105
+ out[field] = el.value === "" ? null : Number(el.value);
106
+ else
107
+ out[field] = el.value;
108
+ }
109
+ return (out);
110
+ }
111
+ resetFields(root) {
112
+ const nodes = root.querySelectorAll("[hot-field]");
113
+ for (let i = 0; i < nodes.length; i++) {
114
+ const el = nodes[i];
115
+ if (el instanceof HTMLInputElement && el.type === "checkbox")
116
+ el.checked = false;
117
+ else if (el instanceof HTMLSelectElement)
118
+ el.selectedIndex = 0;
119
+ else
120
+ el.value = "";
121
+ }
122
+ }
123
+ collapsePanel() {
124
+ const panel = document.getElementById(this.panelId);
125
+ if (panel == null)
126
+ return;
127
+ panel.classList.remove("show");
128
+ const triggers = document.querySelectorAll(`[data-bs-target="#${this.panelId}"]`);
129
+ triggers.forEach(t => t.setAttribute("aria-expanded", "false"));
130
+ }
131
+ refreshAttachedList() {
132
+ if (this.attached_list === "")
133
+ return;
134
+ const list = document.getElementById(this.attached_list);
135
+ if (list != null && typeof list.refreshList === "function")
136
+ list.refreshList();
137
+ }
138
+ output() {
139
+ if (this.name === "")
140
+ throw new Error("admin-add-panel: name is required");
141
+ this.panelId = `${this.name}Panel`;
142
+ this.formId = `${this.name}Form`;
143
+ const showClass = (this.start_open === "1" || this.start_open === "true") ? " show" : "";
144
+ const ariaExp = showClass ? "true" : "false";
145
+ const titleHtml = this.title ? `<strong class="fl-add-panel-title">${this.title}</strong>` : `<span></span>`;
146
+ const cancelHtml = this.cancel_text
147
+ ? `<button type="button" class="btn btn-sm btn-link text-muted fl-add-panel-cancel">${this.cancel_text}</button>`
148
+ : "";
149
+ // Single self-contained card. Header has the toggle, body is the
150
+ // collapse panel containing the form. Bootstrap's data-bs-toggle
151
+ // drives the open/close — no JS wiring needed for that.
152
+ return (`
153
+ <div id="${this.name}" class="card fl-add-panel mb-3">
154
+ <div class="card-header d-flex justify-content-between align-items-center">
155
+ ${titleHtml}
156
+ <button type="button" class="btn btn-sm btn-primary fl-add-panel-toggle"
157
+ data-bs-toggle="collapse" data-bs-target="#${this.panelId}"
158
+ aria-expanded="${ariaExp}" aria-controls="${this.panelId}">${this.add_text}</button>
159
+ </div>
160
+ <div id="${this.panelId}" class="collapse fl-add-panel-body${showClass}">
161
+ <div class="card-body border-top">
162
+ <form id="${this.formId}" class="fl-add-panel-form">
163
+ <div class="row g-2 align-items-end">
164
+ <hot-place-here name="panelBody"></hot-place-here>
165
+ </div>
166
+ <div class="d-flex justify-content-end gap-2 mt-3">
167
+ ${cancelHtml}
168
+ <button type="submit" class="btn btn-sm btn-success fl-add-panel-submit">${this.button_title}</button>
169
+ </div>
170
+ </form>
171
+ </div>
172
+ </div>
173
+ </div>`);
174
+ }
175
+ }
176
+ exports.AdminAddPanel = AdminAddPanel;
177
+ //# sourceMappingURL=admin-add-panel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-add-panel.js","sourceRoot":"","sources":["../../src/components/admin-add-panel.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,qCAAiF;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAa,aAAc,SAAQ,sBAAY;IAoB9C,YAAa,IAA4B,EAAE,GAAW;QAErD,KAAK,CAAE,IAAI,EAAE,GAAG,CAAC,CAAC;QAElB,IAAI,CAAC,GAAG,GAAe,iBAAiB,CAAC;QACzC,IAAI,CAAC,KAAK,GAAa,EAAE,CAAC;QAC1B,IAAI,CAAC,YAAY,GAAM,MAAM,CAAC;QAC9B,IAAI,CAAC,WAAW,GAAO,QAAQ,CAAC;QAChC,IAAI,CAAC,aAAa,GAAK,EAAE,CAAC;QAC1B,IAAI,CAAC,QAAQ,GAAU,OAAO,CAAC;QAC/B,IAAI,CAAC,UAAU,GAAQ,GAAG,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAY,IAAI,CAAC;IAC7B,CAAC;IAED;;;OAGG;IACH,WAAW,CAAE,iBAA8B,EAAE,WAAwB;QAEpE,MAAM,IAAI,GAAG,IAAI,CAAC;QAClB,MAAM,IAAI,GAAG,QAAQ,CAAC,cAAc,CAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACjD,IAAI,IAAI,IAAI,IAAI;YACf,OAAO,CAAC,IAAI,CAAC,CAAC;QAEf,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAE,sBAAsB,CAA6B,CAAC;QAC1F,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAE,sBAAsB,CAA6B,CAAC;QAE1F,IAAI,SAAS,IAAI,IAAI,EACrB,CAAC;YACA,SAAS,CAAC,gBAAgB,CAAE,OAAO,EAAE,CAAO,CAAC,EAAE,EAAE;gBAE/C,CAAC,CAAC,cAAc,EAAG,CAAC;gBACpB,MAAM,MAAM,GAAG,IAAI,CAAC,kBAAkB,CAAE,IAAI,CAAC,CAAC;gBAC9C,SAAS,CAAC,QAAQ,GAAG,IAAI,CAAC;gBAC1B,IACA,CAAC;oBACA,IAAI,QAAQ,GAAQ,KAAK,CAAC;oBAC1B,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,UAAU;wBACpC,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAE,MAAM,CAAC,CAAC;oBAEvC,IAAI,QAAQ,KAAK,KAAK,IAAI,QAAQ,IAAI,IAAI,EAC1C,CAAC;wBACA,IAAI,CAAC,WAAW,CAAE,IAAI,CAAC,CAAC;wBACxB,IAAI,CAAC,aAAa,EAAG,CAAC;wBACtB,IAAI,CAAC,mBAAmB,EAAG,CAAC;oBAC7B,CAAC;gBACF,CAAC;gBACD,OAAO,EAAE,EACT,CAAC;oBACA,OAAO,CAAC,KAAK,CAAE,+BAA+B,EAAE,EAAE,CAAC,CAAC;gBACrD,CAAC;wBAED,CAAC;oBACA,SAAS,CAAC,QAAQ,GAAG,KAAK,CAAC;gBAC5B,CAAC;YACF,CAAC,CAAA,CAAC,CAAC;QACL,CAAC;QAED,IAAI,SAAS,IAAI,IAAI,EACrB,CAAC;YACA,SAAS,CAAC,gBAAgB,CAAE,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;gBAEzC,CAAC,CAAC,cAAc,EAAG,CAAC;gBACpB,IAAI,CAAC,WAAW,CAAE,IAAI,CAAC,CAAC;gBACxB,IAAI,CAAC,aAAa,EAAG,CAAC;YACvB,CAAC,CAAC,CAAC;QACL,CAAC;QAED,OAAO,CAAC,IAAI,CAAC,CAAC;IACf,CAAC;IAES,kBAAkB,CAAE,IAAiB;QAE9C,MAAM,GAAG,GAAQ,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAE,aAAa,CAAC,CAAC;QACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EACrC,CAAC;YACA,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAA+D,CAAC;YAClF,MAAM,KAAK,GAAG,EAAE,CAAC,YAAY,CAAE,WAAW,CAAC,CAAC;YAC5C,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,KAAK,EAAE;gBAAE,SAAS;YAE5C,IAAI,EAAE,YAAY,gBAAgB,IAAI,EAAE,CAAC,IAAI,KAAK,UAAU;gBAC3D,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC;iBACpB,IAAI,EAAE,YAAY,gBAAgB,IAAI,EAAE,CAAC,IAAI,KAAK,QAAQ;gBAC9D,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAE,EAAE,CAAC,KAAK,CAAC,CAAC;;gBAExD,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC;QACxB,CAAC;QACD,OAAO,CAAC,GAAG,CAAC,CAAC;IACd,CAAC;IAES,WAAW,CAAE,IAAiB;QAEvC,MAAM,KAAK,GAAG,IAAI,CAAC,gBAAgB,CAAE,aAAa,CAAC,CAAC;QACpD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EACrC,CAAC;YACA,MAAM,EAAE,GAAG,KAAK,CAAC,CAAC,CAA+D,CAAC;YAClF,IAAI,EAAE,YAAY,gBAAgB,IAAI,EAAE,CAAC,IAAI,KAAK,UAAU;gBAAE,EAAE,CAAC,OAAO,GAAG,KAAK,CAAC;iBAC5E,IAAI,EAAE,YAAY,iBAAiB;gBAAE,EAAE,CAAC,aAAa,GAAG,CAAC,CAAC;;gBAC1D,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC;QACpB,CAAC;IACF,CAAC;IAES,aAAa;QAEtB,MAAM,KAAK,GAAG,QAAQ,CAAC,cAAc,CAAE,IAAI,CAAC,OAAO,CAAC,CAAC;QACrD,IAAI,KAAK,IAAI,IAAI;YAAE,OAAO;QAC1B,KAAK,CAAC,SAAS,CAAC,MAAM,CAAE,MAAM,CAAC,CAAC;QAChC,MAAM,QAAQ,GAAG,QAAQ,CAAC,gBAAgB,CAAE,qBAAqB,IAAI,CAAC,OAAO,IAAI,CAAC,CAAC;QACnF,QAAQ,CAAC,OAAO,CAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,YAAY,CAAE,eAAe,EAAE,OAAO,CAAC,CAAC,CAAC;IACnE,CAAC;IAES,mBAAmB;QAE5B,IAAI,IAAI,CAAC,aAAa,KAAK,EAAE;YAAE,OAAO;QACtC,MAAM,IAAI,GAAQ,QAAQ,CAAC,cAAc,CAAE,IAAI,CAAC,aAAa,CAAC,CAAC;QAC/D,IAAI,IAAI,IAAI,IAAI,IAAI,OAAO,IAAI,CAAC,WAAW,KAAK,UAAU;YACzD,IAAI,CAAC,WAAW,EAAG,CAAC;IACtB,CAAC;IAED,MAAM;QAEL,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE;YACnB,MAAM,IAAI,KAAK,CAAE,mCAAmC,CAAC,CAAC;QAEvD,IAAI,CAAC,OAAO,GAAG,GAAG,IAAI,CAAC,IAAI,OAAO,CAAC;QACnC,IAAI,CAAC,MAAM,GAAI,GAAG,IAAI,CAAC,IAAI,MAAM,CAAC;QAElC,MAAM,SAAS,GAAG,CAAC,IAAI,CAAC,UAAU,KAAK,GAAG,IAAI,IAAI,CAAC,UAAU,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC;QACzF,MAAM,OAAO,GAAG,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;QAC7C,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,sCAAsC,IAAI,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,eAAe,CAAC;QAC7G,MAAM,UAAU,GAAG,IAAI,CAAC,WAAW;YAClC,CAAC,CAAC,oFAAoF,IAAI,CAAC,WAAW,WAAW;YACjH,CAAC,CAAC,EAAE,CAAC;QAEN,iEAAiE;QACjE,iEAAiE;QACjE,wDAAwD;QACxD,OAAO,CAAC;cACI,IAAI,CAAC,IAAI;;OAEhB,SAAS;;mDAEmC,IAAI,CAAC,OAAO;uBACxC,OAAO,oBAAoB,IAAI,CAAC,OAAO,KAAK,IAAI,CAAC,QAAQ;;eAEjE,IAAI,CAAC,OAAO,sCAAsC,SAAS;;kBAExD,IAAI,CAAC,MAAM;;;;;UAKnB,UAAU;mFAC+D,IAAI,CAAC,YAAY;;;;;UAK1F,CAAC,CAAC;IACX,CAAC;CACD;AAtLD,sCAsLC"}
@@ -0,0 +1,55 @@
1
+ import { HotStaq, HotAPI, HotComponent, HotComponentOutput } from "hotstaq";
2
+ /**
3
+ * Freelight-style card list. Renders campaign / project / member rows
4
+ * as cards on every viewport, with optional inline action buttons and
5
+ * a sub-line below the primary label.
6
+ *
7
+ * Replaces the click-row-opens-modal flow of <admin-table> + <admin-edit>:
8
+ * when `hot-detail-route` is set, the whole row becomes a link to the
9
+ * configured detail URL (e.g. "/budget/:id"). When `hot-detail-route` is
10
+ * empty, the row renders without navigation — the caller is expected to
11
+ * provide their own inline action buttons via `hot-row-actions`.
12
+ *
13
+ * Usage:
14
+ * <admin-card-table id="bankAccountsList" hot-list-url="/v1/bank_accounts/list"
15
+ * hot-detail-route="/bankAccount/:id"
16
+ * hot-primary-field="name" hot-subline-field="bankSyncAPIType"
17
+ * hot-empty-text="No bank accounts yet.">
18
+ * </admin-card-table>
19
+ *
20
+ * The component exposes a `.refreshList()` method on the rendered DOM
21
+ * element so callers (the paired admin-add-panel, an edit-save callback,
22
+ * etc.) can re-fetch without a page reload.
23
+ */
24
+ export declare class AdminCardTable extends HotComponent {
25
+ /** Optional title shown in the card header. */
26
+ title: string;
27
+ /** Endpoint that returns { length, data: [...] } — usually the entity's list route. */
28
+ list_url: string;
29
+ /** JWT token to send as Authorization bearer. Empty for public endpoints. */
30
+ jwt: string;
31
+ /** Body params to POST with the list call (JSON). */
32
+ list_params: string;
33
+ /** Field name on each row used as the primary card label (default "name"). */
34
+ primary_field: string;
35
+ /** Optional second-line field rendered in muted text under the primary label. */
36
+ subline_field: string;
37
+ /** Pattern for the row's click target. ":id" interpolates row.id. Empty disables row navigation. */
38
+ detail_route: string;
39
+ /** Text shown when the list is empty. */
40
+ empty_text: string;
41
+ /** Text shown while the list is loading. */
42
+ loading_text: string;
43
+ /** Inner HTML template for the right-side action area, with ":id" placeholder. */
44
+ row_actions: string;
45
+ /** Slot name where the partner admin-add-panel injects its toggle button. */
46
+ add_slot: string;
47
+ constructor(copy: HotComponent | HotStaq, api: HotAPI);
48
+ onPostPlace(parentHtmlElement: HTMLElement, htmlElement: HTMLElement): HTMLElement;
49
+ protected fetchAndRender(): Promise<void>;
50
+ protected escapeHtml(s: any): string;
51
+ protected interpolate(template: string, row: any): string;
52
+ protected renderRow(row: any): string;
53
+ output(): string | HotComponentOutput[];
54
+ }
55
+ //# sourceMappingURL=admin-card-table.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"admin-card-table.d.ts","sourceRoot":"","sources":["../../src/components/admin-card-table.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAO,MAAM,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,qBAAa,cAAe,SAAQ,YAAY;IAE/C,+CAA+C;IAC/C,KAAK,EAAE,MAAM,CAAC;IACd,uFAAuF;IACvF,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,GAAG,EAAE,MAAM,CAAC;IACZ,qDAAqD;IACrD,WAAW,EAAE,MAAM,CAAC;IACpB,8EAA8E;IAC9E,aAAa,EAAE,MAAM,CAAC;IACtB,iFAAiF;IACjF,aAAa,EAAE,MAAM,CAAC;IACtB,oGAAoG;IACpG,YAAY,EAAE,MAAM,CAAC;IACrB,yCAAyC;IACzC,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,WAAW,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;gBAEJ,IAAI,EAAE,YAAY,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM;IAkBtD,WAAW,CAAE,iBAAiB,EAAE,WAAW,EAAE,WAAW,EAAE,WAAW,GAAG,WAAW;cAkBnE,cAAc,IAAK,OAAO,CAAC,IAAI,CAAC;IAyChD,SAAS,CAAC,UAAU,CAAE,CAAC,EAAE,GAAG,GAAG,MAAM;IAOrC,SAAS,CAAC,WAAW,CAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,GAAG,MAAM;IAM1D,SAAS,CAAC,SAAS,CAAE,GAAG,EAAE,GAAG,GAAG,MAAM;IAsBtC,MAAM,IAAK,MAAM,GAAG,kBAAkB,EAAE;CAqBxC"}
@@ -0,0 +1,149 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.AdminCardTable = void 0;
13
+ const hotstaq_1 = require("hotstaq");
14
+ /**
15
+ * Freelight-style card list. Renders campaign / project / member rows
16
+ * as cards on every viewport, with optional inline action buttons and
17
+ * a sub-line below the primary label.
18
+ *
19
+ * Replaces the click-row-opens-modal flow of <admin-table> + <admin-edit>:
20
+ * when `hot-detail-route` is set, the whole row becomes a link to the
21
+ * configured detail URL (e.g. "/budget/:id"). When `hot-detail-route` is
22
+ * empty, the row renders without navigation — the caller is expected to
23
+ * provide their own inline action buttons via `hot-row-actions`.
24
+ *
25
+ * Usage:
26
+ * <admin-card-table id="bankAccountsList" hot-list-url="/v1/bank_accounts/list"
27
+ * hot-detail-route="/bankAccount/:id"
28
+ * hot-primary-field="name" hot-subline-field="bankSyncAPIType"
29
+ * hot-empty-text="No bank accounts yet.">
30
+ * </admin-card-table>
31
+ *
32
+ * The component exposes a `.refreshList()` method on the rendered DOM
33
+ * element so callers (the paired admin-add-panel, an edit-save callback,
34
+ * etc.) can re-fetch without a page reload.
35
+ */
36
+ class AdminCardTable extends hotstaq_1.HotComponent {
37
+ constructor(copy, api) {
38
+ super(copy, api);
39
+ this.tag = "admin-card-table";
40
+ this.title = "";
41
+ this.list_url = "";
42
+ this.jwt = "";
43
+ this.list_params = "{}";
44
+ this.primary_field = "name";
45
+ this.subline_field = "";
46
+ this.detail_route = "";
47
+ this.empty_text = "No items yet.";
48
+ this.loading_text = "Loading…";
49
+ this.row_actions = "";
50
+ this.add_slot = "";
51
+ }
52
+ onPostPlace(parentHtmlElement, htmlElement) {
53
+ const self = this;
54
+ const container = document.getElementById(this.name);
55
+ if (container == null)
56
+ return (null);
57
+ // Expose a refreshList() method on the rendered element so the
58
+ // partner add-panel (and any other caller) can re-fetch when a
59
+ // row changes.
60
+ container.refreshList = function () { return self.fetchAndRender(); };
61
+ // Initial load.
62
+ self.fetchAndRender();
63
+ return (null);
64
+ }
65
+ fetchAndRender() {
66
+ return __awaiter(this, void 0, void 0, function* () {
67
+ const container = document.getElementById(this.name);
68
+ const list = container ? container.querySelector(".fl-card-list") : null;
69
+ if (list == null)
70
+ return;
71
+ try {
72
+ let payload = {};
73
+ try {
74
+ payload = JSON.parse(this.list_params || "{}");
75
+ }
76
+ catch (e) {
77
+ payload = {};
78
+ }
79
+ const headers = { "Content-Type": "application/json" };
80
+ if (this.jwt)
81
+ headers["Authorization"] = "Bearer " + this.jwt;
82
+ const res = yield fetch(this.list_url, {
83
+ method: "POST", headers: headers, body: JSON.stringify(payload)
84
+ });
85
+ if (!res.ok) {
86
+ list.innerHTML = `<div class="text-danger small p-3">Could not load: HTTP ${res.status}</div>`;
87
+ return;
88
+ }
89
+ const result = yield res.json();
90
+ const rows = (result && Array.isArray(result.data)) ? result.data : (Array.isArray(result) ? result : []);
91
+ if (rows.length === 0) {
92
+ list.innerHTML = `<div class="text-muted small text-center py-4">${this.empty_text}</div>`;
93
+ return;
94
+ }
95
+ list.innerHTML = rows.map((row) => this.renderRow(row)).join("");
96
+ }
97
+ catch (ex) {
98
+ list.innerHTML = `<div class="text-danger small p-3">Could not load: ${ex.message}</div>`;
99
+ }
100
+ });
101
+ }
102
+ escapeHtml(s) {
103
+ return String(s == null ? "" : s)
104
+ .replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
105
+ .replace(/"/g, "&quot;").replace(/'/g, "&#39;");
106
+ }
107
+ interpolate(template, row) {
108
+ if (!template)
109
+ return "";
110
+ return template.replace(/:(\w+)/g, (_m, key) => this.escapeHtml(row[key] || ""));
111
+ }
112
+ renderRow(row) {
113
+ const primaryRaw = row[this.primary_field];
114
+ const primary = this.escapeHtml(primaryRaw != null && primaryRaw !== "" ? primaryRaw : (row.id || ""));
115
+ const sublineRaw = this.subline_field ? row[this.subline_field] : "";
116
+ const subline = sublineRaw ? `<div class="fl-card-row-sub text-muted small">${this.escapeHtml(sublineRaw)}</div>` : "";
117
+ const inner = `
118
+ <div class="fl-card-row-main">
119
+ <div class="fl-card-row-label">${primary}</div>
120
+ ${subline}
121
+ </div>
122
+ <div class="fl-card-row-actions">${this.interpolate(this.row_actions, row)}</div>`;
123
+ if (this.detail_route) {
124
+ const href = this.interpolate(this.detail_route, row);
125
+ return `<a href="${href}" class="fl-card-row fl-card-row-link list-group-item list-group-item-action">${inner}</a>`;
126
+ }
127
+ return `<div class="fl-card-row list-group-item">${inner}</div>`;
128
+ }
129
+ output() {
130
+ if (this.name === "")
131
+ throw new Error("admin-card-table: id (name) is required");
132
+ if (this.list_url === "")
133
+ throw new Error("admin-card-table: hot-list-url is required");
134
+ const titleHtml = this.title ? `<strong>${this.title}</strong>` : "";
135
+ const addSlotAttr = this.add_slot ? ` data-card-table-add-slot="${this.add_slot}"` : ` data-card-table-add-slot="${this.name}"`;
136
+ return (`
137
+ <div id="${this.name}" class="card fl-card-table mb-4">
138
+ <div class="card-header d-flex justify-content-between align-items-center">
139
+ ${titleHtml}
140
+ <div class="fl-card-table-actions"${addSlotAttr}></div>
141
+ </div>
142
+ <div class="fl-card-list list-group list-group-flush">
143
+ <div class="text-muted small text-center py-4">${this.loading_text}</div>
144
+ </div>
145
+ </div>`);
146
+ }
147
+ }
148
+ exports.AdminCardTable = AdminCardTable;
149
+ //# sourceMappingURL=admin-card-table.js.map