Add corpus explorer: search bar (Hybrid/BM25/Vector), category drill-down, source row expand

- api/corpus-search.php: new endpoint with three search modes (hybrid RAG, BM25 keyword, Qdrant vector)
- api/corpus-documents.php: paginated document browser by category or source name
- corpus.php: search bar with mode+language pills, Browse docs button on each category card with drill-down panel, expand toggle on each source row showing doc count and scraper class
- tools.css: all new corpus interactive styles appended

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-15 11:55:54 +02:00
parent 785de04f05
commit 38255669a9
4 changed files with 962 additions and 42 deletions
+344
View File
@@ -2708,3 +2708,347 @@ a.dr-source-title-link:hover {
color: var(--teal-dark);
text-decoration: underline;
}
/* ── Corpus Explorer: Search bar ─────────────────────────────────────── */
.corpus-search-box {
padding: 0 0 24px;
border-bottom: 1px solid var(--line);
margin-bottom: 32px;
}
.corpus-search-row {
display: flex;
gap: 8px;
align-items: center;
}
.corpus-search-input {
flex: 1;
height: 40px;
padding: 0 12px;
border: 1px solid var(--line);
border-radius: 6px;
font-size: 0.9rem;
background: var(--panel);
color: var(--ink);
outline: none;
transition: border-color 0.15s;
}
.corpus-search-input:focus { border-color: var(--teal); }
.corpus-search-controls {
display: flex;
align-items: center;
justify-content: space-between;
margin-top: 10px;
gap: 12px;
flex-wrap: wrap;
}
.search-modes,
.lang-pills {
display: flex;
gap: 4px;
}
.mode-pill {
padding: 3px 12px;
border: 1px solid var(--line);
border-radius: 999px;
background: transparent;
color: var(--muted);
font-size: 0.8rem;
cursor: pointer;
transition: background 0.12s, color 0.12s, border-color 0.12s;
}
.mode-pill:hover { border-color: var(--teal); color: var(--teal); }
.mode-pill.is-active {
background: var(--teal);
border-color: var(--teal);
color: #fff;
}
/* ── Search results ───────────────────────────────────────────────────── */
.corpus-search-results {
margin: 0 0 32px;
}
.search-results-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.search-results-count {
font-size: 0.8rem;
color: var(--muted);
}
.search-loading,
.search-empty,
.search-error,
.search-hint {
font-size: 0.85rem;
color: var(--muted);
padding: 12px 0;
}
.search-error { color: var(--coral); }
.passage-card {
background: var(--panel);
border: 1px solid var(--line);
border-left: 3px solid var(--teal);
border-radius: 6px;
padding: 14px 16px;
margin-bottom: 10px;
}
.passage-card__meta {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 6px;
flex-wrap: wrap;
}
.passage-section {
font-size: 0.78rem;
color: var(--muted);
font-style: italic;
}
.passage-score {
font-size: 0.75rem;
background: var(--soft-teal);
color: var(--teal-dark);
padding: 1px 7px;
border-radius: 999px;
margin-left: auto;
}
.passage-card__title {
display: block;
font-size: 0.88rem;
font-weight: 600;
color: var(--ink);
text-decoration: none;
margin-bottom: 6px;
}
.passage-card__title:hover { color: var(--teal); text-decoration: underline; }
.passage-card__excerpt {
font-size: 0.82rem;
color: var(--muted);
line-height: 1.55;
margin: 0;
display: -webkit-box;
-webkit-line-clamp: 4;
-webkit-box-orient: vertical;
overflow: hidden;
}
.passage-card mark {
background: var(--soft-teal);
color: var(--teal-dark);
border-radius: 2px;
padding: 0 1px;
}
/* ── Category card browse button ──────────────────────────────────────── */
.cat-browse-btn {
display: inline-block;
margin-top: 10px;
padding: 4px 12px;
background: var(--soft-teal);
border: 1px solid var(--teal);
border-radius: 5px;
color: var(--teal);
font-size: 0.8rem;
cursor: pointer;
transition: background 0.12s, color 0.12s;
}
.cat-browse-btn:hover {
background: var(--teal);
color: #fff;
}
/* ── Drill-down panel ─────────────────────────────────────────────────── */
.corpus-drill-panel {
margin-top: 20px;
background: var(--panel);
border: 1px solid var(--line);
border-top: 3px solid var(--teal);
border-radius: 0 0 8px 8px;
padding: 24px;
}
.drill-header {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 20px;
}
.drill-header h3 {
margin: 4px 0 0;
font-size: 1.05rem;
}
.drill-close-btn {
background: transparent;
border: 1px solid var(--line);
border-radius: 50%;
width: 28px;
height: 28px;
cursor: pointer;
color: var(--muted);
font-size: 0.9rem;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.drill-close-btn:hover { border-color: var(--teal); color: var(--teal); }
.drill-loading,
.drill-empty,
.drill-error {
font-size: 0.85rem;
color: var(--muted);
padding: 8px 0;
}
.drill-error { color: var(--coral); }
.doc-list { display: flex; flex-direction: column; gap: 8px; }
.doc-list__item {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: 12px;
padding: 10px 12px;
background: var(--bg);
border: 1px solid var(--line);
border-radius: 5px;
}
.doc-list__item:hover { border-color: var(--teal); }
.doc-list__info { flex: 1; min-width: 0; }
.doc-list__title {
display: block;
font-size: 0.88rem;
font-weight: 500;
color: var(--ink);
text-decoration: none;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.doc-list__title:hover { color: var(--teal); text-decoration: underline; }
.doc-list__meta {
display: flex;
align-items: center;
gap: 8px;
margin-top: 4px;
flex-wrap: wrap;
}
.doc-list__date {
font-size: 0.78rem;
color: var(--muted);
}
.doc-list__chunks {
flex-shrink: 0;
font-size: 0.75rem;
background: var(--soft-teal);
color: var(--teal-dark);
padding: 2px 8px;
border-radius: 999px;
white-space: nowrap;
}
.doc-list__more-wrap {
text-align: center;
margin-top: 16px;
}
.doc-list__more {
padding: 7px 20px;
border: 1px solid var(--teal);
border-radius: 5px;
background: transparent;
color: var(--teal);
font-size: 0.85rem;
cursor: pointer;
transition: background 0.12s, color 0.12s;
}
.doc-list__more:hover { background: var(--teal); color: #fff; }
/* ── Sources table expand column ──────────────────────────────────────── */
.source-expand-cell { width: 32px; padding: 0 4px !important; text-align: center; }
.source-expand-btn {
background: transparent;
border: 1px solid var(--line);
border-radius: 4px;
width: 22px;
height: 22px;
font-size: 0.65rem;
cursor: pointer;
color: var(--muted);
display: inline-flex;
align-items: center;
justify-content: center;
transition: border-color 0.12s, color 0.12s;
}
.source-expand-btn:hover { border-color: var(--teal); color: var(--teal); }
.source-expand-row > td {
padding: 0 !important;
background: var(--soft-teal);
border-top: none;
}
.source-expand-inner {
padding: 16px 20px;
}
.source-expand-loading,
.source-expand-error {
font-size: 0.82rem;
color: var(--muted);
}
.source-expand-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
}
.source-expand-dl {
display: grid;
grid-template-columns: auto 1fr;
gap: 4px 12px;
font-size: 0.82rem;
margin: 0;
}
.source-expand-dl dt { color: var(--muted); white-space: nowrap; }
.source-expand-dl dd { margin: 0; }
.source-expand-url {
font-size: 0.78rem;
word-break: break-all;
margin: 0 0 12px;
}
.source-expand-url a { color: var(--teal); }
.source-browse-btn {
font-size: 0.82rem !important;
padding: 5px 14px !important;
}
@media (max-width: 760px) {
.source-expand-grid { grid-template-columns: 1fr; }
.corpus-search-controls { flex-direction: column; align-items: flex-start; }
}