@shamar/adonis 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/admin.css +2 -0
- package/assets/alpine.min.js +5 -0
- package/assets/input.css +2286 -0
- package/assets/shamar-ui.js +3658 -0
- package/dist/assets-controller.d.ts +12 -0
- package/dist/assets-controller.d.ts.map +1 -0
- package/dist/assets-controller.js +32 -0
- package/dist/assets-controller.js.map +1 -0
- package/dist/config.d.ts +79 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +38 -0
- package/dist/config.js.map +1 -0
- package/dist/configure.d.ts +21 -0
- package/dist/configure.d.ts.map +1 -0
- package/dist/configure.js +20 -0
- package/dist/configure.js.map +1 -0
- package/dist/context.d.ts +22 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +2 -0
- package/dist/context.js.map +1 -0
- package/dist/controller.d.ts +31 -0
- package/dist/controller.d.ts.map +1 -0
- package/dist/controller.js +45 -0
- package/dist/controller.js.map +1 -0
- package/dist/controllers/admin_controller.d.ts +72 -0
- package/dist/controllers/admin_controller.d.ts.map +1 -0
- package/dist/controllers/admin_controller.js +1075 -0
- package/dist/controllers/admin_controller.js.map +1 -0
- package/dist/discover.d.ts +7 -0
- package/dist/discover.d.ts.map +1 -0
- package/dist/discover.js +50 -0
- package/dist/discover.js.map +1 -0
- package/dist/form-state.d.ts +41 -0
- package/dist/form-state.d.ts.map +1 -0
- package/dist/form-state.js +74 -0
- package/dist/form-state.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/require_api_key_middleware.d.ts +30 -0
- package/dist/middleware/require_api_key_middleware.d.ts.map +1 -0
- package/dist/middleware/require_api_key_middleware.js +59 -0
- package/dist/middleware/require_api_key_middleware.js.map +1 -0
- package/dist/provider.d.ts +9 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +66 -0
- package/dist/provider.js.map +1 -0
- package/dist/resources/api_key_resource.d.ts +35 -0
- package/dist/resources/api_key_resource.d.ts.map +1 -0
- package/dist/resources/api_key_resource.js +225 -0
- package/dist/resources/api_key_resource.js.map +1 -0
- package/dist/routes.d.ts +5 -0
- package/dist/routes.d.ts.map +1 -0
- package/dist/routes.js +97 -0
- package/dist/routes.js.map +1 -0
- package/dist/runtime.d.ts +27 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +74 -0
- package/dist/runtime.js.map +1 -0
- package/dist/shamar/auth.d.ts +30 -0
- package/dist/shamar/auth.d.ts.map +1 -0
- package/dist/shamar/auth.js +218 -0
- package/dist/shamar/auth.js.map +1 -0
- package/dist/shamar/branding.d.ts +24 -0
- package/dist/shamar/branding.d.ts.map +1 -0
- package/dist/shamar/branding.js +91 -0
- package/dist/shamar/branding.js.map +1 -0
- package/dist/shamar/display-relations.d.ts +7 -0
- package/dist/shamar/display-relations.d.ts.map +1 -0
- package/dist/shamar/display-relations.js +89 -0
- package/dist/shamar/display-relations.js.map +1 -0
- package/dist/shamar/list-headers.d.ts +38 -0
- package/dist/shamar/list-headers.d.ts.map +1 -0
- package/dist/shamar/list-headers.js +218 -0
- package/dist/shamar/list-headers.js.map +1 -0
- package/dist/shamar/list-query.d.ts +229 -0
- package/dist/shamar/list-query.d.ts.map +1 -0
- package/dist/shamar/list-query.js +564 -0
- package/dist/shamar/list-query.js.map +1 -0
- package/dist/shamar/menu.d.ts +48 -0
- package/dist/shamar/menu.d.ts.map +1 -0
- package/dist/shamar/menu.js +93 -0
- package/dist/shamar/menu.js.map +1 -0
- package/dist/shamar/paths.d.ts +5 -0
- package/dist/shamar/paths.d.ts.map +1 -0
- package/dist/shamar/paths.js +16 -0
- package/dist/shamar/paths.js.map +1 -0
- package/dist/shamar/relation-fields.d.ts +54 -0
- package/dist/shamar/relation-fields.d.ts.map +1 -0
- package/dist/shamar/relation-fields.js +94 -0
- package/dist/shamar/relation-fields.js.map +1 -0
- package/dist/shamar/resource-actions.d.ts +9 -0
- package/dist/shamar/resource-actions.d.ts.map +1 -0
- package/dist/shamar/resource-actions.js +42 -0
- package/dist/shamar/resource-actions.js.map +1 -0
- package/dist/shamar/view-context.d.ts +79 -0
- package/dist/shamar/view-context.d.ts.map +1 -0
- package/dist/shamar/view-context.js +74 -0
- package/dist/shamar/view-context.js.map +1 -0
- package/dist/types.d.ts +15 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +67 -0
- package/resources/views/shamar/dashboard.edge +24 -0
- package/resources/views/shamar/form.edge +87 -0
- package/resources/views/shamar/index.edge +149 -0
- package/resources/views/shamar/partials/boolean-value.edge +25 -0
- package/resources/views/shamar/partials/csrf.edge +1 -0
- package/resources/views/shamar/partials/detail-entry.edge +72 -0
- package/resources/views/shamar/partials/dialog-host.edge +125 -0
- package/resources/views/shamar/partials/field-affix-icon.edge +23 -0
- package/resources/views/shamar/partials/field-input.edge +585 -0
- package/resources/views/shamar/partials/field-relation-checkbox.edge +104 -0
- package/resources/views/shamar/partials/field-relation-m2m.edge +110 -0
- package/resources/views/shamar/partials/field-relation-m2o.edge +116 -0
- package/resources/views/shamar/partials/field-relation-table.edge +139 -0
- package/resources/views/shamar/partials/form-container.edge +82 -0
- package/resources/views/shamar/partials/icon.edge +14 -0
- package/resources/views/shamar/partials/list-row.edge +73 -0
- package/resources/views/shamar/partials/list-toolbar.edge +269 -0
- package/resources/views/shamar/partials/nav-mobile.edge +21 -0
- package/resources/views/shamar/partials/nav.edge +58 -0
- package/resources/views/shamar/partials/page-heading.edge +130 -0
- package/resources/views/shamar/partials/pagination.edge +73 -0
- package/resources/views/shamar/partials/record-pager.edge +37 -0
- package/resources/views/shamar/partials/schema-node.edge +289 -0
- package/resources/views/shamar/partials/shell-close.edge +20 -0
- package/resources/views/shamar/partials/shell-open.edge +51 -0
- package/resources/views/shamar/partials/toast.edge +5 -0
- package/resources/views/shamar/partials/topbar.edge +115 -0
- package/resources/views/shamar/show.edge +17 -0
- package/stubs/config/shamar.stub +29 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
@include('shamar::partials/shell-open')
|
|
2
|
+
|
|
3
|
+
<div class="grid gap-4 sm:grid-cols-2 xl:grid-cols-3">
|
|
4
|
+
@each(root in dashboardCards)
|
|
5
|
+
<a
|
|
6
|
+
href="{{ root.href }}"
|
|
7
|
+
class="group shamar-card rounded-xl p-5 transition hover:bg-surface-row-hover"
|
|
8
|
+
>
|
|
9
|
+
<div class="mb-3 flex items-center gap-2.5">
|
|
10
|
+
<span class="flex h-8 w-8 items-center justify-center rounded-lg bg-surface-inset text-fg-brand">
|
|
11
|
+
@include('shamar::partials/icon')
|
|
12
|
+
</span>
|
|
13
|
+
<h3 class="text-base font-semibold text-heading group-hover:text-fg-brand">{{ root.label }}</h3>
|
|
14
|
+
</div>
|
|
15
|
+
<p class="text-sm text-body-subtle">Open {{ root.label }}</p>
|
|
16
|
+
</a>
|
|
17
|
+
@else
|
|
18
|
+
<div class="shamar-card rounded-xl p-6 sm:col-span-2 xl:col-span-3">
|
|
19
|
+
<p class="text-sm text-body-subtle">No resources registered yet.</p>
|
|
20
|
+
</div>
|
|
21
|
+
@endeach
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
@include('shamar::partials/shell-close')
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
@if(embed)
|
|
2
|
+
<form
|
|
3
|
+
id="shamar-form"
|
|
4
|
+
data-shamar-embed-form
|
|
5
|
+
method="post"
|
|
6
|
+
action="{{ mode === 'create' ? `${basePath}/${resource.slug}` : `${basePath}/${resource.slug}/${record.id}` }}"
|
|
7
|
+
class="space-y-4"
|
|
8
|
+
x-data='shamarForm({
|
|
9
|
+
endpoint: {{ jsonAttr(formStateEndpoint) }},
|
|
10
|
+
operation: {{ jsonAttr(mode) }},
|
|
11
|
+
recordId: {{ jsonAttr(record ? record.id : null) }},
|
|
12
|
+
fields: {{ jsonAttr(formLiveFields) }},
|
|
13
|
+
state: {{ jsonAttr(formInitialState) }},
|
|
14
|
+
})'
|
|
15
|
+
>
|
|
16
|
+
@include('shamar::partials/csrf')
|
|
17
|
+
<input type="hidden" name="_shamar_embed" value="1" />
|
|
18
|
+
|
|
19
|
+
@each(node in formSchema)
|
|
20
|
+
@!component('shamar::partials/schema-node', {
|
|
21
|
+
node: node,
|
|
22
|
+
schemaMode: 'form',
|
|
23
|
+
mode: mode,
|
|
24
|
+
record: record,
|
|
25
|
+
formErrors: formErrors,
|
|
26
|
+
relationUi: relationUi,
|
|
27
|
+
})
|
|
28
|
+
@endeach
|
|
29
|
+
|
|
30
|
+
<div data-shamar-dialog-actions>
|
|
31
|
+
<button
|
|
32
|
+
type="button"
|
|
33
|
+
data-shamar-dialog-close
|
|
34
|
+
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"
|
|
35
|
+
>Cancel</button>
|
|
36
|
+
<button
|
|
37
|
+
type="submit"
|
|
38
|
+
form="shamar-form"
|
|
39
|
+
data-shamar-form-save
|
|
40
|
+
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"
|
|
41
|
+
>
|
|
42
|
+
{{ mode === 'create' ? 'Create' : 'Save' }}
|
|
43
|
+
</button>
|
|
44
|
+
</div>
|
|
45
|
+
</form>
|
|
46
|
+
@else
|
|
47
|
+
@include('shamar::partials/shell-open')
|
|
48
|
+
|
|
49
|
+
<div class="mx-auto max-w-5xl space-y-6" data-shamar-record-view="{{ mode }}">
|
|
50
|
+
<form
|
|
51
|
+
id="shamar-form"
|
|
52
|
+
method="post"
|
|
53
|
+
action="{{ mode === 'create' ? `${basePath}/${resource.slug}` : `${basePath}/${resource.slug}/${record.id}${recordPager ? recordPager.navQuery : ''}` }}"
|
|
54
|
+
class="space-y-6"
|
|
55
|
+
data-shamar-autosave="{{ mode === 'create' ? `${basePath}/${resource.slug}` : `${basePath}/${resource.slug}/${record.id}${recordPager ? recordPager.navQuery : ''}` }}"
|
|
56
|
+
data-shamar-save-mode="{{ mode }}"
|
|
57
|
+
@if(mode === 'create')
|
|
58
|
+
data-shamar-after-create="{{ basePath }}/{{ resource.slug }}"
|
|
59
|
+
@if(redirectAfterCreateToShow)
|
|
60
|
+
data-shamar-after-create-view="show"
|
|
61
|
+
@endif
|
|
62
|
+
@endif
|
|
63
|
+
x-data='shamarForm({
|
|
64
|
+
endpoint: {{ jsonAttr(formStateEndpoint) }},
|
|
65
|
+
operation: {{ jsonAttr(mode) }},
|
|
66
|
+
recordId: {{ jsonAttr(record ? record.id : null) }},
|
|
67
|
+
fields: {{ jsonAttr(formLiveFields) }},
|
|
68
|
+
state: {{ jsonAttr(formInitialState) }},
|
|
69
|
+
})'
|
|
70
|
+
>
|
|
71
|
+
@include('shamar::partials/csrf')
|
|
72
|
+
|
|
73
|
+
@each(node in formSchema)
|
|
74
|
+
@!component('shamar::partials/schema-node', {
|
|
75
|
+
node: node,
|
|
76
|
+
schemaMode: 'form',
|
|
77
|
+
mode: mode,
|
|
78
|
+
record: record,
|
|
79
|
+
formErrors: formErrors,
|
|
80
|
+
relationUi: relationUi,
|
|
81
|
+
})
|
|
82
|
+
@endeach
|
|
83
|
+
</form>
|
|
84
|
+
</div>
|
|
85
|
+
|
|
86
|
+
@include('shamar::partials/shell-close')
|
|
87
|
+
@endif
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
@include('shamar::partials/shell-open')
|
|
2
|
+
|
|
3
|
+
<section
|
|
4
|
+
class="space-y-4"
|
|
5
|
+
x-data="shamarListSelection()"
|
|
6
|
+
data-shamar-list-root="{{ resource.slug }}"
|
|
7
|
+
data-shamar-base-path="{{ basePath }}"
|
|
8
|
+
data-shamar-current-view="table"
|
|
9
|
+
data-shamar-total="{{ result.total }}"
|
|
10
|
+
data-shamar-search="{{ query.search ?? '' }}"
|
|
11
|
+
data-shamar-sort="{{ query.sort ?? '' }}"
|
|
12
|
+
data-shamar-direction="{{ query.direction ?? '' }}"
|
|
13
|
+
>
|
|
14
|
+
<div class="shamar-card rounded-xl overflow-hidden">
|
|
15
|
+
@include('shamar::partials/list-toolbar')
|
|
16
|
+
|
|
17
|
+
@if(bulkActions && bulkActions.length)
|
|
18
|
+
<div
|
|
19
|
+
x-show="selected.length || selectAllMatching"
|
|
20
|
+
x-cloak
|
|
21
|
+
class="shamar-bulk-bar"
|
|
22
|
+
@keydown.escape.window="if (bulkOpen) bulkOpen = false"
|
|
23
|
+
>
|
|
24
|
+
<div class="shamar-bulk-menu" @click.outside="bulkOpen = false">
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
class="shamar-bulk-menu__trigger"
|
|
28
|
+
:aria-expanded="bulkOpen.toString()"
|
|
29
|
+
aria-haspopup="menu"
|
|
30
|
+
@click="bulkOpen = !bulkOpen"
|
|
31
|
+
>
|
|
32
|
+
Bulk actions
|
|
33
|
+
<svg class="shamar-bulk-menu__chevron" :class="{ 'is-open': bulkOpen }" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" aria-hidden="true">
|
|
34
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 8.25l-7.5 7.5-7.5-7.5"/>
|
|
35
|
+
</svg>
|
|
36
|
+
</button>
|
|
37
|
+
<div
|
|
38
|
+
x-show="bulkOpen"
|
|
39
|
+
x-cloak
|
|
40
|
+
x-transition.opacity.duration.120ms
|
|
41
|
+
class="shamar-bulk-menu__panel"
|
|
42
|
+
role="menu"
|
|
43
|
+
aria-label="Bulk actions"
|
|
44
|
+
>
|
|
45
|
+
@each(action in bulkActions)
|
|
46
|
+
<button
|
|
47
|
+
type="button"
|
|
48
|
+
role="menuitem"
|
|
49
|
+
class="shamar-bulk-menu__item {{ action.color === 'danger' ? 'is-danger' : '' }}"
|
|
50
|
+
@click="bulkOpen = false; submitBulk({{ jsonAttr(`${basePath}/${resource.slug}/bulk`) }}, {{ jsonAttr(action.name) }}, {{ jsonAttr(action.confirm || '') }})"
|
|
51
|
+
>{{ action.label }}</button>
|
|
52
|
+
@endeach
|
|
53
|
+
</div>
|
|
54
|
+
</div>
|
|
55
|
+
|
|
56
|
+
<div class="shamar-bulk-bar__meta">
|
|
57
|
+
<span class="shamar-bulk-bar__count">
|
|
58
|
+
<span x-text="selectAllMatching ? total : selected.length"></span>
|
|
59
|
+
selected
|
|
60
|
+
</span>
|
|
61
|
+
<button
|
|
62
|
+
type="button"
|
|
63
|
+
class="shamar-bulk-bar__link"
|
|
64
|
+
x-show="pageFullySelected && !selectAllMatching && total > selected.length"
|
|
65
|
+
@click="selectAllInResultSet()"
|
|
66
|
+
>Select all <span x-text="total"></span></button>
|
|
67
|
+
<button
|
|
68
|
+
type="button"
|
|
69
|
+
class="shamar-bulk-bar__link"
|
|
70
|
+
@click="clearSelection(); bulkOpen = false"
|
|
71
|
+
>Clear</button>
|
|
72
|
+
</div>
|
|
73
|
+
</div>
|
|
74
|
+
@endif
|
|
75
|
+
|
|
76
|
+
<div class="overflow-x-auto">
|
|
77
|
+
<table class="w-full text-sm">
|
|
78
|
+
<thead class="bg-surface-header">
|
|
79
|
+
<tr>
|
|
80
|
+
<th class="w-9 px-3 py-3">
|
|
81
|
+
@if(bulkActions && bulkActions.length)
|
|
82
|
+
<input
|
|
83
|
+
type="checkbox"
|
|
84
|
+
class="rounded border-default"
|
|
85
|
+
:checked="pageFullySelected"
|
|
86
|
+
@change="toggleAll($event.target.checked)"
|
|
87
|
+
aria-label="Select all on page"
|
|
88
|
+
/>
|
|
89
|
+
@endif
|
|
90
|
+
</th>
|
|
91
|
+
@each(column in resource.columns)
|
|
92
|
+
<th class="px-4 py-3 text-xs font-semibold uppercase tracking-wider text-body-subtle whitespace-nowrap {{ resolveAlignmentClass(column) }}">
|
|
93
|
+
@if(column.sortable !== false)
|
|
94
|
+
<a
|
|
95
|
+
href="{{ sortColumnUrl(basePath, resource.slug, query, column.name) }}"
|
|
96
|
+
class="inline-flex items-center gap-1 hover:text-heading transition-colors {{ column.alignment === 'end' || column.alignment === 'right' ? 'justify-end w-full' : (column.alignment === 'center' ? 'justify-center w-full' : '') }}"
|
|
97
|
+
>
|
|
98
|
+
{{ column.label ?? humanizeLabel(column.name) }}
|
|
99
|
+
@if(query.sort === column.name)
|
|
100
|
+
<svg class="w-3 h-3 text-fg-brand {{ query.direction === 'desc' ? 'rotate-180' : '' }}" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2.5">
|
|
101
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 15.75l7.5-7.5 7.5 7.5"/>
|
|
102
|
+
</svg>
|
|
103
|
+
@endif
|
|
104
|
+
</a>
|
|
105
|
+
@else
|
|
106
|
+
{{ column.label ?? humanizeLabel(column.name) }}
|
|
107
|
+
@endif
|
|
108
|
+
</th>
|
|
109
|
+
@endeach
|
|
110
|
+
<th class="px-4 py-3 text-right text-xs font-semibold uppercase tracking-wider text-body-subtle">Actions</th>
|
|
111
|
+
</tr>
|
|
112
|
+
</thead>
|
|
113
|
+
<tbody>
|
|
114
|
+
@if(groups && groups.length)
|
|
115
|
+
@each(group in groups)
|
|
116
|
+
<tr class="shamar-list-group">
|
|
117
|
+
<td colspan="100" class="shamar-list-group__cell">
|
|
118
|
+
<span class="shamar-list-group__label">{{ group.label }}</span>
|
|
119
|
+
<span class="shamar-list-group__count">{{ group.items.length }}</span>
|
|
120
|
+
</td>
|
|
121
|
+
</tr>
|
|
122
|
+
@each(record in group.items)
|
|
123
|
+
@include('shamar::partials/list-row')
|
|
124
|
+
@endeach
|
|
125
|
+
@endeach
|
|
126
|
+
@elseif(result.items && result.items.length)
|
|
127
|
+
@each(record in result.items)
|
|
128
|
+
@include('shamar::partials/list-row')
|
|
129
|
+
@endeach
|
|
130
|
+
@else
|
|
131
|
+
<tr>
|
|
132
|
+
<td colspan="100" class="px-4 py-12 text-center text-body-subtle">No records found.</td>
|
|
133
|
+
</tr>
|
|
134
|
+
@endif
|
|
135
|
+
</tbody>
|
|
136
|
+
</table>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
|
|
140
|
+
@if(pagination)
|
|
141
|
+
<div data-shamar-list-pagination>
|
|
142
|
+
@include('shamar::partials/pagination')
|
|
143
|
+
</div>
|
|
144
|
+
@else
|
|
145
|
+
<div data-shamar-list-pagination hidden></div>
|
|
146
|
+
@endif
|
|
147
|
+
</section>
|
|
148
|
+
|
|
149
|
+
@include('shamar::partials/shell-close')
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{{--
|
|
2
|
+
Boolean / icon status chip for detail and table views.
|
|
3
|
+
Expects: checked (bool), label? (string), icon? / falseIcon? (optional glyphs)
|
|
4
|
+
--}}
|
|
5
|
+
@let(isOn = !!checked)
|
|
6
|
+
@let(customIcon = isOn ? icon : falseIcon)
|
|
7
|
+
@let(showLabel = label !== undefined && label !== null && String(label).length > 0)
|
|
8
|
+
<span class="shamar-boolean {{ isOn ? 'is-true' : 'is-false' }}{{ customIcon ? ' shamar-boolean--custom' : '' }}{{ showLabel ? '' : ' shamar-boolean--icon-only' }}">
|
|
9
|
+
<span class="shamar-boolean__mark" aria-hidden="true">
|
|
10
|
+
@if(customIcon)
|
|
11
|
+
<span class="shamar-boolean__glyph">{{ customIcon }}</span>
|
|
12
|
+
@elseif(isOn)
|
|
13
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" width="14" height="14">
|
|
14
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5" />
|
|
15
|
+
</svg>
|
|
16
|
+
@else
|
|
17
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.25" width="14" height="14">
|
|
18
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
|
|
19
|
+
</svg>
|
|
20
|
+
@endif
|
|
21
|
+
</span>
|
|
22
|
+
@if(showLabel)
|
|
23
|
+
<span class="shamar-boolean__label">{{ label }}</span>
|
|
24
|
+
@endif
|
|
25
|
+
</span>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<input type="hidden" name="_csrf" value="{{ csrfToken }}" />
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<div
|
|
2
|
+
class="shamar-detail-cell px-3 py-3 border-t border-card-border sm:border-t-0 sm:border-r sm:border-card-border last:border-r-0"
|
|
3
|
+
style="{{ resolveGridItemStyle(field, 2) }}"
|
|
4
|
+
>
|
|
5
|
+
<div class="shamar-detail__label-row">
|
|
6
|
+
<dt class="shamar-detail__label">{{ field.label ?? field.name }}</dt>
|
|
7
|
+
@if(field.hint)
|
|
8
|
+
<span class="shamar-field__hint">{{ field.hint }}</span>
|
|
9
|
+
@endif
|
|
10
|
+
</div>
|
|
11
|
+
<dd class="shamar-field__value mt-1 {{ alignmentTextClass(field.alignment) }}">
|
|
12
|
+
@if(field.type === 'icon' || field.type === 'boolean' || field.type === 'checkbox' || field.format === 'boolean' || field.format === 'toggle')
|
|
13
|
+
@!component('shamar::partials/boolean-value', {
|
|
14
|
+
checked: fieldChecked(record, field),
|
|
15
|
+
label: detailValue(record, field),
|
|
16
|
+
})
|
|
17
|
+
@elseif(field.type === 'color')
|
|
18
|
+
<span class="shamar-color-entry">
|
|
19
|
+
<span class="shamar-color-entry__swatch" style="background: {{ record[field.name] || '#ccc' }}"></span>
|
|
20
|
+
<span>{{ record[field.name] || '—' }}</span>
|
|
21
|
+
</span>
|
|
22
|
+
@elseif(field.type === 'image')
|
|
23
|
+
@if(record[field.name])
|
|
24
|
+
<img src="{{ record[field.name] }}" alt="{{ field.label ?? field.name }}" class="shamar-image-entry" />
|
|
25
|
+
@else
|
|
26
|
+
—
|
|
27
|
+
@endif
|
|
28
|
+
@elseif(field.format === 'badge' || field.type === 'tags')
|
|
29
|
+
@let(badges = badgeValues(record, field))
|
|
30
|
+
@if(badges.length)
|
|
31
|
+
<div class="shamar-badges">
|
|
32
|
+
@each(badge in badges)
|
|
33
|
+
<span class="shamar-badge">{{ badge }}</span>
|
|
34
|
+
@endeach
|
|
35
|
+
</div>
|
|
36
|
+
@else
|
|
37
|
+
—
|
|
38
|
+
@endif
|
|
39
|
+
@elseif(relationUi && relationUi[field.name] && relationUi[field.name].widget === 'checkboxList')
|
|
40
|
+
@!component('shamar::partials/field-relation-checkbox', {
|
|
41
|
+
field: field,
|
|
42
|
+
relationConfig: relationUi[field.name],
|
|
43
|
+
})
|
|
44
|
+
@elseif(field.copyable)
|
|
45
|
+
<span class="shamar-copyable" x-data>
|
|
46
|
+
<span>{{ detailValue(record, field) }}</span>
|
|
47
|
+
<button
|
|
48
|
+
type="button"
|
|
49
|
+
class="shamar-copyable__btn"
|
|
50
|
+
@click="navigator.clipboard.writeText({{ jsonAttr(String(record[field.name] ?? '')) }})"
|
|
51
|
+
>Copy</button>
|
|
52
|
+
</span>
|
|
53
|
+
@elseif(field.url || field.type === 'email')
|
|
54
|
+
@if(record[field.name])
|
|
55
|
+
@if(field.type === 'email')
|
|
56
|
+
<a href="mailto:{{ record[field.name] }}" class="text-fg-brand hover:underline">{{ detailValue(record, field) }}</a>
|
|
57
|
+
@elseif(field.url === true)
|
|
58
|
+
<a href="{{ record[field.name] }}" class="text-fg-brand hover:underline" target="_blank" rel="noopener">{{ detailValue(record, field) }}</a>
|
|
59
|
+
@else
|
|
60
|
+
<a href="{{ field.url }}" class="text-fg-brand hover:underline" target="_blank" rel="noopener">{{ detailValue(record, field) }}</a>
|
|
61
|
+
@endif
|
|
62
|
+
@else
|
|
63
|
+
—
|
|
64
|
+
@endif
|
|
65
|
+
@else
|
|
66
|
+
{{ detailValue(record, field) }}
|
|
67
|
+
@endif
|
|
68
|
+
</dd>
|
|
69
|
+
@if(field.help)
|
|
70
|
+
<p class="shamar-field__help">{{ field.help }}</p>
|
|
71
|
+
@endif
|
|
72
|
+
</div>
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
<div
|
|
2
|
+
x-data="shamarDialogHost()"
|
|
3
|
+
@shamar-open-dialog.window="openModal($event.detail)"
|
|
4
|
+
@shamar-open-confirm.window="openConfirm($event.detail)"
|
|
5
|
+
@keydown.escape.window="if (open && !confirmMode) dismissDialog()"
|
|
6
|
+
>
|
|
7
|
+
<div x-show="open" x-cloak style="display: none;">
|
|
8
|
+
<div class="shamar-dialog-backdrop" @click="dismissDialog()"></div>
|
|
9
|
+
|
|
10
|
+
<div
|
|
11
|
+
class="shamar-dialog-panel"
|
|
12
|
+
role="dialog"
|
|
13
|
+
aria-modal="true"
|
|
14
|
+
:aria-label="title"
|
|
15
|
+
:class="{ 'is-fullscreen': fullscreen, 'is-prompt': confirmMode }"
|
|
16
|
+
:style="panelStyle()"
|
|
17
|
+
@keydown.tab="trapFocus($event)"
|
|
18
|
+
x-ref="panel"
|
|
19
|
+
>
|
|
20
|
+
<div class="shamar-dialog-header" @mousedown="startDrag($event)">
|
|
21
|
+
<h2 class="min-w-0 flex-1 truncate text-sm font-semibold text-heading" id="shamar-dialog-title" x-text="title"></h2>
|
|
22
|
+
<div class="flex shrink-0 items-center gap-1">
|
|
23
|
+
<a
|
|
24
|
+
x-show="fullPageUrl"
|
|
25
|
+
:href="fullPageUrl"
|
|
26
|
+
class="rounded-md px-2 py-1 text-xs text-body-subtle hover:bg-surface-hover hover:text-heading"
|
|
27
|
+
>Open in full page</a>
|
|
28
|
+
<button
|
|
29
|
+
type="button"
|
|
30
|
+
class="rounded-md p-1.5 text-body-subtle hover:bg-surface-hover hover:text-heading"
|
|
31
|
+
x-show="!confirmMode"
|
|
32
|
+
@click="toggleFullscreen()"
|
|
33
|
+
:title="fullscreen ? 'Exit full screen' : 'Full screen'"
|
|
34
|
+
>
|
|
35
|
+
<svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" aria-hidden="true">
|
|
36
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 3.75v4.5m0-4.5h4.5m-4.5 0L9 9M3.75 20.25v-4.5m0 4.5h4.5m-4.5 0L9 15M20.25 3.75h-4.5m4.5 0v4.5m0-4.5L15 9m5.25 11.25h-4.5m4.5 0v-4.5m0 4.5L15 15"/>
|
|
37
|
+
</svg>
|
|
38
|
+
</button>
|
|
39
|
+
<button
|
|
40
|
+
type="button"
|
|
41
|
+
class="rounded-md p-1.5 text-body-subtle hover:bg-surface-hover hover:text-heading"
|
|
42
|
+
x-show="promptMode !== 'secret'"
|
|
43
|
+
@click="dismissDialog()"
|
|
44
|
+
title="Close"
|
|
45
|
+
aria-label="Close"
|
|
46
|
+
x-ref="closeBtn"
|
|
47
|
+
>×</button>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div class="shamar-dialog-body relative" :class="{ 'shamar-dialog-body--prompt': confirmMode }">
|
|
52
|
+
<div
|
|
53
|
+
x-show="loading"
|
|
54
|
+
class="absolute inset-0 z-10 flex items-center justify-center bg-neutral-primary/90 text-sm text-body-subtle"
|
|
55
|
+
>Loading…</div>
|
|
56
|
+
|
|
57
|
+
<div x-show="confirmMode && !loading" class="space-y-3">
|
|
58
|
+
<div class="flex items-start gap-3">
|
|
59
|
+
<div
|
|
60
|
+
class="shamar-dialog-prompt-icon"
|
|
61
|
+
:class="{
|
|
62
|
+
'is-danger': promptVariant === 'danger',
|
|
63
|
+
'is-warning': promptVariant === 'warning',
|
|
64
|
+
'is-info': promptVariant === 'info' || promptVariant === 'primary',
|
|
65
|
+
'is-success': promptVariant === 'success'
|
|
66
|
+
}"
|
|
67
|
+
aria-hidden="true"
|
|
68
|
+
>
|
|
69
|
+
<svg x-show="promptMode !== 'secret' && (promptVariant === 'danger' || promptVariant === 'warning')" class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
|
|
70
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 9v3.75m-9.303 3.376c-.866 1.5.217 3.374 1.948 3.374h14.71c1.73 0 2.813-1.874 1.948-3.374L13.949 3.378c-.866-1.5-3.032-1.5-3.898 0L2.697 16.126zM12 15.75h.007v.008H12v-.008z"/>
|
|
71
|
+
</svg>
|
|
72
|
+
<svg x-show="promptMode === 'secret'" class="h-5 w-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2">
|
|
73
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M15.75 5.25a3 3 0 013 3m3 0a6 6 0 01-7.029 5.912c-.563-.097-1.159.026-1.563.43L10.5 17.25H8.25v2.25H6v2.25H2.25v-2.818c0-.597.237-1.17.659-1.591l6.499-6.499c.404-.404.527-1 .43-1.563A6 6 0 1121.75 8.25z"/>
|
|
74
|
+
</svg>
|
|
75
|
+
</div>
|
|
76
|
+
<p class="text-sm text-body" x-text="confirmMessage"></p>
|
|
77
|
+
</div>
|
|
78
|
+
|
|
79
|
+
<div x-show="promptMode === 'secret' && secretText" class="shamar-secret-reveal">
|
|
80
|
+
<code class="shamar-secret-reveal__value" x-text="secretText"></code>
|
|
81
|
+
<button
|
|
82
|
+
type="button"
|
|
83
|
+
class="shamar-secret-reveal__copy"
|
|
84
|
+
@click="copySecret()"
|
|
85
|
+
x-text="secretCopied ? 'Copied' : 'Copy'"
|
|
86
|
+
>Copy</button>
|
|
87
|
+
</div>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<div x-show="!confirmMode">
|
|
91
|
+
<div data-shamar-dialog-body></div>
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div class="shamar-dialog-footer" x-show="confirmMode">
|
|
96
|
+
<button
|
|
97
|
+
type="button"
|
|
98
|
+
class="rounded-md px-4 py-2 text-sm hover:bg-surface-hover"
|
|
99
|
+
x-show="promptMode !== 'alert' && promptMode !== 'secret'"
|
|
100
|
+
@click="close()"
|
|
101
|
+
x-text="cancelLabel"
|
|
102
|
+
>Cancel</button>
|
|
103
|
+
<button
|
|
104
|
+
type="button"
|
|
105
|
+
class="rounded-md px-4 py-2 text-sm font-medium text-white hover:opacity-90"
|
|
106
|
+
:class="confirmButtonClass()"
|
|
107
|
+
@click="submitConfirm()"
|
|
108
|
+
x-text="confirmLabel"
|
|
109
|
+
>Confirm</button>
|
|
110
|
+
</div>
|
|
111
|
+
|
|
112
|
+
<div
|
|
113
|
+
class="shamar-dialog-footer"
|
|
114
|
+
x-show="!confirmMode && hasContentFooter"
|
|
115
|
+
data-shamar-dialog-footer
|
|
116
|
+
></div>
|
|
117
|
+
|
|
118
|
+
<div
|
|
119
|
+
class="shamar-dialog-resize-handle"
|
|
120
|
+
x-show="!confirmMode && !fullscreen"
|
|
121
|
+
@mousedown="startResize($event)"
|
|
122
|
+
></div>
|
|
123
|
+
</div>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{{-- Simple affix icon mark. Expects: icon (string slug). --}}
|
|
2
|
+
@if(icon === 'envelope' || icon === 'mail' || icon === 'email')
|
|
3
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" width="16" height="16">
|
|
4
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M21.75 6.75v10.5a2.25 2.25 0 01-2.25 2.25h-15a2.25 2.25 0 01-2.25-2.25V6.75m19.5 0A2.25 2.25 0 0019.5 4.5h-15a2.25 2.25 0 00-2.25 2.25m19.5 0v.243a2.25 2.25 0 01-1.07 1.916l-7.5 4.615a2.25 2.25 0 01-2.36 0L3.32 8.91a2.25 2.25 0 01-1.07-1.916V6.75" />
|
|
5
|
+
</svg>
|
|
6
|
+
@elseif(icon === 'phone' || icon === 'tel')
|
|
7
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" width="16" height="16">
|
|
8
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 6.75c0 8.284 6.716 15 15 15h2.25a2.25 2.25 0 002.25-2.25v-1.372c0-.516-.351-.966-.852-1.091l-4.423-1.106c-.44-.11-.902.055-1.173.417l-.97 1.293c-.282.376-.769.542-1.21.38a12.035 12.035 0 01-7.143-7.143c-.162-.441.004-.928.38-1.21l1.293-.97c.363-.271.527-.734.417-1.173L6.963 3.102a1.125 1.125 0 00-1.091-.852H4.5A2.25 2.25 0 002.25 4.5v2.25z" />
|
|
9
|
+
</svg>
|
|
10
|
+
@elseif(icon === 'globe' || icon === 'link' || icon === 'url')
|
|
11
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" width="16" height="16">
|
|
12
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M12 21a9.004 9.004 0 008.716-6.747M12 21a9.004 9.004 0 01-8.716-6.747M12 21c2.485 0 4.5-4.03 4.5-9S14.485 3 12 3m0 18c-2.485 0-4.5-4.03-4.5-9S9.515 3 12 3m0 0a8.997 8.997 0 017.843 4.582M12 3a8.997 8.997 0 00-7.843 4.582m15.686 0A11.953 11.953 0 0112 10.5c-2.998 0-5.74-1.1-7.843-2.918m15.686 0A8.959 8.959 0 0121 12c0 .778-.099 1.533-.284 2.253m0 0A17.919 17.919 0 0112 16.5c-3.162 0-6.133-.815-8.716-2.247m0 0A9.015 9.015 0 013 12c0-1.605.42-3.113 1.157-4.418" />
|
|
13
|
+
</svg>
|
|
14
|
+
@elseif(icon === 'lock' || icon === 'key')
|
|
15
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" width="16" height="16">
|
|
16
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M16.5 10.5V6.75a4.5 4.5 0 10-9 0v3.75m-.75 11.25h10.5a2.25 2.25 0 002.25-2.25v-6.75a2.25 2.25 0 00-2.25-2.25H6.75a2.25 2.25 0 00-2.25 2.25v6.75a2.25 2.25 0 002.25 2.25z" />
|
|
17
|
+
</svg>
|
|
18
|
+
@else
|
|
19
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" width="16" height="16">
|
|
20
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.37-.49l-1.296-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" />
|
|
21
|
+
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
|
|
22
|
+
</svg>
|
|
23
|
+
@endif
|