113 lines
2.5 KiB
TypeScript
113 lines
2.5 KiB
TypeScript
import React from 'react'
|
|
import {
|
|
View,
|
|
Text,
|
|
StyleSheet,
|
|
ScrollView,
|
|
TouchableOpacity,
|
|
} from 'react-native'
|
|
import { LinearGradient } from 'expo-linear-gradient'
|
|
|
|
export interface Announcement {
|
|
id: string
|
|
title: string
|
|
content?: string
|
|
link?: string
|
|
createdAt: Date
|
|
}
|
|
|
|
export interface AnnouncementBannerProps {
|
|
announcements: Announcement[]
|
|
onPress?: (announcement: Announcement) => void
|
|
}
|
|
|
|
const GRADIENT_COLORS = ['#FF9966', '#FF6699', '#9966FF'] as const
|
|
|
|
export const AnnouncementBanner: React.FC<AnnouncementBannerProps> = ({
|
|
announcements,
|
|
onPress,
|
|
}) => {
|
|
// 无公告时不渲染
|
|
if (!announcements || announcements.length === 0) {
|
|
return null
|
|
}
|
|
|
|
const handlePress = (announcement: Announcement) => {
|
|
onPress?.(announcement)
|
|
}
|
|
|
|
return (
|
|
<View testID="announcement-banner" style={styles.container}>
|
|
<LinearGradient
|
|
testID="gradient-container"
|
|
colors={[...GRADIENT_COLORS]}
|
|
start={{ x: 0, y: 0 }}
|
|
end={{ x: 1, y: 0 }}
|
|
style={styles.gradientContainer}
|
|
>
|
|
<View testID="announcement-icon" style={styles.iconContainer}>
|
|
<Text style={styles.icon}>📢</Text>
|
|
</View>
|
|
<ScrollView
|
|
testID="announcement-scroll-view"
|
|
horizontal
|
|
showsHorizontalScrollIndicator={false}
|
|
style={styles.scrollView}
|
|
contentContainerStyle={styles.scrollContent}
|
|
>
|
|
{announcements.map((announcement) => (
|
|
<TouchableOpacity
|
|
key={announcement.id}
|
|
testID={`announcement-item-${announcement.id}`}
|
|
style={styles.announcementItem}
|
|
onPress={() => handlePress(announcement)}
|
|
activeOpacity={0.7}
|
|
>
|
|
<Text style={styles.title} numberOfLines={1}>
|
|
{announcement.title}
|
|
</Text>
|
|
</TouchableOpacity>
|
|
))}
|
|
</ScrollView>
|
|
</LinearGradient>
|
|
</View>
|
|
)
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
marginHorizontal: 16,
|
|
marginVertical: 8,
|
|
borderRadius: 12,
|
|
overflow: 'hidden',
|
|
},
|
|
gradientContainer: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
paddingVertical: 12,
|
|
paddingHorizontal: 12,
|
|
},
|
|
iconContainer: {
|
|
marginRight: 8,
|
|
},
|
|
icon: {
|
|
fontSize: 18,
|
|
},
|
|
scrollView: {
|
|
flex: 1,
|
|
},
|
|
scrollContent: {
|
|
alignItems: 'center',
|
|
},
|
|
announcementItem: {
|
|
marginRight: 16,
|
|
},
|
|
title: {
|
|
color: '#FFFFFF',
|
|
fontSize: 14,
|
|
fontWeight: '500',
|
|
},
|
|
})
|
|
|
|
export default AnnouncementBanner
|