Skip to content

Commit b34a95f

Browse files
committed
Persist overlay reader state in URL
1 parent fbce581 commit b34a95f

1 file changed

Lines changed: 43 additions & 16 deletions

File tree

apps/frontend/src/App.tsx

Lines changed: 43 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ type UrlState = {
9898
workId: string | null | undefined;
9999
readerPath: string | null | undefined;
100100
chunkId: string | null | undefined;
101+
passageId: string | null | undefined;
101102
profileUserId: string | null | undefined;
102103
runId: string | null | undefined;
103104
adminSection: "runs" | "users" | "analytics" | "incidents" | "logs";
@@ -394,6 +395,7 @@ function readUrlState(): UrlState {
394395
workId: undefined,
395396
readerPath: undefined,
396397
chunkId: undefined,
398+
passageId: undefined,
397399
profileUserId: undefined,
398400
runId: undefined,
399401
adminSection: "runs",
@@ -421,6 +423,7 @@ function readUrlState(): UrlState {
421423
workId: pathnameMatch ? decodeURIComponent(pathnameMatch[1]) : params.has("work") ? params.get("work") || null : undefined,
422424
readerPath: params.has("reader") ? params.get("reader") || null : undefined,
423425
chunkId: params.has("chunk") ? params.get("chunk") || null : undefined,
426+
passageId: window.location.hash ? decodeURIComponent(window.location.hash.replace(/^#/, "").trim()) || null : undefined,
424427
profileUserId: profilePathMatch ? decodeURIComponent(profilePathMatch[1]) : params.has("profile") ? params.get("profile") || null : undefined,
425428
runId: params.has("run") ? params.get("run") || null : undefined,
426429
adminSection:
@@ -487,19 +490,24 @@ function writeUrlState(next: UrlState, mode: UrlWriteMode = "replace") {
487490
} else {
488491
url.searchParams.delete("session");
489492
}
490-
if (next.view === "book" && next.readerPath) {
493+
if (next.workId && next.readerPath) {
491494
url.searchParams.set("reader", next.readerPath);
492495
} else {
493496
url.searchParams.delete("reader");
494497
}
495-
if (next.view === "book" && next.chunkId) {
498+
if (next.workId && next.chunkId) {
496499
url.searchParams.set("chunk", next.chunkId);
497500
} else {
498501
url.searchParams.delete("chunk");
499502
}
500503
if (next.view !== "book" && next.workId) {
501504
url.searchParams.set("work", next.workId);
502505
}
506+
if (next.workId && next.passageId) {
507+
url.hash = next.passageId;
508+
} else {
509+
url.hash = "";
510+
}
503511
if (next.debugEnabled) {
504512
url.searchParams.set("debug", "true");
505513
} else {
@@ -3505,7 +3513,7 @@ export default function App() {
35053513
const [activeReaderPath, setActiveReaderPath] = useState<string | null | undefined>(initialUrlState.readerPath);
35063514
const [activeChunkId, setActiveChunkId] = useState<string | null | undefined>(initialUrlState.chunkId);
35073515
const [pendingCitation, setPendingCitation] = useState<Citation | null>(null);
3508-
const [activePassageId, setActivePassageId] = useState<string | null>(null);
3516+
const [activePassageId, setActivePassageId] = useState<string | null>(initialUrlState.passageId ?? null);
35093517
const [highlightedPassageExcerpt, setHighlightedPassageExcerpt] = useState<string | null>(null);
35103518
const bookReaderFrameRef = useRef<HTMLIFrameElement | null>(null);
35113519
const lastReaderFrameHrefRef = useRef<string | null>(null);
@@ -3860,6 +3868,8 @@ export default function App() {
38603868
setActiveWorkId(next.workId);
38613869
setActiveReaderPath(next.readerPath);
38623870
setActiveChunkId(next.chunkId);
3871+
setActivePassageId(next.passageId ?? null);
3872+
setHighlightedPassageExcerpt(null);
38633873
setActiveProfileUserId(next.profileUserId);
38643874
setSelectedAdminRunId(next.runId);
38653875
setAdminSection(next.adminSection);
@@ -3887,6 +3897,7 @@ export default function App() {
38873897
workId: activeWorkId,
38883898
readerPath: activeReaderPath,
38893899
chunkId: activeChunkId,
3900+
passageId: activePassageId,
38903901
profileUserId: activeProfileUserId,
38913902
runId: selectedAdminRunId,
38923903
adminSection,
@@ -3895,7 +3906,7 @@ export default function App() {
38953906
exploreRandomSeed,
38963907
}, pendingUrlWriteModeRef.current);
38973908
pendingUrlWriteModeRef.current = "replace";
3898-
}, [activeView, selectedSessionId, activeWorkId, activeReaderPath, activeChunkId, activeProfileUserId, selectedAdminRunId, adminSection, debugEnabled, exploreAppliedFilters, exploreRandomSeed]);
3909+
}, [activeView, selectedSessionId, activeWorkId, activeReaderPath, activeChunkId, activePassageId, activeProfileUserId, selectedAdminRunId, adminSection, debugEnabled, exploreAppliedFilters, exploreRandomSeed]);
38993910

39003911
useEffect(() => {
39013912
if (typeof window === "undefined") {
@@ -4319,14 +4330,12 @@ export default function App() {
43194330

43204331
const match = findPassageForCitation(readerPassages, pendingCitation);
43214332
if (match) {
4333+
pendingUrlWriteModeRef.current = "replace";
43224334
setActivePassageId(match.passageId);
43234335
setHighlightedPassageExcerpt(match.highlight);
43244336
if (activeChunkId) {
43254337
setActiveChunkId(null);
43264338
}
4327-
const url = new URL(window.location.href);
4328-
url.hash = match.passageId;
4329-
window.history.replaceState({}, "", `${url.pathname}${url.search}${url.hash}`);
43304339
}
43314340
setPendingCitation(null);
43324341
}, [activeWork, pendingCitation, readerPassages, activeChunkId]);
@@ -4360,6 +4369,7 @@ export default function App() {
43604369
workId: context.workId,
43614370
readerPath: normalized,
43624371
chunkId: context.chunkId,
4372+
passageId: activePassageId,
43634373
profileUserId: context.profileUserId,
43644374
runId: context.runId,
43654375
adminSection: context.adminSection,
@@ -4370,7 +4380,7 @@ export default function App() {
43704380

43714381
window.addEventListener("message", handleReaderLocation);
43724382
return () => window.removeEventListener("message", handleReaderLocation);
4373-
}, []);
4383+
}, [activePassageId]);
43744384

43754385
useEffect(() => {
43764386
if (!activeWorkId) {
@@ -5642,6 +5652,12 @@ export default function App() {
56425652
setRunArtifacts([]);
56435653
setRecoveredActiveRunId(null);
56445654
setLoadError(null);
5655+
setActiveWorkId(null);
5656+
setActiveReaderPath(null);
5657+
setActiveChunkId(null);
5658+
setActivePassageId(null);
5659+
setHighlightedPassageExcerpt(null);
5660+
setPendingCitation(null);
56455661
setActiveView("assistant");
56465662
}
56475663

@@ -5656,6 +5672,8 @@ export default function App() {
56565672
setRunArtifacts([]);
56575673
setRecoveredActiveRunId(null);
56585674
setLoadError(null);
5675+
setActiveReaderPath(null);
5676+
setActiveChunkId(null);
56595677
setHighlightedPassageExcerpt(null);
56605678
setActiveView("book");
56615679
}
@@ -5707,6 +5725,10 @@ export default function App() {
57075725
setMobileNavOpen(false);
57085726
if (view !== "book") {
57095727
setActiveWorkId(null);
5728+
setActiveReaderPath(null);
5729+
setActiveChunkId(null);
5730+
setActivePassageId(null);
5731+
setHighlightedPassageExcerpt(null);
57105732
setPendingCitation(null);
57115733
}
57125734
if (view !== "profile") {
@@ -5765,6 +5787,9 @@ export default function App() {
57655787
setMobileNavOpen(false);
57665788
setPendingCitation(null);
57675789
setActiveReaderPath(null);
5790+
setActiveChunkId(null);
5791+
setActivePassageId(null);
5792+
setHighlightedPassageExcerpt(null);
57685793
setActiveProfileUserId(null);
57695794
setActiveWorkId(workId);
57705795
if (activeView === "explore") {
@@ -5780,6 +5805,9 @@ export default function App() {
57805805
pendingUrlWriteModeRef.current = "push";
57815806
setPendingCitation(null);
57825807
setActiveReaderPath(null);
5808+
setActiveChunkId(null);
5809+
setActivePassageId(null);
5810+
setHighlightedPassageExcerpt(null);
57835811
setActiveWorkId(null);
57845812
}
57855813

@@ -5797,6 +5825,8 @@ export default function App() {
57975825
setMobileNavOpen(false);
57985826
setPendingCitation(citation);
57995827
setActiveReaderPath(null);
5828+
setActivePassageId(null);
5829+
setHighlightedPassageExcerpt(null);
58005830
setActiveProfileUserId(null);
58015831
setActiveWorkId(citation.workId);
58025832
setActiveView("book");
@@ -5806,6 +5836,10 @@ export default function App() {
58065836
pendingUrlWriteModeRef.current = "push";
58075837
setMobileNavOpen(false);
58085838
setActiveWorkId(null);
5839+
setActiveReaderPath(null);
5840+
setActiveChunkId(null);
5841+
setActivePassageId(null);
5842+
setHighlightedPassageExcerpt(null);
58095843
setPendingCitation(null);
58105844
setActiveProfileUserId(userId ?? currentUserId ?? null);
58115845
setActiveView("profile");
@@ -5842,16 +5876,9 @@ export default function App() {
58425876
highlighted: Boolean(highlight),
58435877
});
58445878
}
5879+
pendingUrlWriteModeRef.current = replaceHistory ? "replace" : "push";
58455880
setActivePassageId(passageId);
58465881
setHighlightedPassageExcerpt(highlight);
5847-
const url = new URL(window.location.href);
5848-
url.hash = passageId;
5849-
const nextUrl = `${url.pathname}${url.search}${url.hash}`;
5850-
if (replaceHistory) {
5851-
window.history.replaceState({}, "", nextUrl);
5852-
} else {
5853-
window.history.pushState({}, "", nextUrl);
5854-
}
58555882
}
58565883

58575884
function renderAssistantSurface(props: {

0 commit comments

Comments
 (0)