b37f4363eb
Implement concrete Pinia stores for app UI and domain data instead of placeholder re-exports, including seeded student records and snackbar state. Refresh README guidance for components, plugins, and services to document the current project structure, data flow, and usage conventions.feat(stores): add Pinia domain stores and update docs Implement concrete Pinia stores for app UI and domain data instead of placeholder re-exports, including seeded student records and snackbar state. Refresh README guidance for components, plugins, and services to document the current project structure, data flow, and usage conventions.
148 lines
3.8 KiB
TypeScript
148 lines
3.8 KiB
TypeScript
import type { LayoutMenuItem } from './menu'
|
|
import { defineStore } from 'pinia'
|
|
import { computed, ref, watch } from 'vue'
|
|
|
|
export interface FavoriteItem {
|
|
title: string
|
|
path: string
|
|
icon?: string
|
|
}
|
|
|
|
const storageKey = 'sk_playground_user_favorites'
|
|
const favoritesBarStorageKey = 'sk_admin_favorites_bar_visible'
|
|
const breadcrumbBarStorageKey = 'sk_admin_breadcrumb_bar_visible'
|
|
|
|
function readFavorites(): FavoriteItem[] {
|
|
if (typeof window === 'undefined') return []
|
|
try {
|
|
const raw = window.localStorage.getItem(storageKey)
|
|
if (!raw) return []
|
|
const parsed = JSON.parse(raw)
|
|
return Array.isArray(parsed) ? (parsed as FavoriteItem[]) : []
|
|
} catch {
|
|
return []
|
|
}
|
|
}
|
|
|
|
function writeFavorites(items: FavoriteItem[]) {
|
|
if (typeof window === 'undefined') return
|
|
try {
|
|
window.localStorage.setItem(storageKey, JSON.stringify(items))
|
|
} catch {
|
|
return
|
|
}
|
|
}
|
|
|
|
export const useFavoritesStore = defineStore('favorites', () => {
|
|
const items = ref<FavoriteItem[]>(readFavorites())
|
|
const favoritesBarVisible = ref(true)
|
|
const breadcrumbBarVisible = ref(true)
|
|
|
|
const loadFavoritesBarVisible = () => {
|
|
if (typeof window === 'undefined') return
|
|
const stored = window.localStorage.getItem(favoritesBarStorageKey)
|
|
if (stored === null) return
|
|
favoritesBarVisible.value = stored === '1'
|
|
}
|
|
|
|
const persistFavoritesBarVisible = () => {
|
|
if (typeof window === 'undefined') return
|
|
window.localStorage.setItem(favoritesBarStorageKey, favoritesBarVisible.value ? '1' : '0')
|
|
}
|
|
|
|
const loadBreadcrumbBarVisible = () => {
|
|
if (typeof window === 'undefined') return
|
|
const stored = window.localStorage.getItem(breadcrumbBarStorageKey)
|
|
if (stored === null) return
|
|
breadcrumbBarVisible.value = stored === '1'
|
|
}
|
|
|
|
const persistBreadcrumbBarVisible = () => {
|
|
if (typeof window === 'undefined') return
|
|
window.localStorage.setItem(breadcrumbBarStorageKey, breadcrumbBarVisible.value ? '1' : '0')
|
|
}
|
|
|
|
const add = (item: FavoriteItem) => {
|
|
if (!item?.path) return
|
|
if (items.value.some((x) => x.path === item.path)) return
|
|
items.value = [...items.value, item]
|
|
}
|
|
|
|
const remove = (path: string) => {
|
|
if (!path) return
|
|
items.value = items.value.filter((x) => x.path !== path)
|
|
}
|
|
|
|
const toggle = (item: FavoriteItem) => {
|
|
if (!item?.path) return
|
|
const exists = items.value.some((x) => x.path === item.path)
|
|
if (exists) remove(item.path)
|
|
else add(item)
|
|
}
|
|
|
|
const isFavorite = (path: string) => {
|
|
if (!path) return false
|
|
return items.value.some((x) => x.path === path)
|
|
}
|
|
|
|
const layoutItems = computed<LayoutMenuItem[]>(() =>
|
|
items.value.map((item) => ({
|
|
title: item.title,
|
|
path: item.path,
|
|
icon: item.icon,
|
|
}))
|
|
)
|
|
|
|
watch(
|
|
items,
|
|
(val) => {
|
|
writeFavorites(val)
|
|
},
|
|
{ deep: true }
|
|
)
|
|
|
|
const setFavoritesBarVisible = (value: boolean) => {
|
|
favoritesBarVisible.value = value
|
|
persistFavoritesBarVisible()
|
|
}
|
|
|
|
const toggleFavoritesBarVisible = (nextValue?: boolean) => {
|
|
if (typeof nextValue === 'boolean') {
|
|
setFavoritesBarVisible(nextValue)
|
|
return
|
|
}
|
|
setFavoritesBarVisible(!favoritesBarVisible.value)
|
|
}
|
|
|
|
loadFavoritesBarVisible()
|
|
loadBreadcrumbBarVisible()
|
|
|
|
const setBreadcrumbBarVisible = (value: boolean) => {
|
|
breadcrumbBarVisible.value = value
|
|
persistBreadcrumbBarVisible()
|
|
}
|
|
|
|
const toggleBreadcrumbBarVisible = (nextValue?: boolean) => {
|
|
if (typeof nextValue === 'boolean') {
|
|
setBreadcrumbBarVisible(nextValue)
|
|
return
|
|
}
|
|
setBreadcrumbBarVisible(!breadcrumbBarVisible.value)
|
|
}
|
|
|
|
return {
|
|
items,
|
|
layoutItems,
|
|
add,
|
|
remove,
|
|
toggle,
|
|
isFavorite,
|
|
favoritesBarVisible,
|
|
setFavoritesBarVisible,
|
|
toggleFavoritesBarVisible,
|
|
breadcrumbBarVisible,
|
|
setBreadcrumbBarVisible,
|
|
toggleBreadcrumbBarVisible,
|
|
}
|
|
})
|