<?php
require_once __DIR__ . '/config.php';
if (!IS_INSTALLED) { header('Location: setup.php'); exit; }
require_once ROOT_PATH . '/includes/db.php';
require_once ROOT_PATH . '/includes/functions.php';
require_once ROOT_PATH . '/includes/auth.php';
require_once ROOT_PATH . '/includes/markdown.php';
$slug = trim($_GET['slug'] ?? '');
$topic = $slug ? get_topic($slug) : null;
if (!$topic) { http_response_code(404); die('Topic not found.'); }
// Sub-topics and ancestor breadcrumb
$subTopics = get_subtopics($topic['id']);
$ancestors = get_topic_ancestors($topic['id']);
// Filters
$allTags = audience_tags_enabled() ? get_tags() : [];
$tagFilter = audience_tags_enabled() ? (int)($_GET['tag'] ?? 0) : 0;
$searchQ = trim($_GET['q'] ?? '');
$where = ["d.topic_id = ?", "d.status = 'published'"];
$params = [$topic['id']];
if ($tagFilter) { $where[] = 'd.id IN (SELECT document_id FROM document_tags WHERE tag_id = ?)'; $params[] = $tagFilter; }
if ($searchQ) {
if (fts5_available()) {
$where[] = "d.id IN (SELECT document_id FROM search_index WHERE search_index MATCH ? AND status = 'published')";
$params[] = fts5_query($searchQ);
} else {
$where[] = "(d.title LIKE ? OR d.meta_description LIKE ?)";
$params[] = "%$searchQ%";
$params[] = "%$searchQ%";
}
}
$stmt = db()->prepare(
"SELECT d.*, u.username AS author_name FROM documents d
LEFT JOIN users u ON d.author_id = u.id
WHERE " . implode(' AND ', $where) . " ORDER BY d.updated_at DESC"
);
$stmt->execute($params);
$docs = $stmt->fetchAll();
$meta = build_meta([
'title' => $topic['title'] . ' — ' . get_setting('site_title', SITE_NAME),
'og_title' => $topic['title'],
'og_desc' => $topic['description'] ?: get_setting('og_description'),
'og_image' => $topic['og_image'],
'og_type' => 'website',
]);
include ROOT_PATH . '/includes/header.php';
?>
<!-- Breadcrumb with ancestor chain -->
<div class="breadcrumb">
<a href="<?= h(base_url()) ?>">Home</a>
<?php foreach ($ancestors as $anc): ?>
› <a href="<?= h(topic_url($anc['slug'])) ?>"><?= h($anc['title']) ?></a>
<?php endforeach; ?>
› <?= h($topic['title']) ?>
</div>
<div class="window topic-window">
<div class="win-titlebar">
📂 <?= h($topic['title']) ?>
<a href="<?= h(rss_url($topic['slug'])) ?>" class="rss-badge" title="RSS Feed for this topic">RSS</a>
</div>
<div class="win-body">
<!-- Search at top -->
<div class="tag-filter" style="flex-wrap:wrap;gap:6px;align-items:center;margin-bottom:8px">
<form method="get" action="<?= h(topic_url($topic['slug'])) ?>" style="display:flex;gap:4px;align-items:center;flex-wrap:wrap">
<?php if ($tagFilter): ?><input type="hidden" name="tag" value="<?= $tagFilter ?>"><?php endif; ?>
<input type="search" name="q" placeholder="Search this topic…" value="<?= h($searchQ) ?>"
style="font-size:12px;padding:2px 6px;border:1px solid #808080;background:#FFF;font-family:inherit;width:180px">
<button type="submit" style="font-size:11px;padding:2px 8px;border:2px solid;border-color:#FFF #404040 #404040 #FFF;background:#C0C0C0;cursor:pointer;font-family:inherit">Search</button>
<?php if ($searchQ || $tagFilter): ?>
<a href="<?= h(topic_url($topic['slug'])) ?>" style="font-size:11px">✕ Clear</a>
<?php endif; ?>
</form>
<?php if (!empty($allTags)): ?>
<div style="display:flex;flex-wrap:wrap;gap:4px;align-items:center">
<strong style="font-size:11px">Audience:</strong>
<a href="<?= h(topic_url($topic['slug'])) ?><?= $searchQ ? '?q='.rawurlencode($searchQ) : '' ?>" class="tag-badge <?= !$tagFilter ? 'active' : '' ?>" style="background:#444;color:#FFF">All</a>
<?php foreach ($allTags as $tg): ?>
<?php $tagUrl = topic_url($topic['slug']) . '?tag=' . $tg['id'] . ($searchQ ? '&q='.rawurlencode($searchQ) : ''); ?>
<a href="<?= h($tagUrl) ?>"
class="tag-badge <?= $tagFilter === (int)$tg['id'] ? 'active' : '' ?>"
style="background:<?= h($tg['color']) ?>; color:#FFF;"><?= h($tg['name']) ?></a>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
<?php if ($topic['og_image']): ?>
<img src="<?= h(base_url('uploads/og/' . $topic['og_image'])) ?>" alt="<?= h($topic['title']) ?>" class="topic-feature-image">
<?php endif; ?>
<?php if ($topic['description']): ?>
<p class="topic-description"><?= h($topic['description']) ?></p>
<?php endif; ?>
<p class="topic-meta">Created: <?= h(fmt_date($topic['created_at'])) ?> • Updated: <?= h(fmt_date($topic['updated_at'])) ?></p>
<!-- Topic landing page (Markdown) -->
<?php if (!empty($topic['landing_content']) && ($topic['landing_enabled'] || has_role('editor'))): ?>
<div class="window" style="margin-bottom:12px">
<div class="win-titlebar">📄 <?= h($topic['title']) ?>
<?php if (has_role('editor')): ?>
<div class="win-actions" style="float:right">
<a href="<?= h(base_url('admin/topics.php?action=edit&id=' . $topic['id'])) ?>" class="button btn-sm" style="font-size:11px">✎ Edit Landing</a>
</div>
<?php endif; ?>
<?php if (!$topic['landing_enabled']): ?>
<span style="font-size:11px;opacity:0.75">(disabled — editors only)</span>
<?php endif; ?>
</div>
<div class="win-body"><div class="markdown-body"><?= md($topic['landing_content']) ?></div></div>
</div>
<?php elseif (has_role('editor') && empty($topic['landing_content'])): ?>
<p style="font-size:11px;color:#666;margin:0 0 8px">
<a href="<?= h(base_url('admin/topics.php?action=edit&id=' . $topic['id'])) ?>">+ Add topic landing page</a>
</p>
<?php endif; ?>
<!-- Sub-topics (up to level 3) -->
<?php if (!empty($subTopics)): ?>
<div class="section-titlebar" style="margin:8px 0 6px"><h2 style="margin:0;font-size:13px">📁 Sub-Topics</h2></div>
<div class="topics-grid" style="margin-bottom:14px">
<?php foreach ($subTopics as $st): ?>
<?php $stCount = count(get_documents($st['id'])); ?>
<a href="<?= h(topic_url($st['slug'])) ?>" class="topic-card">
<div class="topic-card-body">
<?php if ($st['og_image']): ?>
<img src="<?= h(base_url('uploads/og/' . $st['og_image'])) ?>" alt="" class="topic-thumb">
<?php else: ?>
<span class="topic-icon">📁</span>
<?php endif; ?>
<strong class="topic-card-name"><?= h($st['title']) ?></strong>
<p class="topic-desc"><?= h($st['description']) ?></p>
<span class="topic-count"><?= $stCount ?> doc<?= $stCount !== 1 ? 's' : '' ?></span>
</div>
</a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<!-- Document cards -->
<?php if (empty($docs)): ?>
<?php if (!empty($subTopics) && !$tagFilter): ?>
<p class="empty-state" style="margin-top:4px">Browse the sub-topics above, or select an audience tag to filter.</p>
<?php else: ?>
<p class="empty-state">No documents in this topic<?= $tagFilter ? ' for this audience' : '' ?>.</p>
<?php endif; ?>
<?php else: ?>
<?php if (!empty($subTopics)): ?><div class="section-titlebar" style="margin:8px 0 6px"><h2 style="margin:0;font-size:13px">📄 Documents in this topic</h2></div><?php endif; ?>
<div class="doc-cards">
<?php foreach ($docs as $d): ?>
<?php
$dtags = audience_tags_enabled() ? get_document_tags($d['id']) : [];
$dgtags = get_document_generic_tags($d['id']);
?>
<div class="doc-card">
<div class="doc-card-body">
<?php if ($d['og_image']): ?>
<img src="<?= h(base_url('uploads/og/' . $d['og_image'])) ?>" alt="" class="doc-card-thumb">
<?php endif; ?>
<strong class="doc-card-name"><a href="<?= h(doc_url($topic['slug'], $d['slug'])) ?>"><?= h($d['title']) ?></a></strong>
<?php if ($d['meta_description']): ?>
<p class="doc-card-desc"><?= h($d['meta_description']) ?></p>
<?php endif; ?>
<div class="doc-card-meta">
<?php if (!empty($dtags)): ?>
<div class="doc-card-tags">
<?php foreach ($dtags as $tg): ?>
<a href="<?= h(topic_url($topic['slug'])) ?>?tag=<?= $tg['id'] ?>"
class="tag-badge"
style="background:<?= h($tg['color']) ?>;color:#FFF"><?= h($tg['name']) ?></a>
<?php endforeach; ?>
</div>
<?php endif; ?>
<?php if (!empty($dgtags)): ?>
<div class="doc-card-tags">
<?php foreach ($dgtags as $gt): ?>
<span class="tag-badge" style="background:#555;color:#FFF"><?= h($gt['name']) ?></span>
<?php endforeach; ?>
</div>
<?php endif; ?>
<div class="doc-card-topic">
🕑 Updated <?= h(fmt_date($d['updated_at'])) ?>
</div>
</div>
</div>
</div>
<?php endforeach; ?>
</div>
<?php endif; ?>
</div>
</div>
<?php include ROOT_PATH . '/includes/footer.php'; ?>