Pre-render website read pages

This commit is contained in:
juvdiaz 2026-06-04 10:42:21 -06:00
parent a47671e2af
commit 307094794f
6 changed files with 149 additions and 31 deletions

View File

@ -62,6 +62,7 @@ RUN set -eu; \
COPY httpd-php-fpm.conf /etc/apache2/conf.d/php-fpm.conf
COPY opcache.ini /usr/local/etc/php/conf.d/zz-opcache.ini
COPY php-fpm-runtime.conf /usr/local/etc/php-fpm.d/zz-runtime.conf
COPY render-static-pages.sh /usr/local/bin/render-static-pages
COPY start-website.sh /usr/local/bin/start-website
COPY . /var/www/localhost/htdocs/
@ -74,10 +75,13 @@ RUN rm -f /var/www/localhost/htdocs/index.html && \
/var/log/apache2 \
/var/www/localhost/htdocs/db \
/tmp/website-lang && \
chmod 0755 /usr/local/bin/render-static-pages && \
/usr/local/bin/render-static-pages /var/www/localhost/htdocs && \
chown -R apache:apache \
/run/apache2 \
/var/log/apache2 \
/var/www/localhost/htdocs/db \
/var/www/localhost/htdocs/static-pages \
/tmp/website-lang && \
chmod 0755 /usr/local/bin/start-website

View File

@ -1,6 +1,5 @@
<?php
require_once __DIR__ . '/lang_helper.php';
require_once __DIR__ . '/ideas_helper.php';
$activityKeys = [
'blog_activity_1',
@ -80,8 +79,6 @@ $caseStudyCards = [
];
$treeHref = 'homelab-tree.php?lang=' . urlencode($lang);
$ideaStatus = visitor_idea_clean((string) ($_GET['idea'] ?? ''), 20);
$visitorIdeas = visitor_ideas_read();
$giteaSourceBase = 'https://lab2025.duckdns.org/git/jv/my-homelab-configs/src/branch/main/';
$stackSourceLinks = [
'blog_stack_1' => [
@ -814,7 +811,12 @@ function renderStackSourceLinks(string $stackKey, array $sourceLinks, string $so
<?php endforeach; ?>
</ul>
<div class="visitor-ideas" id="visitor-ideas">
<div class="visitor-ideas" id="visitor-ideas"
data-recent-title="<?php echo htmlspecialchars($text['blog_ideas_recent_title']); ?>"
data-status-thanks="<?php echo htmlspecialchars($text['blog_idea_status_thanks']); ?>"
data-status-invalid="<?php echo htmlspecialchars($text['blog_idea_status_invalid']); ?>"
data-status-slow="<?php echo htmlspecialchars($text['blog_idea_status_slow']); ?>"
data-status-error="<?php echo htmlspecialchars($text['blog_idea_status_error']); ?>">
<div class="section-heading">
<p class="section-kicker"
data-translate data-key="blog_ideas_kicker"
@ -831,14 +833,6 @@ function renderStackSourceLinks(string $stackKey, array $sourceLinks, string $so
</p>
</div>
<?php if (in_array($ideaStatus, ['thanks', 'invalid', 'slow', 'error'], true)): ?>
<p class="idea-status idea-status-<?php echo htmlspecialchars($ideaStatus); ?>"
data-translate data-key="blog_idea_status_<?php echo htmlspecialchars($ideaStatus); ?>"
data-en="<?php echo htmlspecialchars($en['blog_idea_status_' . $ideaStatus]); ?>">
<?php echo $text['blog_idea_status_' . $ideaStatus]; ?>
</p>
<?php endif; ?>
<form class="idea-form" action="save_idea.php" method="post">
<input type="hidden" name="lang" value="<?php echo htmlspecialchars($lang); ?>">
<label>
@ -866,25 +860,6 @@ function renderStackSourceLinks(string $stackKey, array $sourceLinks, string $so
</button>
</form>
<?php if ($visitorIdeas): ?>
<div class="visitor-idea-list">
<h4 data-translate data-key="blog_ideas_recent_title"
data-en="<?php echo htmlspecialchars($en['blog_ideas_recent_title']); ?>">
<?php echo $text['blog_ideas_recent_title']; ?>
</h4>
<?php foreach ($visitorIdeas as $visitorIdea): ?>
<article class="visitor-idea-card">
<p><?php echo nl2br(htmlspecialchars($visitorIdea['idea'])); ?></p>
<footer>
<span><?php echo htmlspecialchars($visitorIdea['name']); ?></span>
<time datetime="<?php echo htmlspecialchars($visitorIdea['created_at']); ?>">
<?php echo htmlspecialchars(substr($visitorIdea['created_at'], 0, 10)); ?>
</time>
</footer>
</article>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</section>
</main>
@ -893,6 +868,7 @@ function renderStackSourceLinks(string $stackKey, array $sourceLinks, string $so
window.OTHER_PAGES = ['/index.php', '/cv.php', '/homelab-tree.php'];
</script>
<script src="cv-theme.js"></script>
<script src="visitor-ideas.js"></script>
<?php require_once __DIR__ . '/partials/translation_ui.php'; ?>
</body>

View File

@ -1,3 +1,27 @@
RewriteEngine On
RewriteCond %{QUERY_STRING} (^|&)lang=en(&|$)
RewriteRule ^/?(?:index\.php)?$ /static-pages/en/index.html [END]
RewriteCond %{QUERY_STRING} (^|&)lang=en(&|$)
RewriteRule ^/?(cv|blog|demos|homelab-tree)\.php$ /static-pages/en/$1.html [END]
RewriteCond %{QUERY_STRING} (^|&)lang=nah(&|$)
RewriteRule ^/?(?:index\.php)?$ /static-pages/nah/index.html [END]
RewriteCond %{QUERY_STRING} (^|&)lang=nah(&|$)
RewriteRule ^/?(cv|blog|demos|homelab-tree)\.php$ /static-pages/nah/$1.html [END]
RewriteCond %{QUERY_STRING} !(^|&)lang= [NC]
RewriteCond %{HTTP:Accept-Language} ^en [NC]
RewriteRule ^/?(?:index\.php)?$ /static-pages/en/index.html [END]
RewriteCond %{QUERY_STRING} !(^|&)lang= [NC]
RewriteCond %{HTTP:Accept-Language} ^en [NC]
RewriteRule ^/?(cv|blog|demos|homelab-tree)\.php$ /static-pages/en/$1.html [END]
RewriteCond %{QUERY_STRING} !(^|&)lang= [NC]
RewriteRule ^/?(?:index\.php)?$ /static-pages/nah/index.html [END]
RewriteCond %{QUERY_STRING} !(^|&)lang= [NC]
RewriteRule ^/?(cv|blog|demos|homelab-tree)\.php$ /static-pages/nah/$1.html [END]
<FilesMatch "\.php$">
SetHandler "proxy:fcgi://127.0.0.1:9000"
</FilesMatch>

View File

@ -0,0 +1,32 @@
#!/bin/sh
set -eu
root="${1:-/var/www/localhost/htdocs}"
render_page() {
lang="$1"
source="$2"
output="$3"
request_uri="$4"
mkdir -p "$(dirname "$output")"
# shellcheck disable=SC2016
php -r '
parse_str($argv[1], $_GET);
$_SERVER["HTTP_ACCEPT_LANGUAGE"] = $argv[2];
$_SERVER["REQUEST_METHOD"] = "GET";
$_SERVER["REQUEST_URI"] = $argv[3];
$_SERVER["PHP_SELF"] = "/" . $argv[4];
chdir($argv[5]);
include $argv[5] . "/" . $argv[4];
' "lang=$lang" "$lang" "$request_uri" "$source" "$root" > "$output"
}
for lang in en nah; do
static_dir="$root/static-pages/$lang"
render_page "$lang" index.php "$static_dir/index.html" "/?lang=$lang"
render_page "$lang" cv.php "$static_dir/cv.html" "/cv.php?lang=$lang"
render_page "$lang" blog.php "$static_dir/blog.html" "/blog.php?lang=$lang"
render_page "$lang" demos.php "$static_dir/demos.html" "/demos.php?lang=$lang"
render_page "$lang" homelab-tree.php "$static_dir/homelab-tree.html" "/homelab-tree.php?lang=$lang"
done

View File

@ -0,0 +1,68 @@
(function () {
const root = document.getElementById('visitor-ideas');
if (!root) return;
const messages = {
thanks: root.dataset.statusThanks,
invalid: root.dataset.statusInvalid,
slow: root.dataset.statusSlow,
error: root.dataset.statusError,
};
const status = new URLSearchParams(window.location.search).get('idea');
if (status && messages[status]) {
const statusEl = document.createElement('p');
statusEl.className = `idea-status idea-status-${status}`;
statusEl.textContent = messages[status];
const form = root.querySelector('.idea-form');
root.insertBefore(statusEl, form || root.firstChild);
}
function addIdeaText(parent, text) {
String(text || '').split('\n').forEach((line, index) => {
if (index > 0) parent.appendChild(document.createElement('br'));
parent.appendChild(document.createTextNode(line));
});
}
function renderIdeas(ideas) {
const existing = root.querySelector('.visitor-idea-list');
if (existing) existing.remove();
if (!Array.isArray(ideas) || ideas.length === 0) return;
const list = document.createElement('div');
list.className = 'visitor-idea-list';
const heading = document.createElement('h4');
heading.textContent = root.dataset.recentTitle || 'Recent visitor ideas';
list.appendChild(heading);
ideas.forEach((idea) => {
const article = document.createElement('article');
article.className = 'visitor-idea-card';
const body = document.createElement('p');
addIdeaText(body, idea.idea);
article.appendChild(body);
const footer = document.createElement('footer');
const name = document.createElement('span');
name.textContent = idea.name || 'Anonymous visitor';
const time = document.createElement('time');
time.dateTime = idea.created_at || '';
time.textContent = String(idea.created_at || '').slice(0, 10);
footer.appendChild(name);
footer.appendChild(time);
article.appendChild(footer);
list.appendChild(article);
});
root.appendChild(list);
}
fetch('/visitor_ideas.php', { headers: { Accept: 'application/json' } })
.then((response) => (response.ok ? response.json() : { ideas: [] }))
.then((data) => renderIdeas(data.ideas))
.catch(() => renderIdeas([]));
})();

View File

@ -0,0 +1,14 @@
<?php
require_once __DIR__ . '/ideas_helper.php';
if ($_SERVER['REQUEST_METHOD'] !== 'GET') {
http_response_code(405);
exit;
}
header('Content-Type: application/json; charset=utf-8');
echo json_encode(
['ideas' => visitor_ideas_read()],
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);