From 765f90bf7a1c0ba4fca4182fa4ab6baa0d133d42 Mon Sep 17 00:00:00 2001 From: Isaac Cambron Date: Mon, 23 Mar 2026 15:52:00 -0400 Subject: [PATCH 1/9] Add `wasHole` property to DateTime (#1753) --------- Co-authored-by: Take Weiland --- src/datetime.js | 61 ++++++++++++++++++++++++++------------- test/datetime/dst.test.js | 57 ++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 20 deletions(-) diff --git a/src/datetime.js b/src/datetime.js index 3ac0d5f8c..c18c8518e 100644 --- a/src/datetime.js +++ b/src/datetime.js @@ -93,6 +93,7 @@ function clone(inst, alts) { o: inst.o, loc: inst.loc, invalid: inst.invalid, + wasHole: inst.wasHole, }; return new DateTime({ ...current, ...alts, old: current }); } @@ -108,7 +109,7 @@ function fixOffset(localTS, o, tz) { // If so, offset didn't change and we're done if (o === o2) { - return [utcGuess, o]; + return [utcGuess, o, false]; } // If not, change the ts by the difference in the offset @@ -117,11 +118,11 @@ function fixOffset(localTS, o, tz) { // If that gives us the local time we want, we're done const o3 = tz.offset(utcGuess); if (o2 === o3) { - return [utcGuess, o2]; + return [utcGuess, o2, false]; } // If it's different, we're in a hole time. The offset has changed, but the we don't adjust the time - return [localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3)]; + return [localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3), true]; } // convert an epoch timestamp into a calendar object with the given offset @@ -173,7 +174,7 @@ function adjustTime(inst, dur) { }).as("milliseconds"), localTS = objToLocalTS(c); - let [ts, o] = fixOffset(localTS, oPre, inst.zone); + let [ts, o, wasHole] = fixOffset(localTS, oPre, inst.zone); if (millisToAdd !== 0) { ts += millisToAdd; @@ -181,7 +182,7 @@ function adjustTime(inst, dur) { o = inst.zone.offset(ts); } - return { ts, o }; + return { ts, o, wasHole }; } // helper useful in turning the results of parsing into real dates @@ -441,7 +442,7 @@ function quickDT(obj, opts) { const loc = Locale.fromObject(opts); - let ts, o; + let ts, o, wasHole; // assume we have the higher-order units if (!isUndefined(obj.year)) { @@ -457,12 +458,12 @@ function quickDT(obj, opts) { } const offsetProvis = guessOffsetForZone(zone); - [ts, o] = objToTS(obj, offsetProvis, zone); + [ts, o, wasHole] = objToTS(obj, offsetProvis, zone); } else { ts = Settings.now(); } - return new DateTime({ ts, zone, loc, o }); + return new DateTime({ ts, zone, loc, o, wasHole }); } function diffRelative(start, end, opts) { @@ -556,13 +557,14 @@ export default class DateTime { */ this.ts = isUndefined(config.ts) ? Settings.now() : config.ts; - let c = null, - o = null; + let c = null; + let o = null; if (!invalid) { const unchanged = config.old && config.old.ts === this.ts && config.old.zone.equals(zone); if (unchanged) { - [c, o] = [config.old.c, config.old.o]; + c = config.old.c; + o = config.old.o; } else { // If an offset has been passed and we have not been called from // clone(), we can trust it and avoid the offset calculation. @@ -598,9 +600,12 @@ export default class DateTime { * @access private */ this.c = c; + /** * @access private */ + this._wasHole = config.wasHole || false; + this.o = o; /** * @access private @@ -873,16 +878,18 @@ export default class DateTime { // compute the actual time const gregorian = useWeekData - ? weekToGregorian(normalized, minDaysInFirstWeek, startOfWeek) - : containsOrdinal - ? ordinalToGregorian(normalized) - : normalized, - [tsFinal, offsetFinal] = objToTS(gregorian, offsetProvis, zoneToUse), + ? weekToGregorian(normalized, minDaysInFirstWeek, startOfWeek) + : containsOrdinal + ? ordinalToGregorian(normalized) + : normalized; + + const [tsFinal, offsetFinal, wasHole] = objToTS(gregorian, offsetProvis, zoneToUse), inst = new DateTime({ ts: tsFinal, zone: zoneToUse, o: offsetFinal, loc, + wasHole, }); // gregorian data + weekday serves only to validate @@ -1168,6 +1175,19 @@ export default class DateTime { return this.isValid ? this.zone.name : null; } + /** + * Whether this DateTime was created from a "hole time" that can exist during DST due to the + * clocks moving forward. + * + * @example DateTime.local(2017, 3, 12, 2).wasHole; //=> true + * @example DateTime.local(2017, 3, 12, 4).wasHole; //=> false + * + * @return {boolean} + */ + get wasHole() { + return this._wasHole; + } + /** * Get the year * @example DateTime.local(2017, 5, 25).year //=> 2017 @@ -1571,12 +1591,13 @@ export default class DateTime { return DateTime.invalid(unsupportedZone(zone)); } else { let newTS = this.ts; + let wasHole = false; if (keepLocalTime || keepCalendarTime) { const offsetGuess = zone.offset(this.ts); const asObj = this.toObject(); - [newTS] = objToTS(asObj, offsetGuess, zone); + [newTS, , wasHole] = objToTS(asObj, offsetGuess, zone); } - return clone(this, { ts: newTS, zone }); + return clone(this, { ts: newTS, zone, wasHole }); } } @@ -1659,8 +1680,8 @@ export default class DateTime { } } - const [ts, o] = objToTS(mixed, this.o, this.zone); - return clone(this, { ts, o }); + const [ts, o, wasHole] = objToTS(mixed, this.o, this.zone); + return clone(this, { ts, o, wasHole }); } /** diff --git a/test/datetime/dst.test.js b/test/datetime/dst.test.js index 8ab5d77ab..16d5a7867 100644 --- a/test/datetime/dst.test.js +++ b/test/datetime/dst.test.js @@ -15,6 +15,7 @@ for (const [name, local] of Object.entries(dateTimeConstructors)) { const d = local(2017, 3, 12, 2); expect(d.hour).toBe(3); expect(d.offset).toBe(-4 * 60); + expect(d.wasHole).toBe(true); }); if (name == "fromObject") { @@ -190,3 +191,59 @@ describe("DateTime.local() with offset caching", () => { } } }); + +describe("DateTime maintains the wasHole setting properly", () => { + test("is false by default", () => { + expect(DateTime.fromObject({ year: 2017, month: 3, day: 12, hour: 4 }).wasHole).toBe(false); + }); + + test("is set on hole times", () => { + expect(DateTime.fromObject({ year: 2017, month: 3, day: 12, hour: 2 }).wasHole).toBe(true); + }); + + test("is set on hole times with DateTime.local", () => { + expect(DateTime.local(2017, 3, 12, 2).wasHole).toBe(true); + }); + + test("is set on hole times with DateTime.fromISO", () => { + expect(DateTime.fromISO("2017-03-12T02:00:00").wasHole).toBe(true); + }); + + test("is false when setting to non-hole", () => { + const fromHole = DateTime.fromObject({ year: 2017, month: 3, day: 12, hour: 2 }); + expect(fromHole.set({ hour: 4 }).wasHole).toBe(false); + }); + + test("is true when setting hole-time on time from hole", () => { + const dt = DateTime.fromObject({ year: 2017, month: 3, day: 12, hour: 2 }); + expect(dt.wasHole).toBe(true); + expect(dt.set({ hour: 2 }).wasHole).toBe(true); + }); + + test("is true when setting hole-time on time from non-hole", () => { + const dt = DateTime.fromObject({ year: 2017, month: 3, day: 12, hour: 4 }); + expect(dt.wasHole).toBe(false); + expect(dt.set({ hour: 2 }).wasHole).toBe(true); + }); + + test("is dropped on math", () => { + expect( + DateTime.fromObject({ year: 2017, month: 3, day: 12, hour: 2 }).plus({ hours: 2 }).wasHole + ).toBe(false); + }); + + test("is kept on reconfigure", () => { + expect( + DateTime.fromObject({ year: 2017, month: 3, day: 12, hour: 2 }).reconfigure({ + locale: "es-ES", + }).wasHole + ).toBe(true); + }); + + test("is dropped on rezoning", () => { + expect( + DateTime.fromObject({ year: 2017, month: 3, day: 12, hour: 2 }).setZone("Europe/London") + .wasHole + ).toBe(false); + }); +}); From 9d4f750e45fd1d25a1b60336d06665e16b861d58 Mon Sep 17 00:00:00 2001 From: Seokrin Taron Sung Date: Tue, 24 Mar 2026 04:54:50 +0900 Subject: [PATCH 2/9] feat: add weekSettings support to DateTime.reconfigure() (#1756) Allows passing weekSettings to DateTime.reconfigure() to change week settings on an existing DateTime instance. This was previously not supported even though the underlying Locale.clone() already handled it. Fixes #1746 --- src/datetime.js | 14 +++++++++++--- test/datetime/reconfigure.test.js | 18 ++++++++++++++++++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/datetime.js b/src/datetime.js index c18c8518e..e642bc1c8 100644 --- a/src/datetime.js +++ b/src/datetime.js @@ -1602,13 +1602,21 @@ export default class DateTime { } /** - * "Set" the locale, numberingSystem, or outputCalendar. Returns a newly-constructed DateTime. + * "Set" the locale, numberingSystem, outputCalendar, or weekSettings. Returns a newly-constructed DateTime. * @param {Object} properties - the properties to set + * @param {string} [properties.locale] - the locale to set + * @param {string} [properties.numberingSystem] - the numbering system to set + * @param {string} [properties.outputCalendar] - the output calendar to set + * @param {Object} [properties.weekSettings] - the week settings to set + * @param {number} [properties.weekSettings.firstDay] - the first day of the week (1-7, Monday-Sunday) + * @param {number} [properties.weekSettings.minimalDays] - the minimum number of days in the first week + * @param {number[]} [properties.weekSettings.weekend] - the weekend days * @example DateTime.local(2017, 5, 25).reconfigure({ locale: 'en-GB' }) + * @example DateTime.local(2017, 5, 25).reconfigure({ weekSettings: { firstDay: 1 } }) * @return {DateTime} */ - reconfigure({ locale, numberingSystem, outputCalendar } = {}) { - const loc = this.loc.clone({ locale, numberingSystem, outputCalendar }); + reconfigure({ locale, numberingSystem, outputCalendar, weekSettings } = {}) { + const loc = this.loc.clone({ locale, numberingSystem, outputCalendar, weekSettings }); return clone(this, { loc }); } diff --git a/test/datetime/reconfigure.test.js b/test/datetime/reconfigure.test.js index 3801419c7..50fa77bf7 100644 --- a/test/datetime/reconfigure.test.js +++ b/test/datetime/reconfigure.test.js @@ -41,3 +41,21 @@ test("DateTime#reconfigure() with no arguments no opts", () => { expect(recon.numberingSystem).toBe("beng"); expect(recon.outputCalendar).toBe("coptic"); }); + +test("DateTime#reconfigure() sets the weekSettings", () => { + const original = DateTime.local(2022, 1, 4, { locale: "en-US" }); + const recon = original.reconfigure({ + weekSettings: { firstDay: 6, minimalDays: 1, weekend: [1, 2] }, + }); + expect(recon.startOf("week", { useLocaleWeeks: true }).weekday).toBe(6); +}); + +test("DateTime#reconfigure() preserves weekSettings when setting other options", () => { + const original = DateTime.local(2022, 1, 4, { + locale: "en-US", + weekSettings: { firstDay: 3, minimalDays: 1, weekend: [] }, + }); + const recon = original.reconfigure({ locale: "de-DE" }); + expect(recon.locale).toBe("de-DE"); + expect(recon.startOf("week", { useLocaleWeeks: true }).weekday).toBe(3); +}); From afee531a131b6b6a284820e25f2c5e678160fafa Mon Sep 17 00:00:00 2001 From: Per Eriksson Date: Mon, 23 Mar 2026 21:06:07 +0100 Subject: [PATCH 3/9] datetime plus docs typo (#1767) --- src/datetime.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/datetime.js b/src/datetime.js index e642bc1c8..cb6230158 100644 --- a/src/datetime.js +++ b/src/datetime.js @@ -536,7 +536,7 @@ const zoneOffsetGuessCache = new Map(); * {@link DateTime#day}, {@link DateTime#hour}, {@link DateTime#minute}, {@link DateTime#second}, {@link DateTime#millisecond} accessors. * * **Week calendar**: For ISO week calendar attributes, see the {@link DateTime#weekYear}, {@link DateTime#weekNumber}, and {@link DateTime#weekday} accessors. * * **Configuration** See the {@link DateTime#locale} and {@link DateTime#numberingSystem} accessors. - * * **Transformation**: To transform the DateTime into other DateTimes, use {@link DateTime#set}, {@link DateTime#reconfigure}, {@link DateTime#setZone}, {@link DateTime#setLocale}, {@link DateTime.plus}, {@link DateTime#minus}, {@link DateTime#endOf}, {@link DateTime#startOf}, {@link DateTime#toUTC}, and {@link DateTime#toLocal}. + * * **Transformation**: To transform the DateTime into other DateTimes, use {@link DateTime#set}, {@link DateTime#reconfigure}, {@link DateTime#setZone}, {@link DateTime#setLocale}, {@link DateTime#plus}, {@link DateTime#minus}, {@link DateTime#endOf}, {@link DateTime#startOf}, {@link DateTime#toUTC}, and {@link DateTime#toLocal}. * * **Output**: To convert the DateTime to other representations, use the {@link DateTime#toRelative}, {@link DateTime#toRelativeCalendar}, {@link DateTime#toJSON}, {@link DateTime#toISO}, {@link DateTime#toHTTP}, {@link DateTime#toObject}, {@link DateTime#toRFC2822}, {@link DateTime#toString}, {@link DateTime#toLocaleString}, {@link DateTime#toFormat}, {@link DateTime#toMillis} and {@link DateTime#toJSDate}. * * There's plenty others documented below. In addition, for more information on subtler topics like internationalization, time zones, alternative calendars, validity, and so on, see the external documentation. From 2ed382ab0a15b0f695c5e8641161f88da68412e0 Mon Sep 17 00:00:00 2001 From: Take Weiland Date: Mon, 23 Mar 2026 21:13:51 +0100 Subject: [PATCH 4/9] Hide internal members from generated documentation --- src/datetime.js | 6 ++++++ src/impl/conversions.js | 1 + src/impl/tokenParser.js | 1 + src/impl/util.js | 1 + 4 files changed, 9 insertions(+) diff --git a/src/datetime.js b/src/datetime.js index cb6230158..a528c76e7 100644 --- a/src/datetime.js +++ b/src/datetime.js @@ -60,6 +60,7 @@ function unsupportedZone(zone) { // we cache week data on the DT object and this intermediates the cache /** + * @ignore * @param {DateTime} dt */ function possiblyCachedWeekData(dt) { @@ -70,6 +71,7 @@ function possiblyCachedWeekData(dt) { } /** + * @ignore * @param {DateTime} dt */ function possiblyCachedLocalWeekData(dt) { @@ -411,6 +413,7 @@ function normalizeUnitWithLocalWeeks(unit) { /** * @param {Zone} zone * @return {number} + * @ignore */ function guessOffsetForZone(zone) { if (zoneOffsetTs === undefined) { @@ -511,6 +514,7 @@ function lastOpts(argList) { /** * Timestamp to use for cached zone offset guesses (exposed for test) + * @ignore */ let zoneOffsetTs; /** @@ -518,6 +522,8 @@ let zoneOffsetTs; * * This optimizes quickDT via guessOffsetForZone to avoid repeated calls of * zone.offset(). + * + * @ignore */ const zoneOffsetGuessCache = new Map(); diff --git a/src/impl/conversions.js b/src/impl/conversions.js index 4c7d1170e..417611b9a 100644 --- a/src/impl/conversions.js +++ b/src/impl/conversions.js @@ -112,6 +112,7 @@ export function ordinalToGregorian(ordinalData) { * If so, validates that they are not mixed with ISO week units and then copies them to the normal week unit properties. * Modifies obj in-place! * @param obj the object values + * @ignore */ export function usesLocalWeekValues(obj, loc) { const hasLocaleWeekData = diff --git a/src/impl/tokenParser.js b/src/impl/tokenParser.js index 0190efc5f..7a2196c7e 100644 --- a/src/impl/tokenParser.js +++ b/src/impl/tokenParser.js @@ -52,6 +52,7 @@ function escapeToken(value) { /** * @param token * @param {Locale} loc + * @ignore */ function unitForToken(token, loc) { const one = digitRegex(loc), diff --git a/src/impl/util.js b/src/impl/util.js index 916425020..32a5d9d72 100644 --- a/src/impl/util.js +++ b/src/impl/util.js @@ -307,6 +307,7 @@ export function normalizeObject(obj, normalizer) { * @param {string} format - What style of offset to return. * Accepts 'narrow', 'short', or 'techie'. Returning '+6', '+06:00', or '+0600' respectively * @return {string} + * @ignore */ export function formatOffset(offset, format) { const hours = Math.trunc(Math.abs(offset / 60)), From 5e35bf65ddce162e5679d3b7c5d6ae6b1ddda426 Mon Sep 17 00:00:00 2001 From: Per Eriksson Date: Mon, 23 Mar 2026 21:22:01 +0100 Subject: [PATCH 5/9] added support info for Intl.DateTimeFormat.prototype.formatRange() (#1766) --- src/interval.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/interval.js b/src/interval.js index 1cdb6b118..83ab504ff 100644 --- a/src/interval.js +++ b/src/interval.js @@ -589,6 +589,9 @@ export default class Interval { * is browser-specific, but in general it will return an appropriate representation of the * Interval in the assigned locale. Defaults to the system's locale if no locale has been * specified. + * + * Requires support for Intl.DateTimeFormat.prototype.formatRange(). + * * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/DateTimeFormat * @param {Object} [formatOpts=DateTime.DATE_SHORT] - Either a DateTime preset or * Intl.DateTimeFormat constructor options. From 4badf84ab661b4203a03393f1ce2834a7da7b299 Mon Sep 17 00:00:00 2001 From: Sherif <63353826+sheromero@users.noreply.github.com> Date: Tue, 24 Mar 2026 04:23:57 +0800 Subject: [PATCH 6/9] Fix weekday naming inconsistency in regexParser (#1743) Closes #1726 Renamed instances of weekDay to weekday in regexParse.js for consistency. --- src/impl/regexParser.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/impl/regexParser.js b/src/impl/regexParser.js index c39dd2082..807a42ea2 100644 --- a/src/impl/regexParser.js +++ b/src/impl/regexParser.js @@ -75,7 +75,7 @@ const isoTimeExtensionRegex = RegExp(`(?:[Tt]${isoTimeRegex.source})?`); const isoYmdRegex = /([+-]\d{6}|\d{4})(?:-?(\d\d)(?:-?(\d\d))?)?/; const isoWeekRegex = /(\d{4})-?W(\d\d)(?:-?(\d))?/; const isoOrdinalRegex = /(\d{4})-?(\d{3})/; -const extractISOWeekData = simpleParse("weekYear", "weekNumber", "weekDay"); +const extractISOWeekData = simpleParse("weekYear", "weekNumber", "weekday"); const extractISOOrdinalData = simpleParse("year", "ordinal"); const sqlYmdRegex = /(\d{4})-(\d\d)-(\d\d)/; // dumbed-down version of the ISO one const sqlTimeRegex = RegExp( @@ -305,7 +305,7 @@ const extractPartialIsoIntervalEndDate = simpleParse( "month", "day", "weekNumber", - "weekDay", + "weekday", "ordinal" ); From 055837df121e37a80e8c48fdf2f733472c5d7c7e Mon Sep 17 00:00:00 2001 From: Take Weiland Date: Mon, 23 Mar 2026 21:53:09 +0100 Subject: [PATCH 7/9] Fix ES6 links in documentation --- docs/install.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/install.md b/docs/install.md index f29a875bf..13da769ea 100644 --- a/docs/install.md +++ b/docs/install.md @@ -66,8 +66,8 @@ requirejs(["luxon"], function(luxon) { ## ES6 -- [Download full](https://moment.github.io/luxon/es6/luxon.js) -- [Download minified](https://moment.github.io/luxon/es6/luxon.min.js) +- [Download full](https://moment.github.io/luxon/es6/luxon.mjs) +- [Download minified](https://moment.github.io/luxon/es6/luxon.min.mjs) ```js import { DateTime } from "luxon"; From f50c829ae13ea127f1ce217aa39090bc2fb6dcce Mon Sep 17 00:00:00 2001 From: Take Weiland Date: Mon, 23 Mar 2026 21:53:24 +0100 Subject: [PATCH 8/9] Fix "module" entry in package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index f80269b17..ed1f34b9c 100644 --- a/package.json +++ b/package.json @@ -60,7 +60,7 @@ "uglify-js": "^3.13.10" }, "main": "build/node/luxon.js", - "module": "src/luxon.js", + "module": "build/es6/luxon.mjs", "browser": "build/cjs-browser/luxon.js", "jsdelivr": "build/global/luxon.min.js", "unpkg": "build/global/luxon.min.js", From 651127dc694329d51b56d491c56408e9dc4e6923 Mon Sep 17 00:00:00 2001 From: dobon Date: Mon, 23 Mar 2026 14:39:45 -0700 Subject: [PATCH 9/9] Render dark mode toggle in sidebar on all pages (#1763) --------- Co-authored-by: camoch23 <144624835+camoch23@users.noreply.github.com> Co-authored-by: Take Weiland --- site/plugins/dark-theme-toggle.css | 32 +++++++++++++++++++----------- site/plugins/dark-theme-toggle.js | 15 ++++++++++---- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/site/plugins/dark-theme-toggle.css b/site/plugins/dark-theme-toggle.css index 463a79174..11129d4f6 100644 --- a/site/plugins/dark-theme-toggle.css +++ b/site/plugins/dark-theme-toggle.css @@ -1,4 +1,4 @@ -#docsify-dark-theme-toggle { +.docsify-dark-theme-toggle { position: absolute; display: inline-block; width: 52px; @@ -13,30 +13,38 @@ .sidebar > .app-name { position: relative; } -.app-name > #docsify-dark-theme-toggle { +.app-name > .docsify-dark-theme-toggle { margin-right: 1rem; margin-top: 0; right: 0; left: unset; + transition: opacity 250ms ease, visibility 250ms steps(1, jump-both); + opacity: 0; + visibility: hidden; +} +.sticky .app-name > .docsify-dark-theme-toggle { + opacity: 1; + visibility: visible; } -#docsify-dark-theme-toggle::before, #docsify-dark-theme-toggle::after { + +.docsify-dark-theme-toggle::before, .docsify-dark-theme-toggle::after { position: absolute; top: 0.1em; font-size: 16px; transition: opacity 0.3s; } -#docsify-dark-theme-toggle::before { +.docsify-dark-theme-toggle::before { content: "🌙"; left: 0.1em; opacity: 0; z-index: 1; } -#docsify-dark-theme-toggle::after { +.docsify-dark-theme-toggle::after { content: "🌞"; right: 0.1em; opacity: 1; } -#docsify-dark-theme-toggle > span { +.docsify-dark-theme-toggle > span { position: absolute; top: 0; left: 0; @@ -46,7 +54,7 @@ border-radius: 28px; transition: background-color 0.3s; } -#docsify-dark-theme-toggle > span::before { +.docsify-dark-theme-toggle > span::before { content: ""; position: absolute; height: 22px; @@ -58,15 +66,15 @@ border-radius: 50%; transition: transform 0.3s; } -.dark #docsify-dark-theme-toggle::after { +.dark .docsify-dark-theme-toggle::after { opacity: 0; } -.dark #docsify-dark-theme-toggle::before { +.dark .docsify-dark-theme-toggle::before { opacity: 1; } -.dark #docsify-dark-theme-toggle > span { +.dark .docsify-dark-theme-toggle > span { background-color: var(--theme-color, #ea6f5a); } -.dark #docsify-dark-theme-toggle > span::before { +.dark .docsify-dark-theme-toggle > span::before { transform: translateX(24px); -} \ No newline at end of file +} diff --git a/site/plugins/dark-theme-toggle.js b/site/plugins/dark-theme-toggle.js index 13c2e68e9..e6f74cfff 100644 --- a/site/plugins/dark-theme-toggle.js +++ b/site/plugins/dark-theme-toggle.js @@ -3,7 +3,6 @@ const TOGGLE_ID = "docsify-dark-theme-toggle", dom = Docsify.dom, darkThemeStyleSheet = dom.find('link[href$="dark.css"]'), - toggleEl = dom.create("div", ""), applyTheme = (swap = false) => { const isDark = Boolean(swap ^ (localStorage[TOGGLE_ID] == "true")); localStorage[TOGGLE_ID] = isDark; @@ -11,10 +10,18 @@ dom.toggleClass(dom.body, isDark ? "add" : "remove", "dark"); }; localStorage[TOGGLE_ID] ??= matchMedia("(prefers-color-scheme: dark)").matches; - toggleEl.id = TOGGLE_ID; - dom.on(toggleEl, "click", () => applyTheme(true)); hook.init(applyTheme); - hook.doneEach(() => dom.before(dom.find(".cover.show, .sidebar > .app-name"), toggleEl)); + hook.doneEach(() => { + dom.findAll(".cover.show, .sidebar > .app-name").forEach((target) => { + let toggleEl = dom.find(target, `.${TOGGLE_ID}`); + if (null == toggleEl) { + toggleEl = dom.create("div", ""); + toggleEl.className = TOGGLE_ID; + dom.on(toggleEl, "click", () => applyTheme(true)); + } + dom.before(target, toggleEl); + }); + }); }; $docsify ??= {}; $docsify.plugins = [...($docsify.plugins ?? []), darkThemeTogglePlugin];