refactor: 收口分类配置模型
This commit is contained in:
@@ -160,11 +160,16 @@ import {
|
||||
buildPublicCategoryGroups,
|
||||
buildPublicGalleryCardKey,
|
||||
dedupePlatformPublicGalleryEntries,
|
||||
DEFAULT_PLATFORM_CATEGORY_KIND_FILTER,
|
||||
DEFAULT_PLATFORM_CATEGORY_SORT_MODE,
|
||||
DEFAULT_PLATFORM_RANKING_TAB,
|
||||
filterPlatformWorkSearchResults,
|
||||
filterTodayPublishedEntries,
|
||||
getAllPlatformPublicEntries,
|
||||
getNextPlatformCategorySortMode,
|
||||
getPlatformCategoryKindFilterOption,
|
||||
getPlatformCategoryPrimaryMetric,
|
||||
getPlatformCategorySortOption,
|
||||
getPlatformPublicEntries,
|
||||
getPlatformRankingMetric,
|
||||
getPlatformRankingTabConfig,
|
||||
@@ -174,6 +179,8 @@ import {
|
||||
getPlatformWorldRemixCount,
|
||||
isExactPublicWorkCodeSearch,
|
||||
matchesPlatformCategoryKindFilter,
|
||||
PLATFORM_CATEGORY_KIND_FILTERS,
|
||||
PLATFORM_CATEGORY_SORT_OPTIONS,
|
||||
PLATFORM_RANKING_TABS,
|
||||
type PlatformCategoryKindFilter,
|
||||
type PlatformCategorySortMode,
|
||||
@@ -374,30 +381,6 @@ const EDUTAINMENT_DISCOVER_CHANNEL = {
|
||||
id: 'edutainment',
|
||||
label: EDUTAINMENT_WORK_TAG,
|
||||
} as const;
|
||||
const PLATFORM_CATEGORY_KIND_FILTERS: Array<{
|
||||
id: PlatformCategoryKindFilter;
|
||||
label: string;
|
||||
}> = [
|
||||
{ id: 'all', label: '全部' },
|
||||
{ id: 'puzzle', label: '拼图' },
|
||||
{ id: 'match3d', label: '抓鹅' },
|
||||
{ id: 'square-hole', label: '方洞' },
|
||||
{ id: 'visual-novel', label: '视觉' },
|
||||
{ id: 'bark-battle', label: '汪汪' },
|
||||
{ id: 'big-fish', label: '大鱼' },
|
||||
{ id: 'jump-hop', label: '跳跃' },
|
||||
{ id: 'wooden-fish', label: '木鱼' },
|
||||
{ id: 'custom-world', label: 'RPG' },
|
||||
];
|
||||
const PLATFORM_CATEGORY_SORT_OPTIONS: Array<{
|
||||
id: PlatformCategorySortMode;
|
||||
label: string;
|
||||
}> = [
|
||||
{ id: 'composite', label: '综合' },
|
||||
{ id: 'latest', label: '最新' },
|
||||
{ id: 'play', label: '游玩' },
|
||||
{ id: 'like', label: '点赞' },
|
||||
];
|
||||
const BABY_LOVE_DRAWING_DEFAULT_CARD = {
|
||||
title: '宝贝爱画',
|
||||
subtitle: '空白画板',
|
||||
@@ -3522,9 +3505,11 @@ export function RpgEntryHomeView({
|
||||
null,
|
||||
);
|
||||
const [categoryKindFilter, setCategoryKindFilter] =
|
||||
useState<PlatformCategoryKindFilter>('all');
|
||||
useState<PlatformCategoryKindFilter>(
|
||||
DEFAULT_PLATFORM_CATEGORY_KIND_FILTER,
|
||||
);
|
||||
const [categorySortMode, setCategorySortMode] =
|
||||
useState<PlatformCategorySortMode>('composite');
|
||||
useState<PlatformCategorySortMode>(DEFAULT_PLATFORM_CATEGORY_SORT_MODE);
|
||||
const [isCategoryFilterPanelOpen, setIsCategoryFilterPanelOpen] =
|
||||
useState(false);
|
||||
const [discoverChannel, setDiscoverChannel] =
|
||||
@@ -3674,15 +3659,12 @@ export function RpgEntryHomeView({
|
||||
}, [activeCategoryGroup, categoryKindFilter, categorySortMode]);
|
||||
const activeCategoryRawCount = activeCategoryGroup?.entries.length ?? 0;
|
||||
const activeCategoryFilterLabel =
|
||||
PLATFORM_CATEGORY_KIND_FILTERS.find(
|
||||
(option) => option.id === categoryKindFilter,
|
||||
)?.label ?? '全部';
|
||||
getPlatformCategoryKindFilterOption(categoryKindFilter).label;
|
||||
const activeCategorySortLabel =
|
||||
PLATFORM_CATEGORY_SORT_OPTIONS.find(
|
||||
(option) => option.id === categorySortMode,
|
||||
)?.label ?? '综合';
|
||||
getPlatformCategorySortOption(categorySortMode).label;
|
||||
const activeCategoryFilterCount = activeCategoryEntries.length;
|
||||
const categoryFilterApplied = categoryKindFilter !== 'all';
|
||||
const categoryFilterApplied =
|
||||
categoryKindFilter !== DEFAULT_PLATFORM_CATEGORY_KIND_FILTER;
|
||||
const visibleTabs = useMemo<PlatformHomeTab[]>(
|
||||
() =>
|
||||
isAuthenticated
|
||||
@@ -4633,16 +4615,7 @@ export function RpgEntryHomeView({
|
||||
submitWorkSearch(mobileSearchKeyword);
|
||||
};
|
||||
const cycleCategorySortMode = () => {
|
||||
const currentIndex = PLATFORM_CATEGORY_SORT_OPTIONS.findIndex(
|
||||
(option) => option.id === categorySortMode,
|
||||
);
|
||||
const nextIndex =
|
||||
currentIndex >= 0
|
||||
? (currentIndex + 1) % PLATFORM_CATEGORY_SORT_OPTIONS.length
|
||||
: 0;
|
||||
setCategorySortMode(
|
||||
PLATFORM_CATEGORY_SORT_OPTIONS[nextIndex]?.id ?? 'composite',
|
||||
);
|
||||
setCategorySortMode(getNextPlatformCategorySortMode(categorySortMode));
|
||||
};
|
||||
const desktopHeroEntry =
|
||||
featuredShelf[0] ?? generalLatestEntries[0] ?? myEntries[0] ?? null;
|
||||
|
||||
@@ -7,18 +7,27 @@ import {
|
||||
buildPublicCategoryGroups,
|
||||
buildPublicGalleryCardKey,
|
||||
dedupePlatformPublicGalleryEntries,
|
||||
DEFAULT_PLATFORM_CATEGORY_KIND_FILTER,
|
||||
DEFAULT_PLATFORM_CATEGORY_SORT_MODE,
|
||||
DEFAULT_PLATFORM_RANKING_TAB,
|
||||
filterPlatformWorkSearchResults,
|
||||
filterTodayPublishedEntries,
|
||||
getNextPlatformCategorySortMode,
|
||||
getPlatformCategoryKindFilter,
|
||||
getPlatformCategoryKindFilterOption,
|
||||
getPlatformCategoryPrimaryMetric,
|
||||
getPlatformCategorySortOption,
|
||||
getPlatformPublicEntries,
|
||||
getPlatformRankingMetric,
|
||||
getPlatformRankingMetricValue,
|
||||
getPlatformRankingTabConfig,
|
||||
matchesPlatformCategoryKindFilter,
|
||||
parsePlatformEntryTimestamp,
|
||||
PLATFORM_CATEGORY_KIND_FILTERS,
|
||||
PLATFORM_CATEGORY_SORT_OPTIONS,
|
||||
PLATFORM_RANKING_TABS,
|
||||
type PlatformCategoryKindFilter,
|
||||
type PlatformCategorySortMode,
|
||||
selectAdjacentPlatformRecommendEntry,
|
||||
selectPlatformRecommendFeedWindow,
|
||||
sortPlatformCategoryEntries,
|
||||
@@ -308,6 +317,52 @@ test('public gallery ViewModel keeps source kinds behind one category filter sea
|
||||
);
|
||||
});
|
||||
|
||||
test('public gallery ViewModel exposes category filter and sort option interface', () => {
|
||||
expect(DEFAULT_PLATFORM_CATEGORY_KIND_FILTER).toBe('all');
|
||||
expect(DEFAULT_PLATFORM_CATEGORY_SORT_MODE).toBe('composite');
|
||||
expect(PLATFORM_CATEGORY_KIND_FILTERS.map((option) => option.label)).toEqual([
|
||||
'全部',
|
||||
'拼图',
|
||||
'抓鹅',
|
||||
'方洞',
|
||||
'视觉',
|
||||
'汪汪',
|
||||
'大鱼',
|
||||
'跳跃',
|
||||
'木鱼',
|
||||
'RPG',
|
||||
]);
|
||||
expect(PLATFORM_CATEGORY_SORT_OPTIONS.map((option) => option.label)).toEqual([
|
||||
'综合',
|
||||
'最新',
|
||||
'游玩',
|
||||
'点赞',
|
||||
]);
|
||||
expect(getPlatformCategoryKindFilterOption('match3d')).toEqual({
|
||||
id: 'match3d',
|
||||
label: '抓鹅',
|
||||
});
|
||||
expect(getPlatformCategorySortOption('latest')).toEqual({
|
||||
id: 'latest',
|
||||
label: '最新',
|
||||
});
|
||||
expect(
|
||||
getPlatformCategoryKindFilterOption(
|
||||
'unknown' as PlatformCategoryKindFilter,
|
||||
),
|
||||
).toEqual({ id: 'all', label: '全部' });
|
||||
expect(
|
||||
getPlatformCategorySortOption('unknown' as PlatformCategorySortMode),
|
||||
).toEqual({ id: 'composite', label: '综合' });
|
||||
expect(getNextPlatformCategorySortMode('composite')).toBe('latest');
|
||||
expect(getNextPlatformCategorySortMode('latest')).toBe('play');
|
||||
expect(getNextPlatformCategorySortMode('play')).toBe('like');
|
||||
expect(getNextPlatformCategorySortMode('like')).toBe('composite');
|
||||
expect(
|
||||
getNextPlatformCategorySortMode('unknown' as PlatformCategorySortMode),
|
||||
).toBe('composite');
|
||||
});
|
||||
|
||||
test('public gallery ViewModel ranks entries by selected metric', () => {
|
||||
const playWinner = buildJumpHopEntry({
|
||||
profileId: 'play-winner',
|
||||
|
||||
@@ -37,6 +37,14 @@ export type PlatformCategoryKindFilter =
|
||||
| 'wooden-fish'
|
||||
| 'custom-world';
|
||||
export type PlatformCategorySortMode = 'composite' | 'latest' | 'play' | 'like';
|
||||
export type PlatformCategoryKindFilterOption = {
|
||||
id: PlatformCategoryKindFilter;
|
||||
label: string;
|
||||
};
|
||||
export type PlatformCategorySortOption = {
|
||||
id: PlatformCategorySortMode;
|
||||
label: string;
|
||||
};
|
||||
|
||||
export type PlatformPublicCategoryGroup = {
|
||||
tag: string;
|
||||
@@ -44,6 +52,10 @@ export type PlatformPublicCategoryGroup = {
|
||||
};
|
||||
|
||||
export const DEFAULT_PLATFORM_RANKING_TAB: PlatformRankingTab = 'hot';
|
||||
export const DEFAULT_PLATFORM_CATEGORY_KIND_FILTER: PlatformCategoryKindFilter =
|
||||
'all';
|
||||
export const DEFAULT_PLATFORM_CATEGORY_SORT_MODE: PlatformCategorySortMode =
|
||||
'composite';
|
||||
|
||||
export const PLATFORM_RANKING_TABS: PlatformRankingTabConfig[] = [
|
||||
{
|
||||
@@ -77,6 +89,36 @@ const DEFAULT_PLATFORM_RANKING_CONFIG =
|
||||
(config) => config.id === DEFAULT_PLATFORM_RANKING_TAB,
|
||||
) ?? PLATFORM_RANKING_TABS[0]!;
|
||||
|
||||
export const PLATFORM_CATEGORY_KIND_FILTERS: PlatformCategoryKindFilterOption[] =
|
||||
[
|
||||
{ id: 'all', label: '全部' },
|
||||
{ id: 'puzzle', label: '拼图' },
|
||||
{ id: 'match3d', label: '抓鹅' },
|
||||
{ id: 'square-hole', label: '方洞' },
|
||||
{ id: 'visual-novel', label: '视觉' },
|
||||
{ id: 'bark-battle', label: '汪汪' },
|
||||
{ id: 'big-fish', label: '大鱼' },
|
||||
{ id: 'jump-hop', label: '跳跃' },
|
||||
{ id: 'wooden-fish', label: '木鱼' },
|
||||
{ id: 'custom-world', label: 'RPG' },
|
||||
];
|
||||
|
||||
export const PLATFORM_CATEGORY_SORT_OPTIONS: PlatformCategorySortOption[] = [
|
||||
{ id: 'composite', label: '综合' },
|
||||
{ id: 'latest', label: '最新' },
|
||||
{ id: 'play', label: '游玩' },
|
||||
{ id: 'like', label: '点赞' },
|
||||
];
|
||||
|
||||
const DEFAULT_PLATFORM_CATEGORY_KIND_FILTER_OPTION =
|
||||
PLATFORM_CATEGORY_KIND_FILTERS.find(
|
||||
(option) => option.id === DEFAULT_PLATFORM_CATEGORY_KIND_FILTER,
|
||||
) ?? PLATFORM_CATEGORY_KIND_FILTERS[0]!;
|
||||
const DEFAULT_PLATFORM_CATEGORY_SORT_OPTION =
|
||||
PLATFORM_CATEGORY_SORT_OPTIONS.find(
|
||||
(option) => option.id === DEFAULT_PLATFORM_CATEGORY_SORT_MODE,
|
||||
) ?? PLATFORM_CATEGORY_SORT_OPTIONS[0]!;
|
||||
|
||||
export type PlatformRecommendFeedWindow = {
|
||||
activeEntry: PlatformPublicGalleryCard | null;
|
||||
activeEntryKey: string | null;
|
||||
@@ -552,6 +594,41 @@ export function getPlatformCategoryPrimaryMetric(
|
||||
return { label: '游玩', value: getPlatformWorldPlayCount(entry) };
|
||||
}
|
||||
|
||||
export function getPlatformCategoryKindFilterOption(
|
||||
kindFilter: PlatformCategoryKindFilter,
|
||||
): PlatformCategoryKindFilterOption {
|
||||
return (
|
||||
PLATFORM_CATEGORY_KIND_FILTERS.find((option) => option.id === kindFilter) ??
|
||||
DEFAULT_PLATFORM_CATEGORY_KIND_FILTER_OPTION
|
||||
);
|
||||
}
|
||||
|
||||
export function getPlatformCategorySortOption(
|
||||
sortMode: PlatformCategorySortMode,
|
||||
): PlatformCategorySortOption {
|
||||
return (
|
||||
PLATFORM_CATEGORY_SORT_OPTIONS.find((option) => option.id === sortMode) ??
|
||||
DEFAULT_PLATFORM_CATEGORY_SORT_OPTION
|
||||
);
|
||||
}
|
||||
|
||||
export function getNextPlatformCategorySortMode(
|
||||
sortMode: PlatformCategorySortMode,
|
||||
): PlatformCategorySortMode {
|
||||
const currentIndex = PLATFORM_CATEGORY_SORT_OPTIONS.findIndex(
|
||||
(option) => option.id === sortMode,
|
||||
);
|
||||
const nextIndex =
|
||||
currentIndex >= 0
|
||||
? (currentIndex + 1) % PLATFORM_CATEGORY_SORT_OPTIONS.length
|
||||
: 0;
|
||||
|
||||
return (
|
||||
PLATFORM_CATEGORY_SORT_OPTIONS[nextIndex]?.id ??
|
||||
DEFAULT_PLATFORM_CATEGORY_SORT_MODE
|
||||
);
|
||||
}
|
||||
|
||||
export function parsePlatformEntryTimestamp(value: string | null | undefined) {
|
||||
if (!value) {
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user