clean up
This commit is contained in:
@@ -1,213 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="theme-color" content="#2c3e50">
|
||||
<title>Game Timer</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<!-- Deep Linking - App Links for Android -->
|
||||
<link rel="alternate" href="android-app://eu.virtonline.gametimer/https/game-timer.virtonline.eu" />
|
||||
|
||||
<!-- Deep Linking - Universal Links for iOS -->
|
||||
<meta name="apple-itunes-app" content="app-id=yourAppID, app-argument=https://game-timer.virtonline.eu">
|
||||
|
||||
<!-- Deep Linking - Web App URL Handling -->
|
||||
<link rel="alternate" href="web+gametimer://action" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<header class="header">
|
||||
<div class="game-controls">
|
||||
<button id="gameButton" class="game-button">Start Game</button>
|
||||
</div>
|
||||
<div class="header-buttons">
|
||||
<button id="resetButton" class="header-button" title="Reset All Data">
|
||||
<i class="fas fa-redo-alt"></i>
|
||||
</button>
|
||||
<button id="addPlayerButton" class="header-button" title="Add New Player">
|
||||
<i class="fas fa-user-plus"></i>
|
||||
</button>
|
||||
<button id="setupButton" class="header-button" title="Setup Current Player">
|
||||
<i class="fas fa-cog"></i>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="carousel-container">
|
||||
<div id="carousel" class="carousel">
|
||||
<!-- Player cards will be dynamically inserted here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Player Edit Modal -->
|
||||
<div id="playerModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h2 id="modalTitle">Edit Player</h2>
|
||||
<form id="playerForm">
|
||||
<div class="form-group">
|
||||
<label for="playerName">Name</label>
|
||||
<input type="text" id="playerName" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="playerImage">Image</label>
|
||||
<div class="image-input-container">
|
||||
<input type="file" id="playerImage" accept="image/*">
|
||||
<button type="button" id="cameraButton" class="camera-button">
|
||||
<i class="fas fa-camera"></i> Take Photo
|
||||
</button>
|
||||
</div>
|
||||
<div id="imagePreview" class="player-image" style="margin-top: 0.5rem;">
|
||||
<i class="fas fa-user"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="playerTimeContainer" class="form-group">
|
||||
<label for="playerTime">Time (minutes)</label>
|
||||
<input type="number" id="playerTime" min="1" max="180" value="5" required>
|
||||
</div>
|
||||
<div id="remainingTimeContainer" class="form-group" style="display: none;">
|
||||
<label for="playerRemainingTime">Remaining Time (MM:SS)</label>
|
||||
<input type="text" id="playerRemainingTime" pattern="[0-9]{2}:[0-9]{2}" placeholder="05:00">
|
||||
<small>Format: Minutes:Seconds (e.g., 05:30)</small>
|
||||
</div>
|
||||
<div class="form-buttons">
|
||||
<button type="button" id="cancelButton" class="cancel-button">Cancel</button>
|
||||
<button type="submit" class="save-button">Save</button>
|
||||
</div>
|
||||
<div class="form-buttons delete-button-container">
|
||||
<button type="button" id="deletePlayerButton" class="delete-button">Delete Player</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reset Confirmation Modal -->
|
||||
<div id="resetModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h2>Reset All Data</h2>
|
||||
<p>Are you sure you want to reset all players and timers? This action cannot be undone.</p>
|
||||
<div class="form-buttons">
|
||||
<button type="button" id="resetCancelButton" class="cancel-button">Cancel</button>
|
||||
<button type="button" id="resetConfirmButton" class="save-button">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Camera Capture UI -->
|
||||
<div id="cameraContainer" class="camera-container">
|
||||
<div class="camera-view">
|
||||
<video id="cameraView" autoplay playsinline></video>
|
||||
<canvas id="cameraCanvas" style="display: none;"></canvas>
|
||||
</div>
|
||||
<div class="camera-controls">
|
||||
<button id="cameraCancelButton" class="camera-button-cancel">Cancel</button>
|
||||
<button id="cameraCaptureButton" class="camera-button-large"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Script for handling URL scheme and deep links -->
|
||||
<script type="module">
|
||||
// Register the custom URL protocol handler (web+gametimer://)
|
||||
if ('registerProtocolHandler' in navigator) {
|
||||
try {
|
||||
navigator.registerProtocolHandler(
|
||||
'web+gametimer',
|
||||
'https://game-timer.virtonline.eu/?action=%s',
|
||||
'Game Timer'
|
||||
);
|
||||
console.log('Protocol handler registered');
|
||||
} catch (e) {
|
||||
console.error('Failed to register protocol handler:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to parse URL parameters
|
||||
function getUrlParams() {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const hashParams = new URLSearchParams(window.location.hash.substring(1));
|
||||
|
||||
// Check search parameters first (for direct links)
|
||||
const action = searchParams.get('action');
|
||||
if (action) {
|
||||
// Clean the action parameter (remove 'web+gametimer://' if present)
|
||||
return action.replace('web+gametimer://', '');
|
||||
}
|
||||
|
||||
// Then check hash parameters (for deep links)
|
||||
return hashParams.get('action');
|
||||
}
|
||||
|
||||
// Initialize URL handling
|
||||
function initUrlHandling() {
|
||||
const action = getUrlParams();
|
||||
if (action) {
|
||||
console.log('URL action detected:', action);
|
||||
// Set the action in the hash to be processed by the main app
|
||||
window.location.hash = `action=${action}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Run initialization when DOM is fully loaded
|
||||
document.addEventListener('DOMContentLoaded', initUrlHandling);
|
||||
</script>
|
||||
|
||||
<!-- Main application script -->
|
||||
<script type="module" src="audio.js"></script>
|
||||
<script type="module" src="apps.js"></script>
|
||||
<script>
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker.register("/sw.js")
|
||||
.then(() => console.log("Service Worker Registered"))
|
||||
.catch((err) => console.log("Service Worker Failed", err));
|
||||
}
|
||||
</script>
|
||||
<footer class="app-footer">
|
||||
<div class="author-info">
|
||||
<p>Vibe coded by Martin</p>
|
||||
<p>Version 0.0.1</p>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Code injected by live-server -->
|
||||
<script>
|
||||
// <![CDATA[ <-- For SVG support
|
||||
if ('WebSocket' in window) {
|
||||
(function () {
|
||||
function refreshCSS() {
|
||||
var sheets = [].slice.call(document.getElementsByTagName("link"));
|
||||
var head = document.getElementsByTagName("head")[0];
|
||||
for (var i = 0; i < sheets.length; ++i) {
|
||||
var elem = sheets[i];
|
||||
var parent = elem.parentElement || head;
|
||||
parent.removeChild(elem);
|
||||
var rel = elem.rel;
|
||||
if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
|
||||
var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
|
||||
elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
|
||||
}
|
||||
parent.appendChild(elem);
|
||||
}
|
||||
}
|
||||
var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
|
||||
var address = protocol + window.location.host + window.location.pathname + '/ws';
|
||||
var socket = new WebSocket(address);
|
||||
socket.onmessage = function (msg) {
|
||||
if (msg.data == 'reload') window.location.reload();
|
||||
else if (msg.data == 'refreshcss') refreshCSS();
|
||||
};
|
||||
if (sessionStorage && !sessionStorage.getItem('IsThisFirstTime_Log_From_LiveServer')) {
|
||||
console.log('Live reload enabled.');
|
||||
sessionStorage.setItem('IsThisFirstTime_Log_From_LiveServer', true);
|
||||
}
|
||||
})();
|
||||
}
|
||||
else {
|
||||
console.error('Upgrade your browser. This Browser is NOT supported WebSocket for Live-Reloading.');
|
||||
}
|
||||
// ]]>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,213 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="theme-color" content="#2c3e50">
|
||||
<title>Game Timer</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<!-- Deep Linking - App Links for Android -->
|
||||
<link rel="alternate" href="android-app://eu.virtonline.gametimer/https/game-timer.virtonline.eu" />
|
||||
|
||||
<!-- Deep Linking - Universal Links for iOS -->
|
||||
<meta name="apple-itunes-app" content="app-id=yourAppID, app-argument=https://game-timer.virtonline.eu">
|
||||
|
||||
<!-- Deep Linking - Web App URL Handling -->
|
||||
<link rel="alternate" href="web+gametimer://action" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<header class="header">
|
||||
<div class="game-controls">
|
||||
<button id="gameButton" class="game-button">Start Game</button>
|
||||
</div>
|
||||
<div class="header-buttons">
|
||||
<button id="resetButton" class="header-button" title="Reset All Data">
|
||||
<i class="fas fa-redo-alt"></i>
|
||||
</button>
|
||||
<button id="addPlayerButton" class="header-button" title="Add New Player">
|
||||
<i class="fas fa-user-plus"></i>
|
||||
</button>
|
||||
<button id="setupButton" class="header-button" title="Setup Current Player">
|
||||
<i class="fas fa-cog"></i>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="carousel-container">
|
||||
<div id="carousel" class="carousel">
|
||||
<!-- Player cards will be dynamically inserted here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Player Edit Modal -->
|
||||
<div id="playerModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h2 id="modalTitle">Edit Player</h2>
|
||||
<form id="playerForm">
|
||||
<div class="form-group">
|
||||
<label for="playerName">Name</label>
|
||||
<input type="text" id="playerName" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="playerImage">Image</label>
|
||||
<div class="image-input-container">
|
||||
<input type="file" id="playerImage" accept="image/*">
|
||||
<button type="button" id="cameraButton" class="camera-button">
|
||||
<i class="fas fa-camera"></i> Take Photo
|
||||
</button>
|
||||
</div>
|
||||
<div id="imagePreview" class="player-image" style="margin-top: 0.5rem;">
|
||||
<i class="fas fa-user"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="playerTimeContainer" class="form-group">
|
||||
<label for="playerTime">Time (minutes)</label>
|
||||
<input type="number" id="playerTime" min="1" max="180" value="5" required>
|
||||
</div>
|
||||
<div id="remainingTimeContainer" class="form-group" style="display: none;">
|
||||
<label for="playerRemainingTime">Remaining Time (MM:SS)</label>
|
||||
<input type="text" id="playerRemainingTime" pattern="[0-9]{2}:[0-9]{2}" placeholder="05:00">
|
||||
<small>Format: Minutes:Seconds (e.g., 05:30)</small>
|
||||
</div>
|
||||
<div class="form-buttons">
|
||||
<button type="button" id="cancelButton" class="cancel-button">Cancel</button>
|
||||
<button type="submit" class="save-button">Save</button>
|
||||
</div>
|
||||
<div class="form-buttons delete-button-container">
|
||||
<button type="button" id="deletePlayerButton" class="delete-button">Delete Player</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reset Confirmation Modal -->
|
||||
<div id="resetModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h2>Reset All Data</h2>
|
||||
<p>Are you sure you want to reset all players and timers? This action cannot be undone.</p>
|
||||
<div class="form-buttons">
|
||||
<button type="button" id="resetCancelButton" class="cancel-button">Cancel</button>
|
||||
<button type="button" id="resetConfirmButton" class="save-button">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Camera Capture UI -->
|
||||
<div id="cameraContainer" class="camera-container">
|
||||
<div class="camera-view">
|
||||
<video id="cameraView" autoplay playsinline></video>
|
||||
<canvas id="cameraCanvas" style="display: none;"></canvas>
|
||||
</div>
|
||||
<div class="camera-controls">
|
||||
<button id="cameraCancelButton" class="camera-button-cancel">Cancel</button>
|
||||
<button id="cameraCaptureButton" class="camera-button-large"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Script for handling URL scheme and deep links -->
|
||||
<script type="module">
|
||||
// Register the custom URL protocol handler (web+gametimer://)
|
||||
if ('registerProtocolHandler' in navigator) {
|
||||
try {
|
||||
navigator.registerProtocolHandler(
|
||||
'web+gametimer',
|
||||
'https://game-timer.virtonline.eu/?action=%s',
|
||||
'Game Timer'
|
||||
);
|
||||
console.log('Protocol handler registered');
|
||||
} catch (e) {
|
||||
console.error('Failed to register protocol handler:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to parse URL parameters
|
||||
function getUrlParams() {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const hashParams = new URLSearchParams(window.location.hash.substring(1));
|
||||
|
||||
// Check search parameters first (for direct links)
|
||||
const action = searchParams.get('action');
|
||||
if (action) {
|
||||
// Clean the action parameter (remove 'web+gametimer://' if present)
|
||||
return action.replace('web+gametimer://', '');
|
||||
}
|
||||
|
||||
// Then check hash parameters (for deep links)
|
||||
return hashParams.get('action');
|
||||
}
|
||||
|
||||
// Initialize URL handling
|
||||
function initUrlHandling() {
|
||||
const action = getUrlParams();
|
||||
if (action) {
|
||||
console.log('URL action detected:', action);
|
||||
// Set the action in the hash to be processed by the main app
|
||||
window.location.hash = `action=${action}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Run initialization when DOM is fully loaded
|
||||
document.addEventListener('DOMContentLoaded', initUrlHandling);
|
||||
</script>
|
||||
|
||||
<!-- Main application script -->
|
||||
<script type="module" src="audio.js"></script>
|
||||
<script type="module" src="apps.js"></script>
|
||||
<script>
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker.register("/sw.js")
|
||||
.then(() => console.log("Service Worker Registered"))
|
||||
.catch((err) => console.log("Service Worker Failed", err));
|
||||
}
|
||||
</script>
|
||||
<footer class="app-footer">
|
||||
<div class="author-info">
|
||||
<p>Vibe coded by Martin</p>
|
||||
<p>Version 0.0.1</p>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Code injected by live-server -->
|
||||
<script>
|
||||
// <![CDATA[ <-- For SVG support
|
||||
if ('WebSocket' in window) {
|
||||
(function () {
|
||||
function refreshCSS() {
|
||||
var sheets = [].slice.call(document.getElementsByTagName("link"));
|
||||
var head = document.getElementsByTagName("head")[0];
|
||||
for (var i = 0; i < sheets.length; ++i) {
|
||||
var elem = sheets[i];
|
||||
var parent = elem.parentElement || head;
|
||||
parent.removeChild(elem);
|
||||
var rel = elem.rel;
|
||||
if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
|
||||
var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
|
||||
elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
|
||||
}
|
||||
parent.appendChild(elem);
|
||||
}
|
||||
}
|
||||
var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
|
||||
var address = protocol + window.location.host + window.location.pathname + '/ws';
|
||||
var socket = new WebSocket(address);
|
||||
socket.onmessage = function (msg) {
|
||||
if (msg.data == 'reload') window.location.reload();
|
||||
else if (msg.data == 'refreshcss') refreshCSS();
|
||||
};
|
||||
if (sessionStorage && !sessionStorage.getItem('IsThisFirstTime_Log_From_LiveServer')) {
|
||||
console.log('Live reload enabled.');
|
||||
sessionStorage.setItem('IsThisFirstTime_Log_From_LiveServer', true);
|
||||
}
|
||||
})();
|
||||
}
|
||||
else {
|
||||
console.error('Upgrade your browser. This Browser is NOT supported WebSocket for Live-Reloading.');
|
||||
}
|
||||
// ]]>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,213 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="theme-color" content="#2c3e50">
|
||||
<title>Game Timer</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<!-- Deep Linking - App Links for Android -->
|
||||
<link rel="alternate" href="android-app://eu.virtonline.gametimer/https/game-timer.virtonline.eu" />
|
||||
|
||||
<!-- Deep Linking - Universal Links for iOS -->
|
||||
<meta name="apple-itunes-app" content="app-id=yourAppID, app-argument=https://game-timer.virtonline.eu">
|
||||
|
||||
<!-- Deep Linking - Web App URL Handling -->
|
||||
<link rel="alternate" href="web+gametimer://action" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<header class="header">
|
||||
<div class="game-controls">
|
||||
<button id="gameButton" class="game-button">Start Game</button>
|
||||
</div>
|
||||
<div class="header-buttons">
|
||||
<button id="resetButton" class="header-button" title="Reset All Data">
|
||||
<i class="fas fa-redo-alt"></i>
|
||||
</button>
|
||||
<button id="addPlayerButton" class="header-button" title="Add New Player">
|
||||
<i class="fas fa-user-plus"></i>
|
||||
</button>
|
||||
<button id="setupButton" class="header-button" title="Setup Current Player">
|
||||
<i class="fas fa-cog"></i>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="carousel-container">
|
||||
<div id="carousel" class="carousel">
|
||||
<!-- Player cards will be dynamically inserted here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Player Edit Modal -->
|
||||
<div id="playerModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h2 id="modalTitle">Edit Player</h2>
|
||||
<form id="playerForm">
|
||||
<div class="form-group">
|
||||
<label for="playerName">Name</label>
|
||||
<input type="text" id="playerName" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="playerImage">Image</label>
|
||||
<div class="image-input-container">
|
||||
<input type="file" id="playerImage" accept="image/*">
|
||||
<button type="button" id="cameraButton" class="camera-button">
|
||||
<i class="fas fa-camera"></i> Take Photo
|
||||
</button>
|
||||
</div>
|
||||
<div id="imagePreview" class="player-image" style="margin-top: 0.5rem;">
|
||||
<i class="fas fa-user"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="playerTimeContainer" class="form-group">
|
||||
<label for="playerTime">Time (minutes)</label>
|
||||
<input type="number" id="playerTime" min="1" max="180" value="5" required>
|
||||
</div>
|
||||
<div id="remainingTimeContainer" class="form-group" style="display: none;">
|
||||
<label for="playerRemainingTime">Remaining Time (MM:SS)</label>
|
||||
<input type="text" id="playerRemainingTime" pattern="[0-9]{2}:[0-9]{2}" placeholder="05:00">
|
||||
<small>Format: Minutes:Seconds (e.g., 05:30)</small>
|
||||
</div>
|
||||
<div class="form-buttons">
|
||||
<button type="button" id="cancelButton" class="cancel-button">Cancel</button>
|
||||
<button type="submit" class="save-button">Save</button>
|
||||
</div>
|
||||
<div class="form-buttons delete-button-container">
|
||||
<button type="button" id="deletePlayerButton" class="delete-button">Delete Player</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reset Confirmation Modal -->
|
||||
<div id="resetModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h2>Reset All Data</h2>
|
||||
<p>Are you sure you want to reset all players and timers? This action cannot be undone.</p>
|
||||
<div class="form-buttons">
|
||||
<button type="button" id="resetCancelButton" class="cancel-button">Cancel</button>
|
||||
<button type="button" id="resetConfirmButton" class="save-button">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Camera Capture UI -->
|
||||
<div id="cameraContainer" class="camera-container">
|
||||
<div class="camera-view">
|
||||
<video id="cameraView" autoplay playsinline></video>
|
||||
<canvas id="cameraCanvas" style="display: none;"></canvas>
|
||||
</div>
|
||||
<div class="camera-controls">
|
||||
<button id="cameraCancelButton" class="camera-button-cancel">Cancel</button>
|
||||
<button id="cameraCaptureButton" class="camera-button-large"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Script for handling URL scheme and deep links -->
|
||||
<script type="module">
|
||||
// Register the custom URL protocol handler (web+gametimer://)
|
||||
if ('registerProtocolHandler' in navigator) {
|
||||
try {
|
||||
navigator.registerProtocolHandler(
|
||||
'web+gametimer',
|
||||
'https://game-timer.virtonline.eu/?action=%s',
|
||||
'Game Timer'
|
||||
);
|
||||
console.log('Protocol handler registered');
|
||||
} catch (e) {
|
||||
console.error('Failed to register protocol handler:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to parse URL parameters
|
||||
function getUrlParams() {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const hashParams = new URLSearchParams(window.location.hash.substring(1));
|
||||
|
||||
// Check search parameters first (for direct links)
|
||||
const action = searchParams.get('action');
|
||||
if (action) {
|
||||
// Clean the action parameter (remove 'web+gametimer://' if present)
|
||||
return action.replace('web+gametimer://', '');
|
||||
}
|
||||
|
||||
// Then check hash parameters (for deep links)
|
||||
return hashParams.get('action');
|
||||
}
|
||||
|
||||
// Initialize URL handling
|
||||
function initUrlHandling() {
|
||||
const action = getUrlParams();
|
||||
if (action) {
|
||||
console.log('URL action detected:', action);
|
||||
// Set the action in the hash to be processed by the main app
|
||||
window.location.hash = `action=${action}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Run initialization when DOM is fully loaded
|
||||
document.addEventListener('DOMContentLoaded', initUrlHandling);
|
||||
</script>
|
||||
|
||||
<!-- Main application script -->
|
||||
<script type="module" src="audio.js"></script>
|
||||
<script type="module" src="apps.js"></script>
|
||||
<script>
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker.register("/sw.js")
|
||||
.then(() => console.log("Service Worker Registered"))
|
||||
.catch((err) => console.log("Service Worker Failed", err));
|
||||
}
|
||||
</script>
|
||||
<footer class="app-footer">
|
||||
<div class="author-info">
|
||||
<p>Vibe coded by Martin</p>
|
||||
<p>Version 0.0.1</p>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Code injected by live-server -->
|
||||
<script>
|
||||
// <![CDATA[ <-- For SVG support
|
||||
if ('WebSocket' in window) {
|
||||
(function () {
|
||||
function refreshCSS() {
|
||||
var sheets = [].slice.call(document.getElementsByTagName("link"));
|
||||
var head = document.getElementsByTagName("head")[0];
|
||||
for (var i = 0; i < sheets.length; ++i) {
|
||||
var elem = sheets[i];
|
||||
var parent = elem.parentElement || head;
|
||||
parent.removeChild(elem);
|
||||
var rel = elem.rel;
|
||||
if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
|
||||
var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
|
||||
elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
|
||||
}
|
||||
parent.appendChild(elem);
|
||||
}
|
||||
}
|
||||
var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
|
||||
var address = protocol + window.location.host + window.location.pathname + '/ws';
|
||||
var socket = new WebSocket(address);
|
||||
socket.onmessage = function (msg) {
|
||||
if (msg.data == 'reload') window.location.reload();
|
||||
else if (msg.data == 'refreshcss') refreshCSS();
|
||||
};
|
||||
if (sessionStorage && !sessionStorage.getItem('IsThisFirstTime_Log_From_LiveServer')) {
|
||||
console.log('Live reload enabled.');
|
||||
sessionStorage.setItem('IsThisFirstTime_Log_From_LiveServer', true);
|
||||
}
|
||||
})();
|
||||
}
|
||||
else {
|
||||
console.error('Upgrade your browser. This Browser is NOT supported WebSocket for Live-Reloading.');
|
||||
}
|
||||
// ]]>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,213 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="theme-color" content="#2c3e50">
|
||||
<title>Game Timer</title>
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.2/css/all.min.css">
|
||||
<link rel="stylesheet" href="styles.css">
|
||||
|
||||
<!-- Deep Linking - App Links for Android -->
|
||||
<link rel="alternate" href="android-app://eu.virtonline.gametimer/https/game-timer.virtonline.eu" />
|
||||
|
||||
<!-- Deep Linking - Universal Links for iOS -->
|
||||
<meta name="apple-itunes-app" content="app-id=yourAppID, app-argument=https://game-timer.virtonline.eu">
|
||||
|
||||
<!-- Deep Linking - Web App URL Handling -->
|
||||
<link rel="alternate" href="web+gametimer://action" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="app-container">
|
||||
<header class="header">
|
||||
<div class="game-controls">
|
||||
<button id="gameButton" class="game-button">Start Game</button>
|
||||
</div>
|
||||
<div class="header-buttons">
|
||||
<button id="resetButton" class="header-button" title="Reset All Data">
|
||||
<i class="fas fa-redo-alt"></i>
|
||||
</button>
|
||||
<button id="addPlayerButton" class="header-button" title="Add New Player">
|
||||
<i class="fas fa-user-plus"></i>
|
||||
</button>
|
||||
<button id="setupButton" class="header-button" title="Setup Current Player">
|
||||
<i class="fas fa-cog"></i>
|
||||
</button>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<div class="carousel-container">
|
||||
<div id="carousel" class="carousel">
|
||||
<!-- Player cards will be dynamically inserted here -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Player Edit Modal -->
|
||||
<div id="playerModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h2 id="modalTitle">Edit Player</h2>
|
||||
<form id="playerForm">
|
||||
<div class="form-group">
|
||||
<label for="playerName">Name</label>
|
||||
<input type="text" id="playerName" required>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="playerImage">Image</label>
|
||||
<div class="image-input-container">
|
||||
<input type="file" id="playerImage" accept="image/*">
|
||||
<button type="button" id="cameraButton" class="camera-button">
|
||||
<i class="fas fa-camera"></i> Take Photo
|
||||
</button>
|
||||
</div>
|
||||
<div id="imagePreview" class="player-image" style="margin-top: 0.5rem;">
|
||||
<i class="fas fa-user"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div id="playerTimeContainer" class="form-group">
|
||||
<label for="playerTime">Time (minutes)</label>
|
||||
<input type="number" id="playerTime" min="1" max="180" value="5" required>
|
||||
</div>
|
||||
<div id="remainingTimeContainer" class="form-group" style="display: none;">
|
||||
<label for="playerRemainingTime">Remaining Time (MM:SS)</label>
|
||||
<input type="text" id="playerRemainingTime" pattern="[0-9]{2}:[0-9]{2}" placeholder="05:00">
|
||||
<small>Format: Minutes:Seconds (e.g., 05:30)</small>
|
||||
</div>
|
||||
<div class="form-buttons">
|
||||
<button type="button" id="cancelButton" class="cancel-button">Cancel</button>
|
||||
<button type="submit" class="save-button">Save</button>
|
||||
</div>
|
||||
<div class="form-buttons delete-button-container">
|
||||
<button type="button" id="deletePlayerButton" class="delete-button">Delete Player</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Reset Confirmation Modal -->
|
||||
<div id="resetModal" class="modal">
|
||||
<div class="modal-content">
|
||||
<h2>Reset All Data</h2>
|
||||
<p>Are you sure you want to reset all players and timers? This action cannot be undone.</p>
|
||||
<div class="form-buttons">
|
||||
<button type="button" id="resetCancelButton" class="cancel-button">Cancel</button>
|
||||
<button type="button" id="resetConfirmButton" class="save-button">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Camera Capture UI -->
|
||||
<div id="cameraContainer" class="camera-container">
|
||||
<div class="camera-view">
|
||||
<video id="cameraView" autoplay playsinline></video>
|
||||
<canvas id="cameraCanvas" style="display: none;"></canvas>
|
||||
</div>
|
||||
<div class="camera-controls">
|
||||
<button id="cameraCancelButton" class="camera-button-cancel">Cancel</button>
|
||||
<button id="cameraCaptureButton" class="camera-button-large"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Script for handling URL scheme and deep links -->
|
||||
<script type="module">
|
||||
// Register the custom URL protocol handler (web+gametimer://)
|
||||
if ('registerProtocolHandler' in navigator) {
|
||||
try {
|
||||
navigator.registerProtocolHandler(
|
||||
'web+gametimer',
|
||||
'https://game-timer.virtonline.eu/?action=%s',
|
||||
'Game Timer'
|
||||
);
|
||||
console.log('Protocol handler registered');
|
||||
} catch (e) {
|
||||
console.error('Failed to register protocol handler:', e);
|
||||
}
|
||||
}
|
||||
|
||||
// Function to parse URL parameters
|
||||
function getUrlParams() {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
const hashParams = new URLSearchParams(window.location.hash.substring(1));
|
||||
|
||||
// Check search parameters first (for direct links)
|
||||
const action = searchParams.get('action');
|
||||
if (action) {
|
||||
// Clean the action parameter (remove 'web+gametimer://' if present)
|
||||
return action.replace('web+gametimer://', '');
|
||||
}
|
||||
|
||||
// Then check hash parameters (for deep links)
|
||||
return hashParams.get('action');
|
||||
}
|
||||
|
||||
// Initialize URL handling
|
||||
function initUrlHandling() {
|
||||
const action = getUrlParams();
|
||||
if (action) {
|
||||
console.log('URL action detected:', action);
|
||||
// Set the action in the hash to be processed by the main app
|
||||
window.location.hash = `action=${action}`;
|
||||
}
|
||||
}
|
||||
|
||||
// Run initialization when DOM is fully loaded
|
||||
document.addEventListener('DOMContentLoaded', initUrlHandling);
|
||||
</script>
|
||||
|
||||
<!-- Main application script -->
|
||||
<script type="module" src="audio.js"></script>
|
||||
<script type="module" src="apps.js"></script>
|
||||
<script>
|
||||
if ("serviceWorker" in navigator) {
|
||||
navigator.serviceWorker.register("/sw.js")
|
||||
.then(() => console.log("Service Worker Registered"))
|
||||
.catch((err) => console.log("Service Worker Failed", err));
|
||||
}
|
||||
</script>
|
||||
<footer class="app-footer">
|
||||
<div class="author-info">
|
||||
<p>Vibe coded by Martin</p>
|
||||
<p>Version 0.0.1</p>
|
||||
</div>
|
||||
</footer>
|
||||
<!-- Code injected by live-server -->
|
||||
<script>
|
||||
// <![CDATA[ <-- For SVG support
|
||||
if ('WebSocket' in window) {
|
||||
(function () {
|
||||
function refreshCSS() {
|
||||
var sheets = [].slice.call(document.getElementsByTagName("link"));
|
||||
var head = document.getElementsByTagName("head")[0];
|
||||
for (var i = 0; i < sheets.length; ++i) {
|
||||
var elem = sheets[i];
|
||||
var parent = elem.parentElement || head;
|
||||
parent.removeChild(elem);
|
||||
var rel = elem.rel;
|
||||
if (elem.href && typeof rel != "string" || rel.length == 0 || rel.toLowerCase() == "stylesheet") {
|
||||
var url = elem.href.replace(/(&|\?)_cacheOverride=\d+/, '');
|
||||
elem.href = url + (url.indexOf('?') >= 0 ? '&' : '?') + '_cacheOverride=' + (new Date().valueOf());
|
||||
}
|
||||
parent.appendChild(elem);
|
||||
}
|
||||
}
|
||||
var protocol = window.location.protocol === 'http:' ? 'ws://' : 'wss://';
|
||||
var address = protocol + window.location.host + window.location.pathname + '/ws';
|
||||
var socket = new WebSocket(address);
|
||||
socket.onmessage = function (msg) {
|
||||
if (msg.data == 'reload') window.location.reload();
|
||||
else if (msg.data == 'refreshcss') refreshCSS();
|
||||
};
|
||||
if (sessionStorage && !sessionStorage.getItem('IsThisFirstTime_Log_From_LiveServer')) {
|
||||
console.log('Live reload enabled.');
|
||||
sessionStorage.setItem('IsThisFirstTime_Log_From_LiveServer', true);
|
||||
}
|
||||
})();
|
||||
}
|
||||
else {
|
||||
console.error('Upgrade your browser. This Browser is NOT supported WebSocket for Live-Reloading.');
|
||||
}
|
||||
// ]]>
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user