← スキル一覧に戻る

ui-components
by chiraitori
Ad-Free Manga Reader for Android & iOS base on Paperback
⭐ 2🍴 0📅 2026年1月15日
SKILL.md
name: UI Components description: Reusable component patterns and styling
UI Components
MangaCard
interface MangaCardProps {
manga: Manga;
onPress: () => void;
width?: number;
}
function MangaCard({ manga, onPress, width = 120 }: MangaCardProps) {
const { colors } = useTheme();
return (
<Pressable onPress={onPress} style={[styles.card, { width }]}>
<Image
source={{ uri: manga.image }}
style={[styles.cover, { height: width * 1.5 }]}
contentFit="cover"
cachePolicy="memory-disk"
/>
<Text style={[styles.title, { color: colors.text }]} numberOfLines={2}>
{manga.title}
</Text>
</Pressable>
);
}
ChapterListItem
interface ChapterItemProps {
chapter: Chapter;
isRead: boolean;
onPress: () => void;
}
function ChapterListItem({ chapter, isRead, onPress }: ChapterItemProps) {
const { colors } = useTheme();
return (
<Pressable onPress={onPress} style={styles.item}>
<View style={styles.row}>
<Text style={[
styles.title,
{ color: isRead ? colors.textSecondary : colors.text }
]}>
Chapter {chapter.chapNum}
</Text>
<Text style={[styles.date, { color: colors.textSecondary }]}>
{formatDate(chapter.time)}
</Text>
</View>
</Pressable>
);
}
LoadingIndicator
function LoadingIndicator({ size = 'large' }) {
const { colors } = useTheme();
return (
<View style={styles.center}>
<ActivityIndicator size={size} color={colors.primary} />
</View>
);
}
EmptyState
interface EmptyStateProps {
icon: string;
title: string;
message?: string;
action?: { label: string; onPress: () => void };
}
function EmptyState({ icon, title, message, action }: EmptyStateProps) {
const { colors } = useTheme();
return (
<View style={styles.container}>
<Ionicons name={icon} size={64} color={colors.textSecondary} />
<Text style={[styles.title, { color: colors.text }]}>{title}</Text>
{message && (
<Text style={[styles.message, { color: colors.textSecondary }]}>
{message}
</Text>
)}
{action && (
<Pressable onPress={action.onPress} style={styles.button}>
<Text style={{ color: colors.primary }}>{action.label}</Text>
</Pressable>
)}
</View>
);
}
PickerModal
interface PickerModalProps<T> {
visible: boolean;
title: string;
options: { label: string; value: T }[];
selected: T;
onSelect: (value: T) => void;
onClose: () => void;
}
function PickerModal<T>({ visible, title, options, selected, onSelect, onClose }) {
const { colors } = useTheme();
return (
<Modal visible={visible} transparent animationType="fade">
<Pressable style={styles.overlay} onPress={onClose}>
<View style={[styles.modal, { backgroundColor: colors.card }]}>
<Text style={[styles.title, { color: colors.text }]}>{title}</Text>
{options.map((option) => (
<Pressable
key={String(option.value)}
onPress={() => { onSelect(option.value); onClose(); }}
style={styles.option}
>
<Text style={{ color: colors.text }}>{option.label}</Text>
{selected === option.value && (
<Ionicons name="checkmark" color={colors.primary} />
)}
</Pressable>
))}
</View>
</Pressable>
</Modal>
);
}
Haptic Feedback
import * as Haptics from 'expo-haptics';
// Light tap
Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
// Selection change
Haptics.selectionAsync();
// Success/error
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
Blur Effect
import { BlurView } from 'expo-blur';
<BlurView intensity={80} tint="dark" style={styles.blur}>
<Text>Content over blur</Text>
</BlurView>
Linear Gradient
import { LinearGradient } from 'expo-linear-gradient';
<LinearGradient
colors={['transparent', 'rgba(0,0,0,0.8)']}
style={styles.gradient}
/>
Pull to Refresh
<FlatList
data={data}
refreshControl={
<RefreshControl
refreshing={refreshing}
onRefresh={handleRefresh}
tintColor={colors.primary}
/>
}
/>
スコア
総合スコア
50/100
リポジトリの品質指標に基づく評価
✓SKILL.md
SKILL.mdファイルが含まれている
+20
○LICENSE
ライセンスが設定されている
0/10
○説明文
100文字以上の説明がある
0/10
○人気
GitHub Stars 100以上
0/15
○最近の活動
3ヶ月以内に更新がある
0/10
○フォーク
10回以上フォークされている
0/5
✓Issue管理
オープンIssueが50未満
+5
✓言語
プログラミング言語が設定されている
+5
○タグ
1つ以上のタグが設定されている
0/5
レビュー
💬
レビュー機能は近日公開予定です