feat: 首页更新

This commit is contained in:
2025-11-12 00:13:26 +08:00
parent b48cce06f4
commit 9ef9233797
46 changed files with 660 additions and 369 deletions

View File

@@ -24,3 +24,6 @@ export {
// Client-only value (for SSR/Web compatibility)
export { useClientOnlyValue } from './useClientOnlyValue';
// Game Menus
export { useGameMainMenus, useMenuDataLoaded, useSelectedCategory } from './useGameMenus';

View File

@@ -1,10 +1,20 @@
import { useEffect, useState, useMemo } from 'react';
import { useEffect, useState, useMemo, useCallback } from 'react';
import useGameStore from '@/stores/gameStore';
import { GameMainTypesEnum, defaultHomeGameTabMenus, gameMainTypesMap } from '@/constants/game';
import { ThemeEnum } from '@/constants/theme';
import { forEach, cloneDeep, map, filter } from 'lodash-es';
import { useIsLoggedIn } from '@/stores/userStore';
import { useShallow } from 'zustand/react/shallow';
import storageManager, { STORAGE_KEYS } from '@/utils/storageManager';
type GameMenu = {
name: string;
key: string;
icon?: string;
logo?: string;
children?: GameMenu[];
};
// 有子菜单的游戏类型
const hasSubGameMainTypes = [
@@ -78,10 +88,68 @@ export const useGameMainMenus = (theme: ThemeEnum) => {
],
(item) => ({
...item,
// 为了在 React Native 中正确加载本地图片,使用 require 的方式
// 这里保留原始的 icon 名称,在组件中使用 require 加载
icon: item.icon,
key: `${item.key}`,
})
);
) as GameMenu[];
}, [theme, isLogin, menuSort, gameBigClass]);
};
export const useMenuDataLoaded = () => useGameStore((state) => state.menuSort?.length > 0);
/**
* 游戏分类选择 Hook统一管理
*
* 管理当前选中的游戏分类,支持:
* - 从 gameStore 获取当前选中分类
* - 更新选中分类并保存到 session storage
* - 页面刷新后恢复选中分类
*
* @returns {Object} 包含 selectedCategory 和 setSelectedCategory 的对象
*
* @example
* ```typescript
* const { selectedCategory, setSelectedCategory } = useSelectedCategory();
*
* // 获取当前选中分类
* console.log(selectedCategory); // '103'
*
* // 更新选中分类
* setSelectedCategory('1');
* ```
*/
export const useSelectedCategory = () => {
const selectedCategory = useGameStore((state) => state.selectedCategory);
const setSelectedCategoryInStore = useGameStore((state) => state.setSelectedCategory);
// 初始化时从 session storage 恢复选中分类
useEffect(() => {
const initializeSelectedCategory = async () => {
try {
const savedCategory = storageManager.session.getItem(STORAGE_KEYS.APP_ACTIVE_MAIN_MENU_TAB);
if (savedCategory) {
setSelectedCategoryInStore(savedCategory);
}
} catch (error) {
console.error('Failed to restore selected category:', error);
}
};
initializeSelectedCategory();
}, [setSelectedCategoryInStore]);
// 更新选中分类的回调函数
const setSelectedCategory = useCallback(
(categoryId: string) => {
setSelectedCategoryInStore(categoryId);
},
[setSelectedCategoryInStore]
);
return {
selectedCategory,
setSelectedCategory,
};
};

View File

@@ -1,49 +1,50 @@
/**
* 主题 Hooks
*
*
* 提供统一的主题访问接口
*/
import { useMemo } from 'react';
import { useColorScheme as useSystemColorScheme } from 'react-native';
import { useTheme as useThemeStore } from '@/stores';
import Colors from '@/constants/Colors';
import { Colors } from '@/theme';
import { ThemeEnum } from '@/constants/theme';
/**
* 获取当前颜色方案light | dark
*
* 获取当前颜色方案light | dark | orange
*
* 从 settingsStore 读取用户设置的主题
* 支持 'light' | 'dark' | 'auto' 种模式
* 支持 'light' | 'dark' | 'orange' | 'auto' 种模式
*/
export function useColorScheme(): 'light' | 'dark' {
export function useColorScheme(): ThemeEnum {
const userTheme = useThemeStore();
const systemTheme = useSystemColorScheme();
// 如果用户选择了 'auto',则使用系统主题
if (userTheme === 'auto') {
return systemTheme === 'dark' ? 'dark' : 'light';
return systemTheme === 'dark' ? ThemeEnum.DARK : ThemeEnum.LIGHT;
}
// 否则使用用户选择的主题
return userTheme;
return userTheme as ThemeEnum;
}
/**
* 获取主题颜色
*
* @param props - 可选的自定义颜色 { light?: string; dark?: string }
*
* @param props - 可选的自定义颜色 { light?: string; dark?: string; orange?: string }
* @param colorName - Colors 中定义的颜色名称
* @returns 当前主题对应的颜色值
*
*
* @example
* ```tsx
* const textColor = useThemeColor({}, 'text');
* const customColor = useThemeColor({ light: '#000', dark: '#fff' }, 'text');
* const customColor = useThemeColor({ light: '#000', dark: '#fff', orange: '#f90' }, 'text');
* ```
*/
export function useThemeColor(
props: { light?: string; dark?: string },
colorName: keyof typeof Colors.light & keyof typeof Colors.dark
props: { light?: string; dark?: string; orange?: string },
colorName: keyof typeof Colors.light & keyof typeof Colors.dark & keyof typeof Colors.orange
): string {
const theme = useColorScheme();
const colorFromProps = props[theme];
@@ -57,9 +58,9 @@ export function useThemeColor(
/**
* 获取完整的主题颜色对象
*
*
* @returns 当前主题的所有颜色配置
*
*
* @example
* ```tsx
* const colors = useThemeColors();
@@ -70,7 +71,7 @@ export function useThemeColor(
*/
export function useThemeColors() {
const theme = useColorScheme();
return useMemo(() => {
return Colors[theme];
}, [theme]);
@@ -78,23 +79,24 @@ export function useThemeColors() {
/**
* 获取主题相关的所有信息
*
*
* @returns 主题信息对象
*
*
* @example
* ```tsx
* const { theme, colors, isDark } = useThemeInfo();
* const { theme, colors, isDark, isLight, isOrange } = useThemeInfo();
* ```
*/
export function useThemeInfo() {
const theme = useColorScheme();
const colors = useThemeColors();
return useMemo(() => ({
theme,
colors,
isDark: theme === 'dark',
isLight: theme === 'light',
isDark: theme === ThemeEnum.DARK,
isLight: theme === ThemeEnum.LIGHT,
isOrange: theme === ThemeEnum.ORANGE,
}), [theme, colors]);
}