<!DOCTYPE html>
<html lang="hi">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, user-scalable=no"
/>
<title>आप ऑफ़लाइन हैं</title>
<!-- Google Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&family=Noto+Sans+Devanagari:wght@400;500&display=swap"
rel="stylesheet"
/>
<style>
:root {
--primary-color: #6f0ff9;
--primary-light: #8b49ff;
--primary-lighter: #f8f4ff;
--primary-border: #eae0fe;
--background-color: #f0f2f5;
--white-color: #ffffff;
--text-dark: #333333;
--text-light: #555555;
--text-subtle: #888888;
--font-primary: "Poppins", sans-serif;
--font-secondary: "Noto Sans Devanagari", sans-serif;
--shadow-light: 0 4px 15px rgba(0, 0, 0, 0.05);
--shadow-medium: 0 8px 25px rgba(0, 0, 0, 0.1);
--shadow-strong: 0 5px 15px rgba(111, 15, 249, 0.4);
--space-sm: 8px;
--space-md: 16px;
--space-lg: 24px;
--space-xl: 32px;
--border-radius-sm: 10px;
--border-radius-md: 20px;
--transition-smooth: all 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html,
body {
font-family: var(--font-primary);
color: var(--text-light);
height: 100%;
overflow: hidden;
background-color: var(--background-color);
background-image: radial-gradient(
circle at 25% 15%,
var(--primary-lighter) 0%,
var(--background-color) 25%
);
}
/* Particle Container */
.particles-container {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 1;
pointer-events: none;
}
.particle {
position: absolute;
border-radius: 50%;
/* New particle color as requested */
background-color: var(--primary-color);
opacity: 0;
/* New animation for random movement and fading */
animation: moveAndFade 20s infinite;
}
/* New Keyframes for random movement and fading */
@keyframes moveAndFade {
0% {
transform: translate(0, 0);
opacity: 0;
}
25% {
transform: translate(var(--x1), var(--y1));
opacity: 0.7;
}
50% {
transform: translate(var(--x2), var(--y2));
opacity: 0;
}
75% {
transform: translate(var(--x3), var(--y3));
opacity: 0.5;
}
100% {
transform: translate(var(--x4), var(--y4));
opacity: 0;
}
}
/* Main Container */
.container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100%;
padding: var(--space-md);
text-align: center;
position: relative;
z-index: 2;
}
.offline-card {
background-color: var(--white-color);
border-radius: var(--border-radius-md);
padding: var(--space-xl);
width: 100%;
max-width: 420px;
box-shadow: var(--shadow-medium);
border: 1px solid var(--primary-border);
transform: scale(0.95);
opacity: 0;
animation: popIn 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) 0.2s
forwards;
}
@keyframes popIn {
to {
opacity: 1;
transform: scale(1);
}
}
.icon-container {
margin-bottom: var(--space-lg);
}
.icon-pulse {
width: 100px;
height: 100px;
border-radius: 50%;
background-color: var(--primary-lighter);
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto;
position: relative;
}
.icon-pulse::before,
.icon-pulse::after {
content: "";
position: absolute;
border: 1px solid var(--primary-light);
width: 100%;
height: 100%;
border-radius: 50%;
animation: pulse 3s ease-out infinite;
opacity: 0;
}
.icon-pulse::after {
animation-delay: 1.5s;
}
@keyframes pulse {
0% {
transform: scale(0.9);
opacity: 0;
}
50% {
opacity: 0.6;
}
100% {
transform: scale(1.5);
opacity: 0;
}
}
.offline-icon {
width: 50px;
height: 50px;
stroke: var(--primary-color);
}
.title {
font-size: 2rem;
font-weight: 600;
margin-bottom: var(--space-sm);
color: var(--text-dark);
}
.message {
font-size: 1rem;
line-height: 1.6;
margin-bottom: var(--space-lg);
color: var(--text-light);
font-family: var(--font-secondary);
}
.retry-button {
background-color: var(--primary-color);
color: var(--white-color);
border: none;
border-radius: var(--border-radius-sm);
padding: 12px var(--space-lg);
font-size: 1rem;
font-weight: 500;
cursor: pointer;
transition: var(--transition-smooth);
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--space-sm);
box-shadow: var(--shadow-light);
}
.retry-button:hover {
background-color: var(--primary-light);
transform: translateY(-3px);
box-shadow: var(--shadow-strong);
}
.retry-button:active {
transform: translateY(0);
box-shadow: var(--shadow-light);
}
.retry-button.loading {
pointer-events: none;
background-color: var(--text-subtle);
}
.spinner {
width: 18px;
height: 18px;
border: 2px solid transparent;
border-top-color: var(--white-color);
border-radius: 50%;
animation: spin 0.8s linear infinite;
display: none;
}
@keyframes spin {
to {
transform: rotate(360deg);
}
}
/* == FIX: Card was disappearing on small screens == */
@media (max-width: 480px) {
.offline-card {
padding: var(--space-lg) var(--space-md);
/* The following lines were removed to keep the card visible */
/* border: none; */
/* box-shadow: none; */
/* background: transparent; */
}
.title {
font-size: 1.5rem;
}
.message {
font-size: 0.9rem;
}
.icon-pulse {
width: 80px;
height: 80px;
}
.offline-icon {
width: 40px;
height: 40px;
}
}
</style>
</head>
<body>
<div class="particles-container" id="particles-container"></div>
<div class="container">
<div class="offline-card">
<div class="icon-container">
<div class="icon-pulse">
<svg
class="offline-icon"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M18 10h-1.26A8 8 0 1 0 9 20h9a5 5 0 0 0 0-10z"></path>
<line x1="1" y1="1" x2="23" y2="23"></line>
</svg>
</div>
</div>
<h1 class="title" id="title">आप ऑफ़लाइन हैं</h1>
<p class="message" id="message">
कृपया अपना इंटरनेट कनेक्शन जांचें और ऑनलाइन होने पर फिर से प्रयास
करें।
</p>
<button id="retry-button" class="retry-button">
<span class="spinner"></span>
<span id="button-text">फिर से प्रयास करें</span>
</button>
</div>
</div>
<script>
const retryButton = document.getElementById("retry-button");
const buttonText = document.getElementById("button-text");
const spinner = document.querySelector(".spinner");
const title = document.getElementById("title");
const message = document.getElementById("message");
const particlesContainer = document.getElementById("particles-container");
let wasOnline = navigator.onLine;
const translations = {
en: {
title: "You're Offline",
message:
"Please check your internet connection and try again when you're back online.",
retry: "Retry",
checking: "Checking...",
},
hi: {
title: "आप ऑफ़लाइन हैं",
message:
"कृपया अपना इंटरनेट कनेक्शन जांचें और ऑनलाइन होने पर फिर से प्रयास करें।",
retry: "फिर से प्रयास करें",
checking: "जाँच हो रही है...",
},
};
function setLanguage() {
const userLang = navigator.language.toLowerCase().substring(0, 2);
const lang = ["hi"].includes(userLang) ? userLang : "en";
document.documentElement.lang = lang;
title.textContent = translations[lang].title;
message.textContent = translations[lang].message;
buttonText.textContent = translations[lang].retry;
}
// --- New and Improved Particle Background Effect ---
function createParticles() {
// Increase particle count for "dheer saare" effect
const particleCount = Math.floor(window.innerWidth / 15);
particlesContainer.innerHTML = ""; // Clear old particles
for (let i = 0; i < particleCount; i++) {
const particle = document.createElement("div");
particle.classList.add("particle");
const size = Math.random() * 5 + 2; // Size: 2px to 7px
particle.style.width = `${size}px`;
particle.style.height = `${size}px`;
// Start position anywhere on the screen
particle.style.top = `${Math.random() * 100}vh`;
particle.style.left = `${Math.random() * 100}vw`;
// Random destinations for the keyframe animation
const randomRange = 150;
particle.style.setProperty(
"--x1",
`${Math.random() * randomRange - randomRange / 2}px`
);
particle.style.setProperty(
"--y1",
`${Math.random() * randomRange - randomRange / 2}px`
);
particle.style.setProperty(
"--x2",
`${Math.random() * randomRange - randomRange / 2}px`
);
particle.style.setProperty(
"--y2",
`${Math.random() * randomRange - randomRange / 2}px`
);
particle.style.setProperty(
"--x3",
`${Math.random() * randomRange - randomRange / 2}px`
);
particle.style.setProperty(
"--y3",
`${Math.random() * randomRange - randomRange / 2}px`
);
particle.style.setProperty(
"--x4",
`${Math.random() * randomRange - randomRange / 2}px`
);
particle.style.setProperty(
"--y4",
`${Math.random() * randomRange - randomRange / 2}px`
);
// Animation properties for variety
const duration = Math.random() * 15 + 10; // Duration: 10s to 25s
const delay = Math.random() * 10; // Delay: 0s to 10s
particle.style.animationDuration = `${duration}s`;
particle.style.animationDelay = `${delay}s`;
particlesContainer.appendChild(particle);
}
}
function updateOnlineStatus() {
const isOnline = navigator.onLine;
if (isOnline && !wasOnline) {
document.body.style.transition = "opacity 0.5s ease-in-out";
document.body.style.opacity = "0";
setTimeout(() => {
location.reload();
}, 500);
}
wasOnline = isOnline;
}
function handleRetry() {
retryButton.classList.add("loading");
spinner.style.display = "inline-block";
const userLang = document.documentElement.lang;
buttonText.textContent = translations[userLang].checking;
setTimeout(() => {
if (navigator.onLine) {
location.reload();
} else {
retryButton.classList.remove("loading");
spinner.style.display = "none";
buttonText.textContent = translations[userLang].retry;
retryButton.animate(
[
{ transform: "translateX(-6px)" },
{ transform: "translateX(6px)" },
{ transform: "translateX(-6px)" },
{ transform: "translateX(0)" },
],
{ duration: 400, easing: "ease-in-out" }
);
}
}, 1500);
}
function init() {
setLanguage();
createParticles();
window.addEventListener("online", updateOnlineStatus);
window.addEventListener("offline", updateOnlineStatus);
retryButton.addEventListener("click", handleRetry);
// Regenerate particles on resize to fit the new screen size
window.addEventListener("resize", createParticles);
}
window.addEventListener("load", init);
</script>
</body>
</html>
Comments
Post a Comment