@7365admin1/layer-common 3.2.2-staging.85 → 3.2.2-staging.87

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.
@@ -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">
@@ -216,136 +216,3 @@ watch(
216
216
  }
217
217
  );
218
218
  </script>
219
-
220
- <style scoped>
221
- /* ------------------------------------------------------------------ */
222
- /* The card. */
223
- /* ------------------------------------------------------------------ */
224
-
225
- .table-card {
226
- font-family: var(--font-sans);
227
- background: var(--card);
228
- border: 1px solid var(--border);
229
- border-radius: var(--r-card);
230
- box-shadow: var(--shadow);
231
- overflow: hidden;
232
- }
233
-
234
- /**
235
- * The toolbar was `color="grey-lighten-4"` - a literal Vuetify grey, which is
236
- * a near-white bar sitting on a #1c1e24 card in dark mode. It is the card's
237
- * own surface now, with the design's rule under it.
238
- */
239
- .table-card__toolbar {
240
- border-bottom: 1px solid var(--border);
241
- }
242
-
243
- .table-card__range {
244
- font-size: 12px;
245
- font-weight: 600;
246
- color: var(--muted);
247
- font-variant-numeric: tabular-nums;
248
- }
249
-
250
- /* ------------------------------------------------------------------ */
251
- /* The header row and the rows under it. */
252
- /* ------------------------------------------------------------------ */
253
-
254
- .table-card :deep(thead th) {
255
- background: var(--thead) !important;
256
- color: var(--muted) !important;
257
- font-size: var(--fs-table-head) !important;
258
- font-weight: var(--fw-table-head) !important;
259
- letter-spacing: var(--ls-table-head);
260
- text-transform: uppercase;
261
- padding: 10px var(--cellpad-x) !important;
262
- height: auto !important;
263
- border-bottom: 1px solid var(--border) !important;
264
- white-space: nowrap;
265
- }
266
-
267
- .table-card :deep(tbody td) {
268
- font-size: var(--fs-cell);
269
- font-weight: var(--fw-cell);
270
- color: var(--text);
271
- padding: var(--cellpad) var(--cellpad-x) !important;
272
- height: auto !important;
273
- font-variant-numeric: tabular-nums;
274
- }
275
-
276
- .table-card :deep(tbody tr:hover > td) {
277
- background: var(--hover);
278
- }
279
-
280
- /* ------------------------------------------------------------------ */
281
- /* Empty state, in-card search, buttons and in-card tabs. */
282
- /* ------------------------------------------------------------------ */
283
-
284
- .table-card__empty {
285
- display: flex;
286
- flex-direction: column;
287
- align-items: center;
288
- justify-content: center;
289
- gap: 8px;
290
- padding: 52px 16px;
291
- font-size: var(--fs-cell);
292
- color: var(--muted);
293
- }
294
-
295
- .table-card__empty :deep(.v-icon) {
296
- color: var(--muted);
297
- }
298
-
299
- /* The in-card variant: 34px, 10px radius, as drawn. */
300
- .table-card__search :deep(.v-field) {
301
- border-radius: var(--r-inner);
302
- font-size: var(--fs-cell);
303
- }
304
-
305
- .table-card__primary {
306
- height: var(--btn-h);
307
- border-radius: var(--r-inner);
308
- padding: 0 16px;
309
- font-size: var(--fs-btn);
310
- font-weight: var(--fw-btn-strong);
311
- letter-spacing: 0;
312
- background: var(--accent-strong);
313
- color: var(--on-accent-strong);
314
- }
315
-
316
- .table-card__ghost {
317
- height: var(--btn-h);
318
- border-radius: var(--r-inner);
319
- padding: 0 16px;
320
- font-size: var(--fs-btn);
321
- font-weight: var(--fw-btn);
322
- letter-spacing: 0;
323
- color: var(--text2);
324
- border-color: var(--border);
325
- background: var(--card);
326
- }
327
-
328
- /**
329
- * Tabs that a screen puts in this card's extension slot: 13px, the active one
330
- * at 800 in `--accent-text` over a 2px accent underline. Tabs elsewhere in the
331
- * product are their own screens' and are restyled with them.
332
- */
333
- .table-card :deep(.v-tab) {
334
- font-size: var(--fs-nav);
335
- font-weight: var(--fw-cell);
336
- letter-spacing: 0;
337
- text-transform: none;
338
- color: var(--muted);
339
- min-width: 0;
340
- }
341
-
342
- .table-card :deep(.v-tab.v-tab--selected) {
343
- font-weight: var(--fw-table-head);
344
- color: var(--accent-text);
345
- }
346
-
347
- .table-card :deep(.v-tab .v-tab__slider) {
348
- height: 2px;
349
- background: var(--accent);
350
- }
351
- </style>
@@ -24,10 +24,8 @@
24
24
  <!-- Primary action -->
25
25
  <v-btn
26
26
  v-if="canCreateUnit"
27
- class="text-none mr-3"
28
- rounded="pill"
29
- variant="tonal"
30
- size="large"
27
+ class="text-none mr-3 screen-btn-primary"
28
+ variant="flat"
31
29
  @click="onCreateUnit()"
32
30
  >
33
31
  Add Unit
@@ -37,10 +35,8 @@
37
35
  <template #activator="{ props: t }">
38
36
  <v-btn
39
37
  v-bind="t"
40
- class="ma-1"
41
- variant="tonal"
42
- size="large"
43
- rounded="pill"
38
+ class="ma-1 screen-icon-btn"
39
+ variant="flat"
44
40
  href="/files/unit-sample-data.xlsx"
45
41
  target="_blank"
46
42
  download
@@ -55,10 +51,8 @@
55
51
  <template #activator="{ props: t }">
56
52
  <v-btn
57
53
  v-bind="t"
58
- class="ma-1"
59
- variant="tonal"
60
- size="large"
61
- rounded="pill"
54
+ class="ma-1 screen-icon-btn"
55
+ variant="flat"
62
56
  @click="onImportData"
63
57
  >
64
58
  <v-icon>mdi-upload</v-icon>
@@ -71,10 +65,8 @@
71
65
  <template #activator="{ props: t }">
72
66
  <v-btn
73
67
  v-bind="t"
74
- class="ma-1"
75
- variant="tonal"
76
- size="large"
77
- rounded="pill"
68
+ class="ma-1 screen-icon-btn"
69
+ variant="flat"
78
70
  @click="handleDownloadExcel"
79
71
  :loading="isDownloading"
80
72
  >
@@ -88,7 +80,7 @@
88
80
 
89
81
  <v-spacer />
90
82
 
91
- <v-col cols="auto">
83
+ <v-col cols="auto" class="filter-field">
92
84
  <v-text-field
93
85
  v-model="searchInput"
94
86
  density="compact"
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.85",
5
+ "version": "3.2.2-staging.87",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "publishConfig": {
@@ -53,6 +53,7 @@ import type { CookieOptions } from "#app";
53
53
  */
54
54
  import "../assets/css/tokens.css";
55
55
  import "../assets/css/shell.css";
56
+ import "../assets/css/screens.css";
56
57
 
57
58
  export default defineNuxtPlugin((app) => {
58
59
  /**
@@ -35,6 +35,42 @@ test("an unmapped status comes out neutral rather than guessed", () => {
35
35
  }
36
36
  });
37
37
 
38
+ /**
39
+ * PHASE 4. Each of these words is on a module screen today with a colour a
40
+ * per-screen `getStatusColor` gave it. The list has to keep giving it the SAME
41
+ * tone, or adopting the shared chip would quietly repaint a status.
42
+ */
43
+ test("the product's own status words keep the tone the screens already gave them", () => {
44
+ for (const s of ["Accepted", "Approved", "Resolved", "Active"]) {
45
+ assert.equal(statusTone(s), "ok", s);
46
+ }
47
+
48
+ for (const s of ["Rejected", "Deleted", "Suspended"]) {
49
+ assert.equal(statusTone(s), "err", s);
50
+ }
51
+
52
+ for (const s of ["In Progress", "In-Progress", "To-Do", "Awaiting Approval"]) {
53
+ assert.equal(statusTone(s), "warn", s);
54
+ }
55
+
56
+ for (const s of ["Ongoing", "For Review"]) {
57
+ assert.equal(statusTone(s), "info", s);
58
+ }
59
+
60
+ for (const s of ["Inactive", "Expired"]) {
61
+ assert.equal(statusTone(s), "neutral", s);
62
+ }
63
+ });
64
+
65
+ /**
66
+ * The one place the handoff and the old per-screen colour disagree: `Open` was
67
+ * grey on the cleaning schedules and the design names it `ok`. Pinned so the
68
+ * disagreement is a decision on the record rather than a surprise.
69
+ */
70
+ test("Open follows the design, not the old grey", () => {
71
+ assert.equal(statusTone("open"), "ok");
72
+ });
73
+
38
74
  test("the class name matches what tokens.css actually defines", () => {
39
75
  assert.equal(statusToneClass("Paid"), "tone-ok");
40
76
  assert.equal(statusToneClass("Whatever"), "tone-neutral");
package/utils/status.ts CHANGED
@@ -34,6 +34,42 @@ const TONES: Record<string, TStatusTone> = {
34
34
 
35
35
  role: "info",
36
36
  info: "info",
37
+
38
+ /**
39
+ * PHASE 4 - THE WORDS THIS PRODUCT ACTUALLY USES.
40
+ *
41
+ * The handoff names ten words; the module screens show more than that, and
42
+ * each of them is ALREADY painted a colour today by a per-screen
43
+ * `getStatusColor`. So these are not new opinions - each one is the tone the
44
+ * screens already give that word, moved into the one list so that "Ongoing"
45
+ * is the same blue on a cleaning schedule and on a scheduled area. Where the
46
+ * old per-screen colour and the design disagree the design wins, and there
47
+ * is exactly one of those: `Open` was grey and the handoff names it `ok`.
48
+ *
49
+ * Anything still unlisted stays neutral, deliberately - see above.
50
+ */
51
+ ongoing: "info", // was `primary`
52
+ "in progress": "warn", // was #FB8C00, orange
53
+ "for review": "info", // was `primary`
54
+ "to do": "warn", // was `orange`
55
+
56
+ accepted: "ok", // was `success`
57
+ approved: "ok",
58
+ resolved: "ok", // was #4CAF50, green
59
+ active: "ok", // was `success`
60
+
61
+ rejected: "err", // was `error`
62
+ deleted: "err", // was `error`
63
+ suspended: "err", // was `error`
64
+
65
+ complete: "ok",
66
+
67
+ inactive: "neutral", // was `grey`
68
+ "in active": "neutral", // the same word, printed "In-Active"
69
+ declined: "neutral", // was Vuetify's `default`
70
+ expired: "neutral", // was `grey`
71
+
72
+ "awaiting approval": "warn", // a waiting state, like Pending
37
73
  };
38
74
 
39
75
  /**