elysia-rack 0.2.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/README.md +37 -20
  2. package/dist/Dashboard-4wv82gwx.js +212 -0
  3. package/dist/Dashboard-jkvfzyk2.js +210 -0
  4. package/dist/Dashboard-zhg2jtq5.js +211 -0
  5. package/dist/{Panel-fbp3wrsw.js → Panel-1qkzh8t7.js} +355 -311
  6. package/dist/Panel-7zpqz8gy.js +782 -0
  7. package/dist/Panel-9mmh3tbh.js +790 -0
  8. package/dist/Panel-ba0qzknj.js +789 -0
  9. package/dist/Panel-e6jyf4rc.js +789 -0
  10. package/dist/index-0dwhzk3j.js +145 -0
  11. package/dist/{index-6v0ns1xn.js → index-b8sq8rbd.js} +1 -1
  12. package/dist/index-rg87f3v1.js +174 -0
  13. package/dist/panel-app.js +27 -11
  14. package/dist/panel.css +2 -1
  15. package/dist/rack/index.js +5 -5
  16. package/dist/rack/types/metadata.d.ts +2 -1
  17. package/dist/react/donate.d.ts +1 -1
  18. package/dist/react/index.js +40 -15
  19. package/dist/react/page/Panel.d.ts +1 -0
  20. package/dist/react/page/components/Icon.d.ts +10 -0
  21. package/dist/react/page/components/Masthead.d.ts +5 -4
  22. package/dist/react/render.d.ts +1 -1
  23. package/dist/react/types.d.ts +18 -2
  24. package/package.json +8 -3
  25. package/dist/Dashboard-0da8dvbv.js +0 -225
  26. package/dist/Dashboard-2j561p7c.js +0 -225
  27. package/dist/Dashboard-5mt9hnbw.js +0 -252
  28. package/dist/Dashboard-7gmx8c9y.js +0 -248
  29. package/dist/Dashboard-s8nfyf7s.js +0 -39
  30. package/dist/Dashboard-xkh2g9f7.js +0 -248
  31. package/dist/Dashboard-xpstr7fr.js +0 -172
  32. package/dist/Panel-3yrk3krj.js +0 -914
  33. package/dist/Panel-b7jhgvnm.js +0 -916
  34. package/dist/Panel-n0kstkyw.js +0 -735
  35. package/dist/Panel-pkvqf5v8.js +0 -912
  36. package/dist/Panel-wjxjtbmr.js +0 -753
  37. package/dist/Panel-za4av616.js +0 -753
  38. package/dist/index-h3zbq796.js +0 -39
  39. package/dist/index-tgk4jt4d.js +0 -63
  40. package/dist/index-xsfqad54.js +0 -187
  41. package/dist/index-zc7rgvmm.js +0 -13
@@ -1,912 +0,0 @@
1
- import {
2
- getRackTree
3
- } from "./index-4wxvmd8a.js";
4
- import"./index-37x76zdn.js";
5
-
6
- // src/react/page/components/Breadcrumb.tsx
7
- import { jsxDEV } from "react/jsx-dev-runtime";
8
- function Breadcrumb({ trail }) {
9
- return /* @__PURE__ */ jsxDEV("nav", {
10
- "aria-label": "Breadcrumb",
11
- className: "pb-3 text-sm",
12
- children: /* @__PURE__ */ jsxDEV("ol", {
13
- className: "flex flex-wrap items-center gap-1.5",
14
- children: trail.map((item, i) => {
15
- const last = i === trail.length - 1;
16
- return /* @__PURE__ */ jsxDEV("li", {
17
- className: "flex items-center gap-1.5",
18
- children: [
19
- i > 0 ? /* @__PURE__ */ jsxDEV("span", {
20
- "aria-hidden": "true",
21
- className: "text-text-muted",
22
- children: "/"
23
- }, undefined, false, undefined, this) : null,
24
- item.href && !last ? /* @__PURE__ */ jsxDEV("a", {
25
- href: item.href,
26
- className: "text-text-muted hover:text-foreground",
27
- children: item.label
28
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV("span", {
29
- "aria-current": last ? "page" : undefined,
30
- className: last ? "text-foreground font-semibold" : "text-text-muted",
31
- children: item.label
32
- }, undefined, false, undefined, this)
33
- ]
34
- }, `${item.label}-${i}`, true, undefined, this);
35
- })
36
- }, undefined, false, undefined, this)
37
- }, undefined, false, undefined, this);
38
- }
39
-
40
- // src/react/page/components/href.ts
41
- function href(params, over = {}) {
42
- const query = new URLSearchParams;
43
- for (const [key, value] of Object.entries({ ...params, ...over })) {
44
- if (value === undefined || value === null || value === "")
45
- continue;
46
- query.set(key, Array.isArray(value) ? value.join(",") : String(value));
47
- }
48
- const str = query.toString();
49
- return str ? `?${str}` : "?";
50
- }
51
- function pageWindow(page, total) {
52
- const keep = new Set([1, total, page - 1, page, page + 1]);
53
- const sorted = [...keep].filter((p) => p >= 1 && p <= total).sort((a, b) => a - b);
54
- const out = [];
55
- let prev = 0;
56
- for (const p of sorted) {
57
- if (p - prev > 1)
58
- out.push("…");
59
- out.push(p);
60
- prev = p;
61
- }
62
- return out;
63
- }
64
-
65
- // src/react/page/components/DataTable.tsx
66
- import { jsxDEV as jsxDEV2 } from "react/jsx-dev-runtime";
67
- function statusBadge(value) {
68
- if (typeof value !== "string")
69
- return null;
70
- const text = value.toLowerCase();
71
- if (text === "active")
72
- return "bg-success-muted text-success-muted-foreground";
73
- if (text === "archived")
74
- return "bg-warning-muted text-warning-muted-foreground";
75
- return "bg-badge-background text-badge-foreground";
76
- }
77
- function cell(value) {
78
- if (value === null || value === undefined)
79
- return "";
80
- if (value instanceof Date)
81
- return value.toLocaleString("en-US");
82
- if (typeof value === "object")
83
- return JSON.stringify(value);
84
- return String(value);
85
- }
86
- function DataTable({
87
- columns,
88
- rows,
89
- sortable,
90
- params,
91
- selectable,
92
- editable,
93
- primaryKey
94
- }) {
95
- const activeSort = typeof params.sort === "string" ? params.sort : "";
96
- const activeOrder = params.order === "desc" ? "desc" : "asc";
97
- const pk = primaryKey ?? "id";
98
- const extra = (selectable ? 1 : 0) + (editable ? 1 : 0);
99
- if (rows.length === 0)
100
- return /* @__PURE__ */ jsxDEV2("div", {
101
- className: "border-table-border overflow-x-auto rounded-md border",
102
- children: /* @__PURE__ */ jsxDEV2("table", {
103
- className: "bg-table w-full border-collapse text-left text-sm",
104
- "data-selectable": selectable ? true : undefined,
105
- "data-editable": editable ? true : undefined,
106
- "data-pk": primaryKey ?? "id",
107
- children: /* @__PURE__ */ jsxDEV2("tbody", {
108
- "data-panel-rows": true,
109
- children: /* @__PURE__ */ jsxDEV2("tr", {
110
- children: /* @__PURE__ */ jsxDEV2("td", {
111
- colSpan: columns.length + extra || 1,
112
- className: "text-text-muted px-4 py-10 text-center",
113
- children: "No records found."
114
- }, undefined, false, undefined, this)
115
- }, undefined, false, undefined, this)
116
- }, undefined, false, undefined, this)
117
- }, undefined, false, undefined, this)
118
- }, undefined, false, undefined, this);
119
- return /* @__PURE__ */ jsxDEV2("div", {
120
- className: "border-table-border overflow-x-auto rounded-md border",
121
- children: /* @__PURE__ */ jsxDEV2("table", {
122
- className: "bg-table w-full border-collapse text-left text-sm",
123
- "data-selectable": selectable ? true : undefined,
124
- "data-editable": editable ? true : undefined,
125
- "data-pk": primaryKey ?? "id",
126
- children: [
127
- /* @__PURE__ */ jsxDEV2("thead", {
128
- children: /* @__PURE__ */ jsxDEV2("tr", {
129
- className: "bg-table-header",
130
- children: [
131
- selectable ? /* @__PURE__ */ jsxDEV2("th", {
132
- className: "border-table-border border-b px-4 py-2",
133
- children: /* @__PURE__ */ jsxDEV2("input", {
134
- type: "checkbox",
135
- "data-select-all": true,
136
- "aria-label": "Select all"
137
- }, undefined, false, undefined, this)
138
- }, undefined, false, undefined, this) : null,
139
- columns.map((col) => /* @__PURE__ */ jsxDEV2("th", {
140
- "data-col": col,
141
- className: "border-table-border border-b px-4 py-2 text-xs font-bold tracking-wider uppercase",
142
- children: sortable?.includes(col) ? /* @__PURE__ */ jsxDEV2("a", {
143
- className: "text-link hover:text-link-hover",
144
- "data-qlink": true,
145
- "data-sort-link": col,
146
- href: href(params, {
147
- sort: col,
148
- order: activeSort === col && activeOrder === "asc" ? "desc" : "asc"
149
- }),
150
- children: [
151
- col,
152
- /* @__PURE__ */ jsxDEV2("span", {
153
- "data-sort-ind": true,
154
- children: activeSort === col ? activeOrder === "asc" ? " ▲" : " ▼" : ""
155
- }, undefined, false, undefined, this)
156
- ]
157
- }, undefined, true, undefined, this) : col
158
- }, col, false, undefined, this)),
159
- editable ? /* @__PURE__ */ jsxDEV2("th", {
160
- className: "border-table-border border-b px-4 py-2 text-xs font-bold tracking-wider uppercase",
161
- children: "Actions"
162
- }, undefined, false, undefined, this) : null
163
- ]
164
- }, undefined, true, undefined, this)
165
- }, undefined, false, undefined, this),
166
- /* @__PURE__ */ jsxDEV2("tbody", {
167
- "data-panel-rows": true,
168
- children: rows.map((row, i) => /* @__PURE__ */ jsxDEV2("tr", {
169
- className: "hover:bg-table-row-hover",
170
- children: [
171
- selectable ? /* @__PURE__ */ jsxDEV2("td", {
172
- className: "border-table-border border-t px-4 py-2",
173
- children: /* @__PURE__ */ jsxDEV2("input", {
174
- type: "checkbox",
175
- "data-select-row": true,
176
- value: String(row[pk] ?? ""),
177
- "aria-label": `Select row ${String(row[pk] ?? i)}`
178
- }, undefined, false, undefined, this)
179
- }, undefined, false, undefined, this) : null,
180
- columns.map((col) => /* @__PURE__ */ jsxDEV2("td", {
181
- className: "border-table-border border-t px-4 py-2",
182
- children: col === "status" && statusBadge(row[col]) ? /* @__PURE__ */ jsxDEV2("span", {
183
- className: `rounded-full px-2 py-0.5 text-xs font-semibold ${statusBadge(row[col]) ?? ""}`,
184
- children: cell(row[col])
185
- }, undefined, false, undefined, this) : cell(row[col])
186
- }, col, false, undefined, this)),
187
- editable ? /* @__PURE__ */ jsxDEV2("td", {
188
- className: "border-table-border border-t px-4 py-2 whitespace-nowrap",
189
- children: /* @__PURE__ */ jsxDEV2("div", {
190
- className: "border-table-border inline-flex overflow-hidden rounded-md border",
191
- children: [
192
- /* @__PURE__ */ jsxDEV2("button", {
193
- type: "button",
194
- "data-edit-id": String(row[pk] ?? ""),
195
- className: "text-link hover:bg-table-row-hover px-2 py-1 text-sm font-semibold",
196
- children: "Edit"
197
- }, undefined, false, undefined, this),
198
- /* @__PURE__ */ jsxDEV2("button", {
199
- type: "button",
200
- "data-delete-id": String(row[pk] ?? ""),
201
- className: "border-table-border text-destructive hover:bg-table-row-hover border-l px-2 py-1 text-sm font-semibold",
202
- children: "Delete"
203
- }, undefined, false, undefined, this)
204
- ]
205
- }, undefined, true, undefined, this)
206
- }, undefined, false, undefined, this) : null
207
- ]
208
- }, i, true, undefined, this))
209
- }, undefined, false, undefined, this)
210
- ]
211
- }, undefined, true, undefined, this)
212
- }, undefined, false, undefined, this);
213
- }
214
-
215
- // src/react/page/components/Masthead.tsx
216
- import { jsxDEV as jsxDEV3 } from "react/jsx-dev-runtime";
217
- function Masthead({ title, group, resource, total }) {
218
- const today = new Date().toLocaleDateString("en-US", {
219
- weekday: "long",
220
- day: "numeric",
221
- month: "long",
222
- year: "numeric"
223
- });
224
- return /* @__PURE__ */ jsxDEV3("header", {
225
- className: "bg-header text-header-foreground",
226
- children: [
227
- /* @__PURE__ */ jsxDEV3("div", {
228
- className: "flex items-center justify-between gap-4 py-2 text-xs tracking-widest text-text-muted uppercase",
229
- children: [
230
- /* @__PURE__ */ jsxDEV3("span", {
231
- children: today
232
- }, undefined, false, undefined, this),
233
- /* @__PURE__ */ jsxDEV3("span", {
234
- className: "hidden sm:inline",
235
- children: "Daily Edition"
236
- }, undefined, false, undefined, this),
237
- /* @__PURE__ */ jsxDEV3("button", {
238
- id: "koran-theme-toggle",
239
- type: "button",
240
- className: "border-border hover:bg-navigation-hover rounded-full border px-3 py-1 tracking-widest uppercase",
241
- children: "◐ Theme"
242
- }, undefined, false, undefined, this)
243
- ]
244
- }, undefined, true, undefined, this),
245
- /* @__PURE__ */ jsxDEV3("h1", {
246
- className: "font-koran py-2 text-center text-5xl font-black tracking-tight",
247
- children: title
248
- }, undefined, false, undefined, this),
249
- /* @__PURE__ */ jsxDEV3("div", {
250
- className: "flex items-center justify-center gap-2 pb-3 text-sm text-text-muted",
251
- children: [
252
- group ? /* @__PURE__ */ jsxDEV3("span", {
253
- className: "uppercase",
254
- children: group
255
- }, undefined, false, undefined, this) : null,
256
- group && (resource || total !== undefined) ? /* @__PURE__ */ jsxDEV3("span", {
257
- "aria-hidden": "true",
258
- children: "·"
259
- }, undefined, false, undefined, this) : null,
260
- resource ? /* @__PURE__ */ jsxDEV3("span", {
261
- className: "font-mono text-xs",
262
- children: [
263
- "/",
264
- resource
265
- ]
266
- }, undefined, true, undefined, this) : null,
267
- total !== undefined ? /* @__PURE__ */ jsxDEV3("span", {
268
- children: [
269
- total,
270
- " records"
271
- ]
272
- }, undefined, true, undefined, this) : null
273
- ]
274
- }, undefined, true, undefined, this),
275
- /* @__PURE__ */ jsxDEV3("div", {
276
- className: "koran-rule-double"
277
- }, undefined, false, undefined, this)
278
- ]
279
- }, undefined, true, undefined, this);
280
- }
281
-
282
- // src/react/page/components/Pagination.tsx
283
- import { jsxDEV as jsxDEV4 } from "react/jsx-dev-runtime";
284
- var pageClass = "border-border rounded-md border px-3 py-1 text-sm hover:bg-navigation-hover";
285
- var currentClass = "bg-primary text-primary-foreground rounded-md px-3 py-1 text-sm font-bold";
286
- var disabledClass = "border-border text-text-disabled rounded-md border px-3 py-1 text-sm";
287
- function Pagination({ page, totalPages, total, limit, params }) {
288
- const from = total === 0 ? 0 : (page - 1) * limit + 1;
289
- const to = Math.min(page * limit, total);
290
- return /* @__PURE__ */ jsxDEV4("nav", {
291
- className: "flex flex-wrap items-center justify-between gap-3 py-4 text-sm",
292
- children: [
293
- /* @__PURE__ */ jsxDEV4("p", {
294
- className: "text-text-muted",
295
- "data-panel-count": true,
296
- children: [
297
- "Page ",
298
- page,
299
- " of ",
300
- totalPages,
301
- " — ",
302
- from,
303
- "–",
304
- to,
305
- " of ",
306
- total,
307
- " records"
308
- ]
309
- }, undefined, true, undefined, this),
310
- /* @__PURE__ */ jsxDEV4("div", {
311
- className: "flex items-center gap-1",
312
- "data-panel-pages": true,
313
- children: [
314
- page > 1 ? /* @__PURE__ */ jsxDEV4("a", {
315
- className: pageClass,
316
- "data-qlink": true,
317
- href: href(params, { page: page - 1 }),
318
- children: "← Previous"
319
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV4("span", {
320
- className: disabledClass,
321
- children: "← Previous"
322
- }, undefined, false, undefined, this),
323
- pageWindow(page, totalPages).map((p, i) => p === "…" ? /* @__PURE__ */ jsxDEV4("span", {
324
- className: "text-text-muted px-1",
325
- children: "…"
326
- }, `e${i}`, false, undefined, this) : p === page ? /* @__PURE__ */ jsxDEV4("span", {
327
- className: currentClass,
328
- children: p
329
- }, p, false, undefined, this) : /* @__PURE__ */ jsxDEV4("a", {
330
- className: pageClass,
331
- "data-qlink": true,
332
- href: href(params, { page: p }),
333
- children: p
334
- }, p, false, undefined, this)),
335
- page < totalPages ? /* @__PURE__ */ jsxDEV4("a", {
336
- className: pageClass,
337
- "data-qlink": true,
338
- href: href(params, { page: page + 1 }),
339
- children: "Next →"
340
- }, undefined, false, undefined, this) : /* @__PURE__ */ jsxDEV4("span", {
341
- className: disabledClass,
342
- children: "Next →"
343
- }, undefined, false, undefined, this)
344
- ]
345
- }, undefined, true, undefined, this)
346
- ]
347
- }, undefined, true, undefined, this);
348
- }
349
-
350
- // src/react/page/components/Sidebar.tsx
351
- import { jsxDEV as jsxDEV5 } from "react/jsx-dev-runtime";
352
- function SidebarItemView({ item, depth = 0 }) {
353
- const hasChildren = item.children && item.children.length > 0;
354
- return /* @__PURE__ */ jsxDEV5("li", {
355
- children: [
356
- /* @__PURE__ */ jsxDEV5("a", {
357
- href: item.href,
358
- "aria-current": item.active ? "page" : undefined,
359
- className: item.active ? "bg-sidebar-primary text-sidebar-primary-foreground flex items-center gap-2 rounded-md px-2 py-1.5 text-sm font-semibold" : "hover:bg-sidebar-accent hover:text-sidebar-accent-foreground flex items-center gap-2 rounded-md px-2 py-1.5 text-sm",
360
- style: depth > 0 ? { paddingLeft: `${8 + depth * 12}px` } : undefined,
361
- children: [
362
- item.icon ? /* @__PURE__ */ jsxDEV5("span", {
363
- "aria-hidden": "true",
364
- children: item.icon
365
- }, undefined, false, undefined, this) : null,
366
- /* @__PURE__ */ jsxDEV5("span", {
367
- children: item.label
368
- }, undefined, false, undefined, this)
369
- ]
370
- }, undefined, true, undefined, this),
371
- hasChildren ? /* @__PURE__ */ jsxDEV5("ul", {
372
- className: "border-sidebar-border mt-0.5 ml-2 flex flex-col gap-0.5 border-l py-1 pl-2",
373
- children: item.children.map((child) => /* @__PURE__ */ jsxDEV5(SidebarItemView, {
374
- item: child,
375
- depth: depth + 1
376
- }, child.id, false, undefined, this))
377
- }, undefined, false, undefined, this) : null
378
- ]
379
- }, undefined, true, undefined, this);
380
- }
381
- function hasActive(items) {
382
- for (const it of items) {
383
- if (it.active)
384
- return true;
385
- if (it.children && hasActive(it.children))
386
- return true;
387
- }
388
- return false;
389
- }
390
- function Sidebar({ title, groups }) {
391
- return /* @__PURE__ */ jsxDEV5("aside", {
392
- className: "bg-sidebar text-sidebar-foreground border-sidebar-border min-h-0 w-64 shrink-0 overflow-y-auto rounded-lg border",
393
- children: [
394
- /* @__PURE__ */ jsxDEV5("div", {
395
- className: "border-sidebar-border border-b px-4 py-3",
396
- children: /* @__PURE__ */ jsxDEV5("p", {
397
- className: "font-koran text-xl font-black tracking-tight",
398
- children: title
399
- }, undefined, false, undefined, this)
400
- }, undefined, false, undefined, this),
401
- /* @__PURE__ */ jsxDEV5("nav", {
402
- className: "flex flex-col gap-4 p-3",
403
- children: groups.map((group) => /* @__PURE__ */ jsxDEV5("section", {
404
- children: /* @__PURE__ */ jsxDEV5("details", {
405
- className: "group",
406
- open: hasActive(group.items) || undefined,
407
- children: [
408
- /* @__PURE__ */ jsxDEV5("summary", {
409
- className: "font-koran border-sidebar-border flex cursor-pointer list-none items-center justify-between border-b px-2 pb-1 text-base font-bold tracking-tight [&::-webkit-details-marker]:hidden",
410
- children: [
411
- /* @__PURE__ */ jsxDEV5("span", {
412
- children: group.name
413
- }, undefined, false, undefined, this),
414
- /* @__PURE__ */ jsxDEV5("span", {
415
- "aria-hidden": "true",
416
- className: "text-text-muted text-xs transition group-open:rotate-180",
417
- children: "▾"
418
- }, undefined, false, undefined, this)
419
- ]
420
- }, undefined, true, undefined, this),
421
- /* @__PURE__ */ jsxDEV5("ul", {
422
- className: "border-sidebar-border mt-1 ml-2 flex flex-col gap-0.5 border-l py-1 pl-2",
423
- children: group.items.map((item) => /* @__PURE__ */ jsxDEV5(SidebarItemView, {
424
- item
425
- }, item.id, false, undefined, this))
426
- }, undefined, false, undefined, this)
427
- ]
428
- }, undefined, true, undefined, this)
429
- }, group.name, false, undefined, this))
430
- }, undefined, false, undefined, this)
431
- ]
432
- }, undefined, true, undefined, this);
433
- }
434
-
435
- // src/react/page/components/Toolbar.tsx
436
- import { jsxDEV as jsxDEV6, Fragment } from "react/jsx-dev-runtime";
437
- var inputClass = "bg-input-background border-input text-foreground placeholder:text-form-placeholder rounded-md border px-3 py-1.5 text-sm";
438
- var labelClass = "flex flex-col gap-1 text-xs font-semibold tracking-wider text-form-label uppercase";
439
- function Toolbar({ searchable, filterable, sortable, params }) {
440
- if (!searchable?.length && !filterable?.length && !sortable?.length)
441
- return null;
442
- return /* @__PURE__ */ jsxDEV6("form", {
443
- method: "get",
444
- action: "",
445
- className: "flex flex-wrap items-end gap-3 py-4",
446
- children: [
447
- searchable && searchable.length > 0 ? /* @__PURE__ */ jsxDEV6("label", {
448
- className: labelClass,
449
- children: [
450
- "Search",
451
- /* @__PURE__ */ jsxDEV6("input", {
452
- name: "search",
453
- defaultValue: String(params.search ?? ""),
454
- placeholder: searchable.join(", "),
455
- className: inputClass
456
- }, undefined, false, undefined, this)
457
- ]
458
- }, undefined, true, undefined, this) : null,
459
- (filterable ?? []).map((field) => /* @__PURE__ */ jsxDEV6("label", {
460
- className: labelClass,
461
- children: [
462
- field,
463
- /* @__PURE__ */ jsxDEV6("input", {
464
- name: field,
465
- defaultValue: String(params[field] ?? ""),
466
- className: inputClass
467
- }, undefined, false, undefined, this)
468
- ]
469
- }, field, true, undefined, this)),
470
- sortable && sortable.length > 0 ? /* @__PURE__ */ jsxDEV6(Fragment, {
471
- children: [
472
- /* @__PURE__ */ jsxDEV6("label", {
473
- className: labelClass,
474
- children: [
475
- "Sort",
476
- /* @__PURE__ */ jsxDEV6("select", {
477
- name: "sort",
478
- defaultValue: String(params.sort ?? ""),
479
- className: inputClass,
480
- children: [
481
- /* @__PURE__ */ jsxDEV6("option", {
482
- value: "",
483
- children: "—"
484
- }, undefined, false, undefined, this),
485
- sortable.map((field) => /* @__PURE__ */ jsxDEV6("option", {
486
- value: field,
487
- children: field
488
- }, field, false, undefined, this))
489
- ]
490
- }, undefined, true, undefined, this)
491
- ]
492
- }, undefined, true, undefined, this),
493
- /* @__PURE__ */ jsxDEV6("label", {
494
- className: labelClass,
495
- children: [
496
- "Order",
497
- /* @__PURE__ */ jsxDEV6("select", {
498
- name: "order",
499
- defaultValue: String(params.order ?? ""),
500
- className: inputClass,
501
- children: [
502
- /* @__PURE__ */ jsxDEV6("option", {
503
- value: "asc",
504
- children: "Ascending"
505
- }, undefined, false, undefined, this),
506
- /* @__PURE__ */ jsxDEV6("option", {
507
- value: "desc",
508
- children: "Descending"
509
- }, undefined, false, undefined, this)
510
- ]
511
- }, undefined, true, undefined, this)
512
- ]
513
- }, undefined, true, undefined, this)
514
- ]
515
- }, undefined, true, undefined, this) : null,
516
- /* @__PURE__ */ jsxDEV6("button", {
517
- type: "submit",
518
- className: "bg-primary text-primary-foreground rounded-md px-4 py-1.5 text-sm font-semibold",
519
- children: "Apply"
520
- }, undefined, false, undefined, this)
521
- ]
522
- }, undefined, true, undefined, this);
523
- }
524
-
525
- // src/react/page/Panel.tsx
526
- import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
527
- var inputClass2 = "bg-input-background border-input text-foreground rounded-md border px-3 py-1.5 text-sm font-normal normal-case";
528
- var fieldLabelClass = "flex flex-col gap-1 text-xs font-semibold tracking-wider text-form-label uppercase";
529
- function FieldInput({ field, required }) {
530
- switch (field.kind) {
531
- case "enum":
532
- return /* @__PURE__ */ jsxDEV7("label", {
533
- className: fieldLabelClass,
534
- children: [
535
- field.name,
536
- /* @__PURE__ */ jsxDEV7("select", {
537
- name: field.name,
538
- required,
539
- defaultValue: "",
540
- className: inputClass2,
541
- children: [
542
- /* @__PURE__ */ jsxDEV7("option", {
543
- value: "",
544
- children: "—"
545
- }, undefined, false, undefined, this),
546
- (field.enumValues ?? []).map((v) => /* @__PURE__ */ jsxDEV7("option", {
547
- value: v,
548
- children: v
549
- }, v, false, undefined, this))
550
- ]
551
- }, undefined, true, undefined, this)
552
- ]
553
- }, undefined, true, undefined, this);
554
- case "boolean":
555
- return /* @__PURE__ */ jsxDEV7("label", {
556
- className: fieldLabelClass,
557
- children: [
558
- field.name,
559
- /* @__PURE__ */ jsxDEV7("input", {
560
- type: "checkbox",
561
- name: field.name,
562
- value: "true",
563
- className: "h-4 w-4"
564
- }, undefined, false, undefined, this)
565
- ]
566
- }, undefined, true, undefined, this);
567
- case "integer":
568
- case "number":
569
- return /* @__PURE__ */ jsxDEV7("label", {
570
- className: fieldLabelClass,
571
- children: [
572
- field.name,
573
- /* @__PURE__ */ jsxDEV7("input", {
574
- type: "number",
575
- step: field.kind === "number" ? "any" : "1",
576
- name: field.name,
577
- required,
578
- className: inputClass2
579
- }, undefined, false, undefined, this)
580
- ]
581
- }, undefined, true, undefined, this);
582
- case "date":
583
- return /* @__PURE__ */ jsxDEV7("label", {
584
- className: fieldLabelClass,
585
- children: [
586
- field.name,
587
- /* @__PURE__ */ jsxDEV7("input", {
588
- type: "datetime-local",
589
- name: field.name,
590
- required,
591
- className: inputClass2
592
- }, undefined, false, undefined, this)
593
- ]
594
- }, undefined, true, undefined, this);
595
- case "json":
596
- return /* @__PURE__ */ jsxDEV7("label", {
597
- className: fieldLabelClass,
598
- children: [
599
- field.name,
600
- /* @__PURE__ */ jsxDEV7("textarea", {
601
- name: field.name,
602
- "data-json": true,
603
- rows: 3,
604
- placeholder: "{}",
605
- className: `${inputClass2} font-mono`
606
- }, undefined, false, undefined, this)
607
- ]
608
- }, undefined, true, undefined, this);
609
- default:
610
- return /* @__PURE__ */ jsxDEV7("label", {
611
- className: fieldLabelClass,
612
- children: [
613
- field.name,
614
- /* @__PURE__ */ jsxDEV7("input", {
615
- name: field.name,
616
- required,
617
- className: inputClass2
618
- }, undefined, false, undefined, this)
619
- ]
620
- }, undefined, true, undefined, this);
621
- }
622
- }
623
- function itemLabel(r) {
624
- return r.metadata.pluralLabel ?? r.metadata.label ?? r.metadata.id;
625
- }
626
- function toSidebarItem(node, activeId) {
627
- return {
628
- id: node.metadata.id,
629
- label: itemLabel(node),
630
- icon: node.metadata.icon,
631
- href: node.path,
632
- active: node.metadata.id === activeId,
633
- children: node.children.filter((c) => !c.metadata.hidden).map((c) => toSidebarItem(c, activeId))
634
- };
635
- }
636
- function buildGroupsFromTree(tree, activeId) {
637
- const byGroup = new Map;
638
- for (const root of tree) {
639
- if (root.metadata.hidden)
640
- continue;
641
- const name = root.metadata.group ?? "General";
642
- let group = byGroup.get(name);
643
- if (!group) {
644
- group = { name, items: [] };
645
- byGroup.set(name, group);
646
- }
647
- group.items.push(toSidebarItem(root, activeId));
648
- }
649
- return [...byGroup.values()].sort((a, b) => a.name.localeCompare(b.name));
650
- }
651
- async function Panel(props) {
652
- const params = props.params ?? {};
653
- const page = Math.max(Number(params.page ?? 1) || 1, 1);
654
- const limit = Math.max(Number(params.limit ?? props.query?.pagination?.default ?? 20) || 1, 1);
655
- let rows = [];
656
- let total = 0;
657
- if (props.load) {
658
- const result = await props.load(params);
659
- rows = result.data;
660
- total = result.total;
661
- }
662
- const columns = rows.length > 0 ? Object.keys(rows[0] ?? {}).filter((c) => c !== "deletedAt") : [];
663
- const title = props.metadata?.pluralLabel ?? props.metadata?.label ?? props.resource ?? "Panel";
664
- const totalPages = Math.max(1, Math.ceil(total / limit));
665
- const pk = props.primaryKey ?? "id";
666
- const deletedAt = props.deletedAtField ?? "deletedAt";
667
- const fieldDefs = props.fields?.length ? props.fields.filter((f) => !f.autoIncrement && f.name !== deletedAt).map((f) => ({
668
- name: f.name,
669
- kind: f.kind,
670
- nullable: f.nullable,
671
- enumValues: f.enumValues
672
- })) : columns.filter((c) => c !== deletedAt).map((name) => ({
673
- name,
674
- kind: "text",
675
- nullable: name === pk
676
- }));
677
- const createFields = fieldDefs;
678
- const editFields = fieldDefs.filter((f) => f.name !== pk);
679
- const isRequired = (f) => !f.nullable && f.kind !== "boolean";
680
- const canCreate = props.operations?.create !== false;
681
- const canEdit = props.operations?.update !== false || props.operations?.replace !== false;
682
- const canDelete = props.operations?.delete !== false;
683
- const selectable = canEdit || canDelete;
684
- const tree = getRackTree().filter((r) => !r.metadata.hidden);
685
- const groups = buildGroupsFromTree(tree, props.resource);
686
- const trail = [
687
- { label: "Dashboard", href: "/" },
688
- ...props.metadata?.group ? [{ label: props.metadata.group }] : [],
689
- { label: title }
690
- ];
691
- return /* @__PURE__ */ jsxDEV7("div", {
692
- className: "koran-paper font-koran-body text-foreground flex min-h-screen flex-col",
693
- children: /* @__PURE__ */ jsxDEV7("div", {
694
- className: "flex flex-1 gap-6 p-4 sm:p-6",
695
- children: [
696
- /* @__PURE__ */ jsxDEV7(Sidebar, {
697
- title: "Panel",
698
- groups
699
- }, undefined, false, undefined, this),
700
- /* @__PURE__ */ jsxDEV7("main", {
701
- className: "flex min-w-0 flex-1 flex-col",
702
- children: [
703
- /* @__PURE__ */ jsxDEV7(Breadcrumb, {
704
- trail
705
- }, undefined, false, undefined, this),
706
- /* @__PURE__ */ jsxDEV7("div", {
707
- className: "mx-auto w-full max-w-5xl px-4 pb-10 sm:px-6",
708
- children: [
709
- /* @__PURE__ */ jsxDEV7(Masthead, {
710
- title,
711
- group: props.metadata?.group,
712
- resource: props.resource,
713
- total
714
- }, undefined, false, undefined, this),
715
- /* @__PURE__ */ jsxDEV7("div", {
716
- "data-query-url": props.queryUrl,
717
- children: [
718
- /* @__PURE__ */ jsxDEV7(Toolbar, {
719
- searchable: props.query?.searchable,
720
- filterable: props.query?.filterable,
721
- sortable: props.query?.sortable,
722
- params
723
- }, undefined, false, undefined, this),
724
- /* @__PURE__ */ jsxDEV7("div", {
725
- className: "flex items-center justify-between gap-3 pb-3",
726
- children: [
727
- /* @__PURE__ */ jsxDEV7("div", {
728
- "data-bulk-bar": true,
729
- style: { display: "none" },
730
- className: "items-center gap-2",
731
- children: [
732
- /* @__PURE__ */ jsxDEV7("span", {
733
- "data-bulk-count": true,
734
- className: "text-sm text-text-muted"
735
- }, undefined, false, undefined, this),
736
- canDelete ? /* @__PURE__ */ jsxDEV7("button", {
737
- type: "button",
738
- "data-bulk-delete": true,
739
- className: "bg-destructive text-destructive-foreground rounded-md px-3 py-1.5 text-sm font-semibold",
740
- children: "Delete selected"
741
- }, undefined, false, undefined, this) : null,
742
- canEdit ? /* @__PURE__ */ jsxDEV7("span", {
743
- className: "inline-flex items-center gap-2",
744
- children: [
745
- /* @__PURE__ */ jsxDEV7("select", {
746
- "data-bulk-field": true,
747
- "aria-label": "Bulk field",
748
- className: "bg-input-background border-input rounded-md border px-2 py-1.5 text-sm",
749
- children: editFields.map((f) => /* @__PURE__ */ jsxDEV7("option", {
750
- value: f.name,
751
- children: f.name
752
- }, f.name, false, undefined, this))
753
- }, undefined, false, undefined, this),
754
- /* @__PURE__ */ jsxDEV7("input", {
755
- "data-bulk-value": true,
756
- placeholder: "New value",
757
- "aria-label": "Bulk value",
758
- className: "bg-input-background border-input placeholder:text-form-placeholder rounded-md border px-2 py-1.5 text-sm"
759
- }, undefined, false, undefined, this),
760
- /* @__PURE__ */ jsxDEV7("button", {
761
- type: "button",
762
- "data-bulk-apply": true,
763
- className: "bg-secondary text-secondary-foreground rounded-md px-3 py-1.5 text-sm font-semibold",
764
- children: "Apply"
765
- }, undefined, false, undefined, this)
766
- ]
767
- }, undefined, true, undefined, this) : null,
768
- /* @__PURE__ */ jsxDEV7("button", {
769
- type: "button",
770
- "data-bulk-clear": true,
771
- className: "text-text-muted text-sm underline",
772
- children: "Clear"
773
- }, undefined, false, undefined, this)
774
- ]
775
- }, undefined, true, undefined, this),
776
- canCreate ? /* @__PURE__ */ jsxDEV7("button", {
777
- type: "button",
778
- "data-open-create": true,
779
- className: "bg-primary text-primary-foreground ml-auto rounded-md px-4 py-1.5 text-sm font-semibold",
780
- children: "+ New"
781
- }, undefined, false, undefined, this) : null
782
- ]
783
- }, undefined, true, undefined, this),
784
- /* @__PURE__ */ jsxDEV7(DataTable, {
785
- columns,
786
- rows,
787
- sortable: props.query?.sortable,
788
- params,
789
- selectable,
790
- editable: canEdit || canDelete,
791
- primaryKey: pk
792
- }, undefined, false, undefined, this),
793
- /* @__PURE__ */ jsxDEV7(Pagination, {
794
- page,
795
- totalPages,
796
- total,
797
- limit,
798
- params
799
- }, undefined, false, undefined, this),
800
- /* @__PURE__ */ jsxDEV7("dialog", {
801
- id: "rack-create",
802
- className: "bg-card text-card-foreground rounded-lg border p-0",
803
- children: /* @__PURE__ */ jsxDEV7("form", {
804
- "data-create-form": true,
805
- className: "flex min-w-80 flex-col gap-3 p-6",
806
- children: [
807
- /* @__PURE__ */ jsxDEV7("h2", {
808
- className: "font-koran text-2xl font-bold",
809
- children: "New record"
810
- }, undefined, false, undefined, this),
811
- createFields.length > 0 ? createFields.map((f) => /* @__PURE__ */ jsxDEV7(FieldInput, {
812
- field: f,
813
- required: isRequired(f)
814
- }, f.name, false, undefined, this)) : /* @__PURE__ */ jsxDEV7("label", {
815
- className: "flex flex-col gap-1 text-xs font-semibold tracking-wider text-form-label uppercase",
816
- children: [
817
- "JSON body",
818
- /* @__PURE__ */ jsxDEV7("textarea", {
819
- "data-create-json": true,
820
- rows: 4,
821
- placeholder: '{"name": "..."}',
822
- className: "bg-input-background border-input text-foreground rounded-md border px-3 py-1.5 font-mono text-sm font-normal normal-case"
823
- }, undefined, false, undefined, this)
824
- ]
825
- }, undefined, true, undefined, this),
826
- /* @__PURE__ */ jsxDEV7("p", {
827
- "data-form-error": true,
828
- className: "text-form-error text-sm"
829
- }, undefined, false, undefined, this),
830
- /* @__PURE__ */ jsxDEV7("div", {
831
- className: "flex justify-end gap-2",
832
- children: [
833
- /* @__PURE__ */ jsxDEV7("button", {
834
- type: "button",
835
- "data-close": true,
836
- className: "border-border rounded-md border px-4 py-1.5 text-sm",
837
- children: "Cancel"
838
- }, undefined, false, undefined, this),
839
- /* @__PURE__ */ jsxDEV7("button", {
840
- type: "submit",
841
- className: "bg-primary text-primary-foreground rounded-md px-4 py-1.5 text-sm font-semibold",
842
- children: "Create"
843
- }, undefined, false, undefined, this)
844
- ]
845
- }, undefined, true, undefined, this)
846
- ]
847
- }, undefined, true, undefined, this)
848
- }, undefined, false, undefined, this),
849
- /* @__PURE__ */ jsxDEV7("dialog", {
850
- id: "rack-edit",
851
- className: "bg-card text-card-foreground rounded-lg border p-0",
852
- children: /* @__PURE__ */ jsxDEV7("form", {
853
- "data-edit-form": true,
854
- className: "flex min-w-80 flex-col gap-3 p-6",
855
- children: [
856
- /* @__PURE__ */ jsxDEV7("h2", {
857
- className: "font-koran text-2xl font-bold",
858
- children: [
859
- "Edit record ",
860
- /* @__PURE__ */ jsxDEV7("span", {
861
- "data-edit-id-label": true,
862
- className: "text-text-muted text-lg"
863
- }, undefined, false, undefined, this)
864
- ]
865
- }, undefined, true, undefined, this),
866
- editFields.map((f) => /* @__PURE__ */ jsxDEV7(FieldInput, {
867
- field: f
868
- }, f.name, false, undefined, this)),
869
- /* @__PURE__ */ jsxDEV7("p", {
870
- "data-form-error": true,
871
- className: "text-form-error text-sm"
872
- }, undefined, false, undefined, this),
873
- /* @__PURE__ */ jsxDEV7("div", {
874
- className: "flex justify-end gap-2",
875
- children: [
876
- /* @__PURE__ */ jsxDEV7("button", {
877
- type: "button",
878
- "data-close": true,
879
- className: "border-border rounded-md border px-4 py-1.5 text-sm",
880
- children: "Cancel"
881
- }, undefined, false, undefined, this),
882
- /* @__PURE__ */ jsxDEV7("button", {
883
- type: "submit",
884
- className: "bg-primary text-primary-foreground rounded-md px-4 py-1.5 text-sm font-semibold",
885
- children: "Save"
886
- }, undefined, false, undefined, this)
887
- ]
888
- }, undefined, true, undefined, this)
889
- ]
890
- }, undefined, true, undefined, this)
891
- }, undefined, false, undefined, this),
892
- /* @__PURE__ */ jsxDEV7("script", {
893
- type: "module",
894
- src: "/__rack/panel-app.js"
895
- }, undefined, false, undefined, this)
896
- ]
897
- }, undefined, true, undefined, this),
898
- /* @__PURE__ */ jsxDEV7("footer", {
899
- className: "border-border text-text-muted border-t pt-3 text-center text-xs tracking-widest uppercase",
900
- children: "Printed by elysia-rack"
901
- }, undefined, false, undefined, this)
902
- ]
903
- }, undefined, true, undefined, this)
904
- ]
905
- }, undefined, true, undefined, this)
906
- ]
907
- }, undefined, true, undefined, this)
908
- }, undefined, false, undefined, this);
909
- }
910
- export {
911
- Panel as default
912
- };