diff --git a/docs/releases/unreleased.md b/docs/releases/unreleased.md
index ca144a1ba..ba331111f 100644
--- a/docs/releases/unreleased.md
+++ b/docs/releases/unreleased.md
@@ -68,6 +68,9 @@ When a change has user-facing documentation, include a canonical tasknotes.dev l
guides for adopting TaskNotes in an existing vault, mobile use, custom Bases,
and backup and recovery. See the
[TaskNotes documentation](https://tasknotes.dev/).
+- Custom recurrence dialog Interval and Days of week descriptions now update based on the selected frequency (for example, "Every x days" when Daily is selected).
+- Custom recurrence dialog weekday checkboxes stay on one row with clearer spacing below the description, and radio option markers are centered when selected.
+- Native date and time fields across recurrence, date/time picker, timeblock, and reminder modals share consistent padding, border, and corner rounding.
- (#2088) Convert current note to task now uses your default scheduled date when
the note does not already have `scheduled` frontmatter, while the **None**
default still leaves converted notes unscheduled. See
@@ -76,6 +79,8 @@ When a change has user-facing documentation, include a canonical tasknotes.dev l
## Fixed
+- Fixed the Custom recurrence dialog's Monthly, Yearly, and End condition options so switching between "on this date" and "on the Nth weekday" (or between "never"/"after N occurrences"/"until a date") greys out the fields that no longer apply, instead of leaving both sets of controls active and editable at once.
+- Fixed the Custom recurrence dialog not being translated, despite translations already being available for it.
- (#2182) Checklist progress on task cards now excludes cancelled markdown
checklist items such as `[-]` from the completed/total count. Thanks to
@ctrl-q for reporting this.
diff --git a/i18n.manifest.json b/i18n.manifest.json
index b22da7307..0c6ecf0d9 100644
--- a/i18n.manifest.json
+++ b/i18n.manifest.json
@@ -2180,8 +2180,13 @@
"components.recurrenceContextMenu.customRecurrenceModal.frequency": "89836a870e44fb467d13116254b39e2482f5cdf1",
"components.recurrenceContextMenu.customRecurrenceModal.interval": "011efcd591019b5969a332a24dff728a8107dbe2",
"components.recurrenceContextMenu.customRecurrenceModal.intervalDesc": "5e0d9119317427c6517942235c7ee7c72c3f1eba",
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescDaily": "e236ef92e5f3f2d38f99c1aa182f757fbf097bdb",
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescWeekly": "cf6745ebffd319ac91db22b896353d0dd8d72dd2",
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescMonthly": "80c69ef898a0d3731a9f09fe4f4cc07cbc332ce5",
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescYearly": "dca87051697daf49d7f7da5b2d97a6f8b37e70de",
"components.recurrenceContextMenu.customRecurrenceModal.daysOfWeek": "318d817389a2ddc335aabaaea49dd75a998bc7b5",
"components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDesc": "a6eebf484377fe1bbc03824b639a3b4f7d8b3225",
+ "components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDescDaily": "b6edf522d10c13fd3723d455ebee16141a70ed68",
"components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrence": "e0c2c6f69efcf30626e7a5b71ba3b504ee5fe8e6",
"components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrenceDesc": "4c49c84e721518ec3861af880e70c526308bcf98",
"components.recurrenceContextMenu.customRecurrenceModal.yearlyRecurrence": "abfca4467453d216a82a9a556893f4ad1677b935",
diff --git a/i18n.state.json b/i18n.state.json
index aea59c7fa..5a2f554c8 100644
--- a/i18n.state.json
+++ b/i18n.state.json
@@ -8724,6 +8724,22 @@
"source": "5e0d9119317427c6517942235c7ee7c72c3f1eba",
"translation": "d45992fe7e4b03553a46221afe4558b4f3690e36"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescDaily": {
+ "source": "e236ef92e5f3f2d38f99c1aa182f757fbf097bdb",
+ "translation": "c3d515af1d633fe683e20618d0e3de3420829dc3"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescWeekly": {
+ "source": "cf6745ebffd319ac91db22b896353d0dd8d72dd2",
+ "translation": "cc25dcbd4f8ca8c9f7dc3d9644e92cff560d08df"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescMonthly": {
+ "source": "80c69ef898a0d3731a9f09fe4f4cc07cbc332ce5",
+ "translation": "a9ad003eae6ce2c4b051b5b702e12724c9881f4c"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescYearly": {
+ "source": "dca87051697daf49d7f7da5b2d97a6f8b37e70de",
+ "translation": "090ee18bc0de4e0f6bf14e3e78246c73d40a0928"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.daysOfWeek": {
"source": "318d817389a2ddc335aabaaea49dd75a998bc7b5",
"translation": "1d474635b5d26d18871e4f555a4d8634855eb08a"
@@ -8732,6 +8748,10 @@
"source": "a6eebf484377fe1bbc03824b639a3b4f7d8b3225",
"translation": "003b98a14b62214b48b25d3e5757c7e8984b946b"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDescDaily": {
+ "source": "b6edf522d10c13fd3723d455ebee16141a70ed68",
+ "translation": "04a621198f0ca39052fc214130af6fe12b6b3e6d"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrence": {
"source": "e0c2c6f69efcf30626e7a5b71ba3b504ee5fe8e6",
"translation": "6892ee18121a784f543035c219f74eb1a432b883"
@@ -17610,6 +17630,22 @@
"source": "5e0d9119317427c6517942235c7ee7c72c3f1eba",
"translation": "b324e86167e22e49f7d26014422c07c24e4dd7cd"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescDaily": {
+ "source": "e236ef92e5f3f2d38f99c1aa182f757fbf097bdb",
+ "translation": "843f410b90d8490068b3b18305b89eb7eee87b48"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescWeekly": {
+ "source": "cf6745ebffd319ac91db22b896353d0dd8d72dd2",
+ "translation": "c8de42daea359ccde55b95527712d66b382eddea"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescMonthly": {
+ "source": "80c69ef898a0d3731a9f09fe4f4cc07cbc332ce5",
+ "translation": "098f02de83f54ea69d4e634630fc336df6841128"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescYearly": {
+ "source": "dca87051697daf49d7f7da5b2d97a6f8b37e70de",
+ "translation": "3380675e6d1f84934396df46338b1b5f4ad38037"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.daysOfWeek": {
"source": "318d817389a2ddc335aabaaea49dd75a998bc7b5",
"translation": "e65fcf42b9a3b24a99b6b67999aaf7603db83692"
@@ -17618,6 +17654,10 @@
"source": "a6eebf484377fe1bbc03824b639a3b4f7d8b3225",
"translation": "ab2808699f882a069aaf0cbfe083267840da74d3"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDescDaily": {
+ "source": "b6edf522d10c13fd3723d455ebee16141a70ed68",
+ "translation": "60529e6a37b5e1f18b79e8d3f16bb809e53dec29"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrence": {
"source": "e0c2c6f69efcf30626e7a5b71ba3b504ee5fe8e6",
"translation": "99f4fd170f22be947baeb2a8eb188e05ef02f01c"
@@ -26496,6 +26536,22 @@
"source": "5e0d9119317427c6517942235c7ee7c72c3f1eba",
"translation": "1292eb0c8dceb4123a55700ed789ec1105dde4d5"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescDaily": {
+ "source": "e236ef92e5f3f2d38f99c1aa182f757fbf097bdb",
+ "translation": "a3ac31d20d9eaa5cd76bd0d848246e68e45acfc4"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescWeekly": {
+ "source": "cf6745ebffd319ac91db22b896353d0dd8d72dd2",
+ "translation": "99f1aa3847319036bab6ff1959931f7aae7d7ed5"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescMonthly": {
+ "source": "80c69ef898a0d3731a9f09fe4f4cc07cbc332ce5",
+ "translation": "38876d26d7759820aeb72fb03ddef230a6571436"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescYearly": {
+ "source": "dca87051697daf49d7f7da5b2d97a6f8b37e70de",
+ "translation": "df80775997ab731d4000ed5bd80f76cfcae58e3c"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.daysOfWeek": {
"source": "318d817389a2ddc335aabaaea49dd75a998bc7b5",
"translation": "8cf350a0e2caf535ce868898a8943f9755ebab10"
@@ -26504,6 +26560,10 @@
"source": "a6eebf484377fe1bbc03824b639a3b4f7d8b3225",
"translation": "a8099711803b56edc81fda3fce33fa7cc2f76e53"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDescDaily": {
+ "source": "b6edf522d10c13fd3723d455ebee16141a70ed68",
+ "translation": "e0e63f921cf98f2700cd532496bcbb235e24e887"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrence": {
"source": "e0c2c6f69efcf30626e7a5b71ba3b504ee5fe8e6",
"translation": "cc5a4e7850e54e4953522d213fc48d6cbb3b90c8"
@@ -35382,6 +35442,22 @@
"source": "5e0d9119317427c6517942235c7ee7c72c3f1eba",
"translation": "f8e1d3ebb3803e2c1e6cb007fbca9826f5ab0842"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescDaily": {
+ "source": "e236ef92e5f3f2d38f99c1aa182f757fbf097bdb",
+ "translation": "9ff5a5d0be000d16c6184cb9639223f0287cd18a"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescWeekly": {
+ "source": "cf6745ebffd319ac91db22b896353d0dd8d72dd2",
+ "translation": "2878740708f635d155610290632a1a9dbfc637d2"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescMonthly": {
+ "source": "80c69ef898a0d3731a9f09fe4f4cc07cbc332ce5",
+ "translation": "96df23a6cc46acf4c28492b992055e93ccf35657"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescYearly": {
+ "source": "dca87051697daf49d7f7da5b2d97a6f8b37e70de",
+ "translation": "c48ed1fb5f54e1c07ce4053baca0ba04e08f29c4"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.daysOfWeek": {
"source": "318d817389a2ddc335aabaaea49dd75a998bc7b5",
"translation": "234df0a0cf39f296d2b6cf2944354a6380e90e80"
@@ -35390,6 +35466,10 @@
"source": "a6eebf484377fe1bbc03824b639a3b4f7d8b3225",
"translation": "f24641e4e57c9d5505d420ade3a74dff5b66c215"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDescDaily": {
+ "source": "b6edf522d10c13fd3723d455ebee16141a70ed68",
+ "translation": "b0a95ec35cc5d0a157cdf1910b1b4d6182f25f82"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrence": {
"source": "e0c2c6f69efcf30626e7a5b71ba3b504ee5fe8e6",
"translation": "b8bbbbf564ce9e152b6bc7ae83ff86f31f5d2c4f"
@@ -44268,6 +44348,22 @@
"source": "5e0d9119317427c6517942235c7ee7c72c3f1eba",
"translation": "77a102dc23b4e112c190328f9a616b65d9e045a4"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescDaily": {
+ "source": "e236ef92e5f3f2d38f99c1aa182f757fbf097bdb",
+ "translation": "28317054b0464c43e8123c2bd9dc1fe7e5b3b0a0"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescWeekly": {
+ "source": "cf6745ebffd319ac91db22b896353d0dd8d72dd2",
+ "translation": "3092f778e898a8fd5cf4e6675ccc221bb49fe195"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescMonthly": {
+ "source": "80c69ef898a0d3731a9f09fe4f4cc07cbc332ce5",
+ "translation": "296f6d311b85421bc279e5b9a3a7ffcee823042a"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescYearly": {
+ "source": "dca87051697daf49d7f7da5b2d97a6f8b37e70de",
+ "translation": "b9e12b2af18059e0dd79d51fbdaecb6a3c736aa4"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.daysOfWeek": {
"source": "318d817389a2ddc335aabaaea49dd75a998bc7b5",
"translation": "e7215fb35261da63918112f9017c9c0305f65694"
@@ -44276,6 +44372,10 @@
"source": "a6eebf484377fe1bbc03824b639a3b4f7d8b3225",
"translation": "b29adffec57cd5506483d26aee4d9aac9530cd8f"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDescDaily": {
+ "source": "b6edf522d10c13fd3723d455ebee16141a70ed68",
+ "translation": "16132e5e1ada3b2f0ee8b9f02c19e831e2c8d422"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrence": {
"source": "e0c2c6f69efcf30626e7a5b71ba3b504ee5fe8e6",
"translation": "61dfaade24252fe0c6cbb09d78617306f1d40bdd"
@@ -53154,6 +53254,22 @@
"source": "5e0d9119317427c6517942235c7ee7c72c3f1eba",
"translation": "962411a1c0e633fb1ad58fa2cf31f10ac1bfd754"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescDaily": {
+ "source": "e236ef92e5f3f2d38f99c1aa182f757fbf097bdb",
+ "translation": "2520d43ff40983d2696a4ccec1a30f358c811cf7"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescWeekly": {
+ "source": "cf6745ebffd319ac91db22b896353d0dd8d72dd2",
+ "translation": "b17e3681182e8742476ecaa14f31d939829677cb"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescMonthly": {
+ "source": "80c69ef898a0d3731a9f09fe4f4cc07cbc332ce5",
+ "translation": "3731e4458b9e091e8ee8eeeee45575de19fdb1de"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescYearly": {
+ "source": "dca87051697daf49d7f7da5b2d97a6f8b37e70de",
+ "translation": "5e3951e90e521117d17b8059c3904d438f5e44cf"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.daysOfWeek": {
"source": "318d817389a2ddc335aabaaea49dd75a998bc7b5",
"translation": "cec95235f4dee9444e15056b440e4a18ac394f4a"
@@ -53162,6 +53278,10 @@
"source": "a6eebf484377fe1bbc03824b639a3b4f7d8b3225",
"translation": "24016c4914db9f6f5d80511538ca8902e6d30054"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDescDaily": {
+ "source": "b6edf522d10c13fd3723d455ebee16141a70ed68",
+ "translation": "677cbea33b6321c8961b76f282005bcee6c49578"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrence": {
"source": "e0c2c6f69efcf30626e7a5b71ba3b504ee5fe8e6",
"translation": "bfeb544b73d3b18c572c6addf6f65aaff4d024b4"
@@ -62040,6 +62160,22 @@
"source": "5e0d9119317427c6517942235c7ee7c72c3f1eba",
"translation": "79cd1a9542a4a265933552f506dc12fef41a6bc7"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescDaily": {
+ "source": "e236ef92e5f3f2d38f99c1aa182f757fbf097bdb",
+ "translation": "7e7f976bdca45d108aae2bd1e3c59d97dbc7ed47"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescWeekly": {
+ "source": "cf6745ebffd319ac91db22b896353d0dd8d72dd2",
+ "translation": "301a3611a61c55aabf99d31a082c437e3d664fea"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescMonthly": {
+ "source": "80c69ef898a0d3731a9f09fe4f4cc07cbc332ce5",
+ "translation": "956e658af99cf34e07e288f0b493ad57d164e61b"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescYearly": {
+ "source": "dca87051697daf49d7f7da5b2d97a6f8b37e70de",
+ "translation": "8a7d812133c4324ab9d72c57b49b11c822476554"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.daysOfWeek": {
"source": "318d817389a2ddc335aabaaea49dd75a998bc7b5",
"translation": "5b471418f723305e477e2366b05932e22325b297"
@@ -62048,6 +62184,10 @@
"source": "a6eebf484377fe1bbc03824b639a3b4f7d8b3225",
"translation": "0e0ce5484ff11a3058e2b3d8a5b8dc6f1042c69d"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDescDaily": {
+ "source": "b6edf522d10c13fd3723d455ebee16141a70ed68",
+ "translation": "71dd74361470b441b3ec0b8daad98a3374c28409"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrence": {
"source": "e0c2c6f69efcf30626e7a5b71ba3b504ee5fe8e6",
"translation": "8ef10984235523669bd111e0d1c2db8e43eb7f47"
@@ -70926,6 +71066,22 @@
"source": "5e0d9119317427c6517942235c7ee7c72c3f1eba",
"translation": "db774e0760bf80d7718cb376f15d3e4d5a099e7c"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescDaily": {
+ "source": "e236ef92e5f3f2d38f99c1aa182f757fbf097bdb",
+ "translation": "482e6c2514ef82879b26e4f524f6c7973b30054e"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescWeekly": {
+ "source": "cf6745ebffd319ac91db22b896353d0dd8d72dd2",
+ "translation": "9b75d17b29dcd40daaaf528a95b1f97acc45ce5f"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescMonthly": {
+ "source": "80c69ef898a0d3731a9f09fe4f4cc07cbc332ce5",
+ "translation": "3bc98c36d67c2e9b02391033e715ca163a687cc9"
+ },
+ "components.recurrenceContextMenu.customRecurrenceModal.intervalDescYearly": {
+ "source": "dca87051697daf49d7f7da5b2d97a6f8b37e70de",
+ "translation": "3dff2bb8bd58d097f88e9c1ea05fa526c7532e9d"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.daysOfWeek": {
"source": "318d817389a2ddc335aabaaea49dd75a998bc7b5",
"translation": "417ed486f9a6c1909e97ff5285e6deea2c0d73ac"
@@ -70934,6 +71090,10 @@
"source": "a6eebf484377fe1bbc03824b639a3b4f7d8b3225",
"translation": "e92f42241a2e1a3778ac58de2434c88c346b68ee"
},
+ "components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDescDaily": {
+ "source": "b6edf522d10c13fd3723d455ebee16141a70ed68",
+ "translation": "8d37386127b3c6d7598e58f7e90ed919b24ce51c"
+ },
"components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrence": {
"source": "e0c2c6f69efcf30626e7a5b71ba3b504ee5fe8e6",
"translation": "4ea55aa42d1f6c301b2dcc9ccf075333c3970c44"
diff --git a/src/components/RecurrenceContextMenu.ts b/src/components/RecurrenceContextMenu.ts
index 4b1dccce8..414f48ee6 100644
--- a/src/components/RecurrenceContextMenu.ts
+++ b/src/components/RecurrenceContextMenu.ts
@@ -722,21 +722,67 @@ class CustomRecurrenceModal extends Modal {
onOpen() {
const { contentEl } = this;
contentEl.empty();
+ contentEl.addClass("tasknotes-plugin");
+ contentEl.addClass("tn-custom-recurrence-modal");
+ this.modalEl.addClass("tn-custom-recurrence-modal-host");
const calendarLocale = getPluginCalendarLocale(this.plugin);
const firstDay = this.plugin.settings?.calendarViewSettings?.firstDay;
const orderedWeekdays = getOrderedRecurrenceWeekdays(firstDay, calendarLocale);
const recurrenceStartDate = getRecurrenceStartDate(this.scheduledDate);
+ const getIntervalDescKey = (): TranslationKey => {
+ switch (this.frequency) {
+ case "WEEKLY":
+ return "components.recurrenceContextMenu.customRecurrenceModal.intervalDescWeekly";
+ case "MONTHLY":
+ return "components.recurrenceContextMenu.customRecurrenceModal.intervalDescMonthly";
+ case "YEARLY":
+ return "components.recurrenceContextMenu.customRecurrenceModal.intervalDescYearly";
+ case "DAILY":
+ default:
+ return "components.recurrenceContextMenu.customRecurrenceModal.intervalDescDaily";
+ }
+ };
+
+ const getDaysOfWeekDescKey = (): TranslationKey => {
+ return this.frequency === "DAILY"
+ ? "components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDescDaily"
+ : "components.recurrenceContextMenu.customRecurrenceModal.daysOfWeekDesc";
+ };
+
+ // Chromium doesn't render ::before/::after generated content on
+ // elements, so the "selected" indicator has to be a real sibling element
+ // inside its own positioning wrapper, rather than a pseudo-element on the
+ // input itself.
+ const createRadioInput = (
+ radioLabel: HTMLElement,
+ name: string,
+ value: string,
+ checked: boolean
+ ): HTMLInputElement => {
+ const visual = radioLabel.createSpan({
+ cls: "tn-custom-recurrence-modal__radio-visual",
+ });
+ const input = visual.createEl("input", { type: "radio", value });
+ input.name = name;
+ input.checked = checked;
+ visual.createSpan({ cls: "tn-custom-recurrence-modal__radio-dot" });
+ return input;
+ };
+
contentEl.createEl("h2", {
text: this.translate("components.recurrenceContextMenu.customRecurrenceModal.title"),
});
// Start date selection
new Setting(contentEl)
- .setName("Start date")
- .setDesc("The date when the recurrence pattern begins")
+ .setName(this.translate("components.recurrenceContextMenu.customRecurrenceModal.startDate"))
+ .setDesc(
+ this.translate("components.recurrenceContextMenu.customRecurrenceModal.startDateDesc")
+ )
.addText((text) => {
text.inputEl.type = "date";
+ text.inputEl.addClass("tn-datetime-input");
text.setValue(this.dtstart).onChange((value) => {
this.dtstart = value;
});
@@ -749,10 +795,13 @@ class CustomRecurrenceModal extends Modal {
// Start time selection
new Setting(contentEl)
- .setName("Start time")
- .setDesc("The time when recurring instances should appear (optional)")
+ .setName(this.translate("components.recurrenceContextMenu.customRecurrenceModal.startTime"))
+ .setDesc(
+ this.translate("components.recurrenceContextMenu.customRecurrenceModal.startTimeDesc")
+ )
.addText((text) => {
text.inputEl.type = "time";
+ text.inputEl.addClass("tn-datetime-input");
text.setValue(this.dtstartTime).onChange((value) => {
this.dtstartTime = value;
});
@@ -760,12 +809,24 @@ class CustomRecurrenceModal extends Modal {
// Recurrence anchor selection
new Setting(contentEl)
- .setName("Recur from")
- .setDesc("When should the next occurrence be calculated from?")
+ .setName(this.translate("components.recurrenceContextMenu.customRecurrenceModal.recurFrom"))
+ .setDesc(
+ this.translate("components.recurrenceContextMenu.customRecurrenceModal.recurFromDesc")
+ )
.addDropdown((dropdown) => {
dropdown
- .addOption("scheduled", "Scheduled date (fixed schedule)")
- .addOption("completion", "Completion date (flexible schedule)")
+ .addOption(
+ "scheduled",
+ this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.scheduledDate"
+ )
+ )
+ .addOption(
+ "completion",
+ this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.completionDate"
+ )
+ )
.setValue(this.recurrenceAnchor)
.onChange((value) => {
this.recurrenceAnchor = value as "scheduled" | "completion";
@@ -774,35 +835,58 @@ class CustomRecurrenceModal extends Modal {
});
// Frequency selection
- new Setting(contentEl).setName("Frequency").addDropdown((dropdown) => {
- dropdown
- .addOption("DAILY", "Daily")
- .addOption("WEEKLY", "Weekly")
- .addOption("MONTHLY", "Monthly")
- .addOption("YEARLY", "Yearly")
- .setValue(this.frequency)
- .onChange((value) => {
- this.frequency = value;
- this.updateFrequencySpecificVisibility();
- });
- });
+ new Setting(contentEl)
+ .setName(this.translate("components.recurrenceContextMenu.customRecurrenceModal.frequency"))
+ .addDropdown((dropdown) => {
+ dropdown
+ .addOption(
+ "DAILY",
+ this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.frequencies.daily"
+ )
+ )
+ .addOption(
+ "WEEKLY",
+ this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.frequencies.weekly"
+ )
+ )
+ .addOption(
+ "MONTHLY",
+ this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.frequencies.monthly"
+ )
+ )
+ .addOption(
+ "YEARLY",
+ this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.frequencies.yearly"
+ )
+ )
+ .setValue(this.frequency)
+ .onChange((value) => {
+ this.frequency = value;
+ this.updateFrequencySpecificVisibility();
+ });
+ });
// Interval selection
- new Setting(contentEl)
- .setName("Interval")
- .setDesc("Every X days/weeks/months/years")
+ const intervalSetting = new Setting(contentEl)
+ .setName(this.translate("components.recurrenceContextMenu.customRecurrenceModal.interval"))
+ .setDesc(this.translate(getIntervalDescKey()))
.addText((text) => {
text.setValue(this.interval.toString()).onChange((value) => {
this.interval = parseInt(value) || 1;
});
});
- // Days of week (for weekly frequency)
+ // Days of week (for daily or weekly frequency)
const byDaySetting = new Setting(contentEl)
- .setName("Days of week")
- .setDesc("Select specific days (for daily or weekly recurrence)");
+ .setName(this.translate("components.recurrenceContextMenu.customRecurrenceModal.daysOfWeek"))
+ .setDesc(this.translate(getDaysOfWeekDescKey()));
+ byDaySetting.settingEl.addClass("tn-custom-recurrence-modal__days-setting");
- const daysContainer = byDaySetting.controlEl.createDiv("days-container");
+ const daysContainer = byDaySetting.controlEl.createDiv("tn-custom-recurrence-modal__days");
const days = orderedWeekdays.map((day) => ({
key: day.code,
label: this.translate(
@@ -811,20 +895,9 @@ class CustomRecurrenceModal extends Modal {
}));
days.forEach((day) => {
- const dayEl = daysContainer.createEl("label", { cls: "day-checkbox" });
- dayEl.classList.remove(
- "tn-static-display-block-2a1b75c9",
- "tn-static-display-flex-4d51fc62",
- "tn-static-display-flex-75816cae",
- "tn-static-display-flex-8bb39979",
- "tn-static-display-inline-cccfa456",
- "tn-static-display-inline-flex-f984c520",
- "tn-static-display-none-6b99de8b",
- "tn-static-min-height-800px-997b4c8c"
- );
- dayEl.classList.add("tn-static-display-inline-block-60e32dcb");
- dayEl.classList.remove("tn-static-margin-right-4px-c6b76b85");
- dayEl.classList.add("tn-static-margin-right-8px-539fa9a0");
+ const dayEl = daysContainer.createEl("label", {
+ cls: "tn-custom-recurrence-modal__day",
+ });
const checkbox = dayEl.createEl("input", { type: "checkbox" });
checkbox.checked = this.byDay.includes(day.key);
@@ -838,49 +911,38 @@ class CustomRecurrenceModal extends Modal {
}
});
- dayEl.createSpan({ text: ` ${day.label}` });
+ dayEl.createSpan({ text: day.label });
});
// Monthly options
const monthlyTypeSetting = new Setting(contentEl)
- .setName("Monthly recurrence")
- .setDesc("Choose how to repeat monthly");
-
- const monthlyTypeContainer = monthlyTypeSetting.controlEl.createDiv("monthly-options");
+ .setName(
+ this.translate("components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrence")
+ )
+ .setDesc(
+ this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.monthlyRecurrenceDesc"
+ )
+ );
- const monthlyByDateRadio = monthlyTypeContainer.createEl("label", { cls: "radio-option" });
- monthlyByDateRadio.classList.remove(
- "tn-static-display-flex-4d51fc62",
- "tn-static-display-flex-75816cae",
- "tn-static-display-flex-8bb39979",
- "tn-static-display-inline-block-60e32dcb",
- "tn-static-display-inline-cccfa456",
- "tn-static-display-inline-flex-f984c520",
- "tn-static-display-none-6b99de8b",
- "tn-static-min-height-800px-997b4c8c"
+ const monthlyTypeContainer = monthlyTypeSetting.controlEl.createDiv(
+ "tn-custom-recurrence-modal__options"
);
- monthlyByDateRadio.classList.add("tn-static-display-block-2a1b75c9");
- monthlyByDateRadio.classList.remove(
- "tn-static-font-size-12px-65574819",
- "tn-static-font-weight-bold-0fe8c30d",
- "tn-static-font-weight-bold-e0b452bd",
- "tn-static-margin-bottom-0-75rem-c05a3c6e",
- "tn-static-margin-bottom-20px-49f14f8f"
- );
- monthlyByDateRadio.classList.add("tn-static-margin-bottom-8px-fdf33f23");
- const monthlyByDateInput = monthlyByDateRadio.createEl("input", {
- type: "radio",
- value: "bydate",
+
+ const monthlyByDateRadio = monthlyTypeContainer.createEl("label", {
+ cls: "tn-custom-recurrence-modal__radio-option",
});
- monthlyByDateInput.name = "monthly-type";
- monthlyByDateInput.checked =
- this.byMonthDay.length > 0 || (this.byDay.length === 0 && this.bySetPos === undefined);
+ const monthlyByDateInput = createRadioInput(
+ monthlyByDateRadio,
+ "monthly-type",
+ "bydate",
+ this.byMonthDay.length > 0 || (this.byDay.length === 0 && this.bySetPos === undefined)
+ );
monthlyByDateRadio.createSpan({ text: " On " });
- const monthlyDateSelect = monthlyByDateRadio.createEl("select");
- monthlyDateSelect.classList.add("tn-static-margin-left-4px-46cec891");
- monthlyDateSelect.classList.remove("tn-static-margin-right-8px-539fa9a0");
- monthlyDateSelect.classList.add("tn-static-margin-right-4px-c6b76b85");
+ const monthlyDateSelect = monthlyByDateRadio.createEl("select", {
+ cls: "tn-custom-recurrence-modal__select",
+ });
for (const dayOption of getMonthDayOptions()) {
const option = monthlyDateSelect.createEl("option", {
value: dayOption.value,
@@ -895,44 +957,51 @@ class CustomRecurrenceModal extends Modal {
}
monthlyByDateRadio.createSpan({ text: " of each month" });
- const monthlyByDayRadio = monthlyTypeContainer.createEl("label", { cls: "radio-option" });
- monthlyByDayRadio.classList.remove(
- "tn-static-display-flex-4d51fc62",
- "tn-static-display-flex-75816cae",
- "tn-static-display-flex-8bb39979",
- "tn-static-display-inline-block-60e32dcb",
- "tn-static-display-inline-cccfa456",
- "tn-static-display-inline-flex-f984c520",
- "tn-static-display-none-6b99de8b",
- "tn-static-min-height-800px-997b4c8c"
- );
- monthlyByDayRadio.classList.add("tn-static-display-block-2a1b75c9");
- monthlyByDayRadio.classList.remove(
- "tn-static-font-size-12px-65574819",
- "tn-static-font-weight-bold-0fe8c30d",
- "tn-static-font-weight-bold-e0b452bd",
- "tn-static-margin-bottom-0-75rem-c05a3c6e",
- "tn-static-margin-bottom-20px-49f14f8f"
- );
- monthlyByDayRadio.classList.add("tn-static-margin-bottom-8px-fdf33f23");
- const monthlyByDayInput = monthlyByDayRadio.createEl("input", {
- type: "radio",
- value: "byday",
+ const monthlyByDayRadio = monthlyTypeContainer.createEl("label", {
+ cls: "tn-custom-recurrence-modal__radio-option",
});
- monthlyByDayInput.name = "monthly-type";
- monthlyByDayInput.checked = this.byDay.length > 0 && this.bySetPos !== undefined;
+ const monthlyByDayInput = createRadioInput(
+ monthlyByDayRadio,
+ "monthly-type",
+ "byday",
+ this.byDay.length > 0 && this.bySetPos !== undefined
+ );
monthlyByDayRadio.createSpan({ text: " On the " });
- const monthlyWeekSelect = monthlyByDayRadio.createEl("select");
- monthlyWeekSelect.classList.add("tn-static-margin-left-4px-46cec891");
- monthlyWeekSelect.classList.remove("tn-static-margin-right-8px-539fa9a0");
- monthlyWeekSelect.classList.add("tn-static-margin-right-4px-c6b76b85");
+ const monthlyWeekSelect = monthlyByDayRadio.createEl("select", {
+ cls: "tn-custom-recurrence-modal__select",
+ });
const weekOptions = [
- { value: "1", text: "first" },
- { value: "2", text: "second" },
- { value: "3", text: "third" },
- { value: "4", text: "fourth" },
- { value: "-1", text: "last" },
+ {
+ value: "1",
+ text: this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.weekPositions.first"
+ ),
+ },
+ {
+ value: "2",
+ text: this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.weekPositions.second"
+ ),
+ },
+ {
+ value: "3",
+ text: this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.weekPositions.third"
+ ),
+ },
+ {
+ value: "4",
+ text: this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.weekPositions.fourth"
+ ),
+ },
+ {
+ value: "-1",
+ text: this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.weekPositions.last"
+ ),
+ },
];
weekOptions.forEach((opt) => {
const option = monthlyWeekSelect.createEl("option", {
@@ -946,10 +1015,9 @@ class CustomRecurrenceModal extends Modal {
}
});
- const monthlyDaySelect = monthlyByDayRadio.createEl("select");
- monthlyDaySelect.classList.add("tn-static-margin-left-4px-46cec891");
- monthlyDaySelect.classList.remove("tn-static-margin-right-8px-539fa9a0");
- monthlyDaySelect.classList.add("tn-static-margin-right-4px-c6b76b85");
+ const monthlyDaySelect = monthlyByDayRadio.createEl("select", {
+ cls: "tn-custom-recurrence-modal__select",
+ });
const dayOptions = orderedWeekdays.map((day) => ({
value: day.code,
text: this.translate(
@@ -974,58 +1042,48 @@ class CustomRecurrenceModal extends Modal {
// Yearly options
const yearlyTypeSetting = new Setting(contentEl)
- .setName("Yearly recurrence")
- .setDesc("Choose how to repeat yearly");
-
- const yearlyTypeContainer = yearlyTypeSetting.controlEl.createDiv("yearly-options");
+ .setName(
+ this.translate("components.recurrenceContextMenu.customRecurrenceModal.yearlyRecurrence")
+ )
+ .setDesc(
+ this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.yearlyRecurrenceDesc"
+ )
+ );
- const yearlyByDateRadio = yearlyTypeContainer.createEl("label", { cls: "radio-option" });
- yearlyByDateRadio.classList.remove(
- "tn-static-display-flex-4d51fc62",
- "tn-static-display-flex-75816cae",
- "tn-static-display-flex-8bb39979",
- "tn-static-display-inline-block-60e32dcb",
- "tn-static-display-inline-cccfa456",
- "tn-static-display-inline-flex-f984c520",
- "tn-static-display-none-6b99de8b",
- "tn-static-min-height-800px-997b4c8c"
+ const yearlyTypeContainer = yearlyTypeSetting.controlEl.createDiv(
+ "tn-custom-recurrence-modal__options"
);
- yearlyByDateRadio.classList.add("tn-static-display-block-2a1b75c9");
- yearlyByDateRadio.classList.remove(
- "tn-static-font-size-12px-65574819",
- "tn-static-font-weight-bold-0fe8c30d",
- "tn-static-font-weight-bold-e0b452bd",
- "tn-static-margin-bottom-0-75rem-c05a3c6e",
- "tn-static-margin-bottom-20px-49f14f8f"
- );
- yearlyByDateRadio.classList.add("tn-static-margin-bottom-8px-fdf33f23");
- const yearlyByDateInput = yearlyByDateRadio.createEl("input", {
- type: "radio",
- value: "bydate",
+
+ const yearlyByDateRadio = yearlyTypeContainer.createEl("label", {
+ cls: "tn-custom-recurrence-modal__radio-option",
});
- yearlyByDateInput.name = "yearly-type";
- yearlyByDateInput.checked =
- this.byMonthDay.length > 0 || (this.byDay.length === 0 && this.bySetPos === undefined);
+ const yearlyByDateInput = createRadioInput(
+ yearlyByDateRadio,
+ "yearly-type",
+ "bydate",
+ this.byMonthDay.length > 0 || (this.byDay.length === 0 && this.bySetPos === undefined)
+ );
yearlyByDateRadio.createSpan({ text: " On " });
- const yearlyMonthSelect = yearlyByDateRadio.createEl("select");
- yearlyMonthSelect.classList.add("tn-static-margin-left-4px-46cec891");
- yearlyMonthSelect.classList.remove("tn-static-margin-right-8px-539fa9a0");
- yearlyMonthSelect.classList.add("tn-static-margin-right-4px-c6b76b85");
- const monthNames = [
- "January",
- "February",
- "March",
- "April",
- "May",
- "June",
- "July",
- "August",
- "September",
- "October",
- "November",
- "December",
- ];
+ const yearlyMonthSelect = yearlyByDateRadio.createEl("select", {
+ cls: "tn-custom-recurrence-modal__select",
+ });
+ const monthNameKeys = [
+ "january",
+ "february",
+ "march",
+ "april",
+ "may",
+ "june",
+ "july",
+ "august",
+ "september",
+ "october",
+ "november",
+ "december",
+ ] as const;
+ const monthNames = monthNameKeys.map((key) => this.translate(`common.months.${key}`));
monthNames.forEach((month, index) => {
const option = yearlyMonthSelect.createEl("option", {
value: (index + 1).toString(),
@@ -1041,10 +1099,9 @@ class CustomRecurrenceModal extends Modal {
}
});
- const yearlyDateSelect = yearlyByDateRadio.createEl("select");
- yearlyDateSelect.classList.add("tn-static-margin-left-4px-46cec891");
- yearlyDateSelect.classList.remove("tn-static-margin-right-8px-539fa9a0");
- yearlyDateSelect.classList.add("tn-static-margin-right-4px-c6b76b85");
+ const yearlyDateSelect = yearlyByDateRadio.createEl("select", {
+ cls: "tn-custom-recurrence-modal__select",
+ });
for (const dayOption of getMonthDayOptions()) {
const option = yearlyDateSelect.createEl("option", {
value: dayOption.value,
@@ -1059,38 +1116,20 @@ class CustomRecurrenceModal extends Modal {
}
yearlyByDateRadio.createSpan({ text: " each year" });
- const yearlyByDayRadio = yearlyTypeContainer.createEl("label", { cls: "radio-option" });
- yearlyByDayRadio.classList.remove(
- "tn-static-display-flex-4d51fc62",
- "tn-static-display-flex-75816cae",
- "tn-static-display-flex-8bb39979",
- "tn-static-display-inline-block-60e32dcb",
- "tn-static-display-inline-cccfa456",
- "tn-static-display-inline-flex-f984c520",
- "tn-static-display-none-6b99de8b",
- "tn-static-min-height-800px-997b4c8c"
- );
- yearlyByDayRadio.classList.add("tn-static-display-block-2a1b75c9");
- yearlyByDayRadio.classList.remove(
- "tn-static-font-size-12px-65574819",
- "tn-static-font-weight-bold-0fe8c30d",
- "tn-static-font-weight-bold-e0b452bd",
- "tn-static-margin-bottom-0-75rem-c05a3c6e",
- "tn-static-margin-bottom-20px-49f14f8f"
- );
- yearlyByDayRadio.classList.add("tn-static-margin-bottom-8px-fdf33f23");
- const yearlyByDayInput = yearlyByDayRadio.createEl("input", {
- type: "radio",
- value: "byday",
+ const yearlyByDayRadio = yearlyTypeContainer.createEl("label", {
+ cls: "tn-custom-recurrence-modal__radio-option",
});
- yearlyByDayInput.name = "yearly-type";
- yearlyByDayInput.checked = this.byDay.length > 0 && this.bySetPos !== undefined;
+ const yearlyByDayInput = createRadioInput(
+ yearlyByDayRadio,
+ "yearly-type",
+ "byday",
+ this.byDay.length > 0 && this.bySetPos !== undefined
+ );
yearlyByDayRadio.createSpan({ text: " On the " });
- const yearlyWeekSelect = yearlyByDayRadio.createEl("select");
- yearlyWeekSelect.classList.add("tn-static-margin-left-4px-46cec891");
- yearlyWeekSelect.classList.remove("tn-static-margin-right-8px-539fa9a0");
- yearlyWeekSelect.classList.add("tn-static-margin-right-4px-c6b76b85");
+ const yearlyWeekSelect = yearlyByDayRadio.createEl("select", {
+ cls: "tn-custom-recurrence-modal__select",
+ });
weekOptions.forEach((opt) => {
const option = yearlyWeekSelect.createEl("option", {
value: opt.value,
@@ -1103,10 +1142,9 @@ class CustomRecurrenceModal extends Modal {
}
});
- const yearlyDaySelect = yearlyByDayRadio.createEl("select");
- yearlyDaySelect.classList.add("tn-static-margin-left-4px-46cec891");
- yearlyDaySelect.classList.remove("tn-static-margin-right-8px-539fa9a0");
- yearlyDaySelect.classList.add("tn-static-margin-right-4px-c6b76b85");
+ const yearlyDaySelect = yearlyByDayRadio.createEl("select", {
+ cls: "tn-custom-recurrence-modal__select",
+ });
dayOptions.forEach((opt) => {
const option = yearlyDaySelect.createEl("option", { value: opt.value, text: opt.text });
if (this.byDay.length > 0 && this.byDay[0] === opt.value) {
@@ -1116,10 +1154,9 @@ class CustomRecurrenceModal extends Modal {
}
});
- const yearlyByDayMonthSelect = yearlyByDayRadio.createEl("select");
- yearlyByDayMonthSelect.classList.add("tn-static-margin-left-4px-46cec891");
- yearlyByDayMonthSelect.classList.remove("tn-static-margin-right-8px-539fa9a0");
- yearlyByDayMonthSelect.classList.add("tn-static-margin-right-4px-c6b76b85");
+ const yearlyByDayMonthSelect = yearlyByDayRadio.createEl("select", {
+ cls: "tn-custom-recurrence-modal__select",
+ });
monthNames.forEach((month, index) => {
const option = yearlyByDayMonthSelect.createEl("option", {
value: (index + 1).toString(),
@@ -1136,125 +1173,149 @@ class CustomRecurrenceModal extends Modal {
});
yearlyByDayRadio.createSpan({ text: " each year" });
+ // Keep Monthly radio selection in sync with which sub-controls are being edited,
+ // and grey out the inactive option's controls so it's clear which one applies.
+ const updateMonthlyControlsDisabled = () => {
+ const isByDate = monthlyByDateInput.checked;
+ monthlyDateSelect.disabled = !isByDate;
+ monthlyWeekSelect.disabled = isByDate;
+ monthlyDaySelect.disabled = isByDate;
+ };
+ monthlyByDateInput.addEventListener("change", updateMonthlyControlsDisabled);
+ monthlyByDayInput.addEventListener("change", updateMonthlyControlsDisabled);
+ monthlyDateSelect.addEventListener("change", () => {
+ monthlyByDateInput.checked = true;
+ updateMonthlyControlsDisabled();
+ });
+ [monthlyWeekSelect, monthlyDaySelect].forEach((select) => {
+ select.addEventListener("change", () => {
+ monthlyByDayInput.checked = true;
+ updateMonthlyControlsDisabled();
+ });
+ });
+ updateMonthlyControlsDisabled();
+
+ // Same treatment for Yearly's "on date" vs "on the Nth weekday" sub-controls.
+ const updateYearlyControlsDisabled = () => {
+ const isByDate = yearlyByDateInput.checked;
+ yearlyMonthSelect.disabled = !isByDate;
+ yearlyDateSelect.disabled = !isByDate;
+ yearlyWeekSelect.disabled = isByDate;
+ yearlyDaySelect.disabled = isByDate;
+ yearlyByDayMonthSelect.disabled = isByDate;
+ };
+ yearlyByDateInput.addEventListener("change", updateYearlyControlsDisabled);
+ yearlyByDayInput.addEventListener("change", updateYearlyControlsDisabled);
+ [yearlyMonthSelect, yearlyDateSelect].forEach((select) => {
+ select.addEventListener("change", () => {
+ yearlyByDateInput.checked = true;
+ updateYearlyControlsDisabled();
+ });
+ });
+ [yearlyWeekSelect, yearlyDaySelect, yearlyByDayMonthSelect].forEach((select) => {
+ select.addEventListener("change", () => {
+ yearlyByDayInput.checked = true;
+ updateYearlyControlsDisabled();
+ });
+ });
+ updateYearlyControlsDisabled();
+
// End condition
new Setting(contentEl)
- .setName("End condition")
- .setDesc("Choose when the recurrence should end");
+ .setName(
+ this.translate("components.recurrenceContextMenu.customRecurrenceModal.endCondition")
+ )
+ .setDesc(
+ this.translate("components.recurrenceContextMenu.customRecurrenceModal.endConditionDesc")
+ );
- const endConditionContainer = contentEl.createDiv("end-condition-container");
+ const endConditionContainer = contentEl.createDiv(
+ "tn-custom-recurrence-modal__end-condition"
+ );
// Never ends
- const neverRadio = endConditionContainer.createEl("label", { cls: "radio-option" });
- neverRadio.classList.remove(
- "tn-static-display-flex-4d51fc62",
- "tn-static-display-flex-75816cae",
- "tn-static-display-flex-8bb39979",
- "tn-static-display-inline-block-60e32dcb",
- "tn-static-display-inline-cccfa456",
- "tn-static-display-inline-flex-f984c520",
- "tn-static-display-none-6b99de8b",
- "tn-static-min-height-800px-997b4c8c"
- );
- neverRadio.classList.add("tn-static-display-block-2a1b75c9");
- neverRadio.classList.remove(
- "tn-static-font-size-12px-65574819",
- "tn-static-font-weight-bold-0fe8c30d",
- "tn-static-font-weight-bold-e0b452bd",
- "tn-static-margin-bottom-0-75rem-c05a3c6e",
- "tn-static-margin-bottom-20px-49f14f8f"
+ const neverRadio = endConditionContainer.createEl("label", {
+ cls: "tn-custom-recurrence-modal__radio-option",
+ });
+ const neverInput = createRadioInput(
+ neverRadio,
+ "end-type",
+ "never",
+ this.endType === "never"
);
- neverRadio.classList.add("tn-static-margin-bottom-8px-fdf33f23");
- const neverInput = neverRadio.createEl("input", { type: "radio", value: "never" });
- neverInput.name = "end-type";
- neverInput.checked = this.endType === "never";
- neverRadio.createSpan({ text: " Never ends" });
+ neverRadio.createSpan({
+ text: this.translate("components.recurrenceContextMenu.customRecurrenceModal.neverEnds"),
+ });
// End after X occurrences
- const countRadio = endConditionContainer.createEl("label", { cls: "radio-option" });
- countRadio.classList.remove(
- "tn-static-display-flex-4d51fc62",
- "tn-static-display-flex-75816cae",
- "tn-static-display-flex-8bb39979",
- "tn-static-display-inline-block-60e32dcb",
- "tn-static-display-inline-cccfa456",
- "tn-static-display-inline-flex-f984c520",
- "tn-static-display-none-6b99de8b",
- "tn-static-min-height-800px-997b4c8c"
- );
- countRadio.classList.add("tn-static-display-block-2a1b75c9");
- countRadio.classList.remove(
- "tn-static-font-size-12px-65574819",
- "tn-static-font-weight-bold-0fe8c30d",
- "tn-static-font-weight-bold-e0b452bd",
- "tn-static-margin-bottom-0-75rem-c05a3c6e",
- "tn-static-margin-bottom-20px-49f14f8f"
+ const countRadio = endConditionContainer.createEl("label", {
+ cls: "tn-custom-recurrence-modal__radio-option",
+ });
+ const countInput = createRadioInput(
+ countRadio,
+ "end-type",
+ "count",
+ this.endType === "count"
);
- countRadio.classList.add("tn-static-margin-bottom-8px-fdf33f23");
- const countInput = countRadio.createEl("input", { type: "radio", value: "count" });
- countInput.name = "end-type";
- countInput.checked = this.endType === "count";
- countRadio.createSpan({ text: " End after " });
- const countText = countRadio.createEl("input", { type: "number", placeholder: "10" });
- countText.classList.remove(
- "tn-static-width-100-0466783d",
- "tn-static-width-12px-fbf353fb",
- "tn-static-width-16px-7375d50b",
- "tn-static-width-1px-aa77e27e",
- "tn-static-width-200px-2acaf3b5",
- "tn-static-width-80px-8573bae3"
+ const endAfterTemplate = this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.endAfterOccurrences"
);
- countText.classList.add("tn-static-width-60px-bd09c419");
- countText.classList.add("tn-static-margin-left-4px-46cec891");
- countText.classList.remove("tn-static-margin-right-8px-539fa9a0");
- countText.classList.add("tn-static-margin-right-4px-c6b76b85");
+ const [endAfterPrefix, endAfterSuffix] = endAfterTemplate.split("{count}");
+ countRadio.createSpan({ text: endAfterPrefix });
+ const countText = countRadio.createEl("input", {
+ type: "number",
+ placeholder: "10",
+ cls: "tn-custom-recurrence-modal__count-input",
+ });
countText.value = this.count ? this.count.toString() : "";
- countRadio.createSpan({ text: " occurrences" });
+ countRadio.createSpan({ text: endAfterSuffix ? endAfterSuffix.trim() : "" });
// End on date
- const untilRadio = endConditionContainer.createEl("label", { cls: "radio-option" });
- untilRadio.classList.remove(
- "tn-static-display-flex-4d51fc62",
- "tn-static-display-flex-75816cae",
- "tn-static-display-flex-8bb39979",
- "tn-static-display-inline-block-60e32dcb",
- "tn-static-display-inline-cccfa456",
- "tn-static-display-inline-flex-f984c520",
- "tn-static-display-none-6b99de8b",
- "tn-static-min-height-800px-997b4c8c"
+ const untilRadio = endConditionContainer.createEl("label", {
+ cls: "tn-custom-recurrence-modal__radio-option",
+ });
+ const untilInput = createRadioInput(
+ untilRadio,
+ "end-type",
+ "until",
+ this.endType === "until"
);
- untilRadio.classList.add("tn-static-display-block-2a1b75c9");
- untilRadio.classList.remove(
- "tn-static-font-size-12px-65574819",
- "tn-static-font-weight-bold-0fe8c30d",
- "tn-static-font-weight-bold-e0b452bd",
- "tn-static-margin-bottom-0-75rem-c05a3c6e",
- "tn-static-margin-bottom-20px-49f14f8f"
+ const endOnTemplate = this.translate(
+ "components.recurrenceContextMenu.customRecurrenceModal.endOnDate"
);
- untilRadio.classList.add("tn-static-margin-bottom-8px-fdf33f23");
- const untilInput = untilRadio.createEl("input", { type: "radio", value: "until" });
- untilInput.name = "end-type";
- untilInput.checked = this.endType === "until";
- untilRadio.createSpan({ text: " End on " });
- const untilDate = untilRadio.createEl("input", { type: "date" });
- untilDate.classList.add("tn-static-margin-left-4px-46cec891");
+ const [endOnPrefix] = endOnTemplate.split("{date}");
+ untilRadio.createSpan({ text: endOnPrefix });
+ const untilDate = untilRadio.createEl("input", {
+ type: "date",
+ cls: "tn-custom-recurrence-modal__select tn-datetime-input",
+ });
untilDate.value = this.until ? this.until.replace(/(\d{4})(\d{2})(\d{2})/, "$1-$2-$3") : "";
+
+ const updateEndConditionDisabled = () => {
+ countText.disabled = !countInput.checked;
+ untilDate.disabled = !untilInput.checked;
+ };
+
attachDateInputBehavior(untilDate, {
onCommit: (value) => {
this.until = value.replace(/-/g, "");
untilInput.checked = true;
this.endType = "until";
+ updateEndConditionDisabled();
},
});
- // Event listeners for end condition
neverInput.addEventListener("change", () => {
if (neverInput.checked) this.endType = "never";
+ updateEndConditionDisabled();
});
countInput.addEventListener("change", () => {
if (countInput.checked) this.endType = "count";
+ updateEndConditionDisabled();
});
untilInput.addEventListener("change", () => {
if (untilInput.checked) this.endType = "until";
+ updateEndConditionDisabled();
});
countText.addEventListener("input", () => {
@@ -1262,6 +1323,7 @@ class CustomRecurrenceModal extends Modal {
if (countText.value) {
countInput.checked = true;
this.endType = "count";
+ updateEndConditionDisabled();
}
});
@@ -1270,11 +1332,16 @@ class CustomRecurrenceModal extends Modal {
if (untilDate.value) {
untilInput.checked = true;
this.endType = "until";
+ updateEndConditionDisabled();
}
});
+ updateEndConditionDisabled();
+
this.updateFrequencySpecificVisibility = () => {
const useFlexibleInterval = this.recurrenceAnchor === "completion";
+ intervalSetting.setDesc(this.translate(getIntervalDescKey()));
+ byDaySetting.setDesc(this.translate(getDaysOfWeekDescKey()));
byDaySetting.settingEl.style.display =
(this.frequency === "DAILY" || this.frequency === "WEEKLY") &&
!useFlexibleInterval
@@ -1327,12 +1394,17 @@ class CustomRecurrenceModal extends Modal {
);
buttonContainer.classList.add("tn-static-margin-top-16px-1b0f4999");
- const cancelButton = buttonContainer.createEl("button", { text: "Cancel" });
+ const cancelButton = buttonContainer.createEl("button", {
+ text: this.translate("components.recurrenceContextMenu.customRecurrenceModal.cancel"),
+ });
cancelButton.addEventListener("click", () => {
this.close();
});
- const saveButton = buttonContainer.createEl("button", { text: "Save", cls: "mod-cta" });
+ const saveButton = buttonContainer.createEl("button", {
+ text: this.translate("components.recurrenceContextMenu.customRecurrenceModal.save"),
+ cls: "mod-cta",
+ });
saveButton.addEventListener("click", () => {
// Get current radio button states and dropdown values
const monthlyType = monthlyByDateInput.checked ? "bydate" : "byday";
diff --git a/src/i18n/resources/de.ts b/src/i18n/resources/de.ts
index 7d6af1f6c..eed5b9d2d 100644
--- a/src/i18n/resources/de.ts
+++ b/src/i18n/resources/de.ts
@@ -3317,8 +3317,13 @@ export const de: TranslationTree = {
frequency: "Häufigkeit",
interval: "Intervall",
intervalDesc: "Alle X Tage/Wochen/Monate/Jahre",
+ intervalDescDaily: "Alle X Tage",
+ intervalDescWeekly: "Alle X Wochen",
+ intervalDescMonthly: "Alle X Monate",
+ intervalDescYearly: "Alle X Jahre",
daysOfWeek: "Wochentage",
daysOfWeekDesc: "Bestimmte Tage auswählen (für wöchentliche Wiederholung)",
+ daysOfWeekDescDaily: "Tägliche Vorkommen optional auf ausgewählte Wochentage beschränken",
monthlyRecurrence: "Monatliche Wiederholung",
monthlyRecurrenceDesc: "Wähle, wie monatlich wiederholt werden soll",
yearlyRecurrence: "Jährliche Wiederholung",
diff --git a/src/i18n/resources/en.ts b/src/i18n/resources/en.ts
index 4d592f521..76b671b9a 100644
--- a/src/i18n/resources/en.ts
+++ b/src/i18n/resources/en.ts
@@ -3493,8 +3493,13 @@ export const en: TranslationTree = {
frequency: "Frequency",
interval: "Interval",
intervalDesc: "Every x days/weeks/months/years",
+ intervalDescDaily: "Every x days",
+ intervalDescWeekly: "Every x weeks",
+ intervalDescMonthly: "Every x months",
+ intervalDescYearly: "Every x years",
daysOfWeek: "Days of week",
daysOfWeekDesc: "Select specific days (for weekly recurrence)",
+ daysOfWeekDescDaily: "Optionally limit daily occurrences to selected weekdays",
monthlyRecurrence: "Monthly recurrence",
monthlyRecurrenceDesc: "Choose how to repeat monthly",
yearlyRecurrence: "Yearly recurrence",
diff --git a/src/i18n/resources/es.ts b/src/i18n/resources/es.ts
index 50e2e053e..b334b30cf 100644
--- a/src/i18n/resources/es.ts
+++ b/src/i18n/resources/es.ts
@@ -3317,8 +3317,13 @@ export const es: TranslationTree = {
frequency: "Frecuencia",
interval: "Intervalo",
intervalDesc: "Cada X días/semanas/meses/años",
+ intervalDescDaily: "Cada X días",
+ intervalDescWeekly: "Cada X semanas",
+ intervalDescMonthly: "Cada X meses",
+ intervalDescYearly: "Cada X años",
daysOfWeek: "Días de la semana",
daysOfWeekDesc: "Seleccionar días específicos (para recurrencia semanal)",
+ daysOfWeekDescDaily: "Limitar opcionalmente las ocurrencias diarias a los días seleccionados",
monthlyRecurrence: "Recurrencia mensual",
monthlyRecurrenceDesc: "Elegir cómo repetir mensualmente",
yearlyRecurrence: "Recurrencia anual",
diff --git a/src/i18n/resources/fr.ts b/src/i18n/resources/fr.ts
index 976346135..a0174f397 100644
--- a/src/i18n/resources/fr.ts
+++ b/src/i18n/resources/fr.ts
@@ -3317,8 +3317,13 @@ export const fr: TranslationTree = {
frequency: "Fréquence",
interval: "Intervalle",
intervalDesc: "Tous les X jours/semaines/mois/années",
+ intervalDescDaily: "Tous les X jours",
+ intervalDescWeekly: "Toutes les X semaines",
+ intervalDescMonthly: "Tous les X mois",
+ intervalDescYearly: "Tous les X ans",
daysOfWeek: "Jours de la semaine",
daysOfWeekDesc: "Sélectionnez des jours spécifiques (pour la récurrence hebdomadaire)",
+ daysOfWeekDescDaily: "Limiter éventuellement les occurrences quotidiennes aux jours sélectionnés",
monthlyRecurrence: "Récurrence mensuelle",
monthlyRecurrenceDesc: "Choisissez comment répéter mensuellement",
yearlyRecurrence: "Récurrence annuelle",
diff --git a/src/i18n/resources/ja.ts b/src/i18n/resources/ja.ts
index 9eb2f74ec..20147732f 100644
--- a/src/i18n/resources/ja.ts
+++ b/src/i18n/resources/ja.ts
@@ -3317,8 +3317,13 @@ export const ja: TranslationTree = {
frequency: "頻度",
interval: "間隔",
intervalDesc: "X日/週/月/年ごと",
+ intervalDescDaily: "X日ごと",
+ intervalDescWeekly: "X週ごと",
+ intervalDescMonthly: "Xか月ごと",
+ intervalDescYearly: "X年ごと",
daysOfWeek: "曜日",
daysOfWeekDesc: "特定の曜日を選択(週次繰り返し用)",
+ daysOfWeekDescDaily: "毎日の繰り返しを選択した曜日に限定する(任意)",
monthlyRecurrence: "月次繰り返し",
monthlyRecurrenceDesc: "月次繰り返し方法を選択",
yearlyRecurrence: "年次繰り返し",
diff --git a/src/i18n/resources/ko.ts b/src/i18n/resources/ko.ts
index 6d51d313b..94a8cf2a9 100644
--- a/src/i18n/resources/ko.ts
+++ b/src/i18n/resources/ko.ts
@@ -3301,8 +3301,13 @@ export const ko: TranslationTree = {
frequency: "빈도",
interval: "간격",
intervalDesc: "X일/주/월/년마다",
+ intervalDescDaily: "X일마다",
+ intervalDescWeekly: "X주마다",
+ intervalDescMonthly: "X개월마다",
+ intervalDescYearly: "X년마다",
daysOfWeek: "요일",
daysOfWeekDesc: "특정 요일 선택 (주간 반복용)",
+ daysOfWeekDescDaily: "일일 반복을 선택한 요일로 선택적으로 제한",
monthlyRecurrence: "월간 반복",
monthlyRecurrenceDesc: "매월 반복 방법 선택",
yearlyRecurrence: "연간 반복",
diff --git a/src/i18n/resources/pt.ts b/src/i18n/resources/pt.ts
index 212771a33..9957883b4 100644
--- a/src/i18n/resources/pt.ts
+++ b/src/i18n/resources/pt.ts
@@ -3322,8 +3322,13 @@ export const pt: TranslationTree = {
frequency: "Frequência",
interval: "Intervalo",
intervalDesc: "A cada X dias/semanas/meses/anos",
+ intervalDescDaily: "A cada X dias",
+ intervalDescWeekly: "A cada X semanas",
+ intervalDescMonthly: "A cada X meses",
+ intervalDescYearly: "A cada X anos",
daysOfWeek: "Dias da semana",
daysOfWeekDesc: "Selecione dias específicos (para recorrência semanal)",
+ daysOfWeekDescDaily: "Opcionalmente limitar ocorrências diárias aos dias selecionados",
monthlyRecurrence: "Recorrência mensal",
monthlyRecurrenceDesc: "Escolha como repetir mensalmente",
yearlyRecurrence: "Recorrência anual",
diff --git a/src/i18n/resources/ru.ts b/src/i18n/resources/ru.ts
index eff034d4e..0b18a376f 100644
--- a/src/i18n/resources/ru.ts
+++ b/src/i18n/resources/ru.ts
@@ -3317,8 +3317,13 @@ export const ru: TranslationTree = {
frequency: "Частота",
interval: "Интервал",
intervalDesc: "Каждые X дней/недель/месяцев/лет",
+ intervalDescDaily: "Каждые X дней",
+ intervalDescWeekly: "Каждые X недель",
+ intervalDescMonthly: "Каждые X месяцев",
+ intervalDescYearly: "Каждые X лет",
daysOfWeek: "Дни недели",
daysOfWeekDesc: "Выберите конкретные дни (для еженедельного повторения)",
+ daysOfWeekDescDaily: "При необходимости ограничить ежедневные повторения выбранными днями недели",
monthlyRecurrence: "Ежемесячное повторение",
monthlyRecurrenceDesc: "Выберите, как повторять ежемесячно",
yearlyRecurrence: "Ежегодное повторение",
diff --git a/src/i18n/resources/zh.ts b/src/i18n/resources/zh.ts
index d7d1f72f3..2abf6bf47 100644
--- a/src/i18n/resources/zh.ts
+++ b/src/i18n/resources/zh.ts
@@ -3316,8 +3316,13 @@ export const zh: TranslationTree = {
frequency: "频率",
interval: "间隔",
intervalDesc: "每X天/周/月/年",
+ intervalDescDaily: "每X天",
+ intervalDescWeekly: "每X周",
+ intervalDescMonthly: "每X个月",
+ intervalDescYearly: "每X年",
daysOfWeek: "一周中的天",
daysOfWeekDesc: "选择特定天(用于每周重复)",
+ daysOfWeekDescDaily: "可选:将每日重复限制为所选工作日",
monthlyRecurrence: "每月重复",
monthlyRecurrenceDesc: "选择如何每月重复",
yearlyRecurrence: "每年重复",
diff --git a/src/modals/DateTimePickerModal.ts b/src/modals/DateTimePickerModal.ts
index a14f90a55..e1c4b653a 100644
--- a/src/modals/DateTimePickerModal.ts
+++ b/src/modals/DateTimePickerModal.ts
@@ -202,7 +202,7 @@ export class DateTimePickerModal extends Modal {
const control = field.createDiv({ cls: "date-time-picker-modal__native-date-control" });
this.dateInput = control.createEl("input", {
- cls: "date-time-picker-modal__date-input",
+ cls: "date-time-picker-modal__date-input tn-datetime-input",
attr: {
id: "tasknotes-date-time-picker-date",
type: "date",
@@ -250,7 +250,7 @@ export class DateTimePickerModal extends Modal {
});
this.timeInput = field.createEl("input", {
- cls: "date-time-picker-modal__time-input",
+ cls: "date-time-picker-modal__time-input tn-datetime-input",
attr: {
id: "tasknotes-date-time-picker-time",
type: "time",
diff --git a/src/modals/ReminderModal.ts b/src/modals/ReminderModal.ts
index e3e8bbbfa..d31df3705 100644
--- a/src/modals/ReminderModal.ts
+++ b/src/modals/ReminderModal.ts
@@ -452,6 +452,7 @@ export class ReminderModal extends Modal {
this.absoluteDate = value;
});
text.inputEl.type = "date";
+ text.inputEl.addClass("tn-datetime-input");
attachDateInputBehavior(text.inputEl, {
onCommit: (value) => {
this.absoluteDate = value;
@@ -466,6 +467,7 @@ export class ReminderModal extends Modal {
this.absoluteTime = value;
});
text.inputEl.type = "time";
+ text.inputEl.addClass("tn-datetime-input");
});
// Description field (common)
diff --git a/src/modals/TimeblockCreationModal.ts b/src/modals/TimeblockCreationModal.ts
index 5eaafb374..fab130dfb 100644
--- a/src/modals/TimeblockCreationModal.ts
+++ b/src/modals/TimeblockCreationModal.ts
@@ -162,6 +162,7 @@ export class TimeblockCreationModal extends Modal {
.setValue(this.options.startTime || "")
.onChange(() => this.validateForm());
this.startTimeInput.type = "time";
+ this.startTimeInput.addClass("tn-datetime-input");
});
new Setting(contentEl)
@@ -175,6 +176,7 @@ export class TimeblockCreationModal extends Modal {
this.validateForm();
});
this.endTimeInput.type = "time";
+ this.endTimeInput.addClass("tn-datetime-input");
});
// Description (optional)
diff --git a/styles/modal-bem.css b/styles/modal-bem.css
index be1068781..da24b220b 100644
--- a/styles/modal-bem.css
+++ b/styles/modal-bem.css
@@ -305,30 +305,35 @@
/* User-field date input: full width textbox; icon overlayed on the left */
.tasknotes-plugin .tn-date-control {
- position: relative;
- padding-left: 35px; /* reserve space for the icon to the left of the textbox */
+ position: relative;
+ padding-left: 35px;
+ /* reserve space for the icon to the left of the textbox */
}
+
.tasknotes-plugin .tn-date-control input[type="text"] {
- padding-left: 0; /* the padding-left is applied on the container */
+ padding-left: 0;
+ /* the padding-left is applied on the container */
}
+
.tasknotes-plugin .tn-date-control .user-field-date-picker-btn {
- position: absolute;
- left: 10px;
- top: 50%;
- transform: translateY(-50%);
- width: 20px;
- height: 20px;
- display: inline-flex;
- align-items: center;
- justify-content: center;
- border: 0;
- background: transparent;
- padding: 0;
- color: var(--tn-text-muted);
- z-index: 1;
+ position: absolute;
+ left: 10px;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 20px;
+ height: 20px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border: 0;
+ background: transparent;
+ padding: 0;
+ color: var(--tn-text-muted);
+ z-index: 1;
}
+
.tasknotes-plugin .tn-date-control .user-field-date-picker-btn:hover {
- color: var(--text-normal);
+ color: var(--text-normal);
}
@@ -762,6 +767,7 @@
===================================================================== */
@media (max-width: 768px) {
+
.tasknotes-plugin .due-date-modal,
.tasknotes-plugin .scheduled-date-modal {
padding: var(--tn-spacing-lg);
@@ -833,7 +839,7 @@
color: var(--tn-interactive-accent);
}
-.tasknotes-plugin .event-details > div {
+.tasknotes-plugin .event-details>div {
margin-bottom: var(--size-4-1);
font-size: var(--tn-font-size-md);
line-height: 1.4;
@@ -841,12 +847,12 @@
/* Align all modal setting controls to the right edge of the column */
.tasknotes-plugin .modal .setting-item .setting-item-control {
- flex: none;
- text-align: end;
- display: flex;
- justify-content: flex-end;
- align-items: center;
- gap: var(--size-4-2);
+ flex: none;
+ text-align: end;
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ gap: var(--size-4-2);
}
@@ -888,7 +894,7 @@
color: var(--tn-interactive-accent);
}
-.tasknotes-plugin .preview-details > div {
+.tasknotes-plugin .preview-details>div {
margin-bottom: var(--size-4-1);
font-size: var(--tn-font-size-md);
}
@@ -1133,3 +1139,152 @@
color: var(--tn-text-muted);
font-style: italic;
}
+
+/* =====================================================================
+ NATIVE DATE/TIME INPUTS (shared across modals)
+ ===================================================================== */
+
+.tasknotes-plugin .tn-datetime-input {
+ padding: var(--size-4-1) var(--size-4-2);
+ border: 1px solid color-mix(in srgb, var(--background-modifier-border) 65%, transparent);
+ border-radius: var(--radius-s);
+}
+
+/* =====================================================================
+ CUSTOM RECURRENCE MODAL
+ ===================================================================== */
+
+.modal.tn-custom-recurrence-modal-host {
+ width: min(560px, 92vw);
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal {
+ max-width: 100%;
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__days-setting {
+ flex-direction: column;
+ align-items: stretch;
+ gap: var(--size-4-3);
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__days-setting .setting-item-info {
+ margin-right: 0;
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__days-setting .setting-item-control {
+ justify-content: flex-start;
+ width: 100%;
+ margin-top: var(--size-4-2);
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__days {
+ display: flex;
+ flex-wrap: nowrap;
+ align-items: center;
+ gap: var(--tn-spacing-md);
+ width: 100%;
+ overflow-x: auto;
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__day {
+ display: inline-flex;
+ align-items: center;
+ gap: var(--tn-spacing-xs);
+ margin: 0;
+ white-space: nowrap;
+ flex-shrink: 0;
+ cursor: var(--cursor-link, pointer);
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__day input[type="checkbox"] {
+ margin: 0;
+ flex-shrink: 0;
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__options,
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__end-condition {
+ display: flex;
+ flex-direction: column;
+ gap: var(--tn-spacing-sm);
+ width: 100%;
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__radio-option {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: var(--tn-spacing-sm);
+ margin: 0;
+ line-height: 1.2;
+ cursor: var(--cursor-link, pointer);
+}
+
+/* Chromium does not render ::before/::after generated content on
+ elements, so the "selected" dot is a real sibling span layered on top of
+ the radio input inside a small positioning wrapper, instead of a
+ pseudo-element on the input itself. */
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__radio-visual {
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 1rem;
+ height: 1rem;
+ flex-shrink: 0;
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__radio-visual input[type="radio"] {
+ appearance: none;
+ -webkit-appearance: none;
+ box-sizing: border-box;
+ width: 1rem;
+ height: 1rem;
+ margin: 0;
+ padding: 0;
+ border: 2px solid var(--text-muted);
+ border-radius: 50%;
+ background-color: transparent;
+ background-image: none;
+ box-shadow: none;
+ outline: none;
+ vertical-align: middle;
+ cursor: inherit;
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__radio-visual input[type="radio"]:checked {
+ border-color: var(--interactive-accent);
+ background-color: transparent;
+ background-image: none;
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__radio-dot {
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ width: 0.5rem;
+ height: 0.5rem;
+ border-radius: 50%;
+ background-color: var(--interactive-accent);
+ transform: translate(-50%, -50%) scale(0);
+ opacity: 0;
+ pointer-events: none;
+ transition: transform 80ms ease, opacity 80ms ease;
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__radio-visual input[type="radio"]:checked~.tn-custom-recurrence-modal__radio-dot {
+ transform: translate(-50%, -50%) scale(1);
+ opacity: 1;
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__select {
+ margin: 0;
+ width: auto;
+ min-width: 0;
+}
+
+.tasknotes-plugin.tn-custom-recurrence-modal .tn-custom-recurrence-modal__count-input {
+ width: 60px;
+ margin: 0;
+ text-align: center;
+}
\ No newline at end of file