File size: 8,054 Bytes
6aee8f5
 
205158e
6aee8f5
 
 
ceb9831
f7f0a1a
6cfe16d
 
f7f0a1a
 
 
 
 
ceb9831
f7f0a1a
6cfe16d
6aee8f5
 
205158e
 
6aee8f5
6cfe16d
 
6aee8f5
 
205158e
6aee8f5
6cfe16d
6aee8f5
 
 
 
ceb9831
6aee8f5
c560adf
 
 
 
 
f7f0a1a
6cfe16d
f7f0a1a
 
 
6cfe16d
f7f0a1a
 
 
6aee8f5
 
 
 
2b07a83
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6cfe16d
6aee8f5
6cfe16d
f7f0a1a
 
 
 
 
 
 
 
 
 
6cfe16d
6aee8f5
 
 
6cfe16d
6aee8f5
 
 
 
6cfe16d
 
 
 
 
6aee8f5
 
6cfe16d
6aee8f5
 
 
6cfe16d
6aee8f5
 
 
 
 
 
205158e
6cfe16d
6aee8f5
df68a62
 
 
 
 
 
 
f7f0a1a
6aee8f5
 
6cfe16d
6aee8f5
 
 
 
 
 
6cfe16d
df68a62
 
6aee8f5
df68a62
 
6cfe16d
df68a62
 
6cfe16d
df68a62
 
 
6aee8f5
 
f7f0a1a
6cfe16d
f7f0a1a
 
 
 
 
 
 
 
 
 
c560adf
 
 
 
f7f0a1a
c560adf
 
2b07a83
c560adf
f7f0a1a
c560adf
 
 
 
 
 
f7f0a1a
6aee8f5
 
205158e
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<!DOCTYPE html>
<html lang="es">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ title or "MAKER SPACE" }}</title>

    <!-- Meta Tags para PWA (Progressive Web App) -->
    <!-- Define cómo se ve y se comporta la app al instalarse en el móvil -->
    <link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
    <meta name="theme-color" content="#38bdf8">
    <link rel="apple-touch-icon" href="{{ url_for('static', filename='assets/apple-touch-icon.png') }}">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
    <meta name="apple-mobile-web-app-title" content="Maker Space">

    <!-- Iconos y Estilos -->
    <link rel="icon" href="{{ url_for('static', filename='assets/favicon.png') }}">
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Outfit:wght@500;700&display=swap"
        rel="stylesheet">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">

    <!-- Librería Socket.IO para comunicación en tiempo real -->
    <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.js"></script>
</head>

<body class="dark-theme">
    <!-- Barra de Navegación Global -->
    <nav class="navbar glass">
        <div class="nav-container">
            <a href="/" class="nav-logo">
                <i class="fas fa-cube"></i>
                <span>MAKER SPACE</span>
            </a>
            <!-- Botón Hamburguesa -->
            <button class="hamburger" id="hamburger-btn" aria-label="Menu">
                <i class="fas fa-bars"></i>
            </button>

            <div style="display: flex; gap: 1rem; align-items: center;">
                <!-- Botón para instalar PWA (solo aparece si es instalable) -->
                <button id="install-btn" class="btn-icon" style="display: none;">
                    <i class="fas fa-download"></i>
                </button>
                <!-- Botón para solicitar permisos de notificaciones -->
                <button id="notif-btn" class="btn-icon">
                    <i class="fas fa-bell"></i>
                </button>
            </div>
        </div>
    </nav>

    <!-- Sidebar Overlay - Movido fuera del nav para permitir blur global -->
    <div class="nav-overlay" id="nav-overlay">
        <div class="nav-sidebar glass">
            <button class="close-btn" id="close-btn">&times;</button>
            <div class="sidebar-links">
                <a href="/" class="nav-item"><i class="fas fa-home"></i> INICIO</a>
                <a href="/tutoria" class="nav-item"><i class="fas fa-book"></i> TUTORÍA</a>

                {% if current_user.is_authenticated %}
                <a href="/classroom" class="nav-item"><i class="fas fa-chalkboard-teacher"></i> AULAS</a>
                <div style="margin-top: auto; border-top: 1px solid rgba(255,255,255,0.1); padding-top: 1rem;">
                    <a href="/logout" class="nav-item" style="color: #ef4444;"><i class="fas fa-sign-out-alt"></i>
                        Salir</a>
                </div>
                {% else %}
                <a href="/login" class="nav-item" style="color: #38bdf8;"><i class="fas fa-sign-in-alt"></i>
                    Acceder</a>
                {% endif %}
            </div>
        </div>
    </div>

    <!-- Contenido Principal -->
    <main class="content-wrapper">
        <!-- Mostrar mensajes flash de Flask (Alertas de éxito/error) -->
        {% with messages = get_flashed_messages(with_categories=true) %}
        {% if messages %}
        {% for category, message in messages %}
        <div class="notification glass {{ category }}" style="margin-bottom: 2rem;">
            <i class="fas fa-exclamation-circle"></i> <span>{{ message }}</span>
        </div>
        {% endfor %}
        {% endif %}
        {% endwith %}

        <!-- Bloque donde se inserta el contenido de cada página hija -->
        {% block content %}{% endblock %}
    </main>

    <!-- Contenedor flotante para notificaciones Socket.IO -->
    <div id="notification-container"></div>

    <script src="{{ url_for('static', filename='js/script.js') }}"></script>
    <script>
        /* 
           LÓGICA DE CLIENTE (JAVASCRIPT)
        */

        // Inicializar conexión Socket.IO con el servidor
        const socket = io();
        socket.on('notification', (data) => {
            // Recibir notificación del bot de Telegram
            showNotification(data.text, data.color || 'blue');
        });

        // Función para mostrar notificaciones visuales en la web
        function showNotification(text, color) {
            const container = document.getElementById('notification-container');
            const notif = document.createElement('div');
            notif.className = `notification glass ${color}`;
            notif.innerHTML = `<i class="fas fa-info-circle"></i> <span>${text}</span>`;
            container.appendChild(notif);

            // Lanzar notificación de sistema del navegador (PC y Móvil)
            if ("Notification" in window && Notification.permission === "granted") {
                navigator.serviceWorker.ready.then(registration => {
                    registration.showNotification("MAKER SPACE", {
                        body: text,
                        icon: "/static/assets/icon192x192.png",
                        vibrate: [200, 100, 200],
                        badge: "/static/assets/favicon.png"
                    });
                });
            }

            // Desaparecer notificación después de 5 segundos
            setTimeout(() => {
                notif.style.opacity = '0';
                setTimeout(() => notif.remove(), 500);
            }, 5000);
        }

        // Lógica para el botón de activar notificaciones con feedback visual
        const notifBtn = document.getElementById('notif-btn');
        notifBtn.addEventListener('click', () => {
            if ("Notification" in window) {
                Notification.requestPermission().then(permission => {
                    if (permission === 'granted') {
                        notifBtn.style.color = '#10b981'; // Verde si activa
                        showNotification("Notificaciones activadas", "green");
                    } else if (permission === 'denied') {
                        notifBtn.style.color = '#ef4444'; // Rojo si deniega
                        alert("Has bloqueado las notificaciones. Actívalas en la configuración de tu navegador.");
                    }
                });
            }
        });

        // Registro del Service Worker para soporte PWA (Modo Offline)
        if ('serviceWorker' in navigator) {
            window.addEventListener('load', () => {
                navigator.serviceWorker.register('/static/sw.js').then((reg) => {
                    console.log('SW Registered', reg);
                }).catch((err) => {
                    console.log('SW Registration failed', err);
                });
            });
        }

        // Lógica del Menú Hamburguesa
        const hamburgerBtn = document.getElementById('hamburger-btn');
        const closeBtn = document.getElementById('close-btn');
        const navOverlay = document.getElementById('nav-overlay');

        function toggleMenu() {
            navOverlay.classList.toggle('active');
            document.body.classList.toggle('menu-open');
        }

        if (hamburgerBtn) hamburgerBtn.addEventListener('click', toggleMenu);
        if (closeBtn) closeBtn.addEventListener('click', toggleMenu);

        // Cerrar al hacer click fuera del sidebar
        if (navOverlay) navOverlay.addEventListener('click', (e) => {
            if (e.target === navOverlay) toggleMenu();
        });
    </script>
</body>

</html>