Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 45 additions & 7 deletions assets/js/vertex-search.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
import { marked } from 'marked';
import DOMPurify from 'dompurify';

(function () {
'use strict';

marked.setOptions({
gfm: true,
breaks: true
});

// Only run on the search results page
const config = document.getElementById('vertex-search-config');
if (!config) return;
Expand Down Expand Up @@ -29,6 +37,23 @@
.replace(/"/g, '"');
}

function renderSummaryMarkdown(summaryText, citationCount) {
const linkedMarkdown = (summaryText || '').replace(/\[(\d+)\]/g, (_, num) => {
const index = Number(num);
if (!Number.isInteger(index) || index < 1 || index > citationCount) return `[${num}]`;
return `[${num}](#source-row-${index})`;
});

const html = marked.parse(linkedMarkdown);
return DOMPurify.sanitize(html, {
ALLOWED_TAGS: [
'a', 'p', 'ul', 'ol', 'li', 'strong', 'em', 'code', 'pre',
'blockquote', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'br'
],
ALLOWED_ATTR: ['href', 'title', 'target', 'rel', 'id', 'class']
});
}

async function doSearch(q) {
if (!q) {
statusEl.textContent = 'Enter a search query above.';
Expand Down Expand Up @@ -62,29 +87,42 @@

// Show AI summary if available
if (data.summary?.summaryText) {
summaryTxt.textContent = data.summary.summaryText;
summaryEl.style.display = 'block';

// Render numbered citation list
const refs = data.summary?.citations || [];
const validRefs = refs.filter(r => r.title || r.uri);


summaryTxt.innerHTML = renderSummaryMarkdown(data.summary.summaryText, validRefs.length);

const inlineRefs = summaryTxt.querySelectorAll('a[href^="#source-row-"]');
inlineRefs.forEach((el) => {
el.classList.add('summary-inline-citation');
el.setAttribute('aria-label', `Jump to source ${el.textContent}`);
});

summaryEl.style.display = 'block';

// Remove stale source rows before rendering the latest list.
const previousCitations = summaryEl.querySelector('.search-citations');
if (previousCitations) previousCitations.remove();

if (validRefs.length > 0) {
const citationHtml = validRefs.map((ref, i) => `
<div class="search-citation">
<div id="source-row-${i + 1}" class="search-citation">
<span class="citation-number">[${i + 1}]</span>
${ref.uri
? `<a href="${escapeHtml(ref.uri)}" target="_blank" rel="noopener">${escapeHtml(ref.title || ref.uri)}</a>`
: `<span>${escapeHtml(ref.title || 'Unknown source')}</span>`
}
</div>
`).join('');

const citationsDiv = document.createElement('div');
citationsDiv.className = 'search-citations mt-3';
citationsDiv.innerHTML = '<p class="citations-label">Sources</p>' + citationHtml;
summaryEl.querySelector('.ai-summary').appendChild(citationsDiv);
}
} else {
summaryTxt.innerHTML = '';
summaryEl.style.display = 'none';
}

// Show results
Expand Down
46 changes: 45 additions & 1 deletion assets/scss/_styles_project.scss
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,51 @@
margin-bottom: 0.5rem;
}

p { margin: 0; }
p { margin: 0 0 0.75rem; }

p:last-child {
margin-bottom: 0;
}

ul,
ol {
margin: 0.5rem 0 0.75rem 1.25rem;
}

li {
margin-bottom: 0.35rem;
}

h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0.9rem 0 0.5rem;
font-size: 1rem;
font-weight: 700;
color: #124fa8;
}

code {
color: #0b4aa2;
background: rgba(26, 115, 232, 0.1);
border-radius: 3px;
padding: 0 0.2rem;
}
}

.summary-inline-citation {
margin-left: 0.1rem;
text-decoration: none;
font-weight: 600;
color: #1a73e8;

&:hover,
&:focus {
text-decoration: underline;
}
}

.td-search-hit {
Expand Down
2 changes: 1 addition & 1 deletion layouts/search.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ <h2 class="ms-4">Search Results</h2>
<span class="ai-badge">
<i class="fas fa-robot"></i> AI Summary
</span>
<p id="summary-text" class="mt-2 mb-0"></p>
<div id="summary-text" class="mt-2 mb-0"></div>
</div>
</div>

Expand Down
Loading