提交1 bmad搭建与项目启动 - ok

This commit is contained in:
2025-10-17 17:24:56 +08:00
commit ec58562661
686 changed files with 149750 additions and 0 deletions

View File

@@ -0,0 +1,17 @@
import { useState, useEffect } from 'react'
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value)
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value)
}, delay)
return () => {
clearTimeout(handler)
}
}, [value, delay])
return debouncedValue
}

View File

@@ -0,0 +1,56 @@
import { useState, useEffect } from 'react'
export function useLocalStorage<T>(
key: string,
initialValue: T
): [T, (value: T | ((prev: T) => T)) => void] {
// 获取初始值
const [storedValue, setStoredValue] = useState<T>(() => {
if (typeof window === 'undefined') {
return initialValue
}
try {
const item = window.localStorage.getItem(key)
return item ? JSON.parse(item) : initialValue
} catch (error) {
console.warn(`Error reading localStorage key "${key}":`, error)
return initialValue
}
})
// 设置值的函数
const setValue = (value: T | ((prev: T) => T)) => {
try {
// 允许value是一个函数类似于useState
const valueToStore =
value instanceof Function ? value(storedValue) : value
setStoredValue(valueToStore)
if (typeof window !== 'undefined') {
window.localStorage.setItem(key, JSON.stringify(valueToStore))
}
} catch (error) {
console.warn(`Error setting localStorage key "${key}":`, error)
}
}
// 监听localStorage变化
useEffect(() => {
const handleStorageChange = (event: StorageEvent) => {
if (event.key === key && event.newValue !== null) {
try {
setStoredValue(JSON.parse(event.newValue))
} catch (error) {
console.warn(`Error parsing localStorage change for key "${key}":`, error)
}
}
}
window.addEventListener('storage', handleStorageChange)
return () => window.removeEventListener('storage', handleStorageChange)
}, [key])
return [storedValue, setValue]
}

View File

@@ -0,0 +1,58 @@
import { useState, useEffect } from 'react'
import type { Theme } from '@/types'
export function useTheme() {
const [theme, setTheme] = useState<Theme>(() => {
// 从localStorage获取主题设置
const saved = localStorage.getItem('agriculture-theme')
if (saved && ['light', 'dark', 'system'].includes(saved)) {
return saved as Theme
}
return 'system'
})
useEffect(() => {
const root = window.document.documentElement
// 移除之前的主题类
root.classList.remove('light', 'dark')
if (theme === 'system') {
// 使用系统主题
const systemTheme = window.matchMedia('(prefers-color-scheme: dark)')
.matches
? 'dark'
: 'light'
root.classList.add(systemTheme)
} else {
// 使用指定主题
root.classList.add(theme)
}
// 保存到localStorage
localStorage.setItem('agriculture-theme', theme)
}, [theme])
// 监听系统主题变化
useEffect(() => {
if (theme === 'system') {
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
const handleChange = () => {
const root = window.document.documentElement
root.classList.remove('light', 'dark')
root.classList.add(mediaQuery.matches ? 'dark' : 'light')
}
mediaQuery.addEventListener('change', handleChange)
return () => mediaQuery.removeEventListener('change', handleChange)
}
}, [theme])
return {
theme,
setTheme,
isDark: theme === 'dark' || (theme === 'system' &&
window.matchMedia('(prefers-color-scheme: dark)').matches)
}
}