Add reading time and page info to book display
This commit is contained in:
@@ -1,3 +1,7 @@
|
|||||||
|
### 2026-02-01: 1.0.2
|
||||||
|
|
||||||
|
* Add reading time and page info to book metadata display
|
||||||
|
|
||||||
### 2026-02-01: 1.0.1
|
### 2026-02-01: 1.0.1
|
||||||
|
|
||||||
* Persist book metadata to localStorage
|
* Persist book metadata to localStorage
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# ⚡ Speed reader
|
# ⚡ Speed reader
|
||||||
|
|
||||||

|

|
||||||

|

|
||||||

|

|
||||||

|

|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "rsvp-speed-reader",
|
"name": "rsvp-speed-reader",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.1",
|
"version": "1.0.2",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
+27
@@ -223,6 +223,19 @@ function getWordDelay(word, baseDelay) {
|
|||||||
return baseDelay * multiplier;
|
return baseDelay * multiplier;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Format reading time in human-readable format
|
||||||
|
function formatReadingTime(minutes) {
|
||||||
|
if (minutes < 1) return "< 1 min";
|
||||||
|
if (minutes < 60) return `${Math.round(minutes)} min`;
|
||||||
|
const hours = Math.floor(minutes / 60);
|
||||||
|
const mins = Math.round(minutes % 60);
|
||||||
|
if (mins === 0) return `${hours}h`;
|
||||||
|
return `${hours}h ${mins}m`;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Words per page (standard estimate)
|
||||||
|
const WORDS_PER_PAGE = 250;
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
// Load settings only once on mount
|
// Load settings only once on mount
|
||||||
const [savedSettings] = useState(() => loadSettings());
|
const [savedSettings] = useState(() => loadSettings());
|
||||||
@@ -662,6 +675,15 @@ function App() {
|
|||||||
{bookMetadata.author && (
|
{bookMetadata.author && (
|
||||||
<div style={styles.bookAuthor}>{bookMetadata.author}</div>
|
<div style={styles.bookAuthor}>{bookMetadata.author}</div>
|
||||||
)}
|
)}
|
||||||
|
<div style={styles.bookStats}>
|
||||||
|
{(() => {
|
||||||
|
const currentPage = Math.floor(currentIndex / WORDS_PER_PAGE) + 1;
|
||||||
|
const totalPages = Math.max(1, Math.ceil(words.length / WORDS_PER_PAGE));
|
||||||
|
const remainingWords = words.length - currentIndex;
|
||||||
|
const remainingMinutes = remainingWords / wpm;
|
||||||
|
return `Page ${currentPage}/${totalPages} · ${formatReadingTime(remainingMinutes)} left`;
|
||||||
|
})()}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -1317,6 +1339,11 @@ const styles = {
|
|||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
textOverflow: "ellipsis",
|
textOverflow: "ellipsis",
|
||||||
},
|
},
|
||||||
|
bookStats: {
|
||||||
|
fontSize: "0.65rem",
|
||||||
|
color: "#444",
|
||||||
|
marginTop: "2px",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
export default App;
|
export default App;
|
||||||
|
|||||||
Reference in New Issue
Block a user