Use reading log for books and pages chart when filtering by month

This commit is contained in:
Evan Fiordeliso 2025-07-04 09:56:29 -04:00
parent d9cfb3df36
commit 31cfa881c7
12 changed files with 99 additions and 53 deletions

View File

@ -11,7 +11,7 @@
plugin: BookTrackerPlugin;
}
let { plugin }: Props = $props();
const { plugin }: Props = $props();
function bookUri(book: string) {
const v = encodeURIComponent(plugin.app.vault.getName());

View File

@ -23,20 +23,32 @@
import type BookTrackerPlugin from "@src/main";
import BookCountStat from "@ui/components/stats/BookCountStat.svelte";
import { ALL_TIME } from "@ui/stores/date-filter.svelte";
import {
createReadingLog,
setReadingLogContext,
} from "@ui/stores/reading-log.svelte";
interface Props {
plugin: BookTrackerPlugin;
source: string;
}
let { plugin, source }: Props = $props();
const { plugin, source }: Props = $props();
let settingsStore = createSettings(plugin);
const settingsStore = createSettings(plugin);
setSettingsContext(settingsStore);
let metadataStore = createMetadata(plugin);
const metadataStore = createMetadata(plugin);
setMetadataContext(metadataStore);
const readingLogStore = createReadingLog(plugin.readingLog);
setReadingLogContext(readingLogStore);
$effect(() => {
readingLogStore.filterYear = metadataStore.filterYear;
readingLogStore.filterMonth = metadataStore.filterMonth;
});
let sections = $state<ReadingStatsSection[]>([]);
let error = $state<string | null>(null);
@ -68,7 +80,10 @@
}
});
onDestroy(() => metadataStore.destroy());
onDestroy(() => {
metadataStore.destroy();
readingLogStore.destroy();
});
</script>
<div class="obt-reading-stats">

View File

@ -15,7 +15,7 @@
color?: "rainbow" | ColorName;
};
let {
const {
property,
horizontal,
sortByLabel = false,

View File

@ -2,28 +2,46 @@
import { chart } from "@ui/directives/chart";
import { ALL_TIME } from "@ui/stores/date-filter.svelte";
import { getMetadataContext } from "@ui/stores/metadata.svelte";
import { getReadingLogContext } from "@ui/stores/reading-log.svelte";
import { getSettingsContext } from "@ui/stores/settings.svelte";
import { Color } from "@utils/color";
import type { ChartConfiguration } from "chart.js";
const settings = getSettingsContext().settings;
const settingsStore = getSettingsContext();
const store = getMetadataContext();
const config = $derived.by(() => {
const items = store.metadata.map((f) => ({
pageCount: f.frontmatter[settings.pageCountProperty],
date: f.frontmatter[settings.endDateProperty],
}));
const readingLog = getReadingLogContext();
const isMonthly = $derived(
store.filterYear !== ALL_TIME && store.filterMonth !== ALL_TIME,
);
const items = $derived(
isMonthly
? readingLog.entries.map((entry) => ({
pageCount: entry.pagesRead,
date: entry.createdAt,
}))
: store.metadata.map((f) => ({
pageCount:
f.frontmatter[settingsStore.settings.pageCountProperty],
// @ts-expect-error Moment is provided by Obsidian
date: moment(
f.frontmatter[settingsStore.settings.endDateProperty],
),
})),
);
const config = $derived.by(() => {
const books = new Map<number, number>();
const pages = new Map<number, number>();
for (const item of items) {
// @ts-expect-error Moment is provided by Obsidian
const date = moment(item.date);
let key: number;
if (store.filterYear === ALL_TIME) {
key = date.year();
key = item.date.year();
} else if (store.filterMonth === ALL_TIME) {
key = item.date.month();
} else {
key = date.month();
key = item.date.date();
}
const pageCount = pages.get(key) ?? 0;
@ -33,10 +51,26 @@
books.set(key, bookCount + 1);
}
console.log(pages);
if (isMonthly && typeof store.filterMonth === "number") {
// @ts-expect-error Moment is provided by Obsidian
const daysInMonth = moment()
.month(store.filterMonth - 1)
.daysInMonth();
for (let i = 1; i <= daysInMonth; i++) {
if (!pages.has(i)) {
books.set(i, 0);
pages.set(i, 0);
}
}
}
console.log(pages);
const labels = Array.from(books.keys())
.sort((a, b) => a - b)
.map((key) =>
store.filterYear === ALL_TIME
store.filterYear === ALL_TIME || isMonthly
? key
: // @ts-expect-error Moment is provided by Obsidian
moment().month(key).format("MMM"),
@ -48,26 +82,30 @@
.sort((a, b) => a[0] - b[0])
.map((p) => p[1]);
let datasets = [
{
label: "Pages",
data: sortedPages,
borderColor: Color.fromName("blue").hex,
backgroundColor: Color.fromName("blue").alpha(0.5).rgba,
yAxisID: isMonthly ? "y" : "y1",
},
];
if (!isMonthly) {
datasets.push({
label: "Books",
data: sortedBooks,
borderColor: Color.fromName("red").hex,
backgroundColor: Color.fromName("red").alpha(0.5).rgba,
yAxisID: "y",
});
}
return {
type: "line",
data: {
labels,
datasets: [
{
label: "Books",
data: sortedBooks,
borderColor: Color.fromName("red").hex,
backgroundColor: Color.fromName("red").alpha(0.5).rgba,
yAxisID: "y",
},
{
label: "Pages",
data: sortedPages,
borderColor: Color.fromName("blue").hex,
backgroundColor: Color.fromName("blue").alpha(0.5).rgba,
yAxisID: "y1",
},
],
datasets,
},
options: {
scales: {
@ -75,16 +113,13 @@
type: "linear",
display: true,
position: "left",
ticks: { beginAtZero: true },
},
y1: {
type: "linear",
display: true,
display: !isMonthly,
position: "right",
// grid line settings
grid: {
drawOnChartArea: false, // only want the grid lines for one axis to show up
},
grid: { drawOnChartArea: false },
},
},
},

View File

@ -17,7 +17,7 @@
color?: PieChartColor;
};
let { property, groups, unit, unitPlural, responsive, color }: Props =
const { property, groups, unit, unitPlural, responsive, color }: Props =
$props();
const store = createPropertyStore(property);

View File

@ -7,8 +7,7 @@
property: string;
};
let { label, property }: Props = $props();
const { label, property }: Props = $props();
const store = createPropertyStore(property);
const avg = $derived.by(() => {
if (store.propertyData.length === 0) {

View File

@ -6,8 +6,7 @@
label: string;
};
let { label }: Props = $props();
const { label }: Props = $props();
const store = getMetadataContext();
const count = $derived(store.metadata.length);
</script>

View File

@ -7,8 +7,7 @@
property: string;
};
let { label, property }: Props = $props();
const { label, property }: Props = $props();
const store = createPropertyStore(property);
const count = $derived(store.propertyData.length);
</script>

View File

@ -1,13 +1,10 @@
<script lang="ts">
import type { Readable } from "svelte/store";
type Props = {
label: string;
value: number;
};
let { label, value }: Props = $props();
const { label, value }: Props = $props();
const numberFormatter = new Intl.NumberFormat("en-US", {
maximumFractionDigits: 2,
});

View File

@ -7,8 +7,7 @@
property: string;
};
let { label, property }: Props = $props();
const { label, property }: Props = $props();
const store = createPropertyStore(property);
const total = $derived(
store.propertyData.reduce((acc, f) => acc + f.value, 0),

View File

@ -63,6 +63,9 @@ export function chart<
| ChartConfigurationCustomTypesPerDataset<Type, Data, Label>
) => {
chart.data = config.data;
if (config.options) {
chart.options = config.options;
}
chart.update();
},
destroy: () => {

View File

@ -44,7 +44,7 @@ export function createDateFilter<T>(
data().forEach((item) => {
years.add(selector(item).year());
});
return Array.from(years).sort((a, b) => a - b);
return Array.from(years).sort((a, b) => b - a);
});
const filterMonths = $derived.by(() => {