Extension for lovable.dev

A new extension

Size

8.6 KB

Version

1.0.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.0.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        const cards = new Set();
149        
150        // Procurar apenas por imagens que claramente são cartas de jogo
151        const allImages = document.querySelectorAll('img');
152        
153        allImages.forEach(img => {
154            // Verificar se a imagem parece ser uma carta
155            const src = img.src || '';
156            const alt = img.alt || '';
157            const className = img.className || '';
158            
159            // Critérios muito específicos para identificar cartas
160            const looksLikeCard = (
161                (src.includes('card') || alt.includes('card') || alt.includes('carta')) &&
162                !src.includes('icon') &&
163                !src.includes('logo') &&
164                !src.includes('avatar') &&
165                !className.includes('icon') &&
166                !className.includes('logo')
167            );
168            
169            if (!looksLikeCard) {
170                return;
171            }
172            
173            // Verificar tamanho da imagem (cartas geralmente são maiores)
174            const rect = img.getBoundingClientRect();
175            const isCardSize = rect.width >= 100 && rect.height >= 140 && rect.width <= 500 && rect.height <= 700;
176            
177            if (!isCardSize) {
178                return;
179            }
180            
181            // Pegar o container pai apropriado
182            let cardElement = img.parentElement;
183            
184            // Verificar se o pai não é um botão ou link genérico
185            if (cardElement && (cardElement.tagName === 'BUTTON' || cardElement.tagName === 'A')) {
186                cardElement = cardElement.parentElement;
187            }
188            
189            if (cardElement) {
190                cards.add(cardElement);
191            }
192        });
193        
194        console.log(`Encontradas ${cards.size} cartas`);
195        return Array.from(cards);
196    }
197    
198    // Função para processar cartas
199    function processCards() {
200        const cards = findCards();
201        cards.forEach(card => {
202            addReadCardButton(card);
203        });
204    }
205    
206    // Função de debounce
207    function debounce(func, wait) {
208        let timeout;
209        return function executedFunction(...args) {
210            const later = () => {
211                clearTimeout(timeout);
212                func(...args);
213            };
214            clearTimeout(timeout);
215            timeout = setTimeout(later, wait);
216        };
217    }
218    
219    // Observar mudanças no DOM
220    const debouncedProcess = debounce(processCards, 1000);
221    
222    const observer = new MutationObserver(debouncedProcess);
223    
224    // Inicializar quando o body estiver pronto
225    function init() {
226        if (document.body) {
227            console.log('Iniciando observação do DOM');
228            
229            // Processar cartas existentes
230            processCards();
231            
232            // Observar mudanças
233            observer.observe(document.body, {
234                childList: true,
235                subtree: true
236            });
237        } else {
238            setTimeout(init, 100);
239        }
240    }
241    
242    // Iniciar
243    if (document.readyState === 'loading') {
244        document.addEventListener('DOMContentLoaded', init);
245    } else {
246        init();
247    }
248    
249})();