@visns-studio/visns-components 6.6.3 → 6.15.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/README.md +1658 -18
- package/package.json +10 -4
- package/src/components/DataGrid.jsx +619 -158
- package/src/components/Fetch.jsx +80 -3
- package/src/components/Form.jsx +9 -0
- package/src/components/Navigation.jsx +109 -50
- package/src/components/Notification.jsx +279 -9
- package/src/components/TableFilter.jsx +14 -1
- package/src/components/auth/AuthBrandPanel.jsx +43 -0
- package/src/components/auth/AuthLoading.jsx +78 -0
- package/src/components/auth/AuthShell.jsx +59 -0
- package/src/components/auth/ClientAuth.jsx +161 -0
- package/src/components/auth/ClientAuthFrame.jsx +59 -0
- package/src/components/auth/ClientLogin.jsx +266 -55
- package/src/components/auth/ClientOTPVerify.jsx +587 -115
- package/src/components/auth/ImpersonateGate.jsx +254 -0
- package/src/components/auth/Login.jsx +134 -41
- package/src/components/auth/LogoutScreen.jsx +112 -0
- package/src/components/auth/Reset.jsx +134 -77
- package/src/components/auth/TwoFactorAuth.jsx +475 -297
- package/src/components/auth/Verify.jsx +237 -126
- package/src/components/auth/authEndpoints.js +105 -0
- package/src/components/auth/authFont.js +23 -0
- package/src/components/auth/authHelpers.js +465 -0
- package/src/components/auth/clientAuthProtocols.js +240 -0
- package/src/components/auth/useOptionalRouter.js +49 -0
- package/src/components/callQueue/CallQueuePop.jsx +1502 -0
- package/src/components/callQueue/CallQueueSettings.jsx +508 -0
- package/src/components/callQueue/callQueueHelpers.js +280 -0
- package/src/components/callQueue/callQueueSettingsHelpers.js +75 -0
- package/src/components/columns/AutoGrowCell.jsx +141 -0
- package/src/components/columns/ColumnRenderers.jsx +53 -7
- package/src/components/generic/GenericAuth.jsx +163 -96
- package/src/components/generic/GenericDetail.jsx +215 -90
- package/src/components/generic/GenericIndex.jsx +20 -47
- package/src/components/generic/GenericMain.jsx +5 -0
- package/src/components/generic/GroupedReportRenderer.jsx +1 -5
- package/src/components/generic/StandardModal.jsx +17 -5
- package/src/components/generic/reportSemanticSteps/SemanticEntityStep.jsx +1 -6
- package/src/components/generic/reportSemanticSteps/SemanticFieldsStep.jsx +4 -11
- package/src/components/generic/reportSemanticSteps/SemanticFiltersStep.jsx +9 -27
- package/src/components/generic/reportSemanticSteps/SemanticGroupingStep.jsx +5 -13
- package/src/components/generic/reportSemanticSteps/SemanticParameterPrompt.jsx +5 -13
- package/src/components/generic/reportSemanticSteps/SemanticPreviewStep.jsx +14 -31
- package/src/components/generic/reportSemanticSteps/SemanticRelationsStep.jsx +3 -9
- package/src/components/generic/reportSemanticSteps/SemanticValueInput.jsx +2 -15
- package/src/components/navActive.js +60 -0
- package/src/components/notify/desktopNotifications.js +256 -0
- package/src/components/sketch/SketchField.jsx +12 -2
- package/src/components/sms/SmsComposeModal.jsx +495 -0
- package/src/components/sms/SmsInbox.jsx +596 -0
- package/src/components/sms/SmsInboxBadge.jsx +468 -0
- package/src/components/sms/SmsLineSettings.jsx +854 -0
- package/src/components/sms/SmsThreadPanel.jsx +1184 -0
- package/src/components/sms/smsEndpoints.js +56 -0
- package/src/components/sms/smsHelpers.js +1075 -0
- package/src/components/sms/smsLiveState.js +132 -0
- package/src/components/sms/useSmsLive.js +307 -0
- package/src/components/styles/CallQueuePop.module.scss +646 -0
- package/src/components/styles/CallQueueSettings.module.scss +460 -0
- package/src/components/styles/ClientAuth.module.scss +229 -0
- package/src/components/styles/DataGrid.module.scss +10 -0
- package/src/components/styles/GenericDetail.module.scss +153 -26
- package/src/components/styles/GenericIndex.module.scss +13 -0
- package/src/components/styles/GenericMain.module.scss +19 -2
- package/src/components/styles/ImpersonateGate.module.scss +85 -0
- package/src/components/styles/Login.module.scss +13 -122
- package/src/components/styles/LogoutScreen.module.scss +89 -0
- package/src/components/styles/Navigation.module.scss +509 -223
- package/src/components/styles/Notification.module.scss +103 -0
- package/src/components/styles/Reset.module.scss +52 -186
- package/src/components/styles/Sms.module.scss +2382 -0
- package/src/components/styles/TableFilter.module.scss +118 -98
- package/src/components/styles/TwoFactorAuth.module.scss +115 -176
- package/src/components/styles/Vault.module.scss +1983 -0
- package/src/components/styles/Verify.module.scss +57 -180
- package/src/components/styles/_authBrandPanel.scss +163 -0
- package/src/components/styles/_authShell.scss +369 -0
- package/src/components/styles/global-datagrid.css +29 -0
- package/src/components/utils/buildEnv.js +67 -0
- package/src/components/utils/displayValue.js +94 -0
- package/src/components/utils/useDensity.js +345 -9
- package/src/components/vault/OtpChip.jsx +208 -0
- package/src/components/vault/PasswordGenerator.jsx +145 -0
- package/src/components/vault/QrScanner.jsx +326 -0
- package/src/components/vault/VaultAccessLog.jsx +225 -0
- package/src/components/vault/VaultConfirmPanel.jsx +113 -0
- package/src/components/vault/VaultEntryForm.jsx +740 -0
- package/src/components/vault/VaultManager.jsx +1000 -0
- package/src/components/vault/VaultQuickSearch.jsx +681 -0
- package/src/components/vault/qrDecode.js +257 -0
- package/src/components/vault/useDebouncedValue.js +22 -0
- package/src/components/vault/useVaultReveal.js +160 -0
- package/src/components/vault/vaultClipboard.js +33 -0
- package/src/components/vault/vaultEndpoints.js +40 -0
- package/src/components/vault/vaultFit.js +116 -0
- package/src/components/vault/vaultHelpers.js +547 -0
- package/src/components/vault/vaultNavigation.jsx +58 -0
- package/src/components/vault/vaultOtp.js +105 -0
- package/src/index.js +233 -1
|
@@ -0,0 +1,646 @@
|
|
|
1
|
+
// ---------------------------------------------------------------------------
|
|
2
|
+
// Call Queue Pop (.cqpop)
|
|
3
|
+
// ---------------------------------------------------------------------------
|
|
4
|
+
// Bottom-right stack of "a call is ringing on this queue" cards, rendered once
|
|
5
|
+
// at the authenticated root by components/callQueue/CallQueuePop.jsx. Every
|
|
6
|
+
// call queue in the Zoom account pops and they all share one card style — the
|
|
7
|
+
// badge carries the queue's own name, so no per-queue colour is needed.
|
|
8
|
+
//
|
|
9
|
+
// Visually this is a glassmorphism language (blur + a translucent primary
|
|
10
|
+
// wash). It lives in its own namespace on purpose: a consuming app's legacy
|
|
11
|
+
// call banner is typically a single full-width bottom-centre bar, this is a
|
|
12
|
+
// vertical stack of independent cards. Nothing here touches that.
|
|
13
|
+
//
|
|
14
|
+
// Ported from the CRM's resources/css/_call-queue.scss. The sass `config`
|
|
15
|
+
// variables it used do not exist in this library, so every brand value is a
|
|
16
|
+
// CSS custom property with a neutral fallback — a project that defines nothing
|
|
17
|
+
// gets a plain, working call pop rather than any one project's colours.
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
// Local aliases only. Declared via a mixin and applied to BOTH the stack and
|
|
21
|
+
// the card: CSS-module scoping means nothing can rely on a shared `:root`
|
|
22
|
+
// block, and a card rendered outside the stack must still resolve its colours.
|
|
23
|
+
@mixin cqpop-tokens {
|
|
24
|
+
--cq-primary: var(--primary-color, #00386c);
|
|
25
|
+
--cq-secondary: var(--secondary-color, #404040);
|
|
26
|
+
--cq-tertiary: var(--tertiary-color, #fff);
|
|
27
|
+
--cq-paragraph: var(--paragraph-color, #2b2b2b);
|
|
28
|
+
--cq-background: var(--background-color, #fff);
|
|
29
|
+
--cq-br: var(--br, 5px);
|
|
30
|
+
--cq-btn-br: var(--btn-br, 5px);
|
|
31
|
+
|
|
32
|
+
// Literals in the original, kept literal here: they match the legacy
|
|
33
|
+
// `.cpview` / `.cpdismiss` actions rather than any token.
|
|
34
|
+
--cq-answer: rgb(43, 145, 85);
|
|
35
|
+
--cq-dismiss: rgb(214, 100, 100);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.cqpopStack {
|
|
39
|
+
@include cqpop-tokens;
|
|
40
|
+
|
|
41
|
+
position: fixed;
|
|
42
|
+
right: 1.25rem;
|
|
43
|
+
bottom: 1.25rem;
|
|
44
|
+
z-index: 1000; // above the goalbox (999), below the modals (1051+)
|
|
45
|
+
display: flex;
|
|
46
|
+
flex-direction: column;
|
|
47
|
+
align-items: stretch;
|
|
48
|
+
gap: 0.75rem;
|
|
49
|
+
width: 340px;
|
|
50
|
+
max-width: calc(100vw - 2rem);
|
|
51
|
+
// The stack itself is only a positioning frame — let clicks through the
|
|
52
|
+
// gaps between cards.
|
|
53
|
+
pointer-events: none;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Trial-run banner above the stack: small, muted, unmistakably temporary.
|
|
57
|
+
.cqpopTrial {
|
|
58
|
+
pointer-events: none;
|
|
59
|
+
display: inline-flex;
|
|
60
|
+
gap: 0.3rem;
|
|
61
|
+
align-items: center;
|
|
62
|
+
align-self: flex-end;
|
|
63
|
+
padding: 0.2rem 0.55rem;
|
|
64
|
+
border: 1px solid color-mix(in srgb, var(--cq-primary) 20%, transparent);
|
|
65
|
+
border-radius: 999px;
|
|
66
|
+
background: color-mix(in srgb, var(--cq-primary) 8%, transparent);
|
|
67
|
+
backdrop-filter: blur(16px) saturate(180%);
|
|
68
|
+
-webkit-backdrop-filter: blur(16px) saturate(180%);
|
|
69
|
+
color: color-mix(in srgb, var(--cq-paragraph) 75%, transparent);
|
|
70
|
+
font-size: 0.68rem;
|
|
71
|
+
font-weight: 600;
|
|
72
|
+
letter-spacing: 0.2px;
|
|
73
|
+
|
|
74
|
+
svg {
|
|
75
|
+
flex-shrink: 0;
|
|
76
|
+
color: var(--cq-primary);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.cqpopCard {
|
|
81
|
+
@include cqpop-tokens;
|
|
82
|
+
|
|
83
|
+
pointer-events: auto;
|
|
84
|
+
padding: 0.75rem 0.9rem;
|
|
85
|
+
border: 1px solid color-mix(in srgb, var(--cq-primary) 25%, transparent);
|
|
86
|
+
border-radius: calc(var(--cq-br) * 2);
|
|
87
|
+
background-color: color-mix(in srgb, var(--cq-primary) 15%, transparent);
|
|
88
|
+
backdrop-filter: blur(16px) saturate(180%);
|
|
89
|
+
-webkit-backdrop-filter: blur(16px) saturate(180%);
|
|
90
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.18);
|
|
91
|
+
animation: cqpop-in 0.28s cubic-bezier(0.33, 1, 0.68, 1) both;
|
|
92
|
+
|
|
93
|
+
// One accent for every queue: the badge names the queue, so the spine is
|
|
94
|
+
// only there to mark the card as a call pop.
|
|
95
|
+
border-left: 4px solid var(--cq-primary);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
.cqpopCardLeaving {
|
|
99
|
+
animation: cqpop-out 0.22s cubic-bezier(0.33, 0, 0.68, 0) both;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.cqpopCardHead {
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
justify-content: space-between;
|
|
106
|
+
gap: 0.5rem;
|
|
107
|
+
margin-bottom: 0.55rem;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.cqpopCardBody {
|
|
111
|
+
display: flex;
|
|
112
|
+
flex-direction: column;
|
|
113
|
+
gap: 0.25rem;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.cqpopCardActions {
|
|
117
|
+
display: flex;
|
|
118
|
+
gap: 0.5rem;
|
|
119
|
+
margin-top: 0.75rem;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// A slim row under the primary actions for the quieter "go somewhere else"
|
|
123
|
+
// link, so Pick up / Dismiss keep the whole action bar to themselves.
|
|
124
|
+
.cqpopCardMore {
|
|
125
|
+
display: flex;
|
|
126
|
+
justify-content: center;
|
|
127
|
+
margin-top: 0.4rem;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// One badge style for every call queue — the text IS the queue's own name, so
|
|
131
|
+
// nothing is left for a colour to say.
|
|
132
|
+
.cqpopBadge {
|
|
133
|
+
display: inline-flex;
|
|
134
|
+
align-items: center;
|
|
135
|
+
gap: 0.4rem;
|
|
136
|
+
min-width: 0;
|
|
137
|
+
padding: 0.2rem 0.6rem;
|
|
138
|
+
border-radius: 999px;
|
|
139
|
+
background: var(--cq-primary);
|
|
140
|
+
font-size: 0.7rem;
|
|
141
|
+
font-weight: 700;
|
|
142
|
+
letter-spacing: 0.4px;
|
|
143
|
+
text-transform: uppercase;
|
|
144
|
+
color: var(--cq-tertiary);
|
|
145
|
+
// Queue names come from Zoom admin and can be long; keep the badge on one
|
|
146
|
+
// line and let the timer beside it hold its place.
|
|
147
|
+
overflow: hidden;
|
|
148
|
+
text-overflow: ellipsis;
|
|
149
|
+
white-space: nowrap;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Pulsing "still ringing" indicator inside the badge.
|
|
153
|
+
.cqpopDot {
|
|
154
|
+
width: 7px;
|
|
155
|
+
height: 7px;
|
|
156
|
+
flex-shrink: 0;
|
|
157
|
+
border-radius: 50%;
|
|
158
|
+
background: rgba(255, 255, 255, 0.95);
|
|
159
|
+
animation: cqpop-pulse 1.2s ease-in-out infinite;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
.cqpopTimer {
|
|
163
|
+
font-size: 0.72rem;
|
|
164
|
+
font-weight: 600;
|
|
165
|
+
color: color-mix(in srgb, var(--cq-paragraph) 75%, transparent);
|
|
166
|
+
white-space: nowrap;
|
|
167
|
+
font-variant-numeric: tabular-nums;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.cqpopCaller {
|
|
171
|
+
display: flex;
|
|
172
|
+
align-items: center;
|
|
173
|
+
gap: 0.4rem;
|
|
174
|
+
color: var(--cq-primary);
|
|
175
|
+
|
|
176
|
+
svg {
|
|
177
|
+
flex-shrink: 0;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.cqpopNumber {
|
|
182
|
+
font-family: 'SFMono-Regular', 'Menlo', 'Consolas', monospace;
|
|
183
|
+
font-size: 1.02rem;
|
|
184
|
+
font-weight: 700;
|
|
185
|
+
letter-spacing: 0.5px;
|
|
186
|
+
color: var(--cq-primary);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Which of the contact's four numbers the caller rang in on ("mobile", "work"
|
|
190
|
+
// …). Deliberately quiet — it annotates the number, it isn't a headline.
|
|
191
|
+
.cqpopMatched {
|
|
192
|
+
font-size: 0.64rem;
|
|
193
|
+
font-weight: 600;
|
|
194
|
+
letter-spacing: 0.4px;
|
|
195
|
+
text-transform: uppercase;
|
|
196
|
+
color: color-mix(in srgb, var(--cq-paragraph) 55%, transparent);
|
|
197
|
+
white-space: nowrap;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
.cqpopName {
|
|
201
|
+
font-size: 0.85rem;
|
|
202
|
+
font-weight: 600;
|
|
203
|
+
color: var(--cq-paragraph);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.cqpopClient {
|
|
207
|
+
font-size: 0.78rem;
|
|
208
|
+
color: var(--cq-paragraph);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
.cqpopClientNone {
|
|
212
|
+
font-style: italic;
|
|
213
|
+
color: color-mix(in srgb, var(--cq-paragraph) 55%, transparent);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
// Client name + open-task badge, separated by a hairline from the caller
|
|
217
|
+
// line above it so the snapshot reads as its own block.
|
|
218
|
+
.cqpopClientHead {
|
|
219
|
+
display: flex;
|
|
220
|
+
align-items: baseline;
|
|
221
|
+
justify-content: space-between;
|
|
222
|
+
gap: 0.5rem;
|
|
223
|
+
margin-top: 0.15rem;
|
|
224
|
+
padding-top: 0.35rem;
|
|
225
|
+
border-top: 1px solid color-mix(in srgb, var(--cq-primary) 18%, transparent);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.cqpopClientLink {
|
|
229
|
+
font-size: 0.88rem;
|
|
230
|
+
font-weight: 700;
|
|
231
|
+
color: var(--cq-primary);
|
|
232
|
+
text-decoration: underline;
|
|
233
|
+
|
|
234
|
+
&:hover {
|
|
235
|
+
color: color-mix(in srgb, var(--cq-primary) 85%, #000);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.cqpopClientName {
|
|
240
|
+
font-size: 0.88rem;
|
|
241
|
+
font-weight: 700;
|
|
242
|
+
color: var(--cq-primary);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Two columns: a fixed label gutter keeps every value on the same left
|
|
246
|
+
// edge, however short the label is.
|
|
247
|
+
.cqpopClientGrid {
|
|
248
|
+
display: grid;
|
|
249
|
+
grid-template-columns: 4.4rem 1fr;
|
|
250
|
+
gap: 0.1rem 0.5rem;
|
|
251
|
+
margin: 0.35rem 0 0;
|
|
252
|
+
font-size: 0.72rem;
|
|
253
|
+
line-height: 1.35;
|
|
254
|
+
|
|
255
|
+
dt {
|
|
256
|
+
margin: 0;
|
|
257
|
+
font-weight: 600;
|
|
258
|
+
color: color-mix(in srgb, var(--cq-paragraph) 60%, transparent);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
dd {
|
|
262
|
+
margin: 0;
|
|
263
|
+
color: var(--cq-paragraph);
|
|
264
|
+
overflow-wrap: anywhere;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
// The next meeting doubles as the way into the calendar — a link, but kept
|
|
269
|
+
// as quiet as the plain text it replaced until it is pointed at.
|
|
270
|
+
.cqpopClientEvent {
|
|
271
|
+
display: block;
|
|
272
|
+
margin-top: 0.3rem;
|
|
273
|
+
border-radius: var(--cq-br);
|
|
274
|
+
font-size: 0.72rem;
|
|
275
|
+
font-weight: 600;
|
|
276
|
+
color: color-mix(in srgb, var(--cq-paragraph) 85%, transparent);
|
|
277
|
+
text-decoration: none;
|
|
278
|
+
// Rendered as a <button> when the host app supplies an onOpenCalendar
|
|
279
|
+
// handler, so the button chrome has to be neutralised here.
|
|
280
|
+
padding: 0;
|
|
281
|
+
border: none;
|
|
282
|
+
background: none;
|
|
283
|
+
font-family: inherit;
|
|
284
|
+
text-align: left;
|
|
285
|
+
cursor: pointer;
|
|
286
|
+
|
|
287
|
+
&:hover,
|
|
288
|
+
&:focus-visible {
|
|
289
|
+
color: var(--cq-primary);
|
|
290
|
+
text-decoration: underline;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
&:focus-visible {
|
|
294
|
+
outline: 2px solid color-mix(in srgb, var(--cq-primary) 45%, transparent);
|
|
295
|
+
outline-offset: 1px;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
// The open-task count is a disclosure button: it expands the list below.
|
|
300
|
+
.cqpopClientTasks {
|
|
301
|
+
display: inline-flex;
|
|
302
|
+
flex-shrink: 0;
|
|
303
|
+
align-items: center;
|
|
304
|
+
gap: 0.25rem;
|
|
305
|
+
padding: 0.1rem 0.4rem;
|
|
306
|
+
border: 1px solid transparent;
|
|
307
|
+
border-radius: 999px;
|
|
308
|
+
background: color-mix(in srgb, var(--cq-dismiss) 18%, transparent);
|
|
309
|
+
color: color-mix(in srgb, var(--cq-dismiss) 70%, #000);
|
|
310
|
+
font-family: inherit;
|
|
311
|
+
font-size: 0.64rem;
|
|
312
|
+
font-weight: 700;
|
|
313
|
+
line-height: 1.4;
|
|
314
|
+
white-space: nowrap;
|
|
315
|
+
cursor: pointer;
|
|
316
|
+
transition:
|
|
317
|
+
background 0.15s ease,
|
|
318
|
+
border-color 0.15s ease;
|
|
319
|
+
|
|
320
|
+
svg {
|
|
321
|
+
flex-shrink: 0;
|
|
322
|
+
transition: transform 0.2s ease;
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
&:hover,
|
|
326
|
+
&:focus-visible {
|
|
327
|
+
background: color-mix(in srgb, var(--cq-dismiss) 30%, transparent);
|
|
328
|
+
border-color: color-mix(in srgb, var(--cq-dismiss) 55%, transparent);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
&:focus-visible {
|
|
332
|
+
outline: 2px solid color-mix(in srgb, var(--cq-dismiss) 55%, transparent);
|
|
333
|
+
outline-offset: 1px;
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.cqpopClientTasksOpen svg {
|
|
338
|
+
transform: rotate(180deg);
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// The expansion behind the open-task chip. Capped and internally scrollable so
|
|
342
|
+
// a client with ten open tickets grows the card by a fixed, predictable amount
|
|
343
|
+
// rather than shoving the rest of the bottom-anchored stack off screen.
|
|
344
|
+
.cqpopTasks {
|
|
345
|
+
margin-top: 0.4rem;
|
|
346
|
+
padding-top: 0.4rem;
|
|
347
|
+
border-top: 1px solid color-mix(in srgb, var(--cq-primary) 18%, transparent);
|
|
348
|
+
overflow: hidden;
|
|
349
|
+
// `backwards`, not `both`: the max-height in the keyframes is only there to
|
|
350
|
+
// drive the reveal, it must not linger and clip the finished panel.
|
|
351
|
+
animation: cqpop-tasks-in 0.2s cubic-bezier(0.33, 1, 0.68, 1) backwards;
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
.cqpopTasksNote {
|
|
355
|
+
margin: 0;
|
|
356
|
+
font-size: 0.7rem;
|
|
357
|
+
font-style: italic;
|
|
358
|
+
color: color-mix(in srgb, var(--cq-paragraph) 55%, transparent);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
.cqpopTasksList {
|
|
362
|
+
max-height: 160px;
|
|
363
|
+
margin: 0;
|
|
364
|
+
padding: 0;
|
|
365
|
+
overflow-y: auto;
|
|
366
|
+
list-style: none;
|
|
367
|
+
scrollbar-width: thin;
|
|
368
|
+
|
|
369
|
+
li + li {
|
|
370
|
+
border-top: 1px solid color-mix(in srgb, var(--cq-primary) 10%, transparent);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
.cqpopTasksItem {
|
|
375
|
+
display: flex;
|
|
376
|
+
flex-direction: column;
|
|
377
|
+
gap: 0.05rem;
|
|
378
|
+
padding: 0.28rem 0.3rem;
|
|
379
|
+
border-radius: var(--cq-br);
|
|
380
|
+
color: var(--cq-paragraph);
|
|
381
|
+
text-decoration: none;
|
|
382
|
+
transition:
|
|
383
|
+
background 0.15s ease,
|
|
384
|
+
color 0.15s ease;
|
|
385
|
+
|
|
386
|
+
&:hover,
|
|
387
|
+
&:focus-visible {
|
|
388
|
+
background: color-mix(in srgb, var(--cq-primary) 12%, transparent);
|
|
389
|
+
color: var(--cq-primary);
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
&:focus-visible {
|
|
393
|
+
outline: 2px solid color-mix(in srgb, var(--cq-primary) 45%, transparent);
|
|
394
|
+
outline-offset: -1px;
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
.cqpopTasksLabel {
|
|
399
|
+
font-size: 0.72rem;
|
|
400
|
+
font-weight: 600;
|
|
401
|
+
line-height: 1.3;
|
|
402
|
+
overflow-wrap: anywhere;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
.cqpopTasksMeta {
|
|
406
|
+
display: flex;
|
|
407
|
+
gap: 0.4rem;
|
|
408
|
+
font-size: 0.64rem;
|
|
409
|
+
color: color-mix(in srgb, var(--cq-paragraph) 60%, transparent);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
.cqpopTasksType {
|
|
413
|
+
font-weight: 600;
|
|
414
|
+
letter-spacing: 0.3px;
|
|
415
|
+
text-transform: uppercase;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.cqpopTasksDue {
|
|
419
|
+
font-variant-numeric: tabular-nums;
|
|
420
|
+
white-space: nowrap;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
.cqpopTasksAll {
|
|
424
|
+
display: inline-block;
|
|
425
|
+
margin-top: 0.35rem;
|
|
426
|
+
padding: 0.1rem 0.3rem;
|
|
427
|
+
border-radius: var(--cq-br);
|
|
428
|
+
font-size: 0.68rem;
|
|
429
|
+
font-weight: 700;
|
|
430
|
+
color: var(--cq-primary);
|
|
431
|
+
text-decoration: none;
|
|
432
|
+
|
|
433
|
+
&:hover,
|
|
434
|
+
&:focus-visible {
|
|
435
|
+
color: color-mix(in srgb, var(--cq-primary) 85%, #000);
|
|
436
|
+
text-decoration: underline;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
&:focus-visible {
|
|
440
|
+
outline: 2px solid color-mix(in srgb, var(--cq-primary) 45%, transparent);
|
|
441
|
+
outline-offset: 1px;
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// Tertiary action: a text button, deliberately not competing with .cqpopBtn.
|
|
446
|
+
.cqpopLink {
|
|
447
|
+
display: inline-flex;
|
|
448
|
+
align-items: center;
|
|
449
|
+
gap: 0.3rem;
|
|
450
|
+
padding: 0.2rem 0.45rem;
|
|
451
|
+
border-radius: var(--cq-btn-br);
|
|
452
|
+
font-size: 0.7rem;
|
|
453
|
+
font-weight: 600;
|
|
454
|
+
color: color-mix(in srgb, var(--cq-paragraph) 75%, transparent);
|
|
455
|
+
text-decoration: none;
|
|
456
|
+
transition: all 0.15s ease;
|
|
457
|
+
|
|
458
|
+
svg {
|
|
459
|
+
flex-shrink: 0;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
&:hover,
|
|
463
|
+
&:focus-visible {
|
|
464
|
+
background: color-mix(in srgb, var(--cq-primary) 12%, transparent);
|
|
465
|
+
color: var(--cq-primary);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
&:focus-visible {
|
|
469
|
+
outline: 2px solid color-mix(in srgb, var(--cq-primary) 45%, transparent);
|
|
470
|
+
outline-offset: 1px;
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Demo cards, and numbers that do not reduce to an AU local number, have no
|
|
475
|
+
// workspace to open — the row still renders so the card keeps its shape.
|
|
476
|
+
.cqpopLinkInert {
|
|
477
|
+
cursor: not-allowed;
|
|
478
|
+
opacity: 0.5;
|
|
479
|
+
|
|
480
|
+
&:hover {
|
|
481
|
+
background: transparent;
|
|
482
|
+
color: color-mix(in srgb, var(--cq-paragraph) 75%, transparent);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
.cqpopBtn {
|
|
487
|
+
display: inline-flex;
|
|
488
|
+
flex: 1;
|
|
489
|
+
align-items: center;
|
|
490
|
+
justify-content: center;
|
|
491
|
+
gap: 0.35rem;
|
|
492
|
+
padding: 0.4rem 0.7rem;
|
|
493
|
+
border-radius: var(--cq-btn-br);
|
|
494
|
+
font-size: 0.8rem;
|
|
495
|
+
font-weight: 600;
|
|
496
|
+
line-height: 1.2;
|
|
497
|
+
cursor: pointer;
|
|
498
|
+
text-decoration: none;
|
|
499
|
+
transition: all 0.15s ease;
|
|
500
|
+
|
|
501
|
+
svg {
|
|
502
|
+
flex-shrink: 0;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
&:hover {
|
|
506
|
+
transform: translateY(-1px);
|
|
507
|
+
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.18);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
&:active {
|
|
511
|
+
transform: translateY(0);
|
|
512
|
+
box-shadow: none;
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
// Green, matching the legacy `.cpview` action.
|
|
517
|
+
.cqpopBtnAnswer {
|
|
518
|
+
border: 1px solid color-mix(in srgb, var(--cq-answer) 92%, #000);
|
|
519
|
+
background: var(--cq-answer);
|
|
520
|
+
color: var(--cq-tertiary);
|
|
521
|
+
|
|
522
|
+
&:hover {
|
|
523
|
+
background: color-mix(in srgb, var(--cq-answer) 88%, #000);
|
|
524
|
+
color: var(--cq-tertiary);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Pick up while the dial mechanism is unverified: present so staff learn
|
|
529
|
+
// where it will live, but visibly inert.
|
|
530
|
+
.cqpopBtnSoon {
|
|
531
|
+
border: 1px solid color-mix(in srgb, var(--cq-answer) 35%, transparent);
|
|
532
|
+
background: color-mix(in srgb, var(--cq-answer) 25%, transparent);
|
|
533
|
+
color: rgba(255, 255, 255, 0.75);
|
|
534
|
+
cursor: not-allowed;
|
|
535
|
+
|
|
536
|
+
&:hover {
|
|
537
|
+
transform: none;
|
|
538
|
+
box-shadow: none;
|
|
539
|
+
background: color-mix(in srgb, var(--cq-answer) 25%, transparent);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
// Red outline, a quieter take on the legacy `.cpdismiss`.
|
|
544
|
+
.cqpopBtnDismiss {
|
|
545
|
+
flex: 0 0 auto;
|
|
546
|
+
border: 1px solid color-mix(in srgb, var(--cq-dismiss) 85%, #000);
|
|
547
|
+
background: transparent;
|
|
548
|
+
color: color-mix(in srgb, var(--cq-dismiss) 78%, #000);
|
|
549
|
+
|
|
550
|
+
// A queue with no pickup code renders Dismiss on its own — then it
|
|
551
|
+
// takes the whole row rather than sitting stranded on the left.
|
|
552
|
+
&:only-child {
|
|
553
|
+
flex: 1;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
&:hover {
|
|
557
|
+
background: color-mix(in srgb, var(--cq-dismiss) 85%, #000);
|
|
558
|
+
color: var(--cq-tertiary);
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
@keyframes cqpop-in {
|
|
563
|
+
from {
|
|
564
|
+
opacity: 0;
|
|
565
|
+
transform: translateY(24px) scale(0.97);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
to {
|
|
569
|
+
opacity: 1;
|
|
570
|
+
transform: translateY(0) scale(1);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
@keyframes cqpop-out {
|
|
575
|
+
from {
|
|
576
|
+
opacity: 1;
|
|
577
|
+
transform: translateY(0) scale(1);
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
to {
|
|
581
|
+
opacity: 0;
|
|
582
|
+
transform: translateY(12px) scale(0.97);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
@keyframes cqpop-tasks-in {
|
|
587
|
+
from {
|
|
588
|
+
opacity: 0;
|
|
589
|
+
max-height: 0;
|
|
590
|
+
transform: translateY(-4px);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
to {
|
|
594
|
+
opacity: 1;
|
|
595
|
+
max-height: 300px;
|
|
596
|
+
transform: translateY(0);
|
|
597
|
+
}
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
@keyframes cqpop-pulse {
|
|
601
|
+
0%,
|
|
602
|
+
100% {
|
|
603
|
+
opacity: 1;
|
|
604
|
+
transform: scale(1);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
50% {
|
|
608
|
+
opacity: 0.35;
|
|
609
|
+
transform: scale(0.7);
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Full-width cards on small screens, same 768px hinge the goalbox uses.
|
|
614
|
+
@media (max-width: 768px) {
|
|
615
|
+
.cqpopStack {
|
|
616
|
+
right: 0.5rem;
|
|
617
|
+
bottom: 0.5rem;
|
|
618
|
+
left: 0.5rem;
|
|
619
|
+
width: auto;
|
|
620
|
+
max-width: none;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
.cqpopCardActions {
|
|
624
|
+
.cqpopBtn {
|
|
625
|
+
flex: 1;
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
// Respect a reduced-motion preference: keep the card, drop the movement.
|
|
631
|
+
@media (prefers-reduced-motion: reduce) {
|
|
632
|
+
.cqpopCard,
|
|
633
|
+
.cqpopCardLeaving,
|
|
634
|
+
.cqpopDot,
|
|
635
|
+
.cqpopTasks {
|
|
636
|
+
animation: none;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.cqpopBtn:hover {
|
|
640
|
+
transform: none;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
.cqpopClientTasks svg {
|
|
644
|
+
transition: none;
|
|
645
|
+
}
|
|
646
|
+
}
|