Skip to content

Commit 80d8bad

Browse files
authored
Merge pull request #536 from mikegreiner/feature/issue-497-start-week-on-any-day
2 parents a9b05b4 + d285fb1 commit 80d8bad

7 files changed

Lines changed: 258 additions & 44 deletions

File tree

docs/InputParameters.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ These key-value pairs should be placed under the key `month`.
138138
|:--------|:-------|:-----------:|:------|
139139
| `mode` | Pick one mode of the two(circle\|annotation) | 1 |
140140
| `dataset` | Index of the dataset of your interest | 1~NT | all indices of non-x searchTarget |
141-
| `startWeekOn` | First day of a week ('Sun'\|'Mon') | 1 | 'Sun' |
141+
| `startWeekOn` | First day of a week ('Sun'\|'Mon'\|'Tue'\|'Wed'\|'Thu'\|'Fri'\|'Sat' or full names like 'Sunday', 'Monday', etc.) | 1 | 'Sun' |
142142
| `threshold` | Threshold to determine showing a circle on a day or not | 1~NT | 0 |
143143
| `thresholdType` | Pick one of the two (GreaterThan\|LessThan) | 1 | GreaterThan
144144
| `yMin` | Minimum value | 1~NT | Minimum value of the dataset |

examples/TestStartWeekOn.md

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
# Test: startWeekOn Parameter
2+
3+
This example demonstrates the `startWeekOn` parameter which allows you to start the week on any day.
4+
5+
## All Days Supported
6+
7+
The `startWeekOn` parameter now accepts any day of the week:
8+
- Abbreviations: `Sun`, `Mon`, `Tue`, `Wed`, `Thu`, `Fri`, `Sat`
9+
- Full names: `Sunday`, `Monday`, `Tuesday`, `Wednesday`, `Thursday`, `Friday`, `Saturday`
10+
- Case-insensitive: `FRIDAY`, `friday`, `Fri` all work
11+
12+
## Sunday (Default)
13+
14+
```tracker
15+
searchType: tag
16+
searchTarget: test
17+
folder: diary
18+
startDate: 2021-01-01
19+
endDate: 2021-01-31
20+
month:
21+
startWeekOn: Sun
22+
mode: circle
23+
```
24+
25+
## Monday
26+
27+
```tracker
28+
searchType: tag
29+
searchTarget: test
30+
folder: diary
31+
startDate: 2021-01-01
32+
endDate: 2021-01-31
33+
month:
34+
startWeekOn: Mon
35+
mode: circle
36+
```
37+
38+
## Tuesday
39+
40+
```tracker
41+
searchType: tag
42+
searchTarget: test
43+
folder: diary
44+
startDate: 2021-01-01
45+
endDate: 2021-01-31
46+
month:
47+
startWeekOn: Tue
48+
mode: circle
49+
```
50+
51+
## Wednesday
52+
53+
```tracker
54+
searchType: tag
55+
searchTarget: test
56+
folder: diary
57+
startDate: 2021-01-01
58+
endDate: 2021-01-31
59+
month:
60+
startWeekOn: Wed
61+
mode: circle
62+
```
63+
64+
## Thursday
65+
66+
```tracker
67+
searchType: tag
68+
searchTarget: test
69+
folder: diary
70+
startDate: 2021-01-01
71+
endDate: 2021-01-31
72+
month:
73+
startWeekOn: Thu
74+
mode: circle
75+
```
76+
77+
## Friday
78+
79+
```tracker
80+
searchType: tag
81+
searchTarget: test
82+
folder: diary
83+
startDate: 2021-01-01
84+
endDate: 2021-01-31
85+
month:
86+
startWeekOn: Fri
87+
mode: circle
88+
```
89+
90+
## Saturday
91+
92+
```tracker
93+
searchType: tag
94+
searchTarget: test
95+
folder: diary
96+
startDate: 2021-01-01
97+
endDate: 2021-01-31
98+
month:
99+
startWeekOn: Sat
100+
mode: circle
101+
```
102+
103+
## Case Insensitivity
104+
105+
All of these are equivalent:
106+
107+
```tracker
108+
searchType: tag
109+
searchTarget: test
110+
folder: diary
111+
startDate: 2021-01-01
112+
endDate: 2021-01-31
113+
month:
114+
startWeekOn: FRIDAY
115+
mode: circle
116+
```
117+
118+
```tracker
119+
searchType: tag
120+
searchTarget: test
121+
folder: diary
122+
startDate: 2021-01-01
123+
endDate: 2021-01-31
124+
month:
125+
startWeekOn: friday
126+
mode: circle
127+
```
128+
129+
```tracker
130+
searchType: tag
131+
searchTarget: test
132+
folder: diary
133+
startDate: 2021-01-01
134+
endDate: 2021-01-31
135+
month:
136+
startWeekOn: Friday
137+
mode: circle
138+
```
139+
140+
## Full Day Names
141+
142+
You can also use full day names:
143+
144+
```tracker
145+
searchType: tag
146+
searchTarget: test
147+
folder: diary
148+
startDate: 2021-01-01
149+
endDate: 2021-01-31
150+
month:
151+
startWeekOn: Sunday
152+
mode: circle
153+
```
154+
155+
## Error Handling
156+
157+
Invalid values will show a clear error message:
158+
159+
```tracker
160+
searchType: tag
161+
searchTarget: test
162+
folder: diary
163+
startDate: 2021-01-01
164+
endDate: 2021-01-31
165+
month:
166+
startWeekOn: InvalidDay
167+
mode: circle
168+
```
169+
170+
**Expected Error:** "Invalid startWeekOn value: 'InvalidDay'. Must be one of: Sun, Mon, Tue, Wed, Thu, Fri, Sat (or full day names like Sunday, Monday, etc.)"

rollup.config.dev.mjs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,11 @@ export default {
1313
},
1414
external: ['obsidian'],
1515
plugins: [
16-
typescript(),
16+
typescript({
17+
tsconfig: 'tsconfig.json',
18+
rootDir: 'src',
19+
outDir: 'examples/.obsidian/plugins/obsidian-tracker'
20+
}),
1721
nodeResolve({browser: true}),
1822
commonjs(),
1923
copy({

src/heatmap.ts

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -128,17 +128,16 @@ function renderHeatmapDays(
128128
// Prepare data for graph
129129
let daysInHeatmapView: Array<DayInfo> = [];
130130
const dataStartDate = dataset.getStartDate().clone();
131-
let startDate = dataStartDate
132-
.clone()
133-
.subtract(dataStartDate.day(), "days");
134-
if (heatmapInfo.startWeekOn.toLowerCase() === "mon") {
135-
startDate = startDate.add(1, "days");
136-
}
131+
const startDayIndex = helper.getDayIndex(heatmapInfo.startWeekOn);
132+
const currentDayOfWeek = dataStartDate.day(); // 0=Sunday, 1=Monday, etc.
133+
// Calculate days to subtract to get to the start of the week
134+
const daysToSubtract = (currentDayOfWeek - startDayIndex + 7) % 7;
135+
let startDate = dataStartDate.clone().subtract(daysToSubtract, "days");
137136
const dataEndDate = dataset.getEndDate().clone();
138-
let endDate = dataEndDate.clone().add(7 - dataEndDate.day() - 1, "days");
139-
if (heatmapInfo.startWeekOn.toLowerCase() === "mon") {
140-
endDate = endDate.add(1, "days");
141-
}
137+
const endDayOfWeek = dataEndDate.day();
138+
// Calculate days to add to complete the week (get to Saturday of that week)
139+
const daysToAdd = (6 - endDayOfWeek + startDayIndex) % 7;
140+
let endDate = dataEndDate.clone().add(daysToAdd, "days");
142141
// console.log(startDate.format("YYYY-MM-DD"));
143142
// console.log(endDate.format("YYYY-MM-DD"));
144143

@@ -150,16 +149,10 @@ function renderHeatmapDays(
150149
curDate <= endDate;
151150
curDate.add(1, "days")
152151
) {
153-
if (heatmapInfo.startWeekOn.toLowerCase() === "mon") {
154-
indCol = curDate.day() - 1;
155-
if (indCol < 0) {
156-
indCol = 6;
157-
}
158-
indRow = Math.floor(ind / 7);
159-
} else {
160-
indCol = curDate.day(); // 0~6
161-
indRow = Math.floor(ind / 7);
162-
}
152+
const dayOfWeek = curDate.day(); // 0=Sunday, 1=Monday, etc.
153+
// Calculate column: shift by startDayIndex
154+
indCol = (dayOfWeek - startDayIndex + 7) % 7;
155+
indRow = Math.floor(ind / 7);
163156

164157
// curValue and scaledValue
165158
let curValue = dataset.getValue(curDate);

src/helper.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,32 @@ export function trimByChar(str: string, char: string) {
332332
: str.substring(first, str.length - last);
333333
}
334334

335+
/**
336+
* Convert day abbreviation or full name to day index (0-6)
337+
* @param dayAbbr - Day abbreviation or full name: "Sun"/"Sunday", "Mon"/"Monday", etc.
338+
* @returns Day index (0=Sunday, 1=Monday, ..., 6=Saturday)
339+
*/
340+
export function getDayIndex(dayAbbr: string): number {
341+
const dayMap: { [key: string]: number } = {
342+
"sun": 0,
343+
"sunday": 0,
344+
"mon": 1,
345+
"monday": 1,
346+
"tue": 2,
347+
"tuesday": 2,
348+
"wed": 3,
349+
"wednesday": 3,
350+
"thu": 4,
351+
"thursday": 4,
352+
"fri": 5,
353+
"friday": 5,
354+
"sat": 6,
355+
"saturday": 6
356+
};
357+
const normalized = dayAbbr.toLowerCase().trim();
358+
return dayMap[normalized] !== undefined ? dayMap[normalized] : 0; // Default to Sunday
359+
}
360+
335361
export function replaceImgTagByAlt(input: string) {
336362
if (input === null) return null;
337363

src/month.ts

Lines changed: 16 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,9 @@ function renderMonthHeader(
447447

448448
// week day names
449449
let weekdayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
450-
if (monthInfo.startWeekOn.toLowerCase() === "mon") {
450+
const startDayIndex = helper.getDayIndex(monthInfo.startWeekOn);
451+
// Rotate array so startWeekOn is first
452+
for (let i = 0; i < startDayIndex; i++) {
451453
weekdayNames.push(weekdayNames.shift());
452454
}
453455
let weekdayNameSize = helper.measureTextSize(
@@ -572,17 +574,16 @@ function renderMonthDays(
572574

573575
// Start and end
574576
const monthStartDate = curMonthDate.clone().startOf("month");
575-
let startDate = monthStartDate
576-
.clone()
577-
.subtract(monthStartDate.day(), "days");
578-
if (monthInfo.startWeekOn.toLowerCase() === "mon") {
579-
startDate = startDate.add(1, "days");
580-
}
577+
const startDayIndex = helper.getDayIndex(monthInfo.startWeekOn);
578+
const currentDayOfWeek = monthStartDate.day(); // 0=Sunday, 1=Monday, etc.
579+
// Calculate days to subtract to get to the start of the week
580+
const daysToSubtract = (currentDayOfWeek - startDayIndex + 7) % 7;
581+
let startDate = monthStartDate.clone().subtract(daysToSubtract, "days");
581582
const monthEndDate = curMonthDate.clone().endOf("month");
582-
let endDate = monthEndDate.clone().add(7 - monthEndDate.day() - 1, "days");
583-
if (monthInfo.startWeekOn.toLowerCase() === "mon") {
584-
endDate = endDate.add(1, "days");
585-
}
583+
const endDayOfWeek = monthEndDate.day();
584+
// Calculate days to add to complete the week (get to Saturday of that week)
585+
const daysToAdd = (6 - endDayOfWeek + startDayIndex) % 7;
586+
let endDate = monthEndDate.clone().add(daysToAdd, "days");
586587
const dataStartDate = dataset.getStartDate();
587588
const dataEndDate = dataset.getEndDate();
588589
// console.log(monthStartDate.format("YYYY-MM-DD"));
@@ -628,16 +629,10 @@ function renderMonthDays(
628629
logToConsole = false; // Change this to do dubugging
629630
}
630631

631-
if (monthInfo.startWeekOn.toLowerCase() === "mon") {
632-
indCol = curDate.day() - 1;
633-
if (indCol < 0) {
634-
indCol = 6;
635-
}
636-
indRow = Math.floor(ind / 7);
637-
} else {
638-
indCol = curDate.day(); // 0~6
639-
indRow = Math.floor(ind / 7);
640-
}
632+
const dayOfWeek = curDate.day(); // 0=Sunday, 1=Monday, etc.
633+
// Calculate column: shift by startDayIndex
634+
indCol = (dayOfWeek - startDayIndex + 7) % 7;
635+
indRow = Math.floor(ind / 7);
641636

642637
// is this day in this month
643638
let isInThisMonth = true;

src/parsing.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2065,10 +2065,20 @@ export function getRenderInfoFromYaml(
20652065
let numDataset = month.dataset.length;
20662066

20672067
// startWeekOn
2068-
month.startWeekOn = getStringFromInput(
2068+
let startWeekOnValue = getStringFromInput(
20692069
yamlMonth?.startWeekOn,
20702070
month.startWeekOn
20712071
);
2072+
// Validate day abbreviation - supports both abbreviations and full names
2073+
if (startWeekOnValue) {
2074+
const normalized = startWeekOnValue.toLowerCase().trim();
2075+
const validDays = ["sun", "sunday", "mon", "monday", "tue", "tuesday", "wed", "wednesday", "thu", "thursday", "fri", "friday", "sat", "saturday"];
2076+
if (!validDays.includes(normalized)) {
2077+
errorMessage = `Invalid startWeekOn value: "${startWeekOnValue}". Must be one of: Sun, Mon, Tue, Wed, Thu, Fri, Sat (or full day names like Sunday, Monday, etc.)`;
2078+
return errorMessage;
2079+
}
2080+
}
2081+
month.startWeekOn = startWeekOnValue;
20722082
// console.log(month.startWeekOn);
20732083

20742084
// showCircle
@@ -2306,6 +2316,22 @@ export function getRenderInfoFromYaml(
23062316
}
23072317
}
23082318

2319+
// startWeekOn
2320+
let heatmapStartWeekOnValue = getStringFromInput(
2321+
yamlHeatmap?.startWeekOn,
2322+
heatmap.startWeekOn
2323+
);
2324+
// Validate day abbreviation - supports both abbreviations and full names
2325+
if (heatmapStartWeekOnValue) {
2326+
const normalized = heatmapStartWeekOnValue.toLowerCase().trim();
2327+
const validDays = ["sun", "sunday", "mon", "monday", "tue", "tuesday", "wed", "wednesday", "thu", "thursday", "fri", "friday", "sat", "saturday"];
2328+
if (!validDays.includes(normalized)) {
2329+
errorMessage = `Invalid startWeekOn value: "${heatmapStartWeekOnValue}". Must be one of: Sun, Mon, Tue, Wed, Thu, Fri, Sat (or full day names like Sunday, Monday, etc.)`;
2330+
return errorMessage;
2331+
}
2332+
}
2333+
heatmap.startWeekOn = heatmapStartWeekOnValue;
2334+
23092335
renderInfo.heatmap.push(heatmap);
23102336
}
23112337
// console.log(renderInfo.heatmap);

0 commit comments

Comments
 (0)