mkfashion-sdk 1.0.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.
@@ -0,0 +1,15 @@
1
+ {
2
+ // Use IntelliSense to learn about possible attributes.
3
+ // Hover to view descriptions of existing attributes.
4
+ // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
+ "version": "0.2.0",
6
+ "configurations": [
7
+ {
8
+ "type": "chrome",
9
+ "request": "launch",
10
+ "name": "Launch Chrome against localhost",
11
+ "url": "http://localhost:8080",
12
+ "webRoot": "${workspaceFolder}"
13
+ }
14
+ ]
15
+ }
package/README.md ADDED
@@ -0,0 +1,62 @@
1
+ # mKFashion SDK
2
+
3
+ SDK para integrar o provador virtual de roupas com IA em qualquer site ou e-commerce.
4
+
5
+ ## Instalação
6
+
7
+ ```html
8
+ <script src="https://unpkg.com/mkfashion-sdk/src/mkfashion.js"></script>
9
+ ```
10
+
11
+ ## Uso Rápido
12
+
13
+ ```javascript
14
+ // 1. Registrar callback do carrinho
15
+ mkfashion.addToCart(function(payload) {
16
+ console.log("Produto:", payload.identifier);
17
+ console.log("Tamanho:", payload.size);
18
+ });
19
+
20
+ // 2. Abrir o provador
21
+ mkfashion.open({
22
+ type: 'iframe',
23
+ projectid: 'minha-loja',
24
+ identifier: 'PRODUTO-001',
25
+ width: 400,
26
+ height: 700
27
+ });
28
+ ```
29
+
30
+ ## Documentação
31
+
32
+ - [Introdução](./docs/index.md)
33
+ - [Instalação do Plugin](./docs/instalacao.md)
34
+ - [Abrir o Visualizador](./docs/abrir-visualizador.md)
35
+ - [Integração com Carrinho](./docs/integracao-carrinho.md)
36
+ - [SDK Reference](./docs/sdk-reference.md)
37
+
38
+ ## Métodos Disponíveis
39
+
40
+ | Método | Descrição |
41
+ |--------|-----------|
42
+ | `open(options)` | Abre o provador virtual |
43
+ | `close()` | Fecha o provador |
44
+ | `restart()` | Reinicia a experiência |
45
+ | `destroy()` | Remove do DOM |
46
+ | `getStatus()` | Retorna estado atual |
47
+ | `addToCart(callback)` | Callback ao adicionar ao carrinho |
48
+ | `onReady(callback)` | Callback quando pronto |
49
+ | `onClose(callback)` | Callback ao fechar |
50
+ | `onGenerationComplete(callback)` | Callback ao gerar imagem |
51
+ | `onError(callback)` | Callback de erro |
52
+
53
+ ## Desenvolvimento
54
+
55
+ ```bash
56
+ # Testar localmente
57
+ # Abra test.html no navegador
58
+ ```
59
+
60
+ ## Licença
61
+
62
+ MIT - metaKosmos
package/package.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "name": "mkfashion-sdk",
3
+ "version": "1.0.0",
4
+ "description": "SDK para integrar o provador virtual mKFashion",
5
+ "main": "src/mkfashion.js",
6
+ "type": "module",
7
+ "scripts": {
8
+ "test": "echo \"Abra test.html no navegador\""
9
+ },
10
+ "keywords": [
11
+ "fashion",
12
+ "virtual",
13
+ "try-on",
14
+ "sdk",
15
+ "metakosmos"
16
+ ],
17
+ "author": "metaKosmos",
18
+ "license": "MIT"
19
+ }
@@ -0,0 +1,437 @@
1
+ /**
2
+ * mKFashion SDK
3
+ * SDK para integrar o provador virtual mKFashion em qualquer site
4
+ *
5
+ * Instalacao:
6
+ * <script src="https://unpkg.com/mkfashion-sdk/src/mkfashion.js"></script>
7
+ *
8
+ * Uso:
9
+ * mkfashion.open({
10
+ * type: 'iframe',
11
+ * projectid: 'gregory',
12
+ * identifier: 'SKU-001',
13
+ * width: 400,
14
+ * height: 700
15
+ * })
16
+ *
17
+ * mkfashion.addToCart(function(payload) {
18
+ * console.log('Produto adicionado:', payload)
19
+ * })
20
+ */
21
+
22
+ const mkfashion = {
23
+
24
+ // ============ CONFIGURACAO ============
25
+
26
+ appUrl: 'https://fashion.metakosmos.com/',
27
+ debug: false,
28
+
29
+ // Estado interno
30
+ _iframe: null,
31
+ _modal: null,
32
+ _isOpen: false,
33
+ _config: null,
34
+ _callbacks: {
35
+ onReady: null,
36
+ onClose: null,
37
+ onAddToCart: null,
38
+ onGenerationComplete: null,
39
+ onError: null
40
+ },
41
+ _escHandler: null,
42
+ _messageHandler: null,
43
+
44
+ // ============ METODOS PUBLICOS ============
45
+
46
+ /**
47
+ * Abre o provador virtual
48
+ * @param {Object} options - Configuracoes
49
+ * @param {string} options.type - 'iframe' (modal) ou 'embed' (default: 'iframe')
50
+ * @param {string} options.projectid - Identificador do projeto/empresa (obrigatorio)
51
+ * @param {string} options.identifier - SKU ou ID do produto (obrigatorio)
52
+ * @param {string|number} options.width - Largura (ex: 800 ou '90%')
53
+ * @param {string|number} options.height - Altura (ex: 600 ou '95%')
54
+ * @param {string} options.targetId - ID do container (obrigatorio para type='embed')
55
+ */
56
+ open(options = {}) {
57
+ if (this._isOpen) {
58
+ this._log('Ja esta aberto')
59
+ return
60
+ }
61
+
62
+ // Valida opcoes obrigatorias
63
+ if (!options.projectid) {
64
+ console.error('[mKFashion] projectid e obrigatorio')
65
+ return
66
+ }
67
+ if (!options.identifier) {
68
+ console.error('[mKFashion] identifier e obrigatorio')
69
+ return
70
+ }
71
+
72
+ // Salva configuracao
73
+ this._config = {
74
+ type: options.type || 'iframe',
75
+ projectid: options.projectid,
76
+ identifier: options.identifier,
77
+ width: options.width || '90%',
78
+ height: options.height || '95%',
79
+ targetId: options.targetId || null
80
+ }
81
+
82
+ // Inicia listener de mensagens
83
+ this._setupMessageListener()
84
+
85
+ // Abre de acordo com o tipo
86
+ if (this._config.type === 'iframe') {
87
+ this._openModal()
88
+ } else if (this._config.type === 'embed') {
89
+ this._openEmbed()
90
+ }
91
+
92
+ this._isOpen = true
93
+ this._log('Aberto', this._config)
94
+ },
95
+
96
+ /**
97
+ * Fecha o provador virtual
98
+ */
99
+ close() {
100
+ if (!this._isOpen) {
101
+ this._log('Ja esta fechado')
102
+ return
103
+ }
104
+
105
+ // Remove listener de mensagens
106
+ this._removeMessageListener()
107
+
108
+ if (this._config.type === 'iframe') {
109
+ this._closeModal()
110
+ } else if (this._config.type === 'embed') {
111
+ this._closeEmbed()
112
+ }
113
+
114
+ // Dispara callback de fechamento
115
+ this._triggerCallback('onClose')
116
+
117
+ this._isOpen = false
118
+ this._log('Fechado')
119
+ },
120
+
121
+ /**
122
+ * Registra callback para quando usuario adicionar ao carrinho
123
+ * @param {Function} callback - Funcao que recebe o payload do produto
124
+ */
125
+ addToCart(callback) {
126
+ if (typeof callback === 'function') {
127
+ this._callbacks.onAddToCart = callback
128
+ this._log('Callback addToCart registrado')
129
+ } else {
130
+ console.error('[mKFashion] addToCart requer uma funcao como parametro')
131
+ }
132
+ },
133
+
134
+ /**
135
+ * Registra callback para quando app estiver pronta
136
+ * @param {Function} callback - Funcao chamada quando app carregar
137
+ */
138
+ onReady(callback) {
139
+ if (typeof callback === 'function') {
140
+ this._callbacks.onReady = callback
141
+ this._log('Callback onReady registrado')
142
+ }
143
+ },
144
+
145
+ /**
146
+ * Registra callback para quando modal fechar
147
+ * @param {Function} callback - Funcao chamada ao fechar
148
+ */
149
+ onClose(callback) {
150
+ if (typeof callback === 'function') {
151
+ this._callbacks.onClose = callback
152
+ this._log('Callback onClose registrado')
153
+ }
154
+ },
155
+
156
+ /**
157
+ * Registra callback para quando geracao completar
158
+ * @param {Function} callback - Funcao que recebe dados da geracao
159
+ */
160
+ onGenerationComplete(callback) {
161
+ if (typeof callback === 'function') {
162
+ this._callbacks.onGenerationComplete = callback
163
+ this._log('Callback onGenerationComplete registrado')
164
+ }
165
+ },
166
+
167
+ /**
168
+ * Registra callback para erros
169
+ * @param {Function} callback - Funcao que recebe dados do erro
170
+ */
171
+ onError(callback) {
172
+ if (typeof callback === 'function') {
173
+ this._callbacks.onError = callback
174
+ this._log('Callback onError registrado')
175
+ }
176
+ },
177
+
178
+ /**
179
+ * Reinicia a experiencia (volta para tela de instrucoes)
180
+ */
181
+ restart() {
182
+ if (!this._iframe || !this._config) {
183
+ this._log('Nenhum iframe ativo')
184
+ return
185
+ }
186
+
187
+ this._iframe.src = this._buildUrl()
188
+ this._log('Reiniciado')
189
+ },
190
+
191
+ /**
192
+ * Remove completamente do DOM
193
+ */
194
+ destroy() {
195
+ this.close()
196
+ this._iframe = null
197
+ this._modal = null
198
+ this._config = null
199
+ this._callbacks = {
200
+ onReady: null,
201
+ onClose: null,
202
+ onAddToCart: null,
203
+ onGenerationComplete: null,
204
+ onError: null
205
+ }
206
+ this._log('Destruido')
207
+ },
208
+
209
+ /**
210
+ * Retorna o estado atual
211
+ */
212
+ getStatus() {
213
+ return {
214
+ isOpen: this._isOpen,
215
+ config: this._config
216
+ }
217
+ },
218
+
219
+ // ============ METODOS PRIVADOS ============
220
+
221
+ _log(message, data = null) {
222
+ if (this.debug) {
223
+ if (data) {
224
+ console.log(`[mKFashion] ${message}`, data)
225
+ } else {
226
+ console.log(`[mKFashion] ${message}`)
227
+ }
228
+ }
229
+ },
230
+
231
+ _triggerCallback(name, data = null) {
232
+ if (this._callbacks && typeof this._callbacks[name] === 'function') {
233
+ try {
234
+ this._callbacks[name](data)
235
+ this._log(`Callback ${name} executado`, data)
236
+ } catch (error) {
237
+ console.error(`[mKFashion] Erro no callback ${name}:`, error)
238
+ }
239
+ }
240
+ },
241
+
242
+ _buildUrl() {
243
+ const url = new URL(this.appUrl)
244
+ url.searchParams.set('company', this._config.projectid)
245
+ url.searchParams.set('sku', this._config.identifier)
246
+ url.searchParams.set('sdk', 'true')
247
+ return url.toString()
248
+ },
249
+
250
+ _openModal() {
251
+ // Cria o fundo escuro
252
+ this._modal = document.createElement('div')
253
+ this._modal.style.cssText = `
254
+ position: fixed;
255
+ top: 0;
256
+ left: 0;
257
+ width: 100%;
258
+ height: 100%;
259
+ background: rgba(0, 0, 0, 0.8);
260
+ display: flex;
261
+ align-items: center;
262
+ justify-content: center;
263
+ z-index: 99999;
264
+ opacity: 0;
265
+ transition: opacity 0.3s ease;
266
+ `
267
+
268
+ // Cria o iframe
269
+ this._iframe = this._createIframe()
270
+ this._iframe.style.cssText += `
271
+ border-radius: 12px;
272
+ transform: scale(0.95);
273
+ transition: transform 0.3s ease;
274
+ `
275
+
276
+ // Adiciona ao modal
277
+ this._modal.appendChild(this._iframe)
278
+ document.body.appendChild(this._modal)
279
+
280
+ // Anima a entrada
281
+ requestAnimationFrame(() => {
282
+ this._modal.style.opacity = '1'
283
+ this._iframe.style.transform = 'scale(1)'
284
+ })
285
+
286
+ // Fecha ao clicar fora
287
+ this._modal.addEventListener('click', (e) => {
288
+ if (e.target === this._modal) {
289
+ this.close()
290
+ }
291
+ })
292
+
293
+ // Fecha com ESC
294
+ this._escHandler = (e) => {
295
+ if (e.key === 'Escape') {
296
+ this.close()
297
+ }
298
+ }
299
+ document.addEventListener('keydown', this._escHandler)
300
+ },
301
+
302
+ _closeModal() {
303
+ if (!this._modal) return
304
+
305
+ // Anima a saida
306
+ this._modal.style.opacity = '0'
307
+ this._iframe.style.transform = 'scale(0.95)'
308
+
309
+ // Remove apos animacao
310
+ setTimeout(() => {
311
+ if (this._modal && this._modal.parentNode) {
312
+ this._modal.parentNode.removeChild(this._modal)
313
+ }
314
+ this._modal = null
315
+ this._iframe = null
316
+ }, 300)
317
+
318
+ // Remove listener do ESC
319
+ if (this._escHandler) {
320
+ document.removeEventListener('keydown', this._escHandler)
321
+ }
322
+ },
323
+
324
+ _openEmbed() {
325
+ const targetId = this._config.targetId
326
+ if (!targetId) {
327
+ console.error('[mKFashion] targetId e obrigatorio para type="embed"')
328
+ return
329
+ }
330
+
331
+ const container = document.getElementById(targetId)
332
+ if (!container) {
333
+ console.error(`[mKFashion] Elemento #${targetId} nao encontrado`)
334
+ return
335
+ }
336
+
337
+ this._iframe = this._createIframe()
338
+ this._iframe.style.cssText += `
339
+ border-radius: 12px;
340
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15);
341
+ `
342
+
343
+ container.innerHTML = ''
344
+ container.appendChild(this._iframe)
345
+ },
346
+
347
+ _closeEmbed() {
348
+ if (!this._config.targetId) return
349
+
350
+ const container = document.getElementById(this._config.targetId)
351
+ if (container) {
352
+ container.innerHTML = ''
353
+ }
354
+
355
+ this._iframe = null
356
+ },
357
+
358
+ _createIframe() {
359
+ const { width, height } = this._config
360
+ const iframe = document.createElement('iframe')
361
+ iframe.src = this._buildUrl()
362
+ iframe.style.width = typeof width === 'number' ? `${width}px` : width
363
+ iframe.style.height = typeof height === 'number' ? `${height}px` : height
364
+ iframe.style.border = 'none'
365
+ iframe.setAttribute('allow', 'camera; microphone')
366
+ iframe.setAttribute('allowfullscreen', 'true')
367
+ return iframe
368
+ },
369
+
370
+ // Configura listener para mensagens do iframe
371
+ _setupMessageListener() {
372
+ this._messageHandler = (event) => {
373
+ // Ignora mensagens que nao sao da app
374
+ if (!event.data || event.data.source !== 'mkfashion-app') {
375
+ return
376
+ }
377
+
378
+ const { action, data } = event.data
379
+ this._log('Mensagem recebida:', action, data)
380
+
381
+ // Trata as acoes
382
+ switch (action) {
383
+ case 'close_request':
384
+ this.close()
385
+ break
386
+
387
+ case 'restart_request':
388
+ this.restart()
389
+ break
390
+
391
+ case 'ready':
392
+ this._log('App pronta', data)
393
+ this._triggerCallback('onReady', data)
394
+ break
395
+
396
+ case 'add_to_cart':
397
+ this._log('Adicionar ao carrinho', data)
398
+ this._triggerCallback('onAddToCart', {
399
+ identifier: this._config.identifier,
400
+ size: data?.size || null,
401
+ ...data
402
+ })
403
+ break
404
+
405
+ case 'generation_complete':
406
+ this._log('Geracao completa', data)
407
+ this._triggerCallback('onGenerationComplete', data)
408
+ break
409
+
410
+ case 'generation_error':
411
+ this._log('Erro na geracao', data)
412
+ this._triggerCallback('onError', data)
413
+ break
414
+
415
+ default:
416
+ this._log('Acao desconhecida:', action)
417
+ }
418
+ }
419
+
420
+ window.addEventListener('message', this._messageHandler)
421
+ this._log('Listener de mensagens ativado')
422
+ },
423
+
424
+ // Remove listener de mensagens
425
+ _removeMessageListener() {
426
+ if (this._messageHandler) {
427
+ window.removeEventListener('message', this._messageHandler)
428
+ this._messageHandler = null
429
+ this._log('Listener de mensagens removido')
430
+ }
431
+ }
432
+ }
433
+
434
+ // Disponibiliza globalmente
435
+ if (typeof window !== 'undefined') {
436
+ window.mkfashion = mkfashion
437
+ }
package/test.html ADDED
@@ -0,0 +1,235 @@
1
+ <!DOCTYPE html>
2
+ <html lang="pt-BR">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>Teste - mKFashion SDK</title>
8
+ <style>
9
+ * {
10
+ box-sizing: border-box;
11
+ margin: 0;
12
+ padding: 0;
13
+ }
14
+
15
+ body {
16
+ font-family: Arial, sans-serif;
17
+ padding: 40px;
18
+ background: #f5f5f5;
19
+ }
20
+
21
+ h1 {
22
+ margin-bottom: 10px;
23
+ color: #333;
24
+ }
25
+
26
+ p {
27
+ color: #666;
28
+ margin-bottom: 30px;
29
+ }
30
+
31
+ .buttons {
32
+ display: flex;
33
+ gap: 10px;
34
+ flex-wrap: wrap;
35
+ margin-bottom: 30px;
36
+ }
37
+
38
+ button {
39
+ padding: 12px 24px;
40
+ font-size: 16px;
41
+ border: none;
42
+ border-radius: 8px;
43
+ cursor: pointer;
44
+ transition: transform 0.2s;
45
+ }
46
+
47
+ button:hover {
48
+ transform: scale(1.05);
49
+ }
50
+
51
+ .btn-primary {
52
+ background: #4F46E5;
53
+ color: white;
54
+ }
55
+
56
+ .btn-secondary {
57
+ background: #6B7280;
58
+ color: white;
59
+ }
60
+
61
+ .code-box {
62
+ margin-top: 20px;
63
+ padding: 20px;
64
+ background: #1e1e1e;
65
+ border-radius: 8px;
66
+ color: #d4d4d4;
67
+ font-family: monospace;
68
+ font-size: 14px;
69
+ overflow-x: auto;
70
+ }
71
+
72
+ .code-box .comment {
73
+ color: #6a9955;
74
+ }
75
+
76
+ .code-box .string {
77
+ color: #ce9178;
78
+ }
79
+
80
+ .code-box .keyword {
81
+ color: #569cd6;
82
+ }
83
+
84
+ .code-box .function {
85
+ color: #dcdcaa;
86
+ }
87
+
88
+ .events-log {
89
+ margin-top: 30px;
90
+ padding: 20px;
91
+ background: white;
92
+ border-radius: 8px;
93
+ border: 1px solid #e5e5e5;
94
+ }
95
+
96
+ .events-log h3 {
97
+ margin-bottom: 15px;
98
+ color: #333;
99
+ }
100
+
101
+ .events-log ul {
102
+ list-style: none;
103
+ max-height: 200px;
104
+ overflow-y: auto;
105
+ }
106
+
107
+ .events-log li {
108
+ padding: 8px 12px;
109
+ margin-bottom: 5px;
110
+ background: #f9f9f9;
111
+ border-radius: 4px;
112
+ font-family: monospace;
113
+ font-size: 13px;
114
+ }
115
+
116
+ .events-log li.ready {
117
+ border-left: 3px solid #22c55e;
118
+ }
119
+
120
+ .events-log li.close {
121
+ border-left: 3px solid #ef4444;
122
+ }
123
+
124
+ .events-log li.cart {
125
+ border-left: 3px solid #3b82f6;
126
+ }
127
+
128
+ .events-log li.generation {
129
+ border-left: 3px solid #a855f7;
130
+ }
131
+ </style>
132
+ </head>
133
+
134
+ <body>
135
+ <h1>mKFashion SDK - Teste</h1>
136
+ <p>Clique no botao para testar o provador virtual</p>
137
+
138
+ <div class="buttons">
139
+ <button class="btn-primary" onclick="abrirModal()">Abrir Modal</button>
140
+ <button class="btn-secondary" onclick="mkfashion.close()">Fechar</button>
141
+ <button class="btn-secondary" onclick="mkfashion.restart()">Reiniciar</button>
142
+ <button class="btn-secondary" onclick="limparLogs()">Limpar Logs</button>
143
+ </div>
144
+
145
+ <div class="code-box">
146
+ <span class="comment">// 1. Instalar via CDN</span><br>
147
+ &lt;script src=<span class="string">"https://unpkg.com/mkfashion-sdk/src/mkfashion.js"</span>&gt;&lt;/script&gt;<br><br>
148
+
149
+ <span class="comment">// 2. Registrar callback do carrinho</span><br>
150
+ mkfashion.<span class="function">addToCart</span>(<span class="keyword">function</span>(payload) {<br>
151
+ &nbsp;&nbsp;<span class="keyword">console</span>.log(<span class="string">"Produto adicionado:"</span>, payload);<br>
152
+ });<br><br>
153
+
154
+ <span class="comment">// 3. Abrir o visualizador</span><br>
155
+ mkfashion.<span class="function">open</span>({<br>
156
+ &nbsp;&nbsp;type: <span class="string">'iframe'</span>,<br>
157
+ &nbsp;&nbsp;projectid: <span class="string">'gregory'</span>,<br>
158
+ &nbsp;&nbsp;identifier: <span class="string">'VEST-001-AZUL'</span>,<br>
159
+ &nbsp;&nbsp;width: <span class="keyword">400</span>,<br>
160
+ &nbsp;&nbsp;height: <span class="keyword">700</span><br>
161
+ });
162
+ </div>
163
+
164
+ <div class="events-log">
165
+ <h3>Eventos recebidos:</h3>
166
+ <ul id="eventsList">
167
+ <li style="color: #999;">Nenhum evento ainda...</li>
168
+ </ul>
169
+ </div>
170
+
171
+ <script src="src/mkfashion.js"></script>
172
+ <script>
173
+ // Ativa logs no console
174
+ mkfashion.debug = true
175
+
176
+ // Para testar local, mude a URL
177
+ mkfashion.appUrl = 'http://localhost:5173/'
178
+
179
+ // Funcao para adicionar evento na lista
180
+ function logEvent(type, message, data = null) {
181
+ const list = document.getElementById('eventsList')
182
+
183
+ // Remove mensagem inicial
184
+ if (list.children.length === 1 && list.children[0].style.color) {
185
+ list.innerHTML = ''
186
+ }
187
+
188
+ const li = document.createElement('li')
189
+ li.className = type
190
+ const time = new Date().toLocaleTimeString()
191
+ li.textContent = `[${time}] ${message}${data ? ': ' + JSON.stringify(data) : ''}`
192
+ list.insertBefore(li, list.firstChild)
193
+ }
194
+
195
+ // Registra callbacks (padrao mK3D)
196
+ mkfashion.addToCart(function(payload) {
197
+ logEvent('cart', 'Adicionar ao carrinho', payload)
198
+ alert(`Produto ${payload.identifier} tamanho ${payload.size} adicionado ao carrinho!`)
199
+ })
200
+
201
+ mkfashion.onReady(function(data) {
202
+ logEvent('ready', 'App pronta', data)
203
+ })
204
+
205
+ mkfashion.onClose(function() {
206
+ logEvent('close', 'Modal fechado')
207
+ })
208
+
209
+ mkfashion.onGenerationComplete(function(data) {
210
+ logEvent('generation', 'Geracao completa', data)
211
+ })
212
+
213
+ mkfashion.onError(function(data) {
214
+ logEvent('close', 'Erro', data)
215
+ })
216
+
217
+ function abrirModal() {
218
+ mkfashion.open({
219
+ type: 'iframe',
220
+ projectid: 'gregory',
221
+ identifier: 'VEST-001-AZUL',
222
+ width: 400,
223
+ height: 700
224
+ })
225
+
226
+ logEvent('ready', 'Modal aberto')
227
+ }
228
+
229
+ function limparLogs() {
230
+ document.getElementById('eventsList').innerHTML = '<li style="color: #999;">Nenhum evento ainda...</li>'
231
+ }
232
+ </script>
233
+ </body>
234
+
235
+ </html>