xgit simple git

nexus

nexus

clone git clone https://kb.hax.al/nexus

forum/search.php


1<?php
2require_once __DIR__ . '/../includes/bootstrap.php';
3 
4$q    = get('q');
5$type = get('type', 'topics'); // topics | users | posts
6if (!in_array($type, ['topics','users','posts'])) $type = 'topics';
7 
8$topicResults = [];
9$postResults  = [];
10$userResults  = [];
11 
12if (mb_strlen($q) >= 2) {
13    $like = '%' . $q . '%';
14 
15    if ($type === 'topics' || $type === 'posts') {
16        // Topics matching title
17        $topicResults = DB::rows("
18            SELECT t.*, u.username, c.name AS cat_name, c.slug AS cat_slug, c.color AS cat_color,
19                   NULL AS match_post_id
20            FROM topics t
21            JOIN users u ON u.id = t.user_id
22            JOIN categories c ON c.id = t.category_id
23            WHERE t.title LIKE ?
24            ORDER BY t.last_post_at DESC LIMIT 20
25        ", [$like]);
26    }
27 
28    if ($type === 'posts') {
29        // Posts matching content β€” include post ID so we can anchor to it
30        $postResults = DB::rows("
31            SELECT p.id AS post_id, p.content, p.post_num, p.created_at AS post_date,
32                   t.id AS topic_id, t.title, t.slug,
33                   u.username, u.avatar,
34                   c.name AS cat_name, c.slug AS cat_slug, c.color AS cat_color
35            FROM posts p
36            JOIN topics t ON t.id = p.topic_id
37            JOIN users u ON u.id = p.user_id
38            JOIN categories c ON c.id = t.category_id
39            WHERE p.content LIKE ? AND p.deleted = 0
40            ORDER BY p.created_at DESC LIMIT 30
41        ", [$like]);
42    }
43 
44    if ($type === 'users') {
45        $userResults = DB::rows("
46            SELECT id, username, avatar, role, karma, post_count, bio, joined_at
47            FROM users
48            WHERE (username LIKE ? OR bio LIKE ?) AND suspended = 0
49            ORDER BY post_count DESC LIMIT 30
50        ", [$like, $like]);
51    }
52}
53 
54$allCount = count($topicResults) + count($postResults) + count($userResults);
55$PAGE_TITLE = 'Search';
56include __DIR__ . '/../views/partials/layout.php';
57?>
58<div style="max-width:800px">
59 
60  <!-- Search form with type tabs -->
61  <form method="GET" id="searchForm">
62    <div style="display:flex;gap:10px;margin-bottom:16px">
63      <div style="position:relative;flex:1;max-width:560px">
64        <svg style="position:absolute;left:12px;top:50%;transform:translateY(-50%);color:var(--faint);pointer-events:none" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></svg>
65        <input type="text" name="q" value="<?= e($q) ?>" class="fi"
66               style="padding-left:34px" placeholder="Search topics, posts, users…"
67               autofocus autocomplete="off" id="mainSearchInput">
68      </div>
69      <button type="submit" class="btn-primary">Search</button>
70    </div>
71 
72    <!-- Type tabs -->
73    <div style="display:flex;gap:0;margin-bottom:22px;border-bottom:2px solid var(--border)">
74      <?php foreach (['topics'=>'πŸ“‹ Topics','posts'=>'πŸ’¬ Posts','users'=>'πŸ‘₯ Users'] as $t => $lbl): ?>
75        <button type="submit" name="type" value="<?= $t ?>"
76                class="srch-tab <?= $type===$t?'active':'' ?>"><?= $lbl ?></button>
77      <?php endforeach; ?>
78    </div>
79  </form>
80 
81  <?php if (mb_strlen($q) >= 2): ?>
82    <p class="search-info">
83      <?= count($type==='posts'?$postResults:($type==='users'?$userResults:$topicResults)) ?>
84      result<?= count($type==='posts'?$postResults:($type==='users'?$userResults:$topicResults))!==1?'s':'' ?>
85      for "<strong><?= e($q) ?></strong>"
86    </p>
87 
88    <?php if ($type === 'topics'): ?>
89      <?php if (empty($topicResults)): ?>
90        <div class="empty-state"><p>No topics found matching "<?= e($q) ?>".</p></div>
91      <?php else: ?>
92        <?php foreach ($topicResults as $t): ?>
93          <div class="topic-row">
94            <div class="tr-body">
95              <a href="<?= u('forum/topic.php?slug=' . urlencode($t['slug'])) ?>" class="tr-title"><?= e($t['title']) ?></a>
96              <div class="tr-meta">
97                <a href="<?= u('forum/category.php?slug=' . urlencode($t['cat_slug'])) ?>"
98                   class="cat-tag" style="--cc:<?= e($t['cat_color']) ?>"><?= e($t['cat_name']) ?></a>
99                by <a href="<?= u('users/profile.php?u=' . urlencode($t['username'])) ?>">@<?= e($t['username']) ?></a>
100                <span class="ago" data-ts="<?= e($t['created_at']) ?>"></span>
101              </div>
102            </div>
103            <div class="tr-counts"><span>πŸ’¬ <?= $t['reply_count'] ?></span><span>πŸ‘ <?= $t['views'] ?></span></div>
104          </div>
105        <?php endforeach; ?>
106      <?php endif; ?>
107 
108    <?php elseif ($type === 'posts'): ?>
109      <?php if (empty($postResults)): ?>
110        <div class="empty-state"><p>No posts found matching "<?= e($q) ?>".</p></div>
111      <?php else: ?>
112        <?php foreach ($postResults as $p): ?>
113          <?php
114            // Build URL with post anchor so user lands on the exact post
115            $postUrl = u('forum/topic.php?slug=' . urlencode($p['slug']) . '&goto=' . $p['post_id']) . '#post-' . $p['post_id'];
116            // Highlight the search term in content snippet
117            $snippet = mb_substr($p['content'], 0, 200);
118            $pos     = mb_stripos($p['content'], $q);
119            if ($pos !== false) {
120                $start   = max(0, $pos - 60);
121                $snippet = ($start > 0 ? '…' : '') . mb_substr($p['content'], $start, 200) . (mb_strlen($p['content']) > $start+200 ? '…' : '');
122            }
123          ?>
124          <div class="post-search-card">
125            <div class="psc-head">
126              <div style="display:flex;align-items:center;gap:8px;flex:1;min-width:0">
127                <?php if ($p['avatar']): ?>
128                  <img src="<?= e($p['avatar']) ?>" class="av-sm" alt="">
129                <?php else: ?>
130                  <span class="av-sm av-init"><?= strtoupper($p['username'][0]) ?></span>
131                <?php endif; ?>
132                <div style="min-width:0">
133                  <a href="<?= u('users/profile.php?u='.urlencode($p['username'])) ?>" style="font-weight:600;font-size:13px">@<?= e($p['username']) ?></a>
134                  <span style="color:var(--faint);font-size:12px;margin-left:6px">
135                    in <a href="<?= u('forum/topic.php?slug='.urlencode($p['slug'])) ?>" style="color:var(--muted)"><?= e(mb_substr($p['title'],0,60)) ?><?= mb_strlen($p['title'])>60?'…':'' ?></a>
136                  </span>
137                </div>
138              </div>
139              <div style="display:flex;align-items:center;gap:8px;flex-shrink:0">
140                <span class="ago" data-ts="<?= e($p['post_date']) ?>" style="font-size:12px;color:var(--faint)"></span>
141                <a href="<?= e($postUrl) ?>" class="btn-ghost btn-sm">View Post β†’</a>
142              </div>
143            </div>
144            <div class="psc-body"><?= e($snippet) ?></div>
145          </div>
146        <?php endforeach; ?>
147      <?php endif; ?>
148 
149    <?php elseif ($type === 'users'): ?>
150      <?php if (empty($userResults)): ?>
151        <div class="empty-state"><p>No users found matching "<?= e($q) ?>".</p></div>
152      <?php else: ?>
153        <div class="user-search-grid">
154          <?php foreach ($userResults as $u):
155            $kt = karma_tier((int)$u['karma']); ?>
156            <a href="<?= u('users/profile.php?u='.urlencode($u['username'])) ?>" class="user-search-card">
157              <div class="usc-av">
158                <?php if ($u['avatar']): ?>
159                  <img src="<?= e($u['avatar']) ?>" class="av-lg" alt="">
160                <?php else: ?>
161                  <span class="av-lg av-init"><?= strtoupper($u['username'][0]) ?></span>
162                <?php endif; ?>
163              </div>
164              <div class="usc-body">
165                <div class="usc-name">@<?= e($u['username']) ?> <span class="role-tag role-<?= e($u['role']) ?>"><?= e($u['role']) ?></span></div>
166                <?php if ($u['bio']): ?><div class="usc-bio"><?= e(mb_substr($u['bio'],0,80)) ?></div><?php endif; ?>
167                <div class="usc-stats">
168                  <span><?= number_format($u['post_count']) ?> posts</span>
169                  <span>Β·</span>
170                  <span style="color:<?= e($kt['color']) ?>"><?= $kt['icon'] ?> <?= number_format((int)$u['karma']) ?> karma</span>
171                </div>
172              </div>
173            </a>
174          <?php endforeach; ?>
175        </div>
176      <?php endif; ?>
177    <?php endif; ?>
178 
179  <?php elseif ($q): ?>
180    <div class="alert warn">Please enter at least 2 characters to search.</div>
181  <?php endif; ?>
182</div>
183 
184<script>
185// Auto-submit on tab change keeps query
186document.querySelectorAll('.srch-tab').forEach(function(btn){
187  btn.addEventListener('click',function(){
188    document.getElementById('mainSearchInput').form.submit();
189  });
190});
191</script>
192<?php include __DIR__ . '/../views/partials/layout_end.php'; ?>