gruby refaktor otyły panie

This commit is contained in:
Sebastian Molenda
2026-05-13 22:43:29 +02:00
parent 0b23946116
commit 0e62b61188
2553 changed files with 0 additions and 532195 deletions
+26
View File
@@ -0,0 +1,26 @@
{% extends "admin/blank.twig" %}
{% block content %}
<h1 class="text-2xl font-bold mb-6">Recent Access Logs</h1>
<table class="min-w-full bg-white">
<thead>
<tr>
<th class="py-2 px-4 border-b">Username</th>
<th class="py-2 px-4 border-b">Password</th>
<th class="py-2 px-4 border-b">IP</th>
<th class="py-2 px-4 border-b">User Agent</th>
<th class="py-2 px-4 border-b">Time</th>
</tr>
</thead>
<tbody>
{% for log in logs %}
<tr>
<td class="py-2 px-4 border-b">{{ log.username }}</td>
<td class="py-2 px-4 border-b">{{ log.password }}</td>
<td class="py-2 px-4 border-b">{{ log.remote_ip }}</td>
<td class="py-2 px-4 border-b">{{ log.user_agent }}</td>
<td class="py-2 px-4 border-b">{{ log.created_at }}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
+12
View File
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Area</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-100">
{% block content %}{% endblock %}
</body>
</html>
+27
View File
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Admin Area</title>
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@2.2.19/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-100">
<div class="flex min-h-screen">
<aside class="w-64 bg-white shadow-md p-6 flex flex-col">
<h2 class="text-xl font-bold mb-6">Admin Menu</h2>
<nav class="flex-1">
<ul>
<li class="mb-4"><a href="/admin" class="text-blue-600 hover:underline">Dashboard</a></li>
<li class="mb-4"><a href="/admin/contents" class="text-blue-600 hover:underline">Contents</a></li>
<li class="mb-4"><a href="/admin/access-logs" class="text-blue-600 hover:underline">Access Logs</a></li>
<li class="mb-4"><a href="/admin/logout" class="text-red-600 hover:underline">Logout</a></li>
</ul>
</nav>
</aside>
<main class="flex-1 p-10">
{% block content %}{% endblock %}
</main>
</div>
</body>
</html>
+44
View File
@@ -0,0 +1,44 @@
{% extends 'layout.twig' %}
{% block title %}Blog Visits - Admin{% endblock %}
{% block content %}
<h1>Blog Visits</h1>
<h2>Top visitors (by hits)</h2>
<table class="table">
<thead>
<tr><th>IP</th><th>User-Agent</th><th>Count</th><th>First seen</th><th>Last seen</th></tr>
</thead>
<tbody>
{% for v in visitors %}
<tr>
<td>{{ v.ip }}</td>
<td style="max-width:40ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap">{{ v.useragent }}</td>
<td>{{ v.cnt }}</td>
<td>{{ v.first_seen }}</td>
<td>{{ v.last_seen }}</td>
</tr>
{% else %}
<tr><td colspan="5">No visitors yet</td></tr>
{% endfor %}
</tbody>
</table>
<h2>Recent detail log</h2>
<table class="table">
<thead><tr><th>Timestamp</th><th>IP</th><th>URL</th></tr></thead>
<tbody>
{% for d in details %}
<tr>
<td>{{ d.timestamp }}</td>
<td>{{ d.ip }}</td>
<td style="max-width:60ch; overflow:hidden; text-overflow:ellipsis; white-space:nowrap">{{ d.url }}</td>
</tr>
{% else %}
<tr><td colspan="3">No details</td></tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
+77
View File
@@ -0,0 +1,77 @@
{% extends "admin/blank.twig" %}
{% block content %}
<h1 class="text-2xl font-bold mb-6">Add Content</h1>
{% if error %}
<p class="text-red-600 mb-4">{{ error }}</p>
{% endif %}
<form method="POST" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4" onsubmit="return validateForm();">
<div class="mb-4">
<label class="block text-gray-700 text-sm font-bold mb-2" for="key">Key</label>
<input name="key" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="key" type="text" placeholder="Key" oninput="validateKey(this)">
<div id="key-feedback" class="text-sm mt-1"></div>
<script>
function validateKey(el) {
let feedback = document.getElementById('key-feedback');
const re = /^[a-z_]+$/;
if (!el.value) {
feedback.textContent = 'Key is required.';
feedback.className = 'text-red-600';
return false;
} else if (!re.test(el.value)) {
feedback.textContent = 'Key must be all lowercase letters and underscores only.';
feedback.className = 'text-red-600';
return false;
} else {
feedback.textContent = '';
return true;
}
}
function validateForm() {
var keyInput = document.getElementById('key');
return validateKey(keyInput);
}
</script>
</div>
<div class="mb-6">
<label class="block text-gray-700 text-sm font-bold mb-2" for="value">Content</label>
<input type="hidden" name="value" id="value-hidden">
<div id="editor" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline h-40 resize-y bg-white" style="height: 200px;"></div>
<div id="json-feedback" class="text-sm mt-2"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.43.3/ace.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
var editor = ace.edit("editor");
editor.session.setMode("ace/mode/json");
editor.setTheme("ace/theme/github");
editor.setOptions({
minLines: 10,
maxLines: 30,
autoScrollEditorIntoView: true
});
// Sync editor content to hidden input
function syncEditor() {
var val = editor.getValue();
document.getElementById('value-hidden').value = val;
validateJson(val);
}
editor.session.on('change', syncEditor);
// JSON validation
function validateJson(val) {
let feedback = document.getElementById('json-feedback');
try {
JSON.parse(val);
feedback.textContent = 'Valid JSON';
feedback.className = 'text-green-600';
} catch (e) {
feedback.textContent = 'Invalid JSON';
feedback.className = 'text-red-600';
}
}
// Initial sync
syncEditor();
</script>
</div>
<div class="flex items-center justify-between">
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="submit">Create</button>
</div>
</form>
{% endblock %}
+79
View File
@@ -0,0 +1,79 @@
{% extends "admin/blank.twig" %}
{% block content %}
<h1 class="text-2xl font-bold mb-6">Edit Content</h1>
{% if error %}
<p class="text-red-600 mb-4">{{ error }}</p>
{% endif %}
<form method="POST" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4" onsubmit="return validateForm();">
<div class="mb-4">
<label class="block text-gray-700 text-sm font-bold mb-2" for="key">Key</label>
<input name="key" value="{{ content.key }}" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="key" type="text" placeholder="Key" oninput="validateKey(this)">
<div id="key-feedback" class="text-sm mt-1"></div>
<script>
function validateKey(el) {
let feedback = document.getElementById('key-feedback');
const re = /^[a-z_]+$/;
if (!el.value) {
feedback.textContent = 'Key is required.';
feedback.className = 'text-red-600';
return false;
} else if (!re.test(el.value)) {
feedback.textContent = 'Key must be all lowercase letters and underscores only.';
feedback.className = 'text-red-600';
return false;
} else {
feedback.textContent = '';
return true;
}
}
function validateForm() {
var keyInput = document.getElementById('key');
return validateKey(keyInput);
}
</script>
</div>
<div class="mb-6">
<label class="block text-gray-700 text-sm font-bold mb-2" for="value">Content</label>
<input type="hidden" name="value" id="value-hidden">
<div id="editor" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline h-40 resize-y bg-white" style="height: 200px;"></div>
<div id="json-feedback" class="text-sm mt-2"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.43.3/ace.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<script>
var editor = ace.edit("editor");
editor.session.setMode("ace/mode/json");
editor.setTheme("ace/theme/github");
editor.setOptions({
minLines: 10,
maxLines: 30,
autoScrollEditorIntoView: true
});
// Set initial value
editor.setValue({{ content.content|json_encode|raw }});
// Sync editor content to hidden input
function syncEditor() {
var val = editor.getValue();
document.getElementById('value-hidden').value = val;
validateJson(val);
}
editor.session.on('change', syncEditor);
// JSON validation
function validateJson(val) {
let feedback = document.getElementById('json-feedback');
try {
JSON.parse(val);
feedback.textContent = 'Valid JSON';
feedback.className = 'text-green-600';
} catch (e) {
feedback.textContent = 'Invalid JSON';
feedback.className = 'text-red-600';
}
}
// Initial sync
syncEditor();
</script>
</div>
<div class="flex items-center justify-between">
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="submit">Save</button>
</div>
</form>
{% endblock %}
+30
View File
@@ -0,0 +1,30 @@
{% extends "admin/blank.twig" %}
{% block content %}
<h1 class="text-2xl font-bold mb-6">Contents List</h1>
<a href="/admin/contents/create" class="bg-blue-500 text-white px-4 py-2 rounded mb-4 inline-block">Add New</a>
<table class="min-w-full bg-white">
<thead>
<tr>
<th class="py-2 px-4 border-b">ID</th>
<th class="py-2 px-4 border-b">Key</th>
<th class="py-2 px-4 border-b">Content</th>
<th class="py-2 px-4 border-b">Actions</th>
</tr>
</thead>
<tbody>
{% for content in contents %}
<tr>
<td class="py-2 px-4 border-b">{{ content.id }}</td>
<td class="py-2 px-4 border-b">{{ content.key }}</td>
<td class="py-2 px-4 border-b">
{{ content.content|length > 80 ? content.content[:80] ~ '...' : content.content }}
</td>
<td class="py-2 px-4 border-b">
<a href="/admin/contents/edit/{{ content.id }}" class="text-blue-600 hover:underline">Edit</a>
<a href="/admin/contents/delete/{{ content.id }}" class="text-red-600 hover:underline ml-2" onclick="return confirm('Are you sure you want to delete this content?');">Delete</a>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% endblock %}
+25
View File
@@ -0,0 +1,25 @@
{% extends "admin/base.twig" %}
{% block content %}
<div class="w-full max-w-xs mx-auto mt-20">
<form method="POST" class="bg-white shadow-md rounded px-8 pt-6 pb-8 mb-4">
<div class="mb-4">
<label class="block text-gray-700 text-sm font-bold mb-2" for="username">
Username
</label>
<input name="username" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 leading-tight focus:outline-none focus:shadow-outline" id="username" type="text" placeholder="Username">
</div>
<div class="mb-6">
<label class="block text-gray-700 text-sm font-bold mb-2" for="password">
Password
</label>
<input name="password" class="shadow appearance-none border rounded w-full py-2 px-3 text-gray-700 mb-3 leading-tight focus:outline-none focus:shadow-outline" id="password" type="password" placeholder="********">
</div>
<div class="flex items-center justify-between">
<button class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline" type="submit">
Login
</button>
</div>
</form>
</div>
{% endblock %}