Skip to content

Commit 3b45670

Browse files
authored
Merge pull request #48 from SUNET/kano-week-start-day
feat: configurable week start day
2 parents 641a73d + 36276c0 commit 3b45670

File tree

5 files changed

+97
-6
lines changed

5 files changed

+97
-6
lines changed

src/components/calendar/CalendarSidebar.vue

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { ref } from "vue";
33
import { useCalendarStore } from "@/stores/calendar";
44
import { useAccountsStore } from "@/stores/accounts";
5+
import { useUiStore } from "@/stores/ui";
56
import type { Calendar } from "@/lib/types";
67
import { dragCalendarEvent, isCalendarDragging } from "@/lib/calendar-drag-state";
78
import { showToast } from "@/lib/toast";
@@ -19,6 +20,7 @@ const emit = defineEmits<{
1920
2021
const calendarStore = useCalendarStore();
2122
const accountsStore = useAccountsStore();
23+
const uiStore = useUiStore();
2224
2325
function getAccountLabel(accountId: string): string {
2426
const acc = accountsStore.accounts.find((a) => a.id === accountId);
@@ -146,6 +148,20 @@ async function unsubscribeThisCalendar() {
146148
</div>
147149
</div>
148150

151+
<div class="week-start-section">
152+
<div class="section-header">Week starts on</div>
153+
<div class="week-start-options">
154+
<button
155+
v-for="opt in [{ day: 0, label: 'Sunday' }, { day: 1, label: 'Monday' }, { day: 6, label: 'Saturday' }]"
156+
:key="opt.day"
157+
class="week-start-btn"
158+
:class="{ active: uiStore.weekStartDay === opt.day }"
159+
:data-testid="`week-start-${opt.day}`"
160+
@click="uiStore.setWeekStartDay(opt.day)"
161+
>{{ opt.label }}</button>
162+
</div>
163+
</div>
164+
149165
<!-- Right-click context menu -->
150166
<Teleport to="body">
151167
<div
@@ -257,6 +273,45 @@ async function unsubscribeThisCalendar() {
257273
font-size: 12px;
258274
padding: 8px 4px;
259275
}
276+
277+
.week-start-section {
278+
margin-top: 16px;
279+
padding-top: 12px;
280+
border-top: 1px solid var(--color-border);
281+
}
282+
283+
.section-header {
284+
font-size: 10px;
285+
font-weight: 700;
286+
color: var(--color-text-muted);
287+
text-transform: uppercase;
288+
letter-spacing: 1px;
289+
padding: 0 4px 8px;
290+
}
291+
292+
.week-start-options {
293+
display: flex;
294+
flex-direction: column;
295+
gap: 2px;
296+
}
297+
298+
.week-start-btn {
299+
padding: 4px 8px;
300+
font-size: 12px;
301+
color: var(--color-text-secondary);
302+
text-align: left;
303+
border-radius: 4px;
304+
transition: background 0.1s;
305+
}
306+
307+
.week-start-btn:hover {
308+
background: var(--color-bg-hover);
309+
}
310+
311+
.week-start-btn.active {
312+
color: var(--color-accent);
313+
font-weight: 600;
314+
}
260315
</style>
261316

262317
<style>

src/components/calendar/MonthView.vue

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import { computed, ref, onUnmounted } from "vue";
33
import { useCalendarStore } from "@/stores/calendar";
4+
import { useUiStore } from "@/stores/ui";
45
import type { CalendarEvent } from "@/lib/types";
56
import { dragCalendarEvent, isCalendarDragging } from "@/lib/calendar-drag-state";
67
@@ -17,6 +18,7 @@ const emit = defineEmits<{
1718
}>();
1819
1920
const calendarStore = useCalendarStore();
21+
const uiStore = useUiStore();
2022
2123
const weeks = computed(() => {
2224
const d = new Date(calendarStore.currentDate);
@@ -25,9 +27,10 @@ const weeks = computed(() => {
2527
const firstDay = new Date(year, month, 1);
2628
const lastDay = new Date(year, month + 1, 0);
2729
28-
// Start from Sunday of the first week
30+
// Start from the configured week start day
2931
const start = new Date(firstDay);
30-
start.setDate(start.getDate() - start.getDay());
32+
const offset = (start.getDay() - uiStore.weekStartDay + 7) % 7;
33+
start.setDate(start.getDate() - offset);
3134
3235
const rows: Date[][] = [];
3336
const current = new Date(start);
@@ -72,7 +75,11 @@ function getEventColor(event: { calendar_id: string }): string {
7275
return cal?.color || "#4285f4";
7376
}
7477
75-
const dayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
78+
const allDayNames = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
79+
const dayNames = computed(() => {
80+
const s = uiStore.weekStartDay;
81+
return [...allDayNames.slice(s), ...allDayNames.slice(0, s)];
82+
});
7683
7784
// Drag-to-reschedule
7885
const dragStartPos = ref<{ x: number; y: number } | null>(null);

src/components/calendar/WeekView.vue

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
<script setup lang="ts">
22
import { computed, onMounted, onUnmounted, ref, nextTick } from "vue";
33
import { useCalendarStore } from "@/stores/calendar";
4+
import { useUiStore } from "@/stores/ui";
45
import type { CalendarEvent } from "@/lib/types";
56
import { dragCalendarEvent, isCalendarDragging } from "@/lib/calendar-drag-state";
67
@@ -21,6 +22,7 @@ const emit = defineEmits<{
2122
}>();
2223
2324
const calendarStore = useCalendarStore();
25+
const uiStore = useUiStore();
2426
const gridRef = ref<HTMLElement | null>(null);
2527
2628
const hours = Array.from({ length: 24 }, (_, i) => i);
@@ -31,7 +33,8 @@ const days = computed(() => {
3133
return [new Date(d)];
3234
}
3335
const start = new Date(d);
34-
start.setDate(d.getDate() - d.getDay()); // Sunday
36+
const offset = (d.getDay() - uiStore.weekStartDay + 7) % 7;
37+
start.setDate(d.getDate() - offset);
3538
return Array.from({ length: 7 }, (_, i) => {
3639
const day = new Date(start);
3740
day.setDate(start.getDate() + i);
@@ -67,7 +70,13 @@ function isToday(date: Date): boolean {
6770
}
6871
6972
function isWeekend(date: Date): boolean {
70-
return date.getDay() === 0 || date.getDay() === 6;
73+
const day = date.getDay();
74+
if (uiStore.weekStartDay === 6) {
75+
// Saturday start → weekend is Thursday (4) + Friday (5)
76+
return day === 4 || day === 5;
77+
}
78+
// Sunday or Monday start → weekend is Saturday (6) + Sunday (0)
79+
return day === 0 || day === 6;
7180
}
7281
7382
function isCurrentHour(hour: number): boolean {

src/stores/calendar.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import type { Calendar, CalendarEvent, NewEventInput } from "@/lib/types";
55
import { expandRRule } from "@/lib/rrule";
66
import * as api from "@/lib/tauri";
77
import { useAccountsStore } from "./accounts";
8+
import { useUiStore } from "./ui";
89

910
export type CalendarViewMode = "day" | "week" | "month";
1011

@@ -17,6 +18,7 @@ export const useCalendarStore = defineStore("calendar", () => {
1718
const selectedEvent = ref<CalendarEvent | null>(null);
1819

1920
const accountsStore = useAccountsStore();
21+
const uiStore = useUiStore();
2022

2123
// Visible calendars (all by default). Persisted to localStorage so the
2224
// user's hide/show picks survive across sessions.
@@ -95,7 +97,8 @@ export const useCalendarStore = defineStore("calendar", () => {
9597
end.setHours(23, 59, 59, 999);
9698
} else if (viewMode.value === "week") {
9799
start = new Date(d);
98-
start.setDate(d.getDate() - d.getDay()); // Sunday
100+
const offset = (d.getDay() - uiStore.weekStartDay + 7) % 7;
101+
start.setDate(d.getDate() - offset);
99102
start.setHours(0, 0, 0, 0);
100103
end = new Date(start);
101104
end.setDate(start.getDate() + 6);

src/stores/ui.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ export const useUiStore = defineStore("ui", () => {
2222
localStorage.getItem("chithi-decorations") !== "false",
2323
);
2424

25+
// Week start day: 0 = Sunday, 1 = Monday, 6 = Saturday
26+
const VALID_WEEK_STARTS = [0, 1, 6];
27+
const weekStartDay = ref<number>(
28+
(() => {
29+
const stored = parseInt(localStorage.getItem("chithi-week-start-day") || "0", 10);
30+
return VALID_WEEK_STARTS.includes(stored) ? stored : 0;
31+
})(),
32+
);
33+
2534
function toggleReader() {
2635
readerVisible.value = !readerVisible.value;
2736
}
@@ -56,6 +65,12 @@ export const useUiStore = defineStore("ui", () => {
5665
getCurrentWindow().setDecorations(enabled);
5766
}
5867

68+
function setWeekStartDay(day: number) {
69+
if (!VALID_WEEK_STARTS.includes(day)) return;
70+
weekStartDay.value = day;
71+
localStorage.setItem("chithi-week-start-day", String(day));
72+
}
73+
5974
function initTheme() {
6075
document.documentElement.setAttribute("data-theme", theme.value);
6176
}
@@ -92,5 +107,7 @@ export const useUiStore = defineStore("ui", () => {
92107
initDecorations,
93108
operationsPanelOpen,
94109
toggleOperationsPanel,
110+
weekStartDay,
111+
setWeekStartDay,
95112
};
96113
});

0 commit comments

Comments
 (0)