@7365admin1/layer-common 3.2.1 → 3.2.2-staging.101

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 (126) hide show
  1. package/.changeset/camera-wall-gated-endpoint.md +47 -0
  2. package/.changeset/camera-wall-plain-english.md +60 -0
  3. package/.changeset/camera-wall-selection-and-guidance.md +65 -0
  4. package/.changeset/dark-primary-contrast.md +39 -0
  5. package/.changeset/dashboard-dark-theme-contrast.md +15 -0
  6. package/.changeset/notification-preferences.md +17 -0
  7. package/.changeset/pm-sidebar-grouping-and-list-scaffold.md +27 -0
  8. package/.changeset/service-provider-invitation-actions.md +28 -0
  9. package/assets/css/primitives.css +680 -0
  10. package/assets/css/screens.css +541 -0
  11. package/assets/css/shell.css +258 -0
  12. package/assets/css/tokens.css +220 -0
  13. package/components/AccessCardQrTagging.vue +1 -1
  14. package/components/AccessManagement.vue +53 -72
  15. package/components/AppButton.vue +52 -0
  16. package/components/AppCard.vue +20 -0
  17. package/components/AppDateField.vue +35 -0
  18. package/components/AppField.vue +51 -0
  19. package/components/AppKpiTile.vue +65 -0
  20. package/components/AppSegmented.vue +38 -0
  21. package/components/AppSelect.vue +203 -0
  22. package/components/AreaChecklistHistoryLogs.vue +51 -44
  23. package/components/AreaChecklistHistoryMain.vue +6 -2
  24. package/components/AreaMain.vue +9 -17
  25. package/components/AttendanceMain.vue +4 -3
  26. package/components/Avatar/Main.vue +54 -2
  27. package/components/BillingMain.vue +26 -30
  28. package/components/BuildingManagement/buildings.vue +27 -38
  29. package/components/BuildingManagement/units.vue +26 -42
  30. package/components/BulletinBoardManagement.vue +23 -10
  31. package/components/CameraWall.vue +1034 -0
  32. package/components/CameraWallTile.vue +818 -0
  33. package/components/CardToolbar.vue +37 -0
  34. package/components/CleaningScheduleMain.vue +29 -46
  35. package/components/ClientMain.vue +90 -78
  36. package/components/DashboardEmptyState.vue +11 -1
  37. package/components/DashboardMain.vue +349 -275
  38. package/components/DashboardPanel.vue +1 -1
  39. package/components/DocumentManagement.vue +129 -93
  40. package/components/EntryPassInformation.vue +4 -4
  41. package/components/EntryPassMain.vue +49 -27
  42. package/components/EquipmentItemMain.vue +4 -6
  43. package/components/EquipmentManagementMain.vue +9 -7
  44. package/components/FeedbackMain.vue +42 -56
  45. package/components/FormDialog.vue +60 -21
  46. package/components/HidAccessLogDashboard.vue +119 -44
  47. package/components/HidCameraCaptureDialog.vue +199 -0
  48. package/components/HidIntercomManagement.vue +825 -202
  49. package/components/HidQrCodeConfiguration.vue +927 -93
  50. package/components/HidServiceSettingsPanel.vue +20 -1
  51. package/components/HidUserEnrollment.vue +454 -106
  52. package/components/InvitationMain.vue +46 -61
  53. package/components/Layout/Header.vue +289 -37
  54. package/components/Layout/NavigationDrawer.vue +340 -30
  55. package/components/ManageChecklistMain.vue +17 -17
  56. package/components/MemberMain.vue +79 -60
  57. package/components/MyAttendanceMain.vue +3 -5
  58. package/components/NavigationItem.vue +9 -0
  59. package/components/Nfc/NFCPatrolRouteMain.vue +116 -103
  60. package/components/NotificationSettings.vue +361 -0
  61. package/components/OnlineFormConfigurationForm.vue +620 -224
  62. package/components/OnlineFormFill.vue +36 -8
  63. package/components/OnlineFormsConfiguration.vue +7 -3
  64. package/components/PageHeader.vue +43 -0
  65. package/components/PassInformation.vue +104 -45
  66. package/components/QrTemplate/CreditCardLandscape.vue +19 -12
  67. package/components/QrTemplate/PrintDialog.vue +209 -196
  68. package/components/RolePermissionMain.vue +184 -91
  69. package/components/ScanVisitorQRCode.vue +35 -7
  70. package/components/ScheduleAreaMain.vue +15 -49
  71. package/components/ScheduleTaskMain.vue +23 -26
  72. package/components/ScheduleTastTicketMain.vue +18 -43
  73. package/components/ServiceProviderInvitationPrompt.vue +150 -0
  74. package/components/ServiceProviderMain.vue +346 -157
  75. package/components/SiteSettings.vue +25 -10
  76. package/components/SiteSettingsWorkOrder.vue +61 -30
  77. package/components/SpecificAttr.vue +10 -2
  78. package/components/StatusChip.vue +93 -0
  79. package/components/StockCard.vue +17 -12
  80. package/components/SwitchContext.vue +33 -1
  81. package/components/TableHygiene.vue +29 -46
  82. package/components/TableList.vue +1 -1
  83. package/components/TableListSecondary.vue +1 -1
  84. package/components/TableMain.vue +161 -77
  85. package/components/TableV3.vue +61 -66
  86. package/components/UnitMain.vue +9 -17
  87. package/components/VehicleManagement.vue +20 -9
  88. package/components/VisitorForm.vue +294 -78
  89. package/components/VisitorManagement.vue +221 -71
  90. package/components/VisitorSocketPopUp.vue +56 -2
  91. package/components/WorkOrder/Main.vue +42 -51
  92. package/composables/useComment.ts +3 -3
  93. package/composables/useHidAmico.ts +151 -0
  94. package/composables/useHidNavigation.ts +0 -7
  95. package/composables/useLocalAuth.ts +9 -36
  96. package/composables/useNotificationPreference.ts +87 -0
  97. package/composables/useOnlineFormPages.ts +2 -0
  98. package/composables/useOrg.ts +1 -1
  99. package/composables/useRole.ts +22 -0
  100. package/composables/useServiceProviderInvitation.ts +145 -0
  101. package/composables/useSipWebPhone.ts +336 -0
  102. package/composables/useSiteSettings.ts +50 -0
  103. package/composables/useThemePreference.ts +63 -0
  104. package/composables/useVisitor.ts +6 -1
  105. package/composables/useVisitorSocket.ts +26 -0
  106. package/composables/useWebUsb.ts +127 -37
  107. package/nuxt.config.ts +31 -0
  108. package/package.json +4 -1
  109. package/pages/[org]/[site]/access-mgmt/intercom/index.vue +1 -1
  110. package/pages/notification-settings.vue +19 -0
  111. package/plugins/secure-member.client.ts +21 -56
  112. package/plugins/vuetify.ts +68 -9
  113. package/test/visitor-socket.test.mjs +36 -0
  114. package/types/org.d.ts +2 -0
  115. package/types/site.d.ts +71 -0
  116. package/utils/camera-wall.test.ts +571 -0
  117. package/utils/camera-wall.ts +926 -0
  118. package/utils/nav-sections.test.ts +190 -0
  119. package/utils/nav-sections.ts +151 -0
  120. package/utils/status.test.ts +77 -0
  121. package/utils/status.ts +90 -0
  122. package/utils/theme.test.ts +534 -0
  123. package/utils/theme.ts +294 -0
  124. package/components/HidIdentityMapping.vue +0 -975
  125. package/middleware/member.ts +0 -4
  126. package/pages/[org]/[site]/access-mgmt/identity-mapping/index.vue +0 -23
@@ -1,8 +1,13 @@
1
1
  <template>
2
2
  <v-row no-gutters>
3
- <v-expansion-panels multiple v-model="openPanels">
3
+ <!--
4
+ The design draws settings as a stack of bordered sections with one open
5
+ at a time. `multiple` is BEHAVIOUR - which sections a user may have open
6
+ together - so it is left exactly as it was and only the drawing changes.
7
+ -->
8
+ <v-expansion-panels multiple v-model="openPanels" class="screen-accordion">
4
9
  <!-- SITE SETTINGS -->
5
- <v-expansion-panel v-if="canManageSiteInformation" color="primary">
10
+ <v-expansion-panel v-if="canManageSiteInformation">
6
11
  <v-expansion-panel-title>
7
12
  <v-icon class="mr-2">mdi-cog</v-icon>
8
13
  Site Information
@@ -22,7 +27,7 @@
22
27
  <v-img v-if="coverPhotoUrl" :src="coverPhotoUrl" aspect-ratio="16/9" cover rounded="lg"
23
28
  class="w-100 border" />
24
29
  <div v-else
25
- class="w-100 d-flex align-center justify-center rounded-lg bg-grey-lighten-4 border border-dashed"
30
+ class="w-100 d-flex align-center justify-center rounded-lg border border-dashed site-settings__placeholder"
26
31
  style="aspect-ratio: 16/9">
27
32
  <span class="text-caption text-medium-emphasis">No cover photo uploaded</span>
28
33
  </div>
@@ -76,7 +81,7 @@
76
81
  </v-expansion-panel>
77
82
 
78
83
  <!-- ANPR CAMERA -->
79
- <v-expansion-panel v-if="showAnprCamera && canManageANPRCamera" color="primary">
84
+ <v-expansion-panel v-if="showAnprCamera && canManageANPRCamera">
80
85
  <v-expansion-panel-title>
81
86
  <v-icon class="mr-2">mdi-camera</v-icon>
82
87
  ANPR Camera
@@ -118,7 +123,7 @@
118
123
  </v-expansion-panel>
119
124
 
120
125
  <!-- CCTV CAMERA -->
121
- <v-expansion-panel v-if="showCctvCamera && canManageCCTVCamera" color="primary">
126
+ <v-expansion-panel v-if="showCctvCamera && canManageCCTVCamera">
122
127
  <v-expansion-panel-title>
123
128
  <v-icon class="mr-2">mdi-cctv</v-icon>
124
129
  CCTV Camera
@@ -129,7 +134,7 @@
129
134
  </v-expansion-panel-text>
130
135
  </v-expansion-panel>
131
136
 
132
- <v-expansion-panel v-if="showDeliveryCompanies && canManageDeliveryCompanies" color="primary">
137
+ <v-expansion-panel v-if="showDeliveryCompanies && canManageDeliveryCompanies">
133
138
  <v-expansion-panel-title>
134
139
  <v-icon class="mr-2">mdi-truck</v-icon>
135
140
  Delivery Companies
@@ -140,7 +145,7 @@
140
145
  </v-expansion-panel-text>
141
146
  </v-expansion-panel>
142
147
 
143
- <v-expansion-panel v-if="showResidentVisitors && canManageResidentVisitors" color="primary">
148
+ <v-expansion-panel v-if="showResidentVisitors && canManageResidentVisitors">
144
149
  <v-expansion-panel-title>
145
150
  <v-icon class="mr-2">mdi-car</v-icon>
146
151
  Resident Visitors
@@ -150,7 +155,7 @@
150
155
  </v-expansion-panel-text>
151
156
  </v-expansion-panel>
152
157
 
153
- <v-expansion-panel color="primary">
158
+ <v-expansion-panel>
154
159
  <v-expansion-panel-title>
155
160
  <v-icon class="mr-2">mdi-face-recognition</v-icon>
156
161
  HID Face Reader
@@ -163,7 +168,7 @@
163
168
  @refresh="refreshSiteData"
164
169
  />
165
170
  <v-divider class="my-4" />
166
- <HidQrCodeConfiguration :site="siteId" />
171
+ <HidQrCodeConfiguration :site="siteId" :org="orgId" />
167
172
  </v-expansion-panel-text>
168
173
  </v-expansion-panel>
169
174
 
@@ -266,7 +271,9 @@ const { data: siteData, refresh: refreshSiteData } = await useLazyAsyncData(
266
271
  `site-${props.siteId}`,
267
272
  () => getSiteById(props.siteId)
268
273
  );
269
- const orgId = computed(() => props.orgId || String((siteData.value as any)?.orgId ?? ""));
274
+ const orgId = computed(
275
+ () => props.orgId || String((siteData.value as TSite | null)?.orgId ?? "")
276
+ );
270
277
 
271
278
  watch(
272
279
  siteData,
@@ -419,3 +426,11 @@ const saveANPRSettings = async () => {
419
426
  }
420
427
  };
421
428
  </script>
429
+
430
+ <style scoped>
431
+ /* Was `bg-grey-lighten-4`: a literal light grey, so the empty cover-photo tile
432
+ stayed a white slab on the dark page. */
433
+ .site-settings__placeholder {
434
+ background: var(--thead);
435
+ }
436
+ </style>
@@ -1,33 +1,53 @@
1
1
  <template>
2
- <v-row no-gutters>
3
- <v-expansion-panels multiple v-model="openPanels" >
4
-
5
- <!-- Work Order Settings -->
6
- <v-expansion-panel color="primary">
7
- <v-expansion-panel-title>
8
- <v-icon class="mr-2">mdi-format-list-numbered</v-icon>
9
- Work Order Settings
10
- </v-expansion-panel-title>
11
-
12
- <v-expansion-panel-text>
13
- <v-text-field v-model="prefix" label="Prefix" :disabled="isLoading || !canManageSiteSettings"
14
- @input="handleInput" />
15
-
16
- <v-select v-model="noOfDigits" :items="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" label="No. of Digits"
17
- :disabled="isLoading || !canManageSiteSettings" />
18
-
19
- <v-text-field v-model="orderNumberPreview" label="Preview" readonly />
20
-
21
- <v-btn v-if="canManageSiteSettings" class="mt-2" :loading="isLoading" @click="save">
22
- Save
23
- </v-btn>
24
- </v-expansion-panel-text>
25
- </v-expansion-panel>
26
-
27
- </v-expansion-panels>
28
-
29
- <Snackbar v-model="toast.show" :text="toast.message" :color="toast.color" />
30
- </v-row>
2
+ <div>
3
+ <!-- The page had no heading of its own: the five service apps mount this
4
+ component bare on `[org]/[site]/settings`, so the name only ever
5
+ appeared in the navigation rail. "Settings" is that rail's own label. -->
6
+ <PageHeader title="Settings" />
7
+
8
+ <v-row no-gutters>
9
+ <!--
10
+ `multiple` and which panel opens first are BEHAVIOUR, so they are
11
+ left exactly as they were - `.screen-accordion` only changes the
12
+ drawing, the same way `SiteSettings` already does it.
13
+ -->
14
+ <v-expansion-panels multiple v-model="openPanels" class="screen-accordion">
15
+
16
+ <!-- Work Order Settings -->
17
+ <v-expansion-panel>
18
+ <v-expansion-panel-title>
19
+ <v-icon class="mr-2">mdi-format-list-numbered</v-icon>
20
+ Work Order Settings
21
+ </v-expansion-panel-title>
22
+
23
+ <v-expansion-panel-text>
24
+ <div class="wo-settings__fields">
25
+ <AppField v-model="prefix" label="Prefix"
26
+ :disabled="isLoading || !canManageSiteSettings" @input="handleInput" />
27
+
28
+ <!-- `return-object` keeps the emitted value a NUMBER, which is
29
+ what `createWorkOrderSettings` puts on the wire today. -->
30
+ <AppSelect v-model="noOfDigits" return-object
31
+ :items="[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]" label="No. of Digits"
32
+ :disabled="isLoading || !canManageSiteSettings" />
33
+
34
+ <AppField :model-value="orderNumberPreview" label="Preview" readonly />
35
+ </div>
36
+
37
+ <!-- Still a `v-btn`: `AppButton` has no loading state, and the
38
+ spinner on save is feedback, not decoration. -->
39
+ <v-btn v-if="canManageSiteSettings" class="screen-btn-primary text-none mt-4"
40
+ variant="flat" :loading="isLoading" @click="save">
41
+ Save
42
+ </v-btn>
43
+ </v-expansion-panel-text>
44
+ </v-expansion-panel>
45
+
46
+ </v-expansion-panels>
47
+
48
+ <Snackbar v-model="toast.show" :text="toast.message" :color="toast.color" />
49
+ </v-row>
50
+ </div>
31
51
  </template>
32
52
 
33
53
  <script setup lang="ts">
@@ -173,4 +193,15 @@ function show(message: string, color: string) {
173
193
  toast.message = message
174
194
  toast.color = color
175
195
  }
176
- </script>
196
+ </script>
197
+
198
+ <style scoped>
199
+ /* The design stacks a settings form's fields on one gap, rather than leaning on
200
+ each Vuetify field's own 22px of hint space. */
201
+ .wo-settings__fields {
202
+ display: flex;
203
+ flex-direction: column;
204
+ gap: 16px;
205
+ max-width: 420px;
206
+ }
207
+ </style>
@@ -10,11 +10,19 @@
10
10
  Back
11
11
  </span>
12
12
  </v-col>
13
+ <!--
14
+ THE PAGE TITLE ROW. This wrapper is the whole scaffold for every
15
+ single-attribute form page in the estate (18 callers across 10 apps),
16
+ and its title was a `text-h5` span - Vuetify's 24px/400 Roboto, not
17
+ the design's 22px/800. `PageHeader` is placement only: same string,
18
+ same position, same Back link above it, no card added around content
19
+ that already brings its own.
20
+ -->
13
21
  <v-col cols="12">
14
- <span class="text-h5">{{ props.title }}</span>
22
+ <PageHeader :title="props.title" />
15
23
  </v-col>
16
24
 
17
- <v-col cols="12" class="mt-4">
25
+ <v-col cols="12">
18
26
  <slot name="default"> </slot>
19
27
  </v-col>
20
28
 
@@ -0,0 +1,93 @@
1
+ <!--
2
+ THE STATUS CHIP.
3
+
4
+ A pill in the tone the design assigns to the status WORD, with the 6px
5
+ leading dot. The word -> tone mapping is `utils/status.ts` and is shared, so
6
+ "Open" is the same green on a work order and on a Daily Occurrence Book, and
7
+ a status the design never named comes out neutral rather than guessed.
8
+
9
+ Colour only. The chip prints the label it is given; it does not decide, map,
10
+ translate or shorten a status.
11
+ -->
12
+ <template>
13
+ <span
14
+ class="status-chip"
15
+ :class="[toneClass, { 'status-chip--plain': !dot && !pill, 'status-chip--pill': pill }]"
16
+ >
17
+ <span v-if="dot" class="status-chip__dot" />
18
+ <!-- The slot is for the chips that already carried an icon next to their
19
+ word - a padlock on "Closed - View Only" - so adopting the design's
20
+ pill does not quietly drop it. -->
21
+ <slot>{{ label ?? status }}</slot>
22
+ </span>
23
+ </template>
24
+
25
+ <script setup lang="ts">
26
+ import { statusToneClass } from "../utils/status";
27
+
28
+ const props = defineProps({
29
+ /** The status word - what decides the colour. */
30
+ status: { type: String, default: "" },
31
+ /** What to PRINT, when that differs from the word being matched on. */
32
+ label: { type: String, default: undefined },
33
+ /** The design's tag chips (pass IDs, counts) carry no leading dot. */
34
+ dot: { type: Boolean, default: true },
35
+ /**
36
+ * The handoff draws TWO dotless chips, and they are not the same shape: the
37
+ * 7px-radius 11px tag on a pass, and the 999px 11.5px pill a role name sits
38
+ * in on the Members screen. `pill` picks the second.
39
+ */
40
+ pill: { type: Boolean, default: false },
41
+ /**
42
+ * For the chips that are not a status WORD at all - a countdown, a rating, a
43
+ * count - where the screen has already worked out the meaning and only needs
44
+ * the design's tone. Given, it wins over the word mapping.
45
+ */
46
+ tone: {
47
+ type: String as PropType<"ok" | "warn" | "err" | "info" | "neutral" | "">,
48
+ default: "",
49
+ },
50
+ });
51
+
52
+ const toneClass = computed(() =>
53
+ props.tone ? `tone-${props.tone}` : statusToneClass(props.status)
54
+ );
55
+ </script>
56
+
57
+ <style scoped>
58
+ .status-chip {
59
+ display: inline-flex;
60
+ align-items: center;
61
+ gap: 6px;
62
+ padding: 4px 10px;
63
+ border-radius: var(--r-pill);
64
+ font-family: var(--font-sans);
65
+ font-size: var(--fs-chip-lg);
66
+ font-weight: var(--fw-chip);
67
+ line-height: 1.4;
68
+ white-space: nowrap;
69
+ /* `--tone-bg` is set alongside the colour by the `.tone-*` class - see
70
+ assets/css/tokens.css - so one class carries both halves of the pair the
71
+ contrast was measured on. */
72
+ background: var(--tone-bg);
73
+ }
74
+
75
+ .status-chip--plain {
76
+ border-radius: var(--r-tag);
77
+ font-size: var(--fs-chip);
78
+ }
79
+
80
+ /* The role tag: `padding:3px 10px;border-radius:999px;font-size:11.5px`. */
81
+ .status-chip--pill {
82
+ padding: 3px 10px;
83
+ font-size: var(--fs-chip);
84
+ }
85
+
86
+ .status-chip__dot {
87
+ width: 6px;
88
+ height: 6px;
89
+ border-radius: var(--r-pill);
90
+ background: currentColor;
91
+ flex: 0 0 6px;
92
+ }
93
+ </style>
@@ -5,15 +5,18 @@
5
5
  color="page-background-color fill-height header-row"
6
6
  >
7
7
  <v-col cols="12" sm="12" md="11" lg="12" xl="12">
8
- <v-row no-gutters class="mb-4">
9
- <v-col cols="auto">
10
- <v-btn variant="text" color="primary" class="text-none" @click="back">
11
- <v-icon left>mdi-arrow-left</v-icon>
8
+ <!-- The loose Back link above the card becomes the design's title row -
9
+ the page name on the left, its action right-aligned on the same line.
10
+ `title` was already declared here and never drawn. -->
11
+ <PageHeader :title="title">
12
+ <template #actions>
13
+ <AppButton variant="ghost" icon="mdi-arrow-left" @click="back">
12
14
  Back
13
- </v-btn>
14
- </v-col>
15
- </v-row>
16
- <v-card class="pa-5 position-relative rounded-lg">
15
+ </AppButton>
16
+ </template>
17
+ </PageHeader>
18
+
19
+ <AppCard class="pa-5 position-relative">
17
20
  <!-- Stock Information -->
18
21
  <v-row class="pt-2">
19
22
  <v-col cols="12">
@@ -104,7 +107,7 @@
104
107
  </TableMain>
105
108
  </v-col>
106
109
  </v-row>
107
- </v-card>
110
+ </AppCard>
108
111
  </v-col>
109
112
  </v-row>
110
113
  </template>
@@ -181,9 +184,11 @@ watchEffect(() => {
181
184
  </script>
182
185
 
183
186
  <style scoped>
184
- .text-fontgray {
185
- color: #7e7e7e;
186
- }
187
+ /* The scoped `.text-fontgray { color: #7e7e7e }` that used to sit here is gone.
188
+ It out-specified the layer's tokenised rule in `assets/css/screens.css`, which
189
+ is why these four field labels were the estate's one measured 4.06:1 - the
190
+ same fixed grey in both themes. The surface under them is `AppCard`, which is
191
+ itself tokenised, so the ink can safely follow the theme. */
187
192
 
188
193
  :deep() .v-table .v-table__wrapper > table > thead > tr > th:not(:last-child) {
189
194
  border-right: thin solid rgba(var(--v-border-color), var(--v-border-opacity));
@@ -15,7 +15,10 @@
15
15
  :to="props.route"
16
16
  class="text-subtitle-2 font-weight-bold"
17
17
  >
18
- <v-list-item-title class="text-truncate">
18
+ <!-- The design prints the organisation and site names in full.
19
+ Vuetify's list-item title truncates by default, which cut them
20
+ to "Property Managem…" / "Seventh Cond…" in the 252px rail. -->
21
+ <v-list-item-title class="switch-context__name">
19
22
  {{ name || `Select ${prop.title}` }}
20
23
  </v-list-item-title>
21
24
  </v-list-item>
@@ -100,9 +103,38 @@ const name = computed(() => {
100
103
  return prop.items.find((item) => item.value === selected.value)?.text ?? "";
101
104
  });
102
105
 
106
+ /**
107
+ * THE BREADCRUMB'S SITE HALF.
108
+ *
109
+ * The top bar draws `Site name / Page`, but the site's NAME is only ever
110
+ * resolved here - each application loads its own site list and hands it to
111
+ * this selector, so the bar had nothing to print and showed the page alone.
112
+ * The label already on screen is mirrored into shared state for the bar to
113
+ * read. It is a label: no request is made, and what the selector selects is
114
+ * untouched.
115
+ */
116
+ const shellSiteName = useState<string>("shell-context-site-name", () => "");
117
+
118
+ watchEffect(() => {
119
+ if (prop.title?.toLowerCase() === "site" && name.value) {
120
+ shellSiteName.value = name.value;
121
+ }
122
+ });
123
+
103
124
  const selectItem = (value: string) => {
104
125
  selected.value = value;
105
126
  menu.value = false;
106
127
  emit("select", value);
107
128
  };
108
129
  </script>
130
+
131
+ <style scoped>
132
+ /* Wrap onto a second line instead of truncating - the design shows the full
133
+ organisation and site names. */
134
+ .switch-context__name {
135
+ white-space: normal;
136
+ overflow: visible;
137
+ overflow-wrap: anywhere;
138
+ line-height: 1.25;
139
+ }
140
+ </style>
@@ -5,10 +5,8 @@
5
5
  <slot name="actions">
6
6
  <v-btn
7
7
  v-if="canCreate"
8
- class="text-none"
9
- rounded="pill"
10
- variant="tonal"
11
- size="large"
8
+ class="text-none screen-btn-primary"
9
+ variant="flat"
12
10
  @click="emits('create')"
13
11
  >
14
12
  {{ createLabel }}
@@ -18,16 +16,11 @@
18
16
  </v-col>
19
17
 
20
18
  <v-col cols="12">
21
- <v-card
22
- width="100%"
23
- variant="outlined"
24
- border="thin"
25
- rounded="lg"
26
- :loading="loading"
27
- >
19
+ <v-card width="100%" variant="flat" class="table-card" :loading="loading">
28
20
  <v-toolbar
29
21
  density="compact"
30
- color="grey-lighten-4"
22
+ color="transparent"
23
+ class="table-card__toolbar"
31
24
  :extension-height="extensionHeight"
32
25
  >
33
26
  <template #prepend>
@@ -46,7 +39,7 @@
46
39
 
47
40
  <template #append>
48
41
  <v-row no-gutters justify="end" align="center">
49
- <span class="mr-2 text-caption text-fontgray">
42
+ <span class="mr-2 table-card__range">
50
43
  {{ pageRange }}
51
44
  </span>
52
45
  <local-pagination
@@ -68,25 +61,16 @@
68
61
  :max-height="`calc(100vh - (${offset}px))`"
69
62
  class="overflow-y-auto"
70
63
  >
71
- <v-row
72
- v-if="groupedItems.length === 0"
73
- no-gutters
74
- justify="center"
75
- class="py-10"
76
- >
77
- <v-col
78
- cols="auto"
79
- class="text-center text-medium-emphasis text-body-2"
80
- >
81
- {{ noDataText }}
82
- </v-col>
83
- </v-row>
64
+ <div v-if="groupedItems.length === 0" class="table-card__empty">
65
+ <v-icon icon="mdi-magnify-close" size="32" />
66
+ <span>{{ noDataText }}</span>
67
+ </div>
84
68
 
85
69
  <template
86
70
  v-for="(group, groupIndex) in groupedItems"
87
71
  :key="`group-${groupIndex}`"
88
72
  >
89
- <v-sheet color="grey-lighten-4" border="b t">
73
+ <v-sheet color="transparent" class="table-card__group" border="b t">
90
74
  <v-row no-gutters align="center" class="px-4 py-2">
91
75
  <v-col cols="auto" class="d-flex align-center ga-2">
92
76
  <span
@@ -94,39 +78,37 @@
94
78
  >
95
79
  Set {{ group.set }}
96
80
  </span>
97
- <v-chip
81
+ <StatusChip
98
82
  v-if="group.isScheduleTask"
99
- size="x-small"
100
- color="info"
101
- variant="tonal"
102
- prepend-icon="mdi-calendar-clock"
83
+ tone="info"
84
+ :dot="false"
103
85
  class="text-none"
104
86
  >
87
+ <v-icon size="12">mdi-calendar-clock</v-icon>
105
88
  Schedule Task
106
- </v-chip>
89
+ </StatusChip>
107
90
  <slot name="group-header-chips" :group="group">
108
- <v-chip
91
+ <StatusChip
109
92
  v-if="group.completedByName && isGroupComplete(group)"
110
- size="x-small"
111
- color="success"
112
- variant="tonal"
113
- prepend-icon="mdi-check-circle-outline"
93
+ status="Completed"
94
+ :dot="false"
114
95
  class="text-none"
115
96
  >
97
+ <v-icon size="12">mdi-check-circle-outline</v-icon>
116
98
  Completed · {{ group.completedByName }}
117
- </v-chip>
118
- <v-chip
99
+ </StatusChip>
100
+ <StatusChip
119
101
  v-else-if="
120
102
  group.completedByName && isGroupInProgress(group)
121
103
  "
122
- size="x-small"
123
- color="warning"
124
- variant="tonal"
125
- prepend-icon="mdi-progress-clock"
104
+ status="Ongoing"
105
+ tone="warn"
106
+ :dot="false"
126
107
  class="text-none"
127
108
  >
109
+ <v-icon size="12">mdi-progress-clock</v-icon>
128
110
  Ongoing · {{ group.completedByName }}
129
- </v-chip>
111
+ </StatusChip>
130
112
  </slot>
131
113
  </v-col>
132
114
  <v-spacer />
@@ -139,7 +121,8 @@
139
121
  <v-sheet
140
122
  v-for="item in group.items"
141
123
  :key="item[itemValue]"
142
- color="white"
124
+ color="transparent"
125
+ class="table-card__row"
143
126
  border="b"
144
127
  >
145
128
  <v-row no-gutters align="center" class="px-4 py-2">
@@ -6,7 +6,7 @@
6
6
  rounded="lg"
7
7
  :loading="loading"
8
8
  >
9
- <v-toolbar density="compact" color="grey-lighten-4">
9
+ <v-toolbar density="compact" class="px-3 border-b-sm" color="transparent">
10
10
  <template #prepend>
11
11
  <v-checkbox v-model="selectAll" hide-details class="mx-1"></v-checkbox>
12
12
 
@@ -159,6 +159,6 @@ watch(selectAll, (curr) => {
159
159
  }
160
160
 
161
161
  .clickable-rows tbody tr:hover {
162
- background-color: #f5f5f5;
162
+ background-color: var(--hover);
163
163
  }
164
164
  </style>