@7365admin1/layer-common 3.2.2-staging.111 → 3.2.2-staging.113

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,71 +1,67 @@
1
1
  <template>
2
- <v-card width="100%">
3
- <v-toolbar>
4
- <template v-if="$slots.header">
5
- <slot name="header" :title="title" :onClose="onClose" />
6
- </template>
7
- <template v-else>
8
- <v-row no-gutters class="fill-height px-6" align="center">
9
- <span class="font-weight-bold text-h5 text-capitalize">{{
10
- title
11
- }}</span>
12
- </v-row>
13
- </template>
14
- </v-toolbar>
2
+ <!-- The shared detail sheet several list screens open a row into. Its title
3
+ row and its footer were both `v-toolbar`s - fixed grey slabs that stay
4
+ grey on the dark theme - and the footer's action was a hardcoded
5
+ `color="black"` fill. -->
6
+ <v-card class="screen-modal" width="100%">
7
+ <template v-if="$slots.header">
8
+ <slot name="header" :title="title" :onClose="onClose" />
9
+ </template>
10
+ <v-card-title v-else class="text-capitalize">{{ title }}</v-card-title>
15
11
 
16
- <v-card-text style="max-height: 100vh; overflow-y: auto" class="pb-0" :class="contentNoPadding ? 'pa-0' : ''">
12
+ <v-card-text class="screen-modal__body pb-0" :class="contentNoPadding ? 'pa-0' : ''">
17
13
  <slot name="content" />
18
14
  </v-card-text>
19
15
 
20
- <v-toolbar class="pa-0" density="compact">
21
- <v-row no-gutters>
22
- <v-col :cols="(canUpdate || canDelete) ? 6 : 12" class="pa-0">
16
+ <!-- The design's footer strip: equal-width buttons, ghost then primary. -->
17
+ <div class="screen-modal__footer">
18
+ <v-btn
19
+ variant="outlined"
20
+ class="screen-btn-ghost"
21
+ @click="emit('close')"
22
+ >
23
+ Close
24
+ </v-btn>
25
+
26
+ <v-menu v-if="canUpdate || canDelete" contained>
27
+ <template #activator="{ props }">
23
28
  <v-btn
24
- block
25
- variant="text"
26
- class="text-none"
27
- size="large"
28
- @click="emit('close')"
29
- height="48"
29
+ variant="flat"
30
+ class="screen-btn-primary"
31
+ :disabled="disabled"
32
+ v-bind="props"
30
33
  >
31
- Close
34
+ More actions
32
35
  </v-btn>
33
- </v-col>
34
-
35
- <v-col v-if="canUpdate || canDelete" cols="6" class="pa-0" >
36
- <v-menu contained>
37
- <template #activator="{ props }">
38
- <v-btn
39
- block
40
- variant="flat"
41
- color="black"
42
- class="text-none"
43
- height="48"
44
- :disabled="disabled"
45
- v-bind="props"
46
- tile
47
- >
48
- More actions
49
- </v-btn>
50
- </template>
36
+ </template>
51
37
 
52
- <v-list class="pa-0">
53
- <v-list-item v-if="canUpdate" @click="emit('edit')">
54
- <v-list-item-title class="text-subtitle-2">
55
- {{ editButtonLabel }}
56
- </v-list-item-title>
57
- </v-list-item>
38
+ <!-- The dropdown itself is left as Vuetify draws it: the handoff
39
+ specifies the PROFILE dropdown (240px, 14px radius) and mentions a
40
+ per-row kebab menu without giving it a shape, and this menu opens
41
+ on a click the harness cannot drive, so it could not be
42
+ render-verified either. Only the row type and the destructive ink
43
+ change. -->
44
+ <v-list class="pa-0 update-more__list">
45
+ <v-list-item v-if="canUpdate" @click="emit('edit')">
46
+ <v-list-item-title>
47
+ {{ editButtonLabel }}
48
+ </v-list-item-title>
49
+ </v-list-item>
58
50
 
59
- <v-list-item v-if="canDelete" @click="emit('delete')" class="text-red">
60
- <v-list-item-title class="text-subtitle-2">
61
- {{ deleteButtonLabel }}
62
- </v-list-item-title>
63
- </v-list-item>
64
- </v-list>
65
- </v-menu>
66
- </v-col>
67
- </v-row>
68
- </v-toolbar>
51
+ <!-- `text-red` was Vuetify's fixed #f44336, the same red on both
52
+ themes. `text-error` is Vuetify's own class over
53
+ `--v-theme-error`, which IS the design's `--err`. The handoff's
54
+ one documented destructive treatment is the profile menu's
55
+ Logout row: "red Logout row (err color, err-bg hover)" - ink,
56
+ not a filled button - so this row follows it exactly. -->
57
+ <v-list-item v-if="canDelete" @click="emit('delete')" class="text-error">
58
+ <v-list-item-title>
59
+ {{ deleteButtonLabel }}
60
+ </v-list-item-title>
61
+ </v-list-item>
62
+ </v-list>
63
+ </v-menu>
64
+ </div>
69
65
  </v-card>
70
66
  </template>
71
67
 
@@ -105,4 +101,11 @@ const emit = defineEmits(["close", "edit", "delete"]);
105
101
  const { canUpdate, editButtonLabel, deleteButtonLabel, title, disabled } = prop;
106
102
  </script>
107
103
 
108
- <style scoped></style>
104
+ <style scoped>
105
+ /* `text-subtitle-2` was Vuetify's 0.875rem/500; the handoff names no type for
106
+ a menu row, so it takes the established cell type. */
107
+ .update-more__list :deep(.v-list-item-title) {
108
+ font-size: var(--fs-cell);
109
+ font-weight: var(--fw-cell);
110
+ }
111
+ </style>
@@ -1,13 +1,8 @@
1
1
  <template>
2
- <v-card width="100%">
3
- <v-toolbar>
4
- <v-row no-gutters class="fill-height px-6" align="center">
5
- <span class="font-weight-bold text-h5 text-capitalize">
6
- {{ prop.mode }} Document
7
- </span>
8
- </v-row>
9
- </v-toolbar>
10
- <v-card-text style="max-height: 100vh; overflow-y: auto" class="pa-0">
2
+ <v-card width="100%" class="screen-modal">
3
+ <v-card-title class="text-capitalize">{{ prop.mode }} Document</v-card-title>
4
+
5
+ <v-card-text class="screen-modal__body pa-0">
11
6
  <v-form v-model="validForm" :disabled="disable">
12
7
  <v-col cols="12" class="px-6">
13
8
  <InputLabel class="text-capitalize" title="Document Attachment" />
@@ -24,6 +19,7 @@
24
19
  <InputLabel class="text-capitalize" title="Document Name" />
25
20
  <v-text-field
26
21
  v-model.trim="document.name"
22
+ class="filter-field"
27
23
  density="comfortable"
28
24
  ></v-text-field>
29
25
  </v-col>
@@ -42,15 +38,15 @@
42
38
  </v-form>
43
39
  </v-card-text>
44
40
 
45
- <v-toolbar density="compact">
41
+ <!-- Was a `v-toolbar`: a grey slab with square (`tile`) buttons and a
42
+ hardcoded `color="black"` primary. The gate on Submit is unchanged. -->
43
+ <v-card-actions class="screen-modal__footer">
46
44
  <v-row no-gutters>
47
- <v-col cols="6">
45
+ <v-col cols="6" class="pr-2">
48
46
  <v-btn
49
- tile
50
47
  block
51
- variant="text"
52
- class="text-none"
53
- size="48"
48
+ variant="outlined"
49
+ class="text-none screen-btn-ghost"
54
50
  @click="cancel"
55
51
  :disabled="disable"
56
52
  >
@@ -58,14 +54,11 @@
58
54
  </v-btn>
59
55
  </v-col>
60
56
 
61
- <v-col cols="6">
57
+ <v-col cols="6" class="pl-2">
62
58
  <v-btn
63
- tile
64
59
  block
65
60
  variant="flat"
66
- color="black"
67
- class="text-none"
68
- size="48"
61
+ class="text-none screen-btn-primary"
69
62
  :disabled="
70
63
  !validForm ||
71
64
  disable ||
@@ -79,7 +72,7 @@
79
72
  </v-btn>
80
73
  </v-col>
81
74
  </v-row>
82
- </v-toolbar>
75
+ </v-card-actions>
83
76
  </v-card>
84
77
  </template>
85
78
  <script setup lang="ts">
@@ -1,14 +1,24 @@
1
1
  <template>
2
2
  <v-dialog :model-value="modelValue" :max-width="fileType === 'image' ? '1200' : '900'" scrollable
3
3
  @update:model-value="emit('update:modelValue', $event)">
4
- <v-card>
5
- <v-toolbar density="compact">
6
- <v-toolbar-title class="text-subtitle-2 text-truncate">{{ fileName }}</v-toolbar-title>
7
- <v-spacer />
8
- <v-btn icon="mdi-open-in-new" variant="text" size="small" @click="openInNewTab()" />
9
- <v-btn icon="mdi-close" variant="text" size="small" @click="emit('update:modelValue', false)" />
10
- </v-toolbar>
11
- <v-card-text class="pa-0"
4
+ <!-- The card wears `.screen-modal` for the 16px corner, the `--card`
5
+ surface and the modal shadow. The `v-toolbar` header was a fixed
6
+ grey slab that stays grey on the dark theme; the design's modal
7
+ header is a title and its controls on the card's own surface over
8
+ a 1px `--border` rule, which is what this now draws. -->
9
+ <v-card class="screen-modal">
10
+ <v-card-title class="d-flex align-center ga-1 doc-viewer__head">
11
+ <span class="flex-grow-1 text-truncate">{{ fileName }}</span>
12
+ <!-- `.screen-modal__close` is the handoff's modal control:
13
+ 32x32, 8px radius, borderless, `--muted` ink. The handoff
14
+ draws only a close in that row; a second control beside it
15
+ is a case it is silent on, so it takes the same shape. -->
16
+ <v-btn icon="mdi-open-in-new" variant="text" size="small" class="screen-modal__close"
17
+ @click="openInNewTab()" />
18
+ <v-btn icon="mdi-close" variant="text" size="small" class="screen-modal__close"
19
+ @click="emit('update:modelValue', false)" />
20
+ </v-card-title>
21
+ <v-card-text class="screen-modal__body pa-0"
12
22
  :style="{ height: fileType === 'image' ? 'auto' : '75vh', 'overflow-y': fileType === 'image' ? 'auto' : 'auto' }">
13
23
  <!-- Image Viewer -->
14
24
  <v-img v-if="fileType === 'image'" :src="getFileUrl(fileId)" :alt="fileName" class="w-100" />
@@ -24,13 +34,12 @@
24
34
  <iframe v-else :src="getFileUrl(fileId)" width="100%" height="100%" style="border: none;"
25
35
  :title="fileName" />
26
36
  </v-card-text>
27
- <v-card-actions>
28
- <v-spacer />
29
- <v-btn variant="text" class="text-none" @click="openInNewTab()">
37
+ <div class="screen-modal__footer">
38
+ <v-btn variant="outlined" class="screen-btn-ghost" @click="openInNewTab()">
30
39
  <v-icon start>mdi-download</v-icon>
31
40
  Open / Download
32
41
  </v-btn>
33
- </v-card-actions>
42
+ </div>
34
43
  </v-card>
35
44
  </v-dialog>
36
45
  </template>
@@ -73,3 +82,11 @@ function openInNewTab() {
73
82
  window.open(getFileUrl(props.fileId), '_blank', 'noopener,noreferrer');
74
83
  }
75
84
  </script>
85
+
86
+ <style scoped>
87
+ /* The handoff's modal header sits over a 1px --border rule, the same rule the
88
+ footer strip sits under. */
89
+ .doc-viewer__head {
90
+ border-bottom: 1px solid var(--border);
91
+ }
92
+ </style>
@@ -1,14 +1,8 @@
1
1
  <template>
2
- <v-card width="100%">
3
- <v-toolbar>
4
- <v-row no-gutters class="fill-height px-6" align="center">
5
- <span class="font-weight-bold text-h5">
6
- {{ props.title }}
7
- </span>
8
- </v-row>
9
- </v-toolbar>
2
+ <v-card width="100%" class="screen-modal">
3
+ <v-card-title>{{ props.title }}</v-card-title>
10
4
 
11
- <v-card-text style="max-height: 100vh; overflow-y: auto">
5
+ <v-card-text class="screen-modal__body">
12
6
  <v-form v-model="validForm" ref="form" :disabled="disable">
13
7
  <v-row no-gutters>
14
8
 
@@ -17,6 +11,7 @@
17
11
  <InputLabel title="Email" required />
18
12
  <v-text-field
19
13
  v-model="invite.email"
14
+ class="filter-field"
20
15
  density="comfortable"
21
16
  :rules="[requiredRule, emailRule]"
22
17
  :loading="loading.verifyingEmail"
@@ -37,6 +32,7 @@
37
32
  multiple
38
33
  chips
39
34
  closable-chips
35
+ class="filter-field"
40
36
  density="comfortable"
41
37
  :rules="[requiredRule]"
42
38
  @update:model-value="handleUpdateApp"
@@ -50,8 +46,9 @@
50
46
  <v-checkbox-btn
51
47
  :model-value="invite.app.includes(item.raw.value)"
52
48
  :disabled="item.raw.disabled"
53
- color="black"
54
- density="comfortable"
49
+ color="primary"
50
+ class="filter-field"
51
+ density="comfortable"
55
52
  />
56
53
  </template>
57
54
 
@@ -79,6 +76,7 @@
79
76
  :items="roles"
80
77
  item-title="name"
81
78
  item-value="_id"
79
+ class="filter-field"
82
80
  density="comfortable"
83
81
  :rules="[requiredRule]"
84
82
  />
@@ -90,6 +88,7 @@
90
88
  <v-autocomplete
91
89
  v-model="invite.site"
92
90
  :items="sites"
91
+ class="filter-field"
93
92
  density="comfortable"
94
93
  :rules="[requiredRule]"
95
94
  @update:model-value="handleUpdateSite"
@@ -109,21 +108,24 @@
109
108
  </v-card-text>
110
109
 
111
110
  <!-- ACTION -->
112
- <v-toolbar density="compact">
111
+ <v-card-actions class="screen-modal__footer">
113
112
  <v-row no-gutters>
114
- <v-col cols="6">
115
- <v-btn block variant="text" class="text-none" size="48" @click="cancel">
113
+ <v-col cols="6" class="pr-2">
114
+ <v-btn
115
+ block
116
+ variant="outlined"
117
+ class="text-none screen-btn-ghost"
118
+ @click="cancel"
119
+ >
116
120
  Cancel
117
121
  </v-btn>
118
122
  </v-col>
119
123
 
120
- <v-col cols="6">
124
+ <v-col cols="6" class="pl-2">
121
125
  <v-btn
122
126
  block
123
127
  variant="flat"
124
- color="black"
125
- class="text-none"
126
- size="48"
128
+ class="text-none screen-btn-primary"
127
129
  :disabled="!validForm"
128
130
  :loading="loading.submittingForm"
129
131
  @click="submit"
@@ -132,7 +134,7 @@
132
134
  </v-btn>
133
135
  </v-col>
134
136
  </v-row>
135
- </v-toolbar>
137
+ </v-card-actions>
136
138
  </v-card>
137
139
  </template>
138
140
 
@@ -1,13 +1,8 @@
1
1
  <template>
2
- <v-card width="100%">
3
- <v-toolbar>
4
- <v-row no-gutters class="fill-height px-6" align="center">
5
- <span class="font-weight-bold text-h5">
6
- {{ props.title }}
7
- </span>
8
- </v-row>
9
- </v-toolbar>
10
- <v-card-text style="max-height: 100vh; overflow-y: auto">
2
+ <v-card width="100%" class="screen-modal">
3
+ <v-card-title>{{ props.title }}</v-card-title>
4
+
5
+ <v-card-text class="screen-modal__body">
11
6
  <v-form v-model="validForm" ref="form" :disabled="disable">
12
7
  <v-row no-gutters>
13
8
  <v-col cols="12" class="mt-2">
@@ -16,6 +11,7 @@
16
11
  <v-col cols="12">
17
12
  <v-text-field
18
13
  v-model="invite.email"
14
+ class="filter-field"
19
15
  density="comfortable"
20
16
  :rules="[requiredRule, emailRule]"
21
17
  :loading="loading.verifyingEmail"
@@ -34,6 +30,7 @@
34
30
  <v-col cols="12">
35
31
  <v-autocomplete
36
32
  v-model="invite.app"
33
+ class="filter-field"
37
34
  density="comfortable"
38
35
  :rules="[requiredRule]"
39
36
  :items="apps"
@@ -53,6 +50,7 @@
53
50
  item-title="name"
54
51
  item-value="_id"
55
52
  :rules="[requiredRule]"
53
+ class="filter-field"
56
54
  density="comfortable"
57
55
  ></v-autocomplete>
58
56
  </v-col>
@@ -66,6 +64,7 @@
66
64
  <v-autocomplete
67
65
  v-model="invite.site"
68
66
  :items="sites"
67
+ class="filter-field"
69
68
  density="comfortable"
70
69
  :rules="[requiredRule]"
71
70
  @update:model-value="handleUpdateSite"
@@ -99,29 +98,24 @@
99
98
  </v-form>
100
99
  </v-card-text>
101
100
 
102
- <v-toolbar density="compact">
101
+ <v-card-actions class="screen-modal__footer">
103
102
  <v-row no-gutters>
104
- <v-col cols="6">
103
+ <v-col cols="6" class="pr-2">
105
104
  <v-btn
106
- tile
107
105
  block
108
- variant="text"
109
- class="text-none"
110
- size="48"
106
+ variant="outlined"
107
+ class="text-none screen-btn-ghost"
111
108
  @click="cancel"
112
109
  >
113
110
  {{ props.cancelText }}
114
111
  </v-btn>
115
112
  </v-col>
116
113
 
117
- <v-col cols="6">
114
+ <v-col cols="6" class="pl-2">
118
115
  <v-btn
119
- tile
120
116
  block
121
117
  variant="flat"
122
- color="black"
123
- class="text-none"
124
- size="48"
118
+ class="text-none screen-btn-primary"
125
119
  :disabled="!validForm"
126
120
  :loading="loading.submittingForm"
127
121
  @click="submit"
@@ -130,7 +124,7 @@
130
124
  </v-btn>
131
125
  </v-col>
132
126
  </v-row>
133
- </v-toolbar>
127
+ </v-card-actions>
134
128
  </v-card>
135
129
  </template>
136
130
 
@@ -1,24 +1,28 @@
1
1
  <template>
2
+ <!-- 760px is kept: the handoff draws exactly one modal and it is the 520px
3
+ Create Role form, so a multi-section detail dialog is a case it is
4
+ silent on, and narrowing this one would wrap fifteen label/value rows
5
+ rather than follow anything. What changes is the chrome. -->
2
6
  <v-dialog v-model="model" max-width="760" scrollable>
3
- <v-card rounded="lg">
4
- <v-toolbar density="compact" color="grey-lighten-4">
5
- <v-toolbar-title class="text-subtitle-1 font-weight-bold">
6
- View Organization Information
7
- </v-toolbar-title>
8
- </v-toolbar>
7
+ <v-card class="screen-modal">
8
+ <!-- Was a `v-toolbar color="grey-lighten-4"` - a literal light grey that
9
+ stays light grey on the dark theme, i.e. a white bar across the top
10
+ of a dark card. A `v-card-title` is the same row on the card's own
11
+ surface. -->
12
+ <v-card-title>View Organization Information</v-card-title>
9
13
 
10
- <v-card-text class="py-4">
14
+ <v-card-text class="screen-modal__body py-4">
11
15
  <template v-for="section in sections" :key="section.title">
12
- <div class="text-subtitle-2 font-weight-bold mb-2">
16
+ <div class="screen-card-title mb-2">
13
17
  {{ section.title }}
14
18
  </div>
15
19
  <div
16
20
  v-for="row in section.rows"
17
21
  :key="row.label"
18
- class="d-flex justify-space-between py-1"
22
+ class="d-flex justify-space-between py-1 org-view__row"
19
23
  >
20
- <span class="text-body-2 text-medium-emphasis">{{ row.label }}</span>
21
- <span class="text-body-2 font-weight-medium text-right">
24
+ <span class="screen-hint">{{ row.label }}</span>
25
+ <span class="text-right org-view__value">
22
26
  {{ row.value || "--" }}
23
27
  </span>
24
28
  </div>
@@ -26,13 +30,13 @@
26
30
  </template>
27
31
  </v-card-text>
28
32
 
29
- <v-divider />
30
-
31
- <v-card-actions class="justify-center py-3">
32
- <v-btn variant="text" class="text-none" @click="model = false">
33
+ <!-- The design's bordered footer strip. `v-divider` plus a padded
34
+ actions row was the same thing drawn by hand. -->
35
+ <div class="screen-modal__footer">
36
+ <v-btn variant="outlined" class="screen-btn-ghost" @click="model = false">
33
37
  Close
34
38
  </v-btn>
35
- </v-card-actions>
39
+ </div>
36
40
  </v-card>
37
41
  </v-dialog>
38
42
  </template>
@@ -116,3 +120,17 @@ const sections = computed(() => {
116
120
  ];
117
121
  });
118
122
  </script>
123
+
124
+ <style scoped>
125
+ /* The handoff names no type for a label/value detail row, so both take the
126
+ established cell type: the label on `--muted` (it was `text-medium-emphasis`,
127
+ Vuetify's own 60%-alpha ink) and the value on the cell weight. */
128
+ .org-view__row {
129
+ font-size: var(--fs-cell);
130
+ }
131
+
132
+ .org-view__value {
133
+ font-weight: var(--fw-cell);
134
+ color: var(--text);
135
+ }
136
+ </style>
@@ -1,40 +1,54 @@
1
1
  <template>
2
- <v-card width="100%" :disabled="loading || processingPassword" :loading="loading || processingPassword">
3
- <v-toolbar density="compact">
4
- <v-row no-gutters class="pa-3 text-h6 font-weight-bold">
5
- <span>{{ promptTitle }}</span>
6
- </v-row>
7
- </v-toolbar>
8
- <v-card-text style="max-height: 100vh; overflow-y: auto" class="pa-5 my-5 px-7 text-center">
2
+ <!--
3
+ A dialog card, so it wears `.screen-modal` (16px corner, the modal shadow,
4
+ the `--card` surface). The two `v-toolbar`s it used to have were grey
5
+ slabs standing in for a title row and a footer - a `v-toolbar` keeps that
6
+ grey on the dark theme, so this dialog dropped a light slab onto a dark
7
+ card at both ends. A `v-card-title` and a `v-card-actions` are the same
8
+ two rows without the slab, and they follow the theme.
9
+ -->
10
+ <v-card class="screen-modal" width="100%" :disabled="loading || processingPassword" :loading="loading || processingPassword">
11
+ <v-card-title>{{ promptTitle }}</v-card-title>
12
+
13
+ <v-card-text class="screen-modal__body pa-5 my-5 px-7 text-center">
9
14
  <v-row no-gutters class="w-100">
10
15
  <v-col cols="12">
11
- <v-icon icon="mdi-lock-outline" :color="'gray'" class="text-h2" />
16
+ <!-- Was `:color="'gray'"`, a fixed Vuetify grey that is the
17
+ same grey on both themes. `--muted` is the design's
18
+ secondary ink and follows the theme. -->
19
+ <v-icon icon="mdi-lock-outline" class="text-h2 screen-lock-icon" />
12
20
  </v-col>
13
21
  <v-col cols="12" v-if="message" class="mt-2">
14
22
  {{ message }}
15
23
  </v-col>
16
24
  <v-col cols="12" class="mt-5 text-start">
17
- <v-text-field v-model="passwordInput" label="Password" type="password" density="compact" :error-messages="errorMessage"></v-text-field>
25
+ <!-- Still a `v-text-field`, not an `AppField`: it carries
26
+ the `:error-messages` surface that `handleConfirm`
27
+ writes the server's reply into, which `AppField` has
28
+ no equivalent for. `.filter-field` gives it the
29
+ design's 40px / 10px / 13.5px shape without taking
30
+ that away. -->
31
+ <v-text-field v-model="passwordInput" class="filter-field" label="Password" type="password" density="compact" :error-messages="errorMessage"></v-text-field>
18
32
  </v-col>
19
33
  </v-row>
20
34
  </v-card-text>
21
35
 
22
- <v-toolbar class="pa-0" density="compact">
23
- <v-row no-gutters>
24
- <v-col cols="6" class="pa-0">
25
- <v-btn block variant="text" class="text-none" size="large" tile @click="emit('cancel')" height="48">
26
- Cancel
27
- </v-btn>
28
- </v-col>
36
+ <!-- The design's footer: two equal-width buttons, ghost then primary,
37
+ on a bordered strip. The confirming button was a hardcoded
38
+ `color="red"` fill; the handoff draws no destructive button, so it
39
+ takes the primary shape like every other modal's confirm, and the
40
+ destructive-variant gap is raised for a design decision rather than
41
+ invented here. -->
42
+ <div class="screen-modal__footer">
43
+ <v-btn class="screen-btn-ghost" variant="outlined" @click="emit('cancel')">
44
+ Cancel
45
+ </v-btn>
29
46
 
30
- <v-col cols="6" class="pa-0">
31
- <v-btn block tile variant="flat" class="text-none" size="large" height="48" color="red" :disabled="!passwordInput"
32
- @click="handleConfirm">
33
- Confirm
34
- </v-btn>
35
- </v-col>
36
- </v-row>
37
- </v-toolbar>
47
+ <v-btn class="screen-btn-primary" variant="flat" :disabled="!passwordInput"
48
+ @click="handleConfirm">
49
+ Confirm
50
+ </v-btn>
51
+ </div>
38
52
  </v-card>
39
53
  </template>
40
54
 
@@ -75,7 +89,7 @@ async function handleConfirm() {
75
89
  const userId = currentUser.value?._id;
76
90
  if (!userId) {
77
91
  throw new Error('User not found. Please login again.');
78
- }
92
+ }
79
93
  const res = await confirmPassword({ userId, password: passwordInput.value });
80
94
  if (res) {
81
95
  emit('confirm');
@@ -92,4 +106,8 @@ async function handleConfirm() {
92
106
 
93
107
  </script>
94
108
 
95
- <style scoped></style>
109
+ <style scoped>
110
+ .screen-lock-icon {
111
+ color: var(--muted);
112
+ }
113
+ </style>