Forum integration: Flarum extension, local test stack, embedded comments
- forum/extension: oc:import command (archived comments -> one thread per machine) and embed styling - forum/docker: local Flarum 2 test stack - site: optional params.forum.url adds a Forum menu entry and shows the machine thread in the Comments tab Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YDRjtmAiNpo5mK5N3d7QwZ
This commit is contained in:
@@ -4,3 +4,4 @@
|
||||
.hugo_build.lock
|
||||
__pycache__/
|
||||
node_modules/
|
||||
/forum/import/
|
||||
|
||||
@@ -7,10 +7,10 @@ PAGEFIND ?= npx -y pagefind@1
|
||||
DEPLOY_DIR ?= /run/user/$(shell id -u)/gvfs/smb-share:server=barbel-lescar,share=web/oldcomputers
|
||||
DEPLOY_URL ?= https://barbel.synology.me/oldcomputers/
|
||||
|
||||
.PHONY: content build check serve deploy post
|
||||
.PHONY: content build check serve deploy post forum-up forum-import forum-down
|
||||
|
||||
content: ## regenerate content/ and static/media/ from the extraction repo
|
||||
python3 $(OC)/scripts/05_hugo.py --target $(CURDIR)
|
||||
python3 $(OC)/scripts/05_hugo.py --target $(CURDIR) $(if $(wildcard data/forum.json),--forum)
|
||||
|
||||
build: ## build the site and its search index into $(BUILD)/
|
||||
rm -rf $(BUILD)
|
||||
@@ -32,3 +32,17 @@ deploy: check ## build, check, and copy $(BUILD)/ to DEPLOY_DIR (served at DEPL
|
||||
mkdir -p "$(DEPLOY_DIR)"
|
||||
rsync -r --size-only --info=stats1 $(BUILD)/media/ "$(DEPLOY_DIR)/media/"
|
||||
rsync -rc --delete --exclude=/media/ --info=stats1 $(BUILD)/ "$(DEPLOY_DIR)/"
|
||||
|
||||
# --- local test forum (Flarum in Docker, see forum/README.md) ---
|
||||
FORUM = docker compose -f forum/docker-compose.yml
|
||||
SITE_URL ?= http://localhost:1313
|
||||
|
||||
forum-up: ## start the test forum on http://localhost:8081 (admin / adminadmin)
|
||||
$(FORUM) up -d --build
|
||||
|
||||
forum-import: ## export the archived comments and import them into the test forum
|
||||
python3 $(OC)/scripts/06_forum.py --target $(CURDIR)
|
||||
$(FORUM) exec -T flarum php flarum oc:import /import/machines.json --site-url=$(SITE_URL) --map=/import/forum.json
|
||||
|
||||
forum-down: ## stop the test forum (forum-db volume keeps its data)
|
||||
$(FORUM) down
|
||||
|
||||
@@ -10,6 +10,8 @@ Static rebuild of old-computers.com with [Hugo](https://gohugo.io/) (0.158 or ne
|
||||
| `static/media/` | generated (copied images and documents) |
|
||||
| `data/slugs.json` | generated, keeps URLs stable between runs — do not delete |
|
||||
| `content/post/` | written by hand: news posts, see below |
|
||||
| `data/forum.json` | machine → forum thread map, written by the forum import (absent = no forum) |
|
||||
| `forum/` | forum extension, local test stack, install notes |
|
||||
| `content/_index.md`, `layouts/`, `assets/`, `hugo.toml`, `tools/` | written by hand |
|
||||
| `build/`, `public/` | build output (`make build`, `hugo server`), not versioned |
|
||||
|
||||
@@ -39,6 +41,14 @@ sends to `/search/`, where results can be filtered by section. Content pages are
|
||||
visitor-comments tabs are not. `hugo server` has no index: use `make build` and serve `build/`
|
||||
to try the search locally.
|
||||
|
||||
## Forum and comments
|
||||
|
||||
A [Flarum](https://flarum.org/) forum can run next to the site and serve as its comment system:
|
||||
with `params.forum.url` set in `hugo.toml`, the menu gets a Forum entry and the Comments tab of
|
||||
each machine shows that machine's forum thread (archived comments first, new replies after).
|
||||
With the url empty the site has no forum and shows the archived comments as static text.
|
||||
Everything about the forum is in [`forum/README.md`](forum/README.md).
|
||||
|
||||
## Usage
|
||||
|
||||
make content # regenerate from ../oc (OC=path to use another location)
|
||||
|
||||
@@ -162,3 +162,5 @@ table { border-collapse: collapse; }
|
||||
.pager { display: flex; flex-wrap: wrap; justify-content: center; gap: 6px; margin: 24px 0 0; }
|
||||
.pager a, .pager .current { padding: 4px 10px; border: 1px solid var(--line); border-radius: 4px; text-decoration: none; background: var(--panel); }
|
||||
.pager .current { font-weight: 700; border-color: var(--accent); }
|
||||
|
||||
.forum-thread { display: block; width: 100%; min-height: 400px; border: 0; }
|
||||
|
||||
Vendored
+21
File diff suppressed because one or more lines are too long
@@ -0,0 +1,71 @@
|
||||
# Forum and comments (Flarum)
|
||||
|
||||
The forum is a separate PHP application ([Flarum](https://flarum.org/) 2, PHP 8.3+, MariaDB or
|
||||
MySQL). It is not part of the static build: the site only links to it and shows its threads in a
|
||||
frame.
|
||||
|
||||
| Path | Role |
|
||||
|---|---|
|
||||
| `extension/` | Flarum extension `oc/flarum-museum`: the `oc:import` command and the look of embedded threads |
|
||||
| `docker/`, `docker-compose.yml` | local test forum |
|
||||
| `import/` | not versioned: `machines.json` (export from the extraction repo) and `forum.json` (thread map) |
|
||||
|
||||
## How comments work
|
||||
|
||||
- `../oc/scripts/06_forum.py` writes `import/machines.json`: one entry per machine with its
|
||||
archived comments, oldest first.
|
||||
- `php flarum oc:import` creates one discussion per machine: an opening post linking to the
|
||||
museum page, then one post per archived comment, all by the user `Archive`, with the original
|
||||
author and date at the top of each post and the original date as the post date. Discussions go
|
||||
under three tags (Computers, Consoles, Pongs) that are hidden from "All discussions".
|
||||
- The command records what it imported (table `oc_threads`) and skips it on later runs, so it
|
||||
can be run again when new machines arrive. It writes the map machine → discussion to
|
||||
`forum.json`.
|
||||
- Copied to `../data/forum.json`, that map makes `make content` give every machine a Comments
|
||||
tab pointing at its thread (`forum_thread` in the page front matter); the old comments are
|
||||
then no longer written into the pages.
|
||||
- With `params.forum.url` set, the Comments tab shows `<forum>/embed/<id>` (Flarum's Embed
|
||||
extension) in a frame that follows the height of the thread.
|
||||
|
||||
## Local test
|
||||
|
||||
make forum-up # http://localhost:8081, admin / adminadmin (first start takes a minute)
|
||||
make forum-import # export + import; safe to repeat
|
||||
|
||||
To see it in the site, copy `forum/import/forum.json` to `data/forum.json`, run `make content`,
|
||||
and build with `HUGO_PARAMS_FORUM_URL=http://localhost:8081 hugo server`. Do not commit a
|
||||
`data/forum.json` made from the test forum: its thread numbers are not those of the real one.
|
||||
|
||||
## Server install (outline)
|
||||
|
||||
The forum must live **outside** the folder `make deploy` writes to (that folder is synchronised
|
||||
with deletion). On the test server: `web/oldcomputers-forum/`, next to `web/oldcomputers/`.
|
||||
|
||||
1. PHP 8.3 or newer with curl, dom, fileinfo, gd, json, mbstring, openssl, pdo_mysql, tokenizer,
|
||||
zip; an empty database and a user for it.
|
||||
2. `composer create-project flarum/flarum oldcomputers-forum "^2.0"`, then in that folder
|
||||
`composer require flarum/embed "^2.0"`.
|
||||
3. Web server: requests that are not files go to `public/index.php`, and nothing outside `public/`
|
||||
is served. Flarum ships rules for Apache (`public/.htaccess`) and nginx (`.nginx.conf`); a
|
||||
sub-folder install is described in the Flarum documentation ("Customizing paths").
|
||||
4. Open the forum address and finish the installer (database, administrator account).
|
||||
5. Copy `extension/` to `packages/oc-museum/` in the forum folder, then:
|
||||
|
||||
composer config repositories.oc path "packages/*"
|
||||
composer require "oc/flarum-museum:*@dev"
|
||||
php flarum migrate
|
||||
php flarum extension:enable flarum-tags
|
||||
php flarum extension:enable flarum-embed
|
||||
php flarum extension:enable oc-museum
|
||||
|
||||
6. In the admin panel: e-mail settings (registration confirms addresses by e-mail), and a spam
|
||||
filter extension. Schedule a database dump.
|
||||
7. Import: copy `import/machines.json` to the server and run
|
||||
|
||||
php flarum oc:import machines.json --site-url=https://example.org/oldcomputers --map=forum.json
|
||||
|
||||
then bring `forum.json` back as `data/forum.json`, set `params.forum.url`, `make content`,
|
||||
`make deploy`.
|
||||
|
||||
The forum and the site should share one domain: logging in from the embedded thread relies on
|
||||
the forum's cookie, which browsers restrict across domains.
|
||||
@@ -0,0 +1,24 @@
|
||||
# Local test forum on http://localhost:8081 (admin / adminadmin). Data in named volumes.
|
||||
services:
|
||||
db:
|
||||
image: mariadb:11
|
||||
environment:
|
||||
MARIADB_DATABASE: flarum
|
||||
MARIADB_USER: flarum
|
||||
MARIADB_PASSWORD: flarum
|
||||
MARIADB_RANDOM_ROOT_PASSWORD: "1"
|
||||
volumes:
|
||||
- forum-db:/var/lib/mysql
|
||||
flarum:
|
||||
build: docker
|
||||
depends_on: [db]
|
||||
environment:
|
||||
FORUM_URL: http://localhost:8081
|
||||
ADMIN_PASSWORD: adminadmin
|
||||
ports:
|
||||
- "127.0.0.1:8081:80"
|
||||
volumes:
|
||||
- ./extension:/var/www/flarum/packages/oc-museum
|
||||
- ./import:/import
|
||||
volumes:
|
||||
forum-db:
|
||||
@@ -0,0 +1,19 @@
|
||||
# Local test forum: Flarum 2 on Apache. Not the production install (see forum/README.md).
|
||||
FROM php:8.3-apache
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends git unzip libzip-dev libpng-dev libjpeg-dev libfreetype6-dev \
|
||||
&& docker-php-ext-configure gd --with-jpeg --with-freetype \
|
||||
&& docker-php-ext-install pdo_mysql gd zip \
|
||||
&& a2enmod rewrite && rm -rf /var/lib/apt/lists/*
|
||||
COPY --from=composer:2 /usr/bin/composer /usr/bin/composer
|
||||
ENV COMPOSER_ALLOW_SUPERUSER=1
|
||||
RUN composer create-project flarum/flarum /var/www/flarum "^2.0" --no-interaction --prefer-dist \
|
||||
&& cd /var/www/flarum && mkdir packages \
|
||||
&& composer require --no-interaction flarum/embed "^2.0" \
|
||||
&& composer config repositories.oc '{"type": "path", "url": "packages/*", "options": {"symlink": true}}' \
|
||||
&& chown -R www-data:www-data /var/www/flarum
|
||||
RUN sed -ri 's#/var/www/html#/var/www/flarum/public#g' /etc/apache2/sites-available/000-default.conf \
|
||||
&& printf '<Directory /var/www/flarum/public>\n AllowOverride All\n Require all granted\n</Directory>\n' > /etc/apache2/conf-enabled/flarum.conf
|
||||
COPY entrypoint.sh /entrypoint.sh
|
||||
WORKDIR /var/www/flarum
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
CMD ["apache2-foreground"]
|
||||
Executable
+33
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
# First start: install Flarum against the db service, enable the extensions the site relies on.
|
||||
set -e
|
||||
cd /var/www/flarum
|
||||
if [ ! -f config.php ]; then
|
||||
until php -r 'new PDO("mysql:host=db;dbname=flarum", "flarum", "flarum");' >/dev/null 2>&1; do sleep 2; done
|
||||
cat > /tmp/install.yml <<Y
|
||||
debug: true
|
||||
baseUrl: ${FORUM_URL}
|
||||
databaseConfiguration:
|
||||
driver: mysql
|
||||
host: db
|
||||
port: 3306
|
||||
database: flarum
|
||||
username: flarum
|
||||
password: flarum
|
||||
prefix:
|
||||
adminUser:
|
||||
username: admin
|
||||
password: ${ADMIN_PASSWORD}
|
||||
email: admin@example.com
|
||||
settings:
|
||||
forum_title: Old-Computers.com forum
|
||||
Y
|
||||
php flarum install --file=/tmp/install.yml
|
||||
fi
|
||||
# the museum extension is mounted from the repository (forum/extension)
|
||||
composer require --no-interaction "oc/flarum-museum:*@dev" >/dev/null 2>&1 || composer require --no-interaction "oc/flarum-museum:*@dev"
|
||||
php flarum migrate
|
||||
for ext in flarum-tags flarum-markdown flarum-embed oc-museum; do php flarum extension:enable "$ext" || true; done
|
||||
php flarum cache:clear
|
||||
chown -R www-data:www-data storage public/assets
|
||||
exec docker-php-entrypoint "$@"
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"name": "oc/flarum-museum",
|
||||
"description": "Old-Computers.com museum integration: imports the archived visitor comments as discussions and styles the embedded threads.",
|
||||
"type": "flarum-extension",
|
||||
"license": "MIT",
|
||||
"require": {
|
||||
"flarum/core": "^2.0",
|
||||
"flarum/tags": "^2.0",
|
||||
"flarum/embed": "^2.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Oc\\Museum\\": "src/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"flarum-extension": {
|
||||
"title": "Old-Computers museum",
|
||||
"icon": {
|
||||
"name": "fas fa-landmark",
|
||||
"backgroundColor": "#9a3412",
|
||||
"color": "#fff"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
use Flarum\Extend;
|
||||
use Oc\Museum\Console\ImportCommand;
|
||||
|
||||
return [
|
||||
(new Extend\Console())->command(ImportCommand::class),
|
||||
|
||||
// threads shown inside the museum pages (flarum/embed) take the look of the static site
|
||||
(new Extend\Frontend('embed'))->css(__DIR__.'/less/embed.less'),
|
||||
];
|
||||
@@ -0,0 +1,9 @@
|
||||
// Embedded thread, as shown in the Comments tab of the museum pages: full width, on the
|
||||
// light panel colour of the static site (--panel in its assets/css/main.css).
|
||||
@oc-accent: #9a3412;
|
||||
@oc-panel: #fffdf7;
|
||||
|
||||
body, .App { background: @oc-panel; }
|
||||
.Page-content { max-width: none; }
|
||||
.Post-body a, .PostUser-name a, .Button--link { color: @oc-accent; }
|
||||
.Button--primary { background: @oc-accent; }
|
||||
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
use Flarum\Database\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
// One discussion per museum machine; oc_id is the machine id of the original site.
|
||||
return Migration::createTable('oc_threads', function (Blueprint $table) {
|
||||
$table->unsignedInteger('oc_id')->primary();
|
||||
$table->unsignedInteger('discussion_id')->unique();
|
||||
});
|
||||
@@ -0,0 +1,167 @@
|
||||
<?php
|
||||
|
||||
namespace Oc\Museum\Console;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Flarum\Console\AbstractCommand;
|
||||
use Flarum\Discussion\Discussion;
|
||||
use Flarum\Post\CommentPost;
|
||||
use Flarum\Tags\Tag;
|
||||
use Flarum\User\User;
|
||||
use Illuminate\Database\ConnectionInterface;
|
||||
use Illuminate\Support\Str;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
|
||||
/**
|
||||
* Creates one discussion per museum machine from the file written by the extraction
|
||||
* pipeline (oc/scripts/06_forum.py), with the archived visitor comments as its posts.
|
||||
*
|
||||
* Safe to run again: machines already imported (table oc_threads) are skipped.
|
||||
*/
|
||||
class ImportCommand extends AbstractCommand
|
||||
{
|
||||
private const ARCHIVE_USER = 'Archive';
|
||||
private const TAGS = [
|
||||
'Computers' => ['#9a3412', 'fas fa-desktop'],
|
||||
'Consoles' => ['#1d4ed8', 'fas fa-gamepad'],
|
||||
'Pongs' => ['#15803d', 'fas fa-table-tennis-paddle-ball'],
|
||||
];
|
||||
|
||||
public function __construct(private ConnectionInterface $db)
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
protected function configure(): void
|
||||
{
|
||||
$this->setName('oc:import')
|
||||
->setDescription('Import the museum machines and their archived comments as discussions')
|
||||
->addArgument('file', InputArgument::REQUIRED, 'machines.json written by 06_forum.py')
|
||||
->addOption('site-url', null, InputOption::VALUE_REQUIRED, 'Address of the static site, e.g. https://example.org/oldcomputers', '')
|
||||
->addOption('map', null, InputOption::VALUE_REQUIRED, 'Where to write the machine -> discussion map (forum.json)');
|
||||
}
|
||||
|
||||
protected function fire(): int
|
||||
{
|
||||
$machines = json_decode((string) file_get_contents($this->input->getArgument('file')), true);
|
||||
if (! is_array($machines)) {
|
||||
$this->error('Cannot read the import file.');
|
||||
|
||||
return 1;
|
||||
}
|
||||
$site = rtrim((string) $this->input->getOption('site-url'), '/');
|
||||
$archive = $this->archiveUser();
|
||||
$tags = $this->tags();
|
||||
$done = $this->db->table('oc_threads')->pluck('discussion_id', 'oc_id');
|
||||
$created = $posts = 0;
|
||||
|
||||
foreach ($machines as $machine) {
|
||||
if (isset($done[$machine['oc_id']])) {
|
||||
continue;
|
||||
}
|
||||
$this->db->transaction(function () use ($machine, $site, $archive, $tags, &$posts, &$done) {
|
||||
$id = $this->importMachine($machine, $site, $archive, $tags[$machine['section']] ?? $tags['Computers']);
|
||||
$this->db->table('oc_threads')->insert(['oc_id' => $machine['oc_id'], 'discussion_id' => $id]);
|
||||
$done[$machine['oc_id']] = $id;
|
||||
$posts += count($machine['comments']);
|
||||
});
|
||||
if (++$created % 50 === 0) {
|
||||
$this->info("$created discussions…");
|
||||
}
|
||||
}
|
||||
|
||||
$archive->refreshCommentCount()->refreshDiscussionCount()->save();
|
||||
foreach ($tags as $tag) {
|
||||
$tag->discussion_count = $tag->discussions()->count();
|
||||
$tag->refreshLastPostedDiscussion()->save();
|
||||
}
|
||||
if ($map = $this->input->getOption('map')) {
|
||||
file_put_contents($map, json_encode($done, JSON_PRETTY_PRINT)."\n");
|
||||
}
|
||||
$this->info("$created discussions created with $posts archived comments; ".count($done).' machines mapped.');
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private function importMachine(array $machine, string $site, User $archive, Tag $tag): int
|
||||
{
|
||||
$comments = $machine['comments'];
|
||||
// the thread opens just before its first comment (or now, when there is none)
|
||||
$opened = $comments ? Carbon::parse($comments[0]['date'])->subMinute() : Carbon::now();
|
||||
$page = $site.$machine['path'];
|
||||
|
||||
$discussion = Discussion::start($machine['title'], $archive);
|
||||
$discussion->created_at = $opened;
|
||||
$discussion->save();
|
||||
|
||||
$first = $this->post($discussion, $archive, $opened,
|
||||
"Comments about the [{$machine['title']}]($page) page of the museum.\n\n"
|
||||
.($comments ? 'The first messages below were left by visitors of the original site.' : 'Be the first to comment!'));
|
||||
foreach ($comments as $comment) {
|
||||
$header = '**'.$this->plain($comment['author']).'**'
|
||||
.($comment['original_date'] ? ' — '.$this->plain($comment['original_date']) : '');
|
||||
$this->post($discussion, $archive, Carbon::parse($comment['date']), $header."\n\n".$comment['text']);
|
||||
}
|
||||
|
||||
$discussion->setFirstPost($first)->refreshCommentCount()->refreshLastPost()->refreshParticipantCount()->save();
|
||||
$discussion->tags()->sync([$tag->id]);
|
||||
|
||||
return $discussion->id;
|
||||
}
|
||||
|
||||
private function post(Discussion $discussion, User $user, Carbon $when, string $markdown): CommentPost
|
||||
{
|
||||
$post = new CommentPost();
|
||||
$post->discussion_id = $discussion->id;
|
||||
$post->user_id = $user->id;
|
||||
$post->created_at = $when;
|
||||
$post->type = CommentPost::$type;
|
||||
// the pipeline writes hard line breaks as "\" + newline; the forum keeps plain newlines
|
||||
$post->setContentAttribute(str_replace("\\\n", "\n", $markdown), $user);
|
||||
$post->save(); // events raised by the model are not dispatched: no notifications
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
private function plain(string $text): string
|
||||
{
|
||||
return preg_replace('/([\\\\*_`\[\]@])/', '\\\\$1', trim($text));
|
||||
}
|
||||
|
||||
private function archiveUser(): User
|
||||
{
|
||||
$user = User::query()->where('username', self::ARCHIVE_USER)->first();
|
||||
if (! $user) {
|
||||
$user = new User();
|
||||
$user->username = self::ARCHIVE_USER;
|
||||
$user->email = 'archive@invalid.invalid';
|
||||
$user->password = Str::random(40); // nobody logs in as the archive
|
||||
$user->is_email_confirmed = true;
|
||||
$user->joined_at = Carbon::now();
|
||||
$user->save();
|
||||
}
|
||||
|
||||
return $user;
|
||||
}
|
||||
|
||||
/** @return array<string, Tag> */
|
||||
private function tags(): array
|
||||
{
|
||||
$tags = [];
|
||||
$position = (int) Tag::query()->max('position');
|
||||
foreach (self::TAGS as $name => [$color, $icon]) {
|
||||
$tag = Tag::query()->where('slug', Str::slug($name))->first();
|
||||
if (! $tag) {
|
||||
// hidden from "All discussions": one thread per machine would bury the forum topics
|
||||
$tag = Tag::build($name, Str::slug($name), "Comments on the $name pages of the museum", $color, $icon, true);
|
||||
$tag->is_primary = true;
|
||||
$tag->position = ++$position;
|
||||
$tag->save();
|
||||
}
|
||||
$tags[$name] = $tag;
|
||||
}
|
||||
|
||||
return $tags;
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,11 @@ capitalizeListTitles = false
|
||||
listPosts = 10
|
||||
description = "The Old-Computers.com museum of computers, consoles and pongs, rebuilt from the Wayback Machine archive."
|
||||
|
||||
# Forum (Flarum, see forum/README.md). Empty url = no forum: no menu entry, and machine pages
|
||||
# show the archived comments as static text. With a url, the Comments tab shows the forum thread.
|
||||
[params.forum]
|
||||
url = ""
|
||||
|
||||
[taxonomies]
|
||||
category = "categories"
|
||||
type = "types"
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
{{ range site.Menus.main }}
|
||||
<a href="{{ .URL }}"{{ if or ($current.IsMenuCurrent .Menu .) ($current.HasMenuCurrent .Menu .) (eq $current.Section .Page.Section) }} class="active"{{ end }}>{{ .Name }}</a>
|
||||
{{ end }}
|
||||
{{ with site.Params.forum.url }}<a href="{{ . }}">Forum</a>{{ end }}
|
||||
</nav>
|
||||
<form class="search" role="search" action="{{ "search/" | relURL }}" method="get">
|
||||
<input type="search" name="q" placeholder="Search…" aria-label="Search the site">
|
||||
|
||||
@@ -33,6 +33,16 @@
|
||||
{{ end }}
|
||||
</div>
|
||||
|
||||
{{ else if and (eq $tab "comments") $p.forum_thread site.Params.forum.url }}
|
||||
{{/* live comments: the machine's forum thread, shown in a frame sized to its content */}}
|
||||
{{ $thread := printf "%s/embed/%d" (strings.TrimSuffix "/" site.Params.forum.url) (int $p.forum_thread) }}
|
||||
<p class="note">The first comments were left by visitors of the original site. Log in to the forum to add yours. <a href="{{ replace $thread "/embed/" "/d/" }}">Open this discussion in the forum</a>.</p>
|
||||
<iframe class="forum-thread" id="forum-thread" src="{{ $thread }}" title="Comments on {{ $m.Title }}" loading="lazy"></iframe>
|
||||
{{ with resources.Get "js/iframeResizer.min.js" | fingerprint }}
|
||||
<script src="{{ .RelPermalink }}"></script>
|
||||
<script>iFrameResize({ checkOrigin: false, heightCalculationMethod: "lowestElement" }, "#forum-thread");</script>
|
||||
{{ end }}
|
||||
|
||||
{{ else if eq $tab "comments" }}
|
||||
<p class="note">Comments left by visitors of the original site. New comments are closed.</p>
|
||||
<ol class="comments">
|
||||
|
||||
Reference in New Issue
Block a user