@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.
Files changed (134) hide show
  1. package/assets/admin.css +2 -0
  2. package/assets/alpine.min.js +5 -0
  3. package/assets/input.css +2286 -0
  4. package/assets/shamar-ui.js +3658 -0
  5. package/dist/assets-controller.d.ts +12 -0
  6. package/dist/assets-controller.d.ts.map +1 -0
  7. package/dist/assets-controller.js +32 -0
  8. package/dist/assets-controller.js.map +1 -0
  9. package/dist/config.d.ts +79 -0
  10. package/dist/config.d.ts.map +1 -0
  11. package/dist/config.js +38 -0
  12. package/dist/config.js.map +1 -0
  13. package/dist/configure.d.ts +21 -0
  14. package/dist/configure.d.ts.map +1 -0
  15. package/dist/configure.js +20 -0
  16. package/dist/configure.js.map +1 -0
  17. package/dist/context.d.ts +22 -0
  18. package/dist/context.d.ts.map +1 -0
  19. package/dist/context.js +2 -0
  20. package/dist/context.js.map +1 -0
  21. package/dist/controller.d.ts +31 -0
  22. package/dist/controller.d.ts.map +1 -0
  23. package/dist/controller.js +45 -0
  24. package/dist/controller.js.map +1 -0
  25. package/dist/controllers/admin_controller.d.ts +72 -0
  26. package/dist/controllers/admin_controller.d.ts.map +1 -0
  27. package/dist/controllers/admin_controller.js +1075 -0
  28. package/dist/controllers/admin_controller.js.map +1 -0
  29. package/dist/discover.d.ts +7 -0
  30. package/dist/discover.d.ts.map +1 -0
  31. package/dist/discover.js +50 -0
  32. package/dist/discover.js.map +1 -0
  33. package/dist/form-state.d.ts +41 -0
  34. package/dist/form-state.d.ts.map +1 -0
  35. package/dist/form-state.js +74 -0
  36. package/dist/form-state.js.map +1 -0
  37. package/dist/index.d.ts +10 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +10 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/middleware/require_api_key_middleware.d.ts +30 -0
  42. package/dist/middleware/require_api_key_middleware.d.ts.map +1 -0
  43. package/dist/middleware/require_api_key_middleware.js +59 -0
  44. package/dist/middleware/require_api_key_middleware.js.map +1 -0
  45. package/dist/provider.d.ts +9 -0
  46. package/dist/provider.d.ts.map +1 -0
  47. package/dist/provider.js +66 -0
  48. package/dist/provider.js.map +1 -0
  49. package/dist/resources/api_key_resource.d.ts +35 -0
  50. package/dist/resources/api_key_resource.d.ts.map +1 -0
  51. package/dist/resources/api_key_resource.js +225 -0
  52. package/dist/resources/api_key_resource.js.map +1 -0
  53. package/dist/routes.d.ts +5 -0
  54. package/dist/routes.d.ts.map +1 -0
  55. package/dist/routes.js +97 -0
  56. package/dist/routes.js.map +1 -0
  57. package/dist/runtime.d.ts +27 -0
  58. package/dist/runtime.d.ts.map +1 -0
  59. package/dist/runtime.js +74 -0
  60. package/dist/runtime.js.map +1 -0
  61. package/dist/shamar/auth.d.ts +30 -0
  62. package/dist/shamar/auth.d.ts.map +1 -0
  63. package/dist/shamar/auth.js +218 -0
  64. package/dist/shamar/auth.js.map +1 -0
  65. package/dist/shamar/branding.d.ts +24 -0
  66. package/dist/shamar/branding.d.ts.map +1 -0
  67. package/dist/shamar/branding.js +91 -0
  68. package/dist/shamar/branding.js.map +1 -0
  69. package/dist/shamar/display-relations.d.ts +7 -0
  70. package/dist/shamar/display-relations.d.ts.map +1 -0
  71. package/dist/shamar/display-relations.js +89 -0
  72. package/dist/shamar/display-relations.js.map +1 -0
  73. package/dist/shamar/list-headers.d.ts +38 -0
  74. package/dist/shamar/list-headers.d.ts.map +1 -0
  75. package/dist/shamar/list-headers.js +218 -0
  76. package/dist/shamar/list-headers.js.map +1 -0
  77. package/dist/shamar/list-query.d.ts +229 -0
  78. package/dist/shamar/list-query.d.ts.map +1 -0
  79. package/dist/shamar/list-query.js +564 -0
  80. package/dist/shamar/list-query.js.map +1 -0
  81. package/dist/shamar/menu.d.ts +48 -0
  82. package/dist/shamar/menu.d.ts.map +1 -0
  83. package/dist/shamar/menu.js +93 -0
  84. package/dist/shamar/menu.js.map +1 -0
  85. package/dist/shamar/paths.d.ts +5 -0
  86. package/dist/shamar/paths.d.ts.map +1 -0
  87. package/dist/shamar/paths.js +16 -0
  88. package/dist/shamar/paths.js.map +1 -0
  89. package/dist/shamar/relation-fields.d.ts +54 -0
  90. package/dist/shamar/relation-fields.d.ts.map +1 -0
  91. package/dist/shamar/relation-fields.js +94 -0
  92. package/dist/shamar/relation-fields.js.map +1 -0
  93. package/dist/shamar/resource-actions.d.ts +9 -0
  94. package/dist/shamar/resource-actions.d.ts.map +1 -0
  95. package/dist/shamar/resource-actions.js +42 -0
  96. package/dist/shamar/resource-actions.js.map +1 -0
  97. package/dist/shamar/view-context.d.ts +79 -0
  98. package/dist/shamar/view-context.d.ts.map +1 -0
  99. package/dist/shamar/view-context.js +74 -0
  100. package/dist/shamar/view-context.js.map +1 -0
  101. package/dist/types.d.ts +15 -0
  102. package/dist/types.d.ts.map +1 -0
  103. package/dist/types.js +2 -0
  104. package/dist/types.js.map +1 -0
  105. package/package.json +67 -0
  106. package/resources/views/shamar/dashboard.edge +24 -0
  107. package/resources/views/shamar/form.edge +87 -0
  108. package/resources/views/shamar/index.edge +149 -0
  109. package/resources/views/shamar/partials/boolean-value.edge +25 -0
  110. package/resources/views/shamar/partials/csrf.edge +1 -0
  111. package/resources/views/shamar/partials/detail-entry.edge +72 -0
  112. package/resources/views/shamar/partials/dialog-host.edge +125 -0
  113. package/resources/views/shamar/partials/field-affix-icon.edge +23 -0
  114. package/resources/views/shamar/partials/field-input.edge +585 -0
  115. package/resources/views/shamar/partials/field-relation-checkbox.edge +104 -0
  116. package/resources/views/shamar/partials/field-relation-m2m.edge +110 -0
  117. package/resources/views/shamar/partials/field-relation-m2o.edge +116 -0
  118. package/resources/views/shamar/partials/field-relation-table.edge +139 -0
  119. package/resources/views/shamar/partials/form-container.edge +82 -0
  120. package/resources/views/shamar/partials/icon.edge +14 -0
  121. package/resources/views/shamar/partials/list-row.edge +73 -0
  122. package/resources/views/shamar/partials/list-toolbar.edge +269 -0
  123. package/resources/views/shamar/partials/nav-mobile.edge +21 -0
  124. package/resources/views/shamar/partials/nav.edge +58 -0
  125. package/resources/views/shamar/partials/page-heading.edge +130 -0
  126. package/resources/views/shamar/partials/pagination.edge +73 -0
  127. package/resources/views/shamar/partials/record-pager.edge +37 -0
  128. package/resources/views/shamar/partials/schema-node.edge +289 -0
  129. package/resources/views/shamar/partials/shell-close.edge +20 -0
  130. package/resources/views/shamar/partials/shell-open.edge +51 -0
  131. package/resources/views/shamar/partials/toast.edge +5 -0
  132. package/resources/views/shamar/partials/topbar.edge +115 -0
  133. package/resources/views/shamar/show.edge +17 -0
  134. 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