@yakuzaa/jade 0.1.11 → 0.1.12

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.
Files changed (2) hide show
  1. package/commands/html.js +123 -51
  2. package/package.json +1 -1
package/commands/html.js CHANGED
@@ -90,36 +90,36 @@ function gerarCSS(tema = {}) {
90
90
  ${gerarVariaveisCSS(tema)}
91
91
  }
92
92
 
93
- body {
93
+ html, body {
94
+ height: 100%;
94
95
  font-family: var(--jade-fonte);
95
96
  background: var(--jade-cor-fundo);
96
97
  color: var(--jade-cor-texto);
97
- min-height: 100dvh;
98
98
  }
99
99
 
100
- /* Layout principal */
100
+ /* Layout principal — ocupa toda a tela, sem rolar o body */
101
101
  #jade-app {
102
102
  display: flex;
103
- min-height: 100dvh;
103
+ height: 100dvh;
104
+ overflow: hidden;
104
105
  }
105
106
 
106
- /* Nav lateral */
107
+ /* Nav lateral (desktop sempre visível) */
107
108
  #jade-nav {
108
109
  width: 240px;
109
- min-height: 100dvh;
110
+ height: 100%;
110
111
  background: var(--jade-cor-fundo-nav);
111
112
  display: flex;
112
113
  flex-direction: column;
113
114
  flex-shrink: 0;
114
- position: sticky;
115
- top: 0;
116
- height: 100dvh;
117
115
  overflow-y: auto;
116
+ z-index: 10;
118
117
  }
119
118
 
120
119
  #jade-nav-header {
121
120
  padding: 20px 16px 12px;
122
121
  border-bottom: 1px solid rgba(255,255,255,0.08);
122
+ flex-shrink: 0;
123
123
  }
124
124
 
125
125
  #jade-nav-titulo {
@@ -138,10 +138,11 @@ function gerarCSS(tema = {}) {
138
138
 
139
139
  #jade-nav-lista {
140
140
  flex: 1;
141
- padding: 8px 8px;
141
+ padding: 8px;
142
142
  display: flex;
143
143
  flex-direction: column;
144
144
  gap: 2px;
145
+ overflow-y: auto;
145
146
  }
146
147
 
147
148
  .jade-nav-item {
@@ -159,6 +160,7 @@ function gerarCSS(tema = {}) {
159
160
  cursor: pointer;
160
161
  text-align: left;
161
162
  transition: background 0.15s, color 0.15s;
163
+ flex-shrink: 0;
162
164
  }
163
165
 
164
166
  .jade-nav-item:hover {
@@ -173,6 +175,51 @@ function gerarCSS(tema = {}) {
173
175
 
174
176
  .jade-nav-icone { display: flex; align-items: center; }
175
177
 
178
+ /* Área de conteúdo — rola de forma independente */
179
+ #jade-conteudo {
180
+ flex: 1;
181
+ min-width: 0;
182
+ height: 100%;
183
+ padding: 24px;
184
+ overflow-y: auto;
185
+ overflow-x: hidden;
186
+ }
187
+
188
+ /* Overlay escuro para o drawer no mobile */
189
+ #jade-overlay {
190
+ display: none;
191
+ position: fixed;
192
+ inset: 0;
193
+ background: rgba(0,0,0,0.45);
194
+ z-index: 199;
195
+ opacity: 0;
196
+ transition: opacity 0.25s;
197
+ }
198
+ #jade-overlay.visivel {
199
+ display: block;
200
+ opacity: 1;
201
+ }
202
+
203
+ /* Botão hambúrguer — só aparece no mobile */
204
+ #jade-hamburger {
205
+ display: none;
206
+ position: fixed;
207
+ top: 12px;
208
+ left: 12px;
209
+ z-index: 198;
210
+ width: 40px;
211
+ height: 40px;
212
+ border: none;
213
+ border-radius: var(--jade-raio);
214
+ background: var(--jade-cor-fundo-nav);
215
+ color: #fff;
216
+ cursor: pointer;
217
+ align-items: center;
218
+ justify-content: center;
219
+ box-shadow: 0 2px 8px rgba(0,0,0,0.25);
220
+ flex-shrink: 0;
221
+ }
222
+
176
223
  /* Toolbar */
177
224
  .jade-toolbar {
178
225
  display: flex;
@@ -186,6 +233,7 @@ function gerarCSS(tema = {}) {
186
233
  .jade-busca-form { display: flex; gap: 0; }
187
234
  .jade-busca-input {
188
235
  flex: 1;
236
+ min-width: 0;
189
237
  min-height: 44px;
190
238
  padding: 10px 14px;
191
239
  border: 1.5px solid var(--jade-cor-borda);
@@ -232,20 +280,12 @@ function gerarCSS(tema = {}) {
232
280
  letter-spacing: 0.05em;
233
281
  }
234
282
 
235
- /* Área de conteúdo */
236
- #jade-conteudo {
237
- flex: 1;
238
- min-width: 0;
239
- padding: 24px;
240
- overflow-y: auto;
241
- }
242
-
243
283
  /* Carregando */
244
284
  #jade-carregando {
245
285
  display: flex;
246
286
  align-items: center;
247
287
  justify-content: center;
248
- min-height: 100dvh;
288
+ height: 100dvh;
249
289
  color: var(--jade-cor-texto-muted);
250
290
  font-size: 0.9rem;
251
291
  gap: 10px;
@@ -261,41 +301,29 @@ function gerarCSS(tema = {}) {
261
301
 
262
302
  @keyframes jade-giro { to { transform: rotate(360deg); } }
263
303
 
264
- /* Mobile: nav vira barra inferior */
265
- @media (max-width: 640px) {
266
- #jade-app { flex-direction: column-reverse; }
304
+ /* Mobile: hamburger + drawer overlay */
305
+ @media (max-width: 768px) {
306
+ #jade-hamburger { display: flex; }
267
307
 
268
308
  #jade-nav {
269
- width: 100%;
270
- min-height: auto;
271
- height: auto;
272
- position: sticky;
273
- bottom: 0;
274
- top: auto;
275
- border-top: 1px solid rgba(255,255,255,0.1);
309
+ position: fixed;
310
+ top: 0;
311
+ left: 0;
312
+ height: 100dvh;
313
+ z-index: 200;
314
+ transform: translateX(-100%);
315
+ transition: transform 0.25s ease;
316
+ box-shadow: 4px 0 16px rgba(0,0,0,0.3);
276
317
  }
277
318
 
278
- #jade-nav-header { display: none; }
279
-
280
- #jade-nav-lista {
281
- flex-direction: row;
282
- overflow-x: auto;
283
- padding: 6px 8px;
284
- gap: 4px;
319
+ #jade-nav.jade-nav-aberto {
320
+ transform: translateX(0);
285
321
  }
286
322
 
287
- .jade-nav-item {
288
- flex-direction: column;
289
- gap: 2px;
290
- padding: 6px 12px;
291
- font-size: 0.7rem;
292
- white-space: nowrap;
293
- flex-shrink: 0;
323
+ #jade-conteudo {
324
+ padding: 16px;
325
+ padding-top: 64px;
294
326
  }
295
-
296
- .jade-nav-icone { font-size: 1.2rem; }
297
-
298
- #jade-conteudo { padding: 16px; }
299
327
  }
300
328
  `.trim();
301
329
  }
@@ -402,6 +430,40 @@ async function iniciar() {
402
430
  document.getElementById('jade-carregando')?.remove();
403
431
  document.getElementById('jade-app').style.display = '';
404
432
 
433
+ // ── Hamburger (mobile) ──────────────────────────────────────────────────────
434
+ const hamburger = document.getElementById('jade-hamburger');
435
+ const overlay = document.getElementById('jade-overlay');
436
+ const navEl = document.getElementById('jade-nav');
437
+
438
+ // Mostra o botão (estava display:none para não piscar antes do app carregar)
439
+ hamburger.style.display = '';
440
+
441
+ const iconeMenu = criarElementoIcone('menu', 22);
442
+ const iconeFechar = criarElementoIcone('fechar', 22);
443
+ if (iconeMenu) hamburger.appendChild(iconeMenu);
444
+
445
+ function abrirDrawer() {
446
+ navEl.classList.add('jade-nav-aberto');
447
+ overlay.classList.add('visivel');
448
+ hamburger.setAttribute('aria-expanded', 'true');
449
+ if (iconeMenu && iconeFechar) {
450
+ hamburger.replaceChild(iconeFechar, hamburger.firstChild);
451
+ }
452
+ }
453
+ function fecharDrawer() {
454
+ navEl.classList.remove('jade-nav-aberto');
455
+ overlay.classList.remove('visivel');
456
+ hamburger.setAttribute('aria-expanded', 'false');
457
+ if (iconeMenu && hamburger.firstChild !== iconeMenu) {
458
+ hamburger.replaceChild(iconeMenu, hamburger.firstChild);
459
+ }
460
+ }
461
+
462
+ hamburger.addEventListener('click', () =>
463
+ navEl.classList.contains('jade-nav-aberto') ? fecharDrawer() : abrirDrawer()
464
+ );
465
+ overlay.addEventListener('click', fecharDrawer);
466
+
405
467
  if (telas.length === 0) {
406
468
  document.getElementById('jade-conteudo').innerHTML =
407
469
  '<p style="color:var(--jade-cor-texto-muted);padding:2rem">Nenhuma tela declarada.</p>';
@@ -417,6 +479,7 @@ async function iniciar() {
417
479
  const btn = document.createElement('button');
418
480
  btn.className = 'jade-nav-item' + (i === 0 ? ' jade-nav-ativo' : '');
419
481
  btn.dataset.tela = tela.nome;
482
+ btn.setAttribute('role', 'listitem');
420
483
 
421
484
  const svgIcone = criarElementoIcone(nomeIcone(tela.nome), 18);
422
485
  const spanIcone = document.createElement('span');
@@ -428,7 +491,10 @@ async function iniciar() {
428
491
  spanLabel.textContent = tela.titulo || tela.nome;
429
492
  btn.appendChild(spanLabel);
430
493
 
431
- btn.addEventListener('click', () => mudarTela(tela.nome, telas, db, ui, navItems));
494
+ btn.addEventListener('click', () => {
495
+ mudarTela(tela.nome, telas, db, ui, navItems);
496
+ fecharDrawer(); // fecha o drawer no mobile após navegar
497
+ });
432
498
  nav.appendChild(btn);
433
499
  navItems.push(btn);
434
500
  });
@@ -436,7 +502,10 @@ async function iniciar() {
436
502
  // Handler: jade:navegar — gaveta e navegar disparam este evento
437
503
  window.addEventListener('jade:navegar', (e) => {
438
504
  const nomeTela = e.detail?.tela;
439
- if (nomeTela) mudarTela(nomeTela, telas, db, ui, navItems);
505
+ if (nomeTela) {
506
+ mudarTela(nomeTela, telas, db, ui, navItems);
507
+ fecharDrawer();
508
+ }
440
509
  });
441
510
 
442
511
  // Handler: jade:acao — dispara jade:acao:concluido após processar
@@ -496,13 +565,16 @@ ${gerarCSS(tema)}
496
565
  Carregando...
497
566
  </div>
498
567
 
568
+ <button id="jade-hamburger" aria-label="Abrir menu" aria-expanded="false" style="display:none"></button>
569
+ <div id="jade-overlay" role="presentation"></div>
570
+
499
571
  <div id="jade-app" style="display:none">
500
- <nav id="jade-nav">
572
+ <nav id="jade-nav" aria-label="Menu de navegação">
501
573
  <div id="jade-nav-header">
502
574
  <div id="jade-nav-titulo">${nome}</div>
503
575
  <div id="jade-nav-versao">feito com Jade DSL</div>
504
576
  </div>
505
- <div id="jade-nav-lista"></div>
577
+ <div id="jade-nav-lista" role="list"></div>
506
578
  </nav>
507
579
  <main id="jade-conteudo"></main>
508
580
  </div>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@yakuzaa/jade",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "Jade DSL — linguagem empresarial em português compilada para WebAssembly. Instala compilador + runtime + CLI.",
5
5
  "type": "module",
6
6
  "bin": {