|
| 1 | +<!-- |
1 | 2 | <!DOCTYPE html> |
2 | 3 | <html lang="en"> |
3 | 4 | <head> |
4 | 5 | <meta charset="UTF-8" /> |
5 | 6 | <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
6 | 7 |
|
7 | | - <!-- Font Awesome --> |
| 8 | + <!– Font Awesome –> |
8 | 9 | <link |
9 | 10 | rel="stylesheet" |
10 | 11 | href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" |
11 | 12 | /> |
12 | 13 |
|
13 | | - <!-- Favicons --> |
| 14 | + <!– Favicons –> |
14 | 15 | <link |
15 | 16 | rel="icon" type="image/png" |
16 | 17 | href="{{ '/assets/favicon-96x96.png' | relative_url }}" |
|
192 | 193 | </head> |
193 | 194 |
|
194 | 195 | <body> |
195 | | -<!-- Dark Mode & Timezone Controls --> |
| 196 | +<!– Dark Mode & Timezone Controls –> |
196 | 197 | <div id="theme-time-container"> |
197 | 198 | <button class="dark-toggle" onclick="toggleDarkMode()" aria-label="Toggle Dark Mode"> |
198 | 199 | <i class="fas fa-moon"></i> |
|
203 | 204 | </div> |
204 | 205 | </div> |
205 | 206 |
|
206 | | -<!-- Onboarding Tooltip --> |
| 207 | +<!– Onboarding Tooltip –> |
207 | 208 | <div id="tooltip" class="tooltip"> |
208 | 209 | Single tap to hide sidebar, double tap to show |
209 | 210 | </div> |
210 | 211 |
|
211 | | -<!-- Collapsible Sidebar --> |
| 212 | +<!– Collapsible Sidebar –> |
212 | 213 | <div id="sidebar" class="sidebar"> |
213 | 214 | <a href="{{ site.baseurl }}/" class="sidebar-link active"> |
214 | 215 | <i class="fas fa-home"></i> Home |
|
225 | 226 | </a> |
226 | 227 | </div> |
227 | 228 |
|
| 229 | +<!– Toggle Button (Fallback) –> |
| 230 | +<button class="toggle-btn" onclick="toggleSidebar(!document.getElementById('sidebar').classList.contains('hidden'))" aria-label="Toggle Sidebar"> |
| 231 | + <i class="fas fa-bars"></i> |
| 232 | +</button> |
| 233 | +
|
| 234 | +<!– Main Content –> |
| 235 | +<div class="wrapper"> |
| 236 | + <div class="content"> |
| 237 | + <div class="fade-in"> |
| 238 | + {{ content }} |
| 239 | + </div> |
| 240 | + </div> |
| 241 | +</div> |
| 242 | +</body> |
| 243 | +</html> |
| 244 | +--> |
| 245 | + |
| 246 | +<!DOCTYPE html> |
| 247 | +<html lang="en"> |
| 248 | +<head> |
| 249 | + <meta charset="UTF-8" /> |
| 250 | + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> |
| 251 | + |
| 252 | + <!-- Font Awesome --> |
| 253 | + <link |
| 254 | + rel="stylesheet" |
| 255 | + href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" |
| 256 | + /> |
| 257 | + |
| 258 | + <!-- Favicons --> |
| 259 | + <link |
| 260 | + rel="icon" type="image/png" |
| 261 | + href="{{ '/assets/favicon-96x96.png' | relative_url }}" |
| 262 | + sizes="96x96" |
| 263 | + /> |
| 264 | + <link |
| 265 | + rel="icon" type="image/svg+xml" |
| 266 | + href="{{ '/assets/favicon.svg' | relative_url }}" |
| 267 | + /> |
| 268 | + <link |
| 269 | + rel="shortcut icon" |
| 270 | + href="{{ '/assets/favicon.ico' | relative_url }}" |
| 271 | + /> |
| 272 | + <link |
| 273 | + rel="apple-touch-icon" |
| 274 | + sizes="180x180" |
| 275 | + href="{{ '/assets/apple-touch-icon.png' | relative_url }}" |
| 276 | + /> |
| 277 | + <meta name="apple-mobile-web-app-title" content="Java" /> |
| 278 | + <link |
| 279 | + rel="manifest" |
| 280 | + href="/JavaEvolution-Learning-Growing-Mastering/assets/site.webmanifest" |
| 281 | + /> |
| 282 | + <meta name="theme-color" content="#ffffff" /> |
| 283 | + |
| 284 | + <title>{{ page.title }}</title> |
| 285 | + <link |
| 286 | + rel="stylesheet" |
| 287 | + href="{{ '/assets/style.css' | relative_url }}" |
| 288 | + /> |
| 289 | + |
| 290 | + <script> |
| 291 | + // Current timezone tracker |
| 292 | + let currentZone = 'IST'; |
| 293 | + let tapCount = 0; |
| 294 | + let tapTimer = null; |
| 295 | + const TAP_TIMEOUT = 300; // ms for double-tap detection |
| 296 | + const SCROLL_THRESHOLD = 100; // px to hide theme/time container |
| 297 | + |
| 298 | + // Update active link based on URL |
| 299 | + function updateActiveLink() { |
| 300 | + const currentPath = window.location.pathname; |
| 301 | + document.querySelectorAll('.sidebar-link').forEach(link => { |
| 302 | + link.classList.remove('active'); |
| 303 | + if (link.getAttribute('href') === currentPath || |
| 304 | + (currentPath === '/' && link.getAttribute('href') === '{{ site.baseurl }}/')) { |
| 305 | + link.classList.add('active'); |
| 306 | + } |
| 307 | + }); |
| 308 | + } |
| 309 | + |
| 310 | + // Sidebar toggle |
| 311 | + function toggleSidebar(isHidden) { |
| 312 | + const sidebar = document.getElementById('sidebar'); |
| 313 | + const toggleBtn = document.querySelector('.toggle-btn'); |
| 314 | + sidebar.classList.toggle('hidden', isHidden); |
| 315 | + localStorage.setItem('sidebar-hidden', isHidden); |
| 316 | + if (window.innerWidth > 768) { |
| 317 | + toggleBtn.style.display = isHidden ? 'block' : 'none'; |
| 318 | + } |
| 319 | + // Update active link after toggle (for visibility) |
| 320 | + updateActiveLink(); |
| 321 | + } |
| 322 | + |
| 323 | + // Handle tap/click events |
| 324 | + function handleTap(event) { |
| 325 | + const sidebar = document.getElementById('sidebar'); |
| 326 | + const target = event.target; |
| 327 | + |
| 328 | + // Allow taps outside interactive elements to trigger hide/show |
| 329 | + if ( |
| 330 | + target.closest('#sidebar') || |
| 331 | + target.closest('#theme-time-container') || |
| 332 | + target.closest('.toggle-btn') || |
| 333 | + target.closest('.tooltip') |
| 334 | + ) { |
| 335 | + return; |
| 336 | + } |
| 337 | + |
| 338 | + tapCount++; |
| 339 | + if (tapCount === 1) { |
| 340 | + tapTimer = setTimeout(() => { |
| 341 | + if (!sidebar.classList.contains('hidden')) { |
| 342 | + toggleSidebar(true); |
| 343 | + } |
| 344 | + tapCount = 0; |
| 345 | + }, TAP_TIMEOUT); |
| 346 | + } else if (tapCount === 2) { |
| 347 | + clearTimeout(tapTimer); |
| 348 | + if (sidebar.classList.contains('hidden')) { |
| 349 | + toggleSidebar(false); |
| 350 | + } |
| 351 | + tapCount = 0; |
| 352 | + } |
| 353 | + } |
| 354 | + |
| 355 | + // Dark mode toggle |
| 356 | + function toggleDarkMode() { |
| 357 | + const body = document.body; |
| 358 | + body.classList.toggle('dark-mode'); |
| 359 | + const isDark = body.classList.contains('dark-mode'); |
| 360 | + localStorage.setItem('dark-mode', isDark); |
| 361 | + const icon = document.querySelector('.dark-toggle i'); |
| 362 | + icon.classList.remove('fa-moon', 'fa-sun'); |
| 363 | + icon.classList.add(isDark ? 'fa-sun' : 'fa-moon'); |
| 364 | + } |
| 365 | + |
| 366 | + // Timezone toggle |
| 367 | + function toggleTimezone() { |
| 368 | + currentZone = currentZone === 'IST' ? 'GMT' : 'IST'; |
| 369 | + document.getElementById('tz-toggle-btn').textContent = currentZone; |
| 370 | + updateLiveTime(); |
| 371 | + } |
| 372 | + |
| 373 | + // Update live time |
| 374 | + function updateLiveTime() { |
| 375 | + const now = new Date(); |
| 376 | + let date; |
| 377 | + if (currentZone === 'GMT') { |
| 378 | + date = new Date(now.getTime() + now.getTimezoneOffset() * 60000); |
| 379 | + } else { |
| 380 | + const utc = now.getTime() + now.getTimezoneOffset() * 60000; |
| 381 | + date = new Date(utc + 5.5 * 3600000); |
| 382 | + } |
| 383 | + let h = date.getHours(); |
| 384 | + const m = date.getMinutes().toString().padStart(2, '0'); |
| 385 | + const s = date.getSeconds().toString().padStart(2, '0'); |
| 386 | + const ampm = h >= 12 ? 'PM' : 'AM'; |
| 387 | + h = h % 12 || 12; |
| 388 | + document.getElementById('live-time').textContent = |
| 389 | + `Time (${currentZone}): ${h}:${m}:${s} ${ampm}`; |
| 390 | + } |
| 391 | + |
| 392 | + // Handle scroll for theme/time container |
| 393 | + function handleScroll() { |
| 394 | + const themeTimeContainer = document.getElementById('theme-time-container'); |
| 395 | + if (window.scrollY > SCROLL_THRESHOLD) { |
| 396 | + themeTimeContainer.classList.add('hidden'); |
| 397 | + } else { |
| 398 | + themeTimeContainer.classList.remove('hidden'); |
| 399 | + } |
| 400 | + } |
| 401 | + |
| 402 | + // On load: init dark mode, sidebar state, listeners, time, SW |
| 403 | + window.onload = () => { |
| 404 | + // Initialize dark mode |
| 405 | + const isDark = localStorage.getItem('dark-mode') === 'true'; |
| 406 | + const body = document.body; |
| 407 | + if (isDark) { |
| 408 | + body.classList.add('dark-mode'); |
| 409 | + document.querySelector('.dark-toggle i').classList.replace('fa-moon', 'fa-sun'); |
| 410 | + } |
| 411 | + |
| 412 | + // Initialize sidebar state |
| 413 | + const sidebar = document.getElementById('sidebar'); |
| 414 | + const toggleBtn = document.querySelector('.toggle-btn'); |
| 415 | + const isSidebarHidden = localStorage.getItem('sidebar-hidden') === 'true'; |
| 416 | + sidebar.classList.toggle('hidden', isSidebarHidden); |
| 417 | + if (window.innerWidth > 768) { |
| 418 | + toggleBtn.style.display = isSidebarHidden ? 'block' : 'none'; |
| 419 | + } else { |
| 420 | + toggleBtn.style.display = 'block'; |
| 421 | + } |
| 422 | + |
| 423 | + // Add tap/click and scroll listeners |
| 424 | + document.addEventListener('click', handleTap); |
| 425 | + document.addEventListener('touchstart', handleTap, { passive: true }); |
| 426 | + window.addEventListener('scroll', handleScroll, { passive: true }); |
| 427 | + |
| 428 | + // Show tooltip on first visit |
| 429 | + if (!localStorage.getItem('tooltip-shown')) { |
| 430 | + setTimeout(() => { |
| 431 | + const tooltip = document.getElementById('tooltip'); |
| 432 | + tooltip.classList.add('visible'); |
| 433 | + setTimeout(() => { |
| 434 | + tooltip.classList.remove('visible'); |
| 435 | + localStorage.setItem('tooltip-shown', 'true'); |
| 436 | + }, 5000); |
| 437 | + }, 1000); |
| 438 | + } |
| 439 | + |
| 440 | + // Initialize active link |
| 441 | + updateActiveLink(); |
| 442 | + |
| 443 | + updateLiveTime(); |
| 444 | + setInterval(updateLiveTime, 1000); |
| 445 | + |
| 446 | + if ('serviceWorker' in navigator) { |
| 447 | + navigator.serviceWorker |
| 448 | + .register('/JavaEvolution-Learning-Growing-Mastering/assets/sw.js') |
| 449 | + .then(() => console.log('Service Worker Registered')) |
| 450 | + .catch(err => console.error('SW registration failed', err)); |
| 451 | + } |
| 452 | + }; |
| 453 | + </script> |
| 454 | +</head> |
| 455 | + |
| 456 | +<body> |
| 457 | +<!-- Dark Mode & Timezone Controls --> |
| 458 | +<div id="theme-time-container"> |
| 459 | + <button class="dark-toggle" onclick="toggleDarkMode()" aria-label="Toggle Dark Mode"> |
| 460 | + <i class="fas fa-moon"></i> |
| 461 | + </button> |
| 462 | + <div id="time-zone-wrapper"> |
| 463 | + <button id="tz-toggle-btn" class="time-toggle" onclick="toggleTimezone()" aria-label="Toggle Timezone">IST</button> |
| 464 | + <span id="live-time">Time: Loading...</span> |
| 465 | + </div> |
| 466 | +</div> |
| 467 | + |
| 468 | +<!-- Onboarding Tooltip --> |
| 469 | +<div id="tooltip" class="tooltip"> |
| 470 | + Single tap to hide sidebar, double tap to show |
| 471 | +</div> |
| 472 | + |
| 473 | +<!-- Collapsible Sidebar --> |
| 474 | +<div id="sidebar" class="sidebar"> |
| 475 | + <a href="{{ site.baseurl }}/" class="sidebar-link"> |
| 476 | + <i class="fas fa-home"></i> Home |
| 477 | + </a> |
| 478 | + <a href="{{ site.baseurl }}/content" class="sidebar-link"> |
| 479 | + <i class="fas fa-book"></i> All Contents |
| 480 | + </a> |
| 481 | + <a href="https://github.com/Someshdiwan/JavaEvolution-Learning-Growing-Mastering" class="sidebar-link" target="_blank"> |
| 482 | + <i class="fab fa-github"></i> GitHub Repo |
| 483 | + </a> |
| 484 | +</div> |
| 485 | + |
228 | 486 | <!-- Toggle Button (Fallback) --> |
229 | 487 | <button class="toggle-btn" onclick="toggleSidebar(!document.getElementById('sidebar').classList.contains('hidden'))" aria-label="Toggle Sidebar"> |
230 | 488 | <i class="fas fa-bars"></i> |
|
0 commit comments