From fb35e9322647878386bcc3be572cd404b38fd91b Mon Sep 17 00:00:00 2001 From: Josh Ashton Date: Sat, 12 Apr 2025 11:00:44 -0600 Subject: [PATCH] implemented preview of article markdown via AJAX --- components/foot.php | 48 ++++++++-------- compose.php | 98 ++++++++++++++++++++------------- css/base.css | 60 +++++++++++++++++++- functions/article_functions.php | 11 ---- functions/db_functions.php | 2 +- functions/preview.php | 12 ++++ index.php | 7 +-- js/md_preview.js | 7 +-- 8 files changed, 161 insertions(+), 84 deletions(-) create mode 100644 functions/preview.php diff --git a/components/foot.php b/components/foot.php index 76bbaa1..c7dc6ca 100644 --- a/components/foot.php +++ b/components/foot.php @@ -2,56 +2,58 @@ diff --git a/compose.php b/compose.php index 2c5a370..780bf0b 100644 --- a/compose.php +++ b/compose.php @@ -4,77 +4,87 @@ require_once 'functions/functions.php'; include_once 'functions/article_functions.php'; if (!empty($_POST)) { - if (isset($_POST['article_id'])) { - $tags = []; - for ($i = 0; $i < count($_POST['tags']); $i++) - $tags[] = $_POST['tags'][$i]; + if (isset($_POST['article_id'])) { + $tags = []; + for ($i = 0; $i < count($_POST['tags']); $i++) + $tags[] = $_POST['tags'][$i]; - update_article($_POST['article_id'], $_POST['title'], $_POST['excerpt'], $tags, $_POST['markdown']); - header('Location: articles.php?article_id=' . $_POST['article_id']); - } else { - $id = create_article($_COOKIE['user_id'], $_POST['title'], $_POST['excerpt'], (isset($_POST['tags']) ? $_POST['tags'] : []), $_POST['markdown']); - header('Location: articles.php?article_id=' . $id); - } + update_article($_POST['article_id'], $_POST['title'], $_POST['excerpt'], $tags, $_POST['markdown']); + header('Location: articles.php?article_id=' . $_POST['article_id']); + } else { + $id = create_article($_COOKIE['user_id'], $_POST['title'], $_POST['excerpt'], (isset($_POST['tags']) ? $_POST['tags'] : []), $_POST['markdown']); + header('Location: articles.php?article_id=' . $id); + } } if (!isset($_COOKIE['role_id']) || $_COOKIE['role_id'] == 4) - header('Location: articles.php'); + header('Location: articles.php'); include_once 'components/head.php'; if (isset($_GET['article_id'])) { - $article_id = $_GET['article_id']; + $article_id = $_GET['article_id']; - $conn = get_connection(); - $stmt = $conn->prepare('SELECT * FROM article WHERE article_id = ?'); - $stmt->bind_param('i', $article_id); - $stmt->execute(); - $article = $stmt->get_result()->fetch_assoc(); + $conn = get_connection(); + $stmt = $conn->prepare('SELECT * FROM article WHERE article_id = ?'); + $stmt->bind_param('i', $article_id); + $stmt->execute(); + $article = $stmt->get_result()->fetch_assoc(); - $stmt = $conn->prepare('SELECT tag_id FROM article_tags WHERE article_id = ?'); - $stmt->bind_param('i', $article_id); - $stmt->execute(); - $result = $stmt->get_result(); - $tags = []; - while ($row = $result->fetch_assoc()) - $tags[] = $row['tag_id']; + $stmt = $conn->prepare('SELECT tag_id FROM article_tags WHERE article_id = ?'); + $stmt->bind_param('i', $article_id); + $stmt->execute(); + $result = $stmt->get_result(); + $tags = []; + while ($row = $result->fetch_assoc()) + $tags[] = $row['tag_id']; - $title = $article['title']; - $excerpt = $article['excerpt']; - $existing_markdown = read_file_one_string($_ENV['ARTICLES_FQ_PATH'] . $article_id . '/article.md'); + $title = $article['title']; + $excerpt = $article['excerpt']; + $existing_markdown = read_file_one_string($_ENV['ARTICLES_FQ_PATH'] . $article_id . '/article.md'); } +echo ' +
+'; if (!empty($existing_markdown)) { - echo form($article_id, $title, $excerpt, $existing_markdown, $tags); + echo form($article_id, $title, $excerpt, $existing_markdown, $tags); } else { - echo form(); + echo form(); } +echo preview(); + +echo ' +
+'; + include_once 'components/foot.php'; function form($article_id = null, $title = null, $excerpt = null, $existing_markdown = null, $tags = null) { - $raw_tags = article_tags(); - $tags_boxes = ' + $raw_tags = article_tags(); + $tags_boxes = '
'; - foreach ($raw_tags as $row) { - $tags_boxes .= ' + foreach ($raw_tags as $row) { + $tags_boxes .= ' '; - } + } - $tags_boxes .= ' + $tags_boxes .= '
'; - $form = ' -
+ $form = ' +
+
' . (isset($article_id) ? '' : '') . ' @@ -90,8 +100,20 @@ function form($article_id = null, $title = null, $excerpt = null, $existing_mark
+
'; + return $form; +} - return $form; +function preview() +{ + $preview = ' +
+
+
+
+ '; + + return $preview; } diff --git a/css/base.css b/css/base.css index 467b5f6..c7d9e01 100644 --- a/css/base.css +++ b/css/base.css @@ -168,6 +168,7 @@ code { .view_card { margin: 0 auto; margin-top: 50px; + margin-bottom: 50px; width: 70%; padding: 18px; height: max-content; @@ -335,6 +336,7 @@ textarea { margin: 15px 15px 15px 0px; box-sizing: border-box; transition-duration: 500ms; + resize: none; } input:focus, @@ -348,10 +350,12 @@ textarea:hover { textarea { border-radius: 18px; - height: 500px; + height: 70%; } -.checkboxes {} +.checkboxes { + height: max-content; +} input[type="radio"] { display: none; @@ -639,6 +643,58 @@ input[type="file"] { 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) { h1 { font-size: 10vw; diff --git a/functions/article_functions.php b/functions/article_functions.php index 5226230..b102c09 100644 --- a/functions/article_functions.php +++ b/functions/article_functions.php @@ -92,12 +92,6 @@ function article_page_from_markdown($article_id) $parsedown = new Parsedown(); $parsedown->setSafeMode(true); $article_content = $parsedown->text($markdown); - $article_toc = ''; - - $lines = preg_split("/\r\n|\n|\r/", $article_content); - foreach ($lines as $line) - if (str_contains($line, '

')) - $article_toc .= '

' . extract_content_from_tag($line, '

', '

') . '


'; $html = '
@@ -116,14 +110,9 @@ function article_page_from_markdown($article_id)
-
-
- ' . $article_toc . ' -
' . $article_content . '
-
'; diff --git a/functions/db_functions.php b/functions/db_functions.php index 68f53b5..c9ecbed 100644 --- a/functions/db_functions.php +++ b/functions/db_functions.php @@ -1,7 +1,7 @@ safeLoad(); // Use environment variables for the database password and IP address. diff --git a/functions/preview.php b/functions/preview.php new file mode 100644 index 0000000..232b825 --- /dev/null +++ b/functions/preview.php @@ -0,0 +1,12 @@ +setSafeMode(true); +$article_content = $parsedown->text($markdown); + +echo $article_content; diff --git a/index.php b/index.php index 26d7848..9464d88 100644 --- a/index.php +++ b/index.php @@ -1,18 +1,15 @@

Vintage Coding

Intentional Craftsmanship Over Ephemeral Trends

@@ -34,5 +31,5 @@ function home_content() '; - return $content; + return $content; } diff --git a/js/md_preview.js b/js/md_preview.js index 233fce5..15579c9 100644 --- a/js/md_preview.js +++ b/js/md_preview.js @@ -1,9 +1,8 @@ -// Optional: Real-time preview using JavaScript const textarea = document.querySelector('textarea'); -const preview = document.getElementById('preview'); +const preview = document.getElementById('md_preview'); 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', headers: { 'Content-Type': 'application/x-www-form-urlencoded', @@ -12,6 +11,6 @@ textarea.addEventListener('input', function() { }) .then(response => response.text()) .then(data => { - preview.innerHTML = data; + preview.innerHTML = decodeURIComponent(data); }); });