implemented preview of article markdown via AJAX

This commit is contained in:
2025-04-12 11:00:44 -06:00
parent 4f0262aa89
commit fb35e93226
8 changed files with 161 additions and 84 deletions
+13 -11
View File
@@ -2,8 +2,8 @@
<footer> <footer>
<?php <?php
function get_args_from_url() function get_args_from_url()
{ {
$args = []; $args = [];
$arr = explode('&', $_SERVER['QUERY_STRING']); $arr = explode('&', $_SERVER['QUERY_STRING']);
@@ -16,9 +16,9 @@
} }
return $args; return $args;
} }
if ($_SERVER['SCRIPT_NAME'] == '/user.php') { if ($_SERVER['SCRIPT_NAME'] == '/user.php') {
$args = get_args_from_url(); $args = get_args_from_url();
if (isset($args['action'])) { if (isset($args['action'])) {
@@ -26,18 +26,16 @@
echo ' echo '
<script src="js/profile_picture_cropper_modal.js"></script> <script src="js/profile_picture_cropper_modal.js"></script>
<script src="js/upload.js"></script> <script src="js/upload.js"></script>
'; ';
} else if ($args['action'] == 'view') { } else if ($args['action'] == 'view') {
echo ' echo '
<script src="js/user_actions_modal.js"></script> <script src="js/user_actions_modal.js"></script>
<script src="js/profile_picture_cropper_modal.js"></script> <script src="js/profile_picture_cropper_modal.js"></script>
<script src="js/upload.js"></script> <script src="js/upload.js"></script>
'; ';
} }
} }
} } else if ($_SERVER['SCRIPT_NAME'] == '/admin.php') {
if ($_SERVER['SCRIPT_NAME'] == '/admin.php') {
echo ' echo '
<script src="js/clickable_rows.js"></script> <script src="js/clickable_rows.js"></script>
'; ';
@@ -50,8 +48,12 @@
'; ';
} }
} }
} } else if ($_SERVER['SCRIPT_NAME'] == '/compose.php') {
?> echo '
<script src="js/md_preview.js"></script>
';
}
?>
</footer> </footer>
</html> </html>
+24 -2
View File
@@ -44,12 +44,21 @@ if (isset($_GET['article_id'])) {
$existing_markdown = read_file_one_string($_ENV['ARTICLES_FQ_PATH'] . $article_id . '/article.md'); $existing_markdown = read_file_one_string($_ENV['ARTICLES_FQ_PATH'] . $article_id . '/article.md');
} }
echo '
<div class="grid-2x1">
';
if (!empty($existing_markdown)) { if (!empty($existing_markdown)) {
echo form($article_id, $title, $excerpt, $existing_markdown, $tags); echo form($article_id, $title, $excerpt, $existing_markdown, $tags);
} else { } else {
echo form(); echo form();
} }
echo preview();
echo '
</div>
';
include_once 'components/foot.php'; include_once 'components/foot.php';
function form($article_id = null, $title = null, $excerpt = null, $existing_markdown = null, $tags = null) function form($article_id = null, $title = null, $excerpt = null, $existing_markdown = null, $tags = null)
@@ -74,7 +83,8 @@ function form($article_id = null, $title = null, $excerpt = null, $existing_mark
'; ';
$form = ' $form = '
<div class="form_card"> <div class="full-height">
<div class="form_card" id="composer">
<form method="post"> <form method="post">
' . (isset($article_id) ? '<input type="hidden" name="article_id" value="' . $article_id . '">' : '') . ' ' . (isset($article_id) ? '<input type="hidden" name="article_id" value="' . $article_id . '">' : '') . '
@@ -90,8 +100,20 @@ function form($article_id = null, $title = null, $excerpt = null, $existing_mark
<input class="button" type="submit" value="' . (isset($article_id) ? 'Update Article' : 'Create Article') . '"> <input class="button" type="submit" value="' . (isset($article_id) ? 'Update Article' : 'Create Article') . '">
</form> </form>
</div> </div>
</div>
'; ';
return $form; return $form;
} }
function preview()
{
$preview = '
<div class="full-height">
<div class="form_card" id="md_preview">
</div>
</div>
';
return $preview;
}
+58 -2
View File
@@ -168,6 +168,7 @@ code {
.view_card { .view_card {
margin: 0 auto; margin: 0 auto;
margin-top: 50px; margin-top: 50px;
margin-bottom: 50px;
width: 70%; width: 70%;
padding: 18px; padding: 18px;
height: max-content; height: max-content;
@@ -335,6 +336,7 @@ textarea {
margin: 15px 15px 15px 0px; margin: 15px 15px 15px 0px;
box-sizing: border-box; box-sizing: border-box;
transition-duration: 500ms; transition-duration: 500ms;
resize: none;
} }
input:focus, input:focus,
@@ -348,10 +350,12 @@ textarea:hover {
textarea { textarea {
border-radius: 18px; border-radius: 18px;
height: 500px; height: 70%;
} }
.checkboxes {} .checkboxes {
height: max-content;
}
input[type="radio"] { input[type="radio"] {
display: none; display: none;
@@ -639,6 +643,58 @@ input[type="file"] {
display: none; display: none;
} }
::selection {
color: black;
background: orange;
}
.grid-2x1 {
margin: 0 auto;
width: 90%;
display: grid;
grid-template-columns: 50% 50%;
}
.grid-2x1 .form_card,
.grid-2x1 #md_preview {
width: 80%;
height: 90%;
overflow-y: scroll;
box-sizing: border-box;
}
.grid-2x1 #composer {
padding-top: 150px;
}
#md_preview {
border: none;
display: block;
}
.full-height {
height: 700px;
}
::-webkit-scrollbar {
background-color: black;
border-radius: 18px;
}
::-webkit-scrollbar-button {
display: none;
}
::-webkit-scrollbar-track {
display: none;
}
::-webkit-scrollbar-thumb {
background-color: orange;
border-radius: 9px;
}
@media screen and (max-width: 992px) { @media screen and (max-width: 992px) {
h1 { h1 {
font-size: 10vw; font-size: 10vw;
-11
View File
@@ -92,12 +92,6 @@ function article_page_from_markdown($article_id)
$parsedown = new Parsedown(); $parsedown = new Parsedown();
$parsedown->setSafeMode(true); $parsedown->setSafeMode(true);
$article_content = $parsedown->text($markdown); $article_content = $parsedown->text($markdown);
$article_toc = '';
$lines = preg_split("/\r\n|\n|\r/", $article_content);
foreach ($lines as $line)
if (str_contains($line, '<h4>'))
$article_toc .= '<p>' . extract_content_from_tag($line, '<h4>', '</h4>') . '</p><br>';
$html = ' $html = '
<div class="article"> <div class="article">
@@ -116,15 +110,10 @@ function article_page_from_markdown($article_id)
</div> </div>
</div> </div>
<div class="line" style="margin-bottom: 15px;"></div> <div class="line" style="margin-bottom: 15px;"></div>
<div class="article_grid">
<div class="article_toc">
' . $article_toc . '
</div>
<div class="article_content"> <div class="article_content">
' . $article_content . ' ' . $article_content . '
</div> </div>
</div> </div>
</div>
'; ';
return $html; return $html;
+1 -1
View File
@@ -1,7 +1,7 @@
<?php <?php
require_once 'vendor/autoload.php'; require_once 'vendor/autoload.php';
$dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/../'); $dotenv = Dotenv\Dotenv::createImmutable(__DIR__ . '/..');
$dotenv->safeLoad(); $dotenv->safeLoad();
// Use environment variables for the database password and IP address. // Use environment variables for the database password and IP address.
+12
View File
@@ -0,0 +1,12 @@
<?php
session_start();
header("Content-Security-Policy: default-src 'self'; font-src 'self' https://www.nerdfonts.com/assets/fonts/Symbols-2048-em%20Nerd%20Font%20Complete.woff2; style-src 'self' 'unsafe-inline' https://nerdfonts.com/assets/css/webfont.css https://www.nerdfonts.com/assets/css/webfont.css; script-src 'self'; img-src 'self';");
require_once '../vendor/autoload.php';
$markdown = urldecode($_POST['markdown']);
$parsedown = new Parsedown();
$parsedown->setSafeMode(true);
$article_content = $parsedown->text($markdown);
echo $article_content;
-3
View File
@@ -1,11 +1,8 @@
<?php <?php
// Initializes environment variables and other stuff.
// if (!isset($_SESSION['initialized']))
require_once 'functions/init.php'; require_once 'functions/init.php';
require_once 'functions/functions.php'; require_once 'functions/functions.php';
include_once 'components/head.php'; include_once 'components/head.php';
echo home_content(); echo home_content();
include_once 'components/foot.php'; include_once 'components/foot.php';
+3 -4
View File
@@ -1,9 +1,8 @@
// Optional: Real-time preview using JavaScript
const textarea = document.querySelector('textarea'); const textarea = document.querySelector('textarea');
const preview = document.getElementById('preview'); const preview = document.getElementById('md_preview');
textarea.addEventListener('input', function() { textarea.addEventListener('input', function() {
fetch('preview.php', { // Create a separate preview.php file for real-time updates fetch('functions/preview.php', { // Create a separate preview.php file for real-time updates
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/x-www-form-urlencoded', 'Content-Type': 'application/x-www-form-urlencoded',
@@ -12,6 +11,6 @@ textarea.addEventListener('input', function() {
}) })
.then(response => response.text()) .then(response => response.text())
.then(data => { .then(data => {
preview.innerHTML = data; preview.innerHTML = decodeURIComponent(data);
}); });
}); });