feat: implement granular section visibility control
Introduce the ability to reveal specific sections of a document rather than entire files. This includes: - Updating `revealedPaths` to map normalized file paths to sets of revealed section slugs. - Adding `isPathRevealed` to handle visibility logic for connected clients and GMs. - Enhancing `extractHeadings` to calculate `startLine` and `endLine` for each TOC node to support precise section identification.
This commit is contained in:
@@ -29,10 +29,12 @@ export interface JournalStreamState {
|
||||
/** Last sequence number per sender */
|
||||
senderSeq: Record<string, number>;
|
||||
/**
|
||||
* Paths revealed by link messages.
|
||||
* Paths and sections revealed by link messages.
|
||||
* Key: normalized path (no .md). Value: set of revealed section slugs.
|
||||
* An empty set means the whole article is revealed.
|
||||
* Populated during hydration and live receipt via the type's reducer.
|
||||
*/
|
||||
revealedPaths: Set<string>;
|
||||
revealedPaths: Record<string, Set<string>>;
|
||||
/** MQTT connection status */
|
||||
connected: boolean;
|
||||
/** Granular connection state for UI indicators */
|
||||
@@ -101,7 +103,7 @@ const [state, setState] = createStore<JournalStreamState>({
|
||||
sessionName: null,
|
||||
messages: [],
|
||||
senderSeq: {},
|
||||
revealedPaths: new Set(),
|
||||
revealedPaths: {},
|
||||
connected: false,
|
||||
connectionStatus: "disconnected",
|
||||
connectionError: null,
|
||||
@@ -604,6 +606,32 @@ export function visibleMessages(): StreamMessage[] {
|
||||
return state.messages.filter((m) => !m.reverted);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether a path (and optionally section) is revealed.
|
||||
* GM and disconnected clients see everything.
|
||||
* Non-GM connected clients only see explicitly revealed content.
|
||||
*/
|
||||
export function isPathRevealed(path: string, section?: string): boolean {
|
||||
if (!state.connected) return true;
|
||||
if (state.myRole === "gm") return true;
|
||||
|
||||
const normalized = normalizePath(path);
|
||||
const revealed = state.revealedPaths[normalized];
|
||||
if (!revealed) return false;
|
||||
|
||||
// Whole article revealed (empty set)
|
||||
if (revealed.size === 0) return true;
|
||||
// Section-specific check
|
||||
if (section) return revealed.has(section);
|
||||
// No section asked — at least some sections are revealed, article is partially visible
|
||||
return revealed.size > 0;
|
||||
}
|
||||
|
||||
/** Normalize a path for lookup: strip .md, leading ./ or / */
|
||||
function normalizePath(p: string): string {
|
||||
return p.replace(/^\.?\//, "").replace(/\.md$/, "");
|
||||
}
|
||||
|
||||
export function useJournalStream() {
|
||||
return state;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user