Compare commits

...

20 commits

Author SHA1 Message Date
2f5d59dd32 fix: 🐛 fix wrong usave of copy (should have been move_uploaded_file)
Some checks failed
/ phplint (push) Failing after 3s
2023-12-14 11:48:03 +01:00
a82290cf73 feat: add api lock key 2023-12-14 11:47:33 +01:00
bc286413ad test: add some test entry content for good measure 2023-12-14 11:46:17 +01:00
ed80a21495 feat: add simple uploading bash script <3 2023-12-14 11:45:55 +01:00
881ea81488 test: add a test image markdown descriptor 2023-12-13 10:27:59 +01:00
653b91cb1e feat: clean up image template to fit other post layouts, add caption 2023-12-13 10:23:21 +01:00
41c7e0cdc3 feat: use directory's own content field instead of README lookup 2023-12-13 10:22:49 +01:00
38a5056ff0 refactor: ♻️ refactor out post-type specific code 2023-12-13 10:19:00 +01:00
9e855fba36 feat: allow for SQL server port specification 2023-12-12 22:39:06 +01:00
0d9bedcaca feat: 🎨 adjust CSS style to give more room to the post on small screens 2023-12-12 22:36:33 +01:00
16fb45aaf4 fix: fix access setting, adding .htaccess 2023-12-11 23:32:13 +01:00
4baa737d95 feat: add option to use secrets JSON file instead 2023-12-11 23:30:39 +01:00
f02e6b3168 feat: move SQL connection parameters into Env. vars 2023-12-11 23:04:49 +01:00
a7a7c738ec refactor: ♻️ clean up unused Twig templates 2023-12-11 22:52:30 +01:00
d54d3077cb feat: use new adapter upload function 2023-12-11 16:22:42 +01:00
b6b8c587a1 feat: add backend for uploading files 2023-12-11 16:20:27 +01:00
de2dea4b18 feat: add "raw" dir to directory, make it indexable 2023-12-11 16:18:26 +01:00
53fc1fac5a test: add test entries to upload 2023-12-11 16:16:31 +01:00
906014cf05 test: add lorem ipsum filler 2023-12-11 16:15:31 +01:00
81056ea42e feat: add writable directory for server content 2023-12-11 16:14:55 +01:00
32 changed files with 614 additions and 178 deletions

2
.gitignore vendored
View file

@ -1 +1,3 @@
/vendor/
sftp.json

View file

@ -14,5 +14,7 @@ RUN a2enmod rewrite
RUN a2enmod headers
RUN docker-php-ext-install mysqli && docker-php-ext-enable mysqli
RUN mkdir raw
COPY www/ .
RUN chmod -R a+r $(ls -I vendor)
RUN chmod -R a+rw $(ls -I vendor)

View file

@ -5,6 +5,12 @@ services:
dockerfile: docker_dev/Dockerfile
ports:
- 8081:80
environment:
MYSQL_USER: root
MYSQL_PASSWORD: example
MYSQL_DATABASE: dragon_fire
MYSQL_HOST: mysql
MYSQL_PORT: 3306
develop:
watch:
- path: ./
@ -17,6 +23,9 @@ services:
ignore:
- ../.git
- mysql_schema.sql
volumes:
- website_datavolume:/var/www/html/raw
mysql:
build:
dockerfile: MysqlDockerfile
@ -32,7 +41,8 @@ services:
watch:
- path: mysql_schema.sql
action: rebuild
# volumes:
# - sqlvolume:/var/lib/mysql
volumes:
- sqlvolume:/var/lib/mysql
volumes:
sqlvolume: {}
website_datavolume: {}

View file

@ -107,5 +107,15 @@ Sorry for this. Shi is working hard :>
# Nothing here yet!
Sorry for this. She GRABS A LOT
----
## And now, for the lorem:
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Eleifend mi in nulla posuere sollicitudin aliquam ultrices sagittis orci. Risus commodo viverra maecenas accumsan lacus vel facilisis. Sed viverra tellus in hac habitasse. Nulla malesuada pellentesque elit eget gravida cum. Posuere sollicitudin aliquam ultrices sagittis orci a. Libero nunc consequat interdum varius sit amet. Bibendum arcu vitae elementum curabitur vitae nunc sed velit. Amet mauris commodo quis imperdiet massa tincidunt nunc pulvinar. Sed adipiscing diam donec adipiscing. Laoreet id donec ultrices tincidunt arcu non sodales. Id semper risus in hendrerit gravida rutrum quisque non. Ut venenatis tellus in metus vulputate eu.
Risus sed vulputate odio ut enim blandit volutpat. Placerat in egestas erat imperdiet. Non curabitur gravida arcu ac tortor dignissim convallis aenean. Neque aliquam vestibulum morbi blandit cursus risus at. Elementum integer enim neque volutpat ac tincidunt vitae semper. Eu ultrices vitae auctor eu augue ut. In mollis nunc sed id semper risus in hendrerit gravida. Lectus arcu bibendum at varius vel pharetra vel turpis nunc. In pellentesque massa placerat duis. Non quam lacus suspendisse faucibus. Vitae aliquet nec ullamcorper sit amet risus nullam. Accumsan lacus vel facilisis volutpat est velit egestas dui.
Risus feugiat in ante metus dictum at tempor commodo. Duis ut diam quam nulla. Nunc aliquet bibendum enim facilisis gravida neque convallis. Tincidunt augue interdum velit euismod in pellentesque. Praesent semper feugiat nibh sed pulvinar proin gravida hendrerit lectus. Non odio euismod lacinia at quis risus sed vulputate odio. Nunc sed blandit libero volutpat sed cras ornare arcu. Adipiscing enim eu turpis egestas pretium aenean pharetra magna. Ut tristique et egestas quis ipsum suspendisse. Blandit cursus risus at ultrices mi tempus imperdiet nulla malesuada.
'
);

15
scripts/upload_file.sh Executable file
View file

@ -0,0 +1,15 @@
CURL_URL=${DERG_UPLOAD_URL:-https://lucidragons.de/api/admin/upload}
CURL_KEY=${DERG_UPLOAD_KEY:-SoftDragonKeys}
for FILE_PATH in "$@"
do
if [ -f "${FILE_PATH}" ]; then
POST_PATH="/${FILE_PATH#"./"}"
echo "Uploading ${FILE_PATH} to ${POST_PATH}"
curl -i -X POST -H "Content-Type: multipart/form-data" \
-F "api_key=${CURL_KEY}" -F "post_path=${POST_PATH}" -F "post_data=@${FILE_PATH}" "${CURL_URL}"
fi
done

View file

@ -0,0 +1,11 @@
---
tags: [what]
directory_data:
type: text/markdown
---
# The dergens
The
yes

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

View file

@ -0,0 +1,8 @@
---
title: A cuddly image <3
author: Shaky // Doggonaut
---
# Cuddly dragons
A dear picture made by a dear friend. Shaky - we hope you are OK.

View file

@ -0,0 +1,12 @@
---
title: A little image test idea
---
# README concept
This file is just to show the README concept - it's its own file but will be
rendered under a directory listing :)
There's also a test for an image! Let's hope that works:
![A very cute image :>](1.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

View file

@ -0,0 +1,8 @@
---
title: A cuddly image <3
author: Shaky // Doggonaut
---
# Cuddly dragons
A dear picture made by a dear friend. Shaky - we hope you are OK.

View file

@ -0,0 +1,12 @@
---
title: A little image test idea
---
# README concept
This file is just to show the README concept - it's its own file but will be
rendered under a directory listing :)
There's also a test for an image! Let's hope that works:
![A very cute image :>](1.png)

View file

@ -1,6 +1,23 @@
AddType text/plain .md
php_value upload_max_filesize 40M
php_value post_max_size 42M
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/?static/.*
RewriteCond %{REQUEST_URI} !^/?(static|raw)/.*
RewriteRule (.*) router.php
Allow from all
Options +Indexes
<filesMatch ".(flv|gif|ico|jpg|jpeg|mp4|mpeg|png|svg|swf|webp)$">
Header set Cache-Control "max-age=315360, public"
</filesMatch>
<filesMatch ".(js)$">
Header set Cache-Control "max-age=315360, public"
</filesMatch>

View file

@ -1,19 +1,31 @@
<?php
use Spatie\YamlFrontMatter\YamlFrontMatter;
class MySQLAdapter {
public $raw;
function __construct() {
$this->raw = mysqli_connect('mysql', 'root', 'example', 'dragon_fire');
$db_params = json_decode(file_get_contents('secrets/db.json'), true);
if (!$this->raw)
{
echo 'Connection failed<br>';
echo 'Error number: ' . mysqli_connect_errno() . '<br>';
echo 'Error message: ' . mysqli_connect_error() . '<br>';
die();
try {
if(false !== getenv('MYSQL_HOST')) {
$this->raw = mysqli_connect(getenv('MYSQL_HOST'),
getenv('MYSQL_USER'), getenv('MYSQL_PASSWORD'),
getenv('MYSQL_DATABASE'),
getenv('MYSQL_PORT'));
}
else {
$this->raw = mysqli_connect($db_params['MYSQL_HOST'],
$db_params['MYSQL_USER'], $db_params['MYSQL_PASSWORD'],
$db_params['MYSQL_DATABASE'],
$db_params['MYSQL_PORT']);
}
} catch (\Throwable $th) {
echo 'Connection failed<br>';
echo 'Error number: ' . mysqli_connect_errno() . '<br>';
echo 'Error message: ' . mysqli_connect_error() . '<br>';
die();
//throw $th;
}
}
@ -25,39 +37,69 @@ class MySQLAdapter {
return $stmt->get_result();
}
function _prepare_post_data($post_data) {
if($post_data == null) {
$post_data = [
"found" => false
function _normalize_post_data($post_data) {
if($post_data == null) {
return [
"found" => false
];
}
else {
$post_data["found"] = true;
$post_data["post_metadata"] = json_decode($post_data["post_metadata"]);
}
return $post_data;
$post_data["found"] = true;
$post_data['post_metadata'] = json_decode($post_data["post_metadata"], true) ?? [];
$post_data["post_content"] ??= '';
return $post_data;
}
function save_markdown_post($post_path, $post_data) {
$frontmatter_post = YamlFrontMatter::parse($post_data);
function bump_post($post_path, $post_metadata = [], $create_dirs = true) {
$post_path = chop($post_path, '/');
$path_depth = substr_count($post_path, "/");
$post_content = $frontmatter_post->body();
$post_metadata = $frontmatter_post->matter();
$post_metadata['type'] = 'text/markdown';
var_dump($post_path, $post_content, $post_metadata);
if($create_dirs) {
$this->make_post_directory(dirname($post_path));
}
$qry = "
INSERT INTO posts
(post_path, post_path_depth, post_metadata, post_content)
VALUES
( ?, ?, ?, ?) AS new
ON DUPLICATE KEY UPDATE post_metadata=new.post_metadata, post_content=new.post_content;";
INSERT INTO posts
(post_path, post_path_depth, post_metadata, post_content)
VALUES
( ?, ?, ?, ?) AS new
ON DUPLICATE KEY UPDATE post_path=new.post_path;";
$this->_exec($qry, "siss",
$post_path,
$path_depth,
json_encode($post_metadata),
'');
}
function make_post_directory($directory) {
$json_metadata = ["type" => 'directory'];
while(strlen($directory) > 1) {
try {
$this->bump_post($directory, $json_metadata, false);
}
catch(Exception $e) {
}
$directory = dirname($directory);
}
}
function update_or_create_post($post_path, $post_metadata, $post_content) {
$post_path = chop($post_path, '/');
$path_depth = substr_count($post_path, "/");
$this->make_post_directory(dirname($post_path));
$qry = "
INSERT INTO posts
(post_path, post_path_depth, post_metadata, post_content)
VALUES
( ?, ?, ?, ?) AS new
ON DUPLICATE KEY UPDATE post_metadata=new.post_metadata, post_content=new.post_content;";
$this->_exec($qry, "siss",
$post_path,
@ -71,7 +113,8 @@ class MySQLAdapter {
$post_path = chop($post_path, '/');
$post_data = $this->_prepare_post_data($this->_exec($qry, "s", $post_path)->fetch_assoc());
$post_data = $this->_exec($qry, "s", $post_path)->fetch_assoc();
$post_data = $this->_normalize_post_data($post_data);
if($with_subposts) {
$post_data['subposts'] = $this->get_subposts_by_path($post_path);
@ -87,7 +130,7 @@ class MySQLAdapter {
$path_depth = substr_count($path, "/");
$qry = "SELECT post_path, post_metadata
$qry = "SELECT post_path, post_metadata, post_update_time
FROM posts
WHERE (post_path LIKE CONCAT(?,'/%'))
AND post_path_depth = ?
@ -97,7 +140,7 @@ class MySQLAdapter {
$post_data = $this->_exec($qry, "si", $path, $path_depth+1)->fetch_all(MYSQLI_ASSOC);
$fn = function($data) {
return $this->_prepare_post_data($data);
return $this->_normalize_post_data($data);
};
$post_data = array_map($fn, $post_data);

99
www/post_adapter.php Normal file
View file

@ -0,0 +1,99 @@
<?php
require_once 'mysql_adapter.php';
use Spatie\YamlFrontMatter\YamlFrontMatter;
class PostHandler extends MySQLAdapter {
public $data_directory;
function __construct() {
parent::__construct();
$this->data_directory = 'raw';
}
function _normalize_post_data($post_data) {
$post_data = parent::_normalize_post_data($post_data);
$post_data["post_basename"] = basename($post_data["post_path"]);
$post_meta = $post_data['post_metadata'];
$post_meta["title"] ??= basename($post_data["post_path"]);
if(!isset($post_meta['type'])) {
$type = null;
$ext = pathinfo($post_data['post_basename'], PATHINFO_EXTENSION);
$ext_mapping = [
'' => 'directory',
'md' => 'text/markdown',
'png' => 'image',
];
if(isset($ext_mapping[$ext])) {
$post_meta['type'] = $ext_mapping[$ext];
}
}
$post_data["post_file_dir"] = '/' . $this->data_directory . $post_data["post_path"];
$post_data['post_metadata'] = $post_meta;
return $post_data;
}
function make_post_directory($directory) {
$data_directory = $this->data_directory . $directory;
is_dir($data_directory) || mkdir($data_directory, 0777, true);
parent::make_post_directory($directory);
}
function save_file($post_path, $file_path) {
$this->bump_post($post_path);
move_uploaded_file($file_path, $this->data_directory . $post_path);
}
function save_markdown_post($post_path, $post_data) {
$frontmatter_post = YamlFrontMatter::parse($post_data);
$post_path = chop($post_path, '/');
$post_content = $frontmatter_post->body();
$post_metadata = $frontmatter_post->matter();
if(basename($post_path) == "README.md") {
$readme_metadata = [];
if(isset($post_metadata['directory_data'])) {
$readme_metadata = $post_metadata['directory_data'];
}
$this->update_or_create_post(dirname($post_path),
$readme_metadata, $post_content);
}
$this->update_or_create_post($post_path, $post_metadata, $post_content);
}
function handle_upload($post_path, $file_path) {
$ext = pathinfo($post_path, PATHINFO_EXTENSION);
switch($ext) {
case "md":
$this->save_markdown_post($post_path, file_get_contents($file_path));
move_uploaded_file($file_path, $this->data_directory . $post_path);
break;
case "mddesc":
$this->save_markdown_post(chop($post_path, '.mddesc'), file_get_contents($file_path));
break;
default:
$this->save_file($post_path, $file_path);
}
}
}
?>

View file

@ -1,11 +1,11 @@
<?php
require_once 'vendor/autoload.php';
require_once 'mysql_adapter.php';
require_once 'post_adapter.php';
// $sql = mysqli_connect('mysql', 'root', 'example', 'dragon_fire');
$adapter = new MySQLAdapter();
$adapter = new PostHandler();
//if (!$sql)
// {
@ -36,6 +36,32 @@ $SURI = $_SERVER['REQUEST_URI'];
if($SURI == '/') {
echo $twig->render('root.html');
} elseif(preg_match('/^\/api\/admin/', $SURI)) {
header('Content-Type: application/json');
$user_api_key = '';
if(isset($_GET['api_key'])) {
$user_api_key = $_GET['api_key'];
}
if(isset($_POST['api_key'])) {
$user_api_key = $_POST['api_key'];
}
if($user_api_key != file_get_contents('secrets/api_admin_key')) {
http_response_code(401);
echo json_encode([
"authorized" => false
]);
die();
}
if($SURI = '/api/admin/upload') {
$adapter->handle_upload($_POST['post_path'], $_FILES['post_data']['tmp_name']);
echo json_encode(["ok" => true]);
}
} elseif(preg_match('/^\/api/', $SURI)) {
if(preg_match('/^\/api\/posts(.*)$/', $SURI, $match)) {
@ -48,33 +74,37 @@ if($SURI == '/') {
echo json_encode(get_subposts($match[1]));
} elseif($SURI == '/api/upload') {
if(array_key_exists('post_data', $_FILES)) {
$upload_content = file_get_contents($_FILES['post_data']['tmp_name']);
$upload_path = $_POST['post_path'];
$adapter->save_markdown_post($upload_path, $upload_content);
}
echo $twig->render('upload.html');
}
} elseif($_SERVER['HTTP_SEC_FETCH_DEST'] == 'image') {
header('Location: /raw' . $SURI);
exit(0);
} elseif(true) {
$post = $adapter->get_post_by_path($SURI);
echo $twig->render('about.html', [
"post" => $post,
"subposts" => $post['subposts']
]);
if($post['post_metadata']['type'] == 'directory') {
if(preg_match('/^(.*[^\/])((?:#.*)?)$/', $SURI, $match)) {
header('Location: ' . $match[1] . '/' . $match[2]);
exit(0);
}
echo $twig->render('post_types/directory.html', [
"post" => $post,
"subposts" => $post['subposts']
]);
}
elseif($post['post_metadata']['type'] == 'text/markdown') {
echo $twig->render('post_types/markdown.html', [
"post" => $post,
"subposts" => $post['subposts']
]);
}
elseif($post['post_metadata']['type'] == 'image') {
echo $twig->render('post_types/image.html', [
"post" => $post
]);
}
} elseif(preg_match('/^\/about(.html)?$/', $SURI)) {
echo $twig->render('about.html');
} elseif(preg_match('/^\/gallery\/([^\?]+)/', $SURI)) {
echo $twig->render('/gallery/gallery_entry.html', [
'image_url' => '/static/banner/0.png',
'image_title' => 'Test!',
'image_desc' => 'A soft piece made by a dear friend',
'artist_name' => 'Doggonaut',
'artist_src_link' => 'https://twitter.com/doggonaut'
]);
} else {
echo $twig->render('rrror.html',[
"error_code" => '404 Hoard not found!',

2
www/secrets/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
*.json
api_admin_key

2
www/secrets/.htaccess Normal file
View file

@ -0,0 +1,2 @@
Deny from all

View file

@ -1,5 +1,7 @@
Allow from all
Options +Indexes
<filesMatch ".(flv|gif|ico|jpg|jpeg|mp4|mpeg|png|svg|swf|webp)$">
Header set Cache-Control "max-age=315360, public"
</filesMatch>

View file

@ -1,4 +1,5 @@
* {
box-sizing: border-box;
margin: 0;
@ -6,35 +7,44 @@
}
body {
color: #B0B0B0;
background: #201c2a;
--bg_1: #0e0a2a;
--bg_2: #2c2943;
--bg_3: #3f4148;
--highlight_1: #ee9015;
--highlight_2: #edd29e;
--text_1: #FFFFFF;
color: var(--text_1);
background: var(--bg_1);
margin: 0px;
position: relative;
min-height: 100vh;
padding-bottom: 4em;
padding-bottom: 4rem;
}
:link {
color: cyan;
color: var(--highlight_1);
font-style: italic;
text-decoration: none;
transition: color 0.2s;
}
a:visited {
color: cyan;
color: var(--highlight_1);
}
a:hover {
color: lightblue;
color: var(--highlight_2);
}
#main_header {
overflow: hidden;
position: relative;
padding-bottom: 0.7em;
padding-bottom: 0.7rem;
}
#main_banner_img {
position: absolute;
@ -51,9 +61,9 @@ a:hover {
#main_banner_img_link {
position: absolute;
right: 2vw;
bottom: 0.5em;
bottom: 0.5rem;
font-size: 0.8em;
font-size: 0.8rem;
}
#nav_bar {
@ -62,63 +72,124 @@ a:hover {
justify-content: center;
list-style-type: none;
margin-top: 1em;
margin-top: 1rem;
padding: 0px;
}
#nav_bar li {
padding: 0em 0.3em 0em 0.3em;
padding: 0rem 0.3rem 0rem 0.3rem;
}
#big_title {
text-align: center;
font-size: 2.5em;
margin-bottom: 0.2em;
font-size: 2.5rem;
margin-bottom: 0.2rem;
}
#main_header h2 {
text-align: center;
font-size: 2em;
margin-bottom: 0.2em;
font-size: 2rem;
margin-bottom: 0.2rem;
}
#title_separator {
height: 1.5px;
background-color: #ddd;
opacity: 0.5;
margin-left: 2em;
margin-right: 2em;
margin-left: 2rem;
margin-right: 2rem;
}
#main_content_wrapper {
padding: 3vmin 1em 1em 1em;
--content-width: min(100vw, calc(20rem + 40vw));
--content-total-margin: calc(calc(100vw - var(--content-width)) / 2);
--content-padding: max(0px, min(1rem, var(--content-total-margin)));
--content-margin: max(0px, calc(var(--content-total-margin) - 1rem));
padding: 0rem var(--content-padding) 1rem var(--content-padding);
width: auto;
margin-left: max(0.75em, min(max(20vmin, 50vw - 30rem), 50vw - 25rem));
margin-right: max(0.75em, min(max(20vmin, 50vw - 30rem), 50vw - 25rem));
margin-left: var(--content-margin);
margin-right: var(--content-margin);
margin-top: 0px;
min-height: 100%;
background: #3e355479;
background: var(--bg_2);
}
#post_file_bar {
position: sticky;
top: 0px;
background: var(--bg_2);
}
#post_file_titles {
display: flex;
flex-direction: row;
justify-content: left;
list-style-type: none;
padding: 0px;
}
#post_file_titles * {
padding: 0.5rem;
font-style: bold;
font-size: 1.3rem;
background: var(--highlight_1);
}
#post_file_path {
width: 100%;
font-style: italic;
padding-left: 0.5rem;
background: var(--highlight_1);
display: flex;
flex-direction: row;
list-style-type: none;
}
#post_file_path a {
color: var(--text_1);
padding-right: 0.2rem;
}
#main_content_wrapper article {
background: #3e3554;
color: #c6c3c3;
border-radius: 0.3em;
background: var(--bg_3);
border-radius: 0rem 0rem 0.8rem 0.8rem;
box-shadow: 3px 7px 7px 0px #00000040;
padding: 0.75em;
padding: 0.75rem;
}
#main_content_wrapper article h1 {
text-align: left;
padding-left: 3vmin;
margin-bottom: 0.2em;
margin-bottom: 0.2rem;
border-bottom: solid 1px darkgrey;
}
#main_content_wrapper article img {
display: block;
max-width: 100%;
max-height: 70vh;
margin: 1vmin;
margin-right: auto;
margin-left: auto;
}
#main_footer {
display: flex;
height: 2.5em;
height: 2.5rem;
text-align: center;
background-color: #3a3a3a;
margin: 0px;

View file

@ -0,0 +1,43 @@
table.directory {
width: 100%;
}
table.directory caption {
text-align: left;
font-size: 1.5rem;
padding-left: 3vmin;
}
table.directory td {
padding: 0.2rem;
text-align: left;
}
table.directory th {
padding: 0.2rem;
text-align: left;
padding-bottom: 0.05rem;
}
table.directory tr.entry:hover {
background: rgba(255, 255, 255, 0.1);
}
table.directory tr.entry .entry_title {
width: 100%;
}
table.directory .entry_update_time {
display: block;
width: 12rem;
}
@media only screen and (max-width: 600px) {
table.directory .entry_update_time {
visibility: hidden;
display: none;
}
}

View file

@ -1,18 +1,12 @@
article {
margin-top: 0.8em;
margin-left: 10%;
margin-right: 10%;
}
figcaption {
#main_content_wrapper figcaption h1 {
text-align: center;
border-bottom: solid 3px darkgrey;
font-size: 2em;
font-size: 1.8rem;
margin-bottom: 0.3em;
margin-bottom: 0.3rem;
}
#gallery_image {

View file

@ -1,13 +1,13 @@
#rrr_header {
font-size: 2em;
font-size: 2rem;
border-bottom: 1px solid grey;
padding-bottom: 0.2em;
margin-bottom: 0.3em;
padding-bottom: 0.2rem;
margin-bottom: 0.3rem;
}
#rrr_code {
font-size: 1.5em;
font-size: 1.5rem;
}

View file

@ -1,25 +0,0 @@
{% extends "root.html" %}
{% block second_title %}
<h2> {{ post.post_metadata.title }} </h2>
{% endblock %}
{%block main_content%}
<article>
{{ post['post_content']|markdown_to_html }}
</article>
{% if subposts|length > 0 %}
<article>
<h3>Related:</h3>
<ul>
{% for subpost in subposts %}
<li><a href={{subpost.post_path}}>{{ subpost.post_metadata.title }}</a></li>
{% endfor %}
</ul>
</article>
{%endif%}
{%endblock%}

View file

@ -0,0 +1,30 @@
<div id="post_file_bar">
<menu id="post_file_titles">
<li>
{{ post.post_metadata.title }}
</li>
</menu>
<menu id="post_file_path">
{% set split_post = post.post_path |split('/') %}
{% for i in range(0, split_post|length - 1) %}
<li>
{% if i != 0 %}
>
{% endif %}
{% if i != 0 %}
<a href="{{split_post|slice(0,i+1)|join('/')}}">
{{ split_post[i] }}
</a>
{% else %}
<a href="/">root</a>
{% endif %}
</li>
{% endfor %}
<li style="margin-left: auto;">
<a href="/raw{{post.post_path}}">raw</a>
<a href="/api/posts{{post.post_path}}">api</a>
</li>
</menu>
</div>

View file

@ -1,19 +0,0 @@
{% extends "root.html" %}
{% block second_title %}
<h2> Abouts </h2>
{% endblock %}
{%block main_content%}
<article>
{{ include('about.md')|markdown_to_html }}
</article>
<ul>
{% for subpost in subposts %}
<li> {{ subpost.title }} </li>
{% endfor %}
</ul>
{%endblock%}

View file

@ -1,31 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Lucidragons' Fire</title>
<link rel="stylesheet" href="/dergstyle.css">
</head>
<body>
<h1 id="big_title">The dergsite</h1>
<div id="title_separator"></div>
<ul>
<li><a href="/about"> About </a></li>
<li><a href="/blog"> Blog </a></li>
<li><a href="/projects"> Projects </a></li>
<li><a href="/artwork"> Artworks </a></li>
</ul>
<div id="main_content_wrapper">
{% block content %}<h3>Soon there shall be content!</h3>{% endblock %}
</div>
<div id="sidebar-wrapper">
{%block sidebar %}
<ul>
<li> Test 1 </li>
</ul>
{% endblock %}
</div>
</body>
</html>

View file

@ -0,0 +1,18 @@
{% extends "root.html" %}
{% block second_title %}
<h2> {{ post.post_metadata.title }} </h2>
{% endblock %}
{%block main_content%}
{{ include('fragments/filepath_bar.html') }}
<article>
{%block content_article %}
{%endblock%}
</article>
{%endblock%}

View file

@ -0,0 +1,43 @@
{% extends "pathed_content.html" %}
{% block extra_head %}
<link rel="stylesheet" href="/static/directorystyle.css">
{%endblock%}
{%block content_article%}
{% if subposts|length > 0 %}
<table class="directory">
<caption>Directory contents:</caption>
<tr>
<th></th>
<th>Name</th>
<th>Title</th>
<th class="entry_update_time">Modified</th>
</tr>
{% for subpost in subposts %}
<tr class="entry">
<td>
ICN
</td>
<td>
<a href={{subpost.post_path}}>{{subpost.post_basename}}</a>
</td>
<td class="entry_title">
{{ subpost.post_metadata.title }}
</td>
<td class="entry_update_time">
{{ subpost.post_update_time }}
</td>
</tr>
{% endfor %}
</table>
{%else%}
<h4>This directory appears to be empty...</h4>
<span>This shouldn't happen, sorry!</span>
{% endif %}
{{ post.post_content|markdown_to_html }}
{%endblock%}

View file

@ -0,0 +1,19 @@
{% extends "pathed_content.html" %}
{% block extra_head %}
<link rel="stylesheet" href="/static/imagestyle.css">
{%endblock%}
{%block content_article%}
<figure>
<a target="_blank" href="{{post['post_file_dir']}}">
<img id="gallery_image" src="{{post['post_file_dir']}}"></img>
</a>
<figcaption>
{{ post.post_content|markdown_to_html }}
</figcaption>
</figure>
{%endblock%}

View file

@ -0,0 +1,7 @@
{% extends "pathed_content.html" %}
{%block content_article%}
{{ post['post_content']|markdown_to_html }}
{% endblock %}

View file

@ -8,8 +8,9 @@
{%block main_content%}
<article>
<form method="post" enctype="multipart/form-data">
<form method="post" enctype="multipart/form-data" action="/api/admin/upload">
<input type="text" id="post_path" name="post_path"/>
<input type="password" id="api_key" name="api_key"/>
<input type="file" id="post_data" name="post_data"/>
<button>Submit</button>