You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
78 lines
2.1 KiB
78 lines
2.1 KiB
/**
|
|
* 星级打分 / 星级展示组件。
|
|
*
|
|
* 岗位评价(app/jobs/[id].tsx)与候选人反馈(app/application-detail.tsx)都要用,
|
|
* 所以提到 components 层只留一份 —— 两处各写一份的话,改星色或改最大星数时必然漏改一处。
|
|
*
|
|
* 只读态用「实心 / 描边」区分而不只靠颜色:色觉障碍用户也要能读出分数(WCAG 1.4.1)。
|
|
*/
|
|
import { Ionicons } from '@expo/vector-icons';
|
|
import { Pressable, StyleSheet, View } from 'react-native';
|
|
import { colors } from '../src/theme';
|
|
|
|
/**
|
|
* 星色。候选项详情、岗位评价页此前都用 compareOrange 画星,
|
|
* 这里沿用同一语义色,不新造 token。
|
|
*/
|
|
export const STAR_COLOR = colors.compareOrange;
|
|
|
|
export function RatingStars({
|
|
value,
|
|
max = 5,
|
|
size = 14,
|
|
onChange,
|
|
}: {
|
|
/** 当前分值,0 表示未评分 */
|
|
value: number;
|
|
/** 满星数,默认 5 */
|
|
max?: number;
|
|
size?: number;
|
|
/** 传了就是可点打分(编辑器内用),不传即只读展示 */
|
|
onChange?: (next: number) => void;
|
|
}) {
|
|
const readonly = !onChange;
|
|
return (
|
|
<View style={styles.row}>
|
|
{Array.from({ length: max }, (_, i) => {
|
|
const starValue = i + 1;
|
|
const filled = starValue <= value;
|
|
const star = (
|
|
<Ionicons
|
|
name={filled ? 'star' : 'star-outline'}
|
|
size={size}
|
|
color={filled ? STAR_COLOR : colors.borderStrong}
|
|
/>
|
|
);
|
|
if (readonly) {
|
|
return (
|
|
<View key={starValue} style={styles.cell}>
|
|
{star}
|
|
</View>
|
|
);
|
|
}
|
|
return (
|
|
<Pressable
|
|
key={starValue}
|
|
style={styles.cell}
|
|
hitSlop={6}
|
|
onPress={() => onChange(starValue)}
|
|
accessibilityRole="button"
|
|
accessibilityLabel={`打 ${starValue} 分`}
|
|
>
|
|
{star}
|
|
</Pressable>
|
|
);
|
|
})}
|
|
</View>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
row: {
|
|
flexDirection: 'row',
|
|
alignItems: 'center',
|
|
},
|
|
cell: {
|
|
paddingHorizontal: 1,
|
|
},
|
|
});
|
|
|