@7365admin1/layer-common 3.2.2-staging.148 → 3.2.2-staging.150

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.
@@ -1683,27 +1683,52 @@ const finalDashboardData = computed<Record<string, any>>(() => {
1683
1683
 
1684
1684
  // ─── Card Value Configs ───────────────────────────────────────────────────────
1685
1685
 
1686
+ /**
1687
+ * THE KPI TILE PALETTE.
1688
+ *
1689
+ * Was eleven hand-picked hexes restated in four places and blind to the theme:
1690
+ * the SAME orange glyph on the SAME pink tint in light and in dark, because a
1691
+ * literal cannot follow a theme. Its worst pairing measured 1.36:1 and the one
1692
+ * that actually shipped measured 1.74:1 - the lowest readings in the package,
1693
+ * on the first screen every account type opens.
1694
+ *
1695
+ * The handoff names no colour for a KPI tile. It DOES name four status tones
1696
+ * and their soft fills, and the hexes that were here were already those four
1697
+ * hues (`#1d5f99` blue, `#b73535` red, `#d28722` amber, `#23824f` green). So
1698
+ * each pair is re-pointed at the token it was imitating rather than given a
1699
+ * new colour. That also makes each tile the design's own chip pairing, which
1700
+ * is the ruling this project already follows.
1701
+ */
1702
+ const KPI_TONES = {
1703
+ info: { color: "var(--info)", tint: "var(--info-bg)" },
1704
+ err: { color: "var(--err)", tint: "var(--err-bg)" },
1705
+ ok: { color: "var(--ok)", tint: "var(--ok-bg)" },
1706
+ warn: { color: "var(--warn)", tint: "var(--warn-bg)" },
1707
+ } as const;
1708
+
1686
1709
  const defaultCardValues: TDashboardCardValue[] = [
1687
1710
  {
1688
1711
  key: "openWorkOrder",
1689
1712
  periodKey: "period",
1690
1713
  title: "Open Work Order",
1691
1714
  icon: "mdi-briefcase",
1692
- color: "#0b2f47",
1715
+ /** The same tile is `#1d5f99` blue in the other two branches - info. */
1716
+ color: KPI_TONES.info.color,
1693
1717
  },
1694
1718
  {
1695
1719
  key: "taskCompleted",
1696
1720
  periodKey: "period",
1697
1721
  title: "Task Completed",
1698
1722
  icon: "mdi-clipboard-check-outline",
1699
- color: "#f4a340",
1723
+ /** `utils/status.ts`: "completed" is `ok`. This was the 1.74:1 orange. */
1724
+ color: KPI_TONES.ok.color,
1700
1725
  },
1701
1726
  {
1702
1727
  key: "supplyAlert",
1703
1728
  periodKey: "period",
1704
1729
  title: "Supply Alert",
1705
1730
  icon: "mdi-alert",
1706
- color: "#d32f2f",
1731
+ color: KPI_TONES.err.color,
1707
1732
  },
1708
1733
  ];
1709
1734
 
@@ -1713,28 +1738,28 @@ const propertyCardValues: TDashboardCardValue[] = [
1713
1738
  periodKey: "period",
1714
1739
  title: "Open Work Order",
1715
1740
  icon: "mdi-briefcase",
1716
- color: "#1d5f99",
1741
+ color: KPI_TONES.info.color,
1717
1742
  },
1718
1743
  {
1719
1744
  key: "incidents",
1720
1745
  periodKey: "period",
1721
1746
  title: "Open Incidents",
1722
1747
  icon: "mdi-alert",
1723
- color: "#b73535",
1748
+ color: KPI_TONES.err.color,
1724
1749
  },
1725
1750
  {
1726
1751
  key: "visitors",
1727
1752
  periodKey: "period",
1728
1753
  title: "Visitors",
1729
1754
  icon: "mdi-account-multiple",
1730
- color: "#d28722",
1755
+ color: KPI_TONES.warn.color,
1731
1756
  },
1732
1757
  {
1733
1758
  key: "facilityBookings",
1734
1759
  periodKey: "period",
1735
1760
  title: "Facility Booking",
1736
1761
  icon: "mdi-office-building",
1737
- color: "#23824f",
1762
+ color: KPI_TONES.ok.color,
1738
1763
  },
1739
1764
  ];
1740
1765
 
@@ -1744,28 +1769,28 @@ const securityCardValues: TDashboardCardValue[] = [
1744
1769
  periodKey: "period",
1745
1770
  title: "Open Work Order",
1746
1771
  icon: "mdi-briefcase",
1747
- color: "#1d5f99",
1772
+ color: KPI_TONES.info.color,
1748
1773
  },
1749
1774
  {
1750
1775
  key: "incidents",
1751
1776
  periodKey: "period",
1752
1777
  title: "Open Incidents",
1753
1778
  icon: "mdi-alert",
1754
- color: "#b73535",
1779
+ color: KPI_TONES.err.color,
1755
1780
  },
1756
1781
  {
1757
1782
  key: "visitors",
1758
1783
  periodKey: "period",
1759
1784
  title: "Visitors",
1760
1785
  icon: "mdi-account-multiple",
1761
- color: "#d28722",
1786
+ color: KPI_TONES.warn.color,
1762
1787
  },
1763
1788
  {
1764
1789
  key: "patrolCompliance",
1765
1790
  periodKey: "period",
1766
1791
  title: "Patrol Compliance",
1767
1792
  icon: "mdi-office-building",
1768
- color: "#23824f",
1793
+ color: KPI_TONES.ok.color,
1769
1794
  },
1770
1795
  ];
1771
1796
 
@@ -2094,8 +2119,8 @@ function getPropertyKpiCards() {
2094
2119
  key: "workOrders",
2095
2120
  title: "Open Work Order",
2096
2121
  icon: "mdi-briefcase",
2097
- color: "#1d5f99",
2098
- tint: "#d7ecff",
2122
+ color: KPI_TONES.info.color,
2123
+ tint: KPI_TONES.info.tint,
2099
2124
  value: formatNumber(toNumber(workOrderMetric?.count)),
2100
2125
  percentage: toNumber(workOrderMetric?.percentage),
2101
2126
  meta: getMetricMeta(workOrderMetric),
@@ -2106,8 +2131,8 @@ function getPropertyKpiCards() {
2106
2131
  key: "incidents",
2107
2132
  title: "Open Incidents",
2108
2133
  icon: "mdi-alert",
2109
- color: "#b73535",
2110
- tint: "#ffdede",
2134
+ color: KPI_TONES.err.color,
2135
+ tint: KPI_TONES.err.tint,
2111
2136
  value: formatNumber(toNumber(incidentMetric?.count)),
2112
2137
  percentage: toNumber(incidentMetric?.percentage),
2113
2138
  meta: getMetricMeta(incidentMetric),
@@ -2118,8 +2143,8 @@ function getPropertyKpiCards() {
2118
2143
  key: "visitors",
2119
2144
  title: "Visitors",
2120
2145
  icon: "mdi-account-multiple",
2121
- color: "#d28722",
2122
- tint: "#ffe4bd",
2146
+ color: KPI_TONES.warn.color,
2147
+ tint: KPI_TONES.warn.tint,
2123
2148
  value: formatNumber(toNumber(visitorMetric?.count)),
2124
2149
  percentage: toNumber(visitorMetric?.percentage),
2125
2150
  meta: getMetricMeta(visitorMetric),
@@ -2137,8 +2162,8 @@ function getPropertyKpiCards() {
2137
2162
  key: "facilityBookings",
2138
2163
  title: "Facility Booking",
2139
2164
  icon: "mdi-office-building",
2140
- color: "#23824f",
2141
- tint: "#c8f3da",
2165
+ color: KPI_TONES.ok.color,
2166
+ tint: KPI_TONES.ok.tint,
2142
2167
  value: formatNumber(toNumber(facilityMetric?.count)),
2143
2168
  percentage: toNumber(facilityMetric?.percentage),
2144
2169
  meta: getMetricMeta(facilityMetric),
@@ -2172,8 +2197,8 @@ function getSecurityKpiCards() {
2172
2197
  key: "workOrders",
2173
2198
  title: "Open Work Order",
2174
2199
  icon: "mdi-briefcase",
2175
- color: "#1d5f99",
2176
- tint: "#d7ecff",
2200
+ color: KPI_TONES.info.color,
2201
+ tint: KPI_TONES.info.tint,
2177
2202
  value: formatNumber(toNumber(workOrderMetric?.count)),
2178
2203
  percentage: toNumber(workOrderMetric?.percentage),
2179
2204
  meta: getMetricMeta(workOrderMetric),
@@ -2184,8 +2209,8 @@ function getSecurityKpiCards() {
2184
2209
  key: "incidents",
2185
2210
  title: "Open Incidents",
2186
2211
  icon: "mdi-alert",
2187
- color: "#b73535",
2188
- tint: "#ffdede",
2212
+ color: KPI_TONES.err.color,
2213
+ tint: KPI_TONES.err.tint,
2189
2214
  value: formatNumber(toNumber(incidentMetric?.count)),
2190
2215
  percentage: toNumber(incidentMetric?.percentage),
2191
2216
  meta: getMetricMeta(incidentMetric),
@@ -2196,8 +2221,8 @@ function getSecurityKpiCards() {
2196
2221
  key: "visitors",
2197
2222
  title: "Visitors",
2198
2223
  icon: "mdi-account-multiple",
2199
- color: "#d28722",
2200
- tint: "#ffe4bd",
2224
+ color: KPI_TONES.warn.color,
2225
+ tint: KPI_TONES.warn.tint,
2201
2226
  value: formatNumber(toNumber(visitorMetric?.count)),
2202
2227
  percentage: toNumber(visitorMetric?.percentage),
2203
2228
  meta: getMetricMeta(visitorMetric),
@@ -2215,8 +2240,8 @@ function getSecurityKpiCards() {
2215
2240
  key: "patrolCompliance",
2216
2241
  title: "Patrol Compliance",
2217
2242
  icon: "mdi-office-building",
2218
- color: "#23824f",
2219
- tint: "#c8f3da",
2243
+ color: KPI_TONES.ok.color,
2244
+ tint: KPI_TONES.ok.tint,
2220
2245
  value: `${toNumber(patrolMetric?.count)}%`,
2221
2246
  percentage: toNumber(patrolMetric?.percentage),
2222
2247
  meta: getMetricMeta(patrolMetric),
@@ -3607,18 +3632,33 @@ async function exportDashboard(format: "PDF" | "Word") {
3607
3632
 
3608
3633
  // ─── Card Color Helpers ───────────────────────────────────────────────────────
3609
3634
 
3635
+ /** The rotation an unstyled `cardValues` entry falls into - same four tones. */
3636
+ const KPI_ROTATION = [
3637
+ KPI_TONES.info,
3638
+ KPI_TONES.err,
3639
+ KPI_TONES.ok,
3640
+ KPI_TONES.warn,
3641
+ ] as const;
3642
+
3610
3643
  function getCardColor(index: number) {
3611
- return ["#155178", "#9f2f29", "#1f8a56", "#b96d17"][index % 4];
3644
+ return KPI_ROTATION[index % KPI_ROTATION.length].color;
3612
3645
  }
3613
3646
 
3647
+ /**
3648
+ * A tint for whatever colour the caller gave. `props.cardValues` comes from
3649
+ * eleven applications and still arrives as a raw hex in places, so the hex
3650
+ * matching stays - the token names are matched alongside it, not instead.
3651
+ */
3614
3652
  function getCardTint(color: string, index: number) {
3615
- const tints = ["#dbeeff", "#f8c6c3", "#d8f5e5", "#ffe7c2"];
3616
- if (!color) return tints[index % tints.length];
3653
+ if (!color) return KPI_ROTATION[index % KPI_ROTATION.length].tint;
3617
3654
  const n = color.toLowerCase();
3618
- if (n.includes("f44336") || n.includes("d32f2f")) return "#f8c6c3";
3619
- if (n.includes("4caf50") || n.includes("43a047")) return "#d8f5e5";
3620
- if (n.includes("ff9800") || n.includes("ffa726")) return "#ffe7c2";
3621
- return "#dbeeff";
3655
+ if (n.includes("--err") || n.includes("f44336") || n.includes("d32f2f"))
3656
+ return KPI_TONES.err.tint;
3657
+ if (n.includes("--ok") || n.includes("4caf50") || n.includes("43a047"))
3658
+ return KPI_TONES.ok.tint;
3659
+ if (n.includes("--warn") || n.includes("ff9800") || n.includes("ffa726"))
3660
+ return KPI_TONES.warn.tint;
3661
+ return KPI_TONES.info.tint;
3622
3662
  }
3623
3663
 
3624
3664
  // ─── Generic Helpers ─────────────────────────────────────────────────────────
@@ -5,21 +5,23 @@
5
5
  persistent
6
6
  @update:model-value="emit('update:modelValue', $event)"
7
7
  >
8
- <v-card class="camera-dialog" rounded="lg">
9
- <v-card-title class="d-flex align-center justify-space-between pa-4">
10
- <span class="text-subtitle-1 font-weight-bold">Take Facial Photo</span>
8
+ <!-- `rounded="lg"` is dropped, not replaced. Measured on the glass, the card
9
+ read 16px BEFORE and after: the `.rounded-lg` utility it compiled to was
10
+ already being overridden, so the prop stated a radius the card never
11
+ had. `.screen-modal` states the same 16px as `--r-modal`, on purpose. -->
12
+ <v-card class="camera-dialog screen-modal">
13
+ <v-card-title class="d-flex align-center justify-space-between">
14
+ <span>Take Facial Photo</span>
11
15
  <v-btn
12
16
  icon="mdi-close"
13
17
  variant="text"
14
- size="small"
18
+ class="screen-modal__close"
15
19
  aria-label="Close camera"
16
20
  @click="close"
17
21
  />
18
22
  </v-card-title>
19
23
 
20
- <v-divider />
21
-
22
- <v-card-text class="pa-4">
24
+ <v-card-text class="screen-modal__body">
23
25
  <div class="camera-viewport">
24
26
  <video
25
27
  ref="videoElement"
@@ -42,18 +44,20 @@
42
44
 
43
45
  <canvas ref="canvasElement" class="d-none" />
44
46
 
45
- <div class="text-caption text-medium-emphasis mt-3 text-center">
47
+ <div class="camera-dialog__hint text-center">
46
48
  Keep your face centered and make sure the area is well lit.
47
49
  </div>
48
50
  </v-card-text>
49
51
 
50
- <v-divider />
51
-
52
- <v-card-actions class="pa-4">
53
- <v-btn variant="text" @click="close">Cancel</v-btn>
54
- <v-spacer />
52
+ <!-- `color="primary"` on a `v-btn` is the design's FOREGROUND token - the
53
+ link ink - not a fill, so the capture button was accent-on-accent.
54
+ `.screen-btn-primary` states the fill the design does draw. -->
55
+ <div class="screen-modal__footer">
56
+ <v-btn class="text-none screen-btn-ghost" variant="flat" @click="close">
57
+ Cancel
58
+ </v-btn>
55
59
  <v-btn
56
- color="primary"
60
+ class="text-none screen-btn-primary"
57
61
  variant="flat"
58
62
  prepend-icon="mdi-camera"
59
63
  :disabled="starting || !!cameraError || !stream"
@@ -61,7 +65,7 @@
61
65
  >
62
66
  Take Photo
63
67
  </v-btn>
64
- </v-card-actions>
68
+ </div>
65
69
  </v-card>
66
70
  </v-dialog>
67
71
  </template>
@@ -175,10 +179,23 @@ onBeforeUnmount(stopCamera);
175
179
  width: 100%;
176
180
  overflow: hidden;
177
181
  aspect-ratio: 3 / 4;
178
- border-radius: 8px;
182
+ border-radius: var(--r-inner);
183
+ /* Deliberately NOT a theme surface: this is the stage a video sits on, and it
184
+ stays dark in both themes so the preview does not flash white on light.
185
+ Its own `#ffffff` text below is paired with it, not with the theme. */
179
186
  background: #111722;
180
187
  }
181
188
 
189
+ /* The design's small helper line, not Vuetify's `text-caption` /
190
+ `text-medium-emphasis` pair. */
191
+ .camera-dialog__hint {
192
+ margin-top: 12px;
193
+ font-family: var(--font-sans);
194
+ font-size: var(--fs-cell);
195
+ font-weight: 500;
196
+ color: var(--muted);
197
+ }
198
+
182
199
  .camera-preview {
183
200
  width: 100%;
184
201
  height: 100%;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@7365admin1/layer-common",
3
3
  "license": "MIT",
4
4
  "type": "module",
5
- "version": "3.2.2-staging.148",
5
+ "version": "3.2.2-staging.150",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "//files": "What a consumer extending this layer actually loads. Without this npm ships the whole working tree - the changesets, the CI workflows, the render harness in tools/ and any scratch directory that happened to exist at publish time. Nuxt resolves a layer by directory, so every runtime directory below has to stay listed; adding a new top-level runtime directory means adding it here too.",