this repo has no description
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add first pass at stats page

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

+113
+5
crates/tala-srs/src/lib.rs
··· 212 212 format_date(today_naive()) 213 213 } 214 214 215 + /// Returns the date `offset_days` from today as `"YYYY-MM-DD"`. 216 + pub fn date_offset(offset_days: i64) -> String { 217 + format_date(add_days_to_ymd(today_naive(), offset_days)) 218 + } 219 + 215 220 /// Returns true if `schedule.due <= today` (card is due). 216 221 pub fn is_due(schedule: &Schedule) -> bool { 217 222 schedule.due.as_str() <= today_str().as_str()
+103
crates/tala/assets/main.css
··· 247 247 font-family: 'JetBrains Mono', 'Fira Code', monospace; 248 248 } 249 249 250 + /* ── Stats page ──────────────────────────────────────────────────────────── */ 251 + #stats { 252 + padding: 32px 40px; 253 + flex: 1; 254 + overflow-y: auto; 255 + } 256 + 257 + #stats h2 { 258 + margin-top: 0; 259 + font-size: 20px; 260 + color: #c8d0e8; 261 + } 262 + 263 + #stats h3 { 264 + font-size: 14px; 265 + color: #8892aa; 266 + font-weight: 500; 267 + margin-bottom: 12px; 268 + } 269 + 270 + .stats-summary { 271 + display: flex; 272 + gap: 16px; 273 + margin-bottom: 32px; 274 + } 275 + 276 + .stat-box { 277 + display: flex; 278 + flex-direction: column; 279 + align-items: center; 280 + padding: 14px 24px; 281 + background: #13151c; 282 + border: 1px solid #1e2130; 283 + border-radius: 6px; 284 + min-width: 90px; 285 + } 286 + 287 + .stat-value { 288 + font-size: 28px; 289 + font-weight: 600; 290 + color: #c8d0e8; 291 + font-family: 'JetBrains Mono', 'Fira Code', monospace; 292 + line-height: 1; 293 + } 294 + 295 + .stat-new { color: #555c70; } 296 + .stat-due { color: #7aa2f7; } 297 + 298 + .stat-label { 299 + font-size: 10px; 300 + color: #555c70; 301 + margin-top: 6px; 302 + text-transform: uppercase; 303 + letter-spacing: 0.06em; 304 + } 305 + 306 + /* forecast bar chart */ 307 + .forecast-chart { 308 + display: flex; 309 + align-items: stretch; 310 + gap: 4px; 311 + max-width: 600px; 312 + } 313 + 314 + .forecast-col { 315 + display: flex; 316 + flex-direction: column; 317 + align-items: center; 318 + flex: 1; 319 + } 320 + 321 + .forecast-count { 322 + font-size: 10px; 323 + color: #8892aa; 324 + height: 14px; 325 + line-height: 14px; 326 + font-family: 'JetBrains Mono', 'Fira Code', monospace; 327 + } 328 + 329 + .forecast-bar-area { 330 + width: 100%; 331 + height: 80px; 332 + display: flex; 333 + align-items: flex-end; 334 + } 335 + 336 + .forecast-bar { 337 + width: 100%; 338 + background: #2a3060; 339 + border-radius: 2px 2px 0 0; 340 + min-height: 2px; 341 + } 342 + 343 + .bar-today { background: #7aa2f7; } 344 + 345 + .forecast-label { 346 + font-size: 9px; 347 + color: #3a4055; 348 + font-family: 'JetBrains Mono', 'Fira Code', monospace; 349 + margin-top: 4px; 350 + white-space: nowrap; 351 + } 352 + 250 353 /* ── Images page ─────────────────────────────────────────────────────────── */ 251 354 #images-page { 252 355 padding: 32px 40px;
+5
crates/tala/src/main.rs
··· 4 4 use crate::editor::Editor; 5 5 use crate::images::Images; 6 6 use crate::review::Review; 7 + use crate::stats::Stats; 7 8 use crate::util::{card_dir, set_card_dir, cards_path}; 8 9 9 10 mod editor; 10 11 mod images; 11 12 mod review; 13 + mod stats; 12 14 mod util; 13 15 14 16 const FAVICON: Asset = asset!("/assets/favicon.ico"); ··· 45 47 #[layout(Shell)] 46 48 #[route("/")] 47 49 Settings {}, 50 + #[route("/stats")] 51 + Stats {}, 48 52 #[route("/editor")] 49 53 Editor {}, 50 54 #[route("/images")] ··· 79 83 rsx! { 80 84 nav { id: "navbar", 81 85 Link { to: Route::Settings {}, "Settings" } 86 + Link { to: Route::Stats {}, "Stats" } 82 87 Link { to: Route::Editor {}, "Editor" } 83 88 Link { to: Route::Images {}, "Images" } 84 89 Link { to: Route::Review {}, "Review" }