@shamar/adonis 0.1.1 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/assets/admin.css +1 -1
- package/assets/input.css +42 -2
- package/assets/shamar-ui.js +290 -5
- package/dist/config.d.ts +27 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/controllers/admin_controller.d.ts +2 -0
- package/dist/controllers/admin_controller.d.ts.map +1 -1
- package/dist/controllers/admin_controller.js +80 -3
- package/dist/controllers/admin_controller.js.map +1 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +2 -1
- package/dist/provider.js.map +1 -1
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +27 -5
- package/dist/routes.js.map +1 -1
- package/dist/shamar/branding.d.ts +11 -10
- package/dist/shamar/branding.d.ts.map +1 -1
- package/dist/shamar/branding.js +42 -2
- package/dist/shamar/branding.js.map +1 -1
- package/dist/shamar/list-query.d.ts +11 -2
- package/dist/shamar/list-query.d.ts.map +1 -1
- package/dist/shamar/list-query.js +29 -1
- package/dist/shamar/list-query.js.map +1 -1
- package/dist/shamar/relation-fields.d.ts +15 -0
- package/dist/shamar/relation-fields.d.ts.map +1 -1
- package/dist/shamar/relation-fields.js +22 -2
- package/dist/shamar/relation-fields.js.map +1 -1
- package/dist/shamar/relation-table.d.ts +37 -0
- package/dist/shamar/relation-table.d.ts.map +1 -0
- package/dist/shamar/relation-table.js +61 -0
- package/dist/shamar/relation-table.js.map +1 -0
- package/dist/shamar/view-context.d.ts +6 -0
- package/dist/shamar/view-context.d.ts.map +1 -1
- package/dist/shamar/view-context.js +4 -0
- package/dist/shamar/view-context.js.map +1 -1
- package/package.json +5 -5
- package/resources/views/shamar/form.edge +7 -1
- package/resources/views/shamar/index.edge +3 -2
- package/resources/views/shamar/partials/detail-entry.edge +9 -0
- package/resources/views/shamar/partials/field-relation-table.edge +309 -105
- package/resources/views/shamar/partials/list-row.edge +17 -4
- package/resources/views/shamar/partials/list-toolbar.edge +1 -1
- package/resources/views/shamar/partials/shell-open.edge +4 -0
- package/resources/views/shamar/show.edge +59 -14
|
@@ -18,122 +18,326 @@
|
|
|
18
18
|
@endif
|
|
19
19
|
|
|
20
20
|
<div class="shamar-m2m-table__card rounded-md border border-default">
|
|
21
|
-
<div class="shamar-m2m-table__toolbar flex flex-
|
|
22
|
-
<
|
|
23
|
-
<
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
@
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
21
|
+
<div class="shamar-m2m-table__toolbar flex flex-col gap-2 border-b border-default bg-surface-header px-3 py-2">
|
|
22
|
+
<div class="flex flex-wrap items-center justify-between gap-2">
|
|
23
|
+
<p class="text-xs font-medium text-body-subtle">
|
|
24
|
+
<span x-show="listUrl">
|
|
25
|
+
<span x-text="total"></span>
|
|
26
|
+
<span x-text="singularLabel.toLowerCase()"></span><span x-show="total !== 1">s</span>
|
|
27
|
+
</span>
|
|
28
|
+
<span x-show="!listUrl">
|
|
29
|
+
<span x-text="selected.length"></span> linked
|
|
30
|
+
<span x-text="singularLabel.toLowerCase()"></span><span x-show="selected.length !== 1">s</span>
|
|
31
|
+
</span>
|
|
32
|
+
</p>
|
|
33
|
+
<div class="flex flex-wrap items-center gap-2">
|
|
34
|
+
<div class="relative" x-show="listUrl && filterableHeaders.length">
|
|
35
|
+
<button
|
|
36
|
+
type="button"
|
|
37
|
+
class="inline-flex items-center gap-1 rounded-md border border-default bg-neutral-primary px-2.5 py-1 text-xs font-medium text-body hover:border-fg-brand hover:text-fg-brand"
|
|
38
|
+
@click="filterPanelOpen = !filterPanelOpen"
|
|
39
|
+
>
|
|
40
|
+
Filters
|
|
41
|
+
<span
|
|
42
|
+
x-show="listFilters.length"
|
|
43
|
+
class="rounded-full bg-brand-softer px-1.5 text-[10px] font-semibold text-fg-brand"
|
|
44
|
+
x-text="listFilters.length"
|
|
45
|
+
></span>
|
|
46
|
+
</button>
|
|
47
|
+
<div
|
|
48
|
+
x-show="filterPanelOpen"
|
|
49
|
+
x-cloak
|
|
50
|
+
@click.outside="filterPanelOpen = false"
|
|
51
|
+
class="absolute right-0 z-50 mt-1 w-64 rounded-md border border-default bg-neutral-primary p-2 text-sm shadow-lg"
|
|
52
|
+
>
|
|
53
|
+
<template x-for="header in filterableHeaders" :key="header.name">
|
|
54
|
+
<div class="mb-2 last:mb-0">
|
|
55
|
+
<p class="mb-1 text-[11px] font-semibold uppercase tracking-wide text-body-subtle" x-text="header.label"></p>
|
|
56
|
+
<div class="flex gap-1" x-show="header.filter_kind === 'boolean'">
|
|
57
|
+
<button
|
|
58
|
+
type="button"
|
|
59
|
+
class="rounded-md border px-2 py-0.5 text-xs"
|
|
60
|
+
:class="hasFilter(header, true) ? 'border-fg-brand bg-brand-softer text-fg-brand' : 'border-default text-body'"
|
|
61
|
+
@click="toggleBooleanFilter(header, true)"
|
|
62
|
+
>Yes</button>
|
|
63
|
+
<button
|
|
64
|
+
type="button"
|
|
65
|
+
class="rounded-md border px-2 py-0.5 text-xs"
|
|
66
|
+
:class="hasFilter(header, false) ? 'border-fg-brand bg-brand-softer text-fg-brand' : 'border-default text-body'"
|
|
67
|
+
@click="toggleBooleanFilter(header, false)"
|
|
68
|
+
>No</button>
|
|
69
|
+
</div>
|
|
70
|
+
<div
|
|
71
|
+
class="flex max-h-36 flex-col gap-0.5 overflow-auto"
|
|
72
|
+
x-show="header.filter_kind === 'select' && header.options"
|
|
73
|
+
>
|
|
74
|
+
<template x-for="opt in (header.options || [])" :key="String(opt.value)">
|
|
75
|
+
<button
|
|
76
|
+
type="button"
|
|
77
|
+
class="rounded-md px-2 py-1 text-left text-xs hover:bg-surface-hover"
|
|
78
|
+
:class="hasFilter(header, opt.value) ? 'bg-brand-softer text-fg-brand' : 'text-body'"
|
|
79
|
+
@click="toggleSelectFilter(header, opt)"
|
|
80
|
+
x-text="opt.label"
|
|
81
|
+
></button>
|
|
82
|
+
</template>
|
|
83
|
+
</div>
|
|
84
|
+
</div>
|
|
81
85
|
</template>
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
86
|
+
<button
|
|
87
|
+
type="button"
|
|
88
|
+
class="mt-1 w-full rounded-md border border-default px-2 py-1 text-xs text-body hover:bg-surface-hover"
|
|
89
|
+
x-show="listFilters.length"
|
|
90
|
+
@click="clearListFilters()"
|
|
91
|
+
>Clear filters</button>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div class="shamar-m2m-table__add relative" x-show="!readonly">
|
|
96
|
+
<button
|
|
97
|
+
type="button"
|
|
98
|
+
class="inline-flex items-center gap-1 rounded-md border border-default bg-neutral-primary px-2.5 py-1 text-xs font-medium text-body hover:border-fg-brand hover:text-fg-brand"
|
|
99
|
+
@click="toggleAdd()"
|
|
100
|
+
>
|
|
101
|
+
<svg class="h-3.5 w-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" aria-hidden="true">
|
|
102
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4.5v15m7.5-7.5h-15"/>
|
|
103
|
+
</svg>
|
|
104
|
+
Add
|
|
105
|
+
</button>
|
|
106
|
+
<div
|
|
107
|
+
x-show="addOpen"
|
|
108
|
+
x-cloak
|
|
109
|
+
x-transition.opacity.duration.100ms
|
|
110
|
+
class="shamar-m2m-table__add-dropdown absolute right-0 z-50 mt-1 w-72 rounded-md border border-default bg-neutral-primary text-sm shadow-lg"
|
|
111
|
+
>
|
|
112
|
+
<div class="border-b border-default p-2">
|
|
113
|
+
<input
|
|
114
|
+
type="text"
|
|
115
|
+
x-ref="addInput"
|
|
116
|
+
x-model="query"
|
|
117
|
+
@input.debounce.250ms="fetchResults()"
|
|
118
|
+
@keydown.arrow-down.prevent="moveCursor(1)"
|
|
119
|
+
@keydown.arrow-up.prevent="moveCursor(-1)"
|
|
120
|
+
@keydown.enter.prevent="onEnter()"
|
|
121
|
+
placeholder="Search to add…"
|
|
122
|
+
autocomplete="off"
|
|
123
|
+
class="shamar-input w-full text-sm"
|
|
124
|
+
/>
|
|
125
|
+
</div>
|
|
126
|
+
<div class="max-h-56 overflow-auto">
|
|
127
|
+
<template x-if="loading">
|
|
128
|
+
<div class="px-3 py-2 text-xs text-body-subtle">Searching…</div>
|
|
129
|
+
</template>
|
|
130
|
+
<template x-if="!loading && availableResults.length === 0 && !createCandidate">
|
|
131
|
+
<div class="px-3 py-2 text-xs text-body-subtle">No matches.</div>
|
|
132
|
+
</template>
|
|
133
|
+
<ul x-show="!loading && (availableResults.length > 0 || createCandidate || canCreateAndEdit)">
|
|
134
|
+
<template x-for="(item, i) in availableResults" :key="item.id">
|
|
135
|
+
<li
|
|
136
|
+
class="cursor-pointer truncate px-3 py-1.5"
|
|
137
|
+
:class="i === cursor ? 'bg-brand-softer text-fg-brand' : 'text-body hover:bg-neutral-secondary'"
|
|
138
|
+
@mousedown.prevent="pick(item)"
|
|
139
|
+
@mousemove="cursor = i"
|
|
140
|
+
x-text="item.label"
|
|
141
|
+
></li>
|
|
142
|
+
</template>
|
|
143
|
+
<template x-if="createCandidate">
|
|
144
|
+
<li
|
|
145
|
+
class="flex cursor-pointer items-center gap-1.5 border-t border-default px-3 py-1.5 text-fg-success hover:bg-neutral-secondary"
|
|
146
|
+
@click="createFromQuery()"
|
|
147
|
+
>
|
|
148
|
+
<span>Create "<span x-text="query"></span>"</span>
|
|
149
|
+
</li>
|
|
150
|
+
</template>
|
|
151
|
+
<template x-if="canCreateAndEdit">
|
|
152
|
+
<li
|
|
153
|
+
class="flex cursor-pointer items-center gap-1.5 border-t border-default px-3 py-1.5 text-body hover:bg-neutral-secondary"
|
|
154
|
+
@click="createAndEdit()"
|
|
155
|
+
>
|
|
156
|
+
Create and edit…
|
|
157
|
+
</li>
|
|
158
|
+
</template>
|
|
159
|
+
</ul>
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
91
162
|
</div>
|
|
92
163
|
</div>
|
|
93
164
|
</div>
|
|
165
|
+
|
|
166
|
+
<div class="flex flex-wrap items-center gap-2" x-show="listUrl">
|
|
167
|
+
<input
|
|
168
|
+
type="search"
|
|
169
|
+
x-model="listSearch"
|
|
170
|
+
@input.debounce.300ms="applyListSearch()"
|
|
171
|
+
placeholder="Search…"
|
|
172
|
+
class="shamar-input max-w-xs flex-1 text-sm"
|
|
173
|
+
autocomplete="off"
|
|
174
|
+
/>
|
|
175
|
+
<template x-for="chip in listFilters" :key="chip.field + String(chip.value)">
|
|
176
|
+
<button
|
|
177
|
+
type="button"
|
|
178
|
+
class="inline-flex items-center gap-1 rounded-full border border-default bg-neutral-primary px-2 py-0.5 text-[11px] text-body hover:border-fg-danger hover:text-fg-danger"
|
|
179
|
+
@click="removeListFilter(chip)"
|
|
180
|
+
>
|
|
181
|
+
<span x-text="chip.label || chip.field"></span>
|
|
182
|
+
<span aria-hidden="true">×</span>
|
|
183
|
+
</button>
|
|
184
|
+
</template>
|
|
185
|
+
</div>
|
|
94
186
|
</div>
|
|
95
187
|
|
|
96
|
-
<
|
|
97
|
-
<
|
|
98
|
-
<
|
|
99
|
-
<
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
188
|
+
<div class="overflow-x-auto">
|
|
189
|
+
<table class="w-full text-sm">
|
|
190
|
+
<thead>
|
|
191
|
+
<tr class="border-b border-default text-left text-xs uppercase tracking-wider text-body-subtle">
|
|
192
|
+
<th class="px-3 py-2 font-semibold" x-show="!listUrl || !columns.length">Record</th>
|
|
193
|
+
<template x-for="column in columns" :key="column.name">
|
|
194
|
+
<th
|
|
195
|
+
class="px-3 py-2 font-semibold"
|
|
196
|
+
x-show="listUrl"
|
|
197
|
+
:class="[
|
|
198
|
+
column.alignmentClass || '',
|
|
199
|
+
column.sortable ? 'cursor-pointer select-none hover:text-fg-brand' : '',
|
|
200
|
+
]"
|
|
201
|
+
@click="column.sortable && toggleListSort(column.name)"
|
|
202
|
+
>
|
|
203
|
+
<span class="inline-flex items-center gap-1">
|
|
204
|
+
<span x-text="column.label"></span>
|
|
205
|
+
<span
|
|
206
|
+
x-show="listSort === column.name"
|
|
207
|
+
class="text-fg-brand"
|
|
208
|
+
x-text="listDirection === 'asc' ? '↑' : '↓'"
|
|
209
|
+
></span>
|
|
210
|
+
</span>
|
|
211
|
+
</th>
|
|
212
|
+
</template>
|
|
213
|
+
<th class="px-3 py-2 text-right font-semibold" x-show="!readonly">Actions</th>
|
|
107
214
|
</tr>
|
|
108
|
-
</
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
class="text-left text-heading hover:text-fg-brand hover:underline"
|
|
115
|
-
@click="openRecord(item)"
|
|
116
|
-
x-text="item.label"
|
|
117
|
-
></button>
|
|
215
|
+
</thead>
|
|
216
|
+
<tbody>
|
|
217
|
+
{{-- List mode --}}
|
|
218
|
+
<tr x-show="listUrl && listLoading">
|
|
219
|
+
<td :colspan="Math.max(columns.length, 1) + (readonly ? 0 : 1)" class="px-3 py-8 text-center text-xs text-body-subtle">
|
|
220
|
+
Loading…
|
|
118
221
|
</td>
|
|
119
|
-
|
|
120
|
-
|
|
222
|
+
</tr>
|
|
223
|
+
<tr x-show="listUrl && !listLoading && rows.length === 0">
|
|
224
|
+
<td :colspan="Math.max(columns.length, 1) + (readonly ? 0 : 1)" class="px-3 py-8 text-center text-xs text-body-subtle">
|
|
225
|
+
No linked records yet.
|
|
226
|
+
</td>
|
|
227
|
+
</tr>
|
|
228
|
+
<template x-for="row in rows" :key="row.id">
|
|
229
|
+
<tr
|
|
230
|
+
class="cursor-pointer border-b border-default last:border-0 hover:bg-surface-row-hover"
|
|
231
|
+
x-show="listUrl && !listLoading"
|
|
232
|
+
@click="openRecord(row)"
|
|
233
|
+
>
|
|
234
|
+
<template x-for="cell in row.cells" :key="row.id + ':' + cell.name">
|
|
235
|
+
<td class="px-3 py-2 text-body" :class="cellAlignment(cell.name)">
|
|
236
|
+
<span x-show="cell.boolean !== undefined" x-text="cell.boolean ? 'Yes' : 'No'"></span>
|
|
237
|
+
<div class="shamar-badges" x-show="cell.badges && cell.badges.length">
|
|
238
|
+
<template x-for="badge in (cell.badges || [])" :key="badge">
|
|
239
|
+
<span class="shamar-badge" x-text="badge"></span>
|
|
240
|
+
</template>
|
|
241
|
+
</div>
|
|
242
|
+
<a
|
|
243
|
+
x-show="cell.boolean === undefined && !(cell.badges && cell.badges.length) && cell.href"
|
|
244
|
+
:href="cell.href"
|
|
245
|
+
class="text-fg-brand hover:underline"
|
|
246
|
+
@click.stop
|
|
247
|
+
x-text="cell.text"
|
|
248
|
+
></a>
|
|
249
|
+
<span
|
|
250
|
+
class="text-heading"
|
|
251
|
+
x-show="cell.boolean === undefined && !(cell.badges && cell.badges.length) && !cell.href"
|
|
252
|
+
x-text="cell.text"
|
|
253
|
+
></span>
|
|
254
|
+
</td>
|
|
255
|
+
</template>
|
|
256
|
+
<td class="px-3 py-2 text-right" x-show="!readonly" @click.stop>
|
|
257
|
+
<div class="inline-flex items-center gap-1 text-xs">
|
|
258
|
+
<button
|
|
259
|
+
type="button"
|
|
260
|
+
class="rounded-md px-2 py-1 text-body hover:bg-surface-hover"
|
|
261
|
+
@click="openRecord(row)"
|
|
262
|
+
>Open</button>
|
|
263
|
+
<button
|
|
264
|
+
type="button"
|
|
265
|
+
class="rounded-md px-2 py-1 text-fg-danger hover:bg-danger-soft"
|
|
266
|
+
@click="remove(row.id)"
|
|
267
|
+
>Unlink</button>
|
|
268
|
+
</div>
|
|
269
|
+
</td>
|
|
270
|
+
</tr>
|
|
271
|
+
</template>
|
|
272
|
+
|
|
273
|
+
{{-- Legacy single-column mode --}}
|
|
274
|
+
<tr x-show="!listUrl && selected.length === 0">
|
|
275
|
+
<td colspan="2" class="px-3 py-8 text-center text-xs text-body-subtle">No linked records yet.</td>
|
|
276
|
+
</tr>
|
|
277
|
+
<template x-for="item in selected" :key="'legacy-' + item.id">
|
|
278
|
+
<tr class="border-b border-default last:border-0 hover:bg-surface-row-hover" x-show="!listUrl">
|
|
279
|
+
<td class="px-3 py-2">
|
|
121
280
|
<button
|
|
122
281
|
type="button"
|
|
123
|
-
class="
|
|
282
|
+
class="text-left text-heading hover:text-fg-brand hover:underline"
|
|
124
283
|
@click="openRecord(item)"
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
284
|
+
x-text="item.label"
|
|
285
|
+
></button>
|
|
286
|
+
</td>
|
|
287
|
+
<td class="px-3 py-2 text-right" x-show="!readonly">
|
|
288
|
+
<div class="inline-flex items-center gap-1 text-xs">
|
|
289
|
+
<button
|
|
290
|
+
type="button"
|
|
291
|
+
class="rounded-md px-2 py-1 text-body hover:bg-surface-hover"
|
|
292
|
+
@click="openRecord(item)"
|
|
293
|
+
>Open</button>
|
|
294
|
+
<button
|
|
295
|
+
type="button"
|
|
296
|
+
class="rounded-md px-2 py-1 text-fg-danger hover:bg-danger-soft"
|
|
297
|
+
@click="remove(item.id)"
|
|
298
|
+
>Unlink</button>
|
|
299
|
+
</div>
|
|
300
|
+
</td>
|
|
301
|
+
</tr>
|
|
302
|
+
</template>
|
|
303
|
+
</tbody>
|
|
304
|
+
</table>
|
|
305
|
+
</div>
|
|
306
|
+
|
|
307
|
+
<div
|
|
308
|
+
class="flex flex-wrap items-center justify-between gap-2 border-t border-default px-3 py-2 text-xs text-body-subtle"
|
|
309
|
+
x-show="listUrl && (pageCount > 1 || total > 0)"
|
|
310
|
+
>
|
|
311
|
+
<p>
|
|
312
|
+
Page <span x-text="page"></span> of <span x-text="pageCount"></span>
|
|
313
|
+
<span class="text-body-subtle">·</span>
|
|
314
|
+
<span x-text="total"></span> total
|
|
315
|
+
</p>
|
|
316
|
+
<div class="inline-flex items-center gap-1">
|
|
317
|
+
<button
|
|
318
|
+
type="button"
|
|
319
|
+
class="rounded-md border border-default px-2 py-1 hover:bg-surface-hover disabled:opacity-40"
|
|
320
|
+
:disabled="page <= 1 || listLoading"
|
|
321
|
+
@click="setListPage(page - 1)"
|
|
322
|
+
>Prev</button>
|
|
323
|
+
<button
|
|
324
|
+
type="button"
|
|
325
|
+
class="rounded-md border border-default px-2 py-1 hover:bg-surface-hover disabled:opacity-40"
|
|
326
|
+
:disabled="page >= pageCount || listLoading"
|
|
327
|
+
@click="setListPage(page + 1)"
|
|
328
|
+
>Next</button>
|
|
329
|
+
<select
|
|
330
|
+
class="shamar-input py-1 text-xs"
|
|
331
|
+
x-model="perPage"
|
|
332
|
+
@change="setListPage(1)"
|
|
333
|
+
>
|
|
334
|
+
<option value="5">5</option>
|
|
335
|
+
<option value="10">10</option>
|
|
336
|
+
<option value="25">25</option>
|
|
337
|
+
<option value="50">50</option>
|
|
338
|
+
</select>
|
|
339
|
+
</div>
|
|
340
|
+
</div>
|
|
137
341
|
</div>
|
|
138
342
|
</div>
|
|
139
343
|
@endif
|
|
@@ -1,5 +1,9 @@
|
|
|
1
|
-
<tr
|
|
2
|
-
|
|
1
|
+
<tr
|
|
2
|
+
class="hover:bg-surface-row-hover transition-colors cursor-pointer"
|
|
3
|
+
data-shamar-record-id="{{ record.id }}"
|
|
4
|
+
data-shamar-row-href="{{ basePath }}/{{ resource.slug }}/{{ record.id }}{{ recordNavQuery(query) }}"
|
|
5
|
+
>
|
|
6
|
+
<td class="px-3 py-3" data-shamar-stop-row-nav>
|
|
3
7
|
@if(bulkActions && bulkActions.length)
|
|
4
8
|
<input
|
|
5
9
|
type="checkbox"
|
|
@@ -29,11 +33,20 @@
|
|
|
29
33
|
—
|
|
30
34
|
@endif
|
|
31
35
|
@else
|
|
32
|
-
|
|
36
|
+
@let(relatedHref = relatedListLink(resource, record, column, basePath))
|
|
37
|
+
@if(relatedHref)
|
|
38
|
+
<a
|
|
39
|
+
href="{{ relatedHref }}"
|
|
40
|
+
data-shamar-stop-row-nav
|
|
41
|
+
class="text-fg-brand hover:underline"
|
|
42
|
+
>{{ cellValue(record, column) }}</a>
|
|
43
|
+
@else
|
|
44
|
+
<span class="text-heading">{{ cellValue(record, column) }}</span>
|
|
45
|
+
@endif
|
|
33
46
|
@endif
|
|
34
47
|
</td>
|
|
35
48
|
@endeach
|
|
36
|
-
<td class="px-4 py-3 text-right">
|
|
49
|
+
<td class="px-4 py-3 text-right" data-shamar-stop-row-nav>
|
|
37
50
|
<div class="inline-flex flex-wrap items-center justify-end gap-1 text-xs">
|
|
38
51
|
@if(rowActions)
|
|
39
52
|
@each(action in rowActions)
|
|
@@ -4,6 +4,10 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
6
|
<title>{{ pageTitle }} · {{ panelTitle }}</title>
|
|
7
|
+
@if(branding.fontPreconnect)
|
|
8
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
9
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
10
|
+
@endif
|
|
7
11
|
@if(branding.fontUrl)
|
|
8
12
|
<link rel="stylesheet" href="{{ branding.fontUrl }}" />
|
|
9
13
|
@endif
|
|
@@ -1,17 +1,62 @@
|
|
|
1
1
|
@let(mode = 'show')
|
|
2
|
-
@
|
|
2
|
+
@if(embed)
|
|
3
|
+
<div
|
|
4
|
+
class="space-y-4"
|
|
5
|
+
data-shamar-embed-detail
|
|
6
|
+
data-shamar-record-view="show"
|
|
7
|
+
>
|
|
8
|
+
@each(node in detailSchema)
|
|
9
|
+
@!component('shamar::partials/schema-node', {
|
|
10
|
+
node: node,
|
|
11
|
+
schemaMode: 'detail',
|
|
12
|
+
mode: mode,
|
|
13
|
+
record: record,
|
|
14
|
+
formErrors: formErrors,
|
|
15
|
+
relationUi: relationUi,
|
|
16
|
+
})
|
|
17
|
+
@endeach
|
|
3
18
|
|
|
4
|
-
<div class="
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
19
|
+
<div data-shamar-dialog-actions class="flex flex-wrap items-center justify-end gap-2 pt-2">
|
|
20
|
+
<button
|
|
21
|
+
type="button"
|
|
22
|
+
data-shamar-dialog-close
|
|
23
|
+
class="inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium border border-default text-body rounded-md hover:bg-surface-hover transition"
|
|
24
|
+
>Close</button>
|
|
25
|
+
@if(showEditButton)
|
|
26
|
+
<button
|
|
27
|
+
type="button"
|
|
28
|
+
class="inline-flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium text-white rounded-md bg-fg-brand hover:opacity-90 transition"
|
|
29
|
+
@click="$dispatch('shamar-open-dialog', {
|
|
30
|
+
url: {{ jsonAttr(`${basePath}/${resource.slug}/${record.id}/edit`) }},
|
|
31
|
+
title: {{ jsonAttr(`Edit ${pageTitle}`) }},
|
|
32
|
+
slug: {{ jsonAttr(resource.slug) }},
|
|
33
|
+
replace: true,
|
|
34
|
+
})"
|
|
35
|
+
>Edit</button>
|
|
36
|
+
@endif
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
@else
|
|
40
|
+
@include('shamar::partials/shell-open')
|
|
16
41
|
|
|
17
|
-
|
|
42
|
+
<div
|
|
43
|
+
class="mx-auto space-y-6 {{ contentMaxWidthClass || 'max-w-5xl' }}"
|
|
44
|
+
@if(contentMaxWidthStyle)
|
|
45
|
+
style="{{ contentMaxWidthStyle }}"
|
|
46
|
+
@endif
|
|
47
|
+
data-shamar-record-view="show"
|
|
48
|
+
>
|
|
49
|
+
@each(node in detailSchema)
|
|
50
|
+
@!component('shamar::partials/schema-node', {
|
|
51
|
+
node: node,
|
|
52
|
+
schemaMode: 'detail',
|
|
53
|
+
mode: mode,
|
|
54
|
+
record: record,
|
|
55
|
+
formErrors: formErrors,
|
|
56
|
+
relationUi: relationUi,
|
|
57
|
+
})
|
|
58
|
+
@endeach
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
@include('shamar::partials/shell-close')
|
|
62
|
+
@endif
|