Skip to content

Commit

Permalink
feat: 在线分享第一版-数据存储
Browse files Browse the repository at this point in the history
  • Loading branch information
terwer committed Jun 18, 2023
1 parent c812289 commit 9b40199
Show file tree
Hide file tree
Showing 8 changed files with 146 additions and 94 deletions.
102 changes: 52 additions & 50 deletions composables/useThemeMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,28 +26,16 @@
import { BrowserUtil } from "zhi-device"
import { createAppLogger } from "~/common/appLogger"
import { useSettingStore } from "~/stores/useSettingStore"
import AppConfig from "~/app.config"

// 创建日志记录器
const logger = createAppLogger("use-theme-mode")

export const useThemeMode = async () => {
// 创建日志记录器
const logger = createAppLogger("use-theme-mode")
// 获取颜色模式和运行时配置
const color = useColorMode()
const env = useRuntimeConfig()
const { getSetting, updateSetting } = useSettingStore()

// 在 mounted 生命周期中设置主题模式
onMounted(() => {
const isDark = color.value === "dark"
setThemeMode(isDark, true)
})

// =============================================================================================================
// Lifecycle injection APIs can only be used during execution of setup(). If you are using async setup(),
// make sure to register lifecycle hooks before the first await statement
// =============================================================================================================
const setting = await getSetting()

// 根据浏览器模式设置 CSS 和主题模式
const setCssAndThemeMode = (isDarkMode: boolean) => {
const version = "11.5.0"
Expand All @@ -58,9 +46,57 @@ export const useThemeMode = async () => {
document.documentElement.dataset.themeMode = isDarkMode ? "dark" : "light"
}

// 获取颜色模式并暴露 computed 属性
const colorMode = computed({
get: () => {
return color.value === "dark"
},
set: (value) => {
color.value = value ? "dark" : "light"
},
})

const switchMode = () => {
const isDark = color.value === "dark"
setThemeMode(isDark, true)
}

// 切换暗黑模式
const toggleDark = async () => {
colorMode.value = !colorMode.value

const mode = colorMode.value ? "dark" : "light"
if (setting.theme && setting.theme.mode) {
setting.theme.mode = mode
} else {
setting.theme = {
mode: mode,
}
}
await updateSetting(setting)
switchMode()
}

// 在 mounted 生命周期中设置主题模式
onMounted(() => {
switchMode()
})

const setting = await getSetting()
const autoMode = colorMode.value ? "dark" : "light"
useHead({
htmlAttrs: {
"data-theme-mode": setting?.theme?.mode,
"data-light-theme": setting?.theme?.lightTheme,
"data-dark-theme": setting?.theme?.darkTheme,
},
})

// ==================================================
// private methods
// ==================================================
// 设置主题模式
const setThemeMode = (isDarkMode: boolean, isDelay = false) => {
// 更新前端
if (BrowserUtil.isInBrowser) {
// 使用 setTimeout 确保在 CSS 加载完成后再执行函数
const waitTime = parseInt(env.public.waitTime ?? 500)
Expand All @@ -81,39 +117,5 @@ export const useThemeMode = async () => {
color.preference = isDarkMode ? "dark" : "light"
}

// 获取颜色模式并暴露 computed 属性
const colorMode = computed({
get: () => {
return color.value === "dark"
},
set: (value) => {
setThemeMode(value)
},
})

// 切换暗黑模式
const toggleDark = async () => {
colorMode.value = !colorMode.value

// 更新用户设置
const newSetting: typeof AppConfig = {
...setting,
...{
theme: {
mode: colorMode.value ? "dark" : "light",
},
},
}
await updateSetting(newSetting)
}

useHead({
htmlAttrs: {
"data-theme-mode": setting.theme?.mode,
"data-light-theme": setting.theme?.lightTheme,
"data-dark-theme": setting.theme?.darkTheme,
},
})

return { colorMode, toggleDark }
}
12 changes: 2 additions & 10 deletions nuxt.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const generateDynamicV = () => {
}

const isDev = process.env.NODE_ENV === "development"
const appBase = "/plugins/siyuan-blog/"
const appBase = "/"
const staticV = generateDynamicV()

// https://nuxt.com/docs/api/configuration/nuxt-config
Expand All @@ -24,7 +24,7 @@ export default defineNuxtConfig({
},

// build modules
modules: ["@vueuse/nuxt", "@nuxtjs/i18n-edge", "@element-plus/nuxt", "@nuxtjs/color-mode", "@pinia/nuxt"],
modules: ["@vueuse/nuxt", "@nuxtjs/i18n", "@element-plus/nuxt", "@nuxtjs/color-mode", "@pinia/nuxt"],

// vueuse
vueuse: {
Expand Down Expand Up @@ -55,14 +55,6 @@ export default defineNuxtConfig({
themes: ["dark"],
},

// https://nuxt.com/docs/guide/going-further/custom-routing#hash-mode-spa
ssr: false,
router: {
options: {
hashMode: true,
},
},

css: ["~/assets/siyuan/style.styl", "~/assets/siyuan/index.styl"],

app: {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,6 @@
"highlight.js": "^11.8.0",
"pinia": "^2.1.4",
"zhi-device": "^2.3.0",
"zhi-siyuan-api": "^1.14.1"
"zhi-siyuan-api": "^1.16.0"
}
}
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

40 changes: 30 additions & 10 deletions stores/common/commonStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import { StorageLikeAsync } from "@vueuse/core"
import { createAppLogger } from "~/common/appLogger"
import { SiyuanConfig, SiyuanKernelApi } from "zhi-siyuan-api"
import { SiyuanDevice } from "zhi-device"
import { StrUtil } from "zhi-common"

/**
* 通用存储实现,实现了 `StorageLikeAsync` 接口。
Expand All @@ -38,12 +39,14 @@ import { SiyuanDevice } from "zhi-device"
*/
class CommonStorage implements StorageLikeAsync {
private readonly logger
private readonly useSiyuanApi = isUseSiyuanApi()
private readonly useSiyuanApi
private readonly kernelApi
public readonly key

constructor(storageKey: string) {
this.logger = createAppLogger("common-storage")
this.useSiyuanApi = isUseSiyuanApi()

const env = useRuntimeConfig()
const siyuanConfig = new SiyuanConfig(env.public.siyuanApiUrl, env.siyuanAuthToken)
this.kernelApi = new SiyuanKernelApi(siyuanConfig)
Expand All @@ -66,15 +69,29 @@ class CommonStorage implements StorageLikeAsync {
this.logger.info(`Retrieving value for '${key}' from CommonStorage.`)
let ret
if (this.useSiyuanApi) {
// 如果当前运行在思源笔记中,则直接返回空字符串
this.logger.info(`SiYuan, Siyuan_Browser, Node LocalStorageAdaptor.getItem - Key '${key}' not found.`)
ret = "{}"
// 如果当前运行在思源笔记中,则直接返回 null
try {
ret = (await this.kernelApi.getFile(key, "text")) ?? ""
this.logger.info(`Use SiYuan Api LocalStorageAdaptor to getItem - Retrieving '${key}', Value: ${ret}`)
} catch (error) {
this.logger.error(`Failed to get value for key '${key}' from SiYuan Api LocalStorageAdaptor. Error:`, error)
}
} else {
const win = SiyuanDevice.siyuanWindow()
const value = win.localStorage.getItem(key)
ret = value || "{}"
this.logger.info(`Browser LocalStorageAdaptor.getItem - Key '${key}' found, Value: ${ret}`)
try {
const win = SiyuanDevice.siyuanWindow()
const value = win.localStorage.getItem(key)
ret = value ?? ""
this.logger.info(`Use Browser LocalStorageAdaptor to getItem - Retrieving '${key}', Value: ${ret}`)
} catch (error) {
this.logger.error(`Failed to get value for key '${key}' from Browser LocalStorageAdaptor. Error:`, error)
}
}

// 根据 ret 的值返回不同类型的结果
if (StrUtil.isEmptyString(ret)) {
ret = "{}"
}
this.logger.info(`Final getItem - '${key}', Value: '${ret}'`)
return ret
}

Expand All @@ -99,9 +116,12 @@ class CommonStorage implements StorageLikeAsync {
this.logger.info(`Setting value for '${key}' in CommonStorage to '${value}'.`)
if (this.useSiyuanApi) {
// 如果当前运行在思源笔记中,则直接返回空字符串
this.logger.info(`SiYuan, Siyuan_Browser, Node LocalStorageAdaptor.setItem - Key '${key}', Value: '${value}'`)
await this.kernelApi.saveTextData(key, value)
this.logger.info(`Use SiYuan Api LocalStorageAdaptor to setItem - Key '${key}', Value: '${value}'`)
} else {
this.logger.info(`Browser LocalStorageAdaptor.setItem - Key '${key}', Value: '${value}'`)
const win = SiyuanDevice.siyuanWindow()
win.localStorage.setItem(key, value)
this.logger.info(`Use Browser LocalStorageAdaptor to setItem - Key '${key}', Value: '${value}'`)
}
}
}
Expand Down
52 changes: 50 additions & 2 deletions stores/common/useCommonStorageAsync.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,65 @@
* questions.
*/

import { useStorageAsync } from "@vueuse/core"
import CommonStorage from "~/stores/common/commonStorage"
import { StorageSerializers } from "@vueuse/core"
import { createAppLogger } from "~/common/appLogger"

/**
* https://vueuse.org/core/useStorageAsync/
*
* @param storageKey
*/
export const useCommonStorageAsync = <T extends string | number | boolean | object | null>(storageKey: string) => {
const logger = createAppLogger("common-storage-async")
const commonStorage = new CommonStorage(storageKey)
const commonStore = useStorageAsync<T>(commonStorage.key, {} as T, commonStorage, {})

// 获取 initialValue 类型对应的序列化器,如果不存在则使用默认序列化器
const initialValue = {} as T
const rawInit: T = toValue(initialValue)
const type = guessSerializerType<T>(rawInit) as
| "boolean"
| "object"
| "number"
| "any"
| "string"
| "map"
| "set"
| "date"
logger.info(`It is detected that the serialization type is ${type}`)
const serializer = StorageSerializers[type]

// 定义 commonStore 对象
const commonStore = {
async get(): Promise<T> {
const rawValue = (await commonStorage.getItem(commonStorage.key)) ?? "{}"
const ret = await serializer.read(rawValue)
return ret ?? {}
},
async set(value: T): Promise<void> {
await commonStorage.setItem(commonStorage.key, serializer.write(value))
},
}

return { commonStore }
}

function guessSerializerType<T extends string | number | boolean | object | null>(rawInit: T) {
return rawInit == null
? "any"
: rawInit instanceof Set
? "set"
: rawInit instanceof Map
? "map"
: rawInit instanceof Date
? "date"
: typeof rawInit === "boolean"
? "boolean"
: typeof rawInit === "string"
? "string"
: typeof rawInit === "object"
? "object"
: !Number.isNaN(rawInit)
? "number"
: "any"
}
8 changes: 2 additions & 6 deletions stores/useSettingStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@ export const useSettingStore = defineStore("setting", () => {
const { commonStore } = useCommonStorageAsync<typeof AppConfig>(storageKey)

const getSetting = async (): Promise<typeof AppConfig> => {
// const appConfig: typeof AppConfig = useAppConfig()
// const storeSetting = commonStore.value
// const setting = { ...appConfig, ...storeSetting }
const setting = commonStore.value
const setting = await commonStore.get()
logger.info("get data from setting=>", setting)
return setting
}
Expand All @@ -27,9 +24,8 @@ export const useSettingStore = defineStore("setting", () => {
* @param setting - 需要修改的配置
*/
const updateSetting = async (setting: Partial<typeof AppConfig>) => {
// updateAppConfig(setting)
logger.info("update setting=>", setting)
commonStore.value = setting
await commonStore.set(setting)
}

return { getSetting, updateSetting }
Expand Down
16 changes: 5 additions & 11 deletions utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,9 @@ export const isInSiyuanOrSiyuanNewWin = () => {
}

export const isUseSiyuanApi = () => {
const deviceType = DeviceDetection.getDevice()
// 五种情况,主窗口、挂件、新窗口、Node、Siyuan浏览器
const useSiyuanApi =
deviceType === DeviceTypeEnum.DeviceType_Siyuan_MainWin ||
deviceType === DeviceTypeEnum.DeviceType_Siyuan_NewWin ||
deviceType === DeviceTypeEnum.DeviceType_Siyuan_Widget ||
deviceType === DeviceTypeEnum.DeviceType_Siyuan_Browser ||
deviceType === DeviceTypeEnum.DeviceType_Node
logger.debug("deviceType=>", deviceType)
logger.debug("isUseSiyuanApi=>", String(useSiyuanApi))
return useSiyuanApi
const env = useRuntimeConfig()
const isUseSiyuanApi = env.public.defaultType === "siyuan"
logger.debug("defaultType=>", env.public.defaultType)
logger.debug("isUseSiyuanApi=>", String(isUseSiyuanApi))
return isUseSiyuanApi
}

0 comments on commit 9b40199

Please sign in to comment.