M0-M11 狩夜人笔记初始实现:11里程碑+86测试
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
import { create } from 'zustand';
|
||||
|
||||
export interface Tab { id: string; path: string; pinned: boolean; scrollTop: number; }
|
||||
|
||||
interface TabState {
|
||||
tabs: Tab[];
|
||||
activeId: string | null;
|
||||
openTab: (path: string) => void;
|
||||
closeTab: (id: string) => void;
|
||||
setActive: (id: string) => void;
|
||||
togglePin: (id: string) => void;
|
||||
activePath: () => string | null;
|
||||
persist: () => void;
|
||||
restore: () => void;
|
||||
}
|
||||
|
||||
const SESSION_KEY = 'dsh-session';
|
||||
|
||||
export const useTabs = create<TabState>((set, get) => ({
|
||||
tabs: [],
|
||||
activeId: null,
|
||||
|
||||
openTab: (path) => {
|
||||
const existing = get().tabs.find(t => t.path === path);
|
||||
if (existing) { set({ activeId: existing.id }); return; }
|
||||
const id = 'tab-' + Date.now() + '-' + Math.random().toString(36).slice(2, 6);
|
||||
set(s => ({ tabs: [...s.tabs, { id, path, pinned: false, scrollTop: 0 }], activeId: id }));
|
||||
get().persist();
|
||||
},
|
||||
|
||||
closeTab: (id) => {
|
||||
const { tabs, activeId } = get();
|
||||
const idx = tabs.findIndex(t => t.id === id);
|
||||
const remaining = tabs.filter(t => t.id !== id);
|
||||
let newActive = activeId;
|
||||
if (activeId === id) {
|
||||
// 切到相邻(优先未固定的相邻)
|
||||
const neighbor = remaining[idx] ?? remaining[idx - 1] ?? remaining[remaining.length - 1];
|
||||
newActive = neighbor?.id ?? null;
|
||||
}
|
||||
set({ tabs: remaining, activeId: newActive });
|
||||
get().persist();
|
||||
},
|
||||
|
||||
setActive: (id) => { set({ activeId: id }); get().persist(); },
|
||||
|
||||
togglePin: (id) => {
|
||||
set(s => {
|
||||
const tabs = s.tabs.map(t => t.id === id ? { ...t, pinned: !t.pinned } : t);
|
||||
// 固定的排前
|
||||
tabs.sort((a, b) => (a.pinned === b.pinned ? 0 : a.pinned ? -1 : 1));
|
||||
return { tabs };
|
||||
});
|
||||
get().persist();
|
||||
},
|
||||
|
||||
activePath: () => { const { tabs, activeId } = get(); return tabs.find(t => t.id === activeId)?.path ?? null; },
|
||||
|
||||
persist: () => {
|
||||
const { tabs, activeId } = get();
|
||||
try { localStorage.setItem(SESSION_KEY, JSON.stringify({ tabs, activeId })); } catch {}
|
||||
},
|
||||
|
||||
restore: () => {
|
||||
try {
|
||||
const raw = localStorage.getItem(SESSION_KEY);
|
||||
if (!raw) return;
|
||||
const saved = JSON.parse(raw);
|
||||
set({ tabs: saved.tabs ?? [], activeId: saved.activeId ?? null });
|
||||
} catch {}
|
||||
},
|
||||
}));
|
||||
Reference in New Issue
Block a user