feat: Migración completa de SnatchGame a Nuxt 4
Some checks failed
build-and-deploy / filter (push) Successful in 3s
build-and-deploy / build (push) Failing after 6s
build-and-deploy / deploy (push) Has been skipped

- Creado nuevo proyecto Nuxt 4 con estructura app/
- Servidor Colyseus separado para evitar problemas con decoradores
- Migrado GameRoom y toda la lógica del juego
- Implementado cliente con composables useGameClient
- Panel de administración funcional
- Componentes Vue migrados (HomeScreen, GameScreen, PlayerCard, etc)
- Configuración para ejecutar ambos servidores (npm run dev:all)
This commit is contained in:
2025-08-05 16:05:51 -06:00
parent b83d450ac6
commit 62226ab5d4
36 changed files with 17126 additions and 2661 deletions

View File

@@ -0,0 +1,289 @@
<template>
<div class="modal-overlay" @click="$emit('close')">
<div class="modal-content" @click.stop>
<div class="modal-header">
<h2>Configuración</h2>
<button class="close-button" @click="$emit('close')"></button>
</div>
<div class="modal-body">
<div class="settings-section">
<h3>Audio</h3>
<div class="setting-item">
<label>
<input type="checkbox" v-model="settings.soundEnabled" />
Efectos de sonido
</label>
</div>
<div class="setting-item">
<label>
<input type="checkbox" v-model="settings.musicEnabled" />
Música de fondo
</label>
</div>
<div class="setting-item">
<label>
Volumen
<input
type="range"
min="0"
max="100"
v-model="settings.volume"
class="volume-slider"
/>
<span>{{ settings.volume }}%</span>
</label>
</div>
</div>
<div class="settings-section">
<h3>Notificaciones</h3>
<div class="setting-item">
<label>
<input type="checkbox" v-model="settings.notifications" />
Notificaciones del juego
</label>
</div>
<div class="setting-item">
<label>
<input type="checkbox" v-model="settings.tradeAlerts" />
Alertas de intercambio
</label>
</div>
</div>
<div class="settings-section">
<h3>Apariencia</h3>
<div class="setting-item">
<label>
<input type="checkbox" v-model="settings.animations" />
Animaciones
</label>
</div>
<div class="setting-item">
<label>
Tema
<select v-model="settings.theme">
<option value="light">Claro</option>
<option value="dark">Oscuro</option>
<option value="auto">Automático</option>
</select>
</label>
</div>
</div>
</div>
<div class="modal-footer">
<button @click="saveSettings" class="btn-save">Guardar</button>
<button @click="$emit('close')" class="btn-cancel">Cancelar</button>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { ref, reactive, onMounted } from 'vue'
const emit = defineEmits<{
'close': []
}>()
const settings = reactive({
soundEnabled: true,
musicEnabled: true,
volume: 50,
notifications: true,
tradeAlerts: true,
animations: true,
theme: 'dark'
})
onMounted(() => {
// Load settings from localStorage
const savedSettings = localStorage.getItem('gameSettings')
if (savedSettings) {
Object.assign(settings, JSON.parse(savedSettings))
}
})
const saveSettings = () => {
// Save settings to localStorage
localStorage.setItem('gameSettings', JSON.stringify(settings))
console.log('Settings saved:', settings)
emit('close')
}
</script>
<style scoped>
.modal-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.7);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
backdrop-filter: blur(5px);
}
.modal-content {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
border-radius: 16px;
width: 90%;
max-width: 500px;
max-height: 80vh;
overflow-y: auto;
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
}
.modal-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1.5rem;
border-bottom: 1px solid rgba(255, 255, 255, 0.2);
}
.modal-header h2 {
margin: 0;
color: white;
font-size: 1.5rem;
}
.close-button {
background: none;
border: none;
color: white;
font-size: 1.5rem;
cursor: pointer;
padding: 0;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
transition: background 0.3s ease;
}
.close-button:hover {
background: rgba(255, 255, 255, 0.2);
}
.modal-body {
padding: 1.5rem;
color: white;
}
.settings-section {
margin-bottom: 2rem;
}
.settings-section:last-child {
margin-bottom: 0;
}
.settings-section h3 {
margin: 0 0 1rem 0;
font-size: 1.2rem;
color: rgba(255, 255, 255, 0.9);
}
.setting-item {
margin-bottom: 1rem;
}
.setting-item label {
display: flex;
align-items: center;
gap: 0.75rem;
cursor: pointer;
font-size: 1rem;
}
.setting-item input[type="checkbox"] {
width: 20px;
height: 20px;
cursor: pointer;
}
.volume-slider {
flex: 1;
margin: 0 1rem;
}
select {
padding: 0.5rem;
border-radius: 6px;
background: rgba(255, 255, 255, 0.2);
color: white;
border: 1px solid rgba(255, 255, 255, 0.3);
cursor: pointer;
}
select option {
background: #667eea;
color: white;
}
.modal-footer {
display: flex;
gap: 1rem;
padding: 1.5rem;
border-top: 1px solid rgba(255, 255, 255, 0.2);
}
.modal-footer button {
flex: 1;
padding: 0.75rem 1.5rem;
border: none;
border-radius: 8px;
font-size: 1rem;
font-weight: 600;
cursor: pointer;
transition: all 0.3s ease;
color: white;
}
.btn-save {
background: rgba(76, 175, 80, 0.8);
}
.btn-save:hover {
background: rgba(76, 175, 80, 1);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
.btn-cancel {
background: rgba(158, 158, 158, 0.8);
}
.btn-cancel:hover {
background: rgba(158, 158, 158, 1);
transform: translateY(-2px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3);
}
/* Custom scrollbar */
.modal-content::-webkit-scrollbar {
width: 8px;
}
.modal-content::-webkit-scrollbar-track {
background: rgba(255, 255, 255, 0.1);
border-radius: 4px;
}
.modal-content::-webkit-scrollbar-thumb {
background: rgba(255, 255, 255, 0.3);
border-radius: 4px;
}
.modal-content::-webkit-scrollbar-thumb:hover {
background: rgba(255, 255, 255, 0.5);
}
</style>