generated from tpl/obsidian-sample-plugin
Use reading log for books and pages chart when filtering by month
This commit is contained in:
parent
d9cfb3df36
commit
31cfa881c7
|
@ -11,7 +11,7 @@
|
||||||
plugin: BookTrackerPlugin;
|
plugin: BookTrackerPlugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { plugin }: Props = $props();
|
const { plugin }: Props = $props();
|
||||||
|
|
||||||
function bookUri(book: string) {
|
function bookUri(book: string) {
|
||||||
const v = encodeURIComponent(plugin.app.vault.getName());
|
const v = encodeURIComponent(plugin.app.vault.getName());
|
||||||
|
|
|
@ -23,20 +23,32 @@
|
||||||
import type BookTrackerPlugin from "@src/main";
|
import type BookTrackerPlugin from "@src/main";
|
||||||
import BookCountStat from "@ui/components/stats/BookCountStat.svelte";
|
import BookCountStat from "@ui/components/stats/BookCountStat.svelte";
|
||||||
import { ALL_TIME } from "@ui/stores/date-filter.svelte";
|
import { ALL_TIME } from "@ui/stores/date-filter.svelte";
|
||||||
|
import {
|
||||||
|
createReadingLog,
|
||||||
|
setReadingLogContext,
|
||||||
|
} from "@ui/stores/reading-log.svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
plugin: BookTrackerPlugin;
|
plugin: BookTrackerPlugin;
|
||||||
source: string;
|
source: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let { plugin, source }: Props = $props();
|
const { plugin, source }: Props = $props();
|
||||||
|
|
||||||
let settingsStore = createSettings(plugin);
|
const settingsStore = createSettings(plugin);
|
||||||
setSettingsContext(settingsStore);
|
setSettingsContext(settingsStore);
|
||||||
|
|
||||||
let metadataStore = createMetadata(plugin);
|
const metadataStore = createMetadata(plugin);
|
||||||
setMetadataContext(metadataStore);
|
setMetadataContext(metadataStore);
|
||||||
|
|
||||||
|
const readingLogStore = createReadingLog(plugin.readingLog);
|
||||||
|
setReadingLogContext(readingLogStore);
|
||||||
|
|
||||||
|
$effect(() => {
|
||||||
|
readingLogStore.filterYear = metadataStore.filterYear;
|
||||||
|
readingLogStore.filterMonth = metadataStore.filterMonth;
|
||||||
|
});
|
||||||
|
|
||||||
let sections = $state<ReadingStatsSection[]>([]);
|
let sections = $state<ReadingStatsSection[]>([]);
|
||||||
let error = $state<string | null>(null);
|
let error = $state<string | null>(null);
|
||||||
|
|
||||||
|
@ -68,7 +80,10 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
onDestroy(() => metadataStore.destroy());
|
onDestroy(() => {
|
||||||
|
metadataStore.destroy();
|
||||||
|
readingLogStore.destroy();
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="obt-reading-stats">
|
<div class="obt-reading-stats">
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
color?: "rainbow" | ColorName;
|
color?: "rainbow" | ColorName;
|
||||||
};
|
};
|
||||||
|
|
||||||
let {
|
const {
|
||||||
property,
|
property,
|
||||||
horizontal,
|
horizontal,
|
||||||
sortByLabel = false,
|
sortByLabel = false,
|
||||||
|
|
|
@ -2,28 +2,46 @@
|
||||||
import { chart } from "@ui/directives/chart";
|
import { chart } from "@ui/directives/chart";
|
||||||
import { ALL_TIME } from "@ui/stores/date-filter.svelte";
|
import { ALL_TIME } from "@ui/stores/date-filter.svelte";
|
||||||
import { getMetadataContext } from "@ui/stores/metadata.svelte";
|
import { getMetadataContext } from "@ui/stores/metadata.svelte";
|
||||||
|
import { getReadingLogContext } from "@ui/stores/reading-log.svelte";
|
||||||
import { getSettingsContext } from "@ui/stores/settings.svelte";
|
import { getSettingsContext } from "@ui/stores/settings.svelte";
|
||||||
import { Color } from "@utils/color";
|
import { Color } from "@utils/color";
|
||||||
import type { ChartConfiguration } from "chart.js";
|
import type { ChartConfiguration } from "chart.js";
|
||||||
|
|
||||||
const settings = getSettingsContext().settings;
|
const settingsStore = getSettingsContext();
|
||||||
const store = getMetadataContext();
|
const store = getMetadataContext();
|
||||||
const config = $derived.by(() => {
|
const readingLog = getReadingLogContext();
|
||||||
const items = store.metadata.map((f) => ({
|
|
||||||
pageCount: f.frontmatter[settings.pageCountProperty],
|
|
||||||
date: f.frontmatter[settings.endDateProperty],
|
|
||||||
}));
|
|
||||||
|
|
||||||
|
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 books = new Map<number, number>();
|
||||||
const pages = new Map<number, number>();
|
const pages = new Map<number, number>();
|
||||||
for (const item of items) {
|
for (const item of items) {
|
||||||
// @ts-expect-error Moment is provided by Obsidian
|
|
||||||
const date = moment(item.date);
|
|
||||||
let key: number;
|
let key: number;
|
||||||
if (store.filterYear === ALL_TIME) {
|
if (store.filterYear === ALL_TIME) {
|
||||||
key = date.year();
|
key = item.date.year();
|
||||||
|
} else if (store.filterMonth === ALL_TIME) {
|
||||||
|
key = item.date.month();
|
||||||
} else {
|
} else {
|
||||||
key = date.month();
|
key = item.date.date();
|
||||||
}
|
}
|
||||||
|
|
||||||
const pageCount = pages.get(key) ?? 0;
|
const pageCount = pages.get(key) ?? 0;
|
||||||
|
@ -33,10 +51,26 @@
|
||||||
books.set(key, bookCount + 1);
|
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())
|
const labels = Array.from(books.keys())
|
||||||
.sort((a, b) => a - b)
|
.sort((a, b) => a - b)
|
||||||
.map((key) =>
|
.map((key) =>
|
||||||
store.filterYear === ALL_TIME
|
store.filterYear === ALL_TIME || isMonthly
|
||||||
? key
|
? key
|
||||||
: // @ts-expect-error Moment is provided by Obsidian
|
: // @ts-expect-error Moment is provided by Obsidian
|
||||||
moment().month(key).format("MMM"),
|
moment().month(key).format("MMM"),
|
||||||
|
@ -48,26 +82,30 @@
|
||||||
.sort((a, b) => a[0] - b[0])
|
.sort((a, b) => a[0] - b[0])
|
||||||
.map((p) => p[1]);
|
.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 {
|
return {
|
||||||
type: "line",
|
type: "line",
|
||||||
data: {
|
data: {
|
||||||
labels,
|
labels,
|
||||||
datasets: [
|
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",
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
scales: {
|
scales: {
|
||||||
|
@ -75,16 +113,13 @@
|
||||||
type: "linear",
|
type: "linear",
|
||||||
display: true,
|
display: true,
|
||||||
position: "left",
|
position: "left",
|
||||||
|
ticks: { beginAtZero: true },
|
||||||
},
|
},
|
||||||
y1: {
|
y1: {
|
||||||
type: "linear",
|
type: "linear",
|
||||||
display: true,
|
display: !isMonthly,
|
||||||
position: "right",
|
position: "right",
|
||||||
|
grid: { drawOnChartArea: false },
|
||||||
// grid line settings
|
|
||||||
grid: {
|
|
||||||
drawOnChartArea: false, // only want the grid lines for one axis to show up
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
color?: PieChartColor;
|
color?: PieChartColor;
|
||||||
};
|
};
|
||||||
|
|
||||||
let { property, groups, unit, unitPlural, responsive, color }: Props =
|
const { property, groups, unit, unitPlural, responsive, color }: Props =
|
||||||
$props();
|
$props();
|
||||||
|
|
||||||
const store = createPropertyStore(property);
|
const store = createPropertyStore(property);
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
property: string;
|
property: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
let { label, property }: Props = $props();
|
const { label, property }: Props = $props();
|
||||||
|
|
||||||
const store = createPropertyStore(property);
|
const store = createPropertyStore(property);
|
||||||
const avg = $derived.by(() => {
|
const avg = $derived.by(() => {
|
||||||
if (store.propertyData.length === 0) {
|
if (store.propertyData.length === 0) {
|
||||||
|
|
|
@ -6,8 +6,7 @@
|
||||||
label: string;
|
label: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
let { label }: Props = $props();
|
const { label }: Props = $props();
|
||||||
|
|
||||||
const store = getMetadataContext();
|
const store = getMetadataContext();
|
||||||
const count = $derived(store.metadata.length);
|
const count = $derived(store.metadata.length);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
property: string;
|
property: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
let { label, property }: Props = $props();
|
const { label, property }: Props = $props();
|
||||||
|
|
||||||
const store = createPropertyStore(property);
|
const store = createPropertyStore(property);
|
||||||
const count = $derived(store.propertyData.length);
|
const count = $derived(store.propertyData.length);
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Readable } from "svelte/store";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
label: string;
|
label: string;
|
||||||
value: number;
|
value: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
let { label, value }: Props = $props();
|
const { label, value }: Props = $props();
|
||||||
|
|
||||||
const numberFormatter = new Intl.NumberFormat("en-US", {
|
const numberFormatter = new Intl.NumberFormat("en-US", {
|
||||||
maximumFractionDigits: 2,
|
maximumFractionDigits: 2,
|
||||||
});
|
});
|
||||||
|
|
|
@ -7,8 +7,7 @@
|
||||||
property: string;
|
property: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
let { label, property }: Props = $props();
|
const { label, property }: Props = $props();
|
||||||
|
|
||||||
const store = createPropertyStore(property);
|
const store = createPropertyStore(property);
|
||||||
const total = $derived(
|
const total = $derived(
|
||||||
store.propertyData.reduce((acc, f) => acc + f.value, 0),
|
store.propertyData.reduce((acc, f) => acc + f.value, 0),
|
||||||
|
|
|
@ -63,6 +63,9 @@ export function chart<
|
||||||
| ChartConfigurationCustomTypesPerDataset<Type, Data, Label>
|
| ChartConfigurationCustomTypesPerDataset<Type, Data, Label>
|
||||||
) => {
|
) => {
|
||||||
chart.data = config.data;
|
chart.data = config.data;
|
||||||
|
if (config.options) {
|
||||||
|
chart.options = config.options;
|
||||||
|
}
|
||||||
chart.update();
|
chart.update();
|
||||||
},
|
},
|
||||||
destroy: () => {
|
destroy: () => {
|
||||||
|
|
|
@ -44,7 +44,7 @@ export function createDateFilter<T>(
|
||||||
data().forEach((item) => {
|
data().forEach((item) => {
|
||||||
years.add(selector(item).year());
|
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(() => {
|
const filterMonths = $derived.by(() => {
|
||||||
|
|
Loading…
Reference in New Issue