Skip to content

Commit

Permalink
feat: add all fixed interval journals
Browse files Browse the repository at this point in the history
  • Loading branch information
srg-kostyrko committed Aug 27, 2024
1 parent fbeee9a commit 3282414
Show file tree
Hide file tree
Showing 16 changed files with 116 additions and 61 deletions.
2 changes: 1 addition & 1 deletion src/calendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export function initCalendarCustomization(): void {
}
}

export function date(date?: string, format?: string): MomentDate {
export function date_from_string(date?: string, format?: string): MomentDate {
const md = date ? moment(date, format) : moment();
if (calendarSettings$.value.firstDayOfWeek !== -1) {
md.locale(CUSTOM_LOCALE);
Expand Down
4 changes: 2 additions & 2 deletions src/components/DatePicker.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed } from "vue";
import { date } from "../calendar";
import { date_from_string } from "../calendar";
import { VueModal } from "./modals/vue-modal";
import ObsidianButton from "./obsidian/ObsidianButton.vue";
import ObsidianIcon from "./obsidian/ObsidianIcon.vue";
Expand All @@ -23,7 +23,7 @@ const props = withDefaults(
const model = defineModel<string>();
const momentDate = computed(() => {
if (model.value) {
return date(model.value);
return date_from_string(model.value);
}
return null;
});
Expand Down
4 changes: 2 additions & 2 deletions src/components/calendar/CalendarMonth.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script setup lang="ts">
import { computed, toRefs } from "vue";
import { useMonth } from "./use-month";
import { weekdayNames, date } from "../../calendar";
import { weekdayNames, date_from_string } from "../../calendar";
import { calendarViewSettings$ } from "../../stores/settings.store";
import CalendarDay from "./CalendarDay.vue";
import CalendarWeekNumber from "./CalendarWeekNumber.vue";
Expand All @@ -13,7 +13,7 @@ const props = defineProps<{
defineEmits<(e: "select" | "selectWeek", date: string) => void>();
const { refDate } = toRefs(props);
const momentDate = computed(() => date(refDate.value));
const momentDate = computed(() => date_from_string(refDate.value));
const { grid } = useMonth(refDate);
</script>
Expand Down
4 changes: 2 additions & 2 deletions src/components/calendar/CalendarYear.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed, toRefs } from "vue";
import { date } from "../../calendar";
import { date_from_string } from "../../calendar";
import { useYear } from "./use-year";
const props = defineProps<{
Expand All @@ -9,7 +9,7 @@ const props = defineProps<{
defineEmits<(e: "select", date: string) => void>();
const { refDate } = toRefs(props);
const momentDate = computed(() => date(refDate.value));
const momentDate = computed(() => date_from_string(refDate.value));
const { grid } = useYear(refDate);
</script>
Expand Down
4 changes: 2 additions & 2 deletions src/components/calendar/use-month.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import { ref, watchEffect, type Ref } from "vue";
import type { CalendarUiDay } from "../../types/calendar-ui.types";
import { date, today } from "../../calendar";
import { date_from_string, today } from "../../calendar";
import { calendarViewSettings$ } from "../../stores/settings.store";

export function useMonth(refDate: Ref<string>) {
const grid = ref<CalendarUiDay[]>([]);

watchEffect(() => {
const momentDate = date(refDate.value);
const momentDate = date_from_string(refDate.value);
if (!momentDate.isValid()) {
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/calendar/use-year.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { ref, watchEffect, type Ref } from "vue";
import type { CalendarUiElement } from "../../types/calendar-ui.types";
import { date } from "../../calendar";
import { date_from_string } from "../../calendar";

export function useYear(refDate: Ref<string>) {
const grid = ref<CalendarUiElement[]>([]);

watchEffect(() => {
const momentDate = date(refDate.value);
const momentDate = date_from_string(refDate.value);
if (!momentDate.isValid()) {
return;
}
Expand Down
4 changes: 4 additions & 0 deletions src/components/modals/CreateJournal.modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ function submit() {
<ObsidianSetting name="I'll be writing">
<ObsidianDropdown v-model="state.write">
<option value="day">Daily</option>
<option value="week">Weekly</option>
<option value="month">Monthly</option>
<option value="quarter">Quarterly</option>
<option value="year">Annually</option>
</ObsidianDropdown>
</ObsidianSetting>
<ul class="errors">
Expand Down
4 changes: 2 additions & 2 deletions src/components/modals/DatePicker.modal.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script setup lang="ts">
import { computed, ref } from "vue";
import { today, date } from "../../calendar";
import { today, date_from_string } from "../../calendar";
import CalendarMonth from "../calendar/CalendarMonth.vue";
import CalendarYear from "../calendar/CalendarYear.vue";
import ObsidianButton from "../obsidian/ObsidianButton.vue";
Expand All @@ -17,7 +17,7 @@ const emit = defineEmits<{
const mode = ref<"month" | "year">("month");
const currentDate = ref(props.selectedDate ?? today().format("YYYY-MM-DD"));
const currentDateMoment = computed(() => date(currentDate.value).startOf("month"));
const currentDateMoment = computed(() => date_from_string(currentDate.value).startOf("month"));
function prev(step: "month" | "year" = "month") {
currentDate.value = currentDateMoment.value.subtract(1, step).format("YYYY-MM-DD");
Expand Down
35 changes: 18 additions & 17 deletions src/journals/fixed-interval.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,35 @@
import { moment } from "obsidian";
import type { ComputedRef } from "vue";
import type { IntervalResolver, JournalInterval } from "../types/journal.types";
import type { FixedWriteIntervals, JournalCommand } from "../types/settings.types";
import { FRONTMATTER_DATE_FORMAT } from "../constants";
import type { MomentDate } from "../types/date.types";
import { date } from "../calendar";
import { date_from_string } from "../calendar";

// TODO: write tests
export class FixedInterval implements IntervalResolver {
#journalId: string;
#settings: ComputedRef<FixedWriteIntervals>;

constructor(settings: ComputedRef<FixedWriteIntervals>) {
constructor(journalId: string, settings: ComputedRef<FixedWriteIntervals>) {
this.#journalId = journalId;
this.#settings = settings;
}

resolveForDate(date: string): JournalInterval | null {
const baseDate = moment(date);
const baseDate = date_from_string(date);
if (!baseDate.isValid()) return null;
return this.#buildInterval(baseDate);
}

resolveNext(date: string): JournalInterval | null {
const baseDate = moment(date);
const baseDate = date_from_string(date);
if (!baseDate.isValid()) return null;
baseDate.add(1, this.#settings.value.type);
return this.#buildInterval(baseDate);
}

resolvePrevious(date: string): JournalInterval | null {
const baseDate = moment(date);
const baseDate = date_from_string(date);
if (!baseDate.isValid()) return null;
baseDate.subtract(1, this.#settings.value.type);
return this.#buildInterval(baseDate);
Expand All @@ -39,28 +40,28 @@ export class FixedInterval implements IntervalResolver {
case "same":
return date;
case "next":
return moment(date).add(1, this.#settings.value.type).format(FRONTMATTER_DATE_FORMAT);
return date_from_string(date).add(1, this.#settings.value.type).format(FRONTMATTER_DATE_FORMAT);
case "previous":
return moment(date).subtract(1, this.#settings.value.type).format(FRONTMATTER_DATE_FORMAT);
return date_from_string(date).subtract(1, this.#settings.value.type).format(FRONTMATTER_DATE_FORMAT);
case "same_next_week":
return moment(date).add(1, "week").format(FRONTMATTER_DATE_FORMAT);
return date_from_string(date).add(1, "week").format(FRONTMATTER_DATE_FORMAT);
case "same_previous_week":
return moment(date).subtract(1, "week").format(FRONTMATTER_DATE_FORMAT);
return date_from_string(date).subtract(1, "week").format(FRONTMATTER_DATE_FORMAT);
case "same_next_month":
return moment(date).add(1, "month").format(FRONTMATTER_DATE_FORMAT);
return date_from_string(date).add(1, "month").format(FRONTMATTER_DATE_FORMAT);
case "same_previous_month":
return moment(date).subtract(1, "month").format(FRONTMATTER_DATE_FORMAT);
return date_from_string(date).subtract(1, "month").format(FRONTMATTER_DATE_FORMAT);
case "same_next_year":
return moment(date).add(1, "year").format(FRONTMATTER_DATE_FORMAT);
return date_from_string(date).add(1, "year").format(FRONTMATTER_DATE_FORMAT);
case "same_previous_year":
return moment(date).subtract(1, "year").format(FRONTMATTER_DATE_FORMAT);
return date_from_string(date).subtract(1, "year").format(FRONTMATTER_DATE_FORMAT);
}
return null;
}

countRepeats(startDate: string, endDate: string): number {
const start = date(startDate);
const end = date(endDate);
const start = date_from_string(startDate);
const end = date_from_string(endDate);
return Math.ceil(start.diff(end, this.#settings.value.type));
}

Expand All @@ -69,7 +70,7 @@ export class FixedInterval implements IntervalResolver {
const start_date = base.startOf(type).format(FRONTMATTER_DATE_FORMAT);
const end_date = base.endOf(type).format(FRONTMATTER_DATE_FORMAT);
return {
key: `${type}_${start_date}_${end_date}`,
key: `${this.#journalId}_${start_date}_${end_date}`,
start_date,
end_date,
};
Expand Down
45 changes: 45 additions & 0 deletions src/journals/journal-commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import type { JournalSettings } from "../types/settings.types";

export const supportedJournalCommands: Record<JournalSettings["write"]["type"], { label: string; value: string }[]> = {
day: [
{ label: "Open today's note", value: "same" },
{ label: "Open tomorrow's note", value: "next" },
{ label: "Open yesterday's note", value: "previous" },
{ label: "Open same day next week", value: "same_next_week" },
{ label: "Open same day last week", value: "same_previous_week" },
{ label: "Open same day next month", value: "same_next_month" },
{ label: "Open same day last month", value: "same_previous_month" },
{ label: "Open same day next year", value: "same_next_year" },
{ label: "Open same day last year", value: "same_previous_year" },
],
week: [
{ label: "Open current weeks's note", value: "same" },
{ label: "Open next week's note", value: "next" },
{ label: "Open last week's note", value: "previous" },
],
month: [
{ label: "Open current month's note", value: "same" },
{ label: "Open next month's note", value: "next" },
{ label: "Open last month's note", value: "previous" },
{ label: "Open same month next year", value: "same_next_year" },
{ label: "Open same month last year", value: "same_previous_year" },
],
quarter: [
{ label: "Open current quarter's note", value: "same" },
{ label: "Open next quarter's note", value: "next" },
{ label: "Open last quarter's note", value: "previous" },
{ label: "Open same quarter next year", value: "same_next_year" },
{ label: "Open same quarter last year", value: "same_previous_year" },
],
year: [
{ label: "Open this year's note", value: "same" },
{ label: "Open next year's note", value: "next" },
{ label: "Open last year's note", value: "previous" },
],
weekdays: [],
custom: [],
};

export const buildSupportedCommandList = (write: JournalSettings["write"]) => {
return supportedJournalCommands[write.type];
};
21 changes: 11 additions & 10 deletions src/journals/journal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { journals$ } from "../stores/settings.store";
import type { JournalCommand, JournalSettings } from "../types/settings.types";
import type { IntervalResolver, JournalInterval, JournalMetadata } from "../types/journal.types";
import { activeNote$, app$, plugin$ } from "../stores/obsidian.store";
import { normalizePath, TFile, moment, type LeftRibbon } from "obsidian";
import { normalizePath, TFile, type LeftRibbon } from "obsidian";
import { ensureFolderExists } from "../utils/io";
import { replaceTemplateVariables, tryApplyingTemplater } from "../utils/template";
import type { TemplateContext } from "../types/template.types";
Expand All @@ -15,7 +15,7 @@ import {
FRONTMATTER_START_DATE_KEY,
} from "../constants";
import { FixedInterval } from "./fixed-interval";
import { date, today } from "../calendar";
import { date_from_string, today } from "../calendar";

export class Journal {
#config: ComputedRef<JournalSettings>;
Expand All @@ -25,7 +25,7 @@ export class Journal {
this.#config = computed(() => journals$.value[id]);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-expect-error
this.#intervalResolver = new FixedInterval(() => this.#config.value.write);
this.#intervalResolver = new FixedInterval(id, () => this.#config.value.write);
}

registerCommands(): void {
Expand Down Expand Up @@ -183,8 +183,8 @@ export class Journal {
async #ensureFrontMatter(note: TFile, metadata: JournalMetadata): Promise<void> {
await app$.value.fileManager.processFrontMatter(note, (frontmatter) => {
frontmatter[FRONTMATTER_ID_KEY] = this.id;
frontmatter[FRONTMATTER_START_DATE_KEY] = moment(metadata.start_date).format(FRONTMATTER_DATE_FORMAT);
frontmatter[FRONTMATTER_END_DATE_KEY] = moment(metadata.end_date).format(FRONTMATTER_DATE_FORMAT);
frontmatter[FRONTMATTER_START_DATE_KEY] = date_from_string(metadata.start_date).format(FRONTMATTER_DATE_FORMAT);
frontmatter[FRONTMATTER_END_DATE_KEY] = date_from_string(metadata.end_date).format(FRONTMATTER_DATE_FORMAT);
if (metadata.index == null) {
delete frontmatter[FRONTMATTER_INDEX_KEY];
} else {
Expand All @@ -196,6 +196,7 @@ export class Journal {
async #buildMetadata(interval: JournalInterval): Promise<JournalMetadata> {
const metadata: JournalMetadata = {
id: this.id,
key: interval.key,
start_date: interval.start_date,
end_date: interval.start_date,
index: await this.#resolveIndex(interval),
Expand Down Expand Up @@ -236,13 +237,13 @@ export class Journal {

#checkBounds(interval: JournalInterval): boolean {
if (this.#config.value.start) {
const startDate = date(this.#config.value.start);
if (startDate.isValid() && date(interval.end_date).isBefore(startDate)) return false;
const startDate = date_from_string(this.#config.value.start);
if (startDate.isValid() && date_from_string(interval.end_date).isBefore(startDate)) return false;
}

if (this.#config.value.end.type === "date" && this.#config.value.end.date) {
const endDate = date(this.#config.value.end.date);
if (endDate.isValid() && date(interval.start_date).isAfter(endDate)) return false;
const endDate = date_from_string(this.#config.value.end.date);
if (endDate.isValid() && date_from_string(interval.start_date).isAfter(endDate)) return false;
}
if (this.#config.value.end.type === "repeats" && this.#config.value.end.repeats && this.#config.value.start) {
const repeats = this.#intervalResolver.countRepeats(this.#config.value.start, interval.start_date);
Expand Down Expand Up @@ -273,7 +274,7 @@ export class Journal {
}
return index;
}
const anchor = date(this.#config.value.index.anchorDate);
const anchor = date_from_string(this.#config.value.index.anchorDate);
if (!anchor.isValid()) return undefined;
if (
anchor.isAfter(interval.start_date) &&
Expand Down
18 changes: 12 additions & 6 deletions src/journals/journals-index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, type TAbstractFile, TFile, moment, type FrontMatterCache } from "obsidian";
import { Component, type TAbstractFile, TFile, type FrontMatterCache } from "obsidian";
import { app$ } from "../stores/obsidian.store";
import { computed, ref, type ComputedRef } from "vue";
import IntervalTree from "@flatten-js/interval-tree";
Expand All @@ -9,6 +9,7 @@ import {
FRONTMATTER_INDEX_KEY,
FRONTMATTER_START_DATE_KEY,
} from "../constants";
import { date_from_string } from "../calendar";

export class JournalsIndex extends Component {
#pathIndex = ref(new Map<string, JournalMetadata>());
Expand All @@ -33,19 +34,19 @@ export class JournalsIndex extends Component {
}

find(journalId: string, date: string): JournalMetadata | null {
const time = moment(date).toDate().getTime();
const time = date_from_string(date).toDate().getTime();
const list = this.#intervalTree.search([time, time]);
return list.find((entry) => entry.id === journalId);
}

findNext(journalId: string, metadata: JournalInterval): JournalMetadata | null {
const date = moment(metadata.end_date).add(1, "day").toDate().getTime();
const date = date_from_string(metadata.end_date).add(1, "day").toDate().getTime();
const list = this.#intervalTree.search([date, Infinity]);
return list.find((entry) => entry.id === journalId);
}

findPrevious(journalId: string, metadata: JournalInterval): JournalMetadata | null {
const date = moment(metadata.start_date).subtract(1, "day").toDate().getTime();
const date = date_from_string(metadata.start_date).subtract(1, "day").toDate().getTime();
const list = this.#intervalTree.search([0, date]);
return list.findLast((entry) => entry.id === journalId);
}
Expand Down Expand Up @@ -102,17 +103,22 @@ export class JournalsIndex extends Component {
if (!(FRONTMATTER_ID_KEY in frontmatter)) return;
const start_date = frontmatter[FRONTMATTER_START_DATE_KEY];
const end_date = frontmatter[FRONTMATTER_END_DATE_KEY];
if (!moment(start_date).isValid() || !moment(end_date).isValid()) return;
if (!date_from_string(start_date).isValid() || !date_from_string(end_date).isValid()) return;
const id = frontmatter[FRONTMATTER_ID_KEY];
const journalMetadata: JournalMetadata = {
id: frontmatter[FRONTMATTER_ID_KEY],
key: `${id}_${start_date}_${end_date}`,
start_date,
end_date,
path,
index: frontmatter[FRONTMATTER_INDEX_KEY],
};
this.#pathIndex.value.set(path, journalMetadata);
this.#intervalTree.insert(
[moment(start_date).startOf("day").toDate().getTime(), moment(end_date).endOf("day").toDate().getTime()],
[
date_from_string(start_date).startOf("day").toDate().getTime(),
date_from_string(end_date).endOf("day").toDate().getTime(),
],
journalMetadata,
);
}
Expand Down
Loading

0 comments on commit 3282414

Please sign in to comment.