@7365admin1/layer-common 3.2.1 → 3.2.2-staging.100
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/.changeset/camera-wall-gated-endpoint.md +47 -0
- package/.changeset/camera-wall-plain-english.md +60 -0
- package/.changeset/camera-wall-selection-and-guidance.md +65 -0
- package/.changeset/dark-primary-contrast.md +39 -0
- package/.changeset/dashboard-dark-theme-contrast.md +15 -0
- package/.changeset/notification-preferences.md +17 -0
- package/.changeset/pm-sidebar-grouping-and-list-scaffold.md +27 -0
- package/.changeset/service-provider-invitation-actions.md +28 -0
- package/assets/css/primitives.css +680 -0
- package/assets/css/screens.css +541 -0
- package/assets/css/shell.css +258 -0
- package/assets/css/tokens.css +220 -0
- package/components/AccessCardQrTagging.vue +1 -1
- package/components/AccessManagement.vue +53 -72
- package/components/AppButton.vue +52 -0
- package/components/AppCard.vue +20 -0
- package/components/AppDateField.vue +35 -0
- package/components/AppField.vue +46 -0
- package/components/AppKpiTile.vue +65 -0
- package/components/AppSegmented.vue +38 -0
- package/components/AppSelect.vue +203 -0
- package/components/AreaChecklistHistoryMain.vue +6 -2
- package/components/AreaMain.vue +9 -17
- package/components/AttendanceMain.vue +4 -3
- package/components/Avatar/Main.vue +54 -2
- package/components/BillingMain.vue +26 -30
- package/components/BuildingManagement/buildings.vue +27 -38
- package/components/BuildingManagement/units.vue +26 -42
- package/components/BulletinBoardManagement.vue +23 -10
- package/components/CameraWall.vue +1034 -0
- package/components/CameraWallTile.vue +818 -0
- package/components/CardToolbar.vue +37 -0
- package/components/CleaningScheduleMain.vue +29 -46
- package/components/ClientMain.vue +90 -78
- package/components/DashboardEmptyState.vue +11 -1
- package/components/DashboardMain.vue +349 -275
- package/components/DashboardPanel.vue +1 -1
- package/components/DocumentManagement.vue +129 -93
- package/components/EntryPassInformation.vue +4 -4
- package/components/EntryPassMain.vue +49 -27
- package/components/EquipmentItemMain.vue +4 -6
- package/components/EquipmentManagementMain.vue +9 -7
- package/components/FeedbackMain.vue +42 -56
- package/components/FormDialog.vue +60 -21
- package/components/HidAccessLogDashboard.vue +119 -44
- package/components/HidCameraCaptureDialog.vue +199 -0
- package/components/HidIntercomManagement.vue +825 -202
- package/components/HidQrCodeConfiguration.vue +927 -93
- package/components/HidServiceSettingsPanel.vue +20 -1
- package/components/HidUserEnrollment.vue +454 -106
- package/components/InvitationMain.vue +46 -61
- package/components/Layout/Header.vue +289 -37
- package/components/Layout/NavigationDrawer.vue +340 -30
- package/components/ManageChecklistMain.vue +17 -17
- package/components/MemberMain.vue +79 -60
- package/components/MyAttendanceMain.vue +3 -5
- package/components/NavigationItem.vue +9 -0
- package/components/Nfc/NFCPatrolRouteMain.vue +116 -103
- package/components/NotificationSettings.vue +361 -0
- package/components/OnlineFormConfigurationForm.vue +620 -224
- package/components/OnlineFormFill.vue +36 -8
- package/components/OnlineFormsConfiguration.vue +7 -3
- package/components/PageHeader.vue +43 -0
- package/components/PassInformation.vue +104 -45
- package/components/QrTemplate/CreditCardLandscape.vue +19 -12
- package/components/QrTemplate/PrintDialog.vue +209 -196
- package/components/RolePermissionMain.vue +184 -91
- package/components/ScanVisitorQRCode.vue +35 -7
- package/components/ScheduleAreaMain.vue +15 -49
- package/components/ScheduleTaskMain.vue +23 -26
- package/components/ScheduleTastTicketMain.vue +18 -43
- package/components/ServiceProviderInvitationPrompt.vue +150 -0
- package/components/ServiceProviderMain.vue +346 -157
- package/components/SiteSettings.vue +25 -10
- package/components/SpecificAttr.vue +10 -2
- package/components/StatusChip.vue +93 -0
- package/components/SwitchContext.vue +33 -1
- package/components/TableHygiene.vue +29 -46
- package/components/TableList.vue +1 -1
- package/components/TableListSecondary.vue +1 -1
- package/components/TableMain.vue +161 -77
- package/components/TableV3.vue +61 -66
- package/components/UnitMain.vue +9 -17
- package/components/VehicleManagement.vue +20 -9
- package/components/VisitorForm.vue +294 -78
- package/components/VisitorManagement.vue +221 -71
- package/components/VisitorSocketPopUp.vue +56 -2
- package/components/WorkOrder/Main.vue +42 -51
- package/composables/useComment.ts +3 -3
- package/composables/useHidAmico.ts +151 -0
- package/composables/useHidNavigation.ts +0 -7
- package/composables/useLocalAuth.ts +9 -36
- package/composables/useNotificationPreference.ts +87 -0
- package/composables/useOnlineFormPages.ts +2 -0
- package/composables/useOrg.ts +1 -1
- package/composables/useRole.ts +22 -0
- package/composables/useServiceProviderInvitation.ts +145 -0
- package/composables/useSipWebPhone.ts +336 -0
- package/composables/useSiteSettings.ts +50 -0
- package/composables/useThemePreference.ts +63 -0
- package/composables/useVisitor.ts +6 -1
- package/composables/useVisitorSocket.ts +26 -0
- package/composables/useWebUsb.ts +127 -37
- package/nuxt.config.ts +31 -0
- package/package.json +4 -1
- package/pages/[org]/[site]/access-mgmt/intercom/index.vue +1 -1
- package/pages/notification-settings.vue +19 -0
- package/plugins/secure-member.client.ts +21 -56
- package/plugins/vuetify.ts +68 -9
- package/test/visitor-socket.test.mjs +36 -0
- package/types/org.d.ts +2 -0
- package/types/site.d.ts +71 -0
- package/utils/camera-wall.test.ts +571 -0
- package/utils/camera-wall.ts +926 -0
- package/utils/nav-sections.test.ts +190 -0
- package/utils/nav-sections.ts +151 -0
- package/utils/status.test.ts +77 -0
- package/utils/status.ts +90 -0
- package/utils/theme.test.ts +534 -0
- package/utils/theme.ts +294 -0
- package/components/HidIdentityMapping.vue +0 -975
- package/middleware/member.ts +0 -4
- package/pages/[org]/[site]/access-mgmt/identity-mapping/index.vue +0 -23
|
@@ -203,46 +203,36 @@
|
|
|
203
203
|
|
|
204
204
|
<section v-else class="unified-dashboard pb-8">
|
|
205
205
|
<!-- ── Header ──────────────────────────────────────────────────────────── -->
|
|
206
|
-
<
|
|
207
|
-
|
|
206
|
+
<PageHeader
|
|
207
|
+
:title="dashboardTitle"
|
|
208
|
+
:subtitle="currentSiteName || 'Selected site'"
|
|
209
|
+
subtitle-icon="mdi-map-marker"
|
|
208
210
|
>
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
<div
|
|
220
|
-
v-if="showHeaderActions"
|
|
221
|
-
class="d-flex flex-wrap align-center justify-md-end ga-3"
|
|
222
|
-
>
|
|
223
|
-
<v-btn
|
|
224
|
-
variant="outlined"
|
|
225
|
-
color="blue-grey-darken-1"
|
|
226
|
-
class="text-none font-weight-bold"
|
|
227
|
-
prepend-icon="mdi-tune-variant"
|
|
211
|
+
<!--
|
|
212
|
+
The design's three actions: two 38px ghost buttons and the accent
|
|
213
|
+
segmented control. Same dialog, same export menu, same range model -
|
|
214
|
+
`Customize Dashboard` and `Export` shorten to the labels the prototype
|
|
215
|
+
prints, and the export menu keeps both of its formats.
|
|
216
|
+
-->
|
|
217
|
+
<template v-if="showHeaderActions" #actions>
|
|
218
|
+
<AppButton
|
|
219
|
+
variant="ghost"
|
|
220
|
+
icon="mdi-tune-variant"
|
|
228
221
|
@click="openCustomizeDialog"
|
|
229
222
|
>
|
|
230
|
-
Customize
|
|
231
|
-
</
|
|
223
|
+
Customize
|
|
224
|
+
</AppButton>
|
|
232
225
|
|
|
233
226
|
<v-menu>
|
|
234
227
|
<template #activator="{ props: menuProps }">
|
|
235
|
-
<
|
|
228
|
+
<AppButton
|
|
236
229
|
v-bind="menuProps"
|
|
237
|
-
variant="
|
|
238
|
-
|
|
239
|
-
class="text-none font-weight-bold"
|
|
240
|
-
append-icon="mdi-chevron-down"
|
|
241
|
-
:loading="isExporting"
|
|
230
|
+
variant="ghost"
|
|
231
|
+
icon="mdi-download-outline"
|
|
242
232
|
:disabled="isExporting"
|
|
243
233
|
>
|
|
244
234
|
Export
|
|
245
|
-
</
|
|
235
|
+
</AppButton>
|
|
246
236
|
</template>
|
|
247
237
|
|
|
248
238
|
<v-list density="compact" border rounded="lg" elevation="3">
|
|
@@ -251,36 +241,9 @@
|
|
|
251
241
|
</v-list>
|
|
252
242
|
</v-menu>
|
|
253
243
|
|
|
254
|
-
<v-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
density="comfortable"
|
|
258
|
-
divided
|
|
259
|
-
variant="outlined"
|
|
260
|
-
class="bg-white"
|
|
261
|
-
style="border-radius: 8px; border-color: #d9e1e8"
|
|
262
|
-
>
|
|
263
|
-
<v-btn
|
|
264
|
-
v-for="range in rangeOptions"
|
|
265
|
-
:key="range.value"
|
|
266
|
-
:value="range.value"
|
|
267
|
-
class="text-none"
|
|
268
|
-
size="small"
|
|
269
|
-
:style="
|
|
270
|
-
selectedRange === range.value
|
|
271
|
-
? {
|
|
272
|
-
backgroundColor: '#e2e8f0',
|
|
273
|
-
color: '#0b2f47',
|
|
274
|
-
fontWeight: '600',
|
|
275
|
-
}
|
|
276
|
-
: { backgroundColor: 'transparent', color: '#64748b' }
|
|
277
|
-
"
|
|
278
|
-
>
|
|
279
|
-
{{ range.label }}
|
|
280
|
-
</v-btn>
|
|
281
|
-
</v-btn-toggle>
|
|
282
|
-
</div>
|
|
283
|
-
</div>
|
|
244
|
+
<AppSegmented v-model="selectedRange" :options="rangeOptions" />
|
|
245
|
+
</template>
|
|
246
|
+
</PageHeader>
|
|
284
247
|
|
|
285
248
|
<v-progress-linear
|
|
286
249
|
v-if="finalLoading"
|
|
@@ -300,22 +263,24 @@
|
|
|
300
263
|
lg="3"
|
|
301
264
|
class="d-flex"
|
|
302
265
|
>
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
266
|
+
<!--
|
|
267
|
+
The same figures the tile has always shown, in the arrangement the
|
|
268
|
+
handoff draws them: icon and label on one row, the number with its
|
|
269
|
+
percentage pill beside it, the sub-line under both. The filter menu
|
|
270
|
+
and the facility "View All" keep their place at the end of the first
|
|
271
|
+
row and do exactly what they did.
|
|
272
|
+
-->
|
|
273
|
+
<AppKpiTile
|
|
274
|
+
:icon="card.icon"
|
|
275
|
+
:tint="card.tint"
|
|
276
|
+
:color="card.color"
|
|
277
|
+
:label="card.title"
|
|
278
|
+
:value="card.value"
|
|
279
|
+
:chip="kpiChipText(card)"
|
|
280
|
+
:down="Number(card.percentage) < 0"
|
|
281
|
+
:sub="card.meta"
|
|
309
282
|
>
|
|
310
|
-
<
|
|
311
|
-
<div
|
|
312
|
-
class="d-inline-flex align-center justify-center rounded-lg"
|
|
313
|
-
style="height: 28px; width: 28px; flex-shrink: 0"
|
|
314
|
-
:style="{ backgroundColor: card.tint }"
|
|
315
|
-
>
|
|
316
|
-
<v-icon :icon="card.icon" :color="card.color" size="15" />
|
|
317
|
-
</div>
|
|
318
|
-
|
|
283
|
+
<template v-if="card.filter || card.key === 'facilityBookings'" #action>
|
|
319
284
|
<v-menu v-if="card.filter" v-model="filterMenus[card.key]">
|
|
320
285
|
<template #activator="{ props: menuProps }">
|
|
321
286
|
<v-btn
|
|
@@ -359,61 +324,24 @@
|
|
|
359
324
|
>
|
|
360
325
|
View All
|
|
361
326
|
</button>
|
|
362
|
-
</
|
|
327
|
+
</template>
|
|
363
328
|
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
<div
|
|
377
|
-
v-for="item in card.raw.items"
|
|
378
|
-
:key="item._id || item.name"
|
|
379
|
-
class="d-flex justify-space-between text-body-2 text-blue-grey-darken-4 font-weight-medium"
|
|
380
|
-
>
|
|
381
|
-
<span>{{ item.name }}</span>
|
|
382
|
-
<span class="text-blue-grey">Balance: {{ item.qty }}</span>
|
|
383
|
-
</div>
|
|
384
|
-
</div>
|
|
385
|
-
</template>
|
|
386
|
-
<template v-else>
|
|
387
|
-
<div class="d-flex align-center mb-3" style="min-height: 31px">
|
|
388
|
-
<span class="text-h5 font-weight-black text-blue-grey-darken-4">
|
|
389
|
-
{{ card.value }}
|
|
390
|
-
</span>
|
|
391
|
-
</div>
|
|
392
|
-
<div class="d-flex align-center flex-wrap ga-2">
|
|
393
|
-
<span v-if="card.meta" class="text-caption text-blue-grey">{{
|
|
394
|
-
card.meta
|
|
395
|
-
}}</span>
|
|
396
|
-
<v-chip
|
|
397
|
-
:color="card.percentage >= 0 ? 'success' : 'error'"
|
|
398
|
-
size="x-small"
|
|
399
|
-
variant="flat"
|
|
400
|
-
class="font-weight-bold"
|
|
401
|
-
>
|
|
402
|
-
<v-icon
|
|
403
|
-
:icon="
|
|
404
|
-
card.percentage >= 0
|
|
405
|
-
? 'mdi-arrow-up-right'
|
|
406
|
-
: 'mdi-arrow-down-right'
|
|
407
|
-
"
|
|
408
|
-
size="13"
|
|
409
|
-
start
|
|
410
|
-
/>
|
|
411
|
-
{{ Math.abs(card.percentage) }}%
|
|
412
|
-
</v-chip>
|
|
329
|
+
<!-- The supply tile lists items instead of counting one figure. -->
|
|
330
|
+
<template
|
|
331
|
+
v-if="card.key === 'supplyAlert' && Array.isArray(card.raw?.items)"
|
|
332
|
+
>
|
|
333
|
+
<div class="d-flex flex-column ga-2">
|
|
334
|
+
<div
|
|
335
|
+
v-for="item in card.raw.items"
|
|
336
|
+
:key="item._id || item.name"
|
|
337
|
+
class="d-flex justify-space-between text-body-2 text-high-emphasis font-weight-medium"
|
|
338
|
+
>
|
|
339
|
+
<span>{{ item.name }}</span>
|
|
340
|
+
<span class="text-medium-emphasis">Balance: {{ item.qty }}</span>
|
|
413
341
|
</div>
|
|
414
|
-
</
|
|
415
|
-
</
|
|
416
|
-
</
|
|
342
|
+
</div>
|
|
343
|
+
</template>
|
|
344
|
+
</AppKpiTile>
|
|
417
345
|
</v-col>
|
|
418
346
|
</v-row>
|
|
419
347
|
|
|
@@ -421,12 +349,10 @@
|
|
|
421
349
|
<v-card
|
|
422
350
|
v-if="isWidgetVisible('activity')"
|
|
423
351
|
flat
|
|
424
|
-
|
|
425
|
-
rounded="lg"
|
|
426
|
-
class="px-5 pt-4 pb-3 mt-3"
|
|
352
|
+
class="dashboard-card px-5 pt-4 pb-3 mt-3"
|
|
427
353
|
>
|
|
428
354
|
<div class="d-flex align-center justify-space-between">
|
|
429
|
-
<h2 class="
|
|
355
|
+
<h2 class="dashboard-card-title mb-0">
|
|
430
356
|
{{ activityTitle }}
|
|
431
357
|
</h2>
|
|
432
358
|
</div>
|
|
@@ -444,7 +370,7 @@
|
|
|
444
370
|
:y1="tick"
|
|
445
371
|
:x2="chartWidth - 20"
|
|
446
372
|
:y2="tick"
|
|
447
|
-
style="stroke:
|
|
373
|
+
style="stroke: rgba(var(--v-theme-on-surface), 0.12); stroke-width: 1"
|
|
448
374
|
/>
|
|
449
375
|
<text
|
|
450
376
|
v-for="label in chartYLabels"
|
|
@@ -453,7 +379,7 @@
|
|
|
453
379
|
:y="label.y"
|
|
454
380
|
text-anchor="end"
|
|
455
381
|
alignment-baseline="middle"
|
|
456
|
-
style="fill:
|
|
382
|
+
style="fill: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); font-size: 11px; font-weight: 500"
|
|
457
383
|
>
|
|
458
384
|
{{ label.text }}
|
|
459
385
|
</text>
|
|
@@ -483,7 +409,7 @@
|
|
|
483
409
|
:cx="point.x"
|
|
484
410
|
:cy="point.y"
|
|
485
411
|
r="4"
|
|
486
|
-
style="fill: #ff9b9b; stroke:
|
|
412
|
+
style="fill: #ff9b9b; stroke: rgb(var(--v-theme-surface)); stroke-width: 2"
|
|
487
413
|
/>
|
|
488
414
|
<circle
|
|
489
415
|
v-for="point in secondaryDots"
|
|
@@ -491,7 +417,7 @@
|
|
|
491
417
|
:cx="point.x"
|
|
492
418
|
:cy="point.y"
|
|
493
419
|
r="4"
|
|
494
|
-
style="fill: #e53935; stroke:
|
|
420
|
+
style="fill: #e53935; stroke: rgb(var(--v-theme-surface)); stroke-width: 2"
|
|
495
421
|
/>
|
|
496
422
|
<text
|
|
497
423
|
v-for="label in chartAxisLabels"
|
|
@@ -499,7 +425,7 @@
|
|
|
499
425
|
:x="label.x"
|
|
500
426
|
y="246"
|
|
501
427
|
text-anchor="middle"
|
|
502
|
-
style="fill:
|
|
428
|
+
style="fill: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity)); font-size: 12px; font-weight: 600"
|
|
503
429
|
>
|
|
504
430
|
{{ label.text }}
|
|
505
431
|
</text>
|
|
@@ -507,7 +433,7 @@
|
|
|
507
433
|
|
|
508
434
|
<div class="d-flex align-center justify-center ga-5 mt-2">
|
|
509
435
|
<span
|
|
510
|
-
class="d-inline-flex align-center ga-2 text-caption font-weight-bold text-
|
|
436
|
+
class="d-inline-flex align-center ga-2 text-caption font-weight-bold text-medium-emphasis"
|
|
511
437
|
>
|
|
512
438
|
<span
|
|
513
439
|
class="rounded-circle"
|
|
@@ -521,7 +447,7 @@
|
|
|
521
447
|
{{ primaryLegendLabel }}
|
|
522
448
|
</span>
|
|
523
449
|
<span
|
|
524
|
-
class="d-inline-flex align-center ga-2 text-caption font-weight-bold text-
|
|
450
|
+
class="d-inline-flex align-center ga-2 text-caption font-weight-bold text-medium-emphasis"
|
|
525
451
|
>
|
|
526
452
|
<span
|
|
527
453
|
class="rounded-circle"
|
|
@@ -558,18 +484,16 @@
|
|
|
558
484
|
v-for="item in taskScheduleItems"
|
|
559
485
|
:key="item.id"
|
|
560
486
|
flat
|
|
561
|
-
|
|
562
|
-
rounded="lg"
|
|
563
|
-
class="pa-3"
|
|
487
|
+
class="dashboard-row-card pa-3"
|
|
564
488
|
>
|
|
565
489
|
<div class="d-flex align-center flex-wrap ga-3">
|
|
566
490
|
<div class="flex-grow-1" style="min-width: 0">
|
|
567
491
|
<div
|
|
568
|
-
class="text-body-2 font-weight-bold text-
|
|
492
|
+
class="text-body-2 font-weight-bold text-high-emphasis text-truncate"
|
|
569
493
|
>
|
|
570
494
|
{{ item.title }}
|
|
571
495
|
</div>
|
|
572
|
-
<div class="text-caption text-
|
|
496
|
+
<div class="text-caption text-medium-emphasis mt-1 text-truncate">
|
|
573
497
|
{{ item.subtitle
|
|
574
498
|
}}<template v-if="item.subtitle && item.time">
|
|
575
499
|
• </template
|
|
@@ -577,7 +501,7 @@
|
|
|
577
501
|
</div>
|
|
578
502
|
</div>
|
|
579
503
|
<div
|
|
580
|
-
class="d-flex align-center ga-2 text-caption text-
|
|
504
|
+
class="d-flex align-center ga-2 text-caption text-medium-emphasis"
|
|
581
505
|
>
|
|
582
506
|
<AvatarMain :name="item.person" :size="30" />
|
|
583
507
|
<span class="text-truncate" style="max-width: 100px">{{
|
|
@@ -624,25 +548,22 @@
|
|
|
624
548
|
v-for="item in staffStatusItems"
|
|
625
549
|
:key="item.id"
|
|
626
550
|
flat
|
|
627
|
-
|
|
628
|
-
rounded="lg"
|
|
629
|
-
class="pa-3"
|
|
551
|
+
class="dashboard-row-card pa-3"
|
|
630
552
|
>
|
|
631
553
|
<div class="d-flex align-start ga-3">
|
|
632
554
|
<AvatarMain :name="item.name" :size="32" />
|
|
633
555
|
<div class="flex-grow-1" style="min-width: 0">
|
|
634
556
|
<div
|
|
635
|
-
class="text-body-2 font-weight-bold text-
|
|
557
|
+
class="text-body-2 font-weight-bold text-high-emphasis text-truncate"
|
|
636
558
|
>
|
|
637
559
|
{{ item.name }}
|
|
638
560
|
</div>
|
|
639
|
-
<div class="text-caption text-
|
|
561
|
+
<div class="text-caption text-medium-emphasis mt-1 text-truncate">
|
|
640
562
|
{{ item.role }}
|
|
641
563
|
</div>
|
|
642
564
|
</div>
|
|
643
565
|
<v-chip
|
|
644
566
|
size="small"
|
|
645
|
-
color="blue-grey-darken-1"
|
|
646
567
|
variant="tonal"
|
|
647
568
|
label
|
|
648
569
|
class="ml-auto flex-shrink-0 font-weight-bold"
|
|
@@ -666,13 +587,13 @@
|
|
|
666
587
|
<div
|
|
667
588
|
v-for="item in feedbackItems"
|
|
668
589
|
:key="item.id"
|
|
669
|
-
class="d-flex align-center justify-space-between"
|
|
590
|
+
class="d-flex align-center justify-space-between dashboard-feedback-row"
|
|
670
591
|
style="
|
|
671
592
|
padding: 16px 20px;
|
|
672
|
-
border: 1px solid
|
|
593
|
+
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
|
673
594
|
border-radius: 12px;
|
|
674
595
|
margin-bottom: 12px;
|
|
675
|
-
background-color:
|
|
596
|
+
background-color: rgb(var(--v-theme-surface-bright));
|
|
676
597
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);
|
|
677
598
|
"
|
|
678
599
|
>
|
|
@@ -682,12 +603,12 @@
|
|
|
682
603
|
display: block;
|
|
683
604
|
font-size: 15px;
|
|
684
605
|
font-weight: 700;
|
|
685
|
-
color:
|
|
606
|
+
color: rgb(var(--v-theme-on-surface));
|
|
686
607
|
margin-bottom: 4px;
|
|
687
608
|
"
|
|
688
609
|
>{{ item.title }}</strong
|
|
689
610
|
>
|
|
690
|
-
<span style="font-size: 13px; color:
|
|
611
|
+
<span style="font-size: 13px; color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity))">{{
|
|
691
612
|
item.subtitle
|
|
692
613
|
}}</span>
|
|
693
614
|
</div>
|
|
@@ -696,7 +617,7 @@
|
|
|
696
617
|
style="flex: 1; display: flex; align-items: center; gap: 12px"
|
|
697
618
|
>
|
|
698
619
|
<AvatarMain :name="item.person" :size="36" />
|
|
699
|
-
<span style="font-size: 14px; color:
|
|
620
|
+
<span style="font-size: 14px; color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity))">{{
|
|
700
621
|
item.person
|
|
701
622
|
}}</span>
|
|
702
623
|
</div>
|
|
@@ -721,9 +642,9 @@
|
|
|
721
642
|
variant="outlined"
|
|
722
643
|
class="text-none font-weight-medium"
|
|
723
644
|
size="small"
|
|
724
|
-
color="
|
|
645
|
+
color="primary"
|
|
725
646
|
style="
|
|
726
|
-
border-color:
|
|
647
|
+
border-color: rgba(var(--v-border-color), var(--v-border-opacity));
|
|
727
648
|
border-radius: 8px;
|
|
728
649
|
padding: 0 16px;
|
|
729
650
|
height: 32px;
|
|
@@ -967,7 +888,7 @@
|
|
|
967
888
|
<v-col v-if="isWidgetVisible('activePatrol')" cols="12" lg="6">
|
|
968
889
|
<div class="dashboard-card dashboard-panel figma-panel">
|
|
969
890
|
<div class="figma-panel-header">
|
|
970
|
-
<h2>
|
|
891
|
+
<h2>Active Patrol</h2>
|
|
971
892
|
<button
|
|
972
893
|
class="figma-panel-action"
|
|
973
894
|
type="button"
|
|
@@ -1026,9 +947,9 @@
|
|
|
1026
947
|
variant="outlined"
|
|
1027
948
|
class="text-none font-weight-medium"
|
|
1028
949
|
size="small"
|
|
1029
|
-
color="
|
|
950
|
+
color="primary"
|
|
1030
951
|
style="
|
|
1031
|
-
border-color:
|
|
952
|
+
border-color: rgba(var(--v-border-color), var(--v-border-opacity));
|
|
1032
953
|
border-radius: 8px;
|
|
1033
954
|
padding: 0 16px;
|
|
1034
955
|
height: 32px;
|
|
@@ -1047,7 +968,7 @@
|
|
|
1047
968
|
<v-col v-if="isWidgetVisible('staffStatus')" cols="12" lg="6">
|
|
1048
969
|
<div class="dashboard-card dashboard-panel figma-panel">
|
|
1049
970
|
<div class="figma-panel-header">
|
|
1050
|
-
<h2>
|
|
971
|
+
<h2>Staff Status</h2>
|
|
1051
972
|
<button
|
|
1052
973
|
class="figma-panel-action"
|
|
1053
974
|
type="button"
|
|
@@ -1064,10 +985,10 @@
|
|
|
1064
985
|
class="d-flex align-center justify-space-between"
|
|
1065
986
|
style="
|
|
1066
987
|
padding: 16px 20px;
|
|
1067
|
-
border: 1px solid
|
|
988
|
+
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
|
1068
989
|
border-radius: 12px;
|
|
1069
990
|
margin-bottom: 12px;
|
|
1070
|
-
background-color:
|
|
991
|
+
background-color: rgb(var(--v-theme-surface-bright));
|
|
1071
992
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);
|
|
1072
993
|
"
|
|
1073
994
|
>
|
|
@@ -1087,14 +1008,14 @@
|
|
|
1087
1008
|
display: block;
|
|
1088
1009
|
font-size: 15px;
|
|
1089
1010
|
font-weight: 700;
|
|
1090
|
-
color:
|
|
1011
|
+
color: rgb(var(--v-theme-on-surface));
|
|
1091
1012
|
margin-bottom: 4px;
|
|
1092
1013
|
"
|
|
1093
1014
|
>{{
|
|
1094
1015
|
item.userName || item.personName || "Unassigned"
|
|
1095
1016
|
}}</strong
|
|
1096
1017
|
>
|
|
1097
|
-
<span style="font-size: 13px; color:
|
|
1018
|
+
<span style="font-size: 13px; color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity))">{{
|
|
1098
1019
|
item.role || item.designation || "Officer"
|
|
1099
1020
|
}}</span>
|
|
1100
1021
|
</div>
|
|
@@ -1131,13 +1052,13 @@
|
|
|
1131
1052
|
<div
|
|
1132
1053
|
v-for="item in feedbackItems"
|
|
1133
1054
|
:key="item.id"
|
|
1134
|
-
class="d-flex align-center justify-space-between"
|
|
1055
|
+
class="d-flex align-center justify-space-between dashboard-feedback-row"
|
|
1135
1056
|
style="
|
|
1136
1057
|
padding: 16px 20px;
|
|
1137
|
-
border: 1px solid
|
|
1058
|
+
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
|
1138
1059
|
border-radius: 12px;
|
|
1139
1060
|
margin-bottom: 12px;
|
|
1140
|
-
background-color:
|
|
1061
|
+
background-color: rgb(var(--v-theme-surface-bright));
|
|
1141
1062
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);
|
|
1142
1063
|
"
|
|
1143
1064
|
>
|
|
@@ -1147,12 +1068,12 @@
|
|
|
1147
1068
|
display: block;
|
|
1148
1069
|
font-size: 15px;
|
|
1149
1070
|
font-weight: 700;
|
|
1150
|
-
color:
|
|
1071
|
+
color: rgb(var(--v-theme-on-surface));
|
|
1151
1072
|
margin-bottom: 4px;
|
|
1152
1073
|
"
|
|
1153
1074
|
>{{ item.title }}</strong
|
|
1154
1075
|
>
|
|
1155
|
-
<span style="font-size: 13px; color:
|
|
1076
|
+
<span style="font-size: 13px; color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity))">{{
|
|
1156
1077
|
item.subtitle
|
|
1157
1078
|
}}</span>
|
|
1158
1079
|
</div>
|
|
@@ -1161,7 +1082,7 @@
|
|
|
1161
1082
|
style="flex: 1; display: flex; align-items: center; gap: 12px"
|
|
1162
1083
|
>
|
|
1163
1084
|
<AvatarMain :name="item.person" :size="36" />
|
|
1164
|
-
<span style="font-size: 14px; color:
|
|
1085
|
+
<span style="font-size: 14px; color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity))">{{
|
|
1165
1086
|
item.person
|
|
1166
1087
|
}}</span>
|
|
1167
1088
|
</div>
|
|
@@ -1186,9 +1107,9 @@
|
|
|
1186
1107
|
variant="outlined"
|
|
1187
1108
|
class="text-none font-weight-medium"
|
|
1188
1109
|
size="small"
|
|
1189
|
-
color="
|
|
1110
|
+
color="primary"
|
|
1190
1111
|
style="
|
|
1191
|
-
border-color:
|
|
1112
|
+
border-color: rgba(var(--v-border-color), var(--v-border-opacity));
|
|
1192
1113
|
border-radius: 8px;
|
|
1193
1114
|
padding: 0 16px;
|
|
1194
1115
|
height: 32px;
|
|
@@ -1211,10 +1132,10 @@
|
|
|
1211
1132
|
class="d-flex align-start justify-space-between pa-6 pb-4 border-b"
|
|
1212
1133
|
>
|
|
1213
1134
|
<div>
|
|
1214
|
-
<div class="text-h6 font-weight-black text-
|
|
1135
|
+
<div class="text-h6 font-weight-black text-high-emphasis">
|
|
1215
1136
|
Customize Dashboard
|
|
1216
1137
|
</div>
|
|
1217
|
-
<div class="text-caption text-
|
|
1138
|
+
<div class="text-caption text-medium-emphasis mt-1">
|
|
1218
1139
|
Select which widgets to display on your dashboard
|
|
1219
1140
|
</div>
|
|
1220
1141
|
</div>
|
|
@@ -1240,7 +1161,6 @@
|
|
|
1240
1161
|
<div class="d-flex justify-end mt-3 mb-1">
|
|
1241
1162
|
<v-btn
|
|
1242
1163
|
variant="text"
|
|
1243
|
-
color="blue-grey-darken-4"
|
|
1244
1164
|
size="small"
|
|
1245
1165
|
class="text-none font-weight-bold"
|
|
1246
1166
|
prepend-icon="mdi-refresh"
|
|
@@ -1262,11 +1182,11 @@
|
|
|
1262
1182
|
<div class="d-flex align-center justify-space-between ga-4">
|
|
1263
1183
|
<div>
|
|
1264
1184
|
<div
|
|
1265
|
-
class="text-body-2 font-weight-black text-
|
|
1185
|
+
class="text-body-2 font-weight-black text-high-emphasis"
|
|
1266
1186
|
>
|
|
1267
1187
|
{{ widget.title }}
|
|
1268
1188
|
</div>
|
|
1269
|
-
<div class="text-caption text-
|
|
1189
|
+
<div class="text-caption text-medium-emphasis mt-1">
|
|
1270
1190
|
{{ widget.description }}
|
|
1271
1191
|
</div>
|
|
1272
1192
|
</div>
|
|
@@ -1292,7 +1212,7 @@
|
|
|
1292
1212
|
<v-card-actions class="pa-6 pt-4 border-t justify-end ga-3">
|
|
1293
1213
|
<v-btn
|
|
1294
1214
|
variant="text"
|
|
1295
|
-
class="text-none font-weight-bold text-
|
|
1215
|
+
class="text-none font-weight-bold text-medium-emphasis"
|
|
1296
1216
|
@click="cancelCustomize"
|
|
1297
1217
|
>
|
|
1298
1218
|
Cancel
|
|
@@ -1320,7 +1240,7 @@
|
|
|
1320
1240
|
<v-card-title
|
|
1321
1241
|
class="d-flex align-center justify-space-between pa-6 pb-3"
|
|
1322
1242
|
>
|
|
1323
|
-
<div class="text-body-1 font-weight-black text-
|
|
1243
|
+
<div class="text-body-1 font-weight-black text-high-emphasis">
|
|
1324
1244
|
Facility Booking
|
|
1325
1245
|
</div>
|
|
1326
1246
|
<v-btn
|
|
@@ -2505,6 +2425,17 @@ const visibleKpiCards = computed(() =>
|
|
|
2505
2425
|
kpiCards.value.filter((card) => isWidgetVisible(card.key))
|
|
2506
2426
|
);
|
|
2507
2427
|
|
|
2428
|
+
/**
|
|
2429
|
+
* The percentage pill's label. Same number the chip has always shown, written
|
|
2430
|
+
* the way the handoff prints it - `+0%` / `-6.4%`, the sign carrying what the
|
|
2431
|
+
* arrow icon used to. A card without a percentage gets no pill.
|
|
2432
|
+
*/
|
|
2433
|
+
function kpiChipText(card: Record<string, any>): string {
|
|
2434
|
+
const value = Number(card?.percentage);
|
|
2435
|
+
if (!Number.isFinite(value)) return "";
|
|
2436
|
+
return `${value < 0 ? "-" : "+"}${Math.abs(value)}%`;
|
|
2437
|
+
}
|
|
2438
|
+
|
|
2508
2439
|
// ─── Dashboard Title ──────────────────────────────────────────────────────────
|
|
2509
2440
|
|
|
2510
2441
|
const dashboardTitle = computed(() => {
|
|
@@ -3254,31 +3185,37 @@ function getInitials(name?: string) {
|
|
|
3254
3185
|
function getStatusPillStyle(status: any) {
|
|
3255
3186
|
const tone = getStatusTone(status);
|
|
3256
3187
|
const map: Record<string, { backgroundColor: string; color: string }> = {
|
|
3257
|
-
success: { backgroundColor: "
|
|
3258
|
-
warning: { backgroundColor: "
|
|
3259
|
-
error: { backgroundColor: "
|
|
3260
|
-
neutral: { backgroundColor: "
|
|
3188
|
+
success: { backgroundColor: "var(--ok-bg)", color: "var(--ok)" },
|
|
3189
|
+
warning: { backgroundColor: "var(--warn-bg)", color: "var(--warn)" },
|
|
3190
|
+
error: { backgroundColor: "var(--err-bg)", color: "var(--err)" },
|
|
3191
|
+
neutral: { backgroundColor: "var(--hover)", color: "var(--text2)" },
|
|
3261
3192
|
};
|
|
3262
3193
|
return map[tone] || map.neutral;
|
|
3263
3194
|
}
|
|
3264
3195
|
|
|
3196
|
+
/**
|
|
3197
|
+
* The pills are drawn by inline style, so the literal colours lived here rather
|
|
3198
|
+
* than in the stylesheet - which is why they survived the dark-mode repair and
|
|
3199
|
+
* still measured 3.86:1. Same three cases, same words, the design's tones.
|
|
3200
|
+
*/
|
|
3265
3201
|
function getPatrolStatusStyle(status: any) {
|
|
3266
3202
|
const s = String(status || "").toLowerCase();
|
|
3267
3203
|
if (s === "completed" || s === "complete")
|
|
3268
|
-
return { backgroundColor: "
|
|
3204
|
+
return { backgroundColor: "var(--ok-bg)", color: "var(--ok)" };
|
|
3269
3205
|
if (s === "on paused" || s === "paused")
|
|
3270
|
-
return { backgroundColor: "
|
|
3271
|
-
return { backgroundColor: "
|
|
3206
|
+
return { backgroundColor: "var(--hover)", color: "var(--text2)" };
|
|
3207
|
+
return { backgroundColor: "var(--hover)", color: "var(--text2)" };
|
|
3272
3208
|
}
|
|
3273
3209
|
|
|
3274
3210
|
function getStaffStatusPillStyle(status: any) {
|
|
3275
3211
|
const s = String(status || "").toLowerCase();
|
|
3276
3212
|
if (s === "on duty" || s === "on-duty")
|
|
3277
|
-
return { backgroundColor: "
|
|
3213
|
+
return { backgroundColor: "var(--ok-bg)", color: "var(--ok)" };
|
|
3278
3214
|
if (s === "on break" || s === "on-break")
|
|
3279
|
-
return { backgroundColor: "
|
|
3280
|
-
if (s === "absent")
|
|
3281
|
-
|
|
3215
|
+
return { backgroundColor: "var(--warn-bg)", color: "var(--warn)" };
|
|
3216
|
+
if (s === "absent")
|
|
3217
|
+
return { backgroundColor: "var(--err-bg)", color: "var(--err)" };
|
|
3218
|
+
return { backgroundColor: "var(--hover)", color: "var(--text2)" };
|
|
3282
3219
|
}
|
|
3283
3220
|
|
|
3284
3221
|
function getStatusProgressStyle(item: { percent: number; color: string }) {
|
|
@@ -4158,37 +4095,98 @@ function formatDashboardTime(value?: string) {
|
|
|
4158
4095
|
text-transform: capitalize;
|
|
4159
4096
|
}
|
|
4160
4097
|
|
|
4098
|
+
/* Was five pairs of literal pastels - the same pale green on the dark page,
|
|
4099
|
+
and none of them the tones the rest of the product uses. */
|
|
4161
4100
|
.badge-success {
|
|
4162
|
-
background-color:
|
|
4163
|
-
color:
|
|
4101
|
+
background-color: var(--ok-bg);
|
|
4102
|
+
color: var(--ok);
|
|
4164
4103
|
}
|
|
4165
4104
|
|
|
4166
4105
|
.badge-info {
|
|
4167
|
-
background-color:
|
|
4168
|
-
color:
|
|
4106
|
+
background-color: var(--info-bg);
|
|
4107
|
+
color: var(--info);
|
|
4169
4108
|
}
|
|
4170
4109
|
|
|
4171
4110
|
.badge-danger,
|
|
4172
4111
|
.badge-error {
|
|
4173
|
-
background-color:
|
|
4174
|
-
color:
|
|
4112
|
+
background-color: var(--err-bg);
|
|
4113
|
+
color: var(--err);
|
|
4175
4114
|
}
|
|
4176
4115
|
|
|
4177
4116
|
.badge-warning {
|
|
4178
|
-
background-color:
|
|
4179
|
-
color:
|
|
4117
|
+
background-color: var(--warn-bg);
|
|
4118
|
+
color: var(--warn);
|
|
4180
4119
|
}
|
|
4181
4120
|
|
|
4182
4121
|
.badge-neutral {
|
|
4183
|
-
background-color:
|
|
4184
|
-
color:
|
|
4122
|
+
background-color: var(--hover);
|
|
4123
|
+
color: var(--text2);
|
|
4185
4124
|
}
|
|
4186
4125
|
|
|
4126
|
+
/* ------------------------------------------------------------------ */
|
|
4127
|
+
/* PHASE 5 - the design's card, type and semantic tones. */
|
|
4128
|
+
/* */
|
|
4129
|
+
/* The dark-mode repair earlier today moved these surfaces off literal */
|
|
4130
|
+
/* white onto the Vuetify theme; this keeps that and takes the last */
|
|
4131
|
+
/* step, onto the design tokens themselves - so the dashboard's cards, */
|
|
4132
|
+
/* headings and pills are the same 14px card, the same Manrope and the */
|
|
4133
|
+
/* same four status tones as every other screen. */
|
|
4134
|
+
/* ------------------------------------------------------------------ */
|
|
4135
|
+
|
|
4187
4136
|
.dashboard-card {
|
|
4188
|
-
background:
|
|
4189
|
-
border: 1px solid
|
|
4190
|
-
border-radius:
|
|
4191
|
-
box-shadow:
|
|
4137
|
+
background: var(--card);
|
|
4138
|
+
border: 1px solid var(--border);
|
|
4139
|
+
border-radius: var(--r-card);
|
|
4140
|
+
box-shadow: var(--shadow);
|
|
4141
|
+
font-family: var(--font-sans);
|
|
4142
|
+
}
|
|
4143
|
+
|
|
4144
|
+
/* The KPI tile and the rows inside a panel are the same card, one step in. */
|
|
4145
|
+
.dashboard-kpi-card,
|
|
4146
|
+
.dashboard-row-card {
|
|
4147
|
+
background: var(--card);
|
|
4148
|
+
border: 1px solid var(--border);
|
|
4149
|
+
border-radius: var(--r-card);
|
|
4150
|
+
box-shadow: var(--shadow);
|
|
4151
|
+
font-family: var(--font-sans);
|
|
4152
|
+
}
|
|
4153
|
+
|
|
4154
|
+
.dashboard-title {
|
|
4155
|
+
font-family: var(--font-sans);
|
|
4156
|
+
font-size: var(--fs-h1);
|
|
4157
|
+
font-weight: var(--fw-h1);
|
|
4158
|
+
letter-spacing: var(--ls-h1);
|
|
4159
|
+
color: var(--text);
|
|
4160
|
+
}
|
|
4161
|
+
|
|
4162
|
+
.dashboard-card-title {
|
|
4163
|
+
font-family: var(--font-sans);
|
|
4164
|
+
font-size: var(--fs-card-title);
|
|
4165
|
+
font-weight: var(--fw-card-title);
|
|
4166
|
+
letter-spacing: 0;
|
|
4167
|
+
color: var(--text);
|
|
4168
|
+
}
|
|
4169
|
+
|
|
4170
|
+
/* 11px/800 uppercase over a 30px/800 number, tabular so the columns of
|
|
4171
|
+
figures line up - the design's KPI, and the same header type the table
|
|
4172
|
+
card already uses. */
|
|
4173
|
+
.dashboard-kpi-label {
|
|
4174
|
+
font-family: var(--font-sans);
|
|
4175
|
+
font-size: var(--fs-table-head);
|
|
4176
|
+
font-weight: var(--fw-table-head);
|
|
4177
|
+
letter-spacing: var(--ls-table-head);
|
|
4178
|
+
text-transform: uppercase;
|
|
4179
|
+
color: var(--muted);
|
|
4180
|
+
}
|
|
4181
|
+
|
|
4182
|
+
.dashboard-kpi-value {
|
|
4183
|
+
font-family: var(--font-sans);
|
|
4184
|
+
font-size: var(--fs-kpi);
|
|
4185
|
+
font-weight: var(--fw-kpi);
|
|
4186
|
+
letter-spacing: var(--ls-kpi);
|
|
4187
|
+
line-height: 1.1;
|
|
4188
|
+
color: var(--text);
|
|
4189
|
+
font-variant-numeric: tabular-nums;
|
|
4192
4190
|
}
|
|
4193
4191
|
|
|
4194
4192
|
.dashboard-section-grid {
|
|
@@ -4209,7 +4207,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4209
4207
|
}
|
|
4210
4208
|
|
|
4211
4209
|
.figma-panel {
|
|
4212
|
-
border-color:
|
|
4210
|
+
border-color: rgba(var(--v-border-color), var(--v-border-opacity));
|
|
4213
4211
|
box-shadow: none;
|
|
4214
4212
|
min-height: 276px;
|
|
4215
4213
|
padding: 26px 28px 24px;
|
|
@@ -4223,14 +4221,17 @@ function formatDashboardTime(value?: string) {
|
|
|
4223
4221
|
min-height: 18px;
|
|
4224
4222
|
}
|
|
4225
4223
|
|
|
4224
|
+
/* The panel heading is the design's card title: 15.5px/800, sentence case. It
|
|
4225
|
+
was a 12px/900 uppercase label from the earlier Figma. */
|
|
4226
4226
|
.figma-panel-header h2 {
|
|
4227
|
-
color:
|
|
4228
|
-
font-
|
|
4229
|
-
font-
|
|
4227
|
+
color: var(--text);
|
|
4228
|
+
font-family: var(--font-sans);
|
|
4229
|
+
font-size: var(--fs-card-title);
|
|
4230
|
+
font-weight: var(--fw-card-title);
|
|
4230
4231
|
letter-spacing: 0;
|
|
4231
4232
|
line-height: 1.2;
|
|
4232
4233
|
margin: 0;
|
|
4233
|
-
text-transform:
|
|
4234
|
+
text-transform: none;
|
|
4234
4235
|
}
|
|
4235
4236
|
|
|
4236
4237
|
.figma-panel-action,
|
|
@@ -4238,7 +4239,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4238
4239
|
appearance: none;
|
|
4239
4240
|
background: transparent;
|
|
4240
4241
|
border: 0;
|
|
4241
|
-
color:
|
|
4242
|
+
color: rgb(var(--v-theme-primary));
|
|
4242
4243
|
cursor: pointer;
|
|
4243
4244
|
font-size: 12px;
|
|
4244
4245
|
font-weight: 800;
|
|
@@ -4248,7 +4249,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4248
4249
|
}
|
|
4249
4250
|
|
|
4250
4251
|
.facility-booking-modal {
|
|
4251
|
-
border: 1px solid
|
|
4252
|
+
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
|
4252
4253
|
box-shadow: 0 18px 48px rgba(15, 35, 54, 0.18);
|
|
4253
4254
|
}
|
|
4254
4255
|
|
|
@@ -4269,7 +4270,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4269
4270
|
}
|
|
4270
4271
|
|
|
4271
4272
|
.facility-booking-summary-label {
|
|
4272
|
-
color:
|
|
4273
|
+
color: rgb(var(--v-theme-primary));
|
|
4273
4274
|
font-size: 16px;
|
|
4274
4275
|
font-weight: 500;
|
|
4275
4276
|
line-height: 1.25;
|
|
@@ -4289,7 +4290,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4289
4290
|
}
|
|
4290
4291
|
|
|
4291
4292
|
.facility-booking-summary-dots {
|
|
4292
|
-
border-bottom: 2px dotted
|
|
4293
|
+
border-bottom: 2px dotted rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
|
4293
4294
|
display: block;
|
|
4294
4295
|
height: 1px;
|
|
4295
4296
|
min-width: 32px;
|
|
@@ -4297,7 +4298,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4297
4298
|
|
|
4298
4299
|
.facility-booking-summary-value,
|
|
4299
4300
|
.facility-booking-total-label {
|
|
4300
|
-
color:
|
|
4301
|
+
color: rgb(var(--v-theme-on-surface));
|
|
4301
4302
|
font-size: 16px;
|
|
4302
4303
|
font-weight: 800;
|
|
4303
4304
|
line-height: 1.25;
|
|
@@ -4320,8 +4321,8 @@ function formatDashboardTime(value?: string) {
|
|
|
4320
4321
|
|
|
4321
4322
|
.figma-list-row {
|
|
4322
4323
|
align-items: center;
|
|
4323
|
-
background:
|
|
4324
|
-
border: 1px solid
|
|
4324
|
+
background: rgb(var(--v-theme-surface-bright));
|
|
4325
|
+
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
|
4325
4326
|
border-radius: 6px;
|
|
4326
4327
|
display: grid;
|
|
4327
4328
|
gap: 10px;
|
|
@@ -4332,7 +4333,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4332
4333
|
}
|
|
4333
4334
|
|
|
4334
4335
|
.figma-list-row:hover {
|
|
4335
|
-
border-color:
|
|
4336
|
+
border-color: rgba(var(--v-border-color), var(--v-border-opacity));
|
|
4336
4337
|
box-shadow: 0 6px 14px rgba(15, 44, 69, 0.05);
|
|
4337
4338
|
}
|
|
4338
4339
|
|
|
@@ -4341,7 +4342,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4341
4342
|
}
|
|
4342
4343
|
|
|
4343
4344
|
.figma-list-main strong {
|
|
4344
|
-
color:
|
|
4345
|
+
color: rgb(var(--v-theme-on-surface));
|
|
4345
4346
|
display: block;
|
|
4346
4347
|
font-size: 12px;
|
|
4347
4348
|
font-weight: 800;
|
|
@@ -4352,7 +4353,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4352
4353
|
}
|
|
4353
4354
|
|
|
4354
4355
|
.figma-list-main p {
|
|
4355
|
-
color:
|
|
4356
|
+
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
|
4356
4357
|
font-size: 11px;
|
|
4357
4358
|
font-weight: 700;
|
|
4358
4359
|
line-height: 1.3;
|
|
@@ -4377,30 +4378,30 @@ function formatDashboardTime(value?: string) {
|
|
|
4377
4378
|
|
|
4378
4379
|
.figma-event-dot-info,
|
|
4379
4380
|
.figma-event-dot-neutral {
|
|
4380
|
-
background:
|
|
4381
|
-
border: 2px solid
|
|
4381
|
+
background: var(--info-bg);
|
|
4382
|
+
border: 2px solid var(--info);
|
|
4382
4383
|
}
|
|
4383
4384
|
|
|
4384
4385
|
.figma-event-dot-success {
|
|
4385
|
-
background:
|
|
4386
|
-
border: 2px solid
|
|
4386
|
+
background: var(--ok-bg);
|
|
4387
|
+
border: 2px solid var(--ok);
|
|
4387
4388
|
}
|
|
4388
4389
|
|
|
4389
4390
|
.figma-event-dot-danger {
|
|
4390
|
-
background:
|
|
4391
|
-
border: 2px solid
|
|
4391
|
+
background: var(--err-bg);
|
|
4392
|
+
border: 2px solid var(--err);
|
|
4392
4393
|
}
|
|
4393
4394
|
|
|
4394
4395
|
.figma-event-dot-warning {
|
|
4395
|
-
background:
|
|
4396
|
-
border: 2px solid
|
|
4396
|
+
background: var(--warn-bg);
|
|
4397
|
+
border: 2px solid var(--warn);
|
|
4397
4398
|
}
|
|
4398
4399
|
|
|
4399
4400
|
.active-patrol-row {
|
|
4400
4401
|
align-items: center;
|
|
4401
|
-
background-color:
|
|
4402
|
-
border: 1px solid
|
|
4403
|
-
border-radius:
|
|
4402
|
+
background-color: var(--card);
|
|
4403
|
+
border: 1px solid var(--border);
|
|
4404
|
+
border-radius: var(--r-inner-lg);
|
|
4404
4405
|
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.02);
|
|
4405
4406
|
display: grid;
|
|
4406
4407
|
gap: 10px;
|
|
@@ -4416,7 +4417,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4416
4417
|
}
|
|
4417
4418
|
|
|
4418
4419
|
.active-patrol-main strong {
|
|
4419
|
-
color:
|
|
4420
|
+
color: rgb(var(--v-theme-on-surface));
|
|
4420
4421
|
display: block;
|
|
4421
4422
|
font-size: 13px;
|
|
4422
4423
|
font-weight: 700;
|
|
@@ -4426,7 +4427,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4426
4427
|
}
|
|
4427
4428
|
|
|
4428
4429
|
.active-patrol-main span {
|
|
4429
|
-
color:
|
|
4430
|
+
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
|
4430
4431
|
display: block;
|
|
4431
4432
|
font-size: 11px;
|
|
4432
4433
|
line-height: 1.25;
|
|
@@ -4442,8 +4443,8 @@ function formatDashboardTime(value?: string) {
|
|
|
4442
4443
|
|
|
4443
4444
|
.active-patrol-assignee {
|
|
4444
4445
|
align-items: center;
|
|
4445
|
-
background:
|
|
4446
|
-
border: 1px solid
|
|
4446
|
+
background: rgba(var(--v-theme-on-surface), 0.05);
|
|
4447
|
+
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
|
4447
4448
|
border-radius: 999px;
|
|
4448
4449
|
display: inline-flex;
|
|
4449
4450
|
flex: 1 1 auto;
|
|
@@ -4453,8 +4454,23 @@ function formatDashboardTime(value?: string) {
|
|
|
4453
4454
|
padding: 2px 8px 2px 3px;
|
|
4454
4455
|
}
|
|
4455
4456
|
|
|
4457
|
+
/**
|
|
4458
|
+
* Carried from Phase 1: `AvatarMain` colours each person from their NAME, and
|
|
4459
|
+
* writes WHITE initials on whatever tint it picks - 2.34:1 on this dashboard.
|
|
4460
|
+
* That is right in a members list, where the colour tells two people apart,
|
|
4461
|
+
* and wrong on a dashboard, where the same face appears in four panels.
|
|
4462
|
+
*
|
|
4463
|
+
* The component is left alone - Phase 2 took exactly this route for the top
|
|
4464
|
+
* bar's own avatar - and the dashboard paints every avatar it draws with the
|
|
4465
|
+
* design's accent pair instead. One rule, all seven call sites.
|
|
4466
|
+
*/
|
|
4467
|
+
.unified-dashboard :deep(.v-avatar) {
|
|
4468
|
+
background: var(--accent-soft) !important;
|
|
4469
|
+
color: var(--accent-text) !important;
|
|
4470
|
+
}
|
|
4471
|
+
|
|
4456
4472
|
.active-patrol-assignee span {
|
|
4457
|
-
color:
|
|
4473
|
+
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
|
4458
4474
|
font-size: 11px;
|
|
4459
4475
|
font-weight: 600;
|
|
4460
4476
|
line-height: 1.2;
|
|
@@ -4484,10 +4500,10 @@ function formatDashboardTime(value?: string) {
|
|
|
4484
4500
|
|
|
4485
4501
|
.active-patrol-more-pill {
|
|
4486
4502
|
align-items: center;
|
|
4487
|
-
background:
|
|
4488
|
-
border: 1px solid
|
|
4503
|
+
background: rgba(var(--v-theme-on-surface), 0.05);
|
|
4504
|
+
border: 1px solid rgba(var(--v-border-color), var(--v-border-opacity));
|
|
4489
4505
|
border-radius: 999px;
|
|
4490
|
-
color:
|
|
4506
|
+
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
|
4491
4507
|
display: inline-flex;
|
|
4492
4508
|
flex: 0 0 auto;
|
|
4493
4509
|
font-size: 11px;
|
|
@@ -4507,11 +4523,11 @@ function formatDashboardTime(value?: string) {
|
|
|
4507
4523
|
}
|
|
4508
4524
|
|
|
4509
4525
|
.active-patrol-tooltip::after {
|
|
4510
|
-
background:
|
|
4511
|
-
border-radius:
|
|
4526
|
+
background: var(--text);
|
|
4527
|
+
border-radius: var(--r-inner-sm);
|
|
4512
4528
|
bottom: calc(100% + 8px);
|
|
4513
|
-
box-shadow:
|
|
4514
|
-
color:
|
|
4529
|
+
box-shadow: var(--shadow-menu);
|
|
4530
|
+
color: var(--card);
|
|
4515
4531
|
content: attr(data-tooltip);
|
|
4516
4532
|
font-size: 11px;
|
|
4517
4533
|
font-weight: 600;
|
|
@@ -4541,6 +4557,28 @@ function formatDashboardTime(value?: string) {
|
|
|
4541
4557
|
}
|
|
4542
4558
|
}
|
|
4543
4559
|
|
|
4560
|
+
/**
|
|
4561
|
+
* Carried from Phase 1: the dashboard scrolled sideways at 360. This row is a
|
|
4562
|
+
* four-column grid whose last two columns are `max-content`, so on a phone the
|
|
4563
|
+
* assignee pill, the status pill and the action button cannot fit beside a
|
|
4564
|
+
* 120px title and the row pushes ~39px past the viewport.
|
|
4565
|
+
*
|
|
4566
|
+
* Below 600 the four columns become one. Nothing is hidden, dropped or
|
|
4567
|
+
* reordered - the same four blocks, stacked in the same order.
|
|
4568
|
+
*/
|
|
4569
|
+
@media (max-width: 599.98px) {
|
|
4570
|
+
.active-patrol-row {
|
|
4571
|
+
grid-template-columns: minmax(0, 1fr);
|
|
4572
|
+
}
|
|
4573
|
+
|
|
4574
|
+
.active-patrol-action,
|
|
4575
|
+
.active-patrol-statuses,
|
|
4576
|
+
.active-patrol-assignees {
|
|
4577
|
+
justify-self: start;
|
|
4578
|
+
text-align: left;
|
|
4579
|
+
}
|
|
4580
|
+
}
|
|
4581
|
+
|
|
4544
4582
|
.figma-icon-badge {
|
|
4545
4583
|
align-items: center;
|
|
4546
4584
|
border-radius: 50%;
|
|
@@ -4552,28 +4590,28 @@ function formatDashboardTime(value?: string) {
|
|
|
4552
4590
|
}
|
|
4553
4591
|
|
|
4554
4592
|
.figma-icon-badge-danger {
|
|
4555
|
-
background:
|
|
4556
|
-
color:
|
|
4593
|
+
background: var(--err-bg);
|
|
4594
|
+
color: var(--err);
|
|
4557
4595
|
}
|
|
4558
4596
|
|
|
4559
4597
|
.figma-icon-badge-info {
|
|
4560
|
-
background:
|
|
4561
|
-
color:
|
|
4598
|
+
background: var(--info-bg);
|
|
4599
|
+
color: var(--info);
|
|
4562
4600
|
}
|
|
4563
4601
|
|
|
4564
4602
|
.figma-icon-badge-success {
|
|
4565
|
-
background:
|
|
4566
|
-
color:
|
|
4603
|
+
background: var(--ok-bg);
|
|
4604
|
+
color: var(--ok);
|
|
4567
4605
|
}
|
|
4568
4606
|
|
|
4569
4607
|
.figma-icon-badge-warning {
|
|
4570
|
-
background:
|
|
4571
|
-
color:
|
|
4608
|
+
background: var(--warn-bg);
|
|
4609
|
+
color: var(--warn);
|
|
4572
4610
|
}
|
|
4573
4611
|
|
|
4574
4612
|
.figma-icon-badge-neutral {
|
|
4575
|
-
background:
|
|
4576
|
-
color:
|
|
4613
|
+
background: var(--hover);
|
|
4614
|
+
color: var(--text2);
|
|
4577
4615
|
}
|
|
4578
4616
|
|
|
4579
4617
|
.figma-status-stack {
|
|
@@ -4587,7 +4625,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4587
4625
|
|
|
4588
4626
|
.figma-status-label {
|
|
4589
4627
|
align-items: center;
|
|
4590
|
-
color:
|
|
4628
|
+
color: rgb(var(--v-theme-on-surface));
|
|
4591
4629
|
display: flex;
|
|
4592
4630
|
font-size: 12px;
|
|
4593
4631
|
font-weight: 800;
|
|
@@ -4597,13 +4635,13 @@ function formatDashboardTime(value?: string) {
|
|
|
4597
4635
|
}
|
|
4598
4636
|
|
|
4599
4637
|
.figma-status-label strong {
|
|
4600
|
-
color:
|
|
4638
|
+
color: rgb(var(--v-theme-on-surface));
|
|
4601
4639
|
font-size: 12px;
|
|
4602
4640
|
font-weight: 900;
|
|
4603
4641
|
}
|
|
4604
4642
|
|
|
4605
4643
|
.figma-progress-track {
|
|
4606
|
-
background:
|
|
4644
|
+
background: rgba(var(--v-theme-on-surface), 0.08);
|
|
4607
4645
|
border-radius: 999px;
|
|
4608
4646
|
height: 6px;
|
|
4609
4647
|
overflow: hidden;
|
|
@@ -4624,9 +4662,9 @@ function formatDashboardTime(value?: string) {
|
|
|
4624
4662
|
|
|
4625
4663
|
.feedback-row {
|
|
4626
4664
|
align-items: center;
|
|
4627
|
-
background:
|
|
4628
|
-
border: 1px solid
|
|
4629
|
-
border-radius:
|
|
4665
|
+
background: var(--card);
|
|
4666
|
+
border: 1px solid var(--border);
|
|
4667
|
+
border-radius: var(--r-inner-lg);
|
|
4630
4668
|
display: grid;
|
|
4631
4669
|
gap: 16px;
|
|
4632
4670
|
grid-template-columns: minmax(180px, 225px) minmax(130px, 175px) 100px auto;
|
|
@@ -4635,8 +4673,41 @@ function formatDashboardTime(value?: string) {
|
|
|
4635
4673
|
transition: border-color 0.16s ease, box-shadow 0.16s ease;
|
|
4636
4674
|
}
|
|
4637
4675
|
|
|
4676
|
+
/**
|
|
4677
|
+
* The property-mode feedback row is four flex children that each ask for at
|
|
4678
|
+
* least 140px, so on a 360px phone the status pill and the View button were
|
|
4679
|
+
* clipped by the card edge - visible, but cut in half. It wraps now, and below
|
|
4680
|
+
* 600 each block takes the full width: same four blocks, same order.
|
|
4681
|
+
*/
|
|
4682
|
+
.dashboard-feedback-row {
|
|
4683
|
+
flex-wrap: wrap;
|
|
4684
|
+
gap: 12px;
|
|
4685
|
+
}
|
|
4686
|
+
|
|
4687
|
+
@media (max-width: 599.98px) {
|
|
4688
|
+
.dashboard-feedback-row > div {
|
|
4689
|
+
flex: 1 1 100% !important;
|
|
4690
|
+
justify-content: flex-start !important;
|
|
4691
|
+
text-align: left !important;
|
|
4692
|
+
}
|
|
4693
|
+
}
|
|
4694
|
+
|
|
4695
|
+
/* Same story as the patrol row: four fixed-ish columns need ~600px, so on a
|
|
4696
|
+
phone the status pill and the View button were clipped by the card edge.
|
|
4697
|
+
One column below 600, same blocks, same order. */
|
|
4698
|
+
@media (max-width: 599.98px) {
|
|
4699
|
+
.feedback-row {
|
|
4700
|
+
grid-template-columns: minmax(0, 1fr);
|
|
4701
|
+
}
|
|
4702
|
+
|
|
4703
|
+
.feedback-status-pill,
|
|
4704
|
+
.feedback-action {
|
|
4705
|
+
justify-self: start;
|
|
4706
|
+
}
|
|
4707
|
+
}
|
|
4708
|
+
|
|
4638
4709
|
.feedback-row:hover {
|
|
4639
|
-
border-color:
|
|
4710
|
+
border-color: rgba(var(--v-border-color), var(--v-border-opacity));
|
|
4640
4711
|
box-shadow: 0 6px 14px rgba(15, 44, 69, 0.04);
|
|
4641
4712
|
}
|
|
4642
4713
|
|
|
@@ -4645,7 +4716,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4645
4716
|
}
|
|
4646
4717
|
|
|
4647
4718
|
.feedback-summary strong {
|
|
4648
|
-
color:
|
|
4719
|
+
color: rgb(var(--v-theme-on-surface));
|
|
4649
4720
|
display: block;
|
|
4650
4721
|
font-size: 12px;
|
|
4651
4722
|
font-weight: 800;
|
|
@@ -4656,7 +4727,7 @@ function formatDashboardTime(value?: string) {
|
|
|
4656
4727
|
}
|
|
4657
4728
|
|
|
4658
4729
|
.feedback-summary p {
|
|
4659
|
-
color:
|
|
4730
|
+
color: rgba(var(--v-theme-on-surface), var(--v-medium-emphasis-opacity));
|
|
4660
4731
|
font-size: 12px;
|
|
4661
4732
|
font-weight: 500;
|
|
4662
4733
|
line-height: 1.35;
|
|
@@ -4679,11 +4750,13 @@ function formatDashboardTime(value?: string) {
|
|
|
4679
4750
|
white-space: nowrap;
|
|
4680
4751
|
}
|
|
4681
4752
|
|
|
4753
|
+
/* Carried from Phase 1: the initials measured 1.26:1 in dark mode, because the
|
|
4754
|
+
tint was a literal light blue whatever the theme. */
|
|
4682
4755
|
.feedback-avatar {
|
|
4683
4756
|
align-items: center;
|
|
4684
|
-
background:
|
|
4757
|
+
background: var(--accent-soft);
|
|
4685
4758
|
border-radius: 50%;
|
|
4686
|
-
color:
|
|
4759
|
+
color: var(--accent-text);
|
|
4687
4760
|
display: inline-flex;
|
|
4688
4761
|
flex-shrink: 0;
|
|
4689
4762
|
font-size: 11px;
|
|
@@ -4702,31 +4775,32 @@ function formatDashboardTime(value?: string) {
|
|
|
4702
4775
|
white-space: nowrap;
|
|
4703
4776
|
}
|
|
4704
4777
|
|
|
4778
|
+
/* The other two carried Phase 1 items: hard-coded chips. */
|
|
4705
4779
|
.feedback-status-pill-completed {
|
|
4706
|
-
background:
|
|
4707
|
-
color:
|
|
4780
|
+
background: var(--ok-bg);
|
|
4781
|
+
color: var(--ok);
|
|
4708
4782
|
}
|
|
4709
4783
|
|
|
4710
4784
|
.feedback-status-pill-progress {
|
|
4711
|
-
background:
|
|
4712
|
-
color:
|
|
4785
|
+
background: var(--warn-bg);
|
|
4786
|
+
color: var(--warn);
|
|
4713
4787
|
}
|
|
4714
4788
|
|
|
4715
4789
|
.feedback-status-pill-danger {
|
|
4716
|
-
background:
|
|
4717
|
-
color:
|
|
4790
|
+
background: var(--err-bg);
|
|
4791
|
+
color: var(--err);
|
|
4718
4792
|
}
|
|
4719
4793
|
|
|
4720
4794
|
.feedback-status-pill-todo {
|
|
4721
|
-
background:
|
|
4722
|
-
color:
|
|
4795
|
+
background: var(--hover);
|
|
4796
|
+
color: var(--text2);
|
|
4723
4797
|
}
|
|
4724
4798
|
|
|
4725
4799
|
.feedback-view-button {
|
|
4726
4800
|
appearance: none;
|
|
4727
4801
|
background: transparent;
|
|
4728
4802
|
border: 0;
|
|
4729
|
-
color:
|
|
4803
|
+
color: rgb(var(--v-theme-primary));
|
|
4730
4804
|
cursor: pointer;
|
|
4731
4805
|
font-size: 12px;
|
|
4732
4806
|
font-weight: 800;
|