feat: add new Post wrapper and Blog overview page

This commit is contained in:
David Bailey 2024-01-25 15:40:32 +01:00
parent b420a6eafa
commit a2c6842b71
8 changed files with 384 additions and 6 deletions

View file

@ -268,7 +268,7 @@ class MySQLAdapter {
];
$qry = "
SELECT post_path, post_metadata
SELECT *
FROM posts
WHERE MATCH(post_tags) AGAINST (? IN BOOLEAN MODE)
";

166
www/post.php Normal file
View file

@ -0,0 +1,166 @@
<?php
class PostData {
public static $default_banners = [];
public static $markdown_engine = null;
public $data;
public $html_data;
public $raw_data;
public static function _generate_404($sql_row) {
$sql_row ??= [
'post_id' => -1,
'post_path' => '/404.md',
'post_title' => '404 Page',
'post_metadata' => [
'type' => '404'
]
];
}
public static function _deduce_type($path) {
$ext = pathinfo($path, PATHINFO_EXTENSION);
if(preg_match("/\.(\w+)\.md$/", $path, $ext_match)) {
$ext = $ext_match[1];
}
$ext_mapping = [
'' => 'directory',
'md' => 'text/markdown',
'png' => 'image',
'jpg' => 'image',
'jpeg' => 'image'
];
return $ext_mapping[$ext] ?? '?';
}
public static function _deduce_icon($type) {
$icon_mapping = [
'' => 'question',
'text/markdown' => 'markdown',
'directory' => 'folder',
'gallery' => 'images',
'image' => 'image'
];
return $icon_mapping[$type] ?? 'unknown';
}
function __construct($post_handler, $sql_row) {
$this->post_handler = $post_handler;
$this->content_html = null;
$sql_meta = null;
if(!isset($sql_row) or !$sql_row['found']) {
$sql_row = $this->_generate_404($sql_row);
$sql_meta = $sql_row['post_metadata'];
}
$sql_meta = $sql_row['post_metadata'];
if(is_string($sql_meta)) {
$sql_meta = json_decode($sql_meta, true);
}
unset($sql_meta['settings']);
$this->sql_row = $sql_row;
$this->sql_meta = $sql_meta ?? [];
$sql_settings = json_decode($sql_row['post_settings_cache'], true) ?? [];
$data = [
'id' => $sql_row['post_id'],
'path' => $sql_row['post_path'],
'url' => 'https://' . $sql_row['host'] . $sql_row['post_path'],
'created_at' => $sql_row['post_create_time'] ?? '',
'updated_at' => $sql_row['post_update_time'] ?? '',
'view_count' => $sql_row['post_access_count'] ?? 0
];
$data['title'] = $sql_meta['title'] ?? $sql_row['title'];
unset($sql_meta['title']);
$data['tags'] = $sql_meta['tags'] ?? [];
unset($sql_meta['tags']);
$data['type'] = $sql_meta['type']
?? self::_deduce_type($sql_row['post_path']);
unset($sql_meta['type']);
$data['icon'] = $sql_meta['icon']
?? self::_deduce_icon($data['type']);
unset($sql_meta['icon']);
if(isset($sql_meta['media_url'])) {
$data['media_url'] = $sql_meta['media_url'];
$data['thumb_url'] = $sql_meta['thumb_url'] ?? $data['media_url'];
unset($sql_meta['media_url']);
unset($sql_meta['thumb_url']);
}
$data['banners'] = $sql_meta['banners']
?? $sql_settings['banners']
?? self::$default_banners;
unset($sql_meta['banners']);
unset($sql_settings['banners']);
$data['preview_image'] = $sql_meta['preview_image'] ?? $data['banners'][0]['src'] ?? null;
unset($sql_meta['preview_image']);
$data['brief'] = $sql_meta['brief']
?? $data['title'];
unset($sql_meta['brief']);
$data['excerpt'] = $sql_meta['excerpt']
?? substr($sql_row['post_content'], 0, 256);
$data['metadata'] = $sql_meta;
$data['settings'] = $sql_settings;
$this->data = $data;
}
public function __get($name) {
if($name == 'html') {
return $this->get_html();
}
if($name == 'markdown') {
return $this->sql_row['post_content'];
}
if($name == 'json') {
return $this->to_json();
}
return $this->data[$name];
}
public function get_html() {
$fn = self::$markdown_engine;
$this->content_html ??= $fn($this);
return $this->content_html;
}
public function to_json($with_markdown = false, $with_html = false) {
$out_data = $this->data;
if($with_markdown) {
$out_data['markdown'] = $this->sql_row['post_content'];
}
if($with_html) {
$out_data['html'] = $this->get_html();
}
return json_encode($out_data);
}
}
?>

View file

@ -118,12 +118,14 @@ class PostHandler extends MySQLAdapter {
}
function handle_upload($post_path, $file_path) {
$post_path = $this->_sanitize_path($post_path);
$ext = pathinfo($post_path, PATHINFO_EXTENSION);
switch($ext) {
case "md":
$this->save_markdown_post($post_path, file_get_contents($file_path));
$this->make_post_directory(dirname($post_path));
move_uploaded_file($file_path, $this->data_directory . $post_path);
break;
default:

View file

@ -5,6 +5,9 @@ $data_time_start = microtime(true);
require_once 'vendor/autoload.php';
require_once 'post_adapter.php';
require_once 'post.php';
require_once 'fontawesome.php';
require_once 'dergdown.php';
@ -40,6 +43,10 @@ function dergdown_to_html($text) {
return $Parsedown->text($text);
}
function post_to_html($post) {
return dergdown_to_html($post->markdown);
}
PostData::$markdown_engine = "post_to_html";
function deduce_user_agent() {
$real_agent=$_SERVER['HTTP_USER_AGENT'];
@ -160,6 +167,7 @@ function try_render_post($SURI) {
break;
case 'blog':
case 'text/markdown':
echo render_twig('post_types/markdown.html', [
"post" => $post
@ -185,6 +193,30 @@ function try_render_post($SURI) {
]);
break;
case 'blog_list':
if(preg_match('/^(.*[^\/])((?:#.*)?)$/', $SURI, $match)) {
header('Location: ' . $match[1] . '/' . $match[2]);
die();
}
$search_query = $post['post_metadata']['search_tags'] ??
('+type:blog +path:' . $post['post_path'] . '/*');
$search_result = $adapter->perform_post_search($search_query);
$search_result = array_map(function($key) {
$post = new PostData(null, $key);
return $post->data;
}, $search_result['results']);
echo render_twig('post_types/blog_list.html', [
"post" => $post,
"subposts" => $adapter->get_subposts_by_path($SURI),
"blog_posts" => $search_result
]);
break;
case 'image':
echo render_twig('post_types/image.html', [
"post" => $post,
@ -233,7 +265,9 @@ function generate_website($SURI) {
} elseif(preg_match('/^\/api\/posts(.*)$/', $SURI, $match)) {
header('Content-Type: application/json');
echo json_encode($adapter->get_post_by_path($match[1]));
$post = new PostData(null, $adapter->get_post_by_path($match[1]));
echo $post->to_json(with_markdown: true, with_html: true);
} elseif(preg_match('/^\/api\/subposts(.*)$/', $SURI, $match)) {

View file

@ -0,0 +1,81 @@
.article_blop {
position: relative;
overflow: clip;
z-index: 0;
background: var(--bg_2);
margin: 2rem;
padding: 0;
border-radius: 1rem;
box-shadow: 0px 5px 5px 0px #00000040;
transition: 0.3s;
min-height: 10rem;
}
.article_blop_bg {
position: absolute;
left: 0px;
right: 0;
top: 0;
bottom: 0;
background-repeat: no-repeat;
background-position: center;
background-size: cover;
opacity: 0.2;
z-index: -1;
}
.article_blop:hover {
box-shadow: 0px 8px 8px 0px #00000040;
}
.article_blop_content {
padding: 1rem;
padding-top: 5rem;
}
.article_blop_tags {
position: absolute;
top: 0.5rem;
right: 0.2rem;
width: 40%;
height: auto;
list-style: none;
display: flex;
flex-direction: row;
flex-flow: row wrap;
justify-content: right;
}
.article_blop_tags :first-child {
margin-left: auto;
}
.article_blop_tags li {
margin-right: 0.4rem;
margin-bottom: 0.4rem;
padding-left: 0.2rem;
padding-right: 0.2rem;
font-size: 0.8rem;
font-style: normal;
font-weight: bold;
background-color: var(--highlight_1);
border-radius: 0.3rem;
color: var(--bg_2);
}

View file

@ -16,6 +16,7 @@ body {
--bg_2: #2c2943;
--bg_3: #3f4148;
--highlight_0: #ee9015b1;
--highlight_1: #ee9015;
--highlight_2: #edd29e;
@ -185,6 +186,7 @@ a:hover {
z-index: 5;
}
#post_file_titles {
display: flex;
flex-direction: row;
@ -194,13 +196,35 @@ a:hover {
padding: 0px;
}
#post_file_titles * {
padding: 0.5rem;
#post_file_titles li {
padding: 0.2rem 0.8rem;
font-style: bold;
font-size: 1.3rem;
background: var(--highlight_1);
}
#post_file_titles li:hover {
background: var(--highlight_0) !important;
}
#post_file_bar_dirbtn {
margin-left: 0.15rem;
background: var(--bg_2) !important;
}
#post_file_bar #dir_collapse {
display: none;
}
#post_file_bar #dir_collapse:checked + #post_file_bar_dirbtn {
background: var(--highlight_1) !important;
}
.directory {
display: none;
}
#dir_collapse:checked ~ .directory {
display: block;
}
#post_file_path {
width: 100%;
@ -223,7 +247,7 @@ a:hover {
padding-right: 0.2rem;
}
#main_content_wrapper article {
article {
background: var(--bg_3);
border-radius: 0rem 0rem 0.8rem 0.8rem;
@ -232,7 +256,7 @@ a:hover {
padding: 0.75rem;
}
#main_content_wrapper article img {
article img {
display: block;
max-width: 100%;

View file

@ -0,0 +1,23 @@
<a href="{{post.url}}">
<div class="article_blop">
<div class="article_blop_bg" style="background-image:url({{post.preview_image}});"></div>
<div class="article_blop_content">
<h1 class="article_blop_title">
{{post.title}}
</h1>
<ul class="article_blop_tags">
{% for tag in post.tags %}
<li> {{ tag }} </li>
{% endfor %}
</ul>
<span class="article_blop_excerpt">
{{post.excerpt}}
</span>
</div>
</div>
</a>

View file

@ -0,0 +1,48 @@
{% extends "pathed_content.html" %}
{% block extra_head %}
<link rel="stylesheet" href="/static/directorystyle.css">
<link rel="stylesheet" href="/static/article_blop.css">
{%endblock%}
{%block content_article%}
{% if subposts|length > 0 %}
<table class="directory">
<h3>Art Subfolders:</h3>
<tr>
<th></th>
<th class="hsmol_hide">Name</th>
<th>Title</th>
<th class="entry_update_time hsmol_hide">Modified</th>
</tr>
{% for subpost in subposts %}
<tr class="entry">
<td>
{{ fa[subpost.post_metadata.icon] | raw }}
</td>
<td class="hsmol_hide">
<a href={{subpost.post_path}}>{{subpost.post_basename}}</a>
</td>
<td class="entry_title">
<a href={{subpost.post_path}}>{{ subpost.post_metadata.title }}</a>
</td>
<td class="entry_update_time hsmol_hide">
{{ subpost.post_update_time }}
</td>
</tr>
{% endfor %}
</table>
{% endif %}
{{ content_html|raw }}
{% if blog_posts|length > 0 %}
{% for post in blog_posts %}
{% include('fragments/article_blop.html') %}
{% endfor %}
{%else%}
<h4>How sad. There are no blog posts yet... What a real shame :c </h4>
{% endif %}
{%endblock%}