diff --git a/components/home/SearchResults.tsx b/components/home/SearchResults.tsx
index cab6a74..edc9c38 100644
--- a/components/home/SearchResults.tsx
+++ b/components/home/SearchResults.tsx
@@ -2,9 +2,11 @@
import { ResultsHeader } from '@/components/search/ResultsHeader';
import { SourceBadges } from '@/components/search/SourceBadges';
import { TypeBadges } from '@/components/search/TypeBadges';
+import { LanguageBadges } from '@/components/search/LanguageBadges';
import { VideoGrid } from '@/components/search/VideoGrid';
import { useSourceBadges } from '@/lib/hooks/useSourceBadges';
import { useTypeBadges } from '@/lib/hooks/useTypeBadges';
+import { useLanguageBadges } from '@/lib/hooks/useLanguageBadges';
import { Video, SourceBadge } from '@/lib/types';
interface SearchResultsProps {
@@ -34,10 +36,19 @@ export function SearchResults({
const {
typeBadges,
selectedTypes,
- filteredVideos: finalFilteredVideos,
+ filteredVideos: typeFilteredVideos,
toggleType,
} = useTypeBadges(sourceFilteredVideos);
+ // Language badges hook - auto-collects and filters by vod_lang
+ // Apply on type-filtered results for combined filtering
+ const {
+ languageBadges,
+ selectedLangs,
+ filteredVideos: finalFilteredVideos,
+ toggleLang,
+ } = useLanguageBadges(typeFilteredVideos);
+
if (results.length === 0 && !loading) return null;
return (
@@ -68,7 +79,17 @@ export function SearchResults({
/>
)}
- {/* Display filtered videos (both source and type filters applied) */}
+ {/* Language Badges - Auto-collected from search results */}
+ {languageBadges.length > 0 && (
+
+ )}
+
+ {/* Display filtered videos (source, type, and language filters applied) */}
)}
+ {videoData?.vod_lang && (
+
+
+ {videoData.vod_lang}
+
+ )}
{videoData?.vod_content && (
diff --git a/components/search/LanguageBadges.tsx b/components/search/LanguageBadges.tsx
new file mode 100644
index 0000000..83b643c
--- /dev/null
+++ b/components/search/LanguageBadges.tsx
@@ -0,0 +1,92 @@
+/**
+ * LanguageBadges - Language filter badge component
+ * Mirrors TypeBadges pattern, reuses TypeBadgeItem for individual badges
+ */
+
+'use client';
+
+import { memo } from 'react';
+import { Card } from '@/components/ui/Card';
+import { Icons } from '@/components/ui/Icon';
+import { TypeBadgeItem } from './TypeBadgeItem';
+import type { LanguageBadge } from '@/lib/types';
+
+interface LanguageBadgesProps {
+ badges: LanguageBadge[];
+ selectedLangs: Set;
+ onToggleLang: (lang: string) => void;
+ className?: string;
+}
+
+export const LanguageBadges = memo(function LanguageBadges({
+ badges,
+ selectedLangs,
+ onToggleLang,
+ className = ''
+}: LanguageBadgesProps) {
+ if (badges.length === 0) {
+ return null;
+ }
+
+ const handleClearAll = () => {
+ selectedLangs.forEach(lang => onToggleLang(lang));
+ };
+
+ return (
+
+
+
+
+
+ 语言标签 ({badges.length}):
+
+
+
+ {/* Desktop: flex wrap, Mobile: horizontal scroll */}
+
+
+ {badges.map((badge) => (
+ onToggleLang(badge.lang)}
+ />
+ ))}
+
+
+
+
+
+ {badges.map((badge) => (
+ onToggleLang(badge.lang)}
+ />
+ ))}
+
+
+
+
+ {selectedLangs.size > 0 && (
+
+
+
+ )}
+
+ );
+});
diff --git a/components/search/VideoCard.tsx b/components/search/VideoCard.tsx
index a178b57..4d79a20 100644
--- a/components/search/VideoCard.tsx
+++ b/components/search/VideoCard.tsx
@@ -168,6 +168,11 @@ export const VideoCard = memo(({
{video.vod_remarks}
)}
+ {video.vod_lang && (
+
+ {video.vod_lang}
+
+ )}
>
);
})()}
diff --git a/components/search/VideoGroupCard.tsx b/components/search/VideoGroupCard.tsx
index 0b7a314..32b57ee 100644
--- a/components/search/VideoGroupCard.tsx
+++ b/components/search/VideoGroupCard.tsx
@@ -202,6 +202,11 @@ export const VideoGroupCard = memo(({
{displayQuality}
)}
+ {representative.vod_lang && (
+
+ {representative.vod_lang}
+
+ )}
>
);
})()}
diff --git a/components/ui/icons/utility-icons.tsx b/components/ui/icons/utility-icons.tsx
index 98321a8..82779a1 100644
--- a/components/ui/icons/utility-icons.tsx
+++ b/components/ui/icons/utility-icons.tsx
@@ -172,6 +172,17 @@ export const UtilityIcons = {
),
+ Languages: ({ className = "", size = 24 }: IconProps) => (
+
+ ),
+
Settings: ({ className = "", size = 24 }: IconProps) => (