@nyaruka/temba-components 0.172.0 → 0.173.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/CHANGELOG.md +7 -0
- package/dist/static/svg/index.svg +1 -1
- package/dist/temba-components.js +501 -235
- package/dist/temba-components.js.map +1 -1
- package/package.json +1 -1
- package/src/Icons.ts +4 -1
- package/src/interfaces.ts +2 -0
- package/src/layout/HeaderBar.ts +28 -2
- package/src/layout/PageHeader.ts +14 -7
- package/src/list/ShortcutContentList.ts +347 -0
- package/src/styles/designTokens.ts +11 -0
- package/static/svg/index.svg +1 -1
- package/static/svg/work/traced/book-open-01.svg +1 -0
- package/static/svg/work/traced/layout-alt-03.svg +1 -0
- package/static/svg/work/used/book-open-01.svg +3 -0
- package/static/svg/work/used/layout-alt-03.svg +3 -0
- package/temba-modules.ts +2 -0
package/package.json
CHANGED
package/src/Icons.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable @typescript-eslint/no-duplicate-enum-values */
|
|
2
2
|
// for cache busting we dynamically generate a fingerprint, use bun run svg to update
|
|
3
|
-
export const SVG_FINGERPRINT = '
|
|
3
|
+
export const SVG_FINGERPRINT = '132907abcfa6a4611ba27470e2c5c2c0';
|
|
4
4
|
|
|
5
5
|
// only icons below are included in the sprite sheet
|
|
6
6
|
export enum Icon {
|
|
@@ -58,6 +58,7 @@ export enum Icon {
|
|
|
58
58
|
delete = 'trash-03',
|
|
59
59
|
delete_small = 'x',
|
|
60
60
|
docs = 'file-02',
|
|
61
|
+
documents = 'folder',
|
|
61
62
|
down = 'chevron-down',
|
|
62
63
|
down_double = 'chevron-down-double',
|
|
63
64
|
download = 'download-01',
|
|
@@ -97,6 +98,7 @@ export enum Icon {
|
|
|
97
98
|
integrations = 'layers-three-01',
|
|
98
99
|
invitations = 'user-plus-01',
|
|
99
100
|
issue = 'alert-square',
|
|
101
|
+
knowledge = 'book-open-01',
|
|
100
102
|
label = 'tag-01',
|
|
101
103
|
language = 'translate-01',
|
|
102
104
|
language_default = 'switch-horizontal-01',
|
|
@@ -210,6 +212,7 @@ export enum Icon {
|
|
|
210
212
|
users = 'users-01',
|
|
211
213
|
video = 'video-recorder',
|
|
212
214
|
webhook = 'link-external-01',
|
|
215
|
+
website = 'layout-alt-03',
|
|
213
216
|
workspace = 'folder',
|
|
214
217
|
zoom_fit = 'maximize-02',
|
|
215
218
|
zoom_in = 'expand-06',
|
package/src/interfaces.ts
CHANGED
|
@@ -525,6 +525,8 @@ export enum CustomEventType {
|
|
|
525
525
|
RevisionReverted = 'temba-revision-reverted',
|
|
526
526
|
RevisionsClosed = 'temba-revisions-closed',
|
|
527
527
|
RowClick = 'temba-row-click',
|
|
528
|
+
ShortcutEdit = 'temba-shortcut-edit',
|
|
529
|
+
ShortcutDelete = 'temba-shortcut-delete',
|
|
528
530
|
SelectionChange = 'temba-selection-change',
|
|
529
531
|
BulkAction = 'temba-bulk-action',
|
|
530
532
|
/** The label dropdown's "New Label…" row was clicked — detail
|
package/src/layout/HeaderBar.ts
CHANGED
|
@@ -14,13 +14,19 @@ export class HeaderBar extends RapidElement {
|
|
|
14
14
|
${designTokens}
|
|
15
15
|
|
|
16
16
|
:host {
|
|
17
|
+
/* The single source for the bar's inset — it sets the horizontal
|
|
18
|
+
padding here and, for fit-content bars, the vertical padding the
|
|
19
|
+
slotted page header inherits. Both axes move together by
|
|
20
|
+
construction, so the surround can't drift. */
|
|
21
|
+
--header-bar-inset: 8px;
|
|
22
|
+
|
|
17
23
|
flex: 0 0 auto;
|
|
18
24
|
display: flex;
|
|
19
25
|
align-items: center;
|
|
20
26
|
/* 52px strip plus the 1px rule */
|
|
21
|
-
height:
|
|
27
|
+
height: var(--header-h);
|
|
22
28
|
box-sizing: border-box;
|
|
23
|
-
padding: 0
|
|
29
|
+
padding: 0 var(--header-bar-inset);
|
|
24
30
|
background: var(--surface);
|
|
25
31
|
/* the rule is a box-shadow, not a border — host pages (tailwind
|
|
26
32
|
preflight) reset border-width on every element, and outer-scope
|
|
@@ -28,6 +34,26 @@ export class HeaderBar extends RapidElement {
|
|
|
28
34
|
box-shadow: inset 0 -1px 0 0 var(--border);
|
|
29
35
|
}
|
|
30
36
|
|
|
37
|
+
/* Standalone page headers keep the strip height as a floor but grow
|
|
38
|
+
for taller content (a subtitle), with the same surround on every
|
|
39
|
+
side either way.
|
|
40
|
+
|
|
41
|
+
The inset is solved for rather than picked: it's the padding that
|
|
42
|
+
makes inset + one title line + inset come out at exactly the strip
|
|
43
|
+
height, so a single-line title fills the strip with balanced
|
|
44
|
+
spacing. That's why the floor is expressed as height, not as a
|
|
45
|
+
min-height the padding has to fight — with the inset derived this
|
|
46
|
+
way the content already meets the floor, so there's never slack for
|
|
47
|
+
flex centering to absorb into an uneven gap above and below. */
|
|
48
|
+
:host([fit-content]) {
|
|
49
|
+
--header-bar-inset: calc((var(--header-h) - var(--title-line)) / 2);
|
|
50
|
+
--page-header-padding: var(--header-bar-inset) 0;
|
|
51
|
+
|
|
52
|
+
align-items: stretch;
|
|
53
|
+
height: auto;
|
|
54
|
+
min-height: var(--header-h);
|
|
55
|
+
}
|
|
56
|
+
|
|
31
57
|
::slotted(*) {
|
|
32
58
|
flex-grow: 1;
|
|
33
59
|
min-width: 0;
|
package/src/layout/PageHeader.ts
CHANGED
|
@@ -49,14 +49,19 @@ export class PageHeader extends RapidElement {
|
|
|
49
49
|
/* One row: the title/subtitle block on the left and the
|
|
50
50
|
actions/content-menu on the right, vertically centered against
|
|
51
51
|
each other. The title block is the flexing column so the
|
|
52
|
-
actions hold their size.
|
|
53
|
-
horizontal inset
|
|
54
|
-
the
|
|
52
|
+
actions hold their size. Hosts tune the vertical padding to match
|
|
53
|
+
their own horizontal inset — list panels use the default, header
|
|
54
|
+
bars pass down theirs — so the header always ends up with an even
|
|
55
|
+
surround. The height follows from that padding plus the content; a
|
|
56
|
+
host wanting a taller strip should raise the padding rather than
|
|
57
|
+
impose a height, which would be absorbed into the gap around the
|
|
58
|
+
title instead of growing the box. */
|
|
55
59
|
.header {
|
|
60
|
+
box-sizing: border-box;
|
|
56
61
|
display: flex;
|
|
57
62
|
align-items: center;
|
|
58
63
|
gap: var(--gap);
|
|
59
|
-
padding: 12px 0;
|
|
64
|
+
padding: var(--page-header-padding, 12px 0);
|
|
60
65
|
}
|
|
61
66
|
/* Title + subtitle stacked tight, sharing the left column. It
|
|
62
67
|
flexes and clips so a long subtitle truncates against the
|
|
@@ -68,13 +73,15 @@ export class PageHeader extends RapidElement {
|
|
|
68
73
|
flex-direction: column;
|
|
69
74
|
gap: 1px;
|
|
70
75
|
}
|
|
76
|
+
/* Sized from the shared tokens — temba-header-bar solves its inset
|
|
77
|
+
against --title-line, so the two stay in step. */
|
|
71
78
|
.title {
|
|
72
|
-
font-size:
|
|
79
|
+
font-size: var(--title-size);
|
|
73
80
|
/* slotted contact names render at the title's size */
|
|
74
|
-
--contact-name-font-size:
|
|
81
|
+
--contact-name-font-size: var(--title-size);
|
|
75
82
|
font-weight: var(--w-semibold);
|
|
76
83
|
color: var(--text-1);
|
|
77
|
-
line-height:
|
|
84
|
+
line-height: var(--title-leading);
|
|
78
85
|
white-space: nowrap;
|
|
79
86
|
overflow: hidden;
|
|
80
87
|
text-overflow: ellipsis;
|
|
@@ -0,0 +1,347 @@
|
|
|
1
|
+
import { css, html, TemplateResult } from 'lit';
|
|
2
|
+
import { property, state } from 'lit/decorators.js';
|
|
3
|
+
import { Icon } from '../Icons';
|
|
4
|
+
import { CustomEventType, Shortcut } from '../interfaces';
|
|
5
|
+
import { ContentList, ContentListColumn } from './ContentList';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Shortcut management list used by the Tickets knowledge page. This is
|
|
9
|
+
* intentionally separate from `temba-shortcuts`, which is the compact picker
|
|
10
|
+
* shown while composing a ticket reply.
|
|
11
|
+
*/
|
|
12
|
+
export class ShortcutContentList extends ContentList<Shortcut> {
|
|
13
|
+
static get styles() {
|
|
14
|
+
return css`
|
|
15
|
+
${ContentList.styles}
|
|
16
|
+
|
|
17
|
+
tr.row {
|
|
18
|
+
cursor: pointer;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
.table-frame {
|
|
22
|
+
margin-left: -20px;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
tr.header th:first-child,
|
|
26
|
+
tr.row td:first-child {
|
|
27
|
+
padding-left: 20px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
tr.header th:last-child,
|
|
31
|
+
tr.row td:last-child {
|
|
32
|
+
padding-right: 20px;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
.shortcut-name {
|
|
36
|
+
font-weight: var(--w-medium);
|
|
37
|
+
overflow: hidden;
|
|
38
|
+
text-overflow: ellipsis;
|
|
39
|
+
white-space: nowrap;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
.shortcut-text {
|
|
43
|
+
color: var(--text-2);
|
|
44
|
+
overflow: hidden;
|
|
45
|
+
text-overflow: ellipsis;
|
|
46
|
+
white-space: nowrap;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
.detail {
|
|
50
|
+
display: flex;
|
|
51
|
+
flex-direction: column;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.detail-header {
|
|
55
|
+
align-items: center;
|
|
56
|
+
border-bottom: 1px solid var(--border);
|
|
57
|
+
display: flex;
|
|
58
|
+
gap: 12px;
|
|
59
|
+
padding: 1em;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
.detail-title-block {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex: 1;
|
|
65
|
+
flex-direction: column;
|
|
66
|
+
gap: 4px;
|
|
67
|
+
min-width: 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.detail-title {
|
|
71
|
+
color: var(--text-1);
|
|
72
|
+
font-size: 15.5px;
|
|
73
|
+
font-weight: var(--w-semibold);
|
|
74
|
+
overflow: hidden;
|
|
75
|
+
text-overflow: ellipsis;
|
|
76
|
+
white-space: nowrap;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.detail-meta {
|
|
80
|
+
color: var(--text-3);
|
|
81
|
+
font-size: 0.9em;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
.detail-actions {
|
|
85
|
+
align-items: center;
|
|
86
|
+
display: flex;
|
|
87
|
+
flex-shrink: 0;
|
|
88
|
+
gap: 8px;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.menu-button {
|
|
92
|
+
align-items: center;
|
|
93
|
+
background: var(--surface);
|
|
94
|
+
border: 1px solid var(--border-strong);
|
|
95
|
+
border-radius: var(--r-sm);
|
|
96
|
+
box-sizing: border-box;
|
|
97
|
+
color: var(--text-1);
|
|
98
|
+
cursor: pointer;
|
|
99
|
+
display: inline-flex;
|
|
100
|
+
font-size: 12.5px;
|
|
101
|
+
height: 26px;
|
|
102
|
+
padding: 0 10px;
|
|
103
|
+
white-space: nowrap;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
.menu-button:hover {
|
|
107
|
+
background: var(--sunken);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.menu-button.destructive {
|
|
111
|
+
color: var(--danger);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
.menu-button.destructive:hover {
|
|
115
|
+
border-color: var(--danger);
|
|
116
|
+
background: color-mix(in srgb, var(--danger) 6%, var(--surface));
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
.detail-close {
|
|
120
|
+
align-items: center;
|
|
121
|
+
border-radius: var(--r-sm);
|
|
122
|
+
color: var(--text-3);
|
|
123
|
+
cursor: pointer;
|
|
124
|
+
display: inline-flex;
|
|
125
|
+
flex-shrink: 0;
|
|
126
|
+
height: 28px;
|
|
127
|
+
justify-content: center;
|
|
128
|
+
user-select: none;
|
|
129
|
+
width: 28px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.detail-close:hover {
|
|
133
|
+
background: var(--sunken);
|
|
134
|
+
color: var(--text-1);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
.detail-close temba-icon {
|
|
138
|
+
--icon-color: currentColor;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
.detail-body {
|
|
142
|
+
max-height: calc(100vh - 300px);
|
|
143
|
+
overflow-y: auto;
|
|
144
|
+
padding: 1.25em 1.75em;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
.detail-response {
|
|
148
|
+
background: color-mix(in srgb, var(--sunken) 45%, var(--surface));
|
|
149
|
+
border: 1px solid var(--border);
|
|
150
|
+
border-radius: var(--r);
|
|
151
|
+
color: var(--text-1);
|
|
152
|
+
line-height: 1.5;
|
|
153
|
+
padding: 0.9em 1em 1em;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* pre-wrap lives on the text node's own element so the template's
|
|
157
|
+
indentation around the interpolation isn't rendered as leading
|
|
158
|
+
whitespace */
|
|
159
|
+
.detail-text {
|
|
160
|
+
overflow-wrap: anywhere;
|
|
161
|
+
white-space: pre-wrap;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
.detail-section-title {
|
|
165
|
+
color: var(--text-3);
|
|
166
|
+
font-size: 0.75em;
|
|
167
|
+
font-weight: var(--w-semibold);
|
|
168
|
+
letter-spacing: 0.05em;
|
|
169
|
+
margin-bottom: 0.6em;
|
|
170
|
+
text-transform: uppercase;
|
|
171
|
+
}
|
|
172
|
+
`;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
@property({ type: Boolean })
|
|
176
|
+
editable = false;
|
|
177
|
+
|
|
178
|
+
@property({ type: Boolean })
|
|
179
|
+
deletable = false;
|
|
180
|
+
|
|
181
|
+
@state()
|
|
182
|
+
private detailShortcut: Shortcut = null;
|
|
183
|
+
|
|
184
|
+
constructor() {
|
|
185
|
+
super();
|
|
186
|
+
this.valueKey = 'uuid';
|
|
187
|
+
this.emptyMessage = 'No shortcuts';
|
|
188
|
+
this.searchPlaceholder = 'Search shortcuts';
|
|
189
|
+
this.columns = [
|
|
190
|
+
{
|
|
191
|
+
key: 'name',
|
|
192
|
+
label: 'Name',
|
|
193
|
+
minWidth: '140px',
|
|
194
|
+
maxWidth: '240px'
|
|
195
|
+
},
|
|
196
|
+
{ key: 'text', label: 'Text', minWidth: '240px', grow: true }
|
|
197
|
+
];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
public connectedCallback(): void {
|
|
201
|
+
super.connectedCallback();
|
|
202
|
+
this.addEventListener(
|
|
203
|
+
CustomEventType.RowClick,
|
|
204
|
+
this.handleRowClickEvent as EventListener
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
public disconnectedCallback(): void {
|
|
209
|
+
super.disconnectedCallback();
|
|
210
|
+
this.removeEventListener(
|
|
211
|
+
CustomEventType.RowClick,
|
|
212
|
+
this.handleRowClickEvent as EventListener
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
private handleRowClickEvent = (event: CustomEvent): void => {
|
|
217
|
+
const shortcut = event.detail?.item as Shortcut;
|
|
218
|
+
if (shortcut) {
|
|
219
|
+
this.detailShortcut = shortcut;
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
private handleDetailClosed = (): void => {
|
|
224
|
+
this.detailShortcut = null;
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
private handleEditClicked(): void {
|
|
228
|
+
const shortcut = this.detailShortcut;
|
|
229
|
+
this.detailShortcut = null;
|
|
230
|
+
this.fireCustomEvent(CustomEventType.ShortcutEdit, { item: shortcut });
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
private handleDeleteClicked(): void {
|
|
234
|
+
const shortcut = this.detailShortcut;
|
|
235
|
+
this.detailShortcut = null;
|
|
236
|
+
this.fireCustomEvent(CustomEventType.ShortcutDelete, { item: shortcut });
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
private handleActivationKey(event: KeyboardEvent): void {
|
|
240
|
+
if (event.key === 'Enter' || event.key === ' ') {
|
|
241
|
+
event.preventDefault();
|
|
242
|
+
this.handleDetailClosed();
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
protected renderCell(
|
|
247
|
+
shortcut: Shortcut,
|
|
248
|
+
column: ContentListColumn
|
|
249
|
+
): TemplateResult | string {
|
|
250
|
+
switch (column.key) {
|
|
251
|
+
case 'name':
|
|
252
|
+
return html`<span class="shortcut-name" title=${shortcut.name || ''}
|
|
253
|
+
>${shortcut.name || ''}</span
|
|
254
|
+
>`;
|
|
255
|
+
case 'text':
|
|
256
|
+
return html`<span class="shortcut-text" title=${shortcut.text || ''}
|
|
257
|
+
>${shortcut.text || ''}</span
|
|
258
|
+
>`;
|
|
259
|
+
default:
|
|
260
|
+
return super.renderCell(shortcut, column);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
private renderDetail(): TemplateResult {
|
|
265
|
+
const shortcut = this.detailShortcut;
|
|
266
|
+
|
|
267
|
+
return html`
|
|
268
|
+
<temba-dialog
|
|
269
|
+
size="xlarge"
|
|
270
|
+
variant="flat"
|
|
271
|
+
primaryButtonName=""
|
|
272
|
+
cancelButtonName=""
|
|
273
|
+
hideOnClick
|
|
274
|
+
?open=${!!shortcut}
|
|
275
|
+
@temba-dialog-hidden=${this.handleDetailClosed}
|
|
276
|
+
@keyup=${(event: KeyboardEvent) => {
|
|
277
|
+
if (event.key === 'Escape') {
|
|
278
|
+
this.handleDetailClosed();
|
|
279
|
+
}
|
|
280
|
+
}}
|
|
281
|
+
>
|
|
282
|
+
${shortcut
|
|
283
|
+
? html`
|
|
284
|
+
<div class="detail">
|
|
285
|
+
<div class="detail-header">
|
|
286
|
+
<div class="detail-title-block">
|
|
287
|
+
<div class="detail-title">${shortcut.name}</div>
|
|
288
|
+
${shortcut.modified_on
|
|
289
|
+
? html`<div class="detail-meta">
|
|
290
|
+
Modified
|
|
291
|
+
<temba-date
|
|
292
|
+
value=${shortcut.modified_on}
|
|
293
|
+
display="datetime"
|
|
294
|
+
></temba-date>
|
|
295
|
+
</div>`
|
|
296
|
+
: null}
|
|
297
|
+
</div>
|
|
298
|
+
${this.editable || this.deletable
|
|
299
|
+
? html`<div class="detail-actions">
|
|
300
|
+
${this.editable
|
|
301
|
+
? html`<button
|
|
302
|
+
type="button"
|
|
303
|
+
class="menu-button"
|
|
304
|
+
@click=${this.handleEditClicked}
|
|
305
|
+
>
|
|
306
|
+
Edit
|
|
307
|
+
</button>`
|
|
308
|
+
: null}
|
|
309
|
+
${this.deletable
|
|
310
|
+
? html`<button
|
|
311
|
+
type="button"
|
|
312
|
+
class="menu-button destructive"
|
|
313
|
+
@click=${this.handleDeleteClicked}
|
|
314
|
+
>
|
|
315
|
+
Delete
|
|
316
|
+
</button>`
|
|
317
|
+
: null}
|
|
318
|
+
</div>`
|
|
319
|
+
: null}
|
|
320
|
+
<div
|
|
321
|
+
class="detail-close"
|
|
322
|
+
role="button"
|
|
323
|
+
tabindex="0"
|
|
324
|
+
aria-label="Close"
|
|
325
|
+
@click=${this.handleDetailClosed}
|
|
326
|
+
@keydown=${this.handleActivationKey}
|
|
327
|
+
>
|
|
328
|
+
<temba-icon name=${Icon.close} size="1.4"></temba-icon>
|
|
329
|
+
</div>
|
|
330
|
+
</div>
|
|
331
|
+
<div class="detail-body">
|
|
332
|
+
<div class="detail-response">
|
|
333
|
+
<div class="detail-section-title">Response</div>
|
|
334
|
+
<div class="detail-text">${shortcut.text}</div>
|
|
335
|
+
</div>
|
|
336
|
+
</div>
|
|
337
|
+
</div>
|
|
338
|
+
`
|
|
339
|
+
: null}
|
|
340
|
+
</temba-dialog>
|
|
341
|
+
`;
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
public render(): TemplateResult {
|
|
345
|
+
return html`${super.render()}${this.renderDetail()}`;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
@@ -103,6 +103,17 @@ export const designTokens = css`
|
|
|
103
103
|
--pad: 10px;
|
|
104
104
|
--gap: 14px;
|
|
105
105
|
|
|
106
|
+
/* Page header strip. --header-h is the height of a header bar over a
|
|
107
|
+
single-line title (the tickets / contact chat strip). --title-line is
|
|
108
|
+
one line of that title, declared here rather than inside
|
|
109
|
+
temba-page-header because temba-header-bar derives its balanced inset
|
|
110
|
+
from it — keeping both on one definition means restyling the title
|
|
111
|
+
can't silently unbalance the strip. */
|
|
112
|
+
--header-h: 53px;
|
|
113
|
+
--title-size: 15.5px;
|
|
114
|
+
--title-leading: 1.25;
|
|
115
|
+
--title-line: calc(var(--title-size) * var(--title-leading));
|
|
116
|
+
|
|
106
117
|
/* shadows */
|
|
107
118
|
--shadow-1:
|
|
108
119
|
0 1px 1px rgba(15, 22, 36, 0.04), 0 1px 2px rgba(15, 22, 36, 0.04);
|