OpenNIT

Quelltext des aktuellen Standes

Fassung 1.1.1

results.php

20 KB
<?php
// Standardwerte setzen
$query = $query ?? '';
$sort = $sort ?? 'relevance';
$total = $total ?? 0;
$total_pages = $total_pages ?? 1;
$page = $page ?? 1;
$selected_topic = $selected_topic ?? null;
$selected_topic_name = $selected_topic_name ?? '';
$topics = $topics ?? [];
$results = $results ?? [];
$topic_matches = $topic_matches ?? [];
$module_groups = $module_groups ?? [];

$this->layout('layouts/main', [
    'page_title' => 'Suche' . ($query ? ': ' . $query : ''),
    'full_width' => true
]);
?>

<div class="search-fullwidth">

    <!-- Content Header -->
    <div class="content-header">
        <div>
            <h1><?= $this->te('Suche') ?></h1>
            <ol class="breadcrumb">
                <li class="breadcrumb-item"><a href="/"><?= $this->te('Home') ?></a></li>
                <li class="breadcrumb-item active"><?= $this->te('Suche') ?></li>
            </ol>
        </div>
    </div>

    <!-- Body -->
    <div class="srch-body">

        <!-- Search Card -->
        <div class="card card-outline card-primary mb-3">
            <div class="filter-card-body">
                <form action="/search" method="GET">
                    <div class="input-group mb-2">
                        <input type="search" name="q" value="<?= $this->e($query) ?>"
                               placeholder="<?= $this->te('Suchbegriff eingeben…') ?>"
                               class="form-control"
                               autocomplete="off" autofocus>
                        <div class="input-group-append">
                            <button type="submit" class="btn btn-primary"><?= $this->te('&#128269; Suchen') ?></button>
                        </div>
                    </div>
                    <div class="srch-filters">
                        <div class="srch-filter-item">
                            <label for="f-359f-topic_id" class="srch-filter-label"><?= $this->te('Themengebiet:') ?></label>
                            <select id="f-359f-topic_id" name="topic_id" class="form-control form-control-sm" style="width:auto;">
                                <option value=""><?= $this->te('Alle Themengebiete') ?></option>
                                <?php foreach ($topics as $t): ?>
                                    <?php $indent = str_repeat('— ', $t['depth'] ?? 0); ?>
                                    <option value="<?= $t['id'] ?>" <?= ($selected_topic == $t['id']) ? 'selected' : '' ?>>
                                        <?= $indent ?><?= $this->e($t['name']) ?>
                                    </option>
                                <?php endforeach; ?>
                            </select>
                        </div>
                        <div class="srch-filter-item">
                            <label for="f-359f-sort" class="srch-filter-label"><?= $this->te('Sortierung:') ?></label>
                            <select id="f-359f-sort" name="sort" class="form-control form-control-sm" style="width:auto;">
                                <option value="relevance" <?= ($sort === 'relevance') ? 'selected' : '' ?>><?= $this->te('Relevanz') ?></option>
                                <option value="date"      <?= ($sort === 'date')      ? 'selected' : '' ?>><?= $this->te('Datum') ?></option>
                                <option value="title"     <?= ($sort === 'title')     ? 'selected' : '' ?>><?= $this->te('Titel') ?></option>
                            </select>
                        </div>
                    </div>
                </form>
            </div>
        </div>

        <?php if (!empty($query)): ?>
            <?php
            $hasModules  = !empty($module_groups);
            $hasTopics   = !empty($topic_matches);
            $hasPages    = !empty($results);
            $hasAnything = $hasModules || $hasTopics || $hasPages;
            ?>

            <?php if (!$hasAnything): ?>
                <!-- Keine Ergebnisse -->
                <div class="card">
                    <div class="card-body text-center srch-empty">
                        <div class="srch-empty-icon">&#128533;</div>
                        <h4><?= $this->te('Keine Ergebnisse') ?></h4>
                        <p class="text-muted">Für „<strong><?= $this->e($query) ?></strong>" wurden keine Ergebnisse gefunden.</p>
                        <ul class="text-left d-inline-block text-muted" style="font-size:0.875rem;">
                            <li><?= $this->te('Verwenden Sie weniger oder allgemeinere Suchbegriffe') ?></li>
                            <li><?= $this->te('Prüfen Sie die Rechtschreibung') ?></li>
                            <li><?= $this->te('Suchen Sie in allen Themengebieten') ?></li>
                        </ul>
                    </div>
                </div>

            <?php else: ?>

                <p class="srch-summary">
                    Ergebnisse für „<strong><?= $this->e($query) ?></strong>"<?php if ($selected_topic): ?> in <span class="text-primary"><?= $this->e($selected_topic_name ?? '') ?></span><?php endif; ?>
                </p>

                <!-- Modulübergreifende Treffer (Service-gesteuert) -->
                <?php foreach ($module_groups as $g): ?>
                <div class="card card-outline card-primary mb-3">
                    <div class="card-header">
                        <h3 class="card-title"><span class="mr-1"><?= $g['icon'] ?></span> <?= $this->e($g['label']) ?></h3>
                        <div class="card-tools"><span class="badge badge-primary"><?= (int)$g['total'] ?></span></div>
                    </div>
                    <div class="card-body p-0">
                        <?php foreach ($g['items'] as $it): ?>
                        <a href="<?= $this->e($it['url']) ?>" class="srch-row">
                            <div class="srch-row-icon"><span class="srch-emoji"><?= $g['icon'] ?></span></div>
                            <div class="srch-row-body">
                                <div class="srch-row-title"><?= $this->highlightSearch($it['title'] ?? '', $query) ?></div>
                                <?php if (!empty($it['subtitle'])): ?>
                                    <div class="srch-row-meta"><span><?= $this->e($it['subtitle']) ?></span></div>
                                <?php endif; ?>
                            </div>
                            <div class="srch-row-arrow">&#8250;</div>
                        </a>
                        <?php endforeach; ?>
                        <?php if (!empty($g['has_more'])): ?>
                        <a href="<?= $this->e($g['more_url']) ?>" class="srch-row srch-row-more">
                            <div class="srch-row-body"><div class="srch-row-title text-primary"><?= $this->t('Alle') ?> <?= (int)$g['total'] ?> Treffer anzeigen &rarr;</div></div>
                        </a>
                        <?php endif; ?>
                    </div>
                </div>
                <?php endforeach; ?>

                <!-- 2. Themengebiete -->
                <?php if ($hasTopics): ?>
                <div class="card card-outline card-primary mb-3">
                    <div class="card-header">
                        <h3 class="card-title">
                            <i class="fas fa-folder mr-1"></i> <?= $this->te('Themengebiete') ?>
                        </h3>
                        <div class="card-tools">
                            <span class="badge badge-primary"><?= count($topic_matches) ?></span>
                        </div>
                    </div>
                    <div class="card-body p-0">
                        <?php foreach ($topic_matches as $tm): ?>
                        <a href="/topics/<?= $tm['id'] ?>" class="srch-row">
                            <div class="srch-row-icon">
                                <?php if (!empty($tm['image_path'])): ?>
                                    <img src="/uploads/topics/<?= $this->e($tm['image_path']) ?>" alt="" class="srch-avatar srch-avatar-sq">
                                <?php else: ?>
                                    <span class="srch-emoji">&#128193;</span>
                                <?php endif; ?>
                            </div>
                            <div class="srch-row-body">
                                <div class="srch-row-title"><?= $this->highlightSearch($tm['name'], $query) ?></div>
                                <div class="srch-row-meta">
                                    <span><?= (int)$tm['page_count'] ?> Seite<?= (int)$tm['page_count'] !== 1 ? 'n' : '' ?></span>
                                    <?php if (!empty($tm['description'])): ?>
                                        <span><?= $this->e(mb_substr($tm['description'], 0, 100)) ?><?= mb_strlen($tm['description'] ?? '') > 100 ? '…' : '' ?></span>
                                    <?php endif; ?>
                                </div>
                            </div>
                            <div class="srch-row-arrow">&#8250;</div>
                        </a>
                        <?php endforeach; ?>
                    </div>
                </div>
                <?php endif; ?>

                <!-- 3. Seiten / Dateien -->
                <?php if ($hasPages): ?>
                <?php $isTagSearch = str_starts_with($query, 'tag:'); ?>
                <div class="card card-outline card-primary mb-3">
                    <div class="card-header">
                        <h3 class="card-title">
                            <i class="fas fa-file-alt mr-1"></i>
                            <?= $isTagSearch ? 'Seiten mit Tag' : 'Seiten' ?>
                        </h3>
                        <div class="card-tools">
                            <span class="badge badge-primary"><?= $total ?></span>
                        </div>
                    </div>
                    <div class="card-body p-0">
                        <?php foreach ($results as $result): ?>
                        <?php $isFile = (($result['result_type'] ?? 'page') === 'file'); ?>
                        <a href="<?= $isFile ? '/files/' . $result['id'] : '/pages/' . $result['id'] ?>" class="srch-row">
                            <div class="srch-row-icon">
                                <span class="srch-emoji"><?= $isFile ? '&#128206;' : '&#128196;' ?></span>
                            </div>
                            <div class="srch-row-body">
                                <div class="srch-row-title"><?= $this->highlightSearch($result['title'] ?? '', $isTagSearch ? '' : $query) ?></div>
                                <?php if (!empty($result['snippet'])): ?>
                                <div class="srch-row-snippet"><?= $this->highlightSearch($result['snippet'], $isTagSearch ? '' : $query) ?></div>
                                <?php endif; ?>
                                <div class="srch-row-meta">
                                    <?php if (!empty($result['topic_name'])): ?>
                                        <span>&#128193; <?= $this->e($result['topic_name']) ?></span>
                                    <?php endif; ?>
                                    <?php if (!empty($result['version_number'])): ?>
                                        <span>v<?= $result['version_number'] ?></span>
                                    <?php endif; ?>
                                    <?php if (!empty($result['updated_at'])): ?>
                                        <span><?= $this->relativeTime($result['updated_at']) ?></span>
                                    <?php endif; ?>
                                    <?php if (!empty($result['tags'])): ?>
                                        <?php foreach ($result['tags'] as $rtag): ?>
                                        <span class="srch-tag" style="background:<?= $this->e($rtag['color']) ?>18;color:<?= $this->e($rtag['color']) ?>;border:1px solid <?= $this->e($rtag['color']) ?>35;"
                                              onclick="event.stopPropagation();window.location='/search?q=tag%3A<?= urlencode($rtag['name']) ?>';">
                                            <?= $this->e($rtag['name']) ?>
                                        </span>
                                        <?php endforeach; ?>
                                    <?php endif; ?>
                                </div>
                            </div>
                            <div class="srch-row-arrow">&#8250;</div>
                        </a>
                        <?php endforeach; ?>
                    </div>

                    <!-- Pagination -->
                    <?php if ($total_pages > 1): ?>
                    <div class="card-footer">
                        <nav>
                            <ul class="pagination pagination-sm m-0">
                                <li class="page-item <?= $page <= 1 ? 'disabled' : '' ?>">
                                    <a aria-label="<?= $this->te('Vorherige Seite') ?>" class="page-link" href="?q=<?= urlencode($query) ?>&page=<?= $page - 1 ?>&topic_id=<?= $selected_topic ?>&sort=<?= urlencode($sort) ?>">&laquo;</a>
                                </li>
                                <?php
                                $start = max(1, $page - 2);
                                $end   = min($total_pages, $page + 2);
                                if ($start > 1): ?>
                                    <li class="page-item"><a class="page-link" href="?q=<?= urlencode($query) ?>&page=1&topic_id=<?= $selected_topic ?>&sort=<?= urlencode($sort) ?>">1</a></li>
                                    <?php if ($start > 2): ?><li class="page-item disabled"><span class="page-link">&hellip;</span></li><?php endif; ?>
                                <?php endif; ?>
                                <?php for ($i = $start; $i <= $end; $i++): ?>
                                    <li class="page-item <?= $i === $page ? 'active' : '' ?>">
                                        <a class="page-link" href="?q=<?= urlencode($query) ?>&page=<?= $i ?>&topic_id=<?= $selected_topic ?>&sort=<?= urlencode($sort) ?>"><?= $i ?></a>
                                    </li>
                                <?php endfor; ?>
                                <?php if ($end < $total_pages): ?>
                                    <?php if ($end < $total_pages - 1): ?><li class="page-item disabled"><span class="page-link">&hellip;</span></li><?php endif; ?>
                                    <li class="page-item"><a class="page-link" href="?q=<?= urlencode($query) ?>&page=<?= $total_pages ?>&topic_id=<?= $selected_topic ?>&sort=<?= urlencode($sort) ?>"><?= $total_pages ?></a></li>
                                <?php endif; ?>
                                <li class="page-item <?= $page >= $total_pages ? 'disabled' : '' ?>">
                                    <a aria-label="<?= $this->te('Nächste Seite') ?>" class="page-link" href="?q=<?= urlencode($query) ?>&page=<?= $page + 1 ?>&topic_id=<?= $selected_topic ?>&sort=<?= urlencode($sort) ?>">&raquo;</a>
                                </li>
                            </ul>
                        </nav>
                    </div>
                    <?php endif; ?>

                </div>
                <?php endif; ?>

            <?php endif; ?>

        <?php else: ?>
            <!-- Startseite Suche -->
            <div class="card card-outline card-primary">
                <div class="card-body text-center srch-empty">
                    <div class="srch-empty-icon">&#128269;</div>
                    <h4><?= $this->te('Dokumentation durchsuchen') ?></h4>
                    <p class="text-muted"><?= $this->te('Geben Sie einen Suchbegriff ein, um OpenNIT zu durchsuchen.') ?></p>
                    <?php if (!empty($topics)): ?>
                    <div class="srch-topic-tags">
                        <p class="text-muted mb-1" style="font-size:0.85rem;"><?= $this->te('Beliebte Themengebiete:') ?></p>
                        <?php foreach (array_slice($topics, 0, 8) as $t): ?>
                            <?php if (($t['depth'] ?? 0) == 0): ?>
                            <a href="/topics/<?= $t['id'] ?>" class="badge badge-light srch-topic-badge"><?= $this->e($t['name']) ?></a>
                            <?php endif; ?>
                        <?php endforeach; ?>
                    </div>
                    <?php endif; ?>
                </div>
            </div>
        <?php endif; ?>

    </div><!-- /.srch-body -->
</div>

<style>
/* ── Layout ─────────────────────────────────────────────────────────────── */
.srch-body {
    padding: 1.5rem 1rem 3rem;
    background: var(--slate-50);
    min-height: calc(100vh - 320px);
}
.srch-summary {
    font-size: 0.9rem;
    color: var(--gray-500);
    margin: 0 0 1rem 0;
}
.srch-filters {
    display: flex;
    gap: 1.25rem;
    flex-wrap: wrap;
    align-items: center;
}
.srch-filter-item {
    display: flex;
    align-items: center;
    gap: 0.5rem;
}
.srch-filter-label {
    margin: 0;
    font-size: 0.82rem;
    color: var(--color-secondary);
    white-space: nowrap;
}

/* ── Result rows ────────────────────────────────────────────────────────── */
.srch-row {
    display: flex;
    align-items: flex-start;
    gap: 0.875rem;
    padding: 0.75rem 1rem;
    text-decoration: none;
    color: inherit;
    border-bottom: 1px solid var(--gray-100);
    transition: background 0.1s;
}
.srch-row:last-child { border-bottom: none; }
.srch-row:hover { background: var(--slate-50); text-decoration: none; color: inherit; }

.srch-row-icon {
    flex-shrink: 0;
    width: 34px;
    height: 34px;
    display: flex;
    align-items: center;
    justify-content: center;
    margin-top: 0.1rem;
}
.srch-avatar {
    width: 34px; height: 34px;
    border-radius: 50%; object-fit: cover;
}
.srch-avatar-sq { border-radius: 0.25rem; }
.srch-emoji { font-size: 1.35rem; line-height: 1; }

.srch-row-body { flex: 1; min-width: 0; }
.srch-row-title {
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--color-primary-deep);
    margin-bottom: 0.2rem;
}
.srch-row-title mark {
    background: var(--alert-warning-bg); color: inherit;
    padding: 0 2px; border-radius: 2px;
}
.srch-row-snippet {
    font-size: 0.78rem;
    color: var(--gray-500);
    line-height: 1.5;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    margin-bottom: 0.2rem;
}
.srch-row-snippet mark {
    background: var(--alert-warning-bg); color: inherit;
    padding: 0 2px; border-radius: 2px;
}
.srch-row-meta {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    font-size: 0.72rem;
    color: var(--gray-400);
}
.srch-row-meta span + span:not(.badge):not(.srch-tag)::before {
    content: "·";
    margin-right: 0.4rem;
}
.srch-tag {
    display: inline-block;
    padding: 0.1rem 0.45rem;
    border-radius: 0.25rem;
    font-size: 0.68rem;
    font-weight: 600;
    cursor: pointer;
}
.srch-row-arrow {
    flex-shrink: 0;
    color: var(--gray-300);
    font-size: 1.1rem;
    align-self: center;
}

/* ── Empty / start states ───────────────────────────────────────────────── */
.srch-empty { padding: 2.5rem 1rem; }
.srch-empty-icon { font-size: 3.5rem; margin-bottom: 0.75rem; opacity: 0.7; }
.srch-topic-tags { margin-top: 1rem; display: flex; flex-wrap: wrap; gap: 0.4rem; justify-content: center; }
.srch-topic-badge {
    font-size: 0.82rem; font-weight: 500;
    padding: 0.35rem 0.75rem;
    border: 1px solid var(--color-gray-300);
    border-radius: 0.25rem;
    text-decoration: none;
}
.srch-topic-badge:hover { background: var(--color-gray-200); text-decoration: none; }

@media (max-width: 768px) {
    .srch-body { padding: 1rem; }
    .srch-filters { gap: 0.75rem; }
}
</style>