86 lines
3.7 KiB
HTML
86 lines
3.7 KiB
HTML
{{define "base"}}
|
|
<!DOCTYPE html>
|
|
<html lang="ru">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>{{template "title" .}}</title>
|
|
<script src="https://cdn.tailwindcss.com"></script>
|
|
<script src="https://unpkg.com/htmx.org@1.9.10"></script>
|
|
<style>
|
|
.htmx-request { opacity: 0.5; }
|
|
.line-clamp-2 { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
|
|
</style>
|
|
</head>
|
|
<body class="bg-gray-100 min-h-screen">
|
|
<nav class="bg-white shadow-sm sticky top-0 z-40">
|
|
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
<div class="flex justify-between h-14">
|
|
<div class="flex items-center space-x-8">
|
|
<a href="/" class="text-xl font-bold text-blue-600">PriceForge</a>
|
|
<div class="hidden md:flex space-x-4">
|
|
<a id="admin-pricing-link" href="/admin/pricing" class="text-gray-600 hover:text-gray-900 px-3 py-2 text-sm">Администратор цен</a>
|
|
<a href="/pricelists" class="text-gray-600 hover:text-gray-900 px-3 py-2 text-sm">Прайслисты</a>
|
|
<a href="/admin/pricing" class="text-gray-600 hover:text-gray-900 px-3 py-2 text-sm">Настройки</a>
|
|
</div>
|
|
</div>
|
|
<div class="flex items-center space-x-4">
|
|
<span id="db-connection-status" class="inline-flex items-center gap-1 text-xs text-gray-600">
|
|
<span class="inline-block w-2 h-2 rounded-full bg-gray-400"></span>
|
|
DB: checking
|
|
</span>
|
|
<span id="db-user" class="text-sm text-gray-600"></span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</nav>
|
|
|
|
<main class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-6">
|
|
{{template "content" .}}
|
|
</main>
|
|
|
|
<div id="toast" class="fixed bottom-4 right-4 z-50"></div>
|
|
|
|
<script>
|
|
function showToast(msg, type) {
|
|
const colors = { success: 'bg-green-500', error: 'bg-red-500', info: 'bg-blue-500' };
|
|
const el = document.getElementById('toast');
|
|
el.innerHTML = '<div class="' + (colors[type] || colors.info) + ' text-white px-4 py-2 rounded shadow">' + msg + '</div>';
|
|
setTimeout(() => el.innerHTML = '', 3000);
|
|
}
|
|
|
|
function renderDBStatus(connected, errorText) {
|
|
const el = document.getElementById('db-connection-status');
|
|
if (!el) return;
|
|
if (connected) {
|
|
el.innerHTML = '<span class="inline-block w-2 h-2 rounded-full bg-green-500"></span>DB: online';
|
|
el.title = '';
|
|
return;
|
|
}
|
|
el.innerHTML = '<span class="inline-block w-2 h-2 rounded-full bg-red-500"></span>DB: offline';
|
|
el.title = errorText || 'Database not connected';
|
|
}
|
|
|
|
async function refreshDBConnectionStatus() {
|
|
try {
|
|
const resp = await fetch('/api/db-status');
|
|
const data = await resp.json();
|
|
renderDBStatus(data.connected === true, data.error || '');
|
|
const userEl = document.getElementById('db-user');
|
|
if (data.connected && data.db_user) {
|
|
userEl.innerHTML = '<span class="text-gray-500">@</span>' + data.db_user;
|
|
}
|
|
} catch (e) {
|
|
renderDBStatus(false, 'Status request failed');
|
|
}
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', function () {
|
|
refreshDBConnectionStatus();
|
|
setInterval(refreshDBConnectionStatus, 10000);
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|
|
{{end}}
|