feat(偏好设置): 添加浏览器扩展存储支持及时间显示偏好功能
添加 webextension-polyfill 依赖以支持浏览器扩展存储 API 创建 usePreferences store 管理用户偏好设置 将 Playroom 页面的时间显示切换功能迁移至偏好设置 store
This commit is contained in:
		
							parent
							
								
									4a8f68346a
								
							
						
					
					
						commit
						32ab4574dd
					
				
							
								
								
									
										17
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										17
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| 
						 | 
				
			
			@ -14,11 +14,13 @@
 | 
			
		|||
				"pinia": "^3.0.2",
 | 
			
		||||
				"tailwindcss": "^4.1.7",
 | 
			
		||||
				"vue": "^3.5.13",
 | 
			
		||||
				"vue-router": "^4.5.1"
 | 
			
		||||
				"vue-router": "^4.5.1",
 | 
			
		||||
				"webextension-polyfill": "^0.12.0"
 | 
			
		||||
			},
 | 
			
		||||
			"devDependencies": {
 | 
			
		||||
				"@biomejs/biome": "1.9.4",
 | 
			
		||||
				"@types/node": "^22.15.21",
 | 
			
		||||
				"@types/webextension-polyfill": "^0.12.3",
 | 
			
		||||
				"@vitejs/plugin-vue": "^5.2.1",
 | 
			
		||||
				"typescript": "~5.6.2",
 | 
			
		||||
				"vite": "^6.0.1",
 | 
			
		||||
| 
						 | 
				
			
			@ -1246,6 +1248,13 @@
 | 
			
		|||
				"undici-types": "~6.21.0"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@types/webextension-polyfill": {
 | 
			
		||||
			"version": "0.12.3",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@types/webextension-polyfill/-/webextension-polyfill-0.12.3.tgz",
 | 
			
		||||
			"integrity": "sha512-F58aDVSeN/MjUGazXo/cPsmR76EvqQhQ1v4x23hFjUX0cfAJYE+JBWwiOGW36/VJGGxoH74sVlRIF3z7SJCKyg==",
 | 
			
		||||
			"dev": true,
 | 
			
		||||
			"license": "MIT"
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/@vitejs/plugin-vue": {
 | 
			
		||||
			"version": "5.2.4",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz",
 | 
			
		||||
| 
						 | 
				
			
			@ -2647,6 +2656,12 @@
 | 
			
		|||
				"typescript": ">=5.0.0"
 | 
			
		||||
			}
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/webextension-polyfill": {
 | 
			
		||||
			"version": "0.12.0",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/webextension-polyfill/-/webextension-polyfill-0.12.0.tgz",
 | 
			
		||||
			"integrity": "sha512-97TBmpoWJEE+3nFBQ4VocyCdLKfw54rFaJ6EVQYLBCXqCIpLSZkwGgASpv4oPt9gdKCJ80RJlcmNzNn008Ag6Q==",
 | 
			
		||||
			"license": "MPL-2.0"
 | 
			
		||||
		},
 | 
			
		||||
		"node_modules/yallist": {
 | 
			
		||||
			"version": "5.0.0",
 | 
			
		||||
			"resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -19,11 +19,13 @@
 | 
			
		|||
		"pinia": "^3.0.2",
 | 
			
		||||
		"tailwindcss": "^4.1.7",
 | 
			
		||||
		"vue": "^3.5.13",
 | 
			
		||||
		"vue-router": "^4.5.1"
 | 
			
		||||
		"vue-router": "^4.5.1",
 | 
			
		||||
		"webextension-polyfill": "^0.12.0"
 | 
			
		||||
	},
 | 
			
		||||
	"devDependencies": {
 | 
			
		||||
		"@biomejs/biome": "1.9.4",
 | 
			
		||||
		"@types/node": "^22.15.21",
 | 
			
		||||
		"@types/webextension-polyfill": "^0.12.3",
 | 
			
		||||
		"@vitejs/plugin-vue": "^5.2.1",
 | 
			
		||||
		"typescript": "~5.6.2",
 | 
			
		||||
		"vite": "^6.0.1",
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -6,6 +6,7 @@ import { Draggable } from "gsap/Draggable"
 | 
			
		|||
import { onMounted } from 'vue'
 | 
			
		||||
import { useTemplateRef } from 'vue'
 | 
			
		||||
import { ref, watch } from 'vue'
 | 
			
		||||
import { usePreferences } from '../stores/usePreferences'
 | 
			
		||||
 | 
			
		||||
import RewindIcon from '../assets/icons/rewind.vue'
 | 
			
		||||
import ForwardIcon from '../assets/icons/forward.vue'
 | 
			
		||||
| 
						 | 
				
			
			@ -23,6 +24,7 @@ import CycleTwoArrowsWithNumOneIcon from '../assets/icons/cycletwoarrowswithnumo
 | 
			
		|||
import SpeakerIcon from '../assets/icons/speaker.vue'
 | 
			
		||||
 | 
			
		||||
const playQueueStore = usePlayQueueStore()
 | 
			
		||||
const preferences = usePreferences()
 | 
			
		||||
gsap.registerPlugin(Draggable)
 | 
			
		||||
 | 
			
		||||
const progressBarThumb = useTemplateRef('progressBarThumb')
 | 
			
		||||
| 
						 | 
				
			
			@ -30,10 +32,9 @@ const progressBarContainer = useTemplateRef('progressBarContainer')
 | 
			
		|||
const playQueueDialogContainer = useTemplateRef('playQueueDialogContainer')
 | 
			
		||||
const playQueueDialog = useTemplateRef('playQueueDialog')
 | 
			
		||||
 | 
			
		||||
const displayTimeLeft = ref(false)
 | 
			
		||||
const presentQueueListDialog = ref(false)
 | 
			
		||||
 | 
			
		||||
onMounted(() => {
 | 
			
		||||
onMounted(async () => {
 | 
			
		||||
	Draggable.create(progressBarThumb.value, {
 | 
			
		||||
		type: 'x',
 | 
			
		||||
		bounds: progressBarContainer.value,
 | 
			
		||||
| 
						 | 
				
			
			@ -204,10 +205,10 @@ function getCurrentTrack() {
 | 
			
		|||
					</div>
 | 
			
		||||
					<div class="flex flex-1">
 | 
			
		||||
						<div class="flex-1" />
 | 
			
		||||
						<button class="text-white/90 font-medium text-right relative" @click="displayTimeLeft = !displayTimeLeft">
 | 
			
		||||
						<button class="text-white/90 font-medium text-right relative" @click="preferences.displayTimeLeft = !preferences.displayTimeLeft">
 | 
			
		||||
							<span
 | 
			
		||||
								class="text-black blur-lg absolute top-0">{{ `${displayTimeLeft ? '-' : ''}${timeFormatter(displayTimeLeft ? Math.floor(playQueueStore.duration) - Math.floor(playQueueStore.currentTime) : playQueueStore.duration)}` }}</span>
 | 
			
		||||
							<span>{{ `${displayTimeLeft ? '-' : ''}${timeFormatter(displayTimeLeft ? Math.floor(playQueueStore.duration) - Math.floor(playQueueStore.currentTime) : playQueueStore.duration)}` }}</span>
 | 
			
		||||
								class="text-black blur-lg absolute top-0">{{ `${preferences.displayTimeLeft ? '-' : ''}${timeFormatter(preferences.displayTimeLeft ? Math.floor(playQueueStore.duration) - Math.floor(playQueueStore.currentTime) : playQueueStore.duration)}` }}</span>
 | 
			
		||||
							<span>{{ `${preferences.displayTimeLeft ? '-' : ''}${timeFormatter(preferences.displayTimeLeft ? Math.floor(playQueueStore.duration) - Math.floor(playQueueStore.currentTime) : playQueueStore.duration)}` }}</span>
 | 
			
		||||
						</button>
 | 
			
		||||
					</div>
 | 
			
		||||
				</div>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										47
									
								
								src/stores/usePreferences.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/stores/usePreferences.ts
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,47 @@
 | 
			
		|||
import { defineStore } from "pinia"
 | 
			
		||||
import { ref, watch } from "vue"
 | 
			
		||||
import browser from 'webextension-polyfill'
 | 
			
		||||
 | 
			
		||||
export const usePreferences = defineStore('preferences', () => {
 | 
			
		||||
	const displayTimeLeft = ref<boolean>(false) // 设置默认值
 | 
			
		||||
	const isLoaded = ref(false) // 添加加载状态
 | 
			
		||||
 | 
			
		||||
	// 异步初始化函数
 | 
			
		||||
	const initializePreferences = async () => {
 | 
			
		||||
		try {
 | 
			
		||||
			// 指定默认值对象
 | 
			
		||||
			const result = await browser.storage.local.get({
 | 
			
		||||
				displayTimeLeft: false // 如果键不存在,使用这个默认值
 | 
			
		||||
			})
 | 
			
		||||
			
 | 
			
		||||
			displayTimeLeft.value = result.displayTimeLeft as boolean // 现在类型是安全的
 | 
			
		||||
			isLoaded.value = true
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			console.error('加载偏好设置失败:', error)
 | 
			
		||||
			displayTimeLeft.value = false
 | 
			
		||||
			isLoaded.value = true
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 监听变化并保存
 | 
			
		||||
	watch(displayTimeLeft, async (val) => {
 | 
			
		||||
		if (isLoaded.value) { // 只有在初始化完成后才保存
 | 
			
		||||
			try {
 | 
			
		||||
				await browser.storage.local.set({
 | 
			
		||||
					displayTimeLeft: val
 | 
			
		||||
				})
 | 
			
		||||
			} catch (error) {
 | 
			
		||||
				console.error('保存偏好设置失败:', error)
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	// 立即初始化
 | 
			
		||||
	initializePreferences()
 | 
			
		||||
 | 
			
		||||
	return {
 | 
			
		||||
		displayTimeLeft,
 | 
			
		||||
		isLoaded,
 | 
			
		||||
		initializePreferences
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user