FumbleAround/index.html
2025-01-20 01:10:03 -06:00

349 lines
No EOL
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>FumbleAround</title>
<link rel="stylesheet" href="styles.css">
<link rel="icon" type="image/png" href="./Assets/smily.png">
<!-- PWA Meta Tags -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="FumbleAround">
<meta name="mobile-web-app-capable" content="yes">
<meta name="theme-color" content="#ffffff">
<meta name="application-name" content="FumbleAround">
<!-- Apple Touch Icons -->
<link rel="apple-touch-icon" href="./Assets/smily.png">
<link rel="apple-touch-icon" sizes="152x152" href="./Assets/smily.png">
<link rel="apple-touch-icon" sizes="180x180" href="./Assets/smily.png">
<link rel="apple-touch-icon" sizes="167x167" href="./Assets/smily.png">
<!-- Web Manifest -->
<link rel="manifest" href="manifest.json">
</head>
<body>
<header>
<div class="logo">
<img src="./Assets/smily.png" alt="FumbleAround Logo" class="logo-icon">
FumbleAround
</div>
<div class="header-buttons">
<div class="social-buttons">
<button id="donateButton">💝</button>
<button id="githubButton">
<svg viewBox="0 0 24 24" width="24" height="24">
<path fill="currentColor" d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/>
</svg>
</button>
</div>
<div class="app-controls">
<button id="settingsButton">
<svg viewBox="0 0 24 24" width="24" height="24">
<path fill="currentColor" d="M19.14 12.94c.04-.3.06-.61.06-.94 0-.32-.02-.64-.07-.94l2.03-1.58c.18-.14.23-.41.12-.61l-1.92-3.32c-.12-.22-.37-.29-.59-.22l-2.39.96c-.5-.38-1.03-.7-1.62-.94l-.36-2.54c-.04-.24-.24-.41-.48-.41h-3.84c-.24 0-.43.17-.47.41l-.36 2.54c-.59.24-1.13.57-1.62.94l-2.39-.96c-.22-.08-.47 0-.59.22L2.74 8.87c-.12.21-.08.47.12.61l2.03 1.58c-.05.3-.07.62-.07.94s.02.64.07.94l-2.03 1.58c-.18.14-.23.41-.12.61l1.92 3.32c.12.22.37.29.59.22l2.39-.96c.5.38 1.03.7 1.62.94l.36 2.54c.05.24.24.41.48.41h3.84c.24 0 .44-.17.47-.41l.36-2.54c.59-.24 1.13-.56 1.62-.94l2.39.96c.22.08.47 0 .59-.22l1.92-3.32c.12-.22.07-.47-.12-.61l-2.01-1.58zM12 15.6c-1.98 0-3.6-1.62-3.6-3.6s1.62-3.6 3.6-3.6 3.6 1.62 3.6 3.6-1.62 3.6-3.6 3.6z"/>
</svg>
</button>
<button id="fumbleButton">Fumble!</button>
</div>
</div>
</header>
<div id="settingsPanel" class="settings-panel">
<div class="settings-content">
<div class="settings-header">
<h2>Settings</h2>
<button class="close-settings">×</button>
</div>
<div class="settings-section">
<h3>Display</h3>
<div class="setting-item">
<label>Dark Mode</label>
<button id="darkModeToggle">🌙</button>
</div>
</div>
<div class="settings-section">
<h3>Actions</h3>
<div class="setting-item">
<button id="openInNewWindow" class="settings-button">Open in New Window</button>
</div>
</div>
<div class="settings-section">
<h3>About</h3>
<div class="setting-item about-section">
<div class="about-content">
<div class="about-logo">
<img src="./Assets/smily.png" alt="FumbleAround Logo">
<h4>FumbleAround</h4>
</div>
<div class="about-text">
<p>Discover the hidden gems of the internet, powered by Wiby.me's search engine.</p>
<div class="disclaimer">
<h5>Disclaimer</h5>
<p>We are not responsible for the content that appears. Use at your own discretion.</p>
</div>
<div class="tribute">
<p>A homage to the classic StumbleUpon, reimagined for the modern web.</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div id="warningModal" class="modal warning-modal">
<div class="modal-content">
<span class="close-button" style="display: none;">&times;</span>
<h2>⚠️ Slow Down!</h2>
<p>Clicking too quickly may get you flagged as spam by Wiby.me.</p>
<p>Please wait a moment between fumbles.</p>
<div id="cooldownTimer" class="cooldown-timer">
You can close this warning in: <span id="cooldownSeconds">5</span>s
</div>
<button id="warningCloseBtn" class="warning-close-btn" disabled>I Understand</button>
</div>
</div>
<main>
<iframe
id="contentFrame"
src="landing.html"
title="Content"
sandbox="allow-scripts allow-same-origin allow-forms allow-popups"
></iframe>
</main>
<script>
if (performance.navigation.type === performance.navigation.TYPE_RELOAD) {
if (sessionStorage.getItem('hasVisited')) {
window.stop();
requestAnimationFrame(() => fumble());
}
} else if (!sessionStorage.getItem('hasVisited')) {
sessionStorage.setItem('hasVisited', 'true');
}
let lastFumbleTime = 0;
const cooldownPeriod = 5000; // 5 seconds cooldown
let cooldownTimer = null;
let currentPageUrl = null; // Add this to store the current URL
const fumble = () => {
const currentTime = Date.now();
const timeSinceLastFumble = currentTime - lastFumbleTime;
if (timeSinceLastFumble < cooldownPeriod) {
// Show warning modal
const warningModal = document.getElementById('warningModal');
const cooldownSeconds = document.getElementById('cooldownSeconds');
const closeBtn = document.getElementById('warningCloseBtn');
warningModal.classList.add('show');
closeBtn.disabled = true;
// Update countdown timer
let remainingTime = 5; // 5 second countdown for closing
cooldownSeconds.textContent = remainingTime;
if (cooldownTimer) clearInterval(cooldownTimer);
cooldownTimer = setInterval(() => {
remainingTime--;
if (remainingTime <= 0) {
cooldownSeconds.textContent = '0';
closeBtn.disabled = false;
clearInterval(cooldownTimer);
} else {
cooldownSeconds.textContent = remainingTime;
}
}, 1000);
return;
}
lastFumbleTime = currentTime;
const frame = document.getElementById('contentFrame');
frame.src = 'https://wiby.me/surprise/';
// Wait for the page to load then focus
frame.onload = () => {
try {
// Store the actual URL after redirect
currentPageUrl = frame.contentWindow.location.href;
const title = frame.contentWindow.document.title.toLowerCase();
if (title.includes('blocked') ||
title.includes('error') ||
title.includes('refused') ||
title.includes('cannot') ||
title.includes('denied')) {
currentPageUrl = null; // Reset if we hit an error
fumble();
return;
}
} catch (e) {
// Can't access due to CORS
currentPageUrl = null;
}
frame.focus();
try {
frame.contentWindow.focus();
} catch (e) {
// Ignore cross-origin errors
}
};
// Handle load errors
frame.onerror = () => {
fumble(); // Try again if loading fails
};
};
document.getElementById('fumbleButton').addEventListener('click', fumble);
// Dark mode toggle
const darkModeToggle = document.getElementById('darkModeToggle');
const body = document.body;
// Check for saved preference
if (localStorage.getItem('darkMode') === 'true') {
body.classList.add('dark-mode');
darkModeToggle.textContent = '☀️';
}
darkModeToggle.addEventListener('click', () => {
body.classList.toggle('dark-mode');
const isDark = body.classList.contains('dark-mode');
darkModeToggle.textContent = isDark ? '☀️' : '🌙';
localStorage.setItem('darkMode', isDark);
});
// Add GitHub button click handler
document.getElementById('githubButton').addEventListener('click', () => {
window.open('https://git.mauix.bio/michael/FumbleAround', '_blank');
});
// Add donate button click handler
document.getElementById('donateButton').addEventListener('click', () => {
window.open('https://wiby.me/donate/', '_blank');
});
// Add settings button click handler
const settingsPanel = document.getElementById('settingsPanel');
const settingsButton = document.getElementById('settingsButton');
const closeSettings = document.querySelector('.close-settings');
settingsButton.addEventListener('click', () => {
settingsPanel.classList.add('show');
});
closeSettings.addEventListener('click', () => {
settingsPanel.classList.remove('show');
});
// Update the open in new window handler
document.getElementById('openInNewWindow').addEventListener('click', () => {
if (currentPageUrl) {
window.open(currentPageUrl, '_blank');
settingsPanel.classList.remove('show');
}
});
// Update warning modal close handler
const warningModal = document.getElementById('warningModal');
const warningCloseBtn = document.getElementById('warningCloseBtn');
warningCloseBtn.addEventListener('click', () => {
if (!warningCloseBtn.disabled) {
warningModal.classList.remove('show');
if (cooldownTimer) clearInterval(cooldownTimer);
}
});
// Remove the click-outside-to-close functionality for warning modal
window.addEventListener('click', (event) => {
if (event.target === warningModal) { // Only for warning modal
warningModal.classList.remove('show');
}
});
// Add shake detection
let lastX = 0;
let lastY = 0;
let lastZ = 0;
let lastUpdate = 0;
const shakeThreshold = 15; // Adjust sensitivity
const shakeTimeout = 1000; // Prevent multiple shakes
let lastShake = 0;
function handleMotion(event) {
const current = event.accelerationIncludingGravity;
const currentTime = new Date().getTime();
const timeDiff = currentTime - lastUpdate;
if (timeDiff > 100) {
const deltaX = Math.abs(current.x - lastX);
const deltaY = Math.abs(current.y - lastY);
const deltaZ = Math.abs(current.z - lastZ);
if (((deltaX > shakeThreshold && deltaY > shakeThreshold) ||
(deltaX > shakeThreshold && deltaZ > shakeThreshold) ||
(deltaY > shakeThreshold && deltaZ > shakeThreshold)) &&
(currentTime - lastShake > shakeTimeout)) {
// Vibrate if available
if ('vibrate' in navigator) {
navigator.vibrate(200);
}
fumble();
lastShake = currentTime;
}
lastX = current.x;
lastY = current.y;
lastZ = current.z;
lastUpdate = currentTime;
}
}
// Request permission and start shake detection on mobile
function initShakeDetection() {
if (typeof DeviceMotionEvent.requestPermission === 'function') {
// iOS 13+ requires permission
DeviceMotionEvent.requestPermission()
.then(permissionState => {
if (permissionState === 'granted') {
window.addEventListener('devicemotion', handleMotion);
}
})
.catch(console.error);
} else {
// Non iOS 13+ devices
window.addEventListener('devicemotion', handleMotion);
}
}
// Initialize shake detection when page loads
if ('DeviceMotionEvent' in window) {
// Add a button to request permission on iOS
if (typeof DeviceMotionEvent.requestPermission === 'function') {
const settingsPanel = document.getElementById('settingsPanel');
const settingsContent = settingsPanel.querySelector('.settings-content');
const permissionButton = document.createElement('button');
permissionButton.textContent = 'Enable Shake to Fumble';
permissionButton.className = 'permission-button';
permissionButton.addEventListener('click', initShakeDetection);
settingsContent.appendChild(permissionButton);
} else {
// Automatically start for non-iOS devices
initShakeDetection();
}
}
</script>
</body>
</html>