feat(workspace): journal with one note per day and a calendar
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m6s
MindSift CI & Docker Release / Build, Test in Container & Push (push) Successful in 2m6s
- journal_days (migration 8) maps a person's day to an ordinary note;
GET /journal lists the days, POST /journal/{date} opens or creates one
- the journal sits on top of the notes sidebar: days below each other
(today first, older ones load while scrolling), a calendar with month
and year picker follows the day in view and jumps to any day
- the header shares the day in view; journal notes stay out of the folder
tree; can be switched off per device under Darstellung
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
261579f0f2
commit
9008d7c915
19 files changed
+864
-19
No files matched your search
@@ -0,0 +1,62 @@
|
||||
// Journal helpers: dates are local calendar days as YYYY-MM-DD (the server stores them as given).
|
||||
|
||||
export const JOURNAL_ENABLED_KEY = 'mindsift_journal_enabled';
|
||||
|
||||
export function isJournalEnabled(): boolean {
|
||||
try {
|
||||
return localStorage.getItem(JOURNAL_ENABLED_KEY) !== 'false';
|
||||
} catch {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export function setJournalEnabled(on: boolean) {
|
||||
try {
|
||||
localStorage.setItem(JOURNAL_ENABLED_KEY, on ? 'true' : 'false');
|
||||
} catch {
|
||||
// storage blocked: the setting simply does not stick
|
||||
}
|
||||
}
|
||||
|
||||
export function toISODate(d: Date): string {
|
||||
const m = String(d.getMonth() + 1).padStart(2, '0');
|
||||
const day = String(d.getDate()).padStart(2, '0');
|
||||
return `${d.getFullYear()}-${m}-${day}`;
|
||||
}
|
||||
|
||||
export function todayISO(): string {
|
||||
return toISODate(new Date());
|
||||
}
|
||||
|
||||
export function parseISODate(date: string): Date {
|
||||
const [y, m, d] = date.split('-').map(Number);
|
||||
return new Date(y, (m || 1) - 1, d || 1);
|
||||
}
|
||||
|
||||
export const MONTHS = [
|
||||
'Januar', 'Februar', 'März', 'April', 'Mai', 'Juni',
|
||||
'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember',
|
||||
];
|
||||
|
||||
/** "Fr, 30. Okt. 2026" for compact labels */
|
||||
export function shortDateLabel(date: string): string {
|
||||
return parseISODate(date).toLocaleDateString('de-DE', {
|
||||
weekday: 'short',
|
||||
day: 'numeric',
|
||||
month: 'short',
|
||||
year: 'numeric',
|
||||
});
|
||||
}
|
||||
|
||||
/** Weeks of a month for a Monday-first grid; days outside the month are null. */
|
||||
export function monthGrid(year: number, month: number): (string | null)[][] {
|
||||
const first = new Date(year, month, 1);
|
||||
const offset = (first.getDay() + 6) % 7; // Monday = 0
|
||||
const daysInMonth = new Date(year, month + 1, 0).getDate();
|
||||
const cells: (string | null)[] = Array(offset).fill(null);
|
||||
for (let d = 1; d <= daysInMonth; d++) cells.push(toISODate(new Date(year, month, d)));
|
||||
while (cells.length % 7 !== 0) cells.push(null);
|
||||
const weeks: (string | null)[][] = [];
|
||||
for (let i = 0; i < cells.length; i += 7) weeks.push(cells.slice(i, i + 7));
|
||||
return weeks;
|
||||
}
|
||||
Reference in new issue
Block a user