Skip to content

Commit 41a29b0

Browse files
committed
feat: add week start on Monday setting
Add user preference to start the calendar week on Monday instead of Sunday (European style). Includes database migration, backend API support, and Settings UI toggle.
2 parents 62e4104 + 77baa40 commit 41a29b0

File tree

17 files changed

+376
-38
lines changed

17 files changed

+376
-38
lines changed

app/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ class User(Base):
220220
calendar_token = Column(String(64), unique=True, nullable=True)
221221
kanban_enabled = Column(Boolean, nullable=True, default=False)
222222
kanban_columns = Column(String(512), nullable=True, default='["todo", "done"]')
223+
week_start_monday = Column(Boolean, nullable=True, default=False)
223224
notes = relationship("Note", lazy="dynamic", cascade="all, delete, delete-orphan")
224225
meta = relationship("Meta", lazy="dynamic", cascade="all, delete, delete-orphan")
225226
external_calendars = relationship(

app/routes.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1280,6 +1280,8 @@ async def sidebar_data():
12801280
except (json.JSONDecodeError, TypeError):
12811281
kanban_columns = ["todo", "done"]
12821282

1283+
week_start_monday = user.week_start_monday or False
1284+
12831285
return (
12841286
jsonify(
12851287
tags=tags,
@@ -1290,6 +1292,7 @@ async def sidebar_data():
12901292
vim_mode=vim_mode,
12911293
kanban_enabled=kanban_enabled,
12921294
kanban_columns=kanban_columns,
1295+
week_start_monday=week_start_monday,
12931296
),
12941297
200,
12951298
)
@@ -1373,6 +1376,7 @@ async def get_settings():
13731376
vim_mode=user.vim_mode or False,
13741377
kanban_enabled=user.kanban_enabled or False,
13751378
kanban_columns=kanban_columns,
1379+
week_start_monday=user.week_start_monday or False,
13761380
),
13771381
200,
13781382
)
@@ -1414,6 +1418,9 @@ async def update_settings():
14141418
if valid_columns:
14151419
user.kanban_columns = json.dumps(valid_columns)
14161420

1421+
if "week_start_monday" in req:
1422+
user.week_start_monday = req["week_start_monday"]
1423+
14171424
db.session.add(user)
14181425
db.session.flush()
14191426
db.session.commit()
@@ -1432,6 +1439,7 @@ async def update_settings():
14321439
vim_mode=user.vim_mode or False,
14331440
kanban_enabled=user.kanban_enabled or False,
14341441
kanban_columns=kanban_columns,
1442+
week_start_monday=user.week_start_monday or False,
14351443
),
14361444
200,
14371445
)

client/src/components/Calendar.vue

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
:nearby-month-days="true"
99
:nearby-selectable-month-days="true"
1010
:focusable="false"
11+
:first-day-of-week="sidebar.weekStartMonday ? 1 : 0"
1112
@update:model-value="changeDate"
1213
>
1314
</b-datepicker>

client/src/components/Editor.vue

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { computed, inject, onBeforeUnmount, onMounted, ref, watch } from 'vue';
3535
import type { IGlobal } from '../interfaces';
3636
3737
import { newDay, newNote } from '../services/consts';
38+
import directionService from '../services/direction';
3839
import eventHub from '../services/eventHub';
3940
import { SharedBuefy } from '../services/sharedBuefy';
4041
import themeService from '../services/theme';
@@ -813,6 +814,10 @@ const getExtensions = (): Extension[] => {
813814
const newValue = update.state.doc.toString();
814815
generateTaskList(newValue);
815816
throttledEmit(newValue);
817+
// Update auto-direction if in auto mode
818+
if (directionService.preference === 'auto') {
819+
debouncedDirectionUpdate(newValue);
820+
}
816821
}
817822
}),
818823
EditorView.domEventHandlers({
@@ -859,6 +864,15 @@ const throttledEmit = _.throttle(
859864
{ trailing: true, leading: false }
860865
);
861866
867+
// Debounced direction update for auto-detection
868+
const debouncedDirectionUpdate = _.debounce(
869+
(value: string) => {
870+
directionService.updateAutoDirection(value);
871+
},
872+
500,
873+
{ trailing: true, leading: false }
874+
);
875+
862876
onMounted(() => {
863877
if (!editorContainer.value) return;
864878
@@ -873,6 +887,10 @@ onMounted(() => {
873887
handleValueUpdate(true);
874888
// Generate task list on initial mount
875889
generateTaskList(props.value || '');
890+
// Trigger auto-direction on initial content
891+
if (directionService.preference === 'auto') {
892+
directionService.updateAutoDirection(props.value || '');
893+
}
876894
eventHub.on('focusEditor', focus);
877895
});
878896
@@ -977,7 +995,7 @@ defineExpose({
977995
}
978996
979997
.editor :deep(.cm-gutters) {
980-
padding-left: 4px;
998+
padding-inline-start: 4px;
981999
}
9821000
}
9831001
</style>

client/src/components/Header.vue

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -409,15 +409,14 @@ const logout = () => {
409409
}
410410
411411
.dropdown-text {
412-
margin-left: 8px;
413-
margin-right: 12px;
412+
margin-inline-start: 8px;
413+
margin-inline-end: 12px;
414414
}
415415
416416
.dropdown-shortcut {
417417
opacity: 0.6;
418418
font-size: 0.85em;
419-
margin-left: auto;
420-
float: right;
419+
margin-inline-start: auto;
421420
}
422421
423422
/* Mobile-only items in dropdown - hidden by default */
@@ -456,8 +455,8 @@ const logout = () => {
456455
}
457456
458457
.header-title {
459-
margin-left: 0.5em;
460-
margin-right: 0.5em;
458+
margin-inline-start: 0.5em;
459+
margin-inline-end: 0.5em;
461460
}
462461
463462
.header-left,

client/src/components/MarkdownPreview.vue

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ const toggleCheckboxInMarkdown = (checkboxInfo: CheckboxInfo): string => {
373373
color: var(--syntax-keyword);
374374
font-weight: 600;
375375
min-width: 100px;
376-
margin-right: 12px;
376+
margin-inline-end: 12px;
377377
font-size: 0.9em;
378378
}
379379
@@ -460,14 +460,14 @@ const toggleCheckboxInMarkdown = (checkboxInfo: CheckboxInfo): string => {
460460
461461
/* Lists */
462462
.preview-content :deep(ul) {
463-
padding-left: 2em;
463+
padding-inline-start: 2em;
464464
margin-top: 0;
465465
margin-bottom: 16px;
466466
list-style-type: disc;
467467
}
468468
469469
.preview-content :deep(ol) {
470-
padding-left: 2em;
470+
padding-inline-start: 2em;
471471
margin-top: 0;
472472
margin-bottom: 16px;
473473
list-style-type: decimal;
@@ -490,11 +490,11 @@ const toggleCheckboxInMarkdown = (checkboxInfo: CheckboxInfo): string => {
490490
/* Task lists */
491491
.preview-content :deep(.task-list-item) {
492492
list-style-type: none;
493-
margin-left: -1.5em;
493+
margin-inline-start: -1.5em;
494494
}
495495
496496
.preview-content :deep(.task-list-item input[type="checkbox"]) {
497-
margin-right: 0.5em;
497+
margin-inline-end: 0.5em;
498498
vertical-align: middle;
499499
cursor: pointer;
500500
accent-color: var(--accent-primary);
@@ -531,9 +531,9 @@ const toggleCheckboxInMarkdown = (checkboxInfo: CheckboxInfo): string => {
531531
532532
/* Blockquotes */
533533
.preview-content :deep(blockquote) {
534-
border-left: 4px solid var(--text-link);
535-
padding-left: 16px;
536-
margin-left: 0;
534+
border-inline-start: 4px solid var(--text-link);
535+
padding-inline-start: 16px;
536+
margin-inline-start: 0;
537537
margin-bottom: 16px;
538538
color: var(--text-muted);
539539
}
@@ -549,7 +549,7 @@ const toggleCheckboxInMarkdown = (checkboxInfo: CheckboxInfo): string => {
549549
.preview-content :deep(table td) {
550550
border: 1px solid var(--border-color);
551551
padding: 8px 12px;
552-
text-align: left;
552+
text-align: start;
553553
}
554554
555555
.preview-content :deep(table th) {
@@ -614,7 +614,7 @@ const toggleCheckboxInMarkdown = (checkboxInfo: CheckboxInfo): string => {
614614
615615
.frontmatter-key {
616616
min-width: 80px;
617-
margin-right: 8px;
617+
margin-inline-end: 8px;
618618
}
619619
620620
.preview-content :deep(pre) {

client/src/components/NestedTags.vue

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@
7575
</template>
7676

7777
<script setup lang="ts">
78-
import { ref, computed, watch } from 'vue';
78+
import { computed, ref, watch } from 'vue';
7979
import type { ITagNode } from '../interfaces';
8080
import { getExpandedTags, saveExpandedTags } from '../services/localstorage';
8181
@@ -169,7 +169,7 @@ function onChildExpandedChange(childExpanded: string[]) {
169169
}
170170
171171
.children-inline {
172-
padding-left: 20px;
172+
padding-inline-start: 20px;
173173
}
174174
175175
/* Nested level: inline layout */
@@ -188,7 +188,7 @@ function onChildExpandedChange(childExpanded: string[]) {
188188
189189
.sub-children {
190190
display: inline-flex;
191-
margin-left: 0.25em;
191+
margin-inline-start: 0.25em;
192192
}
193193
194194
/* Toggle icons */
@@ -201,7 +201,7 @@ function onChildExpandedChange(childExpanded: string[]) {
201201
cursor: pointer;
202202
color: var(--text-muted);
203203
font-size: 0.7em;
204-
margin-right: 4px;
204+
margin-inline-end: 4px;
205205
flex-shrink: 0;
206206
}
207207
@@ -216,7 +216,7 @@ function onChildExpandedChange(childExpanded: string[]) {
216216
cursor: pointer;
217217
color: var(--text-muted);
218218
font-size: 0.7em;
219-
margin-right: 2px;
219+
margin-inline-end: 2px;
220220
width: 12px;
221221
}
222222

0 commit comments

Comments
 (0)