@7365admin1/layer-common 3.2.2-staging.140 → 3.2.2-staging.142

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.
@@ -774,3 +774,144 @@
774
774
  letter-spacing: 0;
775
775
  text-transform: none;
776
776
  }
777
+
778
+ /* ------------------------------------------------------------------ */
779
+ /* The "Back" link that sits above a page title. */
780
+ /* `SpecificAttr.vue` (17 caller files) and `Container/Standard.vue`. */
781
+ /* */
782
+ /* DESIGN GAP, STATED: the handoff draws no back control anywhere, so */
783
+ /* its SIZE is not a value the design gives. What the design DOES give */
784
+ /* is the rule for a link - `iService365 Redesign.dc.html:26`, */
785
+ /* `a{color:var(--accent-text);text-decoration:underline}` - so the */
786
+ /* colour and the underline are literal, and the underline is kept for */
787
+ /* that reason rather than dropped for looking dated. The size is */
788
+ /* taken from the only standalone inline link the handoff draws, the */
789
+ /* panel's "View All" at line 166: 12.5px / 700. */
790
+ /* */
791
+ /* It replaces `text-subtitle-1 font-weight-medium` - Vuetify's */
792
+ /* 16px/400 Roboto scale, which is neither the product font nor a size */
793
+ /* that appears anywhere in the design. */
794
+ /* ------------------------------------------------------------------ */
795
+ .screen-back {
796
+ display: inline-block;
797
+ font-family: var(--font-sans);
798
+ font-size: var(--fs-breadcrumb);
799
+ font-weight: var(--fw-btn);
800
+ letter-spacing: 0;
801
+ line-height: 1.4;
802
+ color: var(--accent-text);
803
+ text-decoration: underline;
804
+ cursor: pointer;
805
+ }
806
+
807
+ .screen-back:hover {
808
+ color: var(--accent);
809
+ }
810
+
811
+ /* ------------------------------------------------------------------ */
812
+ /* 9. The row kebab and the dropdown it opens. */
813
+ /* */
814
+ /* Both halves are LITERAL, and both were previously left as Vuetify */
815
+ /* draws them - `Dialog/UpdateMoreAction.vue` says so in a comment, */
816
+ /* because a menu teleports out of the measured container and could */
817
+ /* not be render-verified at the time. It can now (force-shot). */
818
+ /* */
819
+ /* The kebab: `iService365 Redesign.dc.html:494`, drawn identically at */
820
+ /* 494, 547, 625 and 660 - a 30px bordered square, 8px radius, */
821
+ /* transparent fill, `--muted` ink, 17px glyph, `--hover` on hover. */
822
+ /* 8px is not one of the radius tokens (the set is 7/9/10/12/14/16), */
823
+ /* so it is written literally rather than snapped to a near token. */
824
+ /* */
825
+ /* The panel: `iService365 Redesign.dc.html:79-90`, the profile */
826
+ /* dropdown - the only dropdown the handoff draws. 240px, `--card` on */
827
+ /* a 1px `--border`, 14px radius, `--shadow-menu`, 8px padding; rows */
828
+ /* are 13px/700 `--text2` at 10px 12px with a 10px radius, and a */
829
+ /* destructive row is `--err` ink with an `--err-bg` hover (line 89), */
830
+ /* which is ink and not a filled button. */
831
+ /* ------------------------------------------------------------------ */
832
+ .v-btn.screen-kebab {
833
+ --v-btn-height: 30px;
834
+ height: 30px;
835
+ width: 30px;
836
+ min-width: 30px;
837
+ padding: 0;
838
+ border: 1px solid var(--border);
839
+ border-radius: 8px;
840
+ background: transparent;
841
+ color: var(--muted);
842
+ }
843
+
844
+ .screen-kebab .v-btn__overlay {
845
+ opacity: 0;
846
+ }
847
+
848
+ .screen-kebab:hover {
849
+ background: var(--hover);
850
+ }
851
+
852
+ .screen-kebab .v-icon {
853
+ font-size: 17px;
854
+ }
855
+
856
+ .v-overlay__content > .v-list.screen-menu {
857
+ width: 240px;
858
+ padding: 8px;
859
+ border: 1px solid var(--border);
860
+ border-radius: var(--r-menu);
861
+ background: var(--card);
862
+ box-shadow: var(--shadow-menu);
863
+ }
864
+
865
+ /* Four classes, to beat Vuetify's own `.v-list .v-list-item--density-*` */
866
+ /* block on specificity rather than on load order - a three-class rule ties */
867
+ /* with it and loses, which is how the drawer's 10px gap never applied. */
868
+ .v-overlay__content > .v-list.screen-menu > .screen-menu__item.v-list-item {
869
+ min-height: 0;
870
+ padding: 10px 12px;
871
+ /* MEASURED, not assumed: without `!important` this read back 0px. Vuetify
872
+ puts the `rounded-0` UTILITY on every `v-list-item` inside a list with no
873
+ `rounded` prop, and utilities carry `!important`, so a four-class rule
874
+ still loses to it. Same trap `NavigationItem.vue` hit in batch Q. */
875
+ border-radius: var(--r-inner) !important;
876
+ color: var(--text2);
877
+ }
878
+
879
+ .screen-menu__item .v-list-item-title {
880
+ font-family: var(--font-sans);
881
+ font-size: var(--fs-nav);
882
+ font-weight: var(--fw-btn);
883
+ letter-spacing: 0;
884
+ line-height: 1.3;
885
+ }
886
+
887
+ .screen-menu__item .v-list-item__prepend > .v-icon {
888
+ font-size: 18px;
889
+ color: var(--muted);
890
+ opacity: 1;
891
+ }
892
+
893
+ /* The design's row gap is 10px; Vuetify's spacer is wider, and the selector */
894
+ /* below matches its own four-class shape for the same reason as above. */
895
+ .screen-menu__item .v-list-item__prepend > .v-icon ~ .v-list-item__spacer {
896
+ width: 10px;
897
+ }
898
+
899
+ .screen-menu__item:hover > .v-list-item__overlay {
900
+ opacity: 0;
901
+ }
902
+
903
+ .screen-menu__item:hover {
904
+ background: var(--hover);
905
+ }
906
+
907
+ .v-overlay__content > .v-list.screen-menu > .screen-menu__item--danger.v-list-item {
908
+ color: var(--err);
909
+ }
910
+
911
+ .screen-menu__item--danger .v-list-item__prepend > .v-icon {
912
+ color: var(--err);
913
+ }
914
+
915
+ .screen-menu__item--danger:hover {
916
+ background: var(--err-bg);
917
+ }
@@ -1,15 +1,17 @@
1
1
  <template>
2
2
  <v-row no-gutters>
3
+ <!--
4
+ The same Back link and the same page title as `SpecificAttr.vue`, which
5
+ is the other half of this pair - it was already on `PageHeader` and this
6
+ one was still on `text-h5 font-weight-medium`, Vuetify's 24px/500 Roboto
7
+ rather than the design's 22px/800. `.screen-back` is stated once in
8
+ `screens.css` with the design gap written out next to it.
9
+ -->
3
10
  <v-col cols="12">
4
- <span
5
- class="font-weight-medium text-subtitle-1 text-decoration-underline cursor-pointer"
6
- @click="emit('back')"
7
- >
8
- Back
9
- </span>
11
+ <span class="screen-back" @click="emit('back')"> Back </span>
10
12
  </v-col>
11
13
  <v-col cols="12">
12
- <span class="text-h5 font-weight-medium">{{ props.title }}</span>
14
+ <PageHeader :title="props.title" />
13
15
  </v-col>
14
16
 
15
17
  <v-col cols="12" class="mt-4">
@@ -370,12 +370,13 @@ const handleClick = (item: any) => {
370
370
  opacity: 1;
371
371
  }
372
372
 
373
- /* Vuetify's own 16px gap between the icon and the label, brought to the 10px
374
- the design draws. The spacer element is what holds that distance - a margin
375
- on the icon leaves it where it was. */
376
- .brand-drawer :deep(.v-list-item__spacer) {
377
- width: 10px;
378
- }
373
+ /* The icon-to-label gap USED to be stated here and it never applied: Vuetify's
374
+ own rule is `.v-list-item__prepend > .v-icon ~ .v-list-item__spacer`, three
375
+ classes, and `.brand-drawer :deep(.v-list-item__spacer)` is also three once
376
+ the scope attribute is counted - a tie, decided by load order, and Vuetify
377
+ loaded last. Measured, the gap was still Vuetify's 32px. The rule now lives
378
+ in `NavigationItem.vue` in Vuetify's own selector shape, so it wins on
379
+ specificity; every item in this list is a `NavigationItem`. */
379
380
 
380
381
  .brand-drawer :deep(.v-list-item--active) {
381
382
  font-weight: var(--fw-section-label);
@@ -1,18 +1,30 @@
1
+ <!--
2
+ A label/value row. Both columns were `text-subtitle-2` - Vuetify's 14px/500
3
+ Roboto - so the label that names a value and the value itself were drawn
4
+ identically, and the trailing chevron was 30px, larger than any icon the
5
+ design draws anywhere.
6
+
7
+ DESIGN GAP, STATED: the handoff has no list row of this shape. The values
8
+ below are the design's own, taken from the nearest things it does draw: the
9
+ table cell type (`--fs-cell` / `--fw-cell`) for both columns, `--muted` for
10
+ the label exactly as the handoff labels a value at line 659, and 18px for the
11
+ trailing icon, the size its own row icons use (lines 87 and 90).
12
+ -->
1
13
  <template>
2
14
  <v-list-item :class="props.divider ? border : defaultBorder">
3
15
  <v-row>
4
- <v-col cols="4" class="text-subtitle-2">
16
+ <v-col cols="4" class="app-list-row__label">
5
17
  <slot name="title"> List Title </slot>
6
18
  </v-col>
7
19
 
8
- <v-col cols="8" class="text-subtitle-2">
20
+ <v-col cols="8" class="app-list-row__value">
9
21
  <slot name="value"> value </slot>
10
22
  </v-col>
11
23
  </v-row>
12
24
 
13
25
  <template #append>
14
26
  <slot name="append">
15
- <v-icon size="30">{{ props.icon }}</v-icon>
27
+ <v-icon size="18">{{ props.icon }}</v-icon>
16
28
  </slot>
17
29
  </template>
18
30
  </v-list-item>
@@ -33,3 +45,21 @@ const props = defineProps({
33
45
  const defaultBorder = "pa-0 pl-8 pr-6 py-4";
34
46
  const border = "border-b-sm" + " " + defaultBorder;
35
47
  </script>
48
+
49
+ <style scoped>
50
+ .app-list-row__label,
51
+ .app-list-row__value {
52
+ font-family: var(--font-sans);
53
+ font-size: var(--fs-cell);
54
+ font-weight: var(--fw-cell);
55
+ letter-spacing: 0;
56
+ }
57
+
58
+ .app-list-row__label {
59
+ color: var(--muted);
60
+ }
61
+
62
+ .app-list-row__value {
63
+ color: var(--text);
64
+ }
65
+ </style>
@@ -11,7 +11,7 @@
11
11
  v-bind="groupProps"
12
12
  :prepend-icon="icon"
13
13
  color="primary"
14
- class="text-subtitle-2"
14
+ class="nav-item"
15
15
  @click.stop="onParentClick"
16
16
  >
17
17
  {{ title }}
@@ -33,7 +33,7 @@
33
33
  :prepend-icon="icon"
34
34
  :to="routeTo"
35
35
  color="primary"
36
- class="text-subtitle-2"
36
+ class="nav-item"
37
37
  >
38
38
  {{ title }}
39
39
  </v-list-item>
@@ -43,7 +43,7 @@
43
43
  :prepend-icon="icon"
44
44
  :href="props.link"
45
45
  color="primary"
46
- class="text-subtitle-2"
46
+ class="nav-item"
47
47
  >
48
48
  {{ title }}
49
49
  </v-list-item>
@@ -97,3 +97,83 @@ const routeTo = computed(() => {
97
97
  return null;
98
98
  });
99
99
  </script>
100
+
101
+ <style scoped>
102
+ /**
103
+ * The sidebar menu row, taken literally from the handoff's `<aside>` — line 56
104
+ * of `iService365 Redesign.dc.html` for the row and line 57 for its icon:
105
+ *
106
+ * padding:8px 12px; border-radius:10px; font-size:13px;
107
+ * font-weight: 800 when active else 600;
108
+ * color: var(--accent-text) when active else var(--text2);
109
+ * icon: font-size:19px; width:20px; color: var(--accent-text)/var(--muted);
110
+ *
111
+ * What this replaced was `text-subtitle-2` — Vuetify's own type scale, 14px/500
112
+ * with 0.1px tracking — and no inactive colour at all, so an unselected item
113
+ * was full-strength body ink and read exactly as loud as the page you are on.
114
+ *
115
+ * STATED HERE RATHER THAN ONLY IN THE DRAWER because five of this component's
116
+ * six call sites are `layouts/*` in the ORG app, outside `.brand-drawer`.
117
+ * `LayoutNavigationDrawer` already states the same shape for the rows it
118
+ * contains; the values below are deliberately IDENTICAL to that block, so the
119
+ * specificity tie between them cannot change what is drawn.
120
+ *
121
+ * `margin: 1px 10px` from the handoff is NOT set here: the drawer insets its
122
+ * own list (`.v-list { padding: 0 8px 12px }`), and a margin as well would
123
+ * double the inset in the ten apps that do use the drawer.
124
+ */
125
+ .nav-item {
126
+ min-height: 38px;
127
+ padding-top: 8px;
128
+ padding-bottom: 8px;
129
+ padding-inline: 12px;
130
+ /* `!important` is not carelessness: Vuetify puts the `rounded-0` UTILITY on
131
+ the item, and utilities are themselves `!important`. Measured without it,
132
+ this row drew `border-radius: 0px`. */
133
+ border-radius: var(--r-inner) !important;
134
+ font-family: var(--font-sans);
135
+ font-size: var(--fs-nav);
136
+ font-weight: var(--fw-cell);
137
+ letter-spacing: 0;
138
+ color: var(--text2);
139
+ }
140
+
141
+ .nav-item.v-list-item--active {
142
+ font-weight: var(--fw-section-label);
143
+ }
144
+
145
+ /**
146
+ * The active row's INK is not set here on purpose. `color="primary"` puts
147
+ * Vuetify's `text-primary` on the item, that utility is `!important`, and
148
+ * `primary` is mapped to `--accent-text` — which is the colour the handoff
149
+ * names for an active row. So the rule above wins for an inactive row and
150
+ * loses, correctly, for an active one.
151
+ */
152
+ .nav-item :deep(.v-list-item__prepend > .v-icon) {
153
+ font-size: 19px;
154
+ width: 20px;
155
+ text-align: center;
156
+ opacity: 1;
157
+ }
158
+
159
+ /* Muted only while inactive — an explicit colour on the icon would also
160
+ out-rank the inherited `--accent-text` on the row you are actually on. */
161
+ .nav-item:not(.v-list-item--active) :deep(.v-list-item__prepend > .v-icon) {
162
+ color: var(--muted);
163
+ }
164
+
165
+ /**
166
+ * The handoff's 10px between icon and label. Vuetify holds that distance in a
167
+ * spacer element, so a margin on the icon leaves it where it was.
168
+ *
169
+ * The selector is Vuetify's own shape ON PURPOSE. Vuetify sets the gap with
170
+ * `.v-list-item__prepend > .v-icon ~ .v-list-item__spacer { width: 32px }` —
171
+ * three classes. A scoped `.nav-item :deep(.v-list-item__spacer)` is also
172
+ * three (the scope attribute counts), so it TIES and loses on source order.
173
+ * Measured: the gap stayed at Vuetify's 32px. Matching the shape makes it four
174
+ * and it wins on specificity rather than on load order.
175
+ */
176
+ .nav-item :deep(.v-list-item__prepend > .v-icon ~ .v-list-item__spacer) {
177
+ width: 10px;
178
+ }
179
+ </style>
@@ -1,34 +1,50 @@
1
+ <!--
2
+ The "page under maintenance" screen — 38 routes across 10 applications.
3
+
4
+ What it was: `font-family: Arial` on `color: #333`. Not a token, not the
5
+ product font, and the same dark grey on the dark page. It was the one screen
6
+ in the estate that ignored both the theme switch and Manrope.
7
+
8
+ DESIGN GAP, STATED: the handoff draws no maintenance / under-construction
9
+ page at all. So this is assembled from the established primitive rather than
10
+ invented — `.screen-empty` (`assets/css/screens.css:149`) is the design's
11
+ centred, muted, 52px-padded empty block, and the heading takes the
12
+ `--fs-card-title` / `--fw-card-title` type the design uses for every other
13
+ panel heading (handoff line 133, `font-size:15.5px;font-weight:800`).
14
+
15
+ The 🚧 emoji is replaced by the central icon: emoji renders in the OS font,
16
+ which is neither Manrope nor a colour the theme controls. `mdi-wrench-clock`
17
+ is translated centrally to Material Symbols `build` — no hand-mapping here.
18
+ -->
1
19
  <template>
2
- <div class="maintenance-container">
3
- <h1>🚧 Page Under Maintenance</h1>
4
- <p>
20
+ <div class="screen-empty placeholder-screen">
21
+ <v-icon icon="mdi-wrench-clock" size="32" />
22
+ <h1 class="placeholder-screen__title">Page Under Maintenance</h1>
23
+ <p class="placeholder-screen__body">
5
24
  We're currently working on improving this page to serve you better. Please
6
25
  check back soon!
7
26
  </p>
8
- <p>Thank you for your patience.</p>
27
+ <p class="placeholder-screen__body">Thank you for your patience.</p>
9
28
  </div>
10
29
  </template>
11
30
 
12
31
  <style scoped>
13
- .maintenance-container {
14
- display: flex;
15
- flex-direction: column;
16
- justify-content: center;
17
- align-items: center;
18
- text-align: center;
32
+ /* The only value kept from the old stylesheet: it is a whole route, so it
33
+ holds the viewport rather than collapsing to the height of three lines. */
34
+ .placeholder-screen {
19
35
  min-height: 50vh;
20
- margin: 0;
21
- font-family: Arial, sans-serif;
22
- color: #333;
23
36
  }
24
37
 
25
- h1 {
26
- font-size: 2rem;
27
- margin-bottom: 1rem;
38
+ .placeholder-screen__title {
39
+ margin: 0;
40
+ font-size: var(--fs-card-title);
41
+ font-weight: var(--fw-card-title);
42
+ color: var(--text);
28
43
  }
29
44
 
30
- p {
31
- font-size: 1.1rem;
32
- line-height: 1.5;
45
+ .placeholder-screen__body {
46
+ max-width: 42ch;
47
+ margin: 0;
48
+ font-weight: var(--fw-cell);
33
49
  }
34
50
  </style>
@@ -1,22 +1,32 @@
1
1
  <template>
2
+ <!-- The per-row kebab and its dropdown. Both were Vuetify defaults: a text
3
+ icon button with no border, and a plain `v-list` panel at Vuetify's 4px
4
+ radius with no border at all. The design draws both - the kebab at
5
+ `iService365 Redesign.dc.html:494`, the dropdown at lines 79-90 - and
6
+ `.screen-kebab` / `.screen-menu` in `screens.css` carry those values. -->
2
7
  <v-menu location="bottom end">
3
8
  <template #activator="{ props }">
4
9
  <v-btn
5
10
  v-bind="props"
6
11
  icon="mdi-dots-vertical"
7
12
  variant="text"
8
- density="comfortable"
13
+ class="screen-kebab"
9
14
  />
10
15
  </template>
11
16
 
12
- <v-list density="compact">
17
+ <v-list class="screen-menu" density="compact">
13
18
  <v-list-item
19
+ class="screen-menu__item"
14
20
  prepend-icon="mdi-pencil-outline"
15
21
  title="Edit plan"
16
22
  @click="$emit('edit')"
17
23
  />
18
24
 
25
+ <!-- Deactivating a plan is the destructive action, so it takes the
26
+ handoff's destructive row treatment (line 89): `--err` ink over an
27
+ `--err-bg` hover, not a filled red button. -->
19
28
  <v-list-item
29
+ class="screen-menu__item screen-menu__item--danger"
20
30
  prepend-icon="mdi-close-circle-outline"
21
31
  title="Deactivate"
22
32
  @click="$emit('deactivate')"
@@ -1,22 +1,35 @@
1
+ <!--
2
+ The attachment thumbnail strip (14 caller files).
3
+
4
+ THREE THINGS WERE WRONG AND ONE OF THEM NEVER DREW AT ALL:
5
+
6
+ 1. The strip painted `backgroundColor: '#FFFF'` inline. That is opaque white
7
+ in BOTH themes - a white band behind the thumbnails on the dark page. It
8
+ is deleted rather than re-coloured: the strip has no surface of its own in
9
+ the design, it sits on whatever panel holds it.
10
+ 2. `.selected` was `border: 2px solid var(--v-theme-primary)`. `--v-theme-*`
11
+ holds a BARE TRIPLET, `74, 110, 182`, not a colour - so the declaration was
12
+ invalid and dropped silently, and a selected thumbnail has never had a
13
+ border. It is now `var(--accent)`, which is a colour.
14
+ 3. The remove button's `color="red"` is a fixed Vuetify red, the same red on
15
+ both themes; `error` is the theme's own. Its `x-large` glyph (40px) was
16
+ larger than any icon the design draws - 18px is the size the handoff gives
17
+ a control icon.
18
+ -->
1
19
  <template>
2
- <v-sheet class="mx-auto">
3
- <v-slide-group
4
- class="pa-1"
5
- show-arrows
6
- :style="{ backgroundColor: '#FFFF' }"
7
- >
20
+ <v-sheet class="mx-auto bg-transparent">
21
+ <v-slide-group class="pa-1" show-arrows>
8
22
  <v-slide-group-item
9
23
  v-for="(data, idx) in localDataFiles"
10
24
  :key="idx"
11
25
  v-slot="{ isSelected }"
12
26
  >
13
27
  <v-card
14
- :class="['ma-1', isSelected && 'selected']"
28
+ :class="['ma-1', 'slide-card', isSelected && 'selected']"
15
29
  width="150"
16
30
  height="100"
31
+ elevation="0"
17
32
  @click="clickable && emit('onClickCarousel', data)"
18
- class="rounded-lg border-thin"
19
- border=" opacity-50 thin "
20
33
  >
21
34
  <v-btn
22
35
  icon
@@ -25,7 +38,7 @@
25
38
  class="remove-btn pa-0 ma-0"
26
39
  @click.stop="removeFile(data)"
27
40
  >
28
- <v-icon color="red" class="pa-0 ma-0" size="x-large"
41
+ <v-icon color="error" class="pa-0 ma-0" size="18"
29
42
  >mdi-close-circle</v-icon
30
43
  >
31
44
  </v-btn>
@@ -181,8 +194,19 @@ const removeFile = (file) => {
181
194
  right: 8px;
182
195
  }
183
196
 
197
+ /* The thumbnail tile: the design's inner radius and its own border token,
198
+ in place of Vuetify's `rounded-lg` + `border-thin` + a `border` prop that
199
+ set an opacity as well. */
200
+ .slide-card {
201
+ border: 1px solid var(--border);
202
+ border-radius: var(--r-inner);
203
+ }
204
+
205
+ /* See the note at the top: this used to name `var(--v-theme-primary)`, a bare
206
+ triplet, so the rule was invalid and the selected tile drew no border at
207
+ all. */
184
208
  .selected {
185
- border: 2px solid var(--v-theme-primary);
209
+ border: 2px solid var(--accent);
186
210
  }
187
211
 
188
212
  .remove-btn {
@@ -3,12 +3,14 @@
3
3
  <v-col cols="12" :lg="props.lg" :md="props.md" :sm="props.sm">
4
4
  <v-row no-gutters>
5
5
  <v-col cols="12">
6
- <span
7
- class="font-weight-medium text-subtitle-1 text-decoration-underline cursor-pointer"
8
- @click="emit('back')"
9
- >
10
- Back
11
- </span>
6
+ <!--
7
+ The Back link. `.screen-back` is stated once in `screens.css`; the
8
+ underline and the accent colour are the handoff's own rule for a
9
+ link (line 26), the 12.5px/700 is its "View All" (line 166), and
10
+ the design draws no back control of its own - the gap is written
11
+ out next to the class.
12
+ -->
13
+ <span class="screen-back" @click="emit('back')"> Back </span>
12
14
  </v-col>
13
15
  <!--
14
16
  THE PAGE TITLE ROW. This wrapper is the whole scaffold for every
@@ -1,33 +1,78 @@
1
+ <!--
2
+ The little "i" that explains a field.
3
+
4
+ TWO FIXES, one of them the same defect batch P found in the toast:
5
+
6
+ 1. `size` is declared `default: ""`. An EMPTY STRING IS NOT `undefined`, so
7
+ Vue's default machinery never runs and the empty string reaches Vuetify,
8
+ which builds the class `v-btn--size-` - a class that matches nothing. The
9
+ button then had no size class at all and fell back to the bare `.v-btn`
10
+ box. `props.size || undefined` lets Vuetify's own default apply when a
11
+ caller says nothing, which is what the prop was written to mean.
12
+ 2. `p-0 m-0` are not Vuetify classes and never were - nothing in this project
13
+ defines them. Dead attributes, removed.
14
+
15
+ DESIGN GAP, STATED: the handoff draws no tooltip anywhere (`grep -i tooltip`
16
+ returns nothing). So the surface below is not invented - it is the same
17
+ assembly the toast uses for the same reason: the design's inner radius, its
18
+ menu shadow, its font and its button type scale, applied to Vuetify's
19
+ tooltip in place of a 4px Roboto pill.
20
+ -->
1
21
  <template>
2
- <v-tooltip v-bind="$attrs" :text="text" @click.stop>
3
- <template v-slot:activator="{ props: activatorProps }">
4
- <v-btn icon="mdi-information-symbol" v-bind="activatorProps" class="p-0 m-0 d-flex align-center"
5
- :density="density" :size="size" color="primary-button" />
6
- </template>
7
- </v-tooltip>
22
+ <v-tooltip v-bind="$attrs" :text="text" content-class="app-tooltip" @click.stop>
23
+ <template #activator="{ props: activatorProps }">
24
+ <v-btn
25
+ icon="mdi-information-symbol"
26
+ v-bind="activatorProps"
27
+ class="d-flex align-center"
28
+ :density="density"
29
+ :size="props.size || undefined"
30
+ color="primary-button"
31
+ />
32
+ </template>
33
+ </v-tooltip>
8
34
  </template>
9
35
 
10
36
  <script setup lang="ts">
37
+ import type { VTooltip } from "vuetify/components";
11
38
 
12
- import type { VTooltip} from "vuetify/components"
13
-
14
- type TTooltipDensity = VTooltip["$props"]["density"]
39
+ type TTooltipDensity = VTooltip["$props"]["density"];
15
40
 
16
41
  const props = defineProps({
17
- text: {
18
- type: String,
19
- default: ""
20
- },
21
- size: {
22
- type: String,
23
- default: ""
24
- },
25
- density: {
26
- type: String as PropType<TTooltipDensity>,
27
- default: "default"
28
- }
29
- })
30
-
42
+ text: {
43
+ type: String,
44
+ default: "",
45
+ },
46
+ size: {
47
+ type: String,
48
+ default: "",
49
+ },
50
+ density: {
51
+ type: String as PropType<TTooltipDensity>,
52
+ default: "default",
53
+ },
54
+ });
31
55
  </script>
32
56
 
33
- <style scoped></style>
57
+ <style>
58
+ /* NOT scoped: a tooltip teleports to the overlay container, outside this
59
+ component's DOM, so a scoped rule cannot reach it. The class is namespaced
60
+ for the same reason. */
61
+ .v-tooltip > .v-overlay__content.app-tooltip {
62
+ /* MEASURED FIRST, then fixed. Left to Vuetify the panel came out
63
+ `rgb(251,251,248)` on the light page - `--sidebar`, the navigation-rail
64
+ colour, 1.03:1 against `--bg` with no border. The identical fall-through
65
+ batch P found behind the invisible toast. `--card` + `--border` is what
66
+ every other floating panel in this product uses (see `.app-profile-menu`
67
+ in `Layout/Header.vue`), so the edge is what carries the boundary. */
68
+ background: var(--card);
69
+ border: 1px solid var(--border);
70
+ color: var(--text2);
71
+ border-radius: var(--r-inner);
72
+ box-shadow: var(--shadow-menu);
73
+ font-family: var(--font-sans);
74
+ font-size: var(--fs-btn);
75
+ font-weight: 600;
76
+ letter-spacing: 0;
77
+ }
78
+ </style>
@@ -1,27 +1,48 @@
1
+ <!--
2
+ The summary a visitor search draws under its result. Every one of the four
3
+ cells was `text-subtitle-1` - Vuetify's 16px/400 Roboto - so the LABEL that
4
+ names a value ("Name:", "NRIC:") was drawn at exactly the same size, weight
5
+ and ink as the value itself, and neither was the product font.
6
+
7
+ DESIGN GAP, STATED: the handoff draws no visitor-search panel. What it does
8
+ draw is a label sitting next to the value it names, at
9
+ `iService365 Redesign.dc.html:659` - `color:var(--muted);font-size:12.5px` -
10
+ inside a row whose own type is 13.5px/600 with the name at 700 (line 658).
11
+ Those are the values below: a muted 12.5px label over a 13.5px/700 value, the
12
+ same label-quieter-than-value relationship `ListItem.vue` already uses.
13
+
14
+ The trailing colons are dropped: the design separates a label from its value
15
+ by weight and ink, not by punctuation.
16
+ -->
1
17
  <template>
2
18
  <div class="w-100 py-2">
3
- <div class="d-flex align-center mb-3 justify-space-between ga-4 w-100">
4
- <span class="text-subtitle-1" style="min-width: 50%">
5
- <div>Name:</div>
6
- <div>{{ displayName }}</div>
7
- </span>
8
- <span class="text-subtitle-1" style="min-width: 50%">
9
- <div>NRIC:</div>
10
- <div>{{ item?.nric || "N/A" }}</div>
11
- </span>
19
+ <div class="d-flex flex-wrap align-center mb-3 justify-space-between ga-4 w-100">
20
+ <!-- These were `<span>` wrappers with `<div>` children - a block inside
21
+ an inline element, which the parser closes early. Now both are
22
+ blocks, which is also what makes the 50% min-width behave. -->
23
+ <div class="visitor-summary__cell">
24
+ <div class="visitor-summary__label">Name</div>
25
+ <div class="visitor-summary__value">{{ displayName }}</div>
26
+ </div>
27
+ <div class="visitor-summary__cell">
28
+ <div class="visitor-summary__label">NRIC</div>
29
+ <div class="visitor-summary__value">{{ item?.nric || "N/A" }}</div>
30
+ </div>
12
31
  </div>
13
32
 
14
33
  <div
15
34
  v-if="contacts.length < 2 && plateNumbers.length < 2"
16
- class="d-flex align-center justify-space-between ga-4 w-100"
35
+ class="d-flex flex-wrap align-center justify-space-between ga-4 w-100"
17
36
  >
18
- <div class="text-subtitle-1" style="min-width: 50%">
19
- <div>Contact:</div>
20
- <div>{{ contacts[0] || "N/A" }}</div>
37
+ <div class="visitor-summary__cell">
38
+ <div class="visitor-summary__label">Contact</div>
39
+ <div class="visitor-summary__value">{{ contacts[0] || "N/A" }}</div>
21
40
  </div>
22
- <div class="text-subtitle-1" style="min-width: 50%">
23
- <div>Plate:</div>
24
- <div class="text-uppercase">{{ plateNumbers[0] || "N/A" }}</div>
41
+ <div class="visitor-summary__cell">
42
+ <div class="visitor-summary__label">Plate</div>
43
+ <div class="visitor-summary__value text-uppercase">
44
+ {{ plateNumbers[0] || "N/A" }}
45
+ </div>
25
46
  </div>
26
47
  </div>
27
48
  </div>
@@ -84,3 +105,26 @@ const plateNumbers = computed(() => {
84
105
  );
85
106
  });
86
107
  </script>
108
+
109
+ <style scoped>
110
+ .visitor-summary__cell {
111
+ min-width: 50%;
112
+ }
113
+
114
+ .visitor-summary__label {
115
+ font-family: var(--font-sans);
116
+ font-size: 12.5px;
117
+ font-weight: var(--fw-cell);
118
+ letter-spacing: 0;
119
+ color: var(--muted);
120
+ margin-bottom: 2px;
121
+ }
122
+
123
+ .visitor-summary__value {
124
+ font-family: var(--font-sans);
125
+ font-size: var(--fs-cell);
126
+ font-weight: var(--fw-btn);
127
+ letter-spacing: 0;
128
+ color: var(--text);
129
+ }
130
+ </style>
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.140",
5
+ "version": "3.2.2-staging.142",
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.",