mirror of
https://github.com/pacnpal/simpleguardhome.git
synced 2025-12-20 12:31:16 -05:00
feat(index.html): implement dark mode toggle and enhance theme handling
This commit is contained in:
@@ -1,10 +1,24 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en" class="dark:bg-gray-900">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
<title>SimpleGuardHome</title>
|
<title>SimpleGuardHome</title>
|
||||||
<script src="https://unpkg.com/@tailwindcss/browser@4" integrity="sha384-fsXZ0Oru5QjGkveFx8DdmBAyKdwnJ7TnbRzDN5LROCKt8PAN8h7y7oqCwtk9cN68" crossorigin="anonymous"></script>
|
<!-- Load Tailwind first -->
|
||||||
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
<script>
|
||||||
|
tailwind.config = {
|
||||||
|
darkMode: 'class'
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize theme before page load
|
||||||
|
const storedTheme = localStorage.getItem('color-theme');
|
||||||
|
if (storedTheme === 'dark') {
|
||||||
|
document.documentElement.classList.add('dark');
|
||||||
|
} else if (storedTheme === 'light') {
|
||||||
|
document.documentElement.classList.remove('dark');
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.3.4/purify.min.js" integrity="sha384-KGmzmwrs7oAU2sG5qfETslFsscVcCaxQrX2d7PW7I9bTrsuTD/eSMFr9jaMS9i+b" crossorigin="anonymous"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dompurify/2.3.4/purify.min.js" integrity="sha384-KGmzmwrs7oAU2sG5qfETslFsscVcCaxQrX2d7PW7I9bTrsuTD/eSMFr9jaMS9i+b" crossorigin="anonymous"></script>
|
||||||
<script>
|
<script>
|
||||||
function escapeHtml(unsafe) {
|
function escapeHtml(unsafe) {
|
||||||
@@ -23,11 +37,11 @@
|
|||||||
const isBlocked = data.reason.startsWith('Filtered');
|
const isBlocked = data.reason.startsWith('Filtered');
|
||||||
if (isBlocked) {
|
if (isBlocked) {
|
||||||
resultDiv.innerHTML = `
|
resultDiv.innerHTML = `
|
||||||
<div class="bg-red-100 border-l-4 border-red-500 text-red-700 p-4 mb-4">
|
<div class="bg-red-100 dark:bg-red-900/30 border-l-4 border-red-500 text-red-700 dark:text-red-300 p-4 mb-4">
|
||||||
<p class="font-bold">Domain is blocked</p>
|
<p class="font-bold">Domain is blocked</p>
|
||||||
<p class="text-sm"><strong>${escapeHtml(domain)}</strong> is blocked</p>
|
<p class="text-sm"><strong>${escapeHtml(domain)}</strong> is blocked</p>
|
||||||
<p class="text-sm">Reason: ${escapeHtml(data.reason)}</p>
|
<p class="text-sm">Reason: ${escapeHtml(data.reason)}</p>
|
||||||
${data.rules?.length ? `<p class="text-sm font-mono bg-red-50 p-2 mt-1 rounded">Rule: ${escapeHtml(data.rules[0].text)}</p>` : ''}
|
${data.rules?.length ? `<p class="text-sm font-mono bg-red-50 dark:bg-red-900/50 p-2 mt-1 rounded">Rule: ${escapeHtml(data.rules[0].text)}</p>` : ''}
|
||||||
${data.service_name ? `<p class="text-sm mt-2">Service: ${escapeHtml(data.service_name)}</p>` : ''}
|
${data.service_name ? `<p class="text-sm mt-2">Service: ${escapeHtml(data.service_name)}</p>` : ''}
|
||||||
</div>`;
|
</div>`;
|
||||||
unblockDiv.innerHTML = `
|
unblockDiv.innerHTML = `
|
||||||
@@ -37,7 +51,7 @@
|
|||||||
</button>`;
|
</button>`;
|
||||||
} else {
|
} else {
|
||||||
resultDiv.innerHTML = `
|
resultDiv.innerHTML = `
|
||||||
<div class="bg-green-100 border-l-4 border-green-500 text-green-700 p-4">
|
<div class="bg-green-100 dark:bg-green-900/30 border-l-4 border-green-500 text-green-700 dark:text-green-300 p-4">
|
||||||
<p class="font-bold">Domain is not blocked</p>
|
<p class="font-bold">Domain is not blocked</p>
|
||||||
<p class="text-sm"><strong>${escapeHtml(domain)}</strong> is allowed</p>
|
<p class="text-sm"><strong>${escapeHtml(domain)}</strong> is allowed</p>
|
||||||
<p class="text-xs mt-2">Status: ${escapeHtml(data.reason)}</p>
|
<p class="text-xs mt-2">Status: ${escapeHtml(data.reason)}</p>
|
||||||
@@ -70,7 +84,7 @@
|
|||||||
domain = preprocessDomain(rawInput);
|
domain = preprocessDomain(rawInput);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
resultDiv.innerHTML = `
|
resultDiv.innerHTML = `
|
||||||
<div class="bg-yellow-100 border-l-4 border-yellow-500 text-yellow-700 p-4">
|
<div class="bg-yellow-100 dark:bg-yellow-900/30 border-l-4 border-yellow-500 text-yellow-700 dark:text-yellow-300 p-4">
|
||||||
<p class="font-bold">Invalid Input</p>
|
<p class="font-bold">Invalid Input</p>
|
||||||
<p class="text-sm">${escapeHtml(error.message)}</p>
|
<p class="text-sm">${escapeHtml(error.message)}</p>
|
||||||
</div>`;
|
</div>`;
|
||||||
@@ -174,18 +188,26 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-gray-100 min-h-screen">
|
<body class="bg-gray-100 dark:bg-gray-900 min-h-screen transition-colors duration-200">
|
||||||
|
<button id="theme-toggle" class="fixed top-4 right-4 p-2 rounded-lg bg-gray-200 dark:bg-gray-700 text-gray-800 dark:text-gray-200 hover:bg-gray-300 dark:hover:bg-gray-600 transition-colors duration-200">
|
||||||
|
<svg id="theme-toggle-dark-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M17.293 13.293A8 8 0 016.707 2.707a8.001 8.001 0 1010.586 10.586z"></path>
|
||||||
|
</svg>
|
||||||
|
<svg id="theme-toggle-light-icon" class="hidden w-5 h-5" fill="currentColor" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M10 2a1 1 0 011 1v1a1 1 0 11-2 0V3a1 1 0 011-1zm4 8a4 4 0 11-8 0 4 4 0 018 0zm-.464 4.95l.707.707a1 1 0 001.414-1.414l-.707-.707a1 1 0 00-1.414 1.414zm2.12-10.607a1 1 0 010 1.414l-.706.707a1 1 0 11-1.414-1.414l.707-.707a1 1 0 011.414 0zM17 11a1 1 0 100-2h-1a1 1 0 100 2h1zm-7 4a1 1 0 011 1v1a1 1 0 11-2 0v-1a1 1 0 011-1zM5.05 6.464A1 1 0 106.465 5.05l-.708-.707a1 1 0 00-1.414 1.414l.707.707zm1.414 8.486l-.707.707a1 1 0 01-1.414-1.414l.707-.707a1 1 0 011.414 1.414zM4 11a1 1 0 100-2H3a1 1 0 000 2h1z"></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
<div class="container mx-auto px-4 py-8 max-w-2xl">
|
<div class="container mx-auto px-4 py-8 max-w-2xl">
|
||||||
<h1 class="text-3xl font-bold text-center mb-8 text-gray-800">SimpleGuardHome</h1>
|
<h1 class="text-3xl font-bold text-center mb-8 text-gray-800 dark:text-white">SimpleGuardHome</h1>
|
||||||
|
|
||||||
<div class="bg-white rounded-lg shadow-md p-6">
|
<div class="bg-white dark:bg-gray-800 rounded-lg shadow-md p-6">
|
||||||
<form onsubmit="checkDomain(event)" class="mb-6">
|
<form onsubmit="checkDomain(event)" class="mb-6">
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label for="domain" class="block text-gray-700 text-sm font-bold mb-2">
|
<label for="domain" class="block text-gray-700 dark:text-gray-300 text-sm font-bold mb-2">
|
||||||
Enter Domain to Check
|
Enter Domain to Check
|
||||||
</label>
|
</label>
|
||||||
<input type="text" id="domain" name="domain" required
|
<input type="text" id="domain" name="domain" required
|
||||||
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline"
|
class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 dark:text-gray-200 dark:bg-gray-700 dark:border-gray-600 leading-tight focus:outline-none focus:shadow-outline"
|
||||||
placeholder="example.com"
|
placeholder="example.com"
|
||||||
title="Please enter a valid domain name">
|
title="Please enter a valid domain name">
|
||||||
</div>
|
</div>
|
||||||
@@ -199,7 +221,60 @@
|
|||||||
<div id="unblock-action" class="mt-4 text-center"></div>
|
<div id="unblock-action" class="mt-4 text-center"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 text-center text-gray-600 text-sm">
|
<script>
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
// Theme toggle functionality
|
||||||
|
const themeToggleDarkIcon = document.getElementById('theme-toggle-dark-icon');
|
||||||
|
const themeToggleLightIcon = document.getElementById('theme-toggle-light-icon');
|
||||||
|
|
||||||
|
// Change the icons inside the button based on previous settings
|
||||||
|
function setThemeIcons() {
|
||||||
|
if (document.documentElement.classList.contains('dark')) {
|
||||||
|
themeToggleDarkIcon.classList.add('hidden');
|
||||||
|
themeToggleLightIcon.classList.remove('hidden');
|
||||||
|
} else {
|
||||||
|
themeToggleLightIcon.classList.add('hidden');
|
||||||
|
themeToggleDarkIcon.classList.remove('hidden');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Check for theme preference
|
||||||
|
const storedTheme = localStorage.getItem('color-theme');
|
||||||
|
if (!storedTheme) {
|
||||||
|
// Only use system preference if no stored preference exists
|
||||||
|
const systemPrefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
document.documentElement.classList.toggle('dark', systemPrefersDark);
|
||||||
|
localStorage.setItem('color-theme', systemPrefersDark ? 'dark' : 'light');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
setThemeIcons();
|
||||||
|
|
||||||
|
// Add click event to toggle button
|
||||||
|
document.getElementById('theme-toggle').addEventListener('click', function() {
|
||||||
|
// Toggle dark class
|
||||||
|
document.documentElement.classList.toggle('dark');
|
||||||
|
|
||||||
|
// Update localStorage
|
||||||
|
if (document.documentElement.classList.contains('dark')) {
|
||||||
|
localStorage.setItem('color-theme', 'dark');
|
||||||
|
} else {
|
||||||
|
localStorage.setItem('color-theme', 'light');
|
||||||
|
}
|
||||||
|
|
||||||
|
setThemeIcons();
|
||||||
|
});
|
||||||
|
|
||||||
|
// System preference changes are now ignored if there's a stored preference
|
||||||
|
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', function(e) {
|
||||||
|
if (!localStorage.getItem('color-theme')) {
|
||||||
|
document.documentElement.classList.toggle('dark', e.matches);
|
||||||
|
localStorage.setItem('color-theme', e.matches ? 'dark' : 'light');
|
||||||
|
setThemeIcons();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<div class="mt-4 text-center text-gray-600 dark:text-gray-400 text-sm">
|
||||||
Make sure your AdGuard Home instance is running and properly configured in the .env file.
|
Make sure your AdGuard Home instance is running and properly configured in the .env file.
|
||||||
<br>
|
<br>
|
||||||
<span class="text-xs">Rules are automatically backed up before any changes.</span>
|
<span class="text-xs">Rules are automatically backed up before any changes.</span>
|
||||||
|
|||||||
Reference in New Issue
Block a user