@7365admin1/layer-common 3.2.2-staging.121 → 3.2.2-staging.123
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/assets/css/primitives.css +92 -0
- package/assets/css/tokens.css +16 -0
- package/components/AppButton.vue +10 -1
- package/components/StatusChip.vue +63 -0
- package/components/VisitorManagement.vue +20 -13
- package/nuxt.config.ts +6 -1
- package/package.json +22 -1
- package/plugins/vuetify.ts +37 -1
- package/utils/materialSymbols.ts +363 -0
- package/.changeset/README.md +0 -8
- package/.changeset/camera-wall-gated-endpoint.md +0 -47
- package/.changeset/camera-wall-plain-english.md +0 -60
- package/.changeset/camera-wall-selection-and-guidance.md +0 -65
- package/.changeset/config.json +0 -11
- package/.changeset/dark-primary-contrast.md +0 -39
- package/.changeset/dashboard-dark-theme-contrast.md +0 -15
- package/.changeset/notification-preferences.md +0 -17
- package/.changeset/pm-sidebar-grouping-and-list-scaffold.md +0 -27
- package/.changeset/service-provider-invitation-actions.md +0 -28
- package/.editorconfig +0 -12
- package/.github/workflows/main.yml +0 -17
- package/.github/workflows/publish-staging.yml +0 -47
- package/.github/workflows/publish.yml +0 -39
- package/PUBLISHING.md +0 -269
- package/components/ScheduleTaskAreaFormDialog.vue +0 -141
- package/components/ScheduleTaskAreaUpdateMoreAction.vue +0 -104
- package/components/TableWithButton.vue +0 -94
- package/test/visitor-socket.test.mjs +0 -36
- package/tools/render-harness/README.md +0 -87
- package/tools/render-harness/baselines.json +0 -117
- package/tools/render-harness/harness-init.ps1 +0 -127
- package/tools/render-harness/probe.mjs +0 -229
- package/tools/render-harness/render-check.mjs +0 -306
- package/tools/render-harness/render-check.selftest.mjs +0 -129
|
@@ -92,6 +92,45 @@
|
|
|
92
92
|
font-family: var(--font-sans, Roboto, sans-serif);
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
+
/* ------------------------------------------------------------------ */
|
|
96
|
+
/* The icon face. */
|
|
97
|
+
/* ------------------------------------------------------------------ */
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The handoff draws every icon with Google's `Material Symbols Outlined`
|
|
101
|
+
* variable font, requested in `nuxt.config.ts` alongside Manrope. The icon
|
|
102
|
+
* set in `plugins/vuetify.ts` turns each `mdi-*` name into that font's
|
|
103
|
+
* ligature and puts this class on the element; this rule is what makes the
|
|
104
|
+
* ligature resolve.
|
|
105
|
+
*
|
|
106
|
+
* One class, no `!important`. `.v-icon` already gives us `font-feature-
|
|
107
|
+
* settings: "liga"`, `letter-spacing: normal`, `line-height: 1` and the 1em
|
|
108
|
+
* box, and Vuetify never sets `font-family` on it - the old family arrived
|
|
109
|
+
* through `.mdi:before`, which we no longer emit. Only `text-transform` has
|
|
110
|
+
* to be stated: `.v-btn` uppercases its contents, and an uppercased "close"
|
|
111
|
+
* matches no ligature, so the icon would render as the word.
|
|
112
|
+
*/
|
|
113
|
+
.material-symbols-outlined {
|
|
114
|
+
font-family: "Material Symbols Outlined";
|
|
115
|
+
font-style: normal;
|
|
116
|
+
font-variation-settings:
|
|
117
|
+
"FILL" 0,
|
|
118
|
+
"GRAD" 0,
|
|
119
|
+
"opsz" 24;
|
|
120
|
+
text-transform: none;
|
|
121
|
+
white-space: nowrap;
|
|
122
|
+
word-wrap: normal;
|
|
123
|
+
direction: ltr;
|
|
124
|
+
-webkit-font-smoothing: antialiased;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/* mdi's spin modifier, kept working now the glyph is not a `:before`.
|
|
128
|
+
`@keyframes mdi-spin` still comes from `@mdi/font`, which stays loaded so
|
|
129
|
+
that any icon name without a mapping keeps drawing its old glyph. */
|
|
130
|
+
.material-symbols-outlined.mdi-spin {
|
|
131
|
+
animation: mdi-spin 2s infinite linear;
|
|
132
|
+
}
|
|
133
|
+
|
|
95
134
|
/* ------------------------------------------------------------------ */
|
|
96
135
|
/* PageHeader - the row every screen opens with. */
|
|
97
136
|
/* ------------------------------------------------------------------ */
|
|
@@ -386,6 +425,59 @@
|
|
|
386
425
|
filter: none;
|
|
387
426
|
}
|
|
388
427
|
|
|
428
|
+
/* ------------------------------------------------------------------ */
|
|
429
|
+
/* The check-in / check-out pair. */
|
|
430
|
+
/* ------------------------------------------------------------------ */
|
|
431
|
+
|
|
432
|
+
/**
|
|
433
|
+
* NEW DESIGN, approved by the owner on 2026-08-14. The handoff draws no
|
|
434
|
+
* check-in and no check-out button, so there is nothing to match here; the
|
|
435
|
+
* gatehouse screens had been carrying Vuetify's `color="success"` and a
|
|
436
|
+
* hardcoded `color="red"` instead.
|
|
437
|
+
*
|
|
438
|
+
* Both are `.app-btn` first - the same 40px box, the same 10px radius, the
|
|
439
|
+
* same 13.5px/800 - so only the fill, the ink and the edge differ and the pair
|
|
440
|
+
* sits level with every other button in the product. The 16px icon at an 8px
|
|
441
|
+
* gap is the only metric either adds.
|
|
442
|
+
*
|
|
443
|
+
* CHECK IN is SOLID. It is the affirmative action a guard hits hundreds of
|
|
444
|
+
* times a shift and should be the heaviest thing on its row.
|
|
445
|
+
*
|
|
446
|
+
* CHECK OUT is TONAL, and that is measured rather than preferred: white on
|
|
447
|
+
* `--err` reads 2.99:1 in the dark theme, which is why batch C built a solid
|
|
448
|
+
* danger button, measured it and reverted it. `--err-bg` fill + `--err` ink +
|
|
449
|
+
* a 24%/28% `--err` edge is the construction the status chips already use, it
|
|
450
|
+
* passes in both themes, and it keeps a routine action from reading as a
|
|
451
|
+
* destructive one.
|
|
452
|
+
*/
|
|
453
|
+
.app-btn--ok,
|
|
454
|
+
.app-btn--err {
|
|
455
|
+
gap: 8px;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
/* The label is `--on-ok`, not a literal white - see tokens.css. White on the
|
|
459
|
+
DARK theme's `--ok` measures 2.14:1; `--on-ok` is the on-fill pair the theme
|
|
460
|
+
already carries, so the green stays exactly the green the design names. */
|
|
461
|
+
.app-btn--ok {
|
|
462
|
+
border: 1px solid var(--ok);
|
|
463
|
+
background: var(--ok);
|
|
464
|
+
color: var(--on-ok);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.app-btn--err {
|
|
468
|
+
border: 1px solid var(--err-border);
|
|
469
|
+
background: var(--err-bg);
|
|
470
|
+
color: var(--err);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/* A tint cannot be hovered with `brightness()` - above 1 it fades in the light
|
|
474
|
+
theme, which is the wrong direction. Layering the theme's own `--hover` over
|
|
475
|
+
the fill darkens in light and lightens in dark, with no new token. */
|
|
476
|
+
.app-btn--err:hover {
|
|
477
|
+
background: linear-gradient(var(--hover), var(--hover)), var(--err-bg);
|
|
478
|
+
filter: none;
|
|
479
|
+
}
|
|
480
|
+
|
|
389
481
|
/* ------------------------------------------------------------------ */
|
|
390
482
|
/* AppField / AppSelect / AppDateField. */
|
|
391
483
|
/* ------------------------------------------------------------------ */
|
package/assets/css/tokens.css
CHANGED
|
@@ -39,6 +39,15 @@
|
|
|
39
39
|
|
|
40
40
|
/* Semantic status */
|
|
41
41
|
--ok: rgb(var(--v-theme-success));
|
|
42
|
+
/*
|
|
43
|
+
* The label on a SOLID `--ok` fill. Not `#fff`: the dark theme's `--ok` is
|
|
44
|
+
* `#41c795`, a light mint, and white on it measures 2.14:1 - worse than the
|
|
45
|
+
* 2.99:1 that got batch C's solid danger button reverted. `on-success` is
|
|
46
|
+
* the pair Vuetify already computes per theme from `PALETTE.onFill`
|
|
47
|
+
* (`#ffffff` light, `#131418` dark), so the fill keeps the colour the design
|
|
48
|
+
* asks for and only the label follows the theme.
|
|
49
|
+
*/
|
|
50
|
+
--on-ok: rgb(var(--v-theme-on-success));
|
|
42
51
|
--warn: rgb(var(--v-theme-warning));
|
|
43
52
|
--err: rgb(var(--v-theme-error));
|
|
44
53
|
--info: rgb(var(--v-theme-info));
|
|
@@ -78,6 +87,11 @@
|
|
|
78
87
|
--warn-bg: rgba(190, 140, 25, 0.13);
|
|
79
88
|
--err-bg: rgba(207, 75, 75, 0.1);
|
|
80
89
|
--info-bg: rgba(59, 111, 212, 0.1);
|
|
90
|
+
|
|
91
|
+
/* The edge of a TONAL error control - the check-out button. Alpha over the
|
|
92
|
+
live `--err` rather than a literal, exactly the way `--accent-soft` is
|
|
93
|
+
built, so it tracks the theme's error colour instead of restating it. */
|
|
94
|
+
--err-border: rgba(var(--v-theme-error), 0.24);
|
|
81
95
|
}
|
|
82
96
|
|
|
83
97
|
.v-theme--dark {
|
|
@@ -89,6 +103,8 @@
|
|
|
89
103
|
--warn-bg: rgba(220, 175, 78, 0.13);
|
|
90
104
|
--err-bg: rgba(229, 115, 115, 0.12);
|
|
91
105
|
--info-bg: rgba(125, 166, 236, 0.12);
|
|
106
|
+
|
|
107
|
+
--err-border: rgba(var(--v-theme-error), 0.28);
|
|
92
108
|
}
|
|
93
109
|
|
|
94
110
|
/* ------------------------------------------------------------------ */
|
package/components/AppButton.vue
CHANGED
|
@@ -13,6 +13,12 @@
|
|
|
13
13
|
box as primary; the handoff differs only in fill, border and weight
|
|
14
14
|
icon 32px transparent square, 8px radius
|
|
15
15
|
row 30px bordered square - the `more_vert` at the end of a table row
|
|
16
|
+
|
|
17
|
+
Two more the handoff does NOT draw, added as NEW design on the owner's
|
|
18
|
+
ruling of 2026-08-14 - see `assets/css/primitives.css` for why check-out is
|
|
19
|
+
tonal and not solid red:
|
|
20
|
+
ok 40px solid `--ok` fill, white label - CHECK IN
|
|
21
|
+
err 40px tonal `--err` fill, `--err` label, `--err` edge - CHECK OUT
|
|
16
22
|
-->
|
|
17
23
|
<template>
|
|
18
24
|
<component
|
|
@@ -33,7 +39,7 @@ import { resolveComponent } from "vue";
|
|
|
33
39
|
|
|
34
40
|
const props = defineProps({
|
|
35
41
|
variant: {
|
|
36
|
-
type: String as PropType<"primary" | "ghost" | "icon" | "row">,
|
|
42
|
+
type: String as PropType<"primary" | "ghost" | "icon" | "row" | "ok" | "err">,
|
|
37
43
|
default: "primary",
|
|
38
44
|
},
|
|
39
45
|
icon: { type: String, default: "" },
|
|
@@ -48,6 +54,9 @@ const resolveLink = resolveComponent("NuxtLink");
|
|
|
48
54
|
const iconSize = computed(() => {
|
|
49
55
|
if (props.variant === "primary") return 18;
|
|
50
56
|
if (props.variant === "row") return 17;
|
|
57
|
+
/* The check-in tick and the check-out cross are drawn at 16px - a glyph, not
|
|
58
|
+
a second focal point beside a two-word label. */
|
|
59
|
+
if (props.variant === "ok" || props.variant === "err") return 16;
|
|
51
60
|
return 18;
|
|
52
61
|
});
|
|
53
62
|
</script>
|
|
@@ -19,6 +19,22 @@
|
|
|
19
19
|
word - a padlock on "Closed - View Only" - so adopting the design's
|
|
20
20
|
pill does not quietly drop it. -->
|
|
21
21
|
<slot>{{ label ?? status }}</slot>
|
|
22
|
+
<!--
|
|
23
|
+
The remove control. NEW design, approved by the owner on 2026-08-14 - the
|
|
24
|
+
handoff draws no removable chip. It is an affordance ON the existing pill,
|
|
25
|
+
not a second shape, so a removable "KEY-309" and a read-only "Issued" stay
|
|
26
|
+
visibly the same family: same 999px pill, same 4px 10px, same 12px/700,
|
|
27
|
+
same 24px height. A chip that cannot be removed is byte-for-byte unchanged.
|
|
28
|
+
-->
|
|
29
|
+
<button
|
|
30
|
+
v-if="removable"
|
|
31
|
+
type="button"
|
|
32
|
+
class="status-chip__x"
|
|
33
|
+
:aria-label="removeLabel || `Remove ${label ?? status}`"
|
|
34
|
+
@click="emit('remove')"
|
|
35
|
+
>
|
|
36
|
+
<v-icon icon="mdi-close" :size="12" />
|
|
37
|
+
</button>
|
|
22
38
|
</span>
|
|
23
39
|
</template>
|
|
24
40
|
|
|
@@ -47,8 +63,19 @@ const props = defineProps({
|
|
|
47
63
|
type: String as PropType<"ok" | "warn" | "err" | "info" | "neutral" | "">,
|
|
48
64
|
default: "",
|
|
49
65
|
},
|
|
66
|
+
/** Draws the × and emits `remove` when it is pressed. */
|
|
67
|
+
removable: { type: Boolean, default: false },
|
|
68
|
+
/**
|
|
69
|
+
* The × 's accessible name. Defaults to `Remove <the printed label>`, which
|
|
70
|
+
* is right for an identifier chip ("Remove KEY-309"); give it explicitly
|
|
71
|
+
* whenever the printed text alone would not tell a screen-reader user what
|
|
72
|
+
* is about to be taken away.
|
|
73
|
+
*/
|
|
74
|
+
removeLabel: { type: String, default: "" },
|
|
50
75
|
});
|
|
51
76
|
|
|
77
|
+
const emit = defineEmits<{ (e: "remove"): void }>();
|
|
78
|
+
|
|
52
79
|
const toneClass = computed(() =>
|
|
53
80
|
props.tone ? `tone-${props.tone}` : statusToneClass(props.status)
|
|
54
81
|
);
|
|
@@ -83,6 +110,42 @@ const toneClass = computed(() =>
|
|
|
83
110
|
font-size: var(--fs-chip);
|
|
84
111
|
}
|
|
85
112
|
|
|
113
|
+
/*
|
|
114
|
+
* A 12px glyph needs a 24px target to stay pressable at 360px, but the chip is
|
|
115
|
+
* only 24px tall - so the hit area is INSET into the pill's own padding rather
|
|
116
|
+
* than added to it. The negative margin is what keeps the × from making a
|
|
117
|
+
* removable chip taller than the read-only one beside it.
|
|
118
|
+
*/
|
|
119
|
+
.status-chip__x {
|
|
120
|
+
display: inline-flex;
|
|
121
|
+
align-items: center;
|
|
122
|
+
justify-content: center;
|
|
123
|
+
width: 24px;
|
|
124
|
+
height: 24px;
|
|
125
|
+
margin: -6px -6px -6px 0;
|
|
126
|
+
padding: 0;
|
|
127
|
+
border: none;
|
|
128
|
+
border-radius: var(--r-pill);
|
|
129
|
+
background: transparent;
|
|
130
|
+
/* Chips read as labels first and controls second, so the × sits back from
|
|
131
|
+
the word until it is reached for. */
|
|
132
|
+
color: inherit;
|
|
133
|
+
opacity: 0.62;
|
|
134
|
+
cursor: pointer;
|
|
135
|
+
transition: opacity var(--motion) ease, background var(--motion) ease;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
.status-chip__x:hover,
|
|
139
|
+
.status-chip__x:focus-visible {
|
|
140
|
+
opacity: 1;
|
|
141
|
+
background: rgba(0, 0, 0, 0.06);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
.v-theme--dark .status-chip__x:hover,
|
|
145
|
+
.v-theme--dark .status-chip__x:focus-visible {
|
|
146
|
+
background: rgba(255, 255, 255, 0.08);
|
|
147
|
+
}
|
|
148
|
+
|
|
86
149
|
.status-chip__dot {
|
|
87
150
|
width: 6px;
|
|
88
151
|
height: 6px;
|
|
@@ -613,15 +613,21 @@
|
|
|
613
613
|
class="d-flex align-center"
|
|
614
614
|
>
|
|
615
615
|
<strong>{{ label }}:</strong>
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
616
|
+
<!-- The design's check-in / check-out pair. Was Vuetify's
|
|
617
|
+
`color="success"` beside a hardcoded `color="red"` - two
|
|
618
|
+
different systems on one field list, and neither of them a
|
|
619
|
+
token. `:loading` is dropped rather than re-invented: the
|
|
620
|
+
same flag already drives `:disabled`, which is the
|
|
621
|
+
precedent set when the scanned-visitor form converted. -->
|
|
622
|
+
<AppButton
|
|
623
|
+
variant="ok"
|
|
624
|
+
icon="mdi-check"
|
|
625
|
+
class="ml-3"
|
|
621
626
|
:disabled="isVisitorDataFromScannedQRCodeCheckingInOut"
|
|
622
627
|
@click="handleCheckin(selectedVisitorDataObject)"
|
|
623
|
-
|
|
624
|
-
|
|
628
|
+
>
|
|
629
|
+
Check In
|
|
630
|
+
</AppButton>
|
|
625
631
|
</span>
|
|
626
632
|
<span
|
|
627
633
|
v-if="
|
|
@@ -633,14 +639,15 @@
|
|
|
633
639
|
class="d-flex align-center"
|
|
634
640
|
>
|
|
635
641
|
<strong>{{ label }}:</strong>
|
|
636
|
-
<
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
text="Checkout"
|
|
642
|
+
<AppButton
|
|
643
|
+
variant="err"
|
|
644
|
+
icon="mdi-close"
|
|
645
|
+
class="ml-3"
|
|
641
646
|
:disabled="loading.checkingOut"
|
|
642
647
|
@click="handleCheckout(selectedVisitorId as string)"
|
|
643
|
-
|
|
648
|
+
>
|
|
649
|
+
Check Out
|
|
650
|
+
</AppButton>
|
|
644
651
|
</span>
|
|
645
652
|
|
|
646
653
|
<span
|
package/nuxt.config.ts
CHANGED
|
@@ -20,6 +20,11 @@ export default defineNuxtConfig({
|
|
|
20
20
|
* leave the whole product looking half-migrated; each phase adopts the token
|
|
21
21
|
* as it rebuilds its own surfaces. Browsers do not download a webfont no
|
|
22
22
|
* element uses, so until then this costs one small CSS request.
|
|
23
|
+
*
|
|
24
|
+
* The second family is the redesign's icon set. Its axis ranges are the
|
|
25
|
+
* handoff's, character for character (`opsz,wght,FILL,GRAD@20..48,300..700,
|
|
26
|
+
* 0..1,0`) - do not widen or narrow them without a design change to point
|
|
27
|
+
* at. `plugins/vuetify.ts` and `assets/css/primitives.css` do the applying.
|
|
23
28
|
*/
|
|
24
29
|
app: {
|
|
25
30
|
head: {
|
|
@@ -32,7 +37,7 @@ export default defineNuxtConfig({
|
|
|
32
37
|
},
|
|
33
38
|
{
|
|
34
39
|
rel: "stylesheet",
|
|
35
|
-
href: "https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,
|
|
40
|
+
href: "https://fonts.googleapis.com/css2?family=Manrope:wght@400;500;600;700;800&family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,300..700,0..1,0&display=swap",
|
|
36
41
|
},
|
|
37
42
|
],
|
|
38
43
|
},
|
package/package.json
CHANGED
|
@@ -2,9 +2,30 @@
|
|
|
2
2
|
"name": "@7365admin1/layer-common",
|
|
3
3
|
"license": "MIT",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"version": "3.2.2-staging.
|
|
5
|
+
"version": "3.2.2-staging.123",
|
|
6
6
|
"author": "7365admin1",
|
|
7
7
|
"main": "./nuxt.config.ts",
|
|
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.",
|
|
9
|
+
"files": [
|
|
10
|
+
"CHANGELOG.md",
|
|
11
|
+
"app.vue",
|
|
12
|
+
"error.vue",
|
|
13
|
+
"nuxt.config.ts",
|
|
14
|
+
"tsconfig.json",
|
|
15
|
+
".nuxtrc",
|
|
16
|
+
"assets",
|
|
17
|
+
"components",
|
|
18
|
+
"composables",
|
|
19
|
+
"constants",
|
|
20
|
+
"layouts",
|
|
21
|
+
"middleware",
|
|
22
|
+
"pages",
|
|
23
|
+
"plugins",
|
|
24
|
+
"public",
|
|
25
|
+
"services",
|
|
26
|
+
"types",
|
|
27
|
+
"utils"
|
|
28
|
+
],
|
|
8
29
|
"publishConfig": {
|
|
9
30
|
"access": "public"
|
|
10
31
|
},
|
package/plugins/vuetify.ts
CHANGED
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
import "vuetify-pro-tiptap/style.css";
|
|
44
44
|
|
|
45
45
|
import { LIGHT_THEME, DARK_THEME } from "../utils/theme";
|
|
46
|
+
import { MDI_TO_SYMBOL } from "../utils/materialSymbols";
|
|
46
47
|
import { THEME_COOKIE } from "../composables/useThemePreference";
|
|
47
48
|
import type { CookieOptions } from "#app";
|
|
48
49
|
|
|
@@ -56,6 +57,41 @@ import "../assets/css/shell.css";
|
|
|
56
57
|
import "../assets/css/screens.css";
|
|
57
58
|
import "../assets/css/primitives.css";
|
|
58
59
|
|
|
60
|
+
/**
|
|
61
|
+
* THE ICON SET.
|
|
62
|
+
*
|
|
63
|
+
* The design handoff draws icons with Google's `Material Symbols Outlined`
|
|
64
|
+
* variable font - the stylesheet for it is already requested in
|
|
65
|
+
* `nuxt.config.ts` - while the product asks for Material Design Icons names
|
|
66
|
+
* (`mdi-close`, `mdi-magnify`, ...) in roughly 680 places here and again in
|
|
67
|
+
* every application. Translating at the icon set means none of those call sites
|
|
68
|
+
* change: a component still writes `mdi-close`, and this renders the Material
|
|
69
|
+
* Symbols glyph for it.
|
|
70
|
+
*
|
|
71
|
+
* A name with no entry in the table falls through to the previous Iconify
|
|
72
|
+
* rendering, so an unrecognised icon draws its old glyph instead of a blank
|
|
73
|
+
* box. `mdi-blank` maps to an empty string on purpose - it is mdi's deliberate
|
|
74
|
+
* spacer, and `.v-icon` keeps the 1em box.
|
|
75
|
+
*
|
|
76
|
+
* `icon` and `tag` are declared props so Vue does not also emit them as
|
|
77
|
+
* literal attributes; everything else Vuetify passes (the `v-icon` classes,
|
|
78
|
+
* size, colour, click handling) falls through to the root element untouched.
|
|
79
|
+
*/
|
|
80
|
+
const MaterialSymbol = (props: any) => {
|
|
81
|
+
// "mdi-loading mdi-spin" - the name first, any mdi modifier classes after it.
|
|
82
|
+
const [name, ...modifiers] = String(props.icon ?? "").split(/\s+/);
|
|
83
|
+
const symbol = MDI_TO_SYMBOL[name];
|
|
84
|
+
|
|
85
|
+
return symbol === undefined
|
|
86
|
+
? h(Icon, { icon: props.icon })
|
|
87
|
+
: h(
|
|
88
|
+
props.tag ?? "span",
|
|
89
|
+
{ class: ["material-symbols-outlined", ...modifiers] },
|
|
90
|
+
symbol,
|
|
91
|
+
);
|
|
92
|
+
};
|
|
93
|
+
MaterialSymbol.props = ["icon", "tag"];
|
|
94
|
+
|
|
59
95
|
export default defineNuxtPlugin((app) => {
|
|
60
96
|
/**
|
|
61
97
|
* BOOT ON THE REMEMBERED THEME, DON'T CORRECT IT AFTERWARDS.
|
|
@@ -145,7 +181,7 @@ export default defineNuxtPlugin((app) => {
|
|
|
145
181
|
defaultSet: "iconify",
|
|
146
182
|
sets: {
|
|
147
183
|
iconify: {
|
|
148
|
-
component:
|
|
184
|
+
component: MaterialSymbol,
|
|
149
185
|
},
|
|
150
186
|
},
|
|
151
187
|
},
|