@7365admin1/layer-common 3.2.2-staging.118 → 3.2.2-staging.121
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/css/primitives.css +168 -0
- package/assets/css/screens.css +76 -1
- package/components/AccessCard/AvailableStats.vue +24 -16
- package/components/AddPassKeyToVisitor.vue +95 -73
- package/components/AppDateField.vue +15 -1
- package/components/AppField.vue +25 -0
- package/components/BuildingUnitFormEdit.vue +5 -1
- package/components/Card/DeleteConfirmation.vue +5 -2
- package/components/HidAccessLogDashboard.vue +288 -447
- package/components/HidIntercomManagement.vue +387 -521
- package/components/HidQrCodeConfiguration.vue +293 -369
- package/components/HidReaderManagement.vue +197 -320
- package/components/HidServiceSettingsPanel.vue +38 -26
- package/components/HidUserEnrollment.vue +239 -344
- package/components/IncidentReport/Authorities.vue +30 -18
- package/components/Nfc/NFCTagForm.vue +5 -1
- package/components/ScanVisitorQRCode.vue +64 -28
- package/components/SearchVehicleNumberUser.vue +39 -37
- package/components/TableMain.vue +50 -1
- package/components/VehicleAddSelection.vue +48 -32
- package/components/VehicleForm.vue +112 -129
- package/components/VehicleUpdateMoreAction.vue +59 -46
- package/components/VisitorDataFromScannedQRCodeForm.vue +90 -65
- package/components/VisitorFormSelection.vue +40 -37
- package/components/VisitorPassKeyQRScanner.vue +65 -18
- package/components/VisitorSocketPopUp.vue +21 -13
- package/components/VisitorsReportPreview.vue +44 -29
- package/package.json +1 -1
- package/tools/render-harness/baselines.json +95 -0
- package/tools/render-harness/harness-init.ps1 +4 -0
- package/utils/status.test.ts +33 -0
- package/utils/status.ts +36 -0
- package/utils/theme-aa-ledger.ts +142 -0
- package/utils/theme.test.ts +95 -34
- package/utils/theme.ts +55 -28
|
@@ -1,53 +1,28 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
HID USER ENROLLMENT - the people a reader will recognise.
|
|
3
|
+
|
|
4
|
+
Was a bespoke screen: an above-card toolbar, a raw `v-table` with six fixed
|
|
5
|
+
column widths, its own refresh strip, footer pager, empty state and three
|
|
6
|
+
private `status-*` chip palettes - about twenty-six literal hexes. Those
|
|
7
|
+
literals are why the screen had no dark theme; `#0a2638` on the dark card
|
|
8
|
+
measures 1.07:1.
|
|
9
|
+
|
|
10
|
+
It is the design's standard table screen, so it is drawn with the shared one:
|
|
11
|
+
`TableMain` supplies the page heading, the card, the in-card toolbar, the
|
|
12
|
+
uppercase header row, the row spec and the pager; the reader picker, search
|
|
13
|
+
and status filter move onto the card's `extension` row. Every column, action,
|
|
14
|
+
dialog and handler is unchanged - the same `users` still feed it and the
|
|
15
|
+
overflow menu still opens the same three dialogs.
|
|
16
|
+
|
|
17
|
+
The handoff draws no HID table, so it states no column proportions - the
|
|
18
|
+
table takes `TableMain`'s automatic layout, as panel 2 does, and the screen's
|
|
19
|
+
own fixed 24/20/12/20/16/8 % are dropped rather than carried over.
|
|
20
|
+
-->
|
|
1
21
|
<template>
|
|
2
22
|
<section class="hid-user-enrollment">
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class="text-none enroll-button"
|
|
7
|
-
variant="flat"
|
|
8
|
-
prepend-icon="mdi-account-plus"
|
|
9
|
-
@click="openEnroll"
|
|
10
|
-
>
|
|
11
|
-
Enroll
|
|
12
|
-
</v-btn>
|
|
13
|
-
|
|
14
|
-
<v-select
|
|
15
|
-
v-if="readers.length"
|
|
16
|
-
v-model="selectedReaderId"
|
|
17
|
-
:items="readerOptions"
|
|
18
|
-
item-title="title"
|
|
19
|
-
item-value="value"
|
|
20
|
-
variant="outlined"
|
|
21
|
-
density="compact"
|
|
22
|
-
hide-details
|
|
23
|
-
class="reader-input"
|
|
24
|
-
@update:model-value="loadUsers"
|
|
25
|
-
/>
|
|
26
|
-
|
|
27
|
-
<div class="toolbar-spacer" />
|
|
28
|
-
|
|
29
|
-
<v-text-field
|
|
30
|
-
v-model="search"
|
|
31
|
-
placeholder="Search"
|
|
32
|
-
variant="outlined"
|
|
33
|
-
density="compact"
|
|
34
|
-
hide-details
|
|
35
|
-
class="search-input"
|
|
36
|
-
prepend-inner-icon="mdi-magnify"
|
|
37
|
-
@keyup.enter="loadUsers"
|
|
38
|
-
/>
|
|
39
|
-
|
|
40
|
-
<v-select
|
|
41
|
-
v-model="status"
|
|
42
|
-
:items="statusOptions"
|
|
43
|
-
variant="outlined"
|
|
44
|
-
density="compact"
|
|
45
|
-
hide-details
|
|
46
|
-
class="status-input"
|
|
47
|
-
@update:model-value="loadUsers"
|
|
48
|
-
/>
|
|
49
|
-
</div>
|
|
50
|
-
|
|
23
|
+
<!-- Staging's portal banner (1e6224e), kept whole: it names the portal the
|
|
24
|
+
selected reader is bound to and warns when it has none. It sat above
|
|
25
|
+
the old table card, so it stays above the shared one. -->
|
|
51
26
|
<v-alert
|
|
52
27
|
v-if="selectedReader"
|
|
53
28
|
:type="selectedReader.portalId && selectedReader.portalName ? 'info' : 'warning'"
|
|
@@ -60,112 +35,106 @@
|
|
|
60
35
|
{{ selectedReader.portalName || "Not configured" }}
|
|
61
36
|
</v-alert>
|
|
62
37
|
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
38
|
+
<TableMain
|
|
39
|
+
title="HID Users"
|
|
40
|
+
:headers="userHeaders"
|
|
41
|
+
:items="users"
|
|
42
|
+
:loading="loading"
|
|
43
|
+
:items-per-page="-1"
|
|
44
|
+
:page="page"
|
|
45
|
+
:pages="pages"
|
|
46
|
+
:page-range="pageRange"
|
|
47
|
+
item-value="_rowKey"
|
|
48
|
+
show-header
|
|
49
|
+
@refresh="loadUsers"
|
|
50
|
+
@update:page="goToPage"
|
|
51
|
+
>
|
|
52
|
+
<template #actions>
|
|
53
|
+
<AppButton icon="mdi-account-plus" @click="openEnroll">Enroll</AppButton>
|
|
54
|
+
</template>
|
|
55
|
+
|
|
56
|
+
<!-- The design puts filters on their own full-width row under the
|
|
57
|
+
toolbar, which is what `extension` is. -->
|
|
58
|
+
<template #extension>
|
|
59
|
+
<div class="app-filter-row hid-user-filters">
|
|
60
|
+
<AppSelect
|
|
61
|
+
v-if="readers.length"
|
|
62
|
+
v-model="selectedReaderId"
|
|
63
|
+
class="reader-select"
|
|
64
|
+
:items="readerOptions"
|
|
65
|
+
@update:model-value="loadUsers"
|
|
66
|
+
/>
|
|
67
|
+
<AppField
|
|
68
|
+
v-model="search"
|
|
69
|
+
search
|
|
70
|
+
placeholder="Search"
|
|
71
|
+
@keyup.enter="loadUsers"
|
|
72
|
+
/>
|
|
73
|
+
<AppSelect
|
|
74
|
+
v-model="status"
|
|
75
|
+
:items="statusOptions"
|
|
76
|
+
@update:model-value="loadUsers"
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
</template>
|
|
80
|
+
|
|
81
|
+
<template #[`item.name`]="{ item }">
|
|
82
|
+
<span class="app-cell--strong">{{ getName(item) }}</span>
|
|
83
|
+
</template>
|
|
84
|
+
|
|
85
|
+
<!-- The face thumbnail, unchanged. It prints whatever `getUserImageSrc`
|
|
86
|
+
already returned; this screen does not read or export a template. -->
|
|
87
|
+
<template #[`item.facialData`]="{ item }">
|
|
88
|
+
<v-avatar
|
|
89
|
+
v-if="getUserImageSrc(item)"
|
|
90
|
+
size="34"
|
|
91
|
+
rounded="lg"
|
|
92
|
+
class="hid-face-avatar"
|
|
93
|
+
>
|
|
94
|
+
<v-img :src="getUserImageSrc(item)" cover />
|
|
95
|
+
</v-avatar>
|
|
96
|
+
<span v-else class="app-cell--muted">{{ getFacialData(item) }}</span>
|
|
97
|
+
</template>
|
|
98
|
+
|
|
99
|
+
<template #[`item.hidUserId`]="{ item }">
|
|
100
|
+
<span class="app-cell--num">{{ formatHidUid(item.hidUserId) || "N/A" }}</span>
|
|
101
|
+
</template>
|
|
102
|
+
|
|
103
|
+
<!-- The shared chip. `utils/status.ts` now carries Mapped/Unmapped with
|
|
104
|
+
the same tones this screen's private `getMappingStatusClass` gave
|
|
105
|
+
them, so the map is one list rather than a fourth private copy. -->
|
|
106
|
+
<template #[`item.status`]="{ item }">
|
|
107
|
+
<StatusChip :status="getMappingStatus(item)" />
|
|
108
|
+
</template>
|
|
109
|
+
|
|
110
|
+
<template #[`item.action-table`]="{ item }">
|
|
111
|
+
<v-menu>
|
|
112
|
+
<template #activator="{ props: menuProps }">
|
|
113
|
+
<AppButton v-bind="menuProps" variant="row" icon="mdi-dots-vertical" />
|
|
114
|
+
</template>
|
|
115
|
+
|
|
116
|
+
<v-list density="compact" min-width="150">
|
|
117
|
+
<v-list-item title="View" @click="openView(item)" />
|
|
118
|
+
<v-list-item title="Edit" @click="openEdit(item)" />
|
|
119
|
+
<v-list-item
|
|
120
|
+
title="Delete"
|
|
121
|
+
class="text-error"
|
|
122
|
+
@click="openDelete(item)"
|
|
123
|
+
/>
|
|
124
|
+
</v-list>
|
|
125
|
+
</v-menu>
|
|
126
|
+
</template>
|
|
127
|
+
|
|
128
|
+
<!-- The screen's own sentence, kept: the shared empty state says "No data
|
|
129
|
+
available", which is less useful on a screen whose whole point is
|
|
130
|
+
that nobody has been enrolled yet. -->
|
|
131
|
+
<template #no-data>
|
|
132
|
+
<div class="table-card__empty">
|
|
133
|
+
<v-icon icon="mdi-account-off-outline" size="32" />
|
|
134
|
+
<span>No HID users enrolled yet.</span>
|
|
142
135
|
</div>
|
|
143
|
-
</
|
|
144
|
-
|
|
145
|
-
<div class="table-footer">
|
|
146
|
-
<span>{{ pageRange }}</span>
|
|
147
|
-
<v-btn
|
|
148
|
-
icon="mdi-chevron-left"
|
|
149
|
-
variant="text"
|
|
150
|
-
density="comfortable"
|
|
151
|
-
:disabled="page <= 1"
|
|
152
|
-
@click="
|
|
153
|
-
page--;
|
|
154
|
-
loadUsers();
|
|
155
|
-
"
|
|
156
|
-
/>
|
|
157
|
-
<v-btn
|
|
158
|
-
icon="mdi-chevron-right"
|
|
159
|
-
variant="text"
|
|
160
|
-
density="comfortable"
|
|
161
|
-
:disabled="page >= pages"
|
|
162
|
-
@click="
|
|
163
|
-
page++;
|
|
164
|
-
loadUsers();
|
|
165
|
-
"
|
|
166
|
-
/>
|
|
167
|
-
</div>
|
|
168
|
-
</v-card>
|
|
136
|
+
</template>
|
|
137
|
+
</TableMain>
|
|
169
138
|
|
|
170
139
|
<v-dialog v-model="formDialog" max-width="420" persistent>
|
|
171
140
|
<v-card rounded="lg">
|
|
@@ -188,7 +157,9 @@
|
|
|
188
157
|
<v-icon icon="mdi-pencil" size="16" />
|
|
189
158
|
</span>
|
|
190
159
|
<template v-else>
|
|
191
|
-
|
|
160
|
+
<!-- Was `color="#a4acb5"`, the same grey on both themes.
|
|
161
|
+
`.photo-button` already sets `--muted`, so it inherits. -->
|
|
162
|
+
<v-icon icon="mdi-account-plus" size="40" />
|
|
192
163
|
<span>Add Photo</span>
|
|
193
164
|
</template>
|
|
194
165
|
</button>
|
|
@@ -217,55 +188,57 @@
|
|
|
217
188
|
</div>
|
|
218
189
|
|
|
219
190
|
<div class="field-label">Name <span>*</span></div>
|
|
220
|
-
<
|
|
191
|
+
<AppField
|
|
221
192
|
v-model="form.name"
|
|
222
193
|
aria-label="Name"
|
|
223
194
|
placeholder="Enter name"
|
|
224
|
-
|
|
225
|
-
variant="outlined"
|
|
226
|
-
hide-details="auto"
|
|
227
|
-
class="mb-3"
|
|
195
|
+
klass="mb-3"
|
|
228
196
|
/>
|
|
229
197
|
|
|
230
198
|
<div class="field-label">ID</div>
|
|
231
|
-
<v-
|
|
232
|
-
v-model="form.hidUserId"
|
|
233
|
-
aria-label="ID"
|
|
234
|
-
density="compact"
|
|
235
|
-
variant="outlined"
|
|
236
|
-
hide-details="auto"
|
|
237
|
-
readonly
|
|
238
|
-
class="mb-3"
|
|
239
|
-
/>
|
|
199
|
+
<AppField v-model="form.hidUserId" aria-label="ID" readonly klass="mb-3" />
|
|
240
200
|
|
|
241
201
|
<div class="field-label">Registration No. <span>*</span></div>
|
|
242
|
-
<
|
|
202
|
+
<AppField
|
|
243
203
|
v-model="form.registration"
|
|
244
204
|
aria-label="Registration No."
|
|
245
205
|
placeholder="Enter registration no."
|
|
246
|
-
density="compact"
|
|
247
|
-
variant="outlined"
|
|
248
|
-
hide-details="auto"
|
|
249
206
|
:readonly="!selectedUser"
|
|
250
|
-
|
|
207
|
+
klass="mb-3"
|
|
251
208
|
/>
|
|
252
209
|
|
|
253
210
|
<div class="field-label">Access PIN (optional)</div>
|
|
254
|
-
|
|
211
|
+
<!--
|
|
212
|
+
The handoff draws no password field anywhere (the sign-in screens
|
|
213
|
+
are the owner's own), so the reveal toggle is this product's, not
|
|
214
|
+
the design's. It goes in `AppField`'s `trailing` slot so the eye
|
|
215
|
+
sits INSIDE the 40px box as it did inside the Vuetify field, rather
|
|
216
|
+
than becoming a second control beside it.
|
|
217
|
+
-->
|
|
218
|
+
<AppField
|
|
255
219
|
v-model="form.accessPin"
|
|
256
220
|
aria-label="Access PIN"
|
|
257
221
|
placeholder="Enter numeric access PIN"
|
|
258
|
-
density="compact"
|
|
259
|
-
variant="outlined"
|
|
260
222
|
inputmode="numeric"
|
|
261
223
|
autocomplete="new-password"
|
|
262
224
|
:type="showPin ? 'text' : 'password'"
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
225
|
+
>
|
|
226
|
+
<template #trailing>
|
|
227
|
+
<button
|
|
228
|
+
type="button"
|
|
229
|
+
class="app-field__trailing"
|
|
230
|
+
:aria-label="showPin ? 'Hide access PIN' : 'Show access PIN'"
|
|
231
|
+
@click="showPin = !showPin"
|
|
232
|
+
>
|
|
233
|
+
<v-icon :icon="showPin ? 'mdi-eye-off' : 'mdi-eye'" size="18" />
|
|
234
|
+
</button>
|
|
235
|
+
</template>
|
|
236
|
+
</AppField>
|
|
237
|
+
<!-- `persistent-hint` was Vuetify's; the design's settings module
|
|
238
|
+
draws an explanatory line as 12-13px/600 in `--muted`. -->
|
|
239
|
+
<p class="field-hint">
|
|
240
|
+
{{ selectedUser && pinEnrolled ? "Leave blank to keep the current PIN." : "PIN works as an alternative to face or QR." }}
|
|
241
|
+
</p>
|
|
269
242
|
<v-checkbox
|
|
270
243
|
v-if="selectedUser && pinEnrolled"
|
|
271
244
|
v-model="removePinRequested"
|
|
@@ -275,6 +248,9 @@
|
|
|
275
248
|
/>
|
|
276
249
|
</v-card-text>
|
|
277
250
|
|
|
251
|
+
<!-- The split footer bar, as panel 2 keeps it: `v-btn` because it needs
|
|
252
|
+
`:loading` and a full-bleed shape the handoff does not draw. Only
|
|
253
|
+
the colours change - they were fixed hexes on both themes. -->
|
|
278
254
|
<v-card-actions class="pa-0">
|
|
279
255
|
<v-btn
|
|
280
256
|
class="text-none action-cancel"
|
|
@@ -324,9 +300,7 @@
|
|
|
324
300
|
</v-card-text>
|
|
325
301
|
<v-card-actions>
|
|
326
302
|
<v-spacer />
|
|
327
|
-
<
|
|
328
|
-
>Close</v-btn
|
|
329
|
-
>
|
|
303
|
+
<AppButton variant="ghost" @click="viewDialog = false">Close</AppButton>
|
|
330
304
|
</v-card-actions>
|
|
331
305
|
</v-card>
|
|
332
306
|
</v-dialog>
|
|
@@ -439,6 +413,30 @@ const form = reactive({
|
|
|
439
413
|
|
|
440
414
|
const statusOptions = ["Status", "Mapped", "Unmapped"];
|
|
441
415
|
|
|
416
|
+
/**
|
|
417
|
+
* `sortable: false` keeps the previous behaviour - the raw `v-table` never
|
|
418
|
+
* sorted - and no `weight` is set, so the table uses `TableMain`'s automatic
|
|
419
|
+
* layout. The handoff draws no HID table, so the screen's own fixed
|
|
420
|
+
* 24/20/12/20/16/8 % were a guess with no design number behind them.
|
|
421
|
+
*/
|
|
422
|
+
const userHeaders = [
|
|
423
|
+
{ title: "Name", value: "name", sortable: false },
|
|
424
|
+
{ title: "Facial Data", value: "facialData", sortable: false },
|
|
425
|
+
{ title: "UID", value: "hidUserId", sortable: false },
|
|
426
|
+
{ title: "Status", value: "status", sortable: false },
|
|
427
|
+
{ title: "", value: "action-table", sortable: false },
|
|
428
|
+
];
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* The list is paged on the SERVER, so the shared pager only moves the cursor -
|
|
432
|
+
* the rows still come from `loadUsers`. This is the same pair of statements
|
|
433
|
+
* the old footer's two chevrons ran.
|
|
434
|
+
*/
|
|
435
|
+
function goToPage(next: number) {
|
|
436
|
+
page.value = next;
|
|
437
|
+
loadUsers();
|
|
438
|
+
}
|
|
439
|
+
|
|
442
440
|
const readerOptions = computed(() =>
|
|
443
441
|
readers.value.map((reader) => ({
|
|
444
442
|
title: `${reader.name || reader.deviceId || reader._id} — ${reader.portalName || "Portal not configured"}`,
|
|
@@ -1316,10 +1314,6 @@ function getMappingStatus(user: Record<string, any>) {
|
|
|
1316
1314
|
return hasMappedRecord(user) ? "Mapped" : "Unmapped";
|
|
1317
1315
|
}
|
|
1318
1316
|
|
|
1319
|
-
function getMappingStatusClass(user: Record<string, any>) {
|
|
1320
|
-
return hasMappedRecord(user) ? "status-success" : "status-warning";
|
|
1321
|
-
}
|
|
1322
|
-
|
|
1323
1317
|
function hasMappedRecord(user: Record<string, any>) {
|
|
1324
1318
|
return Boolean(user?.person || user?.user || user?.member || user?.visitor);
|
|
1325
1319
|
}
|
|
@@ -1368,154 +1362,64 @@ function getHidErrorMessage(error: any) {
|
|
|
1368
1362
|
</script>
|
|
1369
1363
|
|
|
1370
1364
|
<style scoped>
|
|
1365
|
+
/*
|
|
1366
|
+
WHAT IS LEFT AFTER THE CARD AND TABLE MOVED TO `TableMain`.
|
|
1367
|
+
|
|
1368
|
+
The toolbar, the card, the six fixed column widths, the refresh strip, the
|
|
1369
|
+
footer pager, the empty state and the three `status-*` chip palettes are all
|
|
1370
|
+
gone - they were a private copy of the shared table drawn in literal hexes.
|
|
1371
|
+
What remains is the three dialogs, and every colour in them is now a token,
|
|
1372
|
+
so the dark theme reaches them for the first time.
|
|
1373
|
+
*/
|
|
1371
1374
|
.hid-user-enrollment {
|
|
1372
1375
|
padding: 24px 0;
|
|
1373
1376
|
width: 100%;
|
|
1374
1377
|
min-width: 0;
|
|
1375
1378
|
}
|
|
1376
1379
|
|
|
1377
|
-
.
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
margin-bottom: 16px;
|
|
1380
|
+
.hid-user-filters {
|
|
1381
|
+
/* The filter row sits INSIDE the card's extension, so it needs the card's
|
|
1382
|
+
own side padding rather than the row's default bottom margin. */
|
|
1383
|
+
margin: 0;
|
|
1384
|
+
padding: 10px 14px;
|
|
1383
1385
|
}
|
|
1384
1386
|
|
|
1385
|
-
.
|
|
1386
|
-
flex: 1;
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
.enroll-button {
|
|
1390
|
-
min-width: 170px;
|
|
1391
|
-
background: #e4e4e4;
|
|
1392
|
-
color: #0a2638;
|
|
1393
|
-
}
|
|
1394
|
-
|
|
1395
|
-
.reader-input,
|
|
1396
|
-
.search-input {
|
|
1387
|
+
.hid-user-filters :deep(.app-field) {
|
|
1397
1388
|
max-width: 240px;
|
|
1398
1389
|
}
|
|
1399
1390
|
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
display: flex;
|
|
1406
|
-
flex-direction: column;
|
|
1407
|
-
min-height: 430px;
|
|
1408
|
-
overflow: hidden;
|
|
1409
|
-
}
|
|
1410
|
-
|
|
1411
|
-
.table-card :deep(table) {
|
|
1412
|
-
table-layout: fixed;
|
|
1413
|
-
width: 100%;
|
|
1414
|
-
min-width: 820px;
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
.table-card :deep(th),
|
|
1418
|
-
.table-card :deep(td) {
|
|
1419
|
-
white-space: nowrap;
|
|
1420
|
-
}
|
|
1421
|
-
|
|
1422
|
-
.table-card :deep(th:nth-child(1)),
|
|
1423
|
-
.table-card :deep(td:nth-child(1)) {
|
|
1424
|
-
width: 28%;
|
|
1425
|
-
}
|
|
1426
|
-
|
|
1427
|
-
.table-card :deep(th:nth-child(2)),
|
|
1428
|
-
.table-card :deep(td:nth-child(2)) {
|
|
1429
|
-
width: 22%;
|
|
1430
|
-
}
|
|
1431
|
-
|
|
1432
|
-
.table-card :deep(th:nth-child(3)),
|
|
1433
|
-
.table-card :deep(td:nth-child(3)) {
|
|
1434
|
-
width: 25%;
|
|
1435
|
-
}
|
|
1436
|
-
|
|
1437
|
-
.table-card :deep(th:nth-child(4)),
|
|
1438
|
-
.table-card :deep(td:nth-child(4)) {
|
|
1439
|
-
width: 17%;
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
.table-card :deep(th:nth-child(5)),
|
|
1443
|
-
.table-card :deep(td:nth-child(5)) {
|
|
1444
|
-
width: 8%;
|
|
1445
|
-
}
|
|
1446
|
-
|
|
1447
|
-
.table-body {
|
|
1448
|
-
flex: 1;
|
|
1449
|
-
overflow-x: auto;
|
|
1450
|
-
}
|
|
1451
|
-
|
|
1452
|
-
.table-refresh,
|
|
1453
|
-
.table-footer {
|
|
1454
|
-
display: flex;
|
|
1455
|
-
align-items: center;
|
|
1456
|
-
gap: 8px;
|
|
1457
|
-
padding: 8px 10px;
|
|
1458
|
-
border-bottom: 1px solid #eeeeee;
|
|
1459
|
-
}
|
|
1460
|
-
|
|
1461
|
-
.table-footer {
|
|
1462
|
-
justify-content: flex-end;
|
|
1463
|
-
border-top: 1px solid #eeeeee;
|
|
1464
|
-
border-bottom: 0;
|
|
1465
|
-
background: #f6f6f6;
|
|
1466
|
-
min-height: 44px;
|
|
1467
|
-
padding: 4px 10px;
|
|
1468
|
-
}
|
|
1469
|
-
|
|
1470
|
-
.page-count {
|
|
1471
|
-
margin-left: auto;
|
|
1472
|
-
color: #475467;
|
|
1473
|
-
font-size: 12px;
|
|
1474
|
-
}
|
|
1475
|
-
|
|
1476
|
-
.empty-state {
|
|
1477
|
-
min-height: 280px;
|
|
1478
|
-
display: grid;
|
|
1479
|
-
place-items: center;
|
|
1480
|
-
color: #687382;
|
|
1481
|
-
font-size: 13px;
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
.status-chip {
|
|
1485
|
-
min-width: 86px;
|
|
1486
|
-
justify-content: center;
|
|
1487
|
-
font-weight: 600;
|
|
1488
|
-
}
|
|
1489
|
-
|
|
1490
|
-
.status-success {
|
|
1491
|
-
background: #dff7e7 !important;
|
|
1492
|
-
color: #1b7f3a !important;
|
|
1493
|
-
}
|
|
1494
|
-
|
|
1495
|
-
.status-warning {
|
|
1496
|
-
background: #fff0cc !important;
|
|
1497
|
-
color: #9a6700 !important;
|
|
1498
|
-
}
|
|
1499
|
-
|
|
1500
|
-
.status-error {
|
|
1501
|
-
background: #fde2e1 !important;
|
|
1502
|
-
color: #b42318 !important;
|
|
1391
|
+
/* The reader option now reads "Reader - Portal", so it needs more room than
|
|
1392
|
+
the other filters. `AppSelect`'s root class IS `app-field`, so this has to
|
|
1393
|
+
be more specific than the rule above rather than a `.app-select` one. */
|
|
1394
|
+
.hid-user-filters :deep(.app-field.reader-select) {
|
|
1395
|
+
max-width: 320px;
|
|
1503
1396
|
}
|
|
1504
1397
|
|
|
1505
1398
|
.small-title {
|
|
1506
1399
|
font-size: 14px;
|
|
1507
1400
|
font-weight: 700;
|
|
1401
|
+
color: var(--text);
|
|
1508
1402
|
}
|
|
1509
1403
|
|
|
1404
|
+
/* Was `#4f5a66` / `#e53935` - the same two greys on both themes. */
|
|
1510
1405
|
.field-label {
|
|
1511
|
-
color:
|
|
1406
|
+
color: var(--text2);
|
|
1512
1407
|
font-size: 12px;
|
|
1513
1408
|
font-weight: 600;
|
|
1514
1409
|
margin-bottom: 6px;
|
|
1515
1410
|
}
|
|
1516
1411
|
|
|
1517
1412
|
.field-label span {
|
|
1518
|
-
color:
|
|
1413
|
+
color: var(--err);
|
|
1414
|
+
}
|
|
1415
|
+
|
|
1416
|
+
/* Vuetify's `persistent-hint` line, redrawn as the design's explanatory line. */
|
|
1417
|
+
.field-hint {
|
|
1418
|
+
margin: 6px 0 0;
|
|
1419
|
+
color: var(--muted);
|
|
1420
|
+
font-size: 12px;
|
|
1421
|
+
font-weight: 600;
|
|
1422
|
+
line-height: 1.45;
|
|
1519
1423
|
}
|
|
1520
1424
|
|
|
1521
1425
|
.photo-wrap {
|
|
@@ -1527,12 +1431,12 @@ function getHidErrorMessage(error: any) {
|
|
|
1527
1431
|
.photo-button {
|
|
1528
1432
|
width: 120px;
|
|
1529
1433
|
height: 120px;
|
|
1530
|
-
border: 1px solid
|
|
1531
|
-
border-radius:
|
|
1532
|
-
background:
|
|
1434
|
+
border: 1px solid var(--border);
|
|
1435
|
+
border-radius: var(--r-inner);
|
|
1436
|
+
background: var(--card);
|
|
1533
1437
|
display: grid;
|
|
1534
1438
|
place-items: center;
|
|
1535
|
-
color:
|
|
1439
|
+
color: var(--muted);
|
|
1536
1440
|
font-size: 12px;
|
|
1537
1441
|
overflow: hidden;
|
|
1538
1442
|
position: relative;
|
|
@@ -1550,16 +1454,16 @@ function getHidErrorMessage(error: any) {
|
|
|
1550
1454
|
width: 28px;
|
|
1551
1455
|
height: 28px;
|
|
1552
1456
|
border-radius: 50%;
|
|
1553
|
-
background:
|
|
1554
|
-
color:
|
|
1457
|
+
background: var(--card);
|
|
1458
|
+
color: var(--text);
|
|
1555
1459
|
display: grid;
|
|
1556
1460
|
place-items: center;
|
|
1557
|
-
box-shadow:
|
|
1461
|
+
box-shadow: var(--shadow-menu);
|
|
1558
1462
|
}
|
|
1559
1463
|
|
|
1560
1464
|
.hid-face-avatar {
|
|
1561
|
-
border: 1px solid
|
|
1562
|
-
background:
|
|
1465
|
+
border: 1px solid var(--border);
|
|
1466
|
+
background: var(--hover);
|
|
1563
1467
|
}
|
|
1564
1468
|
|
|
1565
1469
|
.hidden-input {
|
|
@@ -1571,43 +1475,38 @@ function getHidErrorMessage(error: any) {
|
|
|
1571
1475
|
grid-template-columns: 1fr 1fr;
|
|
1572
1476
|
gap: 8px 16px;
|
|
1573
1477
|
font-size: 13px;
|
|
1478
|
+
color: var(--text);
|
|
1574
1479
|
}
|
|
1575
1480
|
|
|
1576
1481
|
.detail-grid span {
|
|
1577
|
-
color:
|
|
1482
|
+
color: var(--muted);
|
|
1578
1483
|
}
|
|
1579
1484
|
|
|
1485
|
+
/* The split footer bar. The handoff does not draw one, so the SHAPE is the
|
|
1486
|
+
screen's own; only the colours change - `#062d42` was a fixed navy that sat
|
|
1487
|
+
on the dark card unchanged. Same treatment as panel 2. */
|
|
1580
1488
|
.action-cancel,
|
|
1581
1489
|
.action-submit {
|
|
1582
1490
|
flex: 1;
|
|
1583
1491
|
border-radius: 0;
|
|
1584
1492
|
}
|
|
1585
1493
|
|
|
1494
|
+
.action-cancel {
|
|
1495
|
+
background: var(--card);
|
|
1496
|
+
color: var(--text2);
|
|
1497
|
+
}
|
|
1498
|
+
|
|
1586
1499
|
.action-submit {
|
|
1587
|
-
background:
|
|
1588
|
-
color:
|
|
1500
|
+
background: var(--accent-strong);
|
|
1501
|
+
color: var(--on-accent-strong);
|
|
1589
1502
|
}
|
|
1590
1503
|
|
|
1591
1504
|
@media (max-width: 960px) {
|
|
1592
|
-
.
|
|
1593
|
-
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
|
-
.toolbar-spacer {
|
|
1597
|
-
display: none;
|
|
1598
|
-
}
|
|
1599
|
-
|
|
1600
|
-
.enroll-button,
|
|
1601
|
-
.reader-input,
|
|
1602
|
-
.search-input,
|
|
1603
|
-
.status-input {
|
|
1505
|
+
.hid-user-filters :deep(.app-field),
|
|
1506
|
+
.hid-user-filters :deep(.app-select) {
|
|
1604
1507
|
max-width: none;
|
|
1605
1508
|
width: 100%;
|
|
1606
1509
|
}
|
|
1607
|
-
|
|
1608
|
-
.table-card {
|
|
1609
|
-
min-height: 360px;
|
|
1610
|
-
}
|
|
1611
1510
|
}
|
|
1612
1511
|
|
|
1613
1512
|
@media (max-width: 600px) {
|
|
@@ -1624,10 +1523,6 @@ function getHidErrorMessage(error: any) {
|
|
|
1624
1523
|
height: 104px;
|
|
1625
1524
|
}
|
|
1626
1525
|
|
|
1627
|
-
.table-footer {
|
|
1628
|
-
justify-content: center;
|
|
1629
|
-
}
|
|
1630
|
-
|
|
1631
1526
|
:global(.v-dialog > .v-overlay__content) {
|
|
1632
1527
|
max-width: calc(100vw - 24px) !important;
|
|
1633
1528
|
margin: 12px !important;
|