ui-optago 1.0.1 → 1.0.3
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 +1 -1
- package/ui-optago.css +92 -28
- package/ui-optago.js +76 -1
- package/ui-optago.html +0 -1240
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ui-optago",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
4
4
|
"description": "Design System Óptago — componentes UI em CSS puro + JS vanilla, com tema claro/escuro, verde-lima (#C0FF6B) e app shell com sidebar colapsável.",
|
|
5
5
|
"author": "Óptago <cowork@optago.com.br> (https://optago.com.br)",
|
|
6
6
|
"license": "MIT",
|
package/ui-optago.css
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* ============================================================================
|
|
2
|
-
UI ÓPTAGO — Design System v1.0.
|
|
2
|
+
UI ÓPTAGO — Design System v1.0.3
|
|
3
3
|
CSS puro, sem dependências. Tema escuro por padrão.
|
|
4
4
|
Para tema claro: adicione a classe "light" ao <html> (o ui-optago.js
|
|
5
5
|
gerencia isso automaticamente via localStorage).
|
|
@@ -74,12 +74,12 @@
|
|
|
74
74
|
|
|
75
75
|
/* Superfícies — TEMA CLARO */
|
|
76
76
|
html.light {
|
|
77
|
-
--op-bg: #
|
|
78
|
-
--op-panel: #
|
|
79
|
-
--op-panel-2: #
|
|
80
|
-
--op-panel-3: #
|
|
81
|
-
--op-border: #
|
|
82
|
-
--op-border-2: #
|
|
77
|
+
--op-bg: #E3E9F0;
|
|
78
|
+
--op-panel: #F8FAFC;
|
|
79
|
+
--op-panel-2: #EEF2F7;
|
|
80
|
+
--op-panel-3: #E6EBF2;
|
|
81
|
+
--op-border: #D6DEE7;
|
|
82
|
+
--op-border-2: #BDC9D8;
|
|
83
83
|
--op-text: #334155;
|
|
84
84
|
--op-strong: #0F172A;
|
|
85
85
|
--op-muted: #64748B;
|
|
@@ -100,9 +100,9 @@ html.light {
|
|
|
100
100
|
/* Fundo do tema claro: gradiente suave com um toque de verde-lima no topo */
|
|
101
101
|
html.light body {
|
|
102
102
|
background:
|
|
103
|
-
radial-gradient(900px 420px at 75% -10%, rgba(192,255,107,.
|
|
104
|
-
radial-gradient(700px 380px at 10% 110%, rgba(192,255,107,.
|
|
105
|
-
linear-gradient(180deg, #
|
|
103
|
+
radial-gradient(900px 420px at 75% -10%, rgba(192,255,107,.20) 0%, transparent 60%),
|
|
104
|
+
radial-gradient(700px 380px at 10% 110%, rgba(192,255,107,.10) 0%, transparent 60%),
|
|
105
|
+
linear-gradient(180deg, #E7ECF2 0%, #DEE5EC 100%);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
108
|
/* ----------------------------------------------------------------------------
|
|
@@ -140,7 +140,9 @@ h4 { font-size: 1rem; }
|
|
|
140
140
|
|
|
141
141
|
p { margin: 0 0 1em; }
|
|
142
142
|
a { color: var(--op-accent); }
|
|
143
|
-
html.light a {
|
|
143
|
+
html.light a:not(.op-btn) {
|
|
144
|
+
color: #3F6212;
|
|
145
|
+
}
|
|
144
146
|
code, kbd { font-family: var(--op-font-mono); font-size: .85em; }
|
|
145
147
|
|
|
146
148
|
kbd {
|
|
@@ -279,12 +281,12 @@ html.light .op-brand-mark::after { background: var(--op-accent); }
|
|
|
279
281
|
.op-main {
|
|
280
282
|
flex: 1;
|
|
281
283
|
overflow-y: auto;
|
|
282
|
-
padding:
|
|
284
|
+
padding: 1.5rem;
|
|
283
285
|
scroll-behavior: smooth;
|
|
284
286
|
position: relative;
|
|
285
287
|
z-index: 1; /* mantém o conteúdo acima dos .op-glow do fundo */
|
|
286
288
|
}
|
|
287
|
-
@media (min-width: 1024px) { .op-main { padding:
|
|
289
|
+
@media (min-width: 1024px) { .op-main { padding: 1.75rem 2rem; } }
|
|
288
290
|
|
|
289
291
|
.op-container { max-width: 1100px; margin: 0 auto; }
|
|
290
292
|
|
|
@@ -358,25 +360,28 @@ html.light .op-brand-mark::after { background: var(--op-accent); }
|
|
|
358
360
|
align-items: center;
|
|
359
361
|
gap: .75rem;
|
|
360
362
|
padding: .625rem .75rem;
|
|
363
|
+
border: 1px solid transparent;
|
|
361
364
|
border-radius: var(--op-radius);
|
|
362
365
|
color: var(--op-text);
|
|
363
366
|
text-decoration: none;
|
|
364
367
|
font-weight: 600;
|
|
365
368
|
font-size: .875rem;
|
|
366
369
|
white-space: nowrap;
|
|
367
|
-
transition: background .2s ease, color .2s ease;
|
|
370
|
+
transition: background .2s ease, color .2s ease, border-color .2s ease;
|
|
368
371
|
}
|
|
369
372
|
.op-nav-item i { font-size: 1.25rem; flex-shrink: 0; }
|
|
370
373
|
.op-nav-item:hover {
|
|
371
374
|
background: color-mix(in srgb, var(--op-strong) 6%, transparent);
|
|
375
|
+
border-color: var(--op-border-2);
|
|
372
376
|
color: var(--op-strong);
|
|
373
377
|
}
|
|
374
378
|
.op-nav-item.is-active {
|
|
375
|
-
background: color-mix(in srgb, var(--op-accent)
|
|
379
|
+
background: color-mix(in srgb, var(--op-accent) 15%, transparent);
|
|
380
|
+
border-color: color-mix(in srgb, var(--op-accent) 45%, transparent);
|
|
376
381
|
color: var(--op-strong);
|
|
377
382
|
box-shadow: inset -3px 0 0 var(--op-accent);
|
|
378
383
|
}
|
|
379
|
-
html.light .op-nav-item.is-active { box-shadow: inset -3px 0 0 #84CC16; }
|
|
384
|
+
html.light .op-nav-item.is-active { box-shadow: inset -3px 0 0 #84CC16; border-color: color-mix(in srgb, #84CC16 45%, transparent); }
|
|
380
385
|
.op-nav-item.is-active i { color: var(--op-accent); }
|
|
381
386
|
html.light .op-nav-item.is-active i { color: #3F6212; }
|
|
382
387
|
|
|
@@ -385,7 +390,7 @@ html.light .op-nav-item.is-active i { color: #3F6212; }
|
|
|
385
390
|
.op-sidebar.is-collapsed .op-nav-text,
|
|
386
391
|
.op-sidebar.is-collapsed .op-sidebar-label,
|
|
387
392
|
.op-sidebar.is-collapsed .op-sidebar-header-text { display: none; }
|
|
388
|
-
.op-sidebar.is-collapsed .op-nav-item { justify-content: center; padding
|
|
393
|
+
.op-sidebar.is-collapsed .op-nav-item { justify-content: center; padding: .625rem; }
|
|
389
394
|
|
|
390
395
|
/* Tooltip do item (aparece à esquerda quando colapsada).
|
|
391
396
|
position:fixed — o JS calcula top/right no hover, pois o overflow-y:auto
|
|
@@ -710,6 +715,19 @@ html.light .op-input:focus, html.light .op-select:focus, html.light .op-textarea
|
|
|
710
715
|
}
|
|
711
716
|
.op-input-icon .op-input { padding-left: 2.625rem; }
|
|
712
717
|
|
|
718
|
+
/* Botão de mostrar/ocultar senha: envolva o input com [data-op-reveal] e
|
|
719
|
+
adicione um <button data-op-reveal-toggle> dentro — o toggle de type
|
|
720
|
+
password/text é feito automaticamente pelo JS da lib. */
|
|
721
|
+
[data-op-reveal] { position: relative; }
|
|
722
|
+
[data-op-reveal] .op-input { padding-right: 2.5rem; }
|
|
723
|
+
.op-reveal-btn {
|
|
724
|
+
position: absolute; top: 50%; right: .5rem; translate: 0 -50%;
|
|
725
|
+
background: none; border: 0; cursor: pointer; padding: .25rem;
|
|
726
|
+
color: var(--op-muted); font-size: 1.125rem; line-height: 1;
|
|
727
|
+
display: flex; align-items: center;
|
|
728
|
+
}
|
|
729
|
+
.op-reveal-btn:hover { color: var(--op-text); }
|
|
730
|
+
|
|
713
731
|
/* Input group (prefixo/sufixo) */
|
|
714
732
|
.op-input-group { display: flex; }
|
|
715
733
|
.op-input-group .op-input { border-radius: 0; }
|
|
@@ -1415,6 +1433,11 @@ html.light .op-modal { background: rgba(15,23,42,.5); }
|
|
|
1415
1433
|
border-top: 1px solid var(--op-border);
|
|
1416
1434
|
background: var(--op-panel-2);
|
|
1417
1435
|
}
|
|
1436
|
+
/* Modais com formulário real (method="post") costumam envolver o body e o
|
|
1437
|
+
footer num único <form> para o submit incluir os dois. Sem isso, o <form>
|
|
1438
|
+
(um bloco comum) quebra a coluna flex do .op-modal-box e o body deixa de
|
|
1439
|
+
rolar internamente — o modal cresce para fora da tela em vez de rolar. */
|
|
1440
|
+
.op-modal form { display: contents; }
|
|
1418
1441
|
|
|
1419
1442
|
/* ----------------------------------------------------------------------------
|
|
1420
1443
|
19. TOASTS (criados via OptagoUI.toast)
|
|
@@ -1489,17 +1512,53 @@ html.light .op-modal { background: rgba(15,23,42,.5); }
|
|
|
1489
1512
|
.op-toast-danger .op-toast-icon { background: color-mix(in srgb, var(--op-danger) 15%, transparent); color: var(--op-danger); border-color: color-mix(in srgb, var(--op-danger) 30%, transparent); }
|
|
1490
1513
|
|
|
1491
1514
|
/* ----------------------------------------------------------------------------
|
|
1492
|
-
20.
|
|
1515
|
+
20. TELA DE CARREGAMENTO (overlay em tela cheia)
|
|
1516
|
+
Uso: OptagoUI.showLoading('Mensagem...') / OptagoUI.hideLoading()
|
|
1517
|
+
ou data-op-loading-form no <form> para acionar sozinho no submit.
|
|
1518
|
+
---------------------------------------------------------------------------- */
|
|
1519
|
+
.op-loading-overlay {
|
|
1520
|
+
position: fixed;
|
|
1521
|
+
inset: 0;
|
|
1522
|
+
z-index: 150;
|
|
1523
|
+
display: none;
|
|
1524
|
+
flex-direction: column;
|
|
1525
|
+
align-items: center;
|
|
1526
|
+
justify-content: center;
|
|
1527
|
+
gap: 1.25rem;
|
|
1528
|
+
background: color-mix(in srgb, var(--op-bg) 85%, transparent);
|
|
1529
|
+
backdrop-filter: blur(8px);
|
|
1530
|
+
-webkit-backdrop-filter: blur(8px);
|
|
1531
|
+
opacity: 0;
|
|
1532
|
+
transition: opacity .25s var(--op-ease);
|
|
1533
|
+
}
|
|
1534
|
+
.op-loading-overlay.is-open { display: flex; }
|
|
1535
|
+
.op-loading-overlay.is-visible { opacity: 1; }
|
|
1536
|
+
.op-loading-overlay .op-spinner { width: 46px; height: 46px; border-width: 3px; }
|
|
1537
|
+
.op-loading-message {
|
|
1538
|
+
max-width: 320px;
|
|
1539
|
+
padding: 0 1.5rem;
|
|
1540
|
+
font-family: var(--op-font-mono);
|
|
1541
|
+
font-size: .875rem;
|
|
1542
|
+
font-weight: 600;
|
|
1543
|
+
letter-spacing: .01em;
|
|
1544
|
+
text-align: center;
|
|
1545
|
+
color: var(--op-strong);
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1548
|
+
/* ----------------------------------------------------------------------------
|
|
1549
|
+
21. BLOCO DE DEMONSTRAÇÃO (showcase: preview + copiar + ver código)
|
|
1493
1550
|
---------------------------------------------------------------------------- */
|
|
1494
1551
|
.op-demo {
|
|
1495
1552
|
background: var(--op-panel);
|
|
1496
1553
|
border: 1px solid var(--op-border);
|
|
1497
1554
|
border-radius: var(--op-radius-lg);
|
|
1498
|
-
overflow: hidden;
|
|
1499
1555
|
box-shadow: var(--op-shadow);
|
|
1500
1556
|
}
|
|
1557
|
+
/* Sem overflow:hidden no container: dropdowns/tooltips exibidos dentro do
|
|
1558
|
+
preview não podem ser cortados. O arredondamento é feito nos filhos. */
|
|
1501
1559
|
.op-demo-preview {
|
|
1502
|
-
padding:
|
|
1560
|
+
padding: 1.5rem;
|
|
1561
|
+
border-radius: var(--op-radius-lg) var(--op-radius-lg) 0 0;
|
|
1503
1562
|
background:
|
|
1504
1563
|
radial-gradient(color-mix(in srgb, var(--op-border) 55%, transparent) 1px, transparent 1px);
|
|
1505
1564
|
background-size: 22px 22px;
|
|
@@ -1511,7 +1570,11 @@ html.light .op-modal { background: rgba(15,23,42,.5); }
|
|
|
1511
1570
|
padding: .625rem .875rem;
|
|
1512
1571
|
border-top: 1px solid var(--op-border);
|
|
1513
1572
|
background: var(--op-panel-2);
|
|
1573
|
+
border-radius: 0 0 var(--op-radius-lg) var(--op-radius-lg);
|
|
1514
1574
|
}
|
|
1575
|
+
/* Quando o código-fonte está visível, ele passa a ser o último bloco:
|
|
1576
|
+
a barra perde o arredondamento inferior e o código assume. */
|
|
1577
|
+
.op-demo-bar:has(+ .op-demo-code.is-visible) { border-radius: 0; }
|
|
1515
1578
|
.op-demo-code {
|
|
1516
1579
|
display: none;
|
|
1517
1580
|
margin: 0;
|
|
@@ -1525,6 +1588,7 @@ html.light .op-modal { background: rgba(15,23,42,.5); }
|
|
|
1525
1588
|
overflow-x: auto;
|
|
1526
1589
|
tab-size: 2;
|
|
1527
1590
|
white-space: pre;
|
|
1591
|
+
border-radius: 0 0 var(--op-radius-lg) var(--op-radius-lg);
|
|
1528
1592
|
}
|
|
1529
1593
|
.op-demo-code.is-visible { display: block; }
|
|
1530
1594
|
|
|
@@ -1533,14 +1597,14 @@ html.light .op-modal { background: rgba(15,23,42,.5); }
|
|
|
1533
1597
|
display: flex;
|
|
1534
1598
|
align-items: center;
|
|
1535
1599
|
gap: .75rem;
|
|
1536
|
-
padding-bottom:
|
|
1537
|
-
margin-bottom: 1.
|
|
1600
|
+
padding-bottom: .75rem;
|
|
1601
|
+
margin-bottom: 1.125rem;
|
|
1538
1602
|
border-bottom: 1px solid var(--op-border);
|
|
1539
1603
|
}
|
|
1540
1604
|
.op-section-head i {
|
|
1541
|
-
font-size: 1.
|
|
1605
|
+
font-size: 1.25rem;
|
|
1542
1606
|
color: var(--op-accent);
|
|
1543
|
-
width:
|
|
1607
|
+
width: 38px; height: 38px;
|
|
1544
1608
|
display: flex;
|
|
1545
1609
|
align-items: center;
|
|
1546
1610
|
justify-content: center;
|
|
@@ -1867,7 +1931,7 @@ html.light .op-tabulator.tabulator .tabulator-footer .tabulator-page.active {
|
|
|
1867
1931
|
.op-tabulator .op-progress { min-width: 90px; }
|
|
1868
1932
|
|
|
1869
1933
|
/* ----------------------------------------------------------------------------
|
|
1870
|
-
|
|
1934
|
+
22. UTILITÁRIOS
|
|
1871
1935
|
---------------------------------------------------------------------------- */
|
|
1872
1936
|
.op-row { display: flex; flex-wrap: wrap; gap: 1rem; align-items: center; }
|
|
1873
1937
|
.op-stack { display: flex; flex-direction: column; gap: 1rem; }
|
|
@@ -1886,11 +1950,11 @@ html.light .op-text-accent { color: #3F6212; }
|
|
|
1886
1950
|
.op-text-sm { font-size: .8125rem; }
|
|
1887
1951
|
.op-text-xs { font-size: .6875rem; }
|
|
1888
1952
|
|
|
1889
|
-
.op-mt-1 { margin-top: .5rem; } .op-mt-2 { margin-top: 1rem; } .op-mt-3 { margin-top: 1.5rem; } .op-mt-4 { margin-top:
|
|
1890
|
-
.op-mb-1 { margin-bottom: .5rem; } .op-mb-2 { margin-bottom: 1rem; } .op-mb-3 { margin-bottom: 1.5rem; } .op-mb-4 { margin-bottom:
|
|
1953
|
+
.op-mt-1 { margin-top: .5rem; } .op-mt-2 { margin-top: 1rem; } .op-mt-3 { margin-top: 1.5rem; } .op-mt-4 { margin-top: 1.75rem; }
|
|
1954
|
+
.op-mb-1 { margin-bottom: .5rem; } .op-mb-2 { margin-bottom: 1rem; } .op-mb-3 { margin-bottom: 1.5rem; } .op-mb-4 { margin-bottom: 1.75rem; }
|
|
1891
1955
|
|
|
1892
1956
|
/* ----------------------------------------------------------------------------
|
|
1893
|
-
|
|
1957
|
+
23. ANIMAÇÕES
|
|
1894
1958
|
---------------------------------------------------------------------------- */
|
|
1895
1959
|
@keyframes op-spin { to { transform: rotate(360deg); } }
|
|
1896
1960
|
@keyframes op-bounce {
|
package/ui-optago.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/* ============================================================================
|
|
2
|
-
UI ÓPTAGO — Design System v1.0.
|
|
2
|
+
UI ÓPTAGO — Design System v1.0.3 (JavaScript)
|
|
3
3
|
Sem dependências de build. Carregue no <head> SEM defer para evitar
|
|
4
4
|
flash de tema errado (FOUC):
|
|
5
5
|
|
|
@@ -21,9 +21,13 @@
|
|
|
21
21
|
data-op-dismiss → remove o elemento pai .op-alert
|
|
22
22
|
data-op-copy="#seletor" → copia o HTML do elemento alvo
|
|
23
23
|
data-op-code="#seletor" → mostra/esconde o código-fonte do alvo
|
|
24
|
+
data-op-loading-form → no <form>: mostra a tela de carregamento
|
|
25
|
+
sozinho ao submeter (mensagem opcional em
|
|
26
|
+
data-op-loading-message="Enviando...")
|
|
24
27
|
|
|
25
28
|
API global: OptagoUI.toast(msg, tipo, ms) · OptagoUI.openModal(sel)
|
|
26
29
|
OptagoUI.closeModal(sel) · OptagoUI.setTheme('dark'|'light')
|
|
30
|
+
OptagoUI.showLoading(msg) · OptagoUI.hideLoading()
|
|
27
31
|
============================================================================ */
|
|
28
32
|
(function () {
|
|
29
33
|
'use strict';
|
|
@@ -241,6 +245,53 @@
|
|
|
241
245
|
});
|
|
242
246
|
};
|
|
243
247
|
|
|
248
|
+
/* --------------------------------------------------------------------------
|
|
249
|
+
5c. TELA DE CARREGAMENTO — overlay em tela cheia
|
|
250
|
+
Uso: OptagoUI.showLoading('Salvando...') ... OptagoUI.hideLoading()
|
|
251
|
+
ou data-op-loading-form no <form> para acionar sozinho no submit.
|
|
252
|
+
-------------------------------------------------------------------------- */
|
|
253
|
+
var LOADING_ID = 'opLoadingOverlay';
|
|
254
|
+
|
|
255
|
+
function getLoadingOverlay() {
|
|
256
|
+
var ov = document.getElementById(LOADING_ID);
|
|
257
|
+
if (!ov) {
|
|
258
|
+
ov = document.createElement('div');
|
|
259
|
+
ov.id = LOADING_ID;
|
|
260
|
+
ov.className = 'op-loading-overlay';
|
|
261
|
+
ov.setAttribute('role', 'alert');
|
|
262
|
+
ov.setAttribute('aria-live', 'assertive');
|
|
263
|
+
ov.innerHTML =
|
|
264
|
+
'<span class="op-spinner"></span>' +
|
|
265
|
+
'<span class="op-loading-message"></span>';
|
|
266
|
+
document.body.appendChild(ov);
|
|
267
|
+
}
|
|
268
|
+
return ov;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
OptagoUI.showLoading = function (message) {
|
|
272
|
+
var ov = getLoadingOverlay();
|
|
273
|
+
ov.querySelector('.op-loading-message').textContent = message || 'Carregando...';
|
|
274
|
+
ov.classList.add('is-open');
|
|
275
|
+
requestAnimationFrame(function () {
|
|
276
|
+
requestAnimationFrame(function () { ov.classList.add('is-visible'); });
|
|
277
|
+
});
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
OptagoUI.hideLoading = function () {
|
|
281
|
+
var ov = document.getElementById(LOADING_ID);
|
|
282
|
+
if (!ov) return;
|
|
283
|
+
ov.classList.remove('is-visible');
|
|
284
|
+
setTimeout(function () { ov.classList.remove('is-open'); }, 250);
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
// Ao voltar pelo botão "Voltar" do navegador, a página pode ser restaurada
|
|
288
|
+
// do bfcache exatamente como estava ao sair (overlay de carregamento ainda
|
|
289
|
+
// visível, já que o clique/submit anterior nunca chegou a escondê-lo).
|
|
290
|
+
// pageshow com event.persisted=true é o sinal de que veio do bfcache.
|
|
291
|
+
window.addEventListener('pageshow', function (e) {
|
|
292
|
+
if (e.persisted) OptagoUI.hideLoading();
|
|
293
|
+
});
|
|
294
|
+
|
|
244
295
|
/* --------------------------------------------------------------------------
|
|
245
296
|
6. HELPERS DO SHOWCASE — copiar HTML / ver código
|
|
246
297
|
-------------------------------------------------------------------------- */
|
|
@@ -379,6 +430,22 @@
|
|
|
379
430
|
// Ver código
|
|
380
431
|
t = e.target.closest('[data-op-code]');
|
|
381
432
|
if (t) { OptagoUI.toggleCode(t.getAttribute('data-op-code'), t); return; }
|
|
433
|
+
|
|
434
|
+
// Mostrar/ocultar senha: [data-op-reveal] envolvendo o input,
|
|
435
|
+
// com um <button data-op-reveal-toggle> dentro.
|
|
436
|
+
t = e.target.closest('[data-op-reveal-toggle]');
|
|
437
|
+
if (t) {
|
|
438
|
+
var wrap = t.closest('[data-op-reveal]');
|
|
439
|
+
var input = wrap ? wrap.querySelector('input') : null;
|
|
440
|
+
if (input) {
|
|
441
|
+
var show = input.type === 'password';
|
|
442
|
+
input.type = show ? 'text' : 'password';
|
|
443
|
+
var icon = t.querySelector('i');
|
|
444
|
+
if (icon) icon.className = show ? 'ph ph-eye-slash' : 'ph ph-eye';
|
|
445
|
+
t.setAttribute('aria-label', show ? 'Ocultar senha' : 'Mostrar senha');
|
|
446
|
+
}
|
|
447
|
+
return;
|
|
448
|
+
}
|
|
382
449
|
});
|
|
383
450
|
|
|
384
451
|
// Tooltip da sidebar colapsada: o overflow-y da nav cortaria um tooltip
|
|
@@ -395,6 +462,14 @@
|
|
|
395
462
|
tip.style.left = 'auto';
|
|
396
463
|
});
|
|
397
464
|
|
|
465
|
+
// Formulário com data-op-loading-form: mostra a tela de carregamento
|
|
466
|
+
// sozinho ao submeter (mensagem em data-op-loading-message, se houver).
|
|
467
|
+
document.addEventListener('submit', function (e) {
|
|
468
|
+
var form = e.target.closest('[data-op-loading-form]');
|
|
469
|
+
if (!form) return;
|
|
470
|
+
OptagoUI.showLoading(form.getAttribute('data-op-loading-message'));
|
|
471
|
+
});
|
|
472
|
+
|
|
398
473
|
// ESC fecha modais e dropdowns
|
|
399
474
|
document.addEventListener('keydown', function (e) {
|
|
400
475
|
if (e.key !== 'Escape') return;
|