feat(admin-ui): add tags view state

This commit is contained in:
duanshuwen committed 2026-08-26 21:06:22 +08:00
1 parent 3c8c6490fd
commit 96612607e5
3 files changed
+541

No files matched your search

+166
View File
@@ -0,0 +1,166 @@
import { ref } from "vue";
import { defineStore } from "pinia";
import {
addVisitedTag,
closeAllTags as closeAllVisitedTags,
closeTag,
closeTagsToLeft,
closeTagsToRight,
getTagsViewsKey,
HOME_TAG,
isVisitedTag,
normalizeVisitedTag,
type VisitedTag,
} from "../lib/tags";
export type TagsPersistenceOptions = {
tagsView: boolean;
tagsViewPersist: boolean;
};
function getStorage(): Storage | null {
try {
return typeof window === "undefined" ? null : window.localStorage;
} catch {
return null;
}
}
function readPersistedViews(storageKey: string): VisitedTag[] {
try {
const serialized = getStorage()?.getItem(storageKey);
if (serialized === null || serialized === undefined) return [HOME_TAG];
const parsed: unknown = JSON.parse(serialized);
if (!Array.isArray(parsed)) return [HOME_TAG];
const views = parsed
.filter(isVisitedTag)
.map(normalizeVisitedTag)
.filter((view): view is VisitedTag => view !== null)
.reduce<VisitedTag[]>((result, view) => addVisitedTag(result, view), []);
return [HOME_TAG, ...views.filter((view) => view.fullPath !== HOME_TAG.fullPath && !view.affix)];
} catch {
return [HOME_TAG];
}
}
export const useTagsStore = defineStore("tags", () => {
const visitedViews = ref<VisitedTag[]>([{ ...HOME_TAG }]);
const activePath = ref(HOME_TAG.fullPath);
const tagsView = ref(false);
const tagsViewPersist = ref(false);
let persistenceScope: string | null = null;
function storageKey() {
return getTagsViewsKey(persistenceScope);
}
function persist() {
if (!tagsView.value || !tagsViewPersist.value) return;
try {
getStorage()?.setItem(storageKey(), JSON.stringify(visitedViews.value));
} catch {
// Storage may be unavailable or disabled in the current browser context.
}
}
function setPersistenceEnabled(options: TagsPersistenceOptions) {
tagsView.value = options.tagsView;
tagsViewPersist.value = options.tagsViewPersist;
}
function setPersistenceScope(scope: string | null) {
persistenceScope = scope;
}
function addView(view: VisitedTag) {
visitedViews.value = addVisitedTag(visitedViews.value, view);
activePath.value = view.fullPath;
persist();
}
function updateView(view: VisitedTag) {
const index = visitedViews.value.findIndex((item) => item.fullPath === view.fullPath);
if (index < 0) {
addView(view);
return;
}
visitedViews.value = visitedViews.value.map((item, itemIndex) => itemIndex === index ? { ...view } : { ...item });
activePath.value = view.fullPath;
persist();
}
function closeSelectedTag(fullPath = activePath.value): string {
const result = closeTag(visitedViews.value, fullPath, activePath.value);
visitedViews.value = result.views;
activePath.value = result.activePath;
persist();
return result.activePath;
}
function closeOthersTags(fullPath = activePath.value) {
visitedViews.value = visitedViews.value.filter((view) => view.affix || view.fullPath === fullPath).map((view) => ({ ...view }));
activePath.value = visitedViews.value.some((view) => view.fullPath === fullPath) ? fullPath : HOME_TAG.fullPath;
persist();
}
function closeLeftTags(fullPath = activePath.value) {
visitedViews.value = closeTagsToLeft(visitedViews.value, fullPath);
if (!visitedViews.value.some((view) => view.fullPath === activePath.value)) {
activePath.value = visitedViews.value.some((view) => view.fullPath === fullPath)
? fullPath
: HOME_TAG.fullPath;
}
persist();
}
function closeRightTags(fullPath = activePath.value) {
visitedViews.value = closeTagsToRight(visitedViews.value, fullPath);
if (!visitedViews.value.some((view) => view.fullPath === activePath.value)) {
activePath.value = visitedViews.value.some((view) => view.fullPath === fullPath)
? fullPath
: HOME_TAG.fullPath;
}
persist();
}
function closeAllTags() {
visitedViews.value = closeAllVisitedTags(visitedViews.value);
activePath.value = HOME_TAG.fullPath;
persist();
}
function refreshSelectedTag(): VisitedTag {
const selected = visitedViews.value.find((view) => view.fullPath === activePath.value);
if (selected) return selected;
const fallback = visitedViews.value.find((view) => view.fullPath === HOME_TAG.fullPath) ?? HOME_TAG;
activePath.value = fallback.fullPath;
return fallback;
}
function restorePersistedViews() {
if (!tagsView.value || !tagsViewPersist.value) return;
visitedViews.value = readPersistedViews(storageKey());
activePath.value = visitedViews.value.some((view) => view.fullPath === activePath.value)
? activePath.value
: HOME_TAG.fullPath;
}
return {
visitedViews,
activePath,
tagsView,
tagsViewPersist,
setPersistenceEnabled,
setPersistenceScope,
addView,
updateView,
closeSelectedTag,
closeOthersTags,
closeLeftTags,
closeRightTags,
closeAllTags,
refreshSelectedTag,
restorePersistedViews,
};
});