@visns-studio/visns-components 6.17.2 → 6.20.0
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/package.json +10 -7
- package/src/components/AssociationManager.jsx +344 -177
- package/src/components/AsyncSelect.jsx +2 -2
- package/src/components/Autocomplete.jsx +57 -12
- package/src/components/Breadcrumb.jsx +23 -4
- package/src/components/ClientAssociationManager.jsx +321 -145
- package/src/components/DataGrid.jsx +625 -20
- package/src/components/DropZone.jsx +4 -1
- package/src/components/Form.jsx +233 -6
- package/src/components/MultiSelect.jsx +2 -2
- package/src/components/Navigation.jsx +39 -23
- package/src/components/TableFilter.jsx +172 -12
- package/src/components/UniversalSearch.jsx +390 -0
- package/src/components/auth/Login.jsx +164 -8
- package/src/components/auth/Profile.jsx +209 -22
- package/src/components/auth/authEndpoints.js +4 -0
- package/src/components/auth/webauthn.js +194 -0
- package/src/components/columns/ColumnRenderers.jsx +6 -1
- package/src/components/controls/DataGridSearch.jsx +11 -5
- package/src/components/generic/GenericAuth.jsx +6 -0
- package/src/components/generic/GenericDashboard.jsx +93 -36
- package/src/components/generic/GenericDetail.jsx +146 -61
- package/src/components/generic/GenericIndex.jsx +134 -38
- package/src/components/generic/GenericSettings.jsx +220 -0
- package/src/components/generic/StandardModal.jsx +165 -8
- package/src/components/generic/dashboardChartDefaults.js +230 -0
- package/src/components/generic/shared/indexLayout.js +38 -0
- package/src/components/settings/IntegrationsManager.jsx +474 -0
- package/src/components/sms/SmsLineSettings.jsx +16 -12
- package/src/components/styles/AssociationManager.module.scss +4 -363
- package/src/components/styles/AuditLog.module.scss +6 -6
- package/src/components/styles/AuditLogs.module.scss +3 -3
- package/src/components/styles/Autocomplete.module.scss +7 -7
- package/src/components/styles/BusinessCardOcr.module.scss +6 -1
- package/src/components/styles/CallQueueSettings.module.scss +4 -1
- package/src/components/styles/CameraPlacement.module.scss +19 -19
- package/src/components/styles/CategorizedDropZone.module.scss +6 -1
- package/src/components/styles/ClientAssociationManager.module.scss +5 -289
- package/src/components/styles/ClientAuth.module.scss +1 -1
- package/src/components/styles/DataGrid.module.scss +455 -8
- package/src/components/styles/Field.module.scss +32 -24
- package/src/components/styles/Form.module.scss +123 -3
- package/src/components/styles/GenericDashboard.module.scss +612 -825
- package/src/components/styles/GenericDetail.module.scss +406 -61
- package/src/components/styles/GenericDynamic.module.scss +25 -25
- package/src/components/styles/GenericEditableTable.module.scss +33 -33
- package/src/components/styles/GenericFormBuilder.module.scss +119 -119
- package/src/components/styles/GenericIndex.module.scss +483 -38
- package/src/components/styles/GenericMain.module.scss +6 -3
- package/src/components/styles/GenericQuote.module.scss +399 -81
- package/src/components/styles/GenericReport.module.scss +8 -8
- package/src/components/styles/GenericSettings.module.scss +209 -0
- package/src/components/styles/GenericSort.module.scss +9 -9
- package/src/components/styles/Integrations.module.scss +321 -0
- package/src/components/styles/List.module.scss +4 -4
- package/src/components/styles/Login.module.scss +57 -0
- package/src/components/styles/MultiSelect.module.scss +4 -4
- package/src/components/styles/Navigation.module.scss +12 -12
- package/src/components/styles/Notification.module.scss +12 -8
- package/src/components/styles/NotificationList.module.scss +5 -5
- package/src/components/styles/Profile.module.scss +5 -5
- package/src/components/styles/QrCode.module.scss +4 -4
- package/src/components/styles/QuickAction.module.scss +20 -20
- package/src/components/styles/SortableQuoteItems.module.scss +4 -4
- package/src/components/styles/TableFilter.module.scss +128 -17
- package/src/components/styles/TicketConversation.module.scss +497 -0
- package/src/components/styles/UniversalSearch.module.scss +229 -0
- package/src/components/styles/Vault.module.scss +413 -0
- package/src/components/styles/_associationManager.scss +467 -0
- package/src/components/styles/_authBrandPanel.scss +15 -9
- package/src/components/styles/_controls.scss +43 -39
- package/src/components/styles/global-datagrid.css +196 -0
- package/src/components/styles/global.css +168 -17
- package/src/components/tickets/TicketConversation.jsx +455 -0
- package/src/components/utils/rowActionSettings.js +117 -0
- package/src/components/vault/VaultClientPicker.jsx +183 -0
- package/src/components/vault/VaultEntryForm.jsx +23 -0
- package/src/components/vault/VaultManager.jsx +382 -34
- package/src/components/vault/VaultShareModal.jsx +454 -0
- package/src/components/vault/vaultEndpoints.js +16 -2
- package/src/components/vault/vaultShares.js +247 -0
- package/src/index.js +35 -0
- package/src/utils/fetchUtil.js +38 -14
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// Universal search — the ⌘K palette
|
|
3
|
+
// ----------------------------------------------------------------------------
|
|
4
|
+
// Mounts inside Navigation's `.hactions > ul`, whose chip rules reach every
|
|
5
|
+
// descendant `a` and `button` and hand them white text on a fixed 36px box.
|
|
6
|
+
// On a white panel that renders as blank boxes, so — exactly as Vault and Sms
|
|
7
|
+
// do — nothing here inherits anything it actually needs. Every token carries a
|
|
8
|
+
// fallback, because a var() on an undefined property with no fallback is
|
|
9
|
+
// invalid at computed-value time and the whole declaration is dropped.
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
.wrap {
|
|
13
|
+
--us-primary: var(--primary-color, #1b3933);
|
|
14
|
+
--us-ink: var(--paragraph-color, #2b2b2b);
|
|
15
|
+
--us-surface: var(--background-color, #fff);
|
|
16
|
+
--us-line: color-mix(in srgb, var(--us-ink) 14%, transparent);
|
|
17
|
+
--us-muted: color-mix(in srgb, var(--us-ink) 66%, transparent);
|
|
18
|
+
--us-quiet: color-mix(in srgb, var(--us-ink) 4%, var(--us-surface));
|
|
19
|
+
--us-hover: color-mix(in srgb, var(--us-primary) 8%, var(--us-surface));
|
|
20
|
+
--us-motion: var(--speed, 160ms) var(--ease, cubic-bezier(0.4, 0, 0.2, 1));
|
|
21
|
+
|
|
22
|
+
position: relative;
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
// The same 40px chip as Notification and VaultQuickSearch, so the counts and
|
|
28
|
+
// controls in the header read as one row rather than three treatments.
|
|
29
|
+
.trigger {
|
|
30
|
+
display: inline-flex;
|
|
31
|
+
align-items: center;
|
|
32
|
+
justify-content: center;
|
|
33
|
+
width: var(--nav-action-size, 34px);
|
|
34
|
+
height: var(--nav-action-size, 34px);
|
|
35
|
+
padding: 0;
|
|
36
|
+
border: 0;
|
|
37
|
+
border-radius: var(--nav-chip-radius, var(--radius-pill, 999px));
|
|
38
|
+
background: transparent;
|
|
39
|
+
color: inherit;
|
|
40
|
+
cursor: pointer;
|
|
41
|
+
transition: background var(--us-motion);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.trigger:hover { background: rgba(255, 255, 255, 0.14); }
|
|
45
|
+
|
|
46
|
+
.trigger:focus-visible {
|
|
47
|
+
outline: 2px solid var(--highlight-color, #3cbf7d);
|
|
48
|
+
outline-offset: 2px;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
.overlay {
|
|
52
|
+
position: absolute;
|
|
53
|
+
top: calc(100% + 0.5rem);
|
|
54
|
+
right: 0;
|
|
55
|
+
z-index: 1200;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.panel {
|
|
59
|
+
width: min(620px, calc(100vw - 2rem));
|
|
60
|
+
display: flex;
|
|
61
|
+
flex-direction: column;
|
|
62
|
+
border: 1px solid var(--us-line);
|
|
63
|
+
border-radius: 14px;
|
|
64
|
+
background: var(--us-surface);
|
|
65
|
+
color: var(--us-ink);
|
|
66
|
+
// Two stops: a tight contact shadow plus a wide ambient one. One large
|
|
67
|
+
// blur reads as a smudge rather than a raised surface.
|
|
68
|
+
box-shadow:
|
|
69
|
+
0 2px 4px color-mix(in srgb, var(--us-primary) 10%, transparent),
|
|
70
|
+
0 24px 48px -20px color-mix(in srgb, var(--us-primary) 40%, transparent);
|
|
71
|
+
overflow: hidden;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// -- the field ---------------------------------------------------------------
|
|
75
|
+
|
|
76
|
+
.field {
|
|
77
|
+
display: flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
gap: 0.55rem;
|
|
80
|
+
padding: 0.7rem 0.85rem;
|
|
81
|
+
border-bottom: 1px solid var(--us-line);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.fieldIcon { flex: 0 0 auto; color: var(--us-muted); }
|
|
85
|
+
|
|
86
|
+
.input {
|
|
87
|
+
flex: 1 1 auto;
|
|
88
|
+
min-width: 0;
|
|
89
|
+
height: auto;
|
|
90
|
+
padding: 0;
|
|
91
|
+
border: 0;
|
|
92
|
+
border-radius: 0;
|
|
93
|
+
background: none;
|
|
94
|
+
color: var(--us-ink);
|
|
95
|
+
font: inherit;
|
|
96
|
+
font-size: 0.9375rem;
|
|
97
|
+
line-height: 1.4;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.input:focus { outline: none; } // the panel itself is the focus surface
|
|
101
|
+
.input::placeholder { color: var(--us-muted); }
|
|
102
|
+
|
|
103
|
+
// -- results -----------------------------------------------------------------
|
|
104
|
+
|
|
105
|
+
.results {
|
|
106
|
+
// Scrolls inside the panel; a long result set must never make the page
|
|
107
|
+
// scroll behind the overlay.
|
|
108
|
+
max-height: min(52vh, 26rem);
|
|
109
|
+
overflow-y: auto;
|
|
110
|
+
padding: 0.35rem 0;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
.state {
|
|
114
|
+
margin: 0;
|
|
115
|
+
padding: 1.1rem 0.9rem;
|
|
116
|
+
color: var(--us-muted);
|
|
117
|
+
font-size: 0.8125rem;
|
|
118
|
+
text-align: center;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.group { padding: 0.25rem 0; }
|
|
122
|
+
|
|
123
|
+
.groupLabel {
|
|
124
|
+
margin: 0;
|
|
125
|
+
padding: 0.4rem 0.9rem 0.25rem;
|
|
126
|
+
color: var(--us-muted);
|
|
127
|
+
font-size: 0.6875rem;
|
|
128
|
+
font-weight: 600;
|
|
129
|
+
letter-spacing: 0.05em;
|
|
130
|
+
text-transform: uppercase;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.rows {
|
|
134
|
+
margin: 0;
|
|
135
|
+
padding: 0;
|
|
136
|
+
list-style: none;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// `> li` reset restated explicitly: the host's own `li` rules are 0,1,2 and no
|
|
140
|
+
// single module class can outrank them. Same note as the Sms and Vault lists.
|
|
141
|
+
.rows > li {
|
|
142
|
+
margin: 0;
|
|
143
|
+
padding: 0;
|
|
144
|
+
border: 0;
|
|
145
|
+
background: none;
|
|
146
|
+
list-style: none;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
.row {
|
|
150
|
+
display: grid;
|
|
151
|
+
// A fixed final track for the ↵ hint, so a row does not reflow when it
|
|
152
|
+
// becomes the active one.
|
|
153
|
+
grid-template-columns: minmax(0, 1fr) auto;
|
|
154
|
+
align-items: baseline;
|
|
155
|
+
gap: 0.15rem 0.6rem;
|
|
156
|
+
width: 100%;
|
|
157
|
+
height: auto;
|
|
158
|
+
min-height: 0;
|
|
159
|
+
padding: 0.5rem 0.9rem;
|
|
160
|
+
border: 0;
|
|
161
|
+
border-radius: 0;
|
|
162
|
+
background: none;
|
|
163
|
+
color: var(--us-ink);
|
|
164
|
+
font: inherit;
|
|
165
|
+
text-align: left;
|
|
166
|
+
cursor: pointer;
|
|
167
|
+
transition: background var(--us-motion);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.rowActive { background: var(--us-hover); }
|
|
171
|
+
|
|
172
|
+
.rowTitle {
|
|
173
|
+
grid-column: 1;
|
|
174
|
+
min-width: 0;
|
|
175
|
+
overflow: hidden;
|
|
176
|
+
text-overflow: ellipsis;
|
|
177
|
+
white-space: nowrap;
|
|
178
|
+
font-size: 0.875rem;
|
|
179
|
+
font-weight: 500;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.rowSub {
|
|
183
|
+
grid-column: 1;
|
|
184
|
+
min-width: 0;
|
|
185
|
+
overflow: hidden;
|
|
186
|
+
text-overflow: ellipsis;
|
|
187
|
+
white-space: nowrap;
|
|
188
|
+
color: var(--us-muted);
|
|
189
|
+
font-size: 0.75rem;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
.rowEnter {
|
|
193
|
+
grid-column: 2;
|
|
194
|
+
grid-row: 1 / span 2;
|
|
195
|
+
align-self: center;
|
|
196
|
+
color: var(--us-muted);
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// -- footer ------------------------------------------------------------------
|
|
200
|
+
|
|
201
|
+
.foot {
|
|
202
|
+
display: flex;
|
|
203
|
+
gap: 1rem;
|
|
204
|
+
padding: 0.5rem 0.9rem;
|
|
205
|
+
border-top: 1px solid var(--us-line);
|
|
206
|
+
background: var(--us-quiet);
|
|
207
|
+
color: var(--us-muted);
|
|
208
|
+
font-size: 0.6875rem;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.kbd {
|
|
212
|
+
display: inline-flex;
|
|
213
|
+
align-items: center;
|
|
214
|
+
padding: 0 0.3rem;
|
|
215
|
+
min-width: 1.1rem;
|
|
216
|
+
height: 1.1rem;
|
|
217
|
+
border: 1px solid var(--us-line);
|
|
218
|
+
border-radius: 4px;
|
|
219
|
+
background: var(--us-surface);
|
|
220
|
+
color: var(--us-muted);
|
|
221
|
+
font-family: inherit;
|
|
222
|
+
font-size: 0.6875rem;
|
|
223
|
+
line-height: 1;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@media (prefers-reduced-motion: reduce) {
|
|
227
|
+
.trigger,
|
|
228
|
+
.row { transition: none; }
|
|
229
|
+
}
|
|
@@ -482,6 +482,16 @@ $vault-tick: "data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewB
|
|
|
482
482
|
cursor: pointer;
|
|
483
483
|
}
|
|
484
484
|
|
|
485
|
+
// A select that is currently narrowing the list. Without it a filter picked
|
|
486
|
+
// from a row's chip is a change the user did not make in the toolbar and can
|
|
487
|
+
// easily fail to notice — and then the vault looks half empty.
|
|
488
|
+
.selectActive {
|
|
489
|
+
border-color: color-mix(in srgb, var(--v-primary) 45%, transparent);
|
|
490
|
+
background: var(--v-tint);
|
|
491
|
+
color: var(--v-primary);
|
|
492
|
+
font-weight: 600;
|
|
493
|
+
}
|
|
494
|
+
|
|
485
495
|
// Every checkbox and radio in the vault carries this, so the box survives
|
|
486
496
|
// being mounted anywhere — see `vault-check`. The descendant selectors below
|
|
487
497
|
// repeat it only as a safety net for markup that forgets the class.
|
|
@@ -1981,3 +1991,406 @@ input.checkControl {
|
|
|
1981
1991
|
font-size: 0.75rem;
|
|
1982
1992
|
white-space: nowrap;
|
|
1983
1993
|
}
|
|
1994
|
+
|
|
1995
|
+
// ---------------------------------------------------------------------------
|
|
1996
|
+
// Client attachment
|
|
1997
|
+
//
|
|
1998
|
+
// A vault entry can belong to a client. On the form that is a typeahead; on
|
|
1999
|
+
// the list it is one line under the title, so the association is visible
|
|
2000
|
+
// without opening the entry.
|
|
2001
|
+
// ---------------------------------------------------------------------------
|
|
2002
|
+
|
|
2003
|
+
.clientPicker {
|
|
2004
|
+
position: relative;
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
.clientSpinner {
|
|
2008
|
+
position: absolute;
|
|
2009
|
+
top: 50%;
|
|
2010
|
+
right: 0.55rem;
|
|
2011
|
+
color: var(--v-muted);
|
|
2012
|
+
transform: translateY(-50%);
|
|
2013
|
+
animation: vault-client-spin 0.9s linear infinite;
|
|
2014
|
+
pointer-events: none;
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
@keyframes vault-client-spin {
|
|
2018
|
+
to {
|
|
2019
|
+
transform: translateY(-50%) rotate(360deg);
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
|
|
2023
|
+
.clientResults {
|
|
2024
|
+
position: absolute;
|
|
2025
|
+
z-index: 30;
|
|
2026
|
+
top: calc(100% + 4px);
|
|
2027
|
+
right: 0;
|
|
2028
|
+
left: 0;
|
|
2029
|
+
// Roughly seven rows. Enough to scan, short enough that the field below
|
|
2030
|
+
// it is still reachable without scrolling the modal.
|
|
2031
|
+
max-height: 15rem;
|
|
2032
|
+
margin: 0;
|
|
2033
|
+
padding: 0.25rem;
|
|
2034
|
+
overflow-y: auto;
|
|
2035
|
+
border: 1px solid var(--v-line);
|
|
2036
|
+
border-radius: var(--v-btn-br);
|
|
2037
|
+
background: var(--v-background);
|
|
2038
|
+
box-shadow: 0 12px 28px -12px rgb(0 0 0 / 35%);
|
|
2039
|
+
list-style: none;
|
|
2040
|
+
}
|
|
2041
|
+
|
|
2042
|
+
.clientResult,
|
|
2043
|
+
.clientResultActive {
|
|
2044
|
+
@include vault-reset;
|
|
2045
|
+
@include vault-focus;
|
|
2046
|
+
|
|
2047
|
+
display: flex;
|
|
2048
|
+
gap: 0.45rem;
|
|
2049
|
+
align-items: center;
|
|
2050
|
+
width: 100%;
|
|
2051
|
+
padding: 0.4rem 0.5rem;
|
|
2052
|
+
border-radius: var(--v-btn-br);
|
|
2053
|
+
color: var(--v-paragraph);
|
|
2054
|
+
font-size: 0.85rem;
|
|
2055
|
+
text-align: left;
|
|
2056
|
+
cursor: pointer;
|
|
2057
|
+
|
|
2058
|
+
svg {
|
|
2059
|
+
flex-shrink: 0;
|
|
2060
|
+
color: var(--v-muted);
|
|
2061
|
+
}
|
|
2062
|
+
}
|
|
2063
|
+
|
|
2064
|
+
.clientResultActive {
|
|
2065
|
+
background: var(--v-tint);
|
|
2066
|
+
color: var(--v-primary);
|
|
2067
|
+
|
|
2068
|
+
svg {
|
|
2069
|
+
color: currentcolor;
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
.clientEmpty {
|
|
2074
|
+
padding: 0.5rem;
|
|
2075
|
+
color: var(--v-muted);
|
|
2076
|
+
font-size: 0.82rem;
|
|
2077
|
+
}
|
|
2078
|
+
|
|
2079
|
+
.clientChosen {
|
|
2080
|
+
display: inline-flex;
|
|
2081
|
+
gap: 0.4rem;
|
|
2082
|
+
align-items: center;
|
|
2083
|
+
max-width: 100%;
|
|
2084
|
+
padding: 0.35rem 0.4rem 0.35rem 0.55rem;
|
|
2085
|
+
border: 1px solid var(--v-line);
|
|
2086
|
+
border-radius: 999px;
|
|
2087
|
+
background: var(--v-tint);
|
|
2088
|
+
color: var(--v-primary);
|
|
2089
|
+
font-size: 0.83rem;
|
|
2090
|
+
font-weight: 600;
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
.clientChosenLabel {
|
|
2094
|
+
overflow: hidden;
|
|
2095
|
+
text-overflow: ellipsis;
|
|
2096
|
+
white-space: nowrap;
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
.clientClear {
|
|
2100
|
+
@include vault-reset;
|
|
2101
|
+
@include vault-focus;
|
|
2102
|
+
|
|
2103
|
+
display: inline-flex;
|
|
2104
|
+
flex-shrink: 0;
|
|
2105
|
+
align-items: center;
|
|
2106
|
+
justify-content: center;
|
|
2107
|
+
width: 1.1rem;
|
|
2108
|
+
height: 1.1rem;
|
|
2109
|
+
border-radius: 999px;
|
|
2110
|
+
color: currentcolor;
|
|
2111
|
+
cursor: pointer;
|
|
2112
|
+
opacity: 0.7;
|
|
2113
|
+
|
|
2114
|
+
&:hover {
|
|
2115
|
+
background: color-mix(in srgb, currentcolor 18%, transparent);
|
|
2116
|
+
opacity: 1;
|
|
2117
|
+
}
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
// The client a credential belongs to, beside the title.
|
|
2121
|
+
//
|
|
2122
|
+
// A chip rather than loose grey text. Once the importer's duplicated
|
|
2123
|
+
// "Client — Title" prefix is stripped (vault:strip-client-titles) this is the
|
|
2124
|
+
// ONLY place the client is named on the row, so it has to be legible on its
|
|
2125
|
+
// own — but it must still read as secondary to the title, which is why it
|
|
2126
|
+
// takes the flattest surface in the palette (`--v-surface` is 4% of the body
|
|
2127
|
+
// colour) and the muted text colour rather than a tint of the brand.
|
|
2128
|
+
//
|
|
2129
|
+
// The icon stays: it is what separates this chip at a glance from the tag
|
|
2130
|
+
// pills sitting on the line below, which are the same size and shape.
|
|
2131
|
+
//
|
|
2132
|
+
// Inline, not block: the title cell is `white-space: nowrap` in fitted mode
|
|
2133
|
+
// and the chip is meant to sit on the title's line, with the tags taking the
|
|
2134
|
+
// second. `margin-left` is the whole fix for the run-on look.
|
|
2135
|
+
.clientUnderTitle {
|
|
2136
|
+
display: inline-flex;
|
|
2137
|
+
gap: 0.3rem;
|
|
2138
|
+
align-items: center;
|
|
2139
|
+
max-width: 100%;
|
|
2140
|
+
margin-left: 0.45rem;
|
|
2141
|
+
padding: 0.08rem 0.45rem;
|
|
2142
|
+
border: 1px solid var(--v-line);
|
|
2143
|
+
border-radius: 999px;
|
|
2144
|
+
background: var(--v-surface);
|
|
2145
|
+
color: var(--v-muted);
|
|
2146
|
+
font-size: 0.72rem;
|
|
2147
|
+
font-weight: 600;
|
|
2148
|
+
line-height: 1.5;
|
|
2149
|
+
white-space: nowrap;
|
|
2150
|
+
vertical-align: middle;
|
|
2151
|
+
|
|
2152
|
+
svg {
|
|
2153
|
+
flex-shrink: 0;
|
|
2154
|
+
// The glyph is decoration next to a name that is already the label;
|
|
2155
|
+
// at full strength it competes with the text it introduces.
|
|
2156
|
+
opacity: 0.75;
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
// The name itself. Own ellipsis rather than the cell's: the cell clips
|
|
2160
|
+
// everything after the overflow point, which on a long client name would
|
|
2161
|
+
// take the chip's right-hand border with it and leave a shape that reads
|
|
2162
|
+
// as a rendering fault.
|
|
2163
|
+
.clientChipLabel {
|
|
2164
|
+
display: block;
|
|
2165
|
+
overflow: hidden;
|
|
2166
|
+
text-overflow: ellipsis;
|
|
2167
|
+
white-space: nowrap;
|
|
2168
|
+
// Roughly 22 characters. Past that the client is identified well
|
|
2169
|
+
// enough and the title has the better claim on the row.
|
|
2170
|
+
max-width: 11rem;
|
|
2171
|
+
}
|
|
2172
|
+
|
|
2173
|
+
a {
|
|
2174
|
+
color: inherit;
|
|
2175
|
+
text-decoration: none;
|
|
2176
|
+
|
|
2177
|
+
&:hover,
|
|
2178
|
+
&:focus-visible {
|
|
2179
|
+
text-decoration: underline;
|
|
2180
|
+
}
|
|
2181
|
+
}
|
|
2182
|
+
|
|
2183
|
+
// The name, as the control that filters the list to this client. Reset to
|
|
2184
|
+
// nothing and told to inherit: it has to be indistinguishable from the
|
|
2185
|
+
// plain-text version of the same chip on a page that cannot filter, or the
|
|
2186
|
+
// row grows a button-shaped thing in the middle of a title cell.
|
|
2187
|
+
.clientChipButton {
|
|
2188
|
+
@include vault-reset;
|
|
2189
|
+
@include vault-focus;
|
|
2190
|
+
|
|
2191
|
+
display: block;
|
|
2192
|
+
max-width: 11rem;
|
|
2193
|
+
padding: 0;
|
|
2194
|
+
border: 0;
|
|
2195
|
+
background: none;
|
|
2196
|
+
color: inherit;
|
|
2197
|
+
font: inherit;
|
|
2198
|
+
cursor: pointer;
|
|
2199
|
+
|
|
2200
|
+
&:hover .clientChipLabel,
|
|
2201
|
+
&:focus-visible .clientChipLabel {
|
|
2202
|
+
text-decoration: underline;
|
|
2203
|
+
}
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
// The link to the client's own record, kept alongside the filter button.
|
|
2207
|
+
// Icon-only and quiet: filtering is the common intent from a row, opening
|
|
2208
|
+
// the client is the occasional one.
|
|
2209
|
+
.clientChipLink {
|
|
2210
|
+
display: inline-flex;
|
|
2211
|
+
flex-shrink: 0;
|
|
2212
|
+
align-items: center;
|
|
2213
|
+
opacity: 0.6;
|
|
2214
|
+
|
|
2215
|
+
&:hover,
|
|
2216
|
+
&:focus-visible {
|
|
2217
|
+
opacity: 1;
|
|
2218
|
+
}
|
|
2219
|
+
|
|
2220
|
+
svg {
|
|
2221
|
+
opacity: 1;
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
// The whole chip lifts on hover, so the target reads as the chip rather
|
|
2226
|
+
// than as the few pixels of text inside it.
|
|
2227
|
+
&:has(a:hover),
|
|
2228
|
+
&:has(a:focus-visible),
|
|
2229
|
+
&:has(button:hover),
|
|
2230
|
+
&:has(button:focus-visible) {
|
|
2231
|
+
border-color: color-mix(in srgb, var(--v-primary) 35%, transparent);
|
|
2232
|
+
background: var(--v-tint);
|
|
2233
|
+
color: var(--v-primary);
|
|
2234
|
+
}
|
|
2235
|
+
}
|
|
2236
|
+
|
|
2237
|
+
// The client this list is currently filtered to. Every visible row carries the
|
|
2238
|
+
// same chip once the filter is on, so this is not a highlight so much as a
|
|
2239
|
+
// statement of why these rows are the ones on screen.
|
|
2240
|
+
.clientUnderTitleActive {
|
|
2241
|
+
border-color: color-mix(in srgb, var(--v-primary) 45%, transparent);
|
|
2242
|
+
background: var(--v-tint);
|
|
2243
|
+
color: var(--v-primary);
|
|
2244
|
+
}
|
|
2245
|
+
|
|
2246
|
+
// ---------------------------------------------------------------------------
|
|
2247
|
+
// Share links
|
|
2248
|
+
//
|
|
2249
|
+
// The dialog behind the Share action: choose what to send, get a URL once, and
|
|
2250
|
+
// see what has already gone out. Everything here lives inside `.form`, which
|
|
2251
|
+
// already carries the token block, so these rules only add what the form's own
|
|
2252
|
+
// controls do not.
|
|
2253
|
+
// ---------------------------------------------------------------------------
|
|
2254
|
+
|
|
2255
|
+
.shareFields {
|
|
2256
|
+
display: flex;
|
|
2257
|
+
flex-direction: column;
|
|
2258
|
+
gap: 0.35rem;
|
|
2259
|
+
|
|
2260
|
+
// The hint under a field name — "the current code, not the secret", or the
|
|
2261
|
+
// reason a box is greyed out. Own line, so a long one does not push the
|
|
2262
|
+
// checkbox off centre.
|
|
2263
|
+
.shareHint {
|
|
2264
|
+
display: block;
|
|
2265
|
+
color: var(--v-muted);
|
|
2266
|
+
font-size: 0.72rem;
|
|
2267
|
+
font-style: normal;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
|
|
2271
|
+
// The one-time URL, and the sentence that makes it clear it IS one time.
|
|
2272
|
+
.shareResult {
|
|
2273
|
+
display: flex;
|
|
2274
|
+
flex-direction: column;
|
|
2275
|
+
gap: 0.7rem;
|
|
2276
|
+
padding: 0.85rem;
|
|
2277
|
+
border: 1px solid color-mix(in srgb, var(--v-primary) 35%, transparent);
|
|
2278
|
+
border-radius: var(--v-br);
|
|
2279
|
+
background: var(--v-tint);
|
|
2280
|
+
}
|
|
2281
|
+
|
|
2282
|
+
.shareResultHead {
|
|
2283
|
+
display: flex;
|
|
2284
|
+
gap: 0.35rem;
|
|
2285
|
+
align-items: center;
|
|
2286
|
+
margin: 0;
|
|
2287
|
+
color: var(--v-primary);
|
|
2288
|
+
font-size: 0.82rem;
|
|
2289
|
+
font-weight: 700;
|
|
2290
|
+
}
|
|
2291
|
+
|
|
2292
|
+
// Deliberately loud. The link is the credential, and the two things a person
|
|
2293
|
+
// has to take from this dialog — it will not be shown again, and anyone with
|
|
2294
|
+
// it can read the password — are both easy to skim past in body text.
|
|
2295
|
+
.shareWarning {
|
|
2296
|
+
display: flex;
|
|
2297
|
+
gap: 0.45rem;
|
|
2298
|
+
align-items: flex-start;
|
|
2299
|
+
margin: 0;
|
|
2300
|
+
color: var(--v-paragraph);
|
|
2301
|
+
font-size: 0.78rem;
|
|
2302
|
+
line-height: 1.45;
|
|
2303
|
+
|
|
2304
|
+
svg {
|
|
2305
|
+
flex-shrink: 0;
|
|
2306
|
+
margin-top: 0.15rem;
|
|
2307
|
+
color: var(--v-bad);
|
|
2308
|
+
}
|
|
2309
|
+
|
|
2310
|
+
strong {
|
|
2311
|
+
font-weight: 700;
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
.shareList {
|
|
2316
|
+
display: flex;
|
|
2317
|
+
flex-direction: column;
|
|
2318
|
+
gap: 0.4rem;
|
|
2319
|
+
padding-top: 0.7rem;
|
|
2320
|
+
border-top: 1px solid var(--v-line);
|
|
2321
|
+
|
|
2322
|
+
> p:first-child {
|
|
2323
|
+
display: flex;
|
|
2324
|
+
gap: 0.35rem;
|
|
2325
|
+
align-items: center;
|
|
2326
|
+
margin: 0 0 0.2rem;
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
|
|
2330
|
+
.shareRow {
|
|
2331
|
+
display: flex;
|
|
2332
|
+
flex-wrap: wrap;
|
|
2333
|
+
gap: 0.4rem 0.6rem;
|
|
2334
|
+
align-items: center;
|
|
2335
|
+
padding: 0.5rem 0.6rem;
|
|
2336
|
+
border: 1px solid var(--v-line);
|
|
2337
|
+
border-radius: var(--v-br);
|
|
2338
|
+
background: var(--v-surface);
|
|
2339
|
+
font-size: 0.79rem;
|
|
2340
|
+
|
|
2341
|
+
// The revoke button is pushed to the far end rather than floated, so a row
|
|
2342
|
+
// without one simply has nothing there instead of a gap in the middle.
|
|
2343
|
+
> button:last-child {
|
|
2344
|
+
margin-left: auto;
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
|
|
2348
|
+
.shareRowMain {
|
|
2349
|
+
display: flex;
|
|
2350
|
+
flex-wrap: wrap;
|
|
2351
|
+
gap: 0.4rem;
|
|
2352
|
+
align-items: center;
|
|
2353
|
+
min-width: 0;
|
|
2354
|
+
}
|
|
2355
|
+
|
|
2356
|
+
.shareRowFields {
|
|
2357
|
+
overflow: hidden;
|
|
2358
|
+
color: var(--v-paragraph);
|
|
2359
|
+
font-weight: 600;
|
|
2360
|
+
text-overflow: ellipsis;
|
|
2361
|
+
white-space: nowrap;
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2364
|
+
.shareRowMeta {
|
|
2365
|
+
display: flex;
|
|
2366
|
+
flex-wrap: wrap;
|
|
2367
|
+
gap: 0.15rem 0.5rem;
|
|
2368
|
+
align-items: center;
|
|
2369
|
+
color: var(--v-muted);
|
|
2370
|
+
font-size: 0.74rem;
|
|
2371
|
+
|
|
2372
|
+
// Interpuncts between the facts rather than commas: they are three
|
|
2373
|
+
// independent readings, not a list.
|
|
2374
|
+
> span + span::before {
|
|
2375
|
+
content: '·';
|
|
2376
|
+
margin-right: 0.5rem;
|
|
2377
|
+
}
|
|
2378
|
+
}
|
|
2379
|
+
|
|
2380
|
+
// Green for a link that still opens, red for one somebody deliberately closed,
|
|
2381
|
+
// neutral grey for one that simply ran out — an expired link is not an
|
|
2382
|
+
// incident, and colouring it as one trains people to ignore the colour.
|
|
2383
|
+
.shareStatusActive {
|
|
2384
|
+
background: color-mix(in srgb, var(--v-ok) 15%, var(--v-background));
|
|
2385
|
+
color: var(--v-ok);
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2388
|
+
.shareStatusRevoked {
|
|
2389
|
+
background: color-mix(in srgb, var(--v-bad) 15%, var(--v-background));
|
|
2390
|
+
color: var(--v-bad);
|
|
2391
|
+
}
|
|
2392
|
+
|
|
2393
|
+
.shareStatusClosed {
|
|
2394
|
+
background: color-mix(in srgb, var(--v-paragraph) 12%, var(--v-background));
|
|
2395
|
+
color: var(--v-muted);
|
|
2396
|
+
}
|