diff --git a/app/controllers/BlogController.php b/app/controllers/BlogController.php
new file mode 100644
index 0000000..23f595e
--- /dev/null
+++ b/app/controllers/BlogController.php
@@ -0,0 +1,63 @@
+router->request()->param('search', '');
+ $posts = $this->search($query);
+
+ $this->defineHelpers();
+
+ $this->router->service()->search = $query;
+ $this->router->service()->posts = $posts;
+ $this->router->service()->injectView = $this->views . '/partials/blog-posts.php';
+ parent::view('blog', 'Hello');
+ }
+
+ public function searchAction(): void
+ {
+ $query = $this->router->request()->param('query', '');
+ $posts = $this->search($query);
+
+ $this->defineHelpers();
+
+ $this->router->service()->posts = $posts;
+ $this->router->service()->partial($this->views . '/partials/blog-posts.php', $posts);
+ }
+
+ //-------------------------------------//
+
+ private function search(string $query): ?array
+ {
+ return BlogModel::selectAll(
+ 'blog_post.*, media.filename, media.extension, page.page, section.section, log.created_at', '
+ LEFT JOIN media ON blog_post.media_id = media.id
+ LEFT JOIN page ON blog_post.page_id = page.id
+ LEFT JOIN section ON page.section_id = section.id
+ LEFT JOIN log ON blog_post.log_id = log.id
+ WHERE blog_post.archived = 0 AND
+ (blog_post.title LIKE :query OR blog_post.tag LIKE :query)
+ ', [[':query', "%$query%", \PDO::PARAM_STR]]);
+ }
+
+ private function defineHelpers(): void
+ {
+ $this->router->service()->prettyTimestamp = function (string $timestamp): string {
+ $date = date_create($timestamp);
+ $date = date_format($date, 'd M Y');
+ return "{$date}";
+ };
+
+ $this->router->service()->tags = function (string $tags): array {
+ // Remove empty elements via array_filter()
+ return array_filter(explode(':', $tags));
+ };
+ }
+
+
+}
diff --git a/app/model/BlogModel.php b/app/model/BlogModel.php
new file mode 100644
index 0000000..f6fa299
--- /dev/null
+++ b/app/model/BlogModel.php
@@ -0,0 +1,9 @@
+
Cache
diff --git a/app/views/blog.php b/app/views/blog.php
new file mode 100644
index 0000000..c09f342
--- /dev/null
+++ b/app/views/blog.php
@@ -0,0 +1,17 @@
+
+sideContent ? '8' : '12'; ?>
+
+
+
+
+
+ = $this->partial($this->injectView); ?>
+
+
+
diff --git a/app/views/partials/blog-posts.php b/app/views/partials/blog-posts.php
new file mode 100644
index 0000000..9654423
--- /dev/null
+++ b/app/views/partials/blog-posts.php
@@ -0,0 +1,38 @@
+
+posts as $post) { ?>
+
+
+
+
+
+
= $post['title']; ?>
+ = ($this->prettyTimestamp)($post['created_at']); ?>
+
+
+ = $post['content']; ?>
+
+
+
+
+ tags:
+ tags)($post['tag']); ?>
+ $tag) { ?>
+ = $tag . (($key === array_key_last($tags)) ? '' : ', '); ?>
+
+
+
+
+
+
+
+
+
. '/media/' . $post['filename'] . '.' . $post['extension']; ?>)
+
+
+
+
+
+
diff --git a/public/css/style.css b/public/css/style.css
index 0a8a1c7..3a2b4d9 100644
--- a/public/css/style.css
+++ b/public/css/style.css
@@ -57,6 +57,11 @@ nav.shadow {
cursor: pointer;
}
+a.clear {
+ color: inherit;
+ text-decoration: none;
+}
+
/* Anchor offset */
h3 {
position: relative;
diff --git a/public/js/site.js b/public/js/site.js
index ef22a2c..13f8273 100644
--- a/public/js/site.js
+++ b/public/js/site.js
@@ -12,6 +12,39 @@ $(document).ready(function() {
return elementBottom > viewportTop && elementTop < viewportBottom;
}
+ //------------------------------------------//
+ // Blog search
+
+ function blogSearch(input)
+ {
+ var url = input.data("url");
+ var search = input.val();
+ window.location.href = url + '?search=' + search;
+ }
+
+ $("#js-blog-search").keydown(function(e) {
+ if (e.key == 'Enter') {
+ e.preventDefault();
+ blogSearch($(this));
+ }
+ });
+
+ $("#js-blog-search-button").click(function() {
+ blogSearch($("#js-blog-search"));
+ });
+
+ $("#js-blog-search").on("input", function() {
+ var url = $(this).data("url");
+ var search = $(this).val();
+ if (search.length == 0 || search.length >= 3) {
+ fetch(url + '/search?query=' + search)
+ .then(response => response.text())
+ .then(data => {
+ $("#blog-posts").empty().append(data);
+ });
+ }
+ });
+
//------------------------------------------//
// Image hover mouseenter
diff --git a/route.php b/route.php
index e12df84..8061f6c 100644
--- a/route.php
+++ b/route.php
@@ -17,6 +17,8 @@ return [
['/img/captcha.jpg', 'IndexController', 'captcha'],
['/robots.txt', 'IndexController', 'robots'],
['/sitemap.xml', 'IndexController', 'sitemap'],
+ ['/blog', 'BlogController'],
+ ['/blog/search', 'BlogController', 'search'],
['/login', 'LoginController', 'login', ['', 'Sign in', '']],
['/reset-password', 'LoginController', 'reset', ['', 'Reset password', '']],
['/logout', 'LoginController', 'logout'],