feat: ✨ add new Post wrapper and Blog overview page
This commit is contained in:
parent
b420a6eafa
commit
a2c6842b71
8 changed files with 384 additions and 6 deletions
|
@ -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
166
www/post.php
Normal 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);
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
|
@ -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:
|
||||
|
|
|
@ -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)) {
|
||||
|
||||
|
|
81
www/static/article_blop.css
Normal file
81
www/static/article_blop.css
Normal 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);
|
||||
|
||||
|
||||
}
|
|
@ -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%;
|
||||
|
||||
|
|
23
www/templates/fragments/article_blop.html
Normal file
23
www/templates/fragments/article_blop.html
Normal 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>
|
48
www/templates/post_types/blog_list.html
Normal file
48
www/templates/post_types/blog_list.html
Normal 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%}
|
Loading…
Add table
Add a link
Reference in a new issue