forked from EduCraft/curriculum-project-hub
80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
import { writable, get } from "svelte/store";
|
|
import type { BreadcrumbEntry, NodeDetail } from "./types.js";
|
|
|
|
const STORAGE_KEY = "filelib.browser";
|
|
|
|
interface PersistedState {
|
|
expanded: string[];
|
|
currentNodeId: string | null;
|
|
tab: string | null;
|
|
selectedFilePath: string | null;
|
|
}
|
|
|
|
function loadPersisted(): PersistedState {
|
|
try {
|
|
const raw = sessionStorage.getItem(STORAGE_KEY);
|
|
if (raw) return JSON.parse(raw) as PersistedState;
|
|
} catch { /* ignore */ }
|
|
return { expanded: [], currentNodeId: null, tab: null, selectedFilePath: null };
|
|
}
|
|
|
|
function savePersisted(): void {
|
|
try {
|
|
const state: PersistedState = {
|
|
expanded: [...get(expanded)],
|
|
currentNodeId: get(currentNode)?.id ?? null,
|
|
tab: get(activeTab),
|
|
selectedFilePath: get(selectedFilePath),
|
|
};
|
|
sessionStorage.setItem(STORAGE_KEY, JSON.stringify(state));
|
|
} catch { /* sessionStorage 不可用时静默忽略 */ }
|
|
}
|
|
|
|
const persisted = loadPersisted();
|
|
|
|
/** 树展开集合 / 当前选中节点 / 面包屑 / 树刷新计数。 */
|
|
export const expanded = writable<Set<string>>(new Set(persisted.expanded));
|
|
export const currentNode = writable<NodeDetail | null>(null);
|
|
export const breadcrumb = writable<BreadcrumbEntry[]>([]);
|
|
export const treeVersion = writable(0);
|
|
|
|
/** 刷新后需要恢复的节点 ID;LibraryView onMount 消费后清空。 */
|
|
export const restoreNodeId = persisted.currentNodeId;
|
|
/** 刷新后需要恢复的 tab;NodeDetailPanel 消费。 */
|
|
export const restoreTab = persisted.tab;
|
|
|
|
/** 右侧预览栏:当前选中文件路径(项目内);切换节点时清空。 */
|
|
export const selectedFilePath = writable<string | null>(persisted.selectedFilePath);
|
|
/** 文件列表刷新计数(编辑器保存/删除后 bump,列表随之重载)。 */
|
|
export const filesVersion = writable(0);
|
|
|
|
/** 当前激活的 tab(由 NodeDetailPanel 写入,持久化用)。 */
|
|
export const activeTab = writable<string | null>(persisted.tab);
|
|
|
|
// 订阅需要持久化的 store,变化时写 sessionStorage。
|
|
expanded.subscribe(() => savePersisted());
|
|
currentNode.subscribe(() => savePersisted());
|
|
selectedFilePath.subscribe(() => savePersisted());
|
|
activeTab.subscribe(() => savePersisted());
|
|
|
|
export function bumpTree(): void {
|
|
treeVersion.update((v) => v + 1);
|
|
}
|
|
|
|
export function bumpFiles(): void {
|
|
filesVersion.update((v) => v + 1);
|
|
}
|
|
|
|
export function clearSelectedFile(): void {
|
|
selectedFilePath.set(null);
|
|
}
|
|
|
|
export function toggleExpanded(id: string): void {
|
|
expanded.update((set) => {
|
|
const next = new Set(set);
|
|
if (next.has(id)) next.delete(id);
|
|
else next.add(id);
|
|
return next;
|
|
});
|
|
}
|