1
0

feat: add persist feature for frontend

This commit is contained in:
2026-05-13 11:02:35 +08:00
parent bdee3b3efa
commit 078e61e993
6 changed files with 86 additions and 13 deletions

View File

@@ -18,6 +18,7 @@
"@fortawesome/vue-fontawesome": "^3.2.0", "@fortawesome/vue-fontawesome": "^3.2.0",
"bulma": "^1.0.4", "bulma": "^1.0.4",
"pinia": "^3.0.4", "pinia": "^3.0.4",
"pinia-plugin-persistedstate": "^4.7.1",
"vue": "^3.5.32", "vue": "^3.5.32",
"vue-router": "^5.0.4" "vue-router": "^5.0.4"
}, },

View File

@@ -20,6 +20,9 @@ importers:
pinia: pinia:
specifier: ^3.0.4 specifier: ^3.0.4
version: 3.0.4(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3)) version: 3.0.4(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3))
pinia-plugin-persistedstate:
specifier: ^4.7.1
version: 4.7.1(pinia@3.0.4(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3)))
vue: vue:
specifier: ^3.5.32 specifier: ^3.5.32
version: 3.5.33(typescript@6.0.3) version: 3.5.33(typescript@6.0.3)
@@ -968,6 +971,9 @@ packages:
resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==}
engines: {node: '>=12'} engines: {node: '>=12'}
defu@6.1.7:
resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==}
detect-libc@2.1.2: detect-libc@2.1.2:
resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@@ -1431,6 +1437,20 @@ packages:
engines: {node: '>=0.10'} engines: {node: '>=0.10'}
hasBin: true hasBin: true
pinia-plugin-persistedstate@4.7.1:
resolution: {integrity: sha512-WHOqh2esDlR3eAaknPbqXrkkj0D24h8shrDPqysgCFR6ghqP/fpFfJmMPJp0gETHsvrh9YNNg6dQfo2OEtDnIQ==}
peerDependencies:
'@nuxt/kit': '>=3.0.0'
'@pinia/nuxt': '>=0.10.0'
pinia: '>=3.0.0'
peerDependenciesMeta:
'@nuxt/kit':
optional: true
'@pinia/nuxt':
optional: true
pinia:
optional: true
pinia@3.0.4: pinia@3.0.4:
resolution: {integrity: sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==} resolution: {integrity: sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw==}
peerDependencies: peerDependencies:
@@ -2625,6 +2645,8 @@ snapshots:
define-lazy-prop@3.0.0: {} define-lazy-prop@3.0.0: {}
defu@6.1.7: {}
detect-libc@2.1.2: {} detect-libc@2.1.2: {}
electron-to-chromium@1.5.344: {} electron-to-chromium@1.5.344: {}
@@ -3036,6 +3058,12 @@ snapshots:
pidtree@0.6.0: {} pidtree@0.6.0: {}
pinia-plugin-persistedstate@4.7.1(pinia@3.0.4(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3))):
dependencies:
defu: 6.1.7
optionalDependencies:
pinia: 3.0.4(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3))
pinia@3.0.4(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3)): pinia@3.0.4(typescript@6.0.3)(vue@3.5.33(typescript@6.0.3)):
dependencies: dependencies:
'@vue/devtools-api': 7.7.9 '@vue/devtools-api': 7.7.9

View File

@@ -1,7 +1,9 @@
<script setup lang="ts"> <script setup lang="ts">
import { useLanguageStore } from './stores/global'; import { useLanguageStore } from './stores/i18n';
import { useTokenStore } from './stores/token';
const language = useLanguageStore(); const language = useLanguageStore();
const token = useTokenStore();
</script> </script>
@@ -23,18 +25,18 @@ const language = useLanguageStore();
<div id="coleaf-navbar" class="navbar-menu"> <div id="coleaf-navbar" class="navbar-menu">
<div class="navbar-start"> <div class="navbar-start">
<router-link class="navbar-item" to="/home">Home</router-link> <router-link class="navbar-item" to="/home">Home</router-link>
<router-link class="navbar-item" to="/collection">Collection</router-link> <router-link v-if="token.isLoggedIn" class="navbar-item" to="/collection">Collection</router-link>
<router-link class="navbar-item" to="/calendar">Calendar</router-link> <router-link v-if="token.isLoggedIn" class="navbar-item" to="/calendar">Calendar</router-link>
<router-link class="navbar-item" to="/todo">Todo</router-link> <router-link v-if="token.isLoggedIn" class="navbar-item" to="/todo">Todo</router-link>
<router-link class="navbar-item" to="/admin">Admin</router-link> <router-link v-if="token.isLoggedIn" class="navbar-item" to="/admin">Admin</router-link>
</div> </div>
<div class="navbar-end"> <div class="navbar-end">
<p class="navbar-item"> <p class="navbar-item">
<a class="button is-primary" href="/login">Login</a> <router-link v-if="!token.isLoggedIn" class="button is-primary" to="/login">Login</router-link>
</p> </p>
<p class="navbar-item"> <p class="navbar-item">
<a class="button is-primary">Logout</a> <a v-if="token.isLoggedIn" class="button is-primary">Logout</a>
</p> </p>
<div class="navbar-item has-dropdown is-hoverable"> <div class="navbar-item has-dropdown is-hoverable">

View File

@@ -1,14 +1,17 @@
import { createApp } from 'vue' import { createApp } from 'vue'
import { createPinia } from 'pinia' import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
import App from './App.vue' import App from './App.vue'
import router from './router' import router from './router'
import '../public/index.scss' import '../public/index.scss'
const app = createApp(App) const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
app.use(createPinia()) const app = createApp(App);
app.use(router) app.use(pinia);
app.use(router);
app.mount('#app') app.mount('#app');

View File

@@ -1,9 +1,12 @@
import { ref, computed } from 'vue'
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { Language } from '@/utils/i18n' import { Language } from '@/utils/i18n'
interface LanguageState {
language: Language
}
export const useLanguageStore = defineStore('language', { export const useLanguageStore = defineStore('language', {
state: () => ({ state: (): LanguageState => ({
language: Language.English language: Language.English
}), }),
@@ -23,4 +26,10 @@ export const useLanguageStore = defineStore('language', {
this.changeLanguage(Language.SimplifiedChinese); this.changeLanguage(Language.SimplifiedChinese);
}, },
}, },
persist: {
key: 'ccn-i18n',
storage: localStorage,
pick: ['language'],
},
}) })

View File

@@ -0,0 +1,30 @@
import { defineStore } from 'pinia'
interface TokenState {
token: string | null
}
export const useTokenStore = defineStore('token', {
state: (): TokenState => ({
token: null,
}),
getters: {
isLoggedIn: (state) => typeof state.token === 'string',
},
actions: {
login(token: string) {
this.token = token;
},
logout() {
this.token = null;
},
},
persist: {
key: 'ccn-token',
storage: localStorage,
pick: ['token'],
},
})