Skip to content

Commit 3ad3ed0

Browse files
simonwclaude
andcommitted
Add gistpreview.github.io support to search feature
When hosted on gistpreview.github.io, the search feature now: - Detects the gistpreview hostname - Extracts the gist ID from the URL path - Fetches gist metadata from GitHub API to get the owner - Constructs raw gist URLs for fetching page files This allows search to work correctly when viewing transcripts via gistpreview. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent fb87d60 commit 3ad3ed0

File tree

3 files changed

+147
-3
lines changed

3 files changed

+147
-3
lines changed

src/claude_code_transcripts/templates/search.js

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,42 @@
1515
// Show search box (progressive enhancement)
1616
searchBox.style.display = 'flex';
1717

18+
// Gist preview support - detect if we're on gistpreview.github.io
19+
var isGistPreview = window.location.hostname === 'gistpreview.github.io';
20+
var gistId = null;
21+
var gistOwner = null;
22+
var gistInfoLoaded = false;
23+
24+
if (isGistPreview) {
25+
// Extract gist ID from URL path like /gist-id/index.html or /gist-id/raw/index.html
26+
var pathMatch = window.location.pathname.match(/^\/([a-f0-9]+)/i);
27+
if (pathMatch) {
28+
gistId = pathMatch[1];
29+
}
30+
}
31+
32+
async function loadGistInfo() {
33+
if (!isGistPreview || !gistId || gistInfoLoaded) return;
34+
try {
35+
var response = await fetch('https://api.github.com/gists/' + gistId);
36+
if (response.ok) {
37+
var info = await response.json();
38+
gistOwner = info.owner.login;
39+
gistInfoLoaded = true;
40+
}
41+
} catch (e) {
42+
console.error('Failed to load gist info:', e);
43+
}
44+
}
45+
46+
function getPageUrl(pageFile) {
47+
if (isGistPreview && gistOwner && gistId) {
48+
// Use raw gist URL for fetching
49+
return 'https://gist.githubusercontent.com/' + gistOwner + '/' + gistId + '/raw/' + pageFile;
50+
}
51+
return pageFile;
52+
}
53+
1854
function escapeHtml(text) {
1955
var div = document.createElement('div');
2056
div.textContent = text;
@@ -135,6 +171,16 @@
135171
searchResults.innerHTML = '';
136172
searchStatus.textContent = 'Searching...';
137173

174+
// Load gist info if on gistpreview (needed for constructing URLs)
175+
if (isGistPreview && !gistInfoLoaded) {
176+
searchStatus.textContent = 'Loading gist info...';
177+
await loadGistInfo();
178+
if (!gistOwner) {
179+
searchStatus.textContent = 'Failed to load gist info. Search unavailable.';
180+
return;
181+
}
182+
}
183+
138184
var resultsFound = 0;
139185
var pagesSearched = 0;
140186

@@ -144,14 +190,16 @@
144190
pagesToFetch.push('page-' + String(i).padStart(3, '0') + '.html');
145191
}
146192

193+
searchStatus.textContent = 'Searching...';
194+
147195
// Process pages in batches of 3, but show results immediately as each completes
148196
var batchSize = 3;
149197
for (var i = 0; i < pagesToFetch.length; i += batchSize) {
150198
var batch = pagesToFetch.slice(i, i + batchSize);
151199

152200
// Create promises that process results immediately when each fetch completes
153201
var promises = batch.map(function(pageFile) {
154-
return fetch(pageFile)
202+
return fetch(getPageUrl(pageFile))
155203
.then(function(response) {
156204
if (!response.ok) throw new Error('Failed to fetch');
157205
return response.text();

tests/__snapshots__/test_generate_html/TestGenerateHtml.test_generates_index_html.html

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,42 @@ <h1>Claude Code transcript</h1>
218218
// Show search box (progressive enhancement)
219219
searchBox.style.display = 'flex';
220220

221+
// Gist preview support - detect if we're on gistpreview.github.io
222+
var isGistPreview = window.location.hostname === 'gistpreview.github.io';
223+
var gistId = null;
224+
var gistOwner = null;
225+
var gistInfoLoaded = false;
226+
227+
if (isGistPreview) {
228+
// Extract gist ID from URL path like /gist-id/index.html or /gist-id/raw/index.html
229+
var pathMatch = window.location.pathname.match(/^\/([a-f0-9]+)/i);
230+
if (pathMatch) {
231+
gistId = pathMatch[1];
232+
}
233+
}
234+
235+
async function loadGistInfo() {
236+
if (!isGistPreview || !gistId || gistInfoLoaded) return;
237+
try {
238+
var response = await fetch('https://api.github.com/gists/' + gistId);
239+
if (response.ok) {
240+
var info = await response.json();
241+
gistOwner = info.owner.login;
242+
gistInfoLoaded = true;
243+
}
244+
} catch (e) {
245+
console.error('Failed to load gist info:', e);
246+
}
247+
}
248+
249+
function getPageUrl(pageFile) {
250+
if (isGistPreview && gistOwner && gistId) {
251+
// Use raw gist URL for fetching
252+
return 'https://gist.githubusercontent.com/' + gistOwner + '/' + gistId + '/raw/' + pageFile;
253+
}
254+
return pageFile;
255+
}
256+
221257
function escapeHtml(text) {
222258
var div = document.createElement('div');
223259
div.textContent = text;
@@ -338,6 +374,16 @@ <h1>Claude Code transcript</h1>
338374
searchResults.innerHTML = '';
339375
searchStatus.textContent = 'Searching...';
340376

377+
// Load gist info if on gistpreview (needed for constructing URLs)
378+
if (isGistPreview && !gistInfoLoaded) {
379+
searchStatus.textContent = 'Loading gist info...';
380+
await loadGistInfo();
381+
if (!gistOwner) {
382+
searchStatus.textContent = 'Failed to load gist info. Search unavailable.';
383+
return;
384+
}
385+
}
386+
341387
var resultsFound = 0;
342388
var pagesSearched = 0;
343389

@@ -347,14 +393,16 @@ <h1>Claude Code transcript</h1>
347393
pagesToFetch.push('page-' + String(i).padStart(3, '0') + '.html');
348394
}
349395

396+
searchStatus.textContent = 'Searching...';
397+
350398
// Process pages in batches of 3, but show results immediately as each completes
351399
var batchSize = 3;
352400
for (var i = 0; i < pagesToFetch.length; i += batchSize) {
353401
var batch = pagesToFetch.slice(i, i + batchSize);
354402

355403
// Create promises that process results immediately when each fetch completes
356404
var promises = batch.map(function(pageFile) {
357-
return fetch(pageFile)
405+
return fetch(getPageUrl(pageFile))
358406
.then(function(response) {
359407
if (!response.ok) throw new Error('Failed to fetch');
360408
return response.text();

tests/__snapshots__/test_generate_html/TestParseSessionFile.test_jsonl_generates_html.html

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,42 @@ <h1>Claude Code transcript</h1>
209209
// Show search box (progressive enhancement)
210210
searchBox.style.display = 'flex';
211211

212+
// Gist preview support - detect if we're on gistpreview.github.io
213+
var isGistPreview = window.location.hostname === 'gistpreview.github.io';
214+
var gistId = null;
215+
var gistOwner = null;
216+
var gistInfoLoaded = false;
217+
218+
if (isGistPreview) {
219+
// Extract gist ID from URL path like /gist-id/index.html or /gist-id/raw/index.html
220+
var pathMatch = window.location.pathname.match(/^\/([a-f0-9]+)/i);
221+
if (pathMatch) {
222+
gistId = pathMatch[1];
223+
}
224+
}
225+
226+
async function loadGistInfo() {
227+
if (!isGistPreview || !gistId || gistInfoLoaded) return;
228+
try {
229+
var response = await fetch('https://api.github.com/gists/' + gistId);
230+
if (response.ok) {
231+
var info = await response.json();
232+
gistOwner = info.owner.login;
233+
gistInfoLoaded = true;
234+
}
235+
} catch (e) {
236+
console.error('Failed to load gist info:', e);
237+
}
238+
}
239+
240+
function getPageUrl(pageFile) {
241+
if (isGistPreview && gistOwner && gistId) {
242+
// Use raw gist URL for fetching
243+
return 'https://gist.githubusercontent.com/' + gistOwner + '/' + gistId + '/raw/' + pageFile;
244+
}
245+
return pageFile;
246+
}
247+
212248
function escapeHtml(text) {
213249
var div = document.createElement('div');
214250
div.textContent = text;
@@ -329,6 +365,16 @@ <h1>Claude Code transcript</h1>
329365
searchResults.innerHTML = '';
330366
searchStatus.textContent = 'Searching...';
331367

368+
// Load gist info if on gistpreview (needed for constructing URLs)
369+
if (isGistPreview && !gistInfoLoaded) {
370+
searchStatus.textContent = 'Loading gist info...';
371+
await loadGistInfo();
372+
if (!gistOwner) {
373+
searchStatus.textContent = 'Failed to load gist info. Search unavailable.';
374+
return;
375+
}
376+
}
377+
332378
var resultsFound = 0;
333379
var pagesSearched = 0;
334380

@@ -338,14 +384,16 @@ <h1>Claude Code transcript</h1>
338384
pagesToFetch.push('page-' + String(i).padStart(3, '0') + '.html');
339385
}
340386

387+
searchStatus.textContent = 'Searching...';
388+
341389
// Process pages in batches of 3, but show results immediately as each completes
342390
var batchSize = 3;
343391
for (var i = 0; i < pagesToFetch.length; i += batchSize) {
344392
var batch = pagesToFetch.slice(i, i + batchSize);
345393

346394
// Create promises that process results immediately when each fetch completes
347395
var promises = batch.map(function(pageFile) {
348-
return fetch(pageFile)
396+
return fetch(getPageUrl(pageFile))
349397
.then(function(response) {
350398
if (!response.ok) throw new Error('Failed to fetch');
351399
return response.text();

0 commit comments

Comments
 (0)