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
+15
View File
@@ -0,0 +1,15 @@
{% extends "layout.twig" %}
{% block title %}Page Not Found{% endblock %}
{% block content %}
<section class="section">
<div class="container">
<div class="text-center">
<h1>404</h1>
<p>Page not found.</p>
<a href="/" class="btn btn-primary">Go Home</a>
</div>
</div>
</section>
{% endblock %}
+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 %}
+37
View File
@@ -0,0 +1,37 @@
{% extends "layout.twig" %}
{% block title %}Blog - Molenda.net{% endblock %}
{% block content %}
<!-- Blog Section -->
<section id="blog" class="portfolio section">
<!-- Section Title -->
<div class="container section-title" data-aos="fade-up">
<h2>Blog</h2>
<p>Explore my latest thoughts, insights, and experiences in technology, development, and beyond.</p>
</div><!-- End Section Title -->
<div class="container" data-aos="fade-up" data-aos-delay="100">
<div class="row gy-4">
{% for article in articles %}
<div class="col-lg-4 col-md-6 blog-item">
<div class="portfolio-card">
<div class="portfolio-info">
<h4><a href="/blog/{{ article.stub }}">{{ article.title }}</a></h4>
<p>{{ article.headline }}</p>
</div>
</div>
</div>
{% endfor %}
</div><!-- End Blog Items Container -->
<div class="text-center mt-5" data-aos="fade-up" data-aos-delay="400">
<a href="#blog" class="btn btn-primary">View All Articles</a>
</div>
</div>
</section><!-- /Blog Section -->
{% endblock %}
+73
View File
@@ -0,0 +1,73 @@
{% extends "layout.twig" %}
{% block title %}{{ article.title }} - Blog{% endblock %}
{% block content %}
<!-- Breadcrumb -->
<div class="container mt-4">
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
<li class="breadcrumb-item"><a href="/">Home</a></li>
<li class="breadcrumb-item"><a href="/blog">Blog</a></li>
<li class="breadcrumb-item active" aria-current="page">{{ article.title }}</li>
</ol>
</nav>
</div>
<!-- Blog Post Section -->
<section id="blog-post" class="portfolio-details section">
<div class="container" data-aos="fade-up">
<div class="row gy-4">
<div class="col-lg-12" data-aos="fade-left">
<div class="portfolio-details-content">
<h2 class="project-title">{{ article.title }}</h2>
<div class="project-overview">
<p class="lead">
{{ article.headline }}
</p>
<div class="project-content about">
{{ article.content|raw }}
</div>
</div>
</div>
</div>
</div>
</div>
</section><!-- /Blog Post Section -->
<!-- Also Worth Reading Section -->
<section id="also-worth-reading" class="portfolio section">
<div class="container" data-aos="fade-up">
<div class="section-title">
<h2>Also Worth Reading</h2>
</div>
<div class="row gy-4">
{% for item in alsoReading %}
<div class="col-lg-4 col-md-6 blog-item">
<div class="portfolio-card">
<div class="portfolio-info">
<h4><a href="/blog/{{ item.stub }}">{{ item.title }}</a></h4>
<p>{{ item.headline }}</p>
</div>
</div>
</div>
{% endfor %}
</div>
</div>
</section><!-- /Also Worth Reading Section -->
{% endblock %}
+48
View File
@@ -0,0 +1,48 @@
{% extends "layout.twig" %}
{% block title %}molenda.net{% endblock %}
{% block content %}
<section id="hero" class="hero section">
<div class="container" data-aos="fade-up" data-aos-delay="100">
<div class="row gy-4 align-items-center">
<div class="col-lg-6 order-2 order-lg-1">
<div class="hero-content">
<h1 data-aos="fade-up" data-aos-delay="200">Hello, I'm <span class="highlight">Sebastian Molenda</span></h1>
<h2 data-aos="fade-up" data-aos-delay="300">Experienced <span class="typed" data-typed-items="PHP Developer, Python Developer"></span></h2>
<p data-aos="fade-up" data-aos-delay="400">Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
<div class="hero-actions" data-aos="fade-up" data-aos-delay="500">
<a href="portfolio.html" class="btn btn-primary">Check out my experience</a>
</div>
</div>
</div>
<div class="col-lg-6 order-1 order-lg-2">
<div class="hero-image" data-aos="zoom-in" data-aos-delay="300">
<div class="image-wrapper">
<img src="assets/img/profile/profile.jpg" alt="Sebastian Molenda" class="img-fluid">
<div class="floating-elements">
<div class="floating-card design" data-aos="fade-left" data-aos-delay="700">
<i class="bi bi-file-earmark"></i>
<span>Documentation</span>
</div>
<div class="floating-card code" data-aos="fade-right" data-aos-delay="800">
<i class="bi bi-code-slash"></i>
<span>Coder</span>
</div>
<div class="floating-card creativity" data-aos="fade-up" data-aos-delay="900">
<i class="bi bi-back"></i>
<span>Backend</span>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section><!-- /Hero Section -->
{% endblock %}
+140
View File
@@ -0,0 +1,140 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<title>{% block title %}Molenda.net{% endblock %}</title>
<meta name="description" content="">
<meta name="keywords" content="">
<!-- Favicons -->
<link href="/assets/img/favicon.png" rel="icon">
<link href="/assets/img/apple-touch-icon.png" rel="apple-touch-icon">
<!-- Fonts -->
<link href="https://fonts.googleapis.com" rel="preconnect">
<link href="https://fonts.gstatic.com" rel="preconnect" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,100;0,300;0,400;0,500;0,700;0,900;1,100;1,300;1,400;1,500;1,700;1,900&family=Poppins:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&family=Raleway:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;0,800;0,900;1,100;1,200;1,300;1,400;1,500;1,600;1,700;1,800;1,900&display=swap" rel="stylesheet">
<!-- Vendor CSS Files -->
<link href="/assets/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/assets/vendor/bootstrap-icons/bootstrap-icons.css" rel="stylesheet">
<link href="/assets/vendor/aos/aos.css" rel="stylesheet">
<link href="/assets/vendor/swiper/swiper-bundle.min.css" rel="stylesheet">
<link href="/assets/vendor/glightbox/css/glightbox.min.css" rel="stylesheet">
<!-- Main CSS File -->
<link href="/assets/css/main.css" rel="stylesheet">
<!-- =======================================================
* Template Name: FolioOne
* Template URL: https://bootstrapmade.com/folioone-bootstrap-portfolio-website-template/
* Updated: Aug 23 2025 with Bootstrap v5.3.7
* Author: BootstrapMade.com
* License: https://bootstrapmade.com/license/
======================================================== -->
{% block head %}{% endblock %}
</head>
<body class="starter-page-page">
<header id="header" class="header d-flex align-items-center light-background sticky-top">
<div class="container position-relative d-flex align-items-center justify-content-between">
<a href="/" class="logo d-flex align-items-center me-auto me-xl-0">
<img src="/assets/img/sm_logo.png" alt="">
<!-- <h1 class="sitename">molenda.net</h1> -->
</a>
<nav id="navmenu" class="navmenu">
<ul>
<li><a href="/">Home</a></li>
<li><a href="about.html">About</a></li>
<li><a href="resume.html">Resume</a></li>
<li><a href="services.html">Services</a></li>
<li><a href="portfolio.html">Portfolio</a></li>
<!--
<li class="dropdown"><a href="#"><span>Dropdown</span> <i class="bi bi-chevron-down toggle-dropdown"></i></a>
<ul>
<li><a href="#">Dropdown 1</a></li>
<li class="dropdown"><a href="#"><span>Deep Dropdown</span> <i class="bi bi-chevron-down toggle-dropdown"></i></a>
<ul>
<li><a href="#">Deep Dropdown 1</a></li>
<li><a href="#">Deep Dropdown 2</a></li>
<li><a href="#">Deep Dropdown 3</a></li>
<li><a href="#">Deep Dropdown 4</a></li>
<li><a href="#">Deep Dropdown 5</a></li>
</ul>
</li>
<li><a href="#">Dropdown 2</a></li>
<li><a href="#">Dropdown 3</a></li>
<li><a href="#">Dropdown 4</a></li>
</ul>
</li>
<li><a href="contact.html">Contact</a></li>
-->
</ul>
<i class="mobile-nav-toggle d-xl-none bi bi-list"></i>
</nav>
<div class="header-social-links">
{% for key, link in links %}
<a href="{{ link.url }}" class="{{ key }}"><i class="{{ link.class }}"></i></a>
{% endfor %}
</div>
</div>
</header>
<main class="main">
{% block content %}{% endblock %}
</main>
<footer id="footer" class="footer">
<div class="container">
<div class="copyright text-center ">
<p>© <span>Copyright</span> <strong class="px-1 sitename">FolioOne</strong> <span>All Rights Reserved<br></span></p>
</div>
<div class="social-links d-flex justify-content-center">
{% for key, link in links %}
<a href="{{ link.url }}"><i class="{{ link.class }}"></i></a>
{% endfor %}
</div>
<div class="credits">
<!-- All the links in the footer should remain intact. -->
<!-- You can delete the links only if you've purchased the pro version. -->
<!-- Licensing information: https://bootstrapmade.com/license/ -->
<!-- Purchase the pro version with working PHP/AJAX contact form: [buy-url] -->
Designed by <a href="https://bootstrapmade.com/">BootstrapMade</a> | <a href="https://bootstrapmade.com/tools/">DevTools</a>
</div>
</div>
</footer>
<!-- Scroll Top -->
<a href="#" id="scroll-top" class="scroll-top d-flex align-items-center justify-content-center"><i class="bi bi-arrow-up-short"></i></a>
<!-- Preloader -->
<div id="preloader"></div>
<!-- Vendor JS Files -->
<script src="/assets/vendor/bootstrap/js/bootstrap.bundle.min.js"></script>
<script src="/assets/vendor/php-email-form/validate.js"></script>
<script src="/assets/vendor/aos/aos.js"></script>
<script src="/assets/vendor/typed.js/typed.umd.js"></script>
<script src="/assets/vendor/waypoints/noframework.waypoints.js"></script>
<script src="/assets/vendor/purecounter/purecounter_vanilla.js"></script>
<script src="/assets/vendor/swiper/swiper-bundle.min.js"></script>
<script src="/assets/vendor/imagesloaded/imagesloaded.pkgd.min.js"></script>
<script src="/assets/vendor/isotope-layout/isotope.pkgd.min.js"></script>
<script src="/assets/vendor/glightbox/js/glightbox.min.js"></script>
<!-- Main JS File -->
<script src="/assets/js/main.js"></script>
{% block scripts %}{% endblock %}
</body>
</html>