Skip to content

Commit 018a859

Browse files
authored
Merge pull request #59 from kojibai/codex/enable-auto-refresh-for-sigilexplorer
Ensure Sigil Explorer syncs immediately on open and import
2 parents 1114835 + efae3a6 commit 018a859

3 files changed

Lines changed: 36 additions & 4 deletions

File tree

src/App.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
} from "./utils/kai_pulse";
3535
import { fmt2, formatPulse, modPos, readNum } from "./utils/kaiTimeDisplay";
3636
import { usePerfMode } from "./hooks/usePerfMode";
37+
import { SIGIL_EXPLORER_OPEN_EVENT } from "./constants/sigilExplorer";
3738

3839
import SovereignDeclarations from "./components/SovereignDeclarations";
3940
import { DEFAULT_APP_VERSION, SW_VERSION_EVENT } from "./version";
@@ -606,6 +607,11 @@ function ExplorerPopover({
606607
return () => document.removeEventListener("keydown", onKey);
607608
}, [open, onClose, isClient]);
608609

610+
useEffect(() => {
611+
if (!open || !isClient) return;
612+
window.dispatchEvent(new CustomEvent(SIGIL_EXPLORER_OPEN_EVENT));
613+
}, [open, isClient]);
614+
609615
const closeBtnRef = useRef<HTMLButtonElement | null>(null);
610616
useEffect(() => {
611617
if (!open) return;

src/components/SigilExplorer.tsx

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ import {
5151
type UsernameClaimRegistry,
5252
} from "../utils/usernameClaimRegistry";
5353
import { USERNAME_CLAIM_KIND, type UsernameClaimPayload } from "../types/usernameClaim";
54+
import { SIGIL_EXPLORER_OPEN_EVENT } from "../constants/sigilExplorer";
5455
import "./SigilExplorer.css";
5556

5657
/* ─────────────────────────────────────────────────────────────────────
@@ -119,6 +120,8 @@ type ApiInhaleResponse = {
119120
urls?: string[] | null;
120121
};
121122

123+
type SyncReason = "open" | "pulse" | "visible" | "focus" | "online" | "import";
124+
122125
/* ─────────────────────────────────────────────────────────────────────
123126
* Chakra tint system (per node)
124127
* ───────────────────────────────────────────────────────────────────── */
@@ -2314,6 +2317,7 @@ const SigilExplorer: React.FC = () => {
23142317
ownerHint?: string | null;
23152318
}>
23162319
>([]);
2320+
const syncNowRef = useRef<((reason: SyncReason) => Promise<void>) | null>(null);
23172321

23182322
const markInteracting = useCallback((ms: number) => {
23192323
const until = nowMs() + ms;
@@ -2813,7 +2817,7 @@ const SigilExplorer: React.FC = () => {
28132817
// ── BREATH LOOP: inhale (push) ⇄ exhale (pull)
28142818
const ac = new AbortController();
28152819

2816-
const syncOnce = async (reason: "open" | "pulse" | "visible" | "focus" | "online") => {
2820+
const syncOnce = async (reason: SyncReason) => {
28172821
if (unmounted.current) return;
28182822
if (!isOnline()) return;
28192823
if (syncInFlightRef.current) return;
@@ -2822,7 +2826,7 @@ const SigilExplorer: React.FC = () => {
28222826
if (scrollingRef.current) return;
28232827

28242828
// ✅ mobile stability: avoid heavy remote import while in interaction window
2825-
if (nowMs() < interactUntilRef.current && reason === "pulse") return;
2829+
if (nowMs() < interactUntilRef.current && (reason === "pulse" || reason === "import")) return;
28262830

28272831
syncInFlightRef.current = true;
28282832

@@ -2874,7 +2878,7 @@ const SigilExplorer: React.FC = () => {
28742878
const sealNow = remoteSealRef.current;
28752879
const shouldFullSeed =
28762880
reason === "open" ||
2877-
((reason === "visible" || reason === "focus" || reason === "online") &&
2881+
((reason === "visible" || reason === "focus" || reason === "online" || reason === "import") &&
28782882
sealNow !== lastFullSeedSealRef.current);
28792883

28802884
if (shouldFullSeed) {
@@ -2887,6 +2891,8 @@ const SigilExplorer: React.FC = () => {
28872891
}
28882892
};
28892893

2894+
syncNowRef.current = syncOnce;
2895+
28902896
// OPEN: do a full inhale seed immediately (guarantees repopulation power)
28912897
seedInhaleFromRegistry();
28922898
void syncOnce("open");
@@ -2963,11 +2969,28 @@ window.addEventListener("online", onOnline);
29632969
if (breathTimer != null) window.clearTimeout(breathTimer);
29642970
breathTimer = null;
29652971
ac.abort();
2972+
syncNowRef.current = null;
29662973
unmounted.current = true;
29672974
};
29682975
// eslint-disable-next-line react-hooks/exhaustive-deps
29692976
}, [bump, markInteracting, scheduleUiFlush, setLastAddedSafe]);
29702977

2978+
const requestImmediateSync = useCallback(
2979+
(reason: SyncReason) => {
2980+
const fn = syncNowRef.current;
2981+
if (fn) void fn(reason);
2982+
},
2983+
[],
2984+
);
2985+
2986+
useEffect(() => {
2987+
if (!hasWindow) return;
2988+
2989+
const onOpen = () => requestImmediateSync("visible");
2990+
window.addEventListener(SIGIL_EXPLORER_OPEN_EVENT, onOpen);
2991+
return () => window.removeEventListener(SIGIL_EXPLORER_OPEN_EVENT, onOpen);
2992+
}, [requestImmediateSync]);
2993+
29712994
const forest = useMemo(() => buildForest(memoryRegistry), [registryRev]);
29722995

29732996
const phiTotalsByPulse = useMemo((): ReadonlyMap<number, number> => {
@@ -3175,11 +3198,13 @@ breathTimer = null;
31753198
} else if (urls.length > 0) {
31763199
forceInhaleUrls(urls);
31773200
}
3201+
3202+
requestImmediateSync("import");
31783203
} catch {
31793204
// ignore
31803205
}
31813206
},
3182-
[bump, markInteracting, setLastAddedSafe],
3207+
[bump, markInteracting, requestImmediateSync, setLastAddedSafe],
31833208
);
31843209

31853210
const handleExport = useCallback(() => {

src/constants/sigilExplorer.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const SIGIL_EXPLORER_OPEN_EVENT = "sigil:explorer:open";

0 commit comments

Comments
 (0)