Archived
153 lines
3.5 KiB
TypeScript
153 lines
3.5 KiB
TypeScript
import { type ReactNode } from "react";
|
||
import { View, Text, TouchableOpacity, StyleSheet } from "react-native";
|
||
import { resolvePalette } from "../../utils/epubTheme";
|
||
import type { ReadingSettings } from "../../types/reader";
|
||
|
||
interface ReaderToolbarProps {
|
||
title: string;
|
||
chapterTitle: string;
|
||
progressPct: number;
|
||
settings: ReadingSettings;
|
||
isBookmarked: boolean;
|
||
onBack: () => void;
|
||
onToggleToc: () => void;
|
||
onToggleSettings: () => void;
|
||
onToggleBookmarks: () => void;
|
||
onToggleBookmarkHere: () => void;
|
||
}
|
||
|
||
export function ReaderToolbar({
|
||
title,
|
||
chapterTitle,
|
||
progressPct,
|
||
settings,
|
||
isBookmarked,
|
||
onBack,
|
||
onToggleToc,
|
||
onToggleSettings,
|
||
onToggleBookmarks,
|
||
onToggleBookmarkHere,
|
||
}: ReaderToolbarProps): ReactNode {
|
||
const palette = resolvePalette(settings);
|
||
|
||
return (
|
||
<View style={[styles.bar, { backgroundColor: palette.chrome }]}>
|
||
<View style={styles.row}>
|
||
<TouchableOpacity
|
||
onPress={onBack}
|
||
hitSlop={12}
|
||
style={styles.iconButton}
|
||
>
|
||
<Text style={[styles.icon, { color: palette.text }]}>‹</Text>
|
||
</TouchableOpacity>
|
||
|
||
<View style={styles.titles}>
|
||
<Text
|
||
style={[styles.title, { color: palette.text }]}
|
||
numberOfLines={1}
|
||
>
|
||
{title}
|
||
</Text>
|
||
{chapterTitle ? (
|
||
<Text
|
||
style={[styles.chapter, { color: palette.text }]}
|
||
numberOfLines={1}
|
||
>
|
||
{chapterTitle}
|
||
</Text>
|
||
) : null}
|
||
</View>
|
||
|
||
<TouchableOpacity
|
||
onPress={onToggleBookmarkHere}
|
||
hitSlop={12}
|
||
style={styles.iconButton}
|
||
>
|
||
<Text style={[styles.icon, { color: palette.text }]}>
|
||
{isBookmarked ? "★" : "☆"}
|
||
</Text>
|
||
</TouchableOpacity>
|
||
<TouchableOpacity
|
||
onPress={onToggleBookmarks}
|
||
hitSlop={12}
|
||
style={styles.iconButton}
|
||
>
|
||
<Text style={[styles.iconSmall, { color: palette.text }]}>≡</Text>
|
||
</TouchableOpacity>
|
||
<TouchableOpacity
|
||
onPress={onToggleToc}
|
||
hitSlop={12}
|
||
style={styles.iconButton}
|
||
>
|
||
<Text style={[styles.iconSmall, { color: palette.text }]}>⊟</Text>
|
||
</TouchableOpacity>
|
||
<TouchableOpacity
|
||
onPress={onToggleSettings}
|
||
hitSlop={12}
|
||
style={styles.iconButton}
|
||
>
|
||
<Text style={[styles.iconSmall, { color: palette.text }]}>Aa</Text>
|
||
</TouchableOpacity>
|
||
</View>
|
||
|
||
<View style={styles.progressTrack}>
|
||
<View
|
||
style={[
|
||
styles.progressFill,
|
||
{ width: `${Math.min(100, Math.max(0, progressPct))}%` },
|
||
]}
|
||
/>
|
||
</View>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
const styles = StyleSheet.create({
|
||
bar: {
|
||
paddingTop: 8,
|
||
paddingHorizontal: 8,
|
||
paddingBottom: 6,
|
||
},
|
||
row: {
|
||
flexDirection: "row",
|
||
alignItems: "center",
|
||
},
|
||
titles: {
|
||
flex: 1,
|
||
marginHorizontal: 8,
|
||
},
|
||
title: {
|
||
fontSize: 14,
|
||
fontWeight: "600",
|
||
},
|
||
chapter: {
|
||
fontSize: 11,
|
||
opacity: 0.7,
|
||
},
|
||
iconButton: {
|
||
paddingHorizontal: 8,
|
||
paddingVertical: 4,
|
||
minWidth: 28,
|
||
alignItems: "center",
|
||
},
|
||
icon: {
|
||
fontSize: 28,
|
||
lineHeight: 30,
|
||
},
|
||
iconSmall: {
|
||
fontSize: 17,
|
||
fontWeight: "600",
|
||
},
|
||
progressTrack: {
|
||
height: 3,
|
||
borderRadius: 2,
|
||
backgroundColor: "rgba(127,127,127,0.25)",
|
||
marginTop: 6,
|
||
overflow: "hidden",
|
||
},
|
||
progressFill: {
|
||
height: "100%",
|
||
backgroundColor: "#4f8ef7",
|
||
},
|
||
});
|