Size
8.4 KB
Version
1.1.1
Created
Feb 6, 2026
Updated
29 days ago
1// ==UserScript==
2// @name Extension for lovable.dev
3// @description A new extension
4// @version 1.1.1
5// @match https://*.lovable.dev/*
6// @icon https://lovable.dev/favicon.svg
7// ==/UserScript==
8(function() {
9 'use strict';
10
11 console.log('Extensão Ler Carta iniciada');
12
13 // Função para adicionar botão de ler carta
14 function addReadCardButton(cardElement) {
15 // Verificar se já tem o botão
16 if (cardElement.querySelector('.read-card-button')) {
17 return;
18 }
19
20 // Criar o botão
21 const button = document.createElement('button');
22 button.textContent = 'Ler Carta';
23 button.className = 'read-card-button';
24 button.style.cssText = `
25 position: absolute;
26 bottom: 10px;
27 left: 50%;
28 transform: translateX(-50%);
29 background-color: #4CAF50;
30 color: white;
31 border: none;
32 padding: 8px 16px;
33 border-radius: 4px;
34 cursor: pointer;
35 font-size: 14px;
36 font-weight: bold;
37 z-index: 1000;
38 box-shadow: 0 2px 4px rgba(0,0,0,0.2);
39 `;
40
41 button.addEventListener('mouseenter', () => {
42 button.style.backgroundColor = '#45a049';
43 });
44
45 button.addEventListener('mouseleave', () => {
46 button.style.backgroundColor = '#4CAF50';
47 });
48
49 button.addEventListener('click', async (e) => {
50 e.stopPropagation();
51
52 // Pegar a imagem da carta
53 const cardImage = cardElement.querySelector('img[src*="card"], img[alt*="card"]');
54 if (!cardImage) {
55 console.error('Imagem da carta não encontrada');
56 return;
57 }
58
59 button.textContent = 'Lendo...';
60 button.disabled = true;
61
62 try {
63 // Usar RM.aiCall para ler a carta
64 const cardDescription = await RM.aiCall(
65 `Analise esta carta de jogo e descreva seus atributos, habilidades e efeitos em português. URL da imagem: ${cardImage.src}`,
66 {
67 type: 'json_schema',
68 json_schema: {
69 name: 'card_reading',
70 schema: {
71 type: 'object',
72 properties: {
73 nome: { type: 'string' },
74 tipo: { type: 'string' },
75 atributos: { type: 'array', items: { type: 'string' } },
76 habilidades: { type: 'array', items: { type: 'string' } },
77 descricao: { type: 'string' }
78 },
79 required: ['nome', 'descricao']
80 }
81 }
82 }
83 );
84
85 // Mostrar resultado
86 showCardInfo(cardDescription, cardElement);
87
88 } catch (error) {
89 console.error('Erro ao ler carta:', error);
90 alert('Erro ao ler a carta. Tente novamente.');
91 } finally {
92 button.textContent = 'Ler Carta';
93 button.disabled = false;
94 }
95 });
96
97 // Adicionar o botão à carta
98 cardElement.style.position = 'relative';
99 cardElement.appendChild(button);
100 console.log('Botão adicionado à carta');
101 }
102
103 // Função para mostrar informações da carta
104 function showCardInfo(cardInfo, cardElement) {
105 // Remover info anterior se existir
106 const existingInfo = cardElement.querySelector('.card-info-display');
107 if (existingInfo) {
108 existingInfo.remove();
109 }
110
111 // Criar elemento de informação
112 const infoDiv = document.createElement('div');
113 infoDiv.className = 'card-info-display';
114 infoDiv.style.cssText = `
115 position: absolute;
116 top: 0;
117 left: 0;
118 right: 0;
119 bottom: 0;
120 background-color: rgba(0, 0, 0, 0.9);
121 color: white;
122 padding: 20px;
123 border-radius: 8px;
124 overflow-y: auto;
125 z-index: 999;
126 `;
127
128 infoDiv.innerHTML = `
129 <button class="close-info" style="position: absolute; top: 10px; right: 10px; background: #f44336; color: white; border: none; padding: 5px 10px; border-radius: 4px; cursor: pointer;">✕</button>
130 <h3 style="margin-top: 0;">${cardInfo.nome}</h3>
131 <p><strong>Tipo:</strong> ${cardInfo.tipo || 'N/A'}</p>
132 ${cardInfo.atributos && cardInfo.atributos.length > 0 ? `<p><strong>Atributos:</strong> ${cardInfo.atributos.join(', ')}</p>` : ''}
133 ${cardInfo.habilidades && cardInfo.habilidades.length > 0 ? `<p><strong>Habilidades:</strong></p><ul>${cardInfo.habilidades.map(h => `<li>${h}</li>`).join('')}</ul>` : ''}
134 <p><strong>Descrição:</strong> ${cardInfo.descricao}</p>
135 `;
136
137 // Adicionar evento de fechar
138 infoDiv.querySelector('.close-info').addEventListener('click', (e) => {
139 e.stopPropagation();
140 infoDiv.remove();
141 });
142
143 cardElement.appendChild(infoDiv);
144 }
145
146 // Função para encontrar cartas na página
147 function findCards() {
148 // Seletores muito específicos para cartas de jogo
149 // Ajuste estes seletores de acordo com a estrutura real do site
150 const cardSelectors = [
151 'div[class*="card-container"]:has(img)',
152 'div[class*="game-card"]:has(img)',
153 'div[data-card-id]',
154 '.card-wrapper img[src*="card"]',
155 '[class*="CardImage"]',
156 'img[alt*="carta"]',
157 'img[alt*="card"]'
158 ];
159
160 const cards = new Set();
161
162 cardSelectors.forEach(selector => {
163 try {
164 const elements = document.querySelectorAll(selector);
165 elements.forEach(el => {
166 // Se for uma imagem, pegar o container pai
167 const cardElement = el.tagName === 'IMG' ? el.parentElement : el;
168
169 // Verificar se realmente parece uma carta (tem imagem e tamanho razoável)
170 const hasImage = cardElement.querySelector('img') || cardElement.tagName === 'IMG';
171 const rect = cardElement.getBoundingClientRect();
172 const isReasonableSize = rect.width > 50 && rect.height > 50;
173
174 if (hasImage && isReasonableSize) {
175 cards.add(cardElement);
176 }
177 });
178 } catch (e) {
179 console.error('Erro ao buscar cartas com seletor:', selector, e);
180 }
181 });
182
183 console.log(`Encontradas ${cards.size} cartas`);
184 return Array.from(cards);
185 }
186
187 // Função para processar cartas
188 function processCards() {
189 const cards = findCards();
190 cards.forEach(card => {
191 addReadCardButton(card);
192 });
193 }
194
195 // Função de debounce
196 function debounce(func, wait) {
197 let timeout;
198 return function executedFunction(...args) {
199 const later = () => {
200 clearTimeout(timeout);
201 func(...args);
202 };
203 clearTimeout(timeout);
204 timeout = setTimeout(later, wait);
205 };
206 }
207
208 // Observar mudanças no DOM
209 const debouncedProcess = debounce(processCards, 1000);
210
211 const observer = new MutationObserver(debouncedProcess);
212
213 // Inicializar quando o body estiver pronto
214 function init() {
215 if (document.body) {
216 console.log('Iniciando observação do DOM');
217
218 // Processar cartas existentes
219 processCards();
220
221 // Observar mudanças
222 observer.observe(document.body, {
223 childList: true,
224 subtree: true
225 });
226 } else {
227 setTimeout(init, 100);
228 }
229 }
230
231 // Iniciar
232 if (document.readyState === 'loading') {
233 document.addEventListener('DOMContentLoaded', init);
234 } else {
235 init();
236 }
237
238})();