@7365admin1/layer-common 3.2.2-staging.89 → 3.2.2-staging.91

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.
@@ -1,68 +1,65 @@
1
1
  <template>
2
- <v-row no-gutters>
3
- <v-col cols="12" class="mb-2">
4
- <v-row no-gutters>
5
- <v-btn
6
- v-if="props.seatManagement !== 'index'"
7
- class="text-none screen-btn-primary"
8
- variant="flat"
2
+ <div>
3
+ <!--
4
+ THE DESIGN'S PAGE SCAFFOLD.
5
+
6
+ The handoff opens Members with a 22px title row and puts the tabs INSIDE
7
+ the card's first row, with the pagination on the far end of that same
8
+ line. Before this the screen had no title at all - the page name existed
9
+ only in the rail and the browser tab - and the tabs sat in a toolbar
10
+ extension, i.e. a second stacked bar below a mostly empty one.
11
+
12
+ Nothing here changes what the screen does: the same two tabs route the
13
+ same way, the same refresh and pager call the same `getAll()`, the same
14
+ `headers` prop drives the same columns, and the same menu carries the
15
+ same four actions behind the same permission conditions.
16
+ -->
17
+ <PageHeader :title="props.title">
18
+ <template v-if="props.seatManagement !== 'index'" #actions>
19
+ <AppButton
9
20
  :to="{
10
21
  name: props.seatManagement,
11
22
  params: { organization: props.orgId },
12
23
  }"
13
- size="large"
14
24
  >
15
25
  Manage seats
16
- </v-btn>
17
- </v-row>
18
- </v-col>
19
-
20
- <v-col cols="12">
21
- <v-card width="100%" variant="flat" class="table-card">
22
- <v-toolbar
23
- density="compact"
24
- color="transparent"
25
- class="table-card__toolbar"
26
- >
27
- <template #prepend>
28
- <v-btn fab icon density="comfortable" @click="getAll()">
29
- <v-icon>mdi-refresh</v-icon>
30
- </v-btn>
31
- </template>
32
-
33
- <template #append>
34
- <v-row no-gutters justify="end" align="center">
35
- <span class="mr-2 table-card__range">
36
- {{ pageRange }}
37
- </span>
38
- <local-pagination
39
- v-model="page"
40
- :length="pages"
41
- @update:value="getAll()"
42
- />
43
- </v-row>
44
- </template>
45
-
46
- <template #extension>
47
- <v-tabs
48
- v-model="selectedStatus"
49
- color="primary"
50
- :height="40"
51
- @update:model-value="toRoute"
52
- class="w-100"
53
- >
54
- <v-tab
55
- v-for="(tab, i) in tabOptions"
56
- :value="tab.status"
57
- :key="i"
58
- class="text-capitalize"
59
- >
60
- {{ tab.name }}
61
- </v-tab>
62
- </v-tabs>
63
- </template>
64
- </v-toolbar>
65
-
26
+ </AppButton>
27
+ </template>
28
+ </PageHeader>
29
+
30
+ <AppCard class="table-card">
31
+ <CardToolbar :count="pageRange">
32
+ <template #tabs>
33
+ <button
34
+ v-for="(tab, i) in tabOptions"
35
+ :key="i"
36
+ type="button"
37
+ role="tab"
38
+ class="app-tab"
39
+ :class="{ 'app-tab--active': selectedStatus === tab.status }"
40
+ :aria-selected="selectedStatus === tab.status"
41
+ @click="toRoute(tab.status)"
42
+ >
43
+ {{ tab.name }}
44
+ </button>
45
+ </template>
46
+
47
+ <template #right>
48
+ <AppButton
49
+ variant="icon"
50
+ icon="mdi-refresh"
51
+ aria-label="Refresh"
52
+ @click="getAll()"
53
+ />
54
+ <local-pagination
55
+ v-model="page"
56
+ :length="pages"
57
+ @update:value="getAll()"
58
+ />
59
+ </template>
60
+ </CardToolbar>
61
+
62
+ <div class="app-table-scroll">
66
63
  <v-data-table
67
64
  :headers="props.headers"
68
65
  :items="items"
@@ -76,6 +73,13 @@
76
73
  <template #item.nature="{ item }">
77
74
  {{ replaceMatch(item.nature, "_", " ") }}
78
75
  </template>
76
+ <!-- The role is a soft pill in the design, not a plain word. Same
77
+ text, same column, same source field. -->
78
+ <template #item.roleName="{ item }">
79
+ <StatusChip v-if="item.roleName" :dot="false" pill tone="info">
80
+ {{ item.roleName }}
81
+ </StatusChip>
82
+ </template>
79
83
  <template #item.dateInvited="{ item }">
80
84
  {{ formatDateInvited(item.dateInvited) }}
81
85
  </template>
@@ -92,8 +96,13 @@
92
96
  offset-y
93
97
  width="150"
94
98
  >
95
- <template v-slot:activator="{ props }">
96
- <v-icon v-bind="props">mdi-dots-vertical</v-icon>
99
+ <template v-slot:activator="{ props: menuProps }">
100
+ <AppButton
101
+ v-bind="menuProps"
102
+ variant="row"
103
+ icon="mdi-dots-vertical"
104
+ aria-label="Member actions"
105
+ />
97
106
  </template>
98
107
  <v-list>
99
108
  <v-list-item
@@ -131,8 +140,9 @@
131
140
  </v-menu>
132
141
  </template>
133
142
  </v-data-table>
134
- </v-card>
135
- </v-col>
143
+ </div>
144
+ </AppCard>
145
+
136
146
  <ConfirmDialog
137
147
  v-model="confirmDialog"
138
148
  :loading="updateLoading"
@@ -235,11 +245,17 @@
235
245
  </v-card-text>
236
246
  </v-card>
237
247
  </v-dialog>
238
- </v-row>
248
+ </div>
239
249
  </template>
240
250
 
241
251
  <script setup lang="ts">
242
252
  const props = defineProps({
253
+ /** The design's page title. Every app that mounts this screen calls it
254
+ Members; a caller that names it otherwise passes its own. */
255
+ title: {
256
+ type: String,
257
+ default: "Members",
258
+ },
243
259
  orgId: {
244
260
  type: String,
245
261
  default: "",
@@ -0,0 +1,40 @@
1
+ <!--
2
+ THE PAGE TITLE ROW.
3
+
4
+ The design opens EVERY screen with this row: the page's name at 22px/800,
5
+ and the screen's primary action on the right of the same line. The product
6
+ has never had it - the page name lived only in the browser tab and in the
7
+ navigation rail - which is the single most visible difference between the
8
+ staging site and the handoff.
9
+
10
+ It is a label and a slot. It fetches nothing, decides nothing and navigates
11
+ nowhere; the action passed into it is the screen's own button.
12
+ -->
13
+ <template>
14
+ <div class="app-page-head">
15
+ <div>
16
+ <h1 class="app-page-head__title">
17
+ <slot name="title">{{ title }}</slot>
18
+ </h1>
19
+
20
+ <!-- The design's second line: a location, a count, a date range. Only
21
+ drawn when a screen supplies one. -->
22
+ <div v-if="subtitle || $slots.subtitle" class="app-page-head__sub">
23
+ <v-icon v-if="subtitleIcon" :icon="subtitleIcon" size="15" />
24
+ <slot name="subtitle">{{ subtitle }}</slot>
25
+ </div>
26
+ </div>
27
+
28
+ <div v-if="$slots.actions" class="app-page-head__actions">
29
+ <slot name="actions" />
30
+ </div>
31
+ </div>
32
+ </template>
33
+
34
+ <script setup lang="ts">
35
+ defineProps({
36
+ title: { type: String, default: "" },
37
+ subtitle: { type: String, default: "" },
38
+ subtitleIcon: { type: String, default: "" },
39
+ });
40
+ </script>
@@ -10,7 +10,10 @@
10
10
  translate or shorten a status.
11
11
  -->
12
12
  <template>
13
- <span class="status-chip" :class="[toneClass, { 'status-chip--plain': !dot }]">
13
+ <span
14
+ class="status-chip"
15
+ :class="[toneClass, { 'status-chip--plain': !dot && !pill, 'status-chip--pill': pill }]"
16
+ >
14
17
  <span v-if="dot" class="status-chip__dot" />
15
18
  <!-- The slot is for the chips that already carried an icon next to their
16
19
  word - a padlock on "Closed - View Only" - so adopting the design's
@@ -27,8 +30,14 @@ const props = defineProps({
27
30
  status: { type: String, default: "" },
28
31
  /** What to PRINT, when that differs from the word being matched on. */
29
32
  label: { type: String, default: undefined },
30
- /** The design's tag chips (pass IDs, role names) carry no leading dot. */
33
+ /** The design's tag chips (pass IDs, counts) carry no leading dot. */
31
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 },
32
41
  /**
33
42
  * For the chips that are not a status WORD at all - a countdown, a rating, a
34
43
  * count - where the screen has already worked out the meaning and only needs
@@ -68,6 +77,12 @@ const toneClass = computed(() =>
68
77
  font-size: var(--fs-chip);
69
78
  }
70
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
+
71
86
  .status-chip__dot {
72
87
  width: 6px;
73
88
  height: 6px;
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.89",
5
+ "version": "3.2.2-staging.91",
6
6
  "author": "7365admin1",
7
7
  "main": "./nuxt.config.ts",
8
8
  "publishConfig": {
@@ -54,6 +54,7 @@ import type { CookieOptions } from "#app";
54
54
  import "../assets/css/tokens.css";
55
55
  import "../assets/css/shell.css";
56
56
  import "../assets/css/screens.css";
57
+ import "../assets/css/primitives.css";
57
58
 
58
59
  export default defineNuxtPlugin((app) => {
59
60
  /**