triflix commited on
Commit
a4fcf9e
·
verified ·
1 Parent(s): 3959c3d

Update templates/index.html

Browse files
Files changed (1) hide show
  1. templates/index.html +72 -56
templates/index.html CHANGED
@@ -4,23 +4,51 @@
4
  <meta charset="UTF-8">
5
  <title>Website Status Dashboard</title>
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
 
 
7
  <!-- Tailwind CSS (via CDN) -->
8
  <script src="https://cdn.tailwindcss.com"></script>
9
  <!-- Socket.IO Client -->
10
  <script src="https://cdn.socket.io/4.4.1/socket.io.min.js"></script>
11
  <style>
12
- /* Global retro pixel style */
13
  body, h1, p, button {
14
  font-family: 'VT323', monospace;
15
  }
16
- /* Import a retro pixel font from Google Fonts */
17
- @import url('https://fonts.googleapis.com/css2?family=VT323&display=swap');
18
-
19
- /* Typewriter animation for the header */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  .typewriter {
21
  overflow: hidden;
22
  white-space: nowrap;
23
- border-right: 2px solid #000;
24
  animation: typing 3s steps(30, end), blink-caret 0.75s step-end infinite;
25
  }
26
  @keyframes typing {
@@ -29,10 +57,9 @@
29
  }
30
  @keyframes blink-caret {
31
  from, to { border-color: transparent; }
32
- 50% { border-color: #000; }
33
  }
34
-
35
- /* Fade in animation for status updates */
36
  .fade-in {
37
  animation: fadeIn 0.8s ease-in-out;
38
  }
@@ -40,41 +67,34 @@
40
  from { opacity: 0; }
41
  to { opacity: 1; }
42
  }
43
-
44
- /* Minimal hover animation for buttons */
45
- .retro-btn {
46
- border: 2px solid #000;
47
- transition: all 0.2s ease-in-out;
48
- }
49
- .retro-btn:hover,
50
- .retro-btn:focus {
51
- background-color: #000;
52
- color: #fff;
53
- transform: scale(1.05);
54
- }
55
  </style>
56
  </head>
57
- <body class="bg-gray-100">
58
- <div class="container mx-auto p-4">
59
- <h1 class="text-3xl font-bold mb-4 text-center typewriter">Website Status Dashboard</h1>
60
- <div id="status" class="bg-white shadow rounded p-4 mb-4 fade-in">
 
 
 
 
61
  <!-- Render initial statuses from backend -->
62
  {% for url, status in statuses.items() %}
63
- <div class="border-b py-2">
64
- <p class="font-mono text-sm">
65
  <strong>{{ url }}</strong>:
66
- <span class="{{ 'text-green-500' if status else 'text-red-500' }}">
67
  {{ 'Available' if status else 'Not Available' }}
68
  </span>
69
  </p>
70
  </div>
71
  {% endfor %}
72
  </div>
73
- <div class="flex items-center justify-center mb-4">
74
- <button id="toggleTimer" class="retro-btn bg-blue-500 text-white px-4 py-2 rounded mr-4">
 
75
  Hide Countdown
76
  </button>
77
- <div id="countdownTimer" class="text-xl font-semibold">
78
  Next check in: <span id="countdown">--m --s</span>
79
  </div>
80
  </div>
@@ -91,31 +111,28 @@
91
  }
92
 
93
  // Retrieve or generate a persistent client_id.
94
- let client_id = localStorage.getItem("client_id");
95
- if (!client_id) {
96
- client_id = "";
97
- }
98
-
99
  // Connect to the Socket.IO server with the client_id as a query parameter.
100
  const socket = io({
101
  query: { client_id: client_id }
102
  });
103
-
104
- // If the server sends a new client_id, store it.
105
  socket.on("set_client_id", (data) => {
106
  if (data.client_id) {
107
  localStorage.setItem("client_id", data.client_id);
108
  console.log("Assigned new client_id:", data.client_id);
109
  }
110
  });
111
-
112
  // Global variable for next check timestamp.
113
  let nextCheckTimestamp = 0;
114
-
115
  // Countdown update function.
116
  function updateCountdown() {
117
  if (nextCheckTimestamp > 0) {
118
- const now = Date.now() / 1000; // seconds
119
  let diff = nextCheckTimestamp - now;
120
  if (diff < 0) diff = 0;
121
  const minutes = Math.floor(diff / 60);
@@ -125,30 +142,29 @@
125
  }
126
  // Update countdown every second.
127
  setInterval(updateCountdown, 1000);
128
-
129
  // Listen for realtime status updates.
130
  socket.on("status_update", (data) => {
131
  console.log("Status update received:", data);
132
- // Update next check timestamp (assuming backend sends in seconds)
133
  nextCheckTimestamp = data.next_check;
134
  let htmlContent = "";
135
  let message = "";
136
  for (const [url, status] of Object.entries(data.statuses)) {
137
  const statusText = status ? "Available" : "Not Available";
138
- const colorClass = status ? "text-green-500" : "text-red-500";
139
  message += `${url}: ${statusText}\n`;
140
- htmlContent += `<div class="border-b py-2">
141
- <p class="font-mono text-sm">
142
  <strong>${url}</strong>:
143
- <span class="${colorClass}">${statusText}</span>
144
  </p>
145
  </div>`;
146
  }
147
- // Add fade-in effect when updating the status container
148
  const statusDiv = document.getElementById("status");
149
  statusDiv.innerHTML = htmlContent;
150
  statusDiv.classList.remove("fade-in");
151
- // Force reflow to restart animation
152
  void statusDiv.offsetWidth;
153
  statusDiv.classList.add("fade-in");
154
 
@@ -157,23 +173,23 @@
157
  new Notification("Website Status Update", { body: message });
158
  }
159
  });
160
-
161
  // Listen for cached notifications delivered upon reconnect.
162
  socket.on("notification", (data) => {
163
  if (data.message && Notification.permission === "granted") {
164
  new Notification("Missed Website Status Update", { body: data.message });
165
  }
166
  });
167
-
168
  // Toggle the countdown timer display.
169
  document.getElementById("toggleTimer").addEventListener("click", function() {
170
- let timerDiv = document.getElementById("countdownTimer");
171
- if (timerDiv.style.display === "none" || timerDiv.style.display === "") {
172
- timerDiv.style.display = "block";
173
- this.textContent = "Hide Countdown";
174
- } else {
175
  timerDiv.style.display = "none";
176
  this.textContent = "Show Countdown";
 
 
 
177
  }
178
  });
179
  </script>
 
4
  <meta charset="UTF-8">
5
  <title>Website Status Dashboard</title>
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <!-- Google Fonts: VT323 for a retro/dot-matrix look -->
8
+ <link href="https://fonts.googleapis.com/css2?family=VT323&display=swap" rel="stylesheet">
9
  <!-- Tailwind CSS (via CDN) -->
10
  <script src="https://cdn.tailwindcss.com"></script>
11
  <!-- Socket.IO Client -->
12
  <script src="https://cdn.socket.io/4.4.1/socket.io.min.js"></script>
13
  <style>
14
+ /* Global Nothing OS-inspired style */
15
  body, h1, p, button {
16
  font-family: 'VT323', monospace;
17
  }
18
+ /* Dark, minimalist background with a subtle dotted texture */
19
+ body {
20
+ background-color: #121212;
21
+ background-image: radial-gradient(#1e1e1e 1px, transparent 1px);
22
+ background-size: 20px 20px;
23
+ color: #fff;
24
+ }
25
+ /* Container styling similar to Nothing OS cards */
26
+ .nothing-card {
27
+ background-color: #1f1f1f;
28
+ border: 1px solid #333;
29
+ border-radius: 8px;
30
+ padding: 1.5rem;
31
+ box-shadow: 0 2px 6px rgba(0,0,0,0.8);
32
+ }
33
+ /* Minimal button style */
34
+ .nothing-btn {
35
+ background-color: transparent;
36
+ border: 1px solid #fff;
37
+ padding: 0.75rem 1.5rem;
38
+ border-radius: 4px;
39
+ transition: background-color 0.2s, transform 0.2s;
40
+ }
41
+ .nothing-btn:hover,
42
+ .nothing-btn:focus {
43
+ background-color: #fff;
44
+ color: #121212;
45
+ transform: scale(1.05);
46
+ }
47
+ /* Typewriter animation for header (optional retro effect) */
48
  .typewriter {
49
  overflow: hidden;
50
  white-space: nowrap;
51
+ border-right: 2px solid #fff;
52
  animation: typing 3s steps(30, end), blink-caret 0.75s step-end infinite;
53
  }
54
  @keyframes typing {
 
57
  }
58
  @keyframes blink-caret {
59
  from, to { border-color: transparent; }
60
+ 50% { border-color: #fff; }
61
  }
62
+ /* Fade-in animation for status updates */
 
63
  .fade-in {
64
  animation: fadeIn 0.8s ease-in-out;
65
  }
 
67
  from { opacity: 0; }
68
  to { opacity: 1; }
69
  }
 
 
 
 
 
 
 
 
 
 
 
 
70
  </style>
71
  </head>
72
+ <body>
73
+ <div class="max-w-3xl mx-auto p-6">
74
+ <!-- Header with typewriter animation -->
75
+ <h1 class="text-3xl sm:text-4xl font-bold mb-6 text-center typewriter">
76
+ Website Status Dashboard
77
+ </h1>
78
+ <!-- Status Card -->
79
+ <div id="status" class="nothing-card mb-6 fade-in overflow-x-auto">
80
  <!-- Render initial statuses from backend -->
81
  {% for url, status in statuses.items() %}
82
+ <div class="border-b border-gray-700 py-2">
83
+ <p class="font-mono text-sm sm:text-base">
84
  <strong>{{ url }}</strong>:
85
+ <span class="{{ 'text-green-400' if status else 'text-red-400' }} font-bold">
86
  {{ 'Available' if status else 'Not Available' }}
87
  </span>
88
  </p>
89
  </div>
90
  {% endfor %}
91
  </div>
92
+ <!-- Timer and Button Row -->
93
+ <div class="flex flex-col sm:flex-row items-center justify-center gap-4">
94
+ <button id="toggleTimer" class="nothing-btn text-lg w-full sm:w-auto">
95
  Hide Countdown
96
  </button>
97
+ <div id="countdownTimer" class="text-xl sm:text-2xl font-semibold text-center">
98
  Next check in: <span id="countdown">--m --s</span>
99
  </div>
100
  </div>
 
111
  }
112
 
113
  // Retrieve or generate a persistent client_id.
114
+ let client_id = localStorage.getItem("client_id") || "";
115
+
 
 
 
116
  // Connect to the Socket.IO server with the client_id as a query parameter.
117
  const socket = io({
118
  query: { client_id: client_id }
119
  });
120
+
121
+ // Store new client_id if received from server.
122
  socket.on("set_client_id", (data) => {
123
  if (data.client_id) {
124
  localStorage.setItem("client_id", data.client_id);
125
  console.log("Assigned new client_id:", data.client_id);
126
  }
127
  });
128
+
129
  // Global variable for next check timestamp.
130
  let nextCheckTimestamp = 0;
131
+
132
  // Countdown update function.
133
  function updateCountdown() {
134
  if (nextCheckTimestamp > 0) {
135
+ const now = Date.now() / 1000; // current time in seconds
136
  let diff = nextCheckTimestamp - now;
137
  if (diff < 0) diff = 0;
138
  const minutes = Math.floor(diff / 60);
 
142
  }
143
  // Update countdown every second.
144
  setInterval(updateCountdown, 1000);
145
+
146
  // Listen for realtime status updates.
147
  socket.on("status_update", (data) => {
148
  console.log("Status update received:", data);
149
+ // Update next check timestamp (assumed in seconds)
150
  nextCheckTimestamp = data.next_check;
151
  let htmlContent = "";
152
  let message = "";
153
  for (const [url, status] of Object.entries(data.statuses)) {
154
  const statusText = status ? "Available" : "Not Available";
155
+ const colorClass = status ? "text-green-400" : "text-red-400";
156
  message += `${url}: ${statusText}\n`;
157
+ htmlContent += `<div class="border-b border-gray-700 py-2">
158
+ <p class="font-mono text-sm sm:text-base">
159
  <strong>${url}</strong>:
160
+ <span class="${colorClass} font-bold">${statusText}</span>
161
  </p>
162
  </div>`;
163
  }
 
164
  const statusDiv = document.getElementById("status");
165
  statusDiv.innerHTML = htmlContent;
166
  statusDiv.classList.remove("fade-in");
167
+ // Trigger reflow to restart fade-in animation
168
  void statusDiv.offsetWidth;
169
  statusDiv.classList.add("fade-in");
170
 
 
173
  new Notification("Website Status Update", { body: message });
174
  }
175
  });
176
+
177
  // Listen for cached notifications delivered upon reconnect.
178
  socket.on("notification", (data) => {
179
  if (data.message && Notification.permission === "granted") {
180
  new Notification("Missed Website Status Update", { body: data.message });
181
  }
182
  });
183
+
184
  // Toggle the countdown timer display.
185
  document.getElementById("toggleTimer").addEventListener("click", function() {
186
+ const timerDiv = document.getElementById("countdownTimer");
187
+ if (!timerDiv.style.display || timerDiv.style.display === "block") {
 
 
 
188
  timerDiv.style.display = "none";
189
  this.textContent = "Show Countdown";
190
+ } else {
191
+ timerDiv.style.display = "block";
192
+ this.textContent = "Hide Countdown";
193
  }
194
  });
195
  </script>