Extension for lovable.dev

A new extension

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})();