butztub commited on
Commit
694b02a
verified
1 Parent(s): 8299112

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +1785 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Timetimer
3
- emoji: 馃搳
4
- colorFrom: indigo
5
- colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: timetimer
3
+ emoji: 馃惓
4
+ colorFrom: green
5
+ colorTo: purple
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,1785 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="es">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>TimeTask - Gestor de Tareas Pomodoro</title>
7
+ <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
8
+ <style>
9
+ body {
10
+ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
11
+ transition: background-color 0.3s, color 0.3s;
12
+ }
13
+
14
+ .dark-mode {
15
+ background-color: #1a1a1a;
16
+ color: #f8f9fa;
17
+ }
18
+
19
+ .dark-mode .card, .dark-mode .modal-content, .dark-mode .dropdown-menu {
20
+ background-color: #2d2d2d;
21
+ color: #f8f9fa;
22
+ border-color: #444;
23
+ }
24
+
25
+ .dark-mode .form-control, .dark-mode .form-select {
26
+ background-color: #3d3d3d;
27
+ color: #f8f9fa;
28
+ border-color: #555;
29
+ }
30
+
31
+ .task-card {
32
+ transition: transform 0.2s;
33
+ cursor: pointer;
34
+ }
35
+
36
+ .task-card:hover {
37
+ transform: translateY(-5px);
38
+ }
39
+
40
+ .priority-low {
41
+ border-left: 5px solid #28a745;
42
+ }
43
+
44
+ .priority-medium {
45
+ border-left: 5px solid #ffc107;
46
+ }
47
+
48
+ .priority-high {
49
+ border-left: 5px solid #dc3545;
50
+ }
51
+
52
+ .timeline {
53
+ position: relative;
54
+ padding-left: 50px;
55
+ }
56
+
57
+ .timeline::before {
58
+ content: '';
59
+ position: absolute;
60
+ left: 25px;
61
+ top: 0;
62
+ bottom: 0;
63
+ width: 2px;
64
+ background-color: #007bff;
65
+ }
66
+
67
+ .timeline-item {
68
+ position: relative;
69
+ margin-bottom: 20px;
70
+ }
71
+
72
+ .timeline-item::before {
73
+ content: '';
74
+ position: absolute;
75
+ left: -35px;
76
+ top: 10px;
77
+ width: 16px;
78
+ height: 16px;
79
+ border-radius: 50%;
80
+ background-color: #007bff;
81
+ border: 3px solid #fff;
82
+ }
83
+
84
+ .current-time {
85
+ position: absolute;
86
+ left: 0;
87
+ right: 0;
88
+ height: 2px;
89
+ background-color: red;
90
+ z-index: 100;
91
+ }
92
+
93
+ .calendar-day {
94
+ height: 100px;
95
+ border: 1px solid #dee2e6;
96
+ padding: 5px;
97
+ overflow-y: auto;
98
+ }
99
+
100
+ .calendar-day.today {
101
+ background-color: rgba(0, 123, 255, 0.1);
102
+ }
103
+
104
+ .calendar-day-header {
105
+ font-weight: bold;
106
+ margin-bottom: 5px;
107
+ }
108
+
109
+ .task-dot {
110
+ display: inline-block;
111
+ width: 10px;
112
+ height: 10px;
113
+ border-radius: 50%;
114
+ margin-right: 5px;
115
+ }
116
+
117
+ .pomodoro-timer {
118
+ font-size: 3rem;
119
+ font-weight: bold;
120
+ text-align: center;
121
+ margin: 20px 0;
122
+ }
123
+
124
+ .pomodoro-btn {
125
+ width: 100px;
126
+ margin: 0 5px;
127
+ }
128
+
129
+ .pomodoro-session {
130
+ font-size: 1.2rem;
131
+ text-align: center;
132
+ margin-bottom: 20px;
133
+ }
134
+ </style>
135
+ </head>
136
+ <body>
137
+ <div class="container-fluid">
138
+ <nav class="navbar navbar-expand-lg navbar-dark bg-primary mb-4">
139
+ <div class="container-fluid">
140
+ <a class="navbar-brand" href="#">TimeTask</a>
141
+ <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
142
+ <span class="navbar-toggler-icon"></span>
143
+ </button>
144
+ <div class="collapse navbar-collapse" id="navbarNav">
145
+ <ul class="navbar-nav me-auto">
146
+ <li class="nav-item">
147
+ <a class="nav-link active" href="#" onclick="showView('dashboard')">Inicio</a>
148
+ </li>
149
+ <li class="nav-item">
150
+ <a class="nav-link" href="#" onclick="showView('tasks')">Tareas</a>
151
+ </li>
152
+ <li class="nav-item">
153
+ <a class="nav-link" href="#" onclick="showView('timeline')">L铆nea de Tiempo</a>
154
+ </li>
155
+ <li class="nav-item">
156
+ <a class="nav-link" href="#" onclick="showView('day')">D铆a</a>
157
+ </li>
158
+ <li class="nav-item">
159
+ <a class="nav-link" href="#" onclick="showView('week')">Semana</a>
160
+ </li>
161
+ <li class="nav-item">
162
+ <a class="nav-link" href="#" onclick="showView('calendar')">Calendario</a>
163
+ </li>
164
+ <li class="nav-item">
165
+ <a class="nav-link" href="#" onclick="showView('metrics')">M茅tricas</a>
166
+ </li>
167
+ </ul>
168
+ <div class="d-flex align-items-center">
169
+ <div class="me-3 text-white" id="current-time"></div>
170
+ <div class="form-check form-switch me-3">
171
+ <input class="form-check-input" type="checkbox" id="darkModeSwitch">
172
+ <label class="form-check-label text-white" for="darkModeSwitch">Modo Oscuro</label>
173
+ </div>
174
+ <div class="dropdown">
175
+ <button class="btn btn-outline-light dropdown-toggle" type="button" id="profileDropdown" data-bs-toggle="dropdown">
176
+ Perfil
177
+ </button>
178
+ <ul class="dropdown-menu dropdown-menu-end">
179
+ <li><a class="dropdown-item" href="#" onclick="showView('profile')">Configuraci贸n</a></li>
180
+ <li><hr class="dropdown-divider"></li>
181
+ <li><a class="dropdown-item" href="#" onclick="logout()">Cerrar Sesi贸n</a></li>
182
+ </ul>
183
+ </div>
184
+ </div>
185
+ </div>
186
+ </div>
187
+ </nav>
188
+
189
+ <!-- Main Content -->
190
+ <div id="main-content">
191
+ <!-- Dashboard View -->
192
+ <div id="dashboard-view" class="view">
193
+ <div class="row">
194
+ <div class="col-md-8">
195
+ <div class="card mb-4">
196
+ <div class="card-header d-flex justify-content-between align-items-center">
197
+ <h5 class="mb-0">Pomodoro Timer</h5>
198
+ <button class="btn btn-sm btn-primary" onclick="showView('tasks')">Ver Tareas</button>
199
+ </div>
200
+ <div class="card-body">
201
+ <div class="pomodoro-timer" id="pomodoro-timer">25:00</div>
202
+ <div class="pomodoro-session" id="pomodoro-session">Sesi贸n de Trabajo</div>
203
+ <div class="d-flex justify-content-center">
204
+ <button class="btn btn-success pomodoro-btn" id="start-btn" onclick="startPomodoro()">Iniciar</button>
205
+ <button class="btn btn-danger pomodoro-btn" id="stop-btn" onclick="stopPomodoro()" disabled>Detener</button>
206
+ <button class="btn btn-warning pomodoro-btn" id="reset-btn" onclick="resetPomodoro()">Reiniciar</button>
207
+ </div>
208
+ </div>
209
+ </div>
210
+
211
+ <div class="card mb-4">
212
+ <div class="card-header">
213
+ <h5 class="mb-0">Tareas de Hoy</h5>
214
+ </div>
215
+ <div class="card-body" id="today-tasks">
216
+ <!-- Tasks will be loaded here -->
217
+ </div>
218
+ </div>
219
+ </div>
220
+
221
+ <div class="col-md-4">
222
+ <div class="card mb-4">
223
+ <div class="card-header d-flex justify-content-between align-items-center">
224
+ <h5 class="mb-0">Agregar Tarea R谩pida</h5>
225
+ </div>
226
+ <div class="card-body">
227
+ <form id="quick-task-form">
228
+ <div class="mb-3">
229
+ <input type="text" class="form-control" id="quick-task-name" placeholder="Nombre de la tarea" required>
230
+ </div>
231
+ <div class="mb-3">
232
+ <select class="form-select" id="quick-task-priority">
233
+ <option value="low">Baja</option>
234
+ <option value="medium">Media</option>
235
+ <option value="high">Alta</option>
236
+ </select>
237
+ </div>
238
+ <button type="submit" class="btn btn-primary w-100">Agregar</button>
239
+ </form>
240
+ </div>
241
+ </div>
242
+
243
+ <div class="card">
244
+ <div class="card-header">
245
+ <h5 class="mb-0">Estad铆sticas</h5>
246
+ </div>
247
+ <div class="card-body">
248
+ <div class="mb-3">
249
+ <h6>Tareas completadas hoy: <span id="completed-today">0</span></h6>
250
+ </div>
251
+ <div class="mb-3">
252
+ <h6>Tiempo trabajado hoy: <span id="time-worked">0h 0m</span></h6>
253
+ </div>
254
+ <div class="mb-3">
255
+ <h6>Sesiones Pomodoro: <span id="pomodoro-sessions">0</span></h6>
256
+ </div>
257
+ </div>
258
+ </div>
259
+ </div>
260
+ </div>
261
+ </div>
262
+
263
+ <!-- Tasks View -->
264
+ <div id="tasks-view" class="view" style="display: none;">
265
+ <div class="d-flex justify-content-between align-items-center mb-4">
266
+ <h2>Tareas</h2>
267
+ <button class="btn btn-primary" onclick="showTaskModal()">Nueva Tarea</button>
268
+ </div>
269
+
270
+ <div class="row mb-3">
271
+ <div class="col-md-4">
272
+ <select class="form-select" id="task-sort">
273
+ <option value="date">Ordenar por: Fecha</option>
274
+ <option value="priority">Ordenar por: Prioridad</option>
275
+ <option value="category">Ordenar por: Categor铆a</option>
276
+ </select>
277
+ </div>
278
+ <div class="col-md-4">
279
+ <select class="form-select" id="task-filter">
280
+ <option value="all">Todas las tareas</option>
281
+ <option value="today">Hoy</option>
282
+ <option value="week">Esta semana</option>
283
+ <option value="completed">Completadas</option>
284
+ <option value="pending">Pendientes</option>
285
+ </select>
286
+ </div>
287
+ <div class="col-md-4">
288
+ <input type="text" class="form-control" id="task-search" placeholder="Buscar tareas...">
289
+ </div>
290
+ </div>
291
+
292
+ <div class="row" id="tasks-container">
293
+ <!-- Tasks will be loaded here -->
294
+ </div>
295
+ </div>
296
+
297
+ <!-- Timeline View -->
298
+ <div id="timeline-view" class="view" style="display: none;">
299
+ <div class="d-flex justify-content-between align-items-center mb-4">
300
+ <h2>L铆nea de Tiempo</h2>
301
+ <div class="btn-group">
302
+ <button class="btn btn-outline-primary" onclick="changeTimelineRange('day')">D铆a</button>
303
+ <button class="btn btn-outline-primary" onclick="changeTimelineRange('week')">Semana</button>
304
+ <button class="btn btn-outline-primary" onclick="changeTimelineRange('month')">Mes</button>
305
+ </div>
306
+ </div>
307
+
308
+ <div class="card">
309
+ <div class="card-header">
310
+ <div class="d-flex justify-content-between align-items-center">
311
+ <h5 class="mb-0" id="timeline-title">Hoy</h5>
312
+ <div id="timeline-date"></div>
313
+ </div>
314
+ </div>
315
+ <div class="card-body">
316
+ <div class="timeline" id="timeline-container">
317
+ <div class="current-time" id="current-time-indicator"></div>
318
+ <!-- Timeline items will be loaded here -->
319
+ </div>
320
+ </div>
321
+ </div>
322
+ </div>
323
+
324
+ <!-- Day View -->
325
+ <div id="day-view" class="view" style="display: none;">
326
+ <div class="d-flex justify-content-between align-items-center mb-4">
327
+ <h2>Agenda del D铆a</h2>
328
+ <div class="btn-group">
329
+ <button class="btn btn-outline-primary" onclick="changeDay(-1)">Anterior</button>
330
+ <button class="btn btn-outline-primary" onclick="changeDay(0)">Hoy</button>
331
+ <button class="btn btn-outline-primary" onclick="changeDay(1)">Siguiente</button>
332
+ </div>
333
+ </div>
334
+
335
+ <div class="card">
336
+ <div class="card-header">
337
+ <h5 class="mb-0" id="day-title">Hoy</h5>
338
+ </div>
339
+ <div class="card-body">
340
+ <div class="table-responsive">
341
+ <table class="table">
342
+ <thead>
343
+ <tr>
344
+ <th style="width: 10%">Hora</th>
345
+ <th style="width: 90%">Tareas</th>
346
+ </tr>
347
+ </thead>
348
+ <tbody id="day-schedule">
349
+ <!-- Day schedule will be loaded here -->
350
+ </tbody>
351
+ </table>
352
+ </div>
353
+ </div>
354
+ </div>
355
+ </div>
356
+
357
+ <!-- Week View -->
358
+ <div id="week-view" class="view" style="display: none;">
359
+ <div class="d-flex justify-content-between align-items-center mb-4">
360
+ <h2>Semana</h2>
361
+ <div class="btn-group">
362
+ <button class="btn btn-outline-primary" onclick="changeWeek(-1)">Anterior</button>
363
+ <button class="btn btn-outline-primary" onclick="changeWeek(0)">Esta semana</button>
364
+ <button class="btn btn-outline-primary" onclick="changeWeek(1)">Siguiente</button>
365
+ </div>
366
+ </div>
367
+
368
+ <div class="card">
369
+ <div class="card-header">
370
+ <h5 class="mb-0" id="week-title">Esta semana</h5>
371
+ </div>
372
+ <div class="card-body">
373
+ <div class="table-responsive">
374
+ <table class="table table-bordered" id="week-calendar">
375
+ <thead>
376
+ <tr>
377
+ <th style="width: 14%">Domingo</th>
378
+ <th style="width: 14%">Lunes</th>
379
+ <th style="width: 14%">Martes</th>
380
+ <th style="width: 14%">Mi茅rcoles</th>
381
+ <th style="width: 14%">Jueves</th>
382
+ <th style="width: 14%">Viernes</th>
383
+ <th style="width: 14%">S谩bado</th>
384
+ </tr>
385
+ </thead>
386
+ <tbody>
387
+ <tr>
388
+ <td class="calendar-day" id="week-day-0"></td>
389
+ <td class="calendar-day" id="week-day-1"></td>
390
+ <td class="calendar-day" id="week-day-2"></td>
391
+ <td class="calendar-day" id="week-day-3"></td>
392
+ <td class="calendar-day" id="week-day-4"></td>
393
+ <td class="calendar-day" id="week-day-5"></td>
394
+ <td class="calendar-day" id="week-day-6"></td>
395
+ </tr>
396
+ </tbody>
397
+ </table>
398
+ </div>
399
+ </div>
400
+ </div>
401
+ </div>
402
+
403
+ <!-- Calendar View -->
404
+ <div id="calendar-view" class="view" style="display: none;">
405
+ <div class="d-flex justify-content-between align-items-center mb-4">
406
+ <h2>Calendario</h2>
407
+ <div class="btn-group">
408
+ <button class="btn btn-outline-primary" onclick="changeMonth(-1)">Mes anterior</button>
409
+ <button class="btn btn-outline-primary" onclick="changeMonth(0)">Este mes</button>
410
+ <button class="btn btn-outline-primary" onclick="changeMonth(1)">Siguiente mes</button>
411
+ </div>
412
+ </div>
413
+
414
+ <div class="card">
415
+ <div class="card-header">
416
+ <h5 class="mb-0" id="calendar-title">Este mes</h5>
417
+ </div>
418
+ <div class="card-body">
419
+ <div class="table-responsive">
420
+ <table class="table table-bordered" id="month-calendar">
421
+ <thead>
422
+ <tr>
423
+ <th style="width: 14%">Dom</th>
424
+ <th style="width: 14%">Lun</th>
425
+ <th style="width: 14%">Mar</th>
426
+ <th style="width: 14%">Mi茅</th>
427
+ <th style="width: 14%">Jue</th>
428
+ <th style="width: 14%">Vie</th>
429
+ <th style="width: 14%">S谩b</th>
430
+ </tr>
431
+ </thead>
432
+ <tbody id="calendar-body">
433
+ <!-- Calendar will be loaded here -->
434
+ </tbody>
435
+ </table>
436
+ </div>
437
+ </div>
438
+ </div>
439
+ </div>
440
+
441
+ <!-- Metrics View -->
442
+ <div id="metrics-view" class="view" style="display: none;">
443
+ <div class="d-flex justify-content-between align-items-center mb-4">
444
+ <h2>M茅tricas</h2>
445
+ <div class="btn-group">
446
+ <button class="btn btn-outline-primary" onclick="changeMetricsRange('week')">Semana</button>
447
+ <button class="btn btn-outline-primary" onclick="changeMetricsRange('month')">Mes</button>
448
+ <button class="btn btn-outline-primary" onclick="changeMetricsRange('year')">A帽o</button>
449
+ </div>
450
+ </div>
451
+
452
+ <div class="row">
453
+ <div class="col-md-6">
454
+ <div class="card mb-4">
455
+ <div class="card-header">
456
+ <h5 class="mb-0">Tareas completadas</h5>
457
+ </div>
458
+ <div class="card-body">
459
+ <canvas id="completed-chart" height="300"></canvas>
460
+ </div>
461
+ </div>
462
+ </div>
463
+ <div class="col-md-6">
464
+ <div class="card mb-4">
465
+ <div class="card-header">
466
+ <h5 class="mb-0">Distribuci贸n por prioridad</h5>
467
+ </div>
468
+ <div class="card-body">
469
+ <canvas id="priority-chart" height="300"></canvas>
470
+ </div>
471
+ </div>
472
+ </div>
473
+ </div>
474
+
475
+ <div class="card">
476
+ <div class="card-header">
477
+ <h5 class="mb-0">Productividad</h5>
478
+ </div>
479
+ <div class="card-body">
480
+ <canvas id="productivity-chart" height="300"></canvas>
481
+ </div>
482
+ </div>
483
+ </div>
484
+
485
+ <!-- Profile View -->
486
+ <div id="profile-view" class="view" style="display: none;">
487
+ <div class="row justify-content-center">
488
+ <div class="col-md-8">
489
+ <div class="card">
490
+ <div class="card-header">
491
+ <h5 class="mb-0">Perfil de Usuario</h5>
492
+ </div>
493
+ <div class="card-body">
494
+ <form id="profile-form">
495
+ <div class="mb-3">
496
+ <label for="profile-name" class="form-label">Nombre</label>
497
+ <input type="text" class="form-control" id="profile-name" required>
498
+ </div>
499
+ <div class="mb-3">
500
+ <label for="profile-email" class="form-label">Email</label>
501
+ <input type="email" class="form-control" id="profile-email" required>
502
+ </div>
503
+ <div class="mb-3">
504
+ <label for="profile-password" class="form-label">Nueva Contrase帽a</label>
505
+ <input type="password" class="form-control" id="profile-password" placeholder="Dejar en blanco para no cambiar">
506
+ </div>
507
+ <div class="mb-3">
508
+ <label for="profile-confirm-password" class="form-label">Confirmar Nueva Contrase帽a</label>
509
+ <input type="password" class="form-control" id="profile-confirm-password">
510
+ </div>
511
+ <div class="mb-3 form-check">
512
+ <input type="checkbox" class="form-check-input" id="profile-dark-mode">
513
+ <label class="form-check-label" for="profile-dark-mode">Modo Oscuro</label>
514
+ </div>
515
+ <button type="submit" class="btn btn-primary">Guardar Cambios</button>
516
+ </form>
517
+ </div>
518
+ </div>
519
+ </div>
520
+ </div>
521
+ </div>
522
+ </div>
523
+ </div>
524
+
525
+ <!-- Task Modal -->
526
+ <div class="modal fade" id="taskModal" tabindex="-1" aria-hidden="true">
527
+ <div class="modal-dialog modal-lg">
528
+ <div class="modal-content">
529
+ <div class="modal-header">
530
+ <h5 class="modal-title" id="taskModalTitle">Nueva Tarea</h5>
531
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
532
+ </div>
533
+ <div class="modal-body">
534
+ <form id="task-form">
535
+ <input type="hidden" id="task-id">
536
+ <div class="mb-3">
537
+ <label for="task-name" class="form-label">Nombre</label>
538
+ <input type="text" class="form-control" id="task-name" required>
539
+ </div>
540
+ <div class="row mb-3">
541
+ <div class="col-md-6">
542
+ <label for="task-priority" class="form-label">Prioridad</label>
543
+ <select class="form-select" id="task-priority" required>
544
+ <option value="low">Baja</option>
545
+ <option value="medium">Media</option>
546
+ <option value="high">Alta</option>
547
+ </select>
548
+ </div>
549
+ <div class="col-md-6">
550
+ <label for="task-status" class="form-label">Estado</label>
551
+ <select class="form-select" id="task-status">
552
+ <option value="pending">Pendiente</option>
553
+ <option value="in-progress">En progreso</option>
554
+ <option value="completed">Completada</option>
555
+ </select>
556
+ </div>
557
+ </div>
558
+ <div class="row mb-3">
559
+ <div class="col-md-6">
560
+ <label for="task-category" class="form-label">Categor铆a</label>
561
+ <select class="form-select" id="task-category">
562
+ <option value="work">Trabajo</option>
563
+ <option value="personal">Personal</option>
564
+ <option value="study">Estudio</option>
565
+ <option value="other">Otro</option>
566
+ </select>
567
+ </div>
568
+ <div class="col-md-6">
569
+ <label for="task-subcategory" class="form-label">Subcategor铆a</label>
570
+ <input type="text" class="form-control" id="task-subcategory">
571
+ </div>
572
+ </div>
573
+ <div class="row mb-3">
574
+ <div class="col-md-6">
575
+ <label for="task-start-date" class="form-label">Fecha de inicio</label>
576
+ <input type="date" class="form-control" id="task-start-date" required>
577
+ </div>
578
+ <div class="col-md-6">
579
+ <label for="task-end-date" class="form-label">Fecha de fin</label>
580
+ <input type="date" class="form-control" id="task-end-date">
581
+ </div>
582
+ </div>
583
+ <div class="row mb-3">
584
+ <div class="col-md-6">
585
+ <label for="task-start-time" class="form-label">Hora de inicio</label>
586
+ <input type="time" class="form-control" id="task-start-time">
587
+ </div>
588
+ <div class="col-md-6">
589
+ <label for="task-end-time" class="form-label">Hora de fin</label>
590
+ <input type="time" class="form-control" id="task-end-time">
591
+ </div>
592
+ </div>
593
+ <div class="mb-3">
594
+ <label for="task-description" class="form-label">Descripci贸n</label>
595
+ <textarea class="form-control" id="task-description" rows="5"></textarea>
596
+ </div>
597
+ </form>
598
+
599
+ <div class="mb-3">
600
+ <h6>Comentarios</h6>
601
+ <div id="task-comments">
602
+ <!-- Comments will be loaded here -->
603
+ </div>
604
+ <div class="input-group mt-3">
605
+ <input type="text" class="form-control" id="new-comment" placeholder="Agregar comentario">
606
+ <button class="btn btn-primary" type="button" onclick="addComment()">Agregar</button>
607
+ </div>
608
+ </div>
609
+ </div>
610
+ <div class="modal-footer">
611
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancelar</button>
612
+ <button type="button" class="btn btn-primary" onclick="saveTask()">Guardar Tarea</button>
613
+ </div>
614
+ </div>
615
+ </div>
616
+ </div>
617
+
618
+ <!-- Task Details Modal -->
619
+ <div class="modal fade" id="taskDetailsModal" tabindex="-1" aria-hidden="true">
620
+ <div class="modal-dialog">
621
+ <div class="modal-content">
622
+ <div class="modal-header">
623
+ <h5 class="modal-title" id="taskDetailsTitle">Detalles de la Tarea</h5>
624
+ <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
625
+ </div>
626
+ <div class="modal-body" id="task-details-content">
627
+ <!-- Task details will be loaded here -->
628
+ </div>
629
+ <div class="modal-footer">
630
+ <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cerrar</button>
631
+ <button type="button" class="btn btn-primary" id="edit-task-btn" onclick="editTask()">Editar</button>
632
+ </div>
633
+ </div>
634
+ </div>
635
+ </div>
636
+
637
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
638
+ <script>
639
+ // Global variables
640
+ let tasks = [];
641
+ let currentView = 'dashboard';
642
+ let pomodoroInterval;
643
+ let pomodoroTime = 25 * 60; // 25 minutes in seconds
644
+ let pomodoroSession = 'work'; // 'work' or 'break'
645
+ let pomodoroSessionsCompleted = 0;
646
+ let darkMode = false;
647
+
648
+ // Initialize the application
649
+ document.addEventListener('DOMContentLoaded', function() {
650
+ // Load tasks from localStorage
651
+ loadTasks();
652
+
653
+ // Update current time every second
654
+ updateCurrentTime();
655
+ setInterval(updateCurrentTime, 1000);
656
+
657
+ // Load initial views
658
+ showView('dashboard');
659
+ updateTodayTasks();
660
+ updatePomodoroTimer();
661
+
662
+ // Event listeners
663
+ document.getElementById('darkModeSwitch').addEventListener('change', toggleDarkMode);
664
+ document.getElementById('quick-task-form').addEventListener('submit', addQuickTask);
665
+ document.getElementById('profile-form').addEventListener('submit', saveProfile);
666
+ document.getElementById('task-sort').addEventListener('change', updateTasksView);
667
+ document.getElementById('task-filter').addEventListener('change', updateTasksView);
668
+ document.getElementById('task-search').addEventListener('input', updateTasksView);
669
+
670
+ // Initialize modals
671
+ const taskModal = new bootstrap.Modal(document.getElementById('taskModal'));
672
+ const taskDetailsModal = new bootstrap.Modal(document.getElementById('taskDetailsModal'));
673
+
674
+ // Check for saved dark mode preference
675
+ if (localStorage.getItem('darkMode') === 'true') {
676
+ document.getElementById('darkModeSwitch').checked = true;
677
+ toggleDarkMode();
678
+ }
679
+
680
+ // Load profile data
681
+ loadProfile();
682
+ });
683
+
684
+ // View management
685
+ function showView(viewName) {
686
+ // Hide all views
687
+ document.querySelectorAll('.view').forEach(view => {
688
+ view.style.display = 'none';
689
+ });
690
+
691
+ // Show the selected view
692
+ document.getElementById(`${viewName}-view`).style.display = 'block';
693
+ currentView = viewName;
694
+
695
+ // Update the specific view
696
+ switch(viewName) {
697
+ case 'dashboard':
698
+ updateDashboard();
699
+ break;
700
+ case 'tasks':
701
+ updateTasksView();
702
+ break;
703
+ case 'timeline':
704
+ updateTimelineView();
705
+ break;
706
+ case 'day':
707
+ updateDayView();
708
+ break;
709
+ case 'week':
710
+ updateWeekView();
711
+ break;
712
+ case 'calendar':
713
+ updateCalendarView();
714
+ break;
715
+ case 'metrics':
716
+ updateMetricsView();
717
+ break;
718
+ case 'profile':
719
+ // Already loaded
720
+ break;
721
+ }
722
+ }
723
+
724
+ // Task management
725
+ function loadTasks() {
726
+ const savedTasks = localStorage.getItem('tasks');
727
+ if (savedTasks) {
728
+ tasks = JSON.parse(savedTasks);
729
+ }
730
+ }
731
+
732
+ function saveTasks() {
733
+ localStorage.setItem('tasks', JSON.stringify(tasks));
734
+ }
735
+
736
+ function addTask(task) {
737
+ tasks.push(task);
738
+ saveTasks();
739
+ updateTasksView();
740
+ updateTodayTasks();
741
+ }
742
+
743
+ function updateTask(id, updatedTask) {
744
+ const index = tasks.findIndex(task => task.id === id);
745
+ if (index !== -1) {
746
+ tasks[index] = updatedTask;
747
+ saveTasks();
748
+ updateTasksView();
749
+ updateTodayTasks();
750
+ return true;
751
+ }
752
+ return false;
753
+ }
754
+
755
+ function deleteTask(id) {
756
+ const index = tasks.findIndex(task => task.id === id);
757
+ if (index !== -1) {
758
+ tasks.splice(index, 1);
759
+ saveTasks();
760
+ updateTasksView();
761
+ updateTodayTasks();
762
+ return true;
763
+ }
764
+ return false;
765
+ }
766
+
767
+ function showTaskModal(taskId = null) {
768
+ const modal = bootstrap.Modal.getOrCreateInstance(document.getElementById('taskModal'));
769
+ const form = document.getElementById('task-form');
770
+
771
+ if (taskId) {
772
+ // Edit existing task
773
+ const task = tasks.find(t => t.id === taskId);
774
+ if (task) {
775
+ document.getElementById('taskModalTitle').textContent = 'Editar Tarea';
776
+ document.getElementById('task-id').value = task.id;
777
+ document.getElementById('task-name').value = task.name;
778
+ document.getElementById('task-priority').value = task.priority;
779
+ document.getElementById('task-status').value = task.status || 'pending';
780
+ document.getElementById('task-category').value = task.category || 'work';
781
+ document.getElementById('task-subcategory').value = task.subcategory || '';
782
+ document.getElementById('task-start-date').value = task.startDate || '';
783
+ document.getElementById('task-end-date').value = task.endDate || '';
784
+ document.getElementById('task-start-time').value = task.startTime || '';
785
+ document.getElementById('task-end-time').value = task.endTime || '';
786
+ document.getElementById('task-description').value = task.description || '';
787
+
788
+ // Load comments
789
+ loadComments(task.id);
790
+ }
791
+ } else {
792
+ // Add new task
793
+ document.getElementById('taskModalTitle').textContent = 'Nueva Tarea';
794
+ form.reset();
795
+ document.getElementById('task-id').value = '';
796
+ document.getElementById('task-status').value = 'pending';
797
+ document.getElementById('task-comments').innerHTML = '';
798
+
799
+ // Set default dates
800
+ const today = new Date().toISOString().split('T')[0];
801
+ document.getElementById('task-start-date').value = today;
802
+ }
803
+
804
+ modal.show();
805
+ }
806
+
807
+ function saveTask() {
808
+ const form = document.getElementById('task-form');
809
+ if (!form.checkValidity()) {
810
+ form.reportValidity();
811
+ return;
812
+ }
813
+
814
+ const task = {
815
+ id: document.getElementById('task-id').value || Date.now().toString(),
816
+ name: document.getElementById('task-name').value,
817
+ priority: document.getElementById('task-priority').value,
818
+ status: document.getElementById('task-status').value,
819
+ category: document.getElementById('task-category').value,
820
+ subcategory: document.getElementById('task-subcategory').value,
821
+ startDate: document.getElementById('task-start-date').value,
822
+ endDate: document.getElementById('task-end-date').value,
823
+ startTime: document.getElementById('task-start-time').value,
824
+ endTime: document.getElementById('task-end-time').value,
825
+ description: document.getElementById('task-description').value,
826
+ createdAt: new Date().toISOString()
827
+ };
828
+
829
+ if (task.id) {
830
+ // Update existing task
831
+ updateTask(task.id, task);
832
+ } else {
833
+ // Add new task
834
+ addTask(task);
835
+ }
836
+
837
+ const modal = bootstrap.Modal.getOrCreateInstance(document.getElementById('taskModal'));
838
+ modal.hide();
839
+ }
840
+
841
+ function showTaskDetails(taskId) {
842
+ const task = tasks.find(t => t.id === taskId);
843
+ if (!task) return;
844
+
845
+ const modal = bootstrap.Modal.getOrCreateInstance(document.getElementById('taskDetailsModal'));
846
+ const content = document.getElementById('task-details-content');
847
+
848
+ // Format dates
849
+ const startDate = task.startDate ? new Date(task.startDate).toLocaleDateString() : 'No especificada';
850
+ const endDate = task.endDate ? new Date(task.endDate).toLocaleDateString() : 'No especificada';
851
+
852
+ // Format times
853
+ const startTime = task.startTime || 'No especificada';
854
+ const endTime = task.endTime || 'No especificada';
855
+
856
+ // Priority badge
857
+ let priorityBadge;
858
+ switch(task.priority) {
859
+ case 'low':
860
+ priorityBadge = '<span class="badge bg-success">Baja</span>';
861
+ break;
862
+ case 'medium':
863
+ priorityBadge = '<span class="badge bg-warning text-dark">Media</span>';
864
+ break;
865
+ case 'high':
866
+ priorityBadge = '<span class="badge bg-danger">Alta</span>';
867
+ break;
868
+ }
869
+
870
+ // Status badge
871
+ let statusBadge;
872
+ switch(task.status) {
873
+ case 'pending':
874
+ statusBadge = '<span class="badge bg-secondary">Pendiente</span>';
875
+ break;
876
+ case 'in-progress':
877
+ statusBadge = '<span class="badge bg-primary">En progreso</span>';
878
+ break;
879
+ case 'completed':
880
+ statusBadge = '<span class="badge bg-success">Completada</span>';
881
+ break;
882
+ }
883
+
884
+ // Build the content
885
+ content.innerHTML = `
886
+ <h5>${task.name}</h5>
887
+ <div class="mb-3">
888
+ ${priorityBadge} ${statusBadge}
889
+ </div>
890
+ <div class="mb-3">
891
+ <strong>Categor铆a:</strong> ${task.category} ${task.subcategory ? `(${task.subcategory})` : ''}
892
+ </div>
893
+ <div class="row mb-3">
894
+ <div class="col-md-6">
895
+ <strong>Fecha inicio:</strong> ${startDate}
896
+ </div>
897
+ <div class="col-md-6">
898
+ <strong>Fecha fin:</strong> ${endDate}
899
+ </div>
900
+ </div>
901
+ <div class="row mb-3">
902
+ <div class="col-md-6">
903
+ <strong>Hora inicio:</strong> ${startTime}
904
+ </div>
905
+ <div class="col-md-6">
906
+ <strong>Hora fin:</strong> ${endTime}
907
+ </div>
908
+ </div>
909
+ <div class="mb-3">
910
+ <strong>Descripci贸n:</strong>
911
+ <p>${task.description || 'No hay descripci贸n.'}</p>
912
+ </div>
913
+ <div class="mb-3">
914
+ <strong>Comentarios:</strong>
915
+ <div id="details-comments">
916
+ ${task.comments && task.comments.length > 0 ?
917
+ task.comments.map(c => `<div class="card mb-2"><div class="card-body p-2">${c.text}</div></div>`).join('') :
918
+ '<p>No hay comentarios.</p>'}
919
+ </div>
920
+ </div>
921
+ `;
922
+
923
+ // Set the edit button to edit this task
924
+ document.getElementById('edit-task-btn').setAttribute('data-task-id', task.id);
925
+
926
+ modal.show();
927
+ }
928
+
929
+ function editTask() {
930
+ const taskId = document.getElementById('edit-task-btn').getAttribute('data-task-id');
931
+ const modal = bootstrap.Modal.getOrCreateInstance(document.getElementById('taskDetailsModal'));
932
+ modal.hide();
933
+
934
+ showTaskModal(taskId);
935
+ }
936
+
937
+ function addQuickTask(e) {
938
+ e.preventDefault();
939
+
940
+ const name = document.getElementById('quick-task-name').value;
941
+ const priority = document.getElementById('quick-task-priority').value;
942
+ const today = new Date().toISOString().split('T')[0];
943
+
944
+ const task = {
945
+ id: Date.now().toString(),
946
+ name: name,
947
+ priority: priority,
948
+ status: 'pending',
949
+ category: 'personal',
950
+ startDate: today,
951
+ createdAt: new Date().toISOString()
952
+ };
953
+
954
+ addTask(task);
955
+ document.getElementById('quick-task-form').reset();
956
+ }
957
+
958
+ function addComment() {
959
+ const commentInput = document.getElementById('new-comment');
960
+ const commentText = commentInput.value.trim();
961
+ const taskId = document.getElementById('task-id').value;
962
+
963
+ if (!commentText) return;
964
+
965
+ const task = tasks.find(t => t.id === taskId);
966
+ if (!task) return;
967
+
968
+ if (!task.comments) {
969
+ task.comments = [];
970
+ }
971
+
972
+ task.comments.push({
973
+ text: commentText,
974
+ date: new Date().toISOString()
975
+ });
976
+
977
+ saveTasks();
978
+ loadComments(taskId);
979
+ commentInput.value = '';
980
+ }
981
+
982
+ function loadComments(taskId) {
983
+ const task = tasks.find(t => t.id === taskId);
984
+ if (!task) return;
985
+
986
+ const commentsContainer = document.getElementById('task-comments');
987
+ commentsContainer.innerHTML = '';
988
+
989
+ if (task.comments && task.comments.length > 0) {
990
+ task.comments.forEach(comment => {
991
+ const commentElement = document.createElement('div');
992
+ commentElement.className = 'card mb-2';
993
+ commentElement.innerHTML = `
994
+ <div class="card-body p-2">
995
+ ${comment.text}
996
+ </div>
997
+ `;
998
+ commentsContainer.appendChild(commentElement);
999
+ });
1000
+ } else {
1001
+ commentsContainer.innerHTML = '<p>No hay comentarios.</p>';
1002
+ }
1003
+ }
1004
+
1005
+ // View updates
1006
+ function updateDashboard() {
1007
+ updateTodayTasks();
1008
+ updatePomodoroTimer();
1009
+ updateStats();
1010
+ }
1011
+
1012
+ function updateTasksView() {
1013
+ const container = document.getElementById('tasks-container');
1014
+ container.innerHTML = '';
1015
+
1016
+ const sortBy = document.getElementById('task-sort').value;
1017
+ const filterBy = document.getElementById('task-filter').value;
1018
+ const searchText = document.getElementById('task-search').value.toLowerCase();
1019
+
1020
+ // Filter tasks
1021
+ let filteredTasks = [...tasks];
1022
+
1023
+ // Apply search filter
1024
+ if (searchText) {
1025
+ filteredTasks = filteredTasks.filter(task =>
1026
+ task.name.toLowerCase().includes(searchText) ||
1027
+ (task.description && task.description.toLowerCase().includes(searchText))
1028
+ );
1029
+ }
1030
+
1031
+ // Apply status filter
1032
+ switch(filterBy) {
1033
+ case 'today':
1034
+ const today = new Date().toISOString().split('T')[0];
1035
+ filteredTasks = filteredTasks.filter(task => task.startDate === today);
1036
+ break;
1037
+ case 'week':
1038
+ const currentWeek = getWeekNumber(new Date());
1039
+ filteredTasks = filteredTasks.filter(task => {
1040
+ const taskDate = new Date(task.startDate);
1041
+ return getWeekNumber(taskDate) === currentWeek;
1042
+ });
1043
+ break;
1044
+ case 'completed':
1045
+ filteredTasks = filteredTasks.filter(task => task.status === 'completed');
1046
+ break;
1047
+ case 'pending':
1048
+ filteredTasks = filteredTasks.filter(task => task.status !== 'completed');
1049
+ break;
1050
+ // 'all' - no filter
1051
+ }
1052
+
1053
+ // Sort tasks
1054
+ switch(sortBy) {
1055
+ case 'date':
1056
+ filteredTasks.sort((a, b) => new Date(a.startDate) - new Date(b.startDate));
1057
+ break;
1058
+ case 'priority':
1059
+ const priorityOrder = { high: 1, medium: 2, low: 3 };
1060
+ filteredTasks.sort((a, b) => priorityOrder[a.priority] - priorityOrder[b.priority]);
1061
+ break;
1062
+ case 'category':
1063
+ filteredTasks.sort((a, b) => a.category.localeCompare(b.category));
1064
+ break;
1065
+ }
1066
+
1067
+ // Display tasks
1068
+ if (filteredTasks.length === 0) {
1069
+ container.innerHTML = '<div class="col-12"><p>No hay tareas que mostrar.</p></div>';
1070
+ return;
1071
+ }
1072
+
1073
+ filteredTasks.forEach(task => {
1074
+ const taskElement = document.createElement('div');
1075
+ taskElement.className = 'col-md-6 col-lg-4 mb-4';
1076
+
1077
+ // Priority class
1078
+ let priorityClass;
1079
+ switch(task.priority) {
1080
+ case 'low':
1081
+ priorityClass = 'priority-low';
1082
+ break;
1083
+ case 'medium':
1084
+ priorityClass = 'priority-medium';
1085
+ break;
1086
+ case 'high':
1087
+ priorityClass = 'priority-high';
1088
+ break;
1089
+ }
1090
+
1091
+ // Status badge
1092
+ let statusBadge;
1093
+ switch(task.status) {
1094
+ case 'pending':
1095
+ statusBadge = '<span class="badge bg-secondary">Pendiente</span>';
1096
+ break;
1097
+ case 'in-progress':
1098
+ statusBadge = '<span class="badge bg-primary">En progreso</span>';
1099
+ break;
1100
+ case 'completed':
1101
+ statusBadge = '<span class="badge bg-success">Completada</span>';
1102
+ break;
1103
+ }
1104
+
1105
+ // Format date
1106
+ const taskDate = task.startDate ? new Date(task.startDate).toLocaleDateString() : 'Sin fecha';
1107
+
1108
+ taskElement.innerHTML = `
1109
+ <div class="card task-card ${priorityClass}" onclick="showTaskDetails('${task.id}')">
1110
+ <div class="card-body">
1111
+ <h5 class="card-title">${task.name}</h5>
1112
+ <div class="d-flex justify-content-between mb-2">
1113
+ <span class="text-muted">${taskDate}</span>
1114
+ ${statusBadge}
1115
+ </div>
1116
+ <p class="card-text">${task.description ? task.description.substring(0, 100) + (task.description.length > 100 ? '...' : '') : 'Sin descripci贸n'}</p>
1117
+ <div class="d-flex justify-content-between">
1118
+ <span class="badge bg-light text-dark">${task.category}</span>
1119
+ <button class="btn btn-sm btn-outline-danger" onclick="event.stopPropagation(); deleteTask('${task.id}')">Eliminar</button>
1120
+ </div>
1121
+ </div>
1122
+ </div>
1123
+ `;
1124
+
1125
+ container.appendChild(taskElement);
1126
+ });
1127
+ }
1128
+
1129
+ function updateTodayTasks() {
1130
+ const container = document.getElementById('today-tasks');
1131
+ container.innerHTML = '';
1132
+
1133
+ const today = new Date().toISOString().split('T')[0];
1134
+ const todayTasks = tasks.filter(task => task.startDate === today);
1135
+
1136
+ if (todayTasks.length === 0) {
1137
+ container.innerHTML = '<p>No hay tareas para hoy.</p>';
1138
+ return;
1139
+ }
1140
+
1141
+ todayTasks.forEach(task => {
1142
+ const taskElement = document.createElement('div');
1143
+ taskElement.className = 'mb-3';
1144
+
1145
+ // Priority class
1146
+ let priorityClass;
1147
+ switch(task.priority) {
1148
+ case 'low':
1149
+ priorityClass = 'priority-low';
1150
+ break;
1151
+ case 'medium':
1152
+ priorityClass = 'priority-medium';
1153
+ break;
1154
+ case 'high':
1155
+ priorityClass = 'priority-high';
1156
+ break;
1157
+ }
1158
+
1159
+ // Status badge
1160
+ let statusBadge;
1161
+ switch(task.status) {
1162
+ case 'pending':
1163
+ statusBadge = '<span class="badge bg-secondary">Pendiente</span>';
1164
+ break;
1165
+ case 'in-progress':
1166
+ statusBadge = '<span class="badge bg-primary">En progreso</span>';
1167
+ break;
1168
+ case 'completed':
1169
+ statusBadge = '<span class="badge bg-success">Completada</span>';
1170
+ break;
1171
+ }
1172
+
1173
+ // Time info
1174
+ const timeInfo = task.startTime ?
1175
+ (task.endTime ? `${task.startTime} - ${task.endTime}` : `Desde ${task.startTime}`) :
1176
+ 'Sin hora espec铆fica';
1177
+
1178
+ taskElement.innerHTML = `
1179
+ <div class="card ${priorityClass}">
1180
+ <div class="card-body p-3">
1181
+ <div class="d-flex justify-content-between align-items-center">
1182
+ <h6 class="mb-0">${task.name}</h6>
1183
+ ${statusBadge}
1184
+ </div>
1185
+ <div class="d-flex justify-content-between mt-2">
1186
+ <small class="text-muted">${timeInfo}</small>
1187
+ <div>
1188
+ <button class="btn btn-sm btn-outline-primary" onclick="showTaskDetails('${task.id}')">Detalles</button>
1189
+ <button class="btn btn-sm btn-outline-success" onclick="completeTask('${task.id}')">Completar</button>
1190
+ </div>
1191
+ </div>
1192
+ </div>
1193
+ </div>
1194
+ `;
1195
+
1196
+ container.appendChild(taskElement);
1197
+ });
1198
+ }
1199
+
1200
+ function completeTask(taskId) {
1201
+ const task = tasks.find(t => t.id === taskId);
1202
+ if (task) {
1203
+ task.status = 'completed';
1204
+ saveTasks();
1205
+ updateTodayTasks();
1206
+ updateTasksView();
1207
+ }
1208
+ }
1209
+
1210
+ function updateTimelineView() {
1211
+ const container = document.getElementById('timeline-container');
1212
+ const title = document.getElementById('timeline-title');
1213
+ const dateDisplay = document.getElementById('timeline-date');
1214
+
1215
+ // Clear existing items except the current time indicator
1216
+ container.innerHTML = '<div class="current-time" id="current-time-indicator"></div>';
1217
+
1218
+ // Get today's tasks with time
1219
+ const today = new Date().toISOString().split('T')[0];
1220
+ const todayTasks = tasks.filter(task =>
1221
+ task.startDate === today && task.startTime
1222
+ ).sort((a, b) => {
1223
+ // Sort by time
1224
+ const timeA = a.startTime.split(':').map(Number);
1225
+ const timeB = b.startTime.split(':').map(Number);
1226
+ return (timeA[0] * 60 + timeA[1]) - (timeB[0] * 60 + timeB[1]);
1227
+ });
1228
+
1229
+ title.textContent = 'Hoy';
1230
+ dateDisplay.textContent = new Date().toLocaleDateString();
1231
+
1232
+ if (todayTasks.length === 0) {
1233
+ const noTasks = document.createElement('div');
1234
+ noTasks.className = 'alert alert-info';
1235
+ noTasks.textContent = 'No hay tareas programadas para hoy con hora espec铆fica.';
1236
+ container.appendChild(noTasks);
1237
+ return;
1238
+ }
1239
+
1240
+ todayTasks.forEach(task => {
1241
+ const item = document.createElement('div');
1242
+ item.className = 'timeline-item';
1243
+
1244
+ // Priority dot
1245
+ let priorityDot;
1246
+ switch(task.priority) {
1247
+ case 'low':
1248
+ priorityDot = 'bg-success';
1249
+ break;
1250
+ case 'medium':
1251
+ priorityDot = 'bg-warning';
1252
+ break;
1253
+ case 'high':
1254
+ priorityDot = 'bg-danger';
1255
+ break;
1256
+ }
1257
+
1258
+ // Status badge
1259
+ let statusBadge;
1260
+ switch(task.status) {
1261
+ case 'pending':
1262
+ statusBadge = '<span class="badge bg-secondary">Pendiente</span>';
1263
+ break;
1264
+ case 'in-progress':
1265
+ statusBadge = '<span class="badge bg-primary">En progreso</span>';
1266
+ break;
1267
+ case 'completed':
1268
+ statusBadge = '<span class="badge bg-success">Completada</span>';
1269
+ break;
1270
+ }
1271
+
1272
+ // Time range
1273
+ const timeRange = task.endTime ?
1274
+ `${task.startTime} - ${task.endTime}` :
1275
+ `Desde ${task.startTime}`;
1276
+
1277
+ item.innerHTML = `
1278
+ <div class="card">
1279
+ <div class="card-body">
1280
+ <div class="d-flex justify-content-between align-items-center mb-2">
1281
+ <h6 class="mb-0">${task.name}</h6>
1282
+ <span class="badge ${priorityDot}">${task.priority}</span>
1283
+ </div>
1284
+ <div class="d-flex justify-content-between align-items-center">
1285
+ <span>${timeRange}</span>
1286
+ ${statusBadge}
1287
+ </div>
1288
+ ${task.description ? `<p class="mt-2 mb-0">${task.description}</p>` : ''}
1289
+ </div>
1290
+ </div>
1291
+ `;
1292
+
1293
+ container.appendChild(item);
1294
+ });
1295
+
1296
+ // Update current time indicator position
1297
+ updateCurrentTimeIndicator();
1298
+ }
1299
+
1300
+ function updateCurrentTimeIndicator() {
1301
+ const now = new Date();
1302
+ const hours = now.getHours();
1303
+ const minutes = now.getMinutes();
1304
+ const totalMinutes = hours * 60 + minutes;
1305
+
1306
+ // Assuming timeline starts at 8:00 AM and ends at 8:00 PM (12 hours)
1307
+ const timelineStart = 8 * 60; // 8:00 AM in minutes
1308
+ const timelineEnd = 20 * 60; // 8:00 PM in minutes
1309
+ const timelineHeight = document.getElementById('timeline-container').offsetHeight;
1310
+
1311
+ if (totalMinutes >= timelineStart && totalMinutes <= timelineEnd) {
1312
+ const position = ((totalMinutes - timelineStart) / (timelineEnd - timelineStart)) * timelineHeight;
1313
+ document.getElementById('current-time-indicator').style.top = `${position}px`;
1314
+ document.getElementById('current-time-indicator').style.display = 'block';
1315
+ } else {
1316
+ document.getElementById('current-time-indicator').style.display = 'none';
1317
+ }
1318
+ }
1319
+
1320
+ function updateDayView() {
1321
+ const container = document.getElementById('day-schedule');
1322
+ const title = document.getElementById('day-title');
1323
+
1324
+ // For now, we'll just show today's schedule
1325
+ const today = new Date();
1326
+ title.textContent = today.toLocaleDateString('es-ES', { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
1327
+
1328
+ // Clear the schedule
1329
+ container.innerHTML = '';
1330
+
1331
+ // Get today's tasks
1332
+ const todayStr = today.toISOString().split('T')[0];
1333
+ const todayTasks = tasks.filter(task => task.startDate === todayStr);
1334
+
1335
+ if (todayTasks.length === 0) {
1336
+ container.innerHTML = '<tr><td colspan="2" class="text-center py-4">No hay tareas programadas para hoy.</td></tr>';
1337
+ return;
1338
+ }
1339
+
1340
+ // Group tasks by hour (simplified for this example)
1341
+ const hours = Array.from({ length: 24 }, (_, i) => i); // 0-23
1342
+
1343
+ hours.forEach(hour => {
1344
+ const hourTasks = todayTasks.filter(task => {
1345
+ if (!task.startTime) return false;
1346
+ const taskHour = parseInt(task.startTime.split(':')[0]);
1347
+ return taskHour === hour;
1348
+ });
1349
+
1350
+ if (hourTasks.length > 0) {
1351
+ const row = document.createElement('tr');
1352
+
1353
+ // Hour cell
1354
+ const hourCell = document.createElement('td');
1355
+ hourCell.textContent = `${hour}:00`;
1356
+ row.appendChild(hourCell);
1357
+
1358
+ // Tasks cell
1359
+ const tasksCell = document.createElement('td');
1360
+
1361
+ hourTasks.forEach(task => {
1362
+ const taskElement = document.createElement('div');
1363
+ taskElement.className = 'mb-2';
1364
+
1365
+ // Priority dot
1366
+ let priorityDot;
1367
+ switch(task.priority) {
1368
+ case 'low':
1369
+ priorityDot = 'bg-success';
1370
+ break;
1371
+ case 'medium':
1372
+ priorityDot = 'bg-warning';
1373
+ break;
1374
+ case 'high':
1375
+ priorityDot = 'bg-danger';
1376
+ break;
1377
+ }
1378
+
1379
+ taskElement.innerHTML = `
1380
+ <div class="d-flex align-items-center">
1381
+ <span class="task-dot ${priorityDot}"></span>
1382
+ <span>${task.name}</span>
1383
+ <button class="btn btn-sm btn-outline-primary ms-auto" onclick="showTaskDetails('${task.id}')">Ver</button>
1384
+ </div>
1385
+ `;
1386
+
1387
+ tasksCell.appendChild(taskElement);
1388
+ });
1389
+
1390
+ row.appendChild(tasksCell);
1391
+ container.appendChild(row);
1392
+ }
1393
+ });
1394
+ }
1395
+
1396
+ function updateWeekView() {
1397
+ const title = document.getElementById('week-title');
1398
+ const now = new Date();
1399
+ const startOfWeek = getStartOfWeek(now);
1400
+
1401
+ title.textContent = `Semana del ${startOfWeek.toLocaleDateString()} al ${new Date(startOfWeek.getTime() + 6 * 24 * 60 * 60 * 1000).toLocaleDateString()}`;
1402
+
1403
+ // Update each day in the week view
1404
+ for (let i = 0; i < 7; i++) {
1405
+ const day = new Date(startOfWeek.getTime() + i * 24 * 60 * 60 * 1000);
1406
+ const dayStr = day.toISOString().split('T')[0];
1407
+ const dayElement = document.getElementById(`week-day-${i}`);
1408
+
1409
+ // Clear the day
1410
+ dayElement.innerHTML = '';
1411
+
1412
+ // Add day header
1413
+ const header = document.createElement('div');
1414
+ header.className = 'calendar-day-header';
1415
+ header.textContent = day.toLocaleDateString('es-ES', { weekday: 'short', day: 'numeric' });
1416
+ dayElement.appendChild(header);
1417
+
1418
+ // Check if it's today
1419
+ const today = new Date().toISOString().split('T')[0];
1420
+ if (dayStr === today) {
1421
+ dayElement.classList.add('today');
1422
+ } else {
1423
+ dayElement.classList.remove('today');
1424
+ }
1425
+
1426
+ // Get tasks for this day
1427
+ const dayTasks = tasks.filter(task => task.startDate === dayStr);
1428
+
1429
+ if (dayTasks.length === 0) {
1430
+ const noTasks = document.createElement('div');
1431
+ noTasks.className = 'text-muted small';
1432
+ noTasks.textContent = 'Sin tareas';
1433
+ dayElement.appendChild(noTasks);
1434
+ continue;
1435
+ }
1436
+
1437
+ // Add tasks to the day
1438
+ dayTasks.forEach(task => {
1439
+ const taskElement = document.createElement('div');
1440
+ taskElement.className = 'small mb-1';
1441
+
1442
+ // Priority dot
1443
+ let priorityDot;
1444
+ switch(task.priority) {
1445
+ case 'low':
1446
+ priorityDot = 'bg-success';
1447
+ break;
1448
+ case 'medium':
1449
+ priorityDot = 'bg-warning';
1450
+ break;
1451
+ case 'high':
1452
+ priorityDot = 'bg-danger';
1453
+ break;
1454
+ }
1455
+
1456
+ taskElement.innerHTML = `
1457
+ <span class="task-dot ${priorityDot}"></span>
1458
+ ${task.name}
1459
+ `;
1460
+
1461
+ dayElement.appendChild(taskElement);
1462
+ });
1463
+ }
1464
+ }
1465
+
1466
+ function updateCalendarView() {
1467
+ const title = document.getElementById('calendar-title');
1468
+ const now = new Date();
1469
+ const month = now.getMonth();
1470
+ const year = now.getFullYear();
1471
+
1472
+ title.textContent = now.toLocaleDateString('es-ES', { month: 'long', year: 'numeric' });
1473
+
1474
+ // Get first day of month and last day of month
1475
+ const firstDay = new Date(year, month, 1);
1476
+ const lastDay = new Date(year, month + 1, 0);
1477
+
1478
+ // Get days in month
1479
+ const daysInMonth = lastDay.getDate();
1480
+
1481
+ // Get starting day of week (0 = Sunday, 6 = Saturday)
1482
+ const startingDay = firstDay.getDay();
1483
+
1484
+ // Clear calendar
1485
+ const calendarBody = document.getElementById('calendar-body');
1486
+ calendarBody.innerHTML = '';
1487
+
1488
+ let date = 1;
1489
+ let row;
1490
+
1491
+ // Create calendar rows
1492
+ for (let i = 0; i < 6; i++) {
1493
+ // Stop if we've run out of days
1494
+ if (date > daysInMonth) break;
1495
+
1496
+ // Create a new row
1497
+ row = document.createElement('tr');
1498
+
1499
+ // Create cells for each day of the week
1500
+ for (let j = 0; j < 7; j++) {
1501
+ const cell = document.createElement('td');
1502
+
1503
+ // Fill in empty cells before the first day of the month
1504
+ if (i === 0 && j < startingDay) {
1505
+ cell.className = 'calendar-day';
1506
+ row.appendChild(cell);
1507
+ continue;
1508
+ }
1509
+
1510
+ // Stop if we've run out of days
1511
+ if (date > daysInMonth) {
1512
+ cell.className = 'calendar-day';
1513
+ row.appendChild(cell);
1514
+ continue;
1515
+ }
1516
+
1517
+ // Create day cell
1518
+ cell.className = 'calendar-day';
1519
+
1520
+ // Check if it's today
1521
+ const today = new Date();
1522
+ if (date === today.getDate() && month === today.getMonth() && year === today.getFullYear()) {
1523
+ cell.classList.add('today');
1524
+ }
1525
+
1526
+ // Add day number
1527
+ const dayHeader = document.createElement('div');
1528
+ dayHeader.className = 'calendar-day-header';
1529
+ dayHeader.textContent = date;
1530
+ cell.appendChild(dayHeader);
1531
+
1532
+ // Get tasks for this day
1533
+ const dayStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(date).padStart(2, '0')}`;
1534
+ const dayTasks = tasks.filter(task => task.startDate === dayStr);
1535
+
1536
+ // Add tasks to the day
1537
+ dayTasks.forEach(task => {
1538
+ const taskElement = document.createElement('div');
1539
+ taskElement.className = 'small mb-1';
1540
+
1541
+ // Priority dot
1542
+ let priorityDot;
1543
+ switch(task.priority) {
1544
+ case 'low':
1545
+ priorityDot = 'bg-success';
1546
+ break;
1547
+ case 'medium':
1548
+ priorityDot = 'bg-warning';
1549
+ break;
1550
+ case 'high':
1551
+ priorityDot = 'bg-danger';
1552
+ break;
1553
+ }
1554
+
1555
+ taskElement.innerHTML = `
1556
+ <span class="task-dot ${priorityDot}"></span>
1557
+ ${task.name}
1558
+ `;
1559
+
1560
+ cell.appendChild(taskElement);
1561
+ });
1562
+
1563
+ row.appendChild(cell);
1564
+ date++;
1565
+ }
1566
+
1567
+ calendarBody.appendChild(row);
1568
+ }
1569
+ }
1570
+
1571
+ function updateMetricsView() {
1572
+ // In a real app, we would use a charting library like Chart.js
1573
+ // For this example, we'll just show some basic stats
1574
+
1575
+ // Completed tasks this week
1576
+ const currentWeek = getWeekNumber(new Date());
1577
+ const weekTasks = tasks.filter(task => {
1578
+ const taskDate = new Date(task.startDate);
1579
+ return getWeekNumber(taskDate) === currentWeek;
1580
+ });
1581
+
1582
+ const completedThisWeek = weekTasks.filter(task => task.status === 'completed').length;
1583
+
1584
+ // Priority distribution
1585
+ const priorityCounts = {
1586
+ low: tasks.filter(task => task.priority === 'low').length,
1587
+ medium: tasks.filter(task => task.priority === 'medium').length,
1588
+ high: tasks.filter(task => task.priority === 'high').length
1589
+ };
1590
+
1591
+ // For now, we'll just update some text elements
1592
+ // In a real app, we would render charts here
1593
+ console.log('Metrics updated:', {
1594
+ completedThisWeek,
1595
+ priorityCounts
1596
+ });
1597
+ }
1598
+
1599
+ // Pomodoro timer functions
1600
+ function startPomodoro() {
1601
+ document.getElementById('start-btn').disabled = true;
1602
+ document.getElementById('stop-btn').disabled = false;
1603
+
1604
+ pomodoroInterval = setInterval(() => {
1605
+ pomodoroTime--;
1606
+ updatePomodoroTimer();
1607
+
1608
+ if (pomodoroTime <= 0) {
1609
+ clearInterval(pomodoroInterval);
1610
+ pomodoroSessionCompleted();
1611
+ }
1612
+ }, 1000);
1613
+ }
1614
+
1615
+ function stopPomodoro() {
1616
+ clearInterval(pomodoroInterval);
1617
+ document.getElementById('start-btn').disabled = false;
1618
+ document.getElementById('stop-btn').disabled = true;
1619
+ }
1620
+
1621
+ function resetPomodoro() {
1622
+ stopPomodoro();
1623
+ pomodoroTime = pomodoroSession === 'work' ? 25 * 60 : 5 * 60;
1624
+ updatePomodoroTimer();
1625
+ }
1626
+
1627
+ function pomodoroSessionCompleted() {
1628
+ pomodoroSessionsCompleted++;
1629
+
1630
+ if (pomodoroSession === 'work') {
1631
+ // Work session completed, start break
1632
+ pomodoroSession = 'break';
1633
+ pomodoroTime = 5 * 60; // 5 minutes
1634
+ document.getElementById('pomodoro-session').textContent = 'Descanso';
1635
+ alert('隆Sesi贸n de trabajo completada! Toma un descanso de 5 minutos.');
1636
+ } else {
1637
+ // Break completed, start work
1638
+ pomodoroSession = 'work';
1639
+ pomodoroTime = 25 * 60; // 25 minutes
1640
+ document.getElementById('pomodoro-session').textContent = 'Sesi贸n de Trabajo';
1641
+ alert('隆Descanso completado! Volvamos al trabajo.');
1642
+ }
1643
+
1644
+ updateStats();
1645
+ startPomodoro();
1646
+ }
1647
+
1648
+ function updatePomodoroTimer() {
1649
+ const minutes = Math.floor(pomodoroTime / 60);
1650
+ const seconds = pomodoroTime % 60;
1651
+ document.getElementById('pomodoro-timer').textContent =
1652
+ `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`;
1653
+ }
1654
+
1655
+ // Utility functions
1656
+ function updateCurrentTime() {
1657
+ const now = new Date();
1658
+ document.getElementById('current-time').textContent = now.toLocaleTimeString();
1659
+
1660
+ // Update current time indicator in timeline view if it's visible
1661
+ if (currentView === 'timeline') {
1662
+ updateCurrentTimeIndicator();
1663
+ }
1664
+ }
1665
+
1666
+ function getStartOfWeek(date) {
1667
+ const d = new Date(date);
1668
+ const day = d.getDay();
1669
+ const diff = d.getDate() - day + (day === 0 ? -6 : 1); // adjust when day is Sunday
1670
+ return new Date(d.setDate(diff));
1671
+ }
1672
+
1673
+ function getWeekNumber(date) {
1674
+ const d = new Date(date);
1675
+ d.setHours(0, 0, 0, 0);
1676
+ d.setDate(d.getDate() + 3 - (d.getDay() + 6) % 7);
1677
+ const week1 = new Date(d.getFullYear(), 0, 4);
1678
+ return 1 + Math.round(((d - week1) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);
1679
+ }
1680
+
1681
+ function toggleDarkMode() {
1682
+ darkMode = document.getElementById('darkModeSwitch').checked;
1683
+ document.body.classList.toggle('dark-mode', darkMode);
1684
+ localStorage.setItem('darkMode', darkMode);
1685
+ }
1686
+
1687
+ function updateStats() {
1688
+ // Completed today
1689
+ const today = new Date().toISOString().split('T')[0];
1690
+ const completedToday = tasks.filter(task =>
1691
+ task.startDate === today && task.status === 'completed'
1692
+ ).length;
1693
+
1694
+ document.getElementById('completed-today').textContent = completedToday;
1695
+
1696
+ // Pomodoro sessions
1697
+ document.getElementById('pomodoro-sessions').textContent = pomodoroSessionsCompleted;
1698
+
1699
+ // Time worked (simplified for this example)
1700
+ document.getElementById('time-worked').textContent = `${Math.floor(pomodoroSessionsCompleted * 25 / 60)}h ${pomodoroSessionsCompleted * 25 % 60}m`;
1701
+ }
1702
+
1703
+ function changeDay(offset) {
1704
+ // In a real app, we would change the day being viewed
1705
+ console.log('Day changed by', offset);
1706
+ updateDayView();
1707
+ }
1708
+
1709
+ function changeWeek(offset) {
1710
+ // In a real app, we would change the week being viewed
1711
+ console.log('Week changed by', offset);
1712
+ updateWeekView();
1713
+ }
1714
+
1715
+ function changeMonth(offset) {
1716
+ // In a real app, we would change the month being viewed
1717
+ console.log('Month changed by', offset);
1718
+ updateCalendarView();
1719
+ }
1720
+
1721
+ function changeTimelineRange(range) {
1722
+ // In a real app, we would change the timeline range
1723
+ console.log('Timeline range changed to', range);
1724
+ updateTimelineView();
1725
+ }
1726
+
1727
+ function changeMetricsRange(range) {
1728
+ // In a real app, we would change the metrics range
1729
+ console.log('Metrics range changed to', range);
1730
+ updateMetricsView();
1731
+ }
1732
+
1733
+ // Profile functions
1734
+ function loadProfile() {
1735
+ const profile = JSON.parse(localStorage.getItem('profile')) || {
1736
+ name: 'Usuario',
1737
+ email: 'usuario@example.com',
1738
+ darkMode: false
1739
+ };
1740
+
1741
+ document.getElementById('profile-name').value = profile.name;
1742
+ document.getElementById('profile-email').value = profile.email;
1743
+ document.getElementById('profile-dark-mode').checked = profile.darkMode;
1744
+ }
1745
+
1746
+ function saveProfile(e) {
1747
+ e.preventDefault();
1748
+
1749
+ const profile = {
1750
+ name: document.getElementById('profile-name').value,
1751
+ email: document.getElementById('profile-email').value,
1752
+ darkMode: document.getElementById('profile-dark-mode').checked
1753
+ };
1754
+
1755
+ const password = document.getElementById('profile-password').value;
1756
+ const confirmPassword = document.getElementById('profile-confirm-password').value;
1757
+
1758
+ if (password && password !== confirmPassword) {
1759
+ alert('Las contrase帽as no coinciden.');
1760
+ return;
1761
+ }
1762
+
1763
+ if (password) {
1764
+ profile.password = password; // In a real app, you would hash this
1765
+ }
1766
+
1767
+ localStorage.setItem('profile', JSON.stringify(profile));
1768
+
1769
+ // Update dark mode if changed
1770
+ if (profile.darkMode !== darkMode) {
1771
+ darkMode = profile.darkMode;
1772
+ document.getElementById('darkModeSwitch').checked = darkMode;
1773
+ document.body.classList.toggle('dark-mode', darkMode);
1774
+ }
1775
+
1776
+ alert('Perfil actualizado correctamente.');
1777
+ }
1778
+
1779
+ function logout() {
1780
+ // In a real app, you would handle actual logout
1781
+ alert('Sesi贸n cerrada (simulado)');
1782
+ }
1783
+ </script>
1784
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 馃К <a href="https://enzostvs-deepsite.hf.space?remix=butztub/timetimer" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body>
1785
+ </html>