This repository has been archived on 2026-07-21. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
cloud-reader/mobile/src/components/reader/BookmarksModal.tsx
T
crisleo94 22ded87250 feat: implement mobile reader
- implement mobile epub reader
2026-06-20 13:33:44 -05:00

148 lines
3.5 KiB
TypeScript

import { type ReactNode } from "react";
import {
Text,
FlatList,
TouchableOpacity,
StyleSheet,
View,
} from "react-native";
import { resolvePalette } from "../../utils/epubTheme";
import type { ReadingSettings } from "../../types/reader";
import type { Bookmark } from "../../types";
import { ReaderBottomSheet } from "./ReaderBottomSheet";
interface BookmarksModalProps {
visible: boolean;
bookmarks: Bookmark[];
settings: ReadingSettings;
onSelect: (bookmark: Bookmark) => void;
onDelete: (bookmark: Bookmark) => void;
onClose: () => void;
}
export function BookmarksModal({
visible,
bookmarks,
settings,
onSelect,
onDelete,
onClose,
}: BookmarksModalProps): ReactNode {
const palette = resolvePalette(settings);
return (
<ReaderBottomSheet
visible={visible}
title="Bookmarks & highlights"
chromeColor={palette.chrome}
textColor={palette.text}
onClose={onClose}
>
<FlatList
data={bookmarks}
keyExtractor={(item) => item.id}
ListEmptyComponent={
<Text style={[styles.empty, { color: palette.text }]}>
No bookmarks yet. Tap the star to bookmark a page, or select text to
highlight it.
</Text>
}
renderItem={({ item }) => (
<View style={styles.row}>
<TouchableOpacity
style={styles.rowMain}
onPress={() => onSelect(item)}
>
{item.highlight_color ? (
<View
style={[
styles.dot,
{ backgroundColor: item.highlight_color },
]}
/>
) : (
<Text style={styles.star}></Text>
)}
<View style={styles.rowTextWrap}>
{item.chapter_title ? (
<Text
style={[styles.chapter, { color: palette.text }]}
numberOfLines={1}
>
{item.chapter_title}
</Text>
) : null}
<Text
style={[styles.excerpt, { color: palette.text }]}
numberOfLines={2}
>
{item.content || item.location_text || "Bookmarked page"}
</Text>
</View>
</TouchableOpacity>
<TouchableOpacity
onPress={() => onDelete(item)}
hitSlop={8}
style={styles.deleteButton}
>
<Text style={styles.deleteText}>Delete</Text>
</TouchableOpacity>
</View>
)}
/>
</ReaderBottomSheet>
);
}
const styles = StyleSheet.create({
row: {
flexDirection: "row",
alignItems: "center",
paddingVertical: 12,
paddingHorizontal: 16,
borderTopWidth: StyleSheet.hairlineWidth,
borderTopColor: "rgba(127,127,127,0.2)",
},
rowMain: {
flex: 1,
flexDirection: "row",
alignItems: "center",
},
rowTextWrap: {
flex: 1,
marginLeft: 10,
},
star: {
fontSize: 16,
color: "#4f8ef7",
},
dot: {
width: 14,
height: 14,
borderRadius: 7,
},
chapter: {
fontSize: 12,
opacity: 0.7,
marginBottom: 2,
},
excerpt: {
fontSize: 14,
},
deleteButton: {
marginLeft: 12,
paddingHorizontal: 10,
paddingVertical: 6,
},
deleteText: {
color: "#ff453a",
fontSize: 13,
fontWeight: "600",
},
empty: {
padding: 24,
textAlign: "center",
opacity: 0.7,
},
});