feat: Add peeking Bongo Cat Easter Egg with micro-animations
All checks were successful
Build & Push Docker Image to Gitea Registry / build-and-push (push) Successful in 11s
All checks were successful
Build & Push Docker Image to Gitea Registry / build-and-push (push) Successful in 11s
This commit is contained in:
64
app.js
64
app.js
@@ -232,3 +232,67 @@ loadConfig()
|
||||
dashboardSections.innerHTML = '<p class="empty-state">Dashboard-Konfiguration konnte nicht geladen werden.</p>';
|
||||
onlineCount.textContent = '--';
|
||||
});
|
||||
|
||||
// ==========================================================================
|
||||
// Peeking Bongo Cat Easter Egg Logic
|
||||
// ==========================================================================
|
||||
(function initPeekingCat() {
|
||||
const peekingCat = document.querySelector('#peekingCat');
|
||||
const searchInput = document.querySelector('#serviceSearch');
|
||||
|
||||
if (!peekingCat) return;
|
||||
|
||||
let tapTimeout = null;
|
||||
|
||||
// Function to trigger heart popup on click
|
||||
function createHeart(x, y) {
|
||||
const heart = document.createElement('div');
|
||||
heart.className = 'cat-heart';
|
||||
heart.innerHTML = '❤️';
|
||||
heart.style.left = `${x - 12}px`;
|
||||
heart.style.top = `${y - 20}px`;
|
||||
|
||||
// Set random rotation angle in CSS custom variable
|
||||
const randomRot = Math.random() * 40 - 20;
|
||||
heart.style.setProperty('--rot', `${randomRot}deg`);
|
||||
|
||||
document.body.appendChild(heart);
|
||||
|
||||
// Cleanup heart after animation completes
|
||||
setTimeout(() => heart.remove(), 800);
|
||||
}
|
||||
|
||||
// Focus search box triggers peeking active state
|
||||
if (searchInput) {
|
||||
searchInput.addEventListener('focus', () => {
|
||||
peekingCat.classList.add('is-active');
|
||||
});
|
||||
|
||||
searchInput.addEventListener('blur', () => {
|
||||
peekingCat.classList.remove('is-active');
|
||||
peekingCat.classList.remove('is-tapping');
|
||||
});
|
||||
|
||||
// Keyboard typing triggers tapping animation!
|
||||
searchInput.addEventListener('input', () => {
|
||||
peekingCat.classList.add('is-active');
|
||||
peekingCat.classList.add('is-tapping');
|
||||
|
||||
if (tapTimeout) clearTimeout(tapTimeout);
|
||||
tapTimeout = setTimeout(() => {
|
||||
peekingCat.classList.remove('is-tapping');
|
||||
}, 350); // Stop tapping 350ms after typing stops
|
||||
});
|
||||
}
|
||||
|
||||
// Click on cat triggers tapping + heart animation!
|
||||
peekingCat.addEventListener('click', (e) => {
|
||||
peekingCat.classList.add('is-tapping');
|
||||
createHeart(e.clientX, e.clientY);
|
||||
|
||||
if (tapTimeout) clearTimeout(tapTimeout);
|
||||
tapTimeout = setTimeout(() => {
|
||||
peekingCat.classList.remove('is-tapping');
|
||||
}, 800);
|
||||
});
|
||||
})();
|
||||
|
||||
48
index.html
48
index.html
@@ -13,7 +13,7 @@
|
||||
<link rel="apple-touch-icon" href="/icons/apple-touch-icon-v2.png">
|
||||
<link rel="icon" type="image/png" sizes="192x192" href="/icons/icon-192.png">
|
||||
<link rel="icon" type="image/png" sizes="512x512" href="/icons/icon-512.png">
|
||||
<link rel="stylesheet" href="style.css?v=18">
|
||||
<link rel="stylesheet" href="style.css?v=19">
|
||||
</head>
|
||||
<body>
|
||||
<header class="shell hero">
|
||||
@@ -73,6 +73,50 @@
|
||||
<span id="lastChecked">Status wird im Hintergrund geprueft.</span>
|
||||
</footer>
|
||||
|
||||
<script src="/app.js?v=4" defer></script>
|
||||
<!-- Peeking Bongo Cat Easter Egg -->
|
||||
<div class="peeking-cat" id="peekingCat" aria-hidden="true">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 120 100" width="120" height="100">
|
||||
<!-- Left Ear -->
|
||||
<path class="cat-ear cat-ear-left" d="M 25 50 L 10 15 L 45 35 Z" fill="#ffffff" stroke="#1e293b" stroke-width="3" stroke-linejoin="round" />
|
||||
<path class="cat-ear cat-ear-left-inner" d="M 28 45 L 17 21 L 40 34 Z" fill="#fecdd3" />
|
||||
|
||||
<!-- Right Ear -->
|
||||
<path class="cat-ear cat-ear-right" d="M 95 50 L 110 15 L 75 35 Z" fill="#ffffff" stroke="#1e293b" stroke-width="3" stroke-linejoin="round" />
|
||||
<path class="cat-ear cat-ear-right-inner" d="M 92 45 L 103 21 L 80 34 Z" fill="#fecdd3" />
|
||||
|
||||
<!-- Face/Head -->
|
||||
<path class="cat-head" d="M 15 70 C 15 25, 105 25, 105 70 L 15 70 Z" fill="#ffffff" stroke="#1e293b" stroke-width="3" stroke-linejoin="round" />
|
||||
|
||||
<!-- Cheeks -->
|
||||
<ellipse class="cat-blush" cx="28" cy="58" rx="8" ry="5" fill="#fca5a5" opacity="0.6" />
|
||||
<ellipse class="cat-blush" cx="92" cy="58" rx="8" ry="5" fill="#fca5a5" opacity="0.6" />
|
||||
|
||||
<!-- Eyes -->
|
||||
<g class="cat-eye-group">
|
||||
<ellipse class="cat-eye cat-eye-l" cx="42" cy="50" rx="4" ry="5" fill="#1e293b" />
|
||||
<circle class="cat-eye-shine cat-eye-shine-l" cx="40" cy="48" r="1.2" fill="#ffffff" />
|
||||
</g>
|
||||
<g class="cat-eye-group">
|
||||
<ellipse class="cat-eye cat-eye-r" cx="78" cy="50" rx="4" ry="5" fill="#1e293b" />
|
||||
<circle class="cat-eye-shine cat-eye-shine-r" cx="76" cy="48" r="1.2" fill="#ffffff" />
|
||||
</g>
|
||||
|
||||
<!-- Nose/Mouth -->
|
||||
<path class="cat-mouth" d="M 57 54 Q 60 57 63 54 Q 66 57 69 54" fill="none" stroke="#1e293b" stroke-width="2.5" stroke-linecap="round" />
|
||||
|
||||
<!-- Whiskers -->
|
||||
<line class="cat-whisker" x1="12" y1="52" x2="3" y2="50" stroke="#1e293b" stroke-width="2" stroke-linecap="round" />
|
||||
<line class="cat-whisker" x1="11" y1="58" x2="2" y2="58" stroke="#1e293b" stroke-width="2" stroke-linecap="round" />
|
||||
|
||||
<line class="cat-whisker" x1="108" y1="52" x2="117" y2="50" stroke="#1e293b" stroke-width="2" stroke-linecap="round" />
|
||||
<line class="cat-whisker" x1="109" y1="58" x2="118" y2="58" stroke="#1e293b" stroke-width="2" stroke-linecap="round" />
|
||||
|
||||
<!-- Paws -->
|
||||
<path class="cat-paw cat-paw-left" d="M 30 70 C 30 58, 46 58, 46 70 Z" fill="#ffffff" stroke="#1e293b" stroke-width="3" stroke-linejoin="round" />
|
||||
<path class="cat-paw cat-paw-right" d="M 74 70 C 74 58, 90 58, 90 70 Z" fill="#ffffff" stroke="#1e293b" stroke-width="3" stroke-linejoin="round" />
|
||||
</svg>
|
||||
</div>
|
||||
|
||||
<script src="/app.js?v=5" defer></script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
114
style.css
114
style.css
@@ -820,3 +820,117 @@ main {
|
||||
animation-iteration-count: 1 !important;
|
||||
}
|
||||
}
|
||||
|
||||
/* ==========================================================================
|
||||
Peeking Bongo Cat Easter Egg
|
||||
========================================================================== */
|
||||
.peeking-cat {
|
||||
position: fixed;
|
||||
bottom: -45px;
|
||||
left: 24px;
|
||||
width: 120px;
|
||||
height: 100px;
|
||||
z-index: 1000;
|
||||
cursor: pointer;
|
||||
transition: bottom 0.35s cubic-bezier(0.175, 0.885, 0.32, 1.275), transform 0.3s ease;
|
||||
user-select: none;
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
.peeking-cat:hover {
|
||||
bottom: -15px;
|
||||
transform: scale(1.06);
|
||||
}
|
||||
|
||||
.peeking-cat.is-active {
|
||||
bottom: -15px;
|
||||
}
|
||||
|
||||
/* Blinking eyes animation */
|
||||
@keyframes cat-blink {
|
||||
0%, 90%, 100% {
|
||||
transform: scaleY(1);
|
||||
}
|
||||
95% {
|
||||
transform: scaleY(0.1);
|
||||
}
|
||||
}
|
||||
.cat-eye-group {
|
||||
transform-origin: 42px 50px;
|
||||
animation: cat-blink 4s infinite;
|
||||
}
|
||||
.cat-eye-group:nth-child(2) {
|
||||
transform-origin: 78px 50px;
|
||||
}
|
||||
|
||||
/* Ear wiggle animation on hover */
|
||||
@keyframes ear-wiggle-l {
|
||||
0%, 100% { transform: rotate(0deg); }
|
||||
50% { transform: rotate(-6deg); }
|
||||
}
|
||||
@keyframes ear-wiggle-r {
|
||||
0%, 100% { transform: rotate(0deg); }
|
||||
50% { transform: rotate(6deg); }
|
||||
}
|
||||
.peeking-cat:hover .cat-ear-left,
|
||||
.peeking-cat:hover .cat-ear-left-inner {
|
||||
animation: ear-wiggle-l 0.4s ease-in-out infinite alternate;
|
||||
transform-origin: 35px 42px;
|
||||
}
|
||||
.peeking-cat:hover .cat-ear-right,
|
||||
.peeking-cat:hover .cat-ear-right-inner {
|
||||
animation: ear-wiggle-r 0.4s ease-in-out infinite alternate;
|
||||
transform-origin: 85px 42px;
|
||||
}
|
||||
|
||||
/* Paw tapping animation (Bongo Cat typing style) */
|
||||
@keyframes paw-tap-left {
|
||||
0%, 100% { transform: translateY(0) rotate(0); }
|
||||
50% { transform: translateY(-10px) rotate(-3deg); }
|
||||
}
|
||||
@keyframes paw-tap-right {
|
||||
0%, 100% { transform: translateY(0) rotate(0); }
|
||||
50% { transform: translateY(-10px) rotate(3deg); }
|
||||
}
|
||||
.peeking-cat.is-tapping .cat-paw-left {
|
||||
animation: paw-tap-left 0.14s ease-in-out infinite alternate;
|
||||
transform-origin: 38px 70px;
|
||||
}
|
||||
.peeking-cat.is-tapping .cat-paw-right {
|
||||
animation: paw-tap-right 0.14s ease-in-out infinite alternate-reverse;
|
||||
transform-origin: 82px 70px;
|
||||
}
|
||||
|
||||
/* Floating Hearts on click */
|
||||
.cat-heart {
|
||||
position: fixed;
|
||||
pointer-events: none;
|
||||
z-index: 10001;
|
||||
font-size: 20px;
|
||||
animation: heart-float 0.8s cubic-bezier(0.1, 0.8, 0.3, 1) forwards;
|
||||
}
|
||||
|
||||
@keyframes heart-float {
|
||||
0% {
|
||||
transform: translateY(0) scale(0.6) rotate(0deg);
|
||||
opacity: 1;
|
||||
}
|
||||
100% {
|
||||
transform: translateY(-80px) scale(1.4) rotate(var(--rot, 15deg));
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Responsive adjustment for mobile screen */
|
||||
@media (max-width: 620px) {
|
||||
.peeking-cat {
|
||||
width: 90px;
|
||||
height: 75px;
|
||||
bottom: -35px;
|
||||
left: 12px;
|
||||
}
|
||||
.peeking-cat:hover,
|
||||
.peeking-cat.is-active {
|
||||
bottom: -10px;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user