Skip to content

Commit d0f02a4

Browse files
committed
Added empty Recap page
1 parent bc7e346 commit d0f02a4

File tree

6 files changed

+104
-6
lines changed

6 files changed

+104
-6
lines changed

Cargo.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "koshelf"
3-
version = "1.4.3"
3+
version = "1.4.4"
44
description = "Transform your KOReader library into a beautiful reading dashboard with statistics."
55
repository = "https://github.com/paviro/KOShelf"
66
license = "EUPL-1.2 license"

src/site_generator/recap.rs

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use super::SiteGenerator;
44
use super::utils::{format_duration, format_day_month};
55
use crate::models::{Book, StatisticsData, RecapItem, MonthRecap, YearlySummary};
6-
use crate::templates::RecapTemplate;
6+
use crate::templates::{RecapTemplate, RecapEmptyTemplate};
77
use anyhow::Result;
88
use askama::Template;
99
use chrono::Datelike;
@@ -101,7 +101,20 @@ impl SiteGenerator {
101101
}
102102

103103
if years.is_empty() {
104-
// No completions → don't generate recap pages
104+
// No completions → render empty state page
105+
let template = RecapEmptyTemplate {
106+
site_title: self.site_title.clone(),
107+
version: self.get_version(),
108+
last_updated: self.get_last_updated(),
109+
navbar_items: self.create_navbar_items_with_recap("recap", None),
110+
};
111+
112+
let html = template.render()?;
113+
let recap_dir = self.recap_dir();
114+
fs::create_dir_all(&recap_dir)?;
115+
let path = recap_dir.join("index.html");
116+
self.write_minify_html(path, &html)?;
117+
105118
return Ok(());
106119
}
107120

src/site_generator/utils.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,8 +106,8 @@ impl SiteGenerator {
106106

107107
pub(crate) fn create_navbar_items_with_recap(&self, current_page: &str, recap_latest_href: Option<&str>) -> Vec<NavItem> {
108108
let mut items = self.create_navbar_items(current_page);
109-
if self.statistics_db_path.is_some()
110-
&& let Some(href) = recap_latest_href {
109+
if self.statistics_db_path.is_some() {
110+
let href = recap_latest_href.unwrap_or("/recap/");
111111
items.push(NavItem {
112112
label: "Recap".to_string(),
113113
href: href.to_string(),

src/templates.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,15 @@ pub struct RecapTemplate {
3737
pub navbar_items: Vec<NavItem>,
3838
}
3939

40+
#[derive(Template)]
41+
#[template(path = "recap/recap_empty.html", whitespace = "minimize")]
42+
pub struct RecapEmptyTemplate {
43+
pub site_title: String,
44+
pub version: String,
45+
pub last_updated: String,
46+
pub navbar_items: Vec<NavItem>,
47+
}
48+
4049
#[derive(Template)]
4150
#[template(path = "book_details/book_details.html", whitespace = "minimize")]
4251
pub struct BookTemplate {

templates/recap/recap_empty.html

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
<!DOCTYPE html>
2+
<html lang="en" class="h-full">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Recap - {{ site_title }}</title>
7+
<link rel="stylesheet" href="/assets/css/style.css">
8+
<link rel="manifest" href="/manifest.json">
9+
<meta name="theme-color" content="#6366f1">
10+
<meta name="apple-mobile-web-app-capable" content="yes">
11+
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
12+
</head>
13+
<body class="min-h-full bg-gray-100 dark:bg-dark-900 text-gray-900 dark:text-white font-sans">
14+
{% include "sidebar.html" %}
15+
16+
<div class="min-h-full lg:ml-64">
17+
<header class="fixed top-0 left-0 right-0 lg:left-64 bg-white/90 dark:bg-dark-850/95 backdrop-blur-sm border-b border-gray-200/50 dark:border-dark-700/50 px-4 md:px-6 h-[70px] md:h-[80px] z-40">
18+
<div class="flex items-center justify-between h-full">
19+
<!-- Mobile title -->
20+
<div class="lg:hidden flex items-center">
21+
<h1 class="text-lg md:text-2xl font-bold text-gray-900 dark:text-white truncate">Recap</h1>
22+
</div>
23+
24+
<!-- Desktop title -->
25+
<h2 class="hidden lg:block text-2xl font-bold text-gray-900 dark:text-white">Recap</h2>
26+
</div>
27+
</header>
28+
29+
<main class="pt-[88px] md:pt-24 pb-28 md:pb-6 px-4 md:px-6">
30+
<div id="dynamicEmptyState" class="flex flex-col items-center justify-center text-center" style="min-height: calc(100vh - 88px - 7rem); padding-top: 2rem; padding-bottom: 2rem;">
31+
<div class="relative mb-8">
32+
<!-- Gradient Background Circle (Purple/Pink for Recap theme) -->
33+
<div class="absolute inset-0 w-32 h-32 bg-gradient-to-br from-purple-500/20 to-pink-500/20 rounded-full blur-2xl"></div>
34+
<!-- Icon Container -->
35+
<div class="relative w-24 h-24 bg-gradient-to-br from-purple-500 to-pink-500 rounded-2xl flex items-center justify-center shadow-2xl">
36+
<svg class="w-12 h-12 text-white" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="1.5">
37+
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 00-3.375-3.375h-1.5A1.125 1.125 0 0113.5 7.125v-1.5a3.375 3.375 0 00-3.375-3.375H8.25m0 12.75h7.5m-7.5 3H12M10.5 2.25H5.625c-.621 0-1.125.504-1.125 1.125v17.25c0 .621.504 1.125 1.125 1.125h12.75c.621 0 1.125-.504 1.125-1.125V11.25a9 9 0 00-9-9z" />
38+
</svg>
39+
</div>
40+
</div>
41+
<h3 class="text-2xl md:text-3xl font-bold text-gray-900 dark:text-white mb-4">No Books Found</h3>
42+
<p class="text-lg text-gray-600 dark:text-dark-300 mb-8 max-w-md leading-relaxed">
43+
Finish reading a book in KoReader to see your recap.
44+
</p>
45+
46+
<!-- Info Box -->
47+
<div class="max-w-md mx-auto">
48+
<details class="group bg-white dark:bg-dark-800/40 border border-gray-200/60 dark:border-dark-700/60 rounded-lg overflow-hidden transition-all duration-300 open:shadow-sm">
49+
<summary class="flex items-center justify-between p-4 cursor-pointer select-none text-sm font-medium text-gray-600 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-dark-700/50 transition-colors list-none [&::-webkit-details-marker]:hidden">
50+
<div class="flex items-center gap-3">
51+
<svg class="w-5 h-5 text-gray-400 dark:text-gray-500 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24">
52+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
53+
</svg>
54+
<span>Why aren't my books showing up?</span>
55+
</div>
56+
<svg class="w-4 h-4 text-gray-400 transform transition-transform duration-200 group-open:rotate-180 ml-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
57+
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" />
58+
</svg>
59+
</summary>
60+
<div class="px-4 pb-4 pt-4 text-left text-sm text-gray-500 dark:text-gray-400 ml-8 leading-relaxed">
61+
<p>
62+
KoShelf uses reading statistics to detect completions, which allows tracking re-reads.
63+
Simply marking a book as "finished" without reading data will not make it appear here.
64+
</p>
65+
</div>
66+
</details>
67+
</div>
68+
</div>
69+
</main>
70+
</div>
71+
72+
{% include "bottom_navbar.html" %}
73+
74+
<script type="module" src="/assets/js/pwa.js"></script>
75+
</body>
76+
</html>

0 commit comments

Comments
 (0)