diff --git a/package.json b/package.json index 497bcdf..eed390a 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ }, "dependencies": { "pinia": "^3.0.3", + "pinia-plugin-persistedstate": "^4.5.0", "vue": "^3.5.18" }, "devDependencies": { @@ -34,4 +35,4 @@ "vite": "npm:rolldown-vite@latest", "vite-plugin-vue-devtools": "^8.0.0" } -} \ No newline at end of file +} diff --git a/src/components/CalendarView.vue b/src/components/CalendarView.vue index 036cc63..6cad89f 100644 --- a/src/components/CalendarView.vue +++ b/src/components/CalendarView.vue @@ -63,7 +63,8 @@ const totalVirtualWeeks = computed(() => { }) const initialScrollTop = computed(() => { - const targetWeekIndex = getWeekIndex(calendarStore.now) - 3 + const nowDate = new Date(calendarStore.now) + const targetWeekIndex = getWeekIndex(nowDate) - 3 return (targetWeekIndex - minVirtualWeek.value) * rowHeight.value }) @@ -76,7 +77,8 @@ const selectedDateRange = computed(() => { }) const todayString = computed(() => { - const t = calendarStore.now + const d = new Date(calendarStore.now) + const t = d .toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' }) .replace(/,? /, '\n') return t.charAt(0).toUpperCase() + t.slice(1) diff --git a/src/main.js b/src/main.js index a7a997b..c74fed5 100644 --- a/src/main.js +++ b/src/main.js @@ -2,11 +2,14 @@ import './assets/calendar.css' import { createApp } from 'vue' import { createPinia } from 'pinia' +import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' import App from './App.vue' const app = createApp(App) -app.use(createPinia()) +const pinia = createPinia() +pinia.use(piniaPluginPersistedstate) +app.use(pinia) app.mount('#app') diff --git a/src/plugins/persist.js b/src/plugins/persist.js new file mode 100644 index 0000000..c41031d --- /dev/null +++ b/src/plugins/persist.js @@ -0,0 +1,24 @@ +// Simple Pinia persistence plugin supporting `persist: true` and Map serialization. +export function persistPlugin({ store }) { + if (!store.$options || !store.$options.persist) return + const key = `pinia-${store.$id}` + try { + const raw = localStorage.getItem(key) + if (raw) { + const state = JSON.parse(raw, (k, v) => { + if (v && v.__map === true && Array.isArray(v.data)) return new Map(v.data) + return v + }) + store.$patch(state) + } + } catch {} + store.$subscribe((_mutation, state) => { + try { + const json = JSON.stringify(state, (_k, v) => { + if (v instanceof Map) return { __map: true, data: Array.from(v.entries()) } + return v + }) + localStorage.setItem(key, json) + } catch {} + }) +} diff --git a/src/stores/CalendarStore.js b/src/stores/CalendarStore.js index e12bc1d..741bc5a 100644 --- a/src/stores/CalendarStore.js +++ b/src/stores/CalendarStore.js @@ -7,7 +7,7 @@ const MAX_YEAR = 2100 export const useCalendarStore = defineStore('calendar', { state: () => ({ today: toLocalString(new Date()), - now: new Date(), + now: new Date().toISOString(), // store as ISO string events: new Map(), // Map of date strings to arrays of events weekend: getLocaleWeekendDays(), config: { @@ -26,8 +26,9 @@ export const useCalendarStore = defineStore('calendar', { actions: { updateCurrentDate() { - this.now = new Date() - const today = toLocalString(this.now) + const d = new Date() + this.now = d.toISOString() + const today = toLocalString(d) if (this.today !== today) { this.today = today } @@ -468,4 +469,19 @@ export const useCalendarStore = defineStore('calendar', { // NOTE: legacy dynamic getEventById for synthetic occurrences removed. }, + persist: { + key: 'calendar-store', + storage: localStorage, + paths: ['today', 'events', 'config'], + serializer: { + serialize(value) { + return JSON.stringify(value, (_k, v) => + v instanceof Map ? { __map: true, data: [...v] } : v, + ) + }, + deserialize(value) { + return JSON.parse(value, (_k, v) => (v && v.__map ? new Map(v.data) : v)) + }, + }, + }, })