GitHub Relative Time Format

replacing GitHub relative timestamps(<relative-time>) with customizable date and time formats

이 스크립트를 설치하려면 Tampermonkey, Greasemonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램을 설치해야 합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Violentmonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey 또는 Userscripts와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 Tampermonkey와 같은 확장 프로그램이 필요합니다.

이 스크립트를 설치하려면 유저 스크립트 관리자 확장 프로그램이 필요합니다.

(이미 유저 스크립트 관리자가 설치되어 있습니다. 설치를 진행합니다!)

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 Stylus와 같은 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

이 스타일을 설치하려면 유저 스타일 관리자 확장 프로그램이 필요합니다.

(이미 유저 스타일 관리자가 설치되어 있습니다. 설치를 진행합니다!)

// ==UserScript==
// @name              GitHub Relative Time Format
// @name:zh-CN        GitHub 时间格式化
// @namespace         https://greatest.deepsurf.us/zh-CN/scripts/480032-github-relative-time-format
// @version           0.7.1
// @description       replacing GitHub relative timestamps(<relative-time>) with customizable date and time formats
// @description:zh-CN 用自定义的日期时间格式替换 GitHub 时间显示(<relative-time>)
// @author            MuXiu1997 (https://github.com/MuXiu1997)
// @license           MIT
// @homepageURL       https://github.com/MuXiu1997/github-relative-time-format
// @supportURL        https://github.com/MuXiu1997/github-relative-time-format
// @match             https://github.com/**
// @icon              https://www.google.com/s2/favicons?sz=64&domain=github.com
// @grant             GM_getValue
// @grant             GM_setValue
// @grant             GM_registerMenuCommand
// @grant             GM_unregisterMenuCommand
// @require           https://cdn.jsdelivr.net/npm/[email protected]/dayjs.min.js
// @require           https://cdn.jsdelivr.net/npm/[email protected]/dist/src/index.umd.js
// ==/UserScript==
(function(ts_debounce, dayjs) {

//#region rolldown:runtime
	var __create = Object.create;
	var __defProp = Object.defineProperty;
	var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
	var __getOwnPropNames = Object.getOwnPropertyNames;
	var __getProtoOf = Object.getPrototypeOf;
	var __hasOwnProp = Object.prototype.hasOwnProperty;
	var __copyProps = (to, from, except, desc) => {
		if (from && typeof from === "object" || typeof from === "function") {
			for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
				key = keys[i];
				if (!__hasOwnProp.call(to, key) && key !== except) {
					__defProp(to, key, {
						get: ((k) => from[k]).bind(null, key),
						enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
					});
				}
			}
		}
		return to;
	};
	var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
		value: mod,
		enumerable: true
	}) : target, mod));

//#endregion
dayjs = __toESM(dayjs);

//#region node_modules/.pnpm/[email protected]/node_modules/alien-signals/esm/system.mjs
	function createReactiveSystem({ update, notify, unwatched }) {
		return {
			link: link$1,
			unlink: unlink$1,
			propagate: propagate$1,
			checkDirty: checkDirty$1,
			shallowPropagate: shallowPropagate$1
		};
		function link$1(dep, sub, version$1) {
			const prevDep = sub.depsTail;
			if (prevDep !== void 0 && prevDep.dep === dep) return;
			const nextDep = prevDep !== void 0 ? prevDep.nextDep : sub.deps;
			if (nextDep !== void 0 && nextDep.dep === dep) {
				nextDep.version = version$1;
				sub.depsTail = nextDep;
				return;
			}
			const prevSub = dep.subsTail;
			if (prevSub !== void 0 && prevSub.version === version$1 && prevSub.sub === sub) return;
			const newLink = sub.depsTail = dep.subsTail = {
				version: version$1,
				dep,
				sub,
				prevDep,
				nextDep,
				prevSub,
				nextSub: void 0
			};
			if (nextDep !== void 0) nextDep.prevDep = newLink;
			if (prevDep !== void 0) prevDep.nextDep = newLink;
			else sub.deps = newLink;
			if (prevSub !== void 0) prevSub.nextSub = newLink;
			else dep.subs = newLink;
		}
		function unlink$1(link$2, sub = link$2.sub) {
			const dep = link$2.dep;
			const prevDep = link$2.prevDep;
			const nextDep = link$2.nextDep;
			const nextSub = link$2.nextSub;
			const prevSub = link$2.prevSub;
			if (nextDep !== void 0) nextDep.prevDep = prevDep;
			else sub.depsTail = prevDep;
			if (prevDep !== void 0) prevDep.nextDep = nextDep;
			else sub.deps = nextDep;
			if (nextSub !== void 0) nextSub.prevSub = prevSub;
			else dep.subsTail = prevSub;
			if (prevSub !== void 0) prevSub.nextSub = nextSub;
			else if ((dep.subs = nextSub) === void 0) unwatched(dep);
			return nextDep;
		}
		function propagate$1(link$2) {
			let next = link$2.nextSub;
			let stack;
			top: do {
				const sub = link$2.sub;
				let flags = sub.flags;
				if (!(flags & 60)) sub.flags = flags | 32;
				else if (!(flags & 12)) flags = 0;
				else if (!(flags & 4)) sub.flags = flags & -9 | 32;
				else if (!(flags & 48) && isValidLink(link$2, sub)) {
					sub.flags = flags | 40;
					flags &= 1;
				} else flags = 0;
				if (flags & 2) notify(sub);
				if (flags & 1) {
					const subSubs = sub.subs;
					if (subSubs !== void 0) {
						const nextSub = (link$2 = subSubs).nextSub;
						if (nextSub !== void 0) {
							stack = {
								value: next,
								prev: stack
							};
							next = nextSub;
						}
						continue;
					}
				}
				if ((link$2 = next) !== void 0) {
					next = link$2.nextSub;
					continue;
				}
				while (stack !== void 0) {
					link$2 = stack.value;
					stack = stack.prev;
					if (link$2 !== void 0) {
						next = link$2.nextSub;
						continue top;
					}
				}
				break;
			} while (true);
		}
		function checkDirty$1(link$2, sub) {
			let stack;
			let checkDepth = 0;
			let dirty = false;
			top: do {
				const dep = link$2.dep;
				const flags = dep.flags;
				if (sub.flags & 16) dirty = true;
				else if ((flags & 17) === 17) {
					if (update(dep)) {
						const subs = dep.subs;
						if (subs.nextSub !== void 0) shallowPropagate$1(subs);
						dirty = true;
					}
				} else if ((flags & 33) === 33) {
					if (link$2.nextSub !== void 0 || link$2.prevSub !== void 0) stack = {
						value: link$2,
						prev: stack
					};
					link$2 = dep.deps;
					sub = dep;
					++checkDepth;
					continue;
				}
				if (!dirty) {
					const nextDep = link$2.nextDep;
					if (nextDep !== void 0) {
						link$2 = nextDep;
						continue;
					}
				}
				while (checkDepth--) {
					const firstSub = sub.subs;
					const hasMultipleSubs = firstSub.nextSub !== void 0;
					if (hasMultipleSubs) {
						link$2 = stack.value;
						stack = stack.prev;
					} else link$2 = firstSub;
					if (dirty) {
						if (update(sub)) {
							if (hasMultipleSubs) shallowPropagate$1(firstSub);
							sub = link$2.sub;
							continue;
						}
						dirty = false;
					} else sub.flags &= -33;
					sub = link$2.sub;
					const nextDep = link$2.nextDep;
					if (nextDep !== void 0) {
						link$2 = nextDep;
						continue top;
					}
				}
				return dirty;
			} while (true);
		}
		function shallowPropagate$1(link$2) {
			do {
				const sub = link$2.sub;
				const flags = sub.flags;
				if ((flags & 48) === 32) {
					sub.flags = flags | 16;
					if ((flags & 6) === 2) notify(sub);
				}
			} while ((link$2 = link$2.nextSub) !== void 0);
		}
		function isValidLink(checkLink, sub) {
			let link$2 = sub.depsTail;
			while (link$2 !== void 0) {
				if (link$2 === checkLink) return true;
				link$2 = link$2.prevDep;
			}
			return false;
		}
	}

//#endregion
//#region node_modules/.pnpm/[email protected]/node_modules/alien-signals/esm/index.mjs
	let cycle = 0;
	let batchDepth = 0;
	let notifyIndex = 0;
	let queuedLength = 0;
	let activeSub;
	const queued = [];
	const { link, unlink, propagate, checkDirty, shallowPropagate } = createReactiveSystem({
		update(node) {
			if (node.depsTail !== void 0) return updateComputed(node);
			else return updateSignal(node);
		},
		notify(effect$1) {
			let insertIndex = queuedLength;
			let firstInsertedIndex = insertIndex;
			do {
				var _effect$subs;
				effect$1.flags &= -3;
				queued[insertIndex++] = effect$1;
				effect$1 = (_effect$subs = effect$1.subs) === null || _effect$subs === void 0 ? void 0 : _effect$subs.sub;
				if (effect$1 === void 0 || !(effect$1.flags & 2)) break;
			} while (true);
			queuedLength = insertIndex;
			while (firstInsertedIndex < --insertIndex) {
				const left = queued[firstInsertedIndex];
				queued[firstInsertedIndex++] = queued[insertIndex];
				queued[insertIndex] = left;
			}
		},
		unwatched(node) {
			if (!(node.flags & 1)) effectScopeOper.call(node);
			else if (node.depsTail !== void 0) {
				node.depsTail = void 0;
				node.flags = 17;
				purgeDeps(node);
			}
		}
	});
	function setActiveSub(sub) {
		const prevSub = activeSub;
		activeSub = sub;
		return prevSub;
	}
	function signal(initialValue) {
		return signalOper.bind({
			currentValue: initialValue,
			pendingValue: initialValue,
			subs: void 0,
			subsTail: void 0,
			flags: 1
		});
	}
	function computed(getter) {
		return computedOper.bind({
			value: void 0,
			subs: void 0,
			subsTail: void 0,
			deps: void 0,
			depsTail: void 0,
			flags: 0,
			getter
		});
	}
	function effect(fn) {
		const e = {
			fn,
			subs: void 0,
			subsTail: void 0,
			deps: void 0,
			depsTail: void 0,
			flags: 6
		};
		const prevSub = setActiveSub(e);
		if (prevSub !== void 0) link(e, prevSub, 0);
		try {
			e.fn();
		} finally {
			activeSub = prevSub;
			e.flags &= -5;
		}
		return effectOper.bind(e);
	}
	function updateComputed(c) {
		++cycle;
		c.depsTail = void 0;
		c.flags = 5;
		const prevSub = setActiveSub(c);
		try {
			const oldValue = c.value;
			return oldValue !== (c.value = c.getter(oldValue));
		} finally {
			activeSub = prevSub;
			c.flags &= -5;
			purgeDeps(c);
		}
	}
	function updateSignal(s) {
		s.flags = 1;
		return s.currentValue !== (s.currentValue = s.pendingValue);
	}
	function run(e) {
		const flags = e.flags;
		if (flags & 16 || flags & 32 && checkDirty(e.deps, e)) {
			++cycle;
			e.depsTail = void 0;
			e.flags = 6;
			const prevSub = setActiveSub(e);
			try {
				e.fn();
			} finally {
				activeSub = prevSub;
				e.flags &= -5;
				purgeDeps(e);
			}
		} else e.flags = 2;
	}
	function flush() {
		while (notifyIndex < queuedLength) {
			const effect$1 = queued[notifyIndex];
			queued[notifyIndex++] = void 0;
			run(effect$1);
		}
		notifyIndex = 0;
		queuedLength = 0;
	}
	function computedOper() {
		const flags = this.flags;
		if (flags & 16 || flags & 32 && (checkDirty(this.deps, this) || (this.flags = flags & -33, false))) {
			if (updateComputed(this)) {
				const subs = this.subs;
				if (subs !== void 0) shallowPropagate(subs);
			}
		} else if (!flags) {
			this.flags = 5;
			const prevSub = setActiveSub(this);
			try {
				this.value = this.getter();
			} finally {
				activeSub = prevSub;
				this.flags &= -5;
			}
		}
		const sub = activeSub;
		if (sub !== void 0) link(this, sub, cycle);
		return this.value;
	}
	function signalOper(...value) {
		if (value.length) {
			if (this.pendingValue !== (this.pendingValue = value[0])) {
				this.flags = 17;
				const subs = this.subs;
				if (subs !== void 0) {
					propagate(subs);
					if (!batchDepth) flush();
				}
			}
		} else {
			if (this.flags & 16) {
				if (updateSignal(this)) {
					const subs = this.subs;
					if (subs !== void 0) shallowPropagate(subs);
				}
			}
			let sub = activeSub;
			while (sub !== void 0) {
				var _sub$subs;
				if (sub.flags & 3) {
					link(this, sub, cycle);
					break;
				}
				sub = (_sub$subs = sub.subs) === null || _sub$subs === void 0 ? void 0 : _sub$subs.sub;
			}
			return this.currentValue;
		}
	}
	function effectOper() {
		effectScopeOper.call(this);
	}
	function effectScopeOper() {
		this.depsTail = void 0;
		this.flags = 0;
		purgeDeps(this);
		const sub = this.subs;
		if (sub !== void 0) unlink(sub);
	}
	function purgeDeps(sub) {
		const depsTail = sub.depsTail;
		let dep = depsTail !== void 0 ? depsTail.nextDep : sub.deps;
		while (dep !== void 0) dep = unlink(dep, sub);
	}

//#endregion
//#region \0@[email protected]/helpers/typeof.js
	function _typeof(o) {
		"@babel/helpers - typeof";
		return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function(o$1) {
			return typeof o$1;
		} : function(o$1) {
			return o$1 && "function" == typeof Symbol && o$1.constructor === Symbol && o$1 !== Symbol.prototype ? "symbol" : typeof o$1;
		}, _typeof(o);
	}

//#endregion
//#region \0@[email protected]/helpers/toPrimitive.js
	function toPrimitive(t, r) {
		if ("object" != _typeof(t) || !t) return t;
		var e = t[Symbol.toPrimitive];
		if (void 0 !== e) {
			var i = e.call(t, r || "default");
			if ("object" != _typeof(i)) return i;
			throw new TypeError("@@toPrimitive must return a primitive value.");
		}
		return ("string" === r ? String : Number)(t);
	}

//#endregion
//#region \0@[email protected]/helpers/toPropertyKey.js
	function toPropertyKey(t) {
		var i = toPrimitive(t, "string");
		return "symbol" == _typeof(i) ? i : i + "";
	}

//#endregion
//#region \0@[email protected]/helpers/defineProperty.js
	function _defineProperty(e, r, t) {
		return (r = toPropertyKey(r)) in e ? Object.defineProperty(e, r, {
			value: t,
			enumerable: !0,
			configurable: !0,
			writable: !0
		}) : e[r] = t, e;
	}

//#endregion
//#region \0@[email protected]/helpers/objectSpread2.js
	function ownKeys(e, r) {
		var t = Object.keys(e);
		if (Object.getOwnPropertySymbols) {
			var o = Object.getOwnPropertySymbols(e);
			r && (o = o.filter(function(r$1) {
				return Object.getOwnPropertyDescriptor(e, r$1).enumerable;
			})), t.push.apply(t, o);
		}
		return t;
	}
	function _objectSpread2(e) {
		for (var r = 1; r < arguments.length; r++) {
			var t = null != arguments[r] ? arguments[r] : {};
			r % 2 ? ownKeys(Object(t), !0).forEach(function(r$1) {
				_defineProperty(e, r$1, t[r$1]);
			}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function(r$1) {
				Object.defineProperty(e, r$1, Object.getOwnPropertyDescriptor(t, r$1));
			});
		}
		return e;
	}

//#endregion
//#region node_modules/.pnpm/[email protected]/node_modules/consola/dist/core.mjs
	const LogLevels = {
		silent: Number.NEGATIVE_INFINITY,
		fatal: 0,
		error: 0,
		warn: 1,
		log: 2,
		info: 3,
		success: 3,
		fail: 3,
		ready: 3,
		start: 3,
		box: 3,
		debug: 4,
		trace: 5,
		verbose: Number.POSITIVE_INFINITY
	};
	const LogTypes = {
		silent: { level: -1 },
		fatal: { level: LogLevels.fatal },
		error: { level: LogLevels.error },
		warn: { level: LogLevels.warn },
		log: { level: LogLevels.log },
		info: { level: LogLevels.info },
		success: { level: LogLevels.success },
		fail: { level: LogLevels.fail },
		ready: { level: LogLevels.info },
		start: { level: LogLevels.info },
		box: { level: LogLevels.info },
		debug: { level: LogLevels.debug },
		trace: { level: LogLevels.trace },
		verbose: { level: LogLevels.verbose }
	};
	function isPlainObject$1(value) {
		if (value === null || typeof value !== "object") return false;
		const prototype = Object.getPrototypeOf(value);
		if (prototype !== null && prototype !== Object.prototype && Object.getPrototypeOf(prototype) !== null) return false;
		if (Symbol.iterator in value) return false;
		if (Symbol.toStringTag in value) return Object.prototype.toString.call(value) === "[object Module]";
		return true;
	}
	function _defu(baseObject, defaults, namespace = ".", merger) {
		if (!isPlainObject$1(defaults)) return _defu(baseObject, {}, namespace, merger);
		const object = Object.assign({}, defaults);
		for (const key in baseObject) {
			if (key === "__proto__" || key === "constructor") continue;
			const value = baseObject[key];
			if (value === null || value === void 0) continue;
			if (merger && merger(object, key, value, namespace)) continue;
			if (Array.isArray(value) && Array.isArray(object[key])) object[key] = [...value, ...object[key]];
			else if (isPlainObject$1(value) && isPlainObject$1(object[key])) object[key] = _defu(value, object[key], (namespace ? `${namespace}.` : "") + key.toString(), merger);
			else object[key] = value;
		}
		return object;
	}
	function createDefu(merger) {
		return (...arguments_) => arguments_.reduce((p, c) => _defu(p, c, "", merger), {});
	}
	const defu = createDefu();
	function isPlainObject(obj) {
		return Object.prototype.toString.call(obj) === "[object Object]";
	}
	function isLogObj(arg) {
		if (!isPlainObject(arg)) return false;
		if (!arg.message && !arg.args) return false;
		if (arg.stack) return false;
		return true;
	}
	let paused = false;
	const queue = [];
	var Consola = class Consola {
		/**
		* Creates an instance of Consola with specified options or defaults.
		*
		* @param {Partial<ConsolaOptions>} [options={}] - Configuration options for the Consola instance.
		*/
		constructor(options = {}) {
			const types = options.types || LogTypes;
			this.options = defu(_objectSpread2(_objectSpread2({}, options), {}, {
				defaults: _objectSpread2({}, options.defaults),
				level: _normalizeLogLevel(options.level, types),
				reporters: [...options.reporters || []]
			}), {
				types: LogTypes,
				throttle: 1e3,
				throttleMin: 5,
				formatOptions: {
					date: true,
					colors: false,
					compact: true
				}
			});
			for (const type in types) {
				const defaults = _objectSpread2(_objectSpread2({ type }, this.options.defaults), types[type]);
				this[type] = this._wrapLogFn(defaults);
				this[type].raw = this._wrapLogFn(defaults, true);
			}
			if (this.options.mockFn) this.mockTypes();
			this._lastLog = {};
		}
		/**
		* Gets the current log level of the Consola instance.
		*
		* @returns {number} The current log level.
		*/
		get level() {
			return this.options.level;
		}
		/**
		* Sets the minimum log level that will be output by the instance.
		*
		* @param {number} level - The new log level to set.
		*/
		set level(level) {
			this.options.level = _normalizeLogLevel(level, this.options.types, this.options.level);
		}
		/**
		* Displays a prompt to the user and returns the response.
		* Throw an error if `prompt` is not supported by the current configuration.
		*
		* @template T
		* @param {string} message - The message to display in the prompt.
		* @param {T} [opts] - Optional options for the prompt. See {@link PromptOptions}.
		* @returns {promise<T>} A promise that infer with the prompt options. See {@link PromptOptions}.
		*/
		prompt(message, opts) {
			if (!this.options.prompt) throw new Error("prompt is not supported!");
			return this.options.prompt(message, opts);
		}
		/**
		* Creates a new instance of Consola, inheriting options from the current instance, with possible overrides.
		*
		* @param {Partial<ConsolaOptions>} options - Optional overrides for the new instance. See {@link ConsolaOptions}.
		* @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}.
		*/
		create(options) {
			const instance = new Consola(_objectSpread2(_objectSpread2({}, this.options), options));
			if (this._mockFn) instance.mockTypes(this._mockFn);
			return instance;
		}
		/**
		* Creates a new Consola instance with the specified default log object properties.
		*
		* @param {InputLogObject} defaults - Default properties to include in any log from the new instance. See {@link InputLogObject}.
		* @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}.
		*/
		withDefaults(defaults) {
			return this.create(_objectSpread2(_objectSpread2({}, this.options), {}, { defaults: _objectSpread2(_objectSpread2({}, this.options.defaults), defaults) }));
		}
		/**
		* Creates a new Consola instance with a specified tag, which will be included in every log.
		*
		* @param {string} tag - The tag to include in each log of the new instance.
		* @returns {ConsolaInstance} A new Consola instance. See {@link ConsolaInstance}.
		*/
		withTag(tag) {
			return this.withDefaults({ tag: this.options.defaults.tag ? this.options.defaults.tag + ":" + tag : tag });
		}
		/**
		* Adds a custom reporter to the Consola instance.
		* Reporters will be called for each log message, depending on their implementation and log level.
		*
		* @param {ConsolaReporter} reporter - The reporter to add. See {@link ConsolaReporter}.
		* @returns {Consola} The current Consola instance.
		*/
		addReporter(reporter) {
			this.options.reporters.push(reporter);
			return this;
		}
		/**
		* Removes a custom reporter from the Consola instance.
		* If no reporter is specified, all reporters will be removed.
		*
		* @param {ConsolaReporter} reporter - The reporter to remove. See {@link ConsolaReporter}.
		* @returns {Consola} The current Consola instance.
		*/
		removeReporter(reporter) {
			if (reporter) {
				const i = this.options.reporters.indexOf(reporter);
				if (i !== -1) return this.options.reporters.splice(i, 1);
			} else this.options.reporters.splice(0);
			return this;
		}
		/**
		* Replaces all reporters of the Consola instance with the specified array of reporters.
		*
		* @param {ConsolaReporter[]} reporters - The new reporters to set. See {@link ConsolaReporter}.
		* @returns {Consola} The current Consola instance.
		*/
		setReporters(reporters) {
			this.options.reporters = Array.isArray(reporters) ? reporters : [reporters];
			return this;
		}
		wrapAll() {
			this.wrapConsole();
			this.wrapStd();
		}
		restoreAll() {
			this.restoreConsole();
			this.restoreStd();
		}
		/**
		* Overrides console methods with Consola logging methods for consistent logging.
		*/
		wrapConsole() {
			for (const type in this.options.types) {
				if (!console["__" + type]) console["__" + type] = console[type];
				console[type] = this[type].raw;
			}
		}
		/**
		* Restores the original console methods, removing Consola overrides.
		*/
		restoreConsole() {
			for (const type in this.options.types) if (console["__" + type]) {
				console[type] = console["__" + type];
				delete console["__" + type];
			}
		}
		/**
		* Overrides standard output and error streams to redirect them through Consola.
		*/
		wrapStd() {
			this._wrapStream(this.options.stdout, "log");
			this._wrapStream(this.options.stderr, "log");
		}
		_wrapStream(stream, type) {
			if (!stream) return;
			if (!stream.__write) stream.__write = stream.write;
			stream.write = (data) => {
				this[type].raw(String(data).trim());
			};
		}
		/**
		* Restores the original standard output and error streams, removing the Consola redirection.
		*/
		restoreStd() {
			this._restoreStream(this.options.stdout);
			this._restoreStream(this.options.stderr);
		}
		_restoreStream(stream) {
			if (!stream) return;
			if (stream.__write) {
				stream.write = stream.__write;
				delete stream.__write;
			}
		}
		/**
		* Pauses logging, queues incoming logs until resumed.
		*/
		pauseLogs() {
			paused = true;
		}
		/**
		* Resumes logging, processing any queued logs.
		*/
		resumeLogs() {
			paused = false;
			const _queue = queue.splice(0);
			for (const item of _queue) item[0]._logFn(item[1], item[2]);
		}
		/**
		* Replaces logging methods with mocks if a mock function is provided.
		*
		* @param {ConsolaOptions["mockFn"]} mockFn - The function to use for mocking logging methods. See {@link ConsolaOptions["mockFn"]}.
		*/
		mockTypes(mockFn) {
			const _mockFn = mockFn || this.options.mockFn;
			this._mockFn = _mockFn;
			if (typeof _mockFn !== "function") return;
			for (const type in this.options.types) {
				this[type] = _mockFn(type, this.options.types[type]) || this[type];
				this[type].raw = this[type];
			}
		}
		_wrapLogFn(defaults, isRaw) {
			return (...args) => {
				if (paused) {
					queue.push([
						this,
						defaults,
						args,
						isRaw
					]);
					return;
				}
				return this._logFn(defaults, args, isRaw);
			};
		}
		_logFn(defaults, args, isRaw) {
			if ((defaults.level || 0) > this.level) return false;
			const logObj = _objectSpread2(_objectSpread2({
				date: /* @__PURE__ */ new Date(),
				args: []
			}, defaults), {}, { level: _normalizeLogLevel(defaults.level, this.options.types) });
			if (!isRaw && args.length === 1 && isLogObj(args[0])) Object.assign(logObj, args[0]);
			else logObj.args = [...args];
			if (logObj.message) {
				logObj.args.unshift(logObj.message);
				delete logObj.message;
			}
			if (logObj.additional) {
				if (!Array.isArray(logObj.additional)) logObj.additional = logObj.additional.split("\n");
				logObj.args.push("\n" + logObj.additional.join("\n"));
				delete logObj.additional;
			}
			logObj.type = typeof logObj.type === "string" ? logObj.type.toLowerCase() : "log";
			logObj.tag = typeof logObj.tag === "string" ? logObj.tag : "";
			const resolveLog = (newLog = false) => {
				const repeated = (this._lastLog.count || 0) - this.options.throttleMin;
				if (this._lastLog.object && repeated > 0) {
					const args2 = [...this._lastLog.object.args];
					if (repeated > 1) args2.push(`(repeated ${repeated} times)`);
					this._log(_objectSpread2(_objectSpread2({}, this._lastLog.object), {}, { args: args2 }));
					this._lastLog.count = 1;
				}
				if (newLog) {
					this._lastLog.object = logObj;
					this._log(logObj);
				}
			};
			clearTimeout(this._lastLog.timeout);
			const diffTime = this._lastLog.time && logObj.date ? logObj.date.getTime() - this._lastLog.time.getTime() : 0;
			this._lastLog.time = logObj.date;
			if (diffTime < this.options.throttle) try {
				const serializedLog = JSON.stringify([
					logObj.type,
					logObj.tag,
					logObj.args
				]);
				const isSameLog = this._lastLog.serialized === serializedLog;
				this._lastLog.serialized = serializedLog;
				if (isSameLog) {
					this._lastLog.count = (this._lastLog.count || 0) + 1;
					if (this._lastLog.count > this.options.throttleMin) {
						this._lastLog.timeout = setTimeout(resolveLog, this.options.throttle);
						return;
					}
				}
			} catch (_unused) {}
			resolveLog(true);
		}
		_log(logObj) {
			for (const reporter of this.options.reporters) reporter.log(logObj, { options: this.options });
		}
	};
	function _normalizeLogLevel(input, types = {}, defaultLevel = 3) {
		if (input === void 0) return defaultLevel;
		if (typeof input === "number") return input;
		if (types[input] && types[input].level !== void 0) return types[input].level;
		return defaultLevel;
	}
	Consola.prototype.add = Consola.prototype.addReporter;
	Consola.prototype.remove = Consola.prototype.removeReporter;
	Consola.prototype.clear = Consola.prototype.removeReporter;
	Consola.prototype.withScope = Consola.prototype.withTag;
	Consola.prototype.mock = Consola.prototype.mockTypes;
	Consola.prototype.pause = Consola.prototype.pauseLogs;
	Consola.prototype.resume = Consola.prototype.resumeLogs;
	function createConsola(options = {}) {
		return new Consola(options);
	}

//#endregion
//#region node_modules/.pnpm/[email protected]/node_modules/consola/dist/browser.mjs
	var BrowserReporter = class {
		constructor(options) {
			this.options = _objectSpread2({}, options);
			this.defaultColor = "#7f8c8d";
			this.levelColorMap = {
				0: "#c0392b",
				1: "#f39c12",
				3: "#00BCD4"
			};
			this.typeColorMap = { success: "#2ecc71" };
		}
		_getLogFn(level) {
			if (level < 1) return console.__error || console.error;
			if (level === 1) return console.__warn || console.warn;
			return console.__log || console.log;
		}
		log(logObj) {
			const consoleLogFn = this._getLogFn(logObj.level);
			const type = logObj.type === "log" ? "" : logObj.type;
			const tag = logObj.tag || "";
			const style = `
      background: ${this.typeColorMap[logObj.type] || this.levelColorMap[logObj.level] || this.defaultColor};
      border-radius: 0.5em;
      color: white;
      font-weight: bold;
      padding: 2px 0.5em;
    `;
			const badge = `%c${[tag, type].filter(Boolean).join(":")}`;
			if (typeof logObj.args[0] === "string") consoleLogFn(`${badge}%c ${logObj.args[0]}`, style, "", ...logObj.args.slice(1));
			else consoleLogFn(badge, style, ...logObj.args);
		}
	};
	function createConsola$1(options = {}) {
		return createConsola(_objectSpread2({
			reporters: options.reporters || [new BrowserReporter({})],
			prompt(message, options2 = {}) {
				if (options2.type === "confirm") return Promise.resolve(confirm(message));
				return Promise.resolve(prompt(message));
			}
		}, options));
	}
	const consola = createConsola$1();

//#endregion
//#region package.json
	var version = "0.7.1";

//#endregion
//#region src/core.ts
	const logger = consola.withDefaults({ tag: "GRTF" });
	/** Check if the element is a valid relative-time custom element */
	function isRelativeTimeElement(element) {
		return element instanceof HTMLElement && element.tagName === "RELATIVE-TIME";
	}
	/**
	* Check if the node is a <relative-time> element or sits inside one (including Shadow DOM).
	* This is efficient for attribute or characterData mutations.
	*/
	function isInsideRelativeTime(node) {
		if (!node) return false;
		const element = node instanceof Element ? node : node.parentElement;
		if (element === null || element === void 0 ? void 0 : element.closest("relative-time")) return true;
		const root = node.getRootNode();
		return root instanceof ShadowRoot && isRelativeTimeElement(root.host);
	}
	/**
	* Check if the element contains any <relative-time> descendants.
	* This is useful for childList mutations where a container might be added.
	*/
	function isContainingRelativeTime(node) {
		return node instanceof Element && node.getElementsByTagName("relative-time").length > 0;
	}
	/** Determine if the element should preserve its native format based on attributes */
	function shouldPreserveNativeFormat(element) {
		const format = element.getAttribute("format");
		return format === "duration" || format === "elapsed";
	}
	/** Apply custom format to a single relative-time element */
	function applyCustomFormat(element, displayFormat, tooltipFormat) {
		const startTime = performance.now();
		const datetime = element.getAttribute("datetime");
		if (!datetime) return;
		const date = (0, dayjs.default)(datetime);
		if (!date.isValid()) return;
		element.title = date.format(tooltipFormat);
		try {
			var _element$disconnected;
			(_element$disconnected = element.disconnectedCallback) === null || _element$disconnected === void 0 || _element$disconnected.call(element);
			let updated = false;
			if (element.shadowRoot) {
				const newContent = date.format(displayFormat);
				if (element.shadowRoot.innerHTML !== newContent) {
					element.shadowRoot.innerHTML = newContent;
					updated = true;
				}
			} else {
				const newContent = date.format(displayFormat);
				if (element.textContent !== newContent) {
					element.textContent = newContent;
					updated = true;
				}
			}
			if (updated) {
				const duration = performance.now() - startTime;
				logger.debug(`Updated element:`, element, `in ${duration.toFixed(3)}ms`);
			}
		} catch (error) {
			logger.warn("Error updating element", element, error);
		}
	}
	/** Restore the native behavior of the relative-time element */
	function restoreNativeFormat(element) {
		try {
			var _element$connectedCal;
			(_element$connectedCal = element.connectedCallback) === null || _element$connectedCal === void 0 || _element$connectedCal.call(element);
		} catch (error) {
			logger.warn("Error restoring element", element, error);
		}
	}
	/** Iterate and update all relative-time elements in the DOM */
	function updateAllElements(displayFormat, tooltipFormat) {
		const startTime = performance.now();
		const elements = document.querySelectorAll(`relative-time`);
		if (elements.length === 0) return;
		let updateCount = 0;
		for (const element of elements) if (shouldPreserveNativeFormat(element)) restoreNativeFormat(element);
		else {
			applyCustomFormat(element, displayFormat, tooltipFormat);
			updateCount++;
		}
		const duration = performance.now() - startTime;
		if (updateCount > 0) logger.debug({
			type: "success",
			message: `Total updated: ${updateCount} elements in ${duration.toFixed(3)}ms`
		});
	}

//#endregion
//#region \0@[email protected]/helpers/asyncToGenerator.js
	function asyncGeneratorStep(n, t, e, r, o, a, c) {
		try {
			var i = n[a](c), u = i.value;
		} catch (n$1) {
			e(n$1);
			return;
		}
		i.done ? t(u) : Promise.resolve(u).then(r, o);
	}
	function _asyncToGenerator(n) {
		return function() {
			var t = this, e = arguments;
			return new Promise(function(r, o) {
				var a = n.apply(t, e);
				function _next(n$1) {
					asyncGeneratorStep(a, r, o, _next, _throw, "next", n$1);
				}
				function _throw(n$1) {
					asyncGeneratorStep(a, r, o, _next, _throw, "throw", n$1);
				}
				_next(void 0);
			});
		};
	}

//#endregion
//#region src/ui.ts
	let activeResolve = null;
	/**
	* Show a GitHub-style modal for option editing
	*/
	function showOptionModal(_x, _x2, _x3) {
		return _showOptionModal.apply(this, arguments);
	}
	function _showOptionModal() {
		_showOptionModal = _asyncToGenerator(function* (title, currentValue, type) {
			if (activeResolve) {
				activeResolve(null);
				activeResolve = null;
			}
			const existingDialog = document.querySelector("dialog[data-grtf-modal]");
			if (existingDialog) {
				existingDialog.close();
				existingDialog.remove();
			}
			return new Promise((resolve) => {
				var _dialog$querySelector, _dialog$querySelector2, _dialog$querySelector3;
				activeResolve = resolve;
				const dialog = document.createElement("dialog");
				dialog.dataset.grtfModal = "";
				dialog.className = "Box Box--overlay d-flex flex-column anim-fade-in fast";
				dialog.style.cssText = `
      width: 448px;
      padding: 0;
      border: 1px solid var(--color-border-default, #30363d);
      border-radius: 6px;
      background-color: var(--bgColor-default, var(--color-canvas-overlay, #161b22));
      color: var(--color-fg-default, #c9d1d9);
      box-shadow: var(--color-shadow-large, 0 8px 24px rgba(1, 4, 9, 0.2));
      position: fixed;
      top: 10%;
      left: 50%;
      transform: translateX(-50%);
      margin: 0;
      display: flex;
    `;
				const isBoolean = type === "boolean";
				dialog.innerHTML = `
      <div class="Box-header d-flex flex-items-center">
        <h3 class="Box-title flex-auto">${title}</h3>
        <button class="btn-octicon" type="button" id="modal-close" aria-label="Close">
          <svg aria-hidden="true" height="16" viewBox="0 0 16 16" width="16" fill="currentColor"><path d="M3.72 3.72a.75.75 0 011.06 0L8 6.94l3.22-3.22a.75.75 0 111.06 1.06L9.06 8l3.22 3.22a.75.75 0 11-1.06 1.06L8 9.06l-3.22 3.22a.75.75 0 01-1.06-1.06L6.94 8 3.72 4.78a.75.75 0 010-1.06z"></path></svg>
        </button>
      </div>
      <div class="Box-body">
        ${isBoolean ? `
          <div class="form-checkbox">
            <label>
              <input type="checkbox" id="modal-input" ${currentValue === "true" ? "checked" : ""}>
              Enable
            </label>
          </div>
          ` : `
          <input type="text" id="modal-input" class="form-control input-block" value="${currentValue}" spellcheck="false">
          `}
      </div>
      <div class="Box-footer text-right">
        <button class="btn btn-secondary mr-2" type="button" id="modal-cancel">Cancel</button>
        <button class="btn btn-primary" type="button" id="modal-save">Save</button>
      </div>
    `;
				if (!document.getElementById("grtf-modal-style")) {
					const style = document.createElement("style");
					style.id = "grtf-modal-style";
					style.textContent = `
        dialog[data-grtf-modal]::backdrop {
          background-color: rgba(0, 0, 0, 0.7);
          backdrop-filter: blur(2px);
        }
        dialog[data-grtf-modal] {
          background-color: var(--bgColor-default, var(--color-canvas-overlay, #161b22)) !important;
        }
      `;
					document.head.appendChild(style);
				}
				document.body.appendChild(dialog);
				dialog.showModal();
				const input = dialog.querySelector("#modal-input");
				const close = () => {
					activeResolve = null;
					dialog.close();
					document.body.removeChild(dialog);
				};
				(_dialog$querySelector = dialog.querySelector("#modal-save")) === null || _dialog$querySelector === void 0 || _dialog$querySelector.addEventListener("click", () => {
					const result = isBoolean ? input.checked ? "true" : "false" : input.value;
					const resolveFn = resolve;
					close();
					resolveFn(result);
				});
				(_dialog$querySelector2 = dialog.querySelector("#modal-cancel")) === null || _dialog$querySelector2 === void 0 || _dialog$querySelector2.addEventListener("click", () => {
					const resolveFn = resolve;
					close();
					resolveFn(null);
				});
				(_dialog$querySelector3 = dialog.querySelector("#modal-close")) === null || _dialog$querySelector3 === void 0 || _dialog$querySelector3.addEventListener("click", () => {
					const resolveFn = resolve;
					close();
					resolveFn(null);
				});
				dialog.addEventListener("cancel", () => {
					activeResolve = null;
					document.body.removeChild(dialog);
					resolve(null);
				});
				setTimeout(() => {
					if (isBoolean) input.focus();
					else {
						input.focus();
						input.select();
					}
				}, 0);
			});
		});
		return _showOptionModal.apply(this, arguments);
	}

//#endregion
//#region src/useOption.ts
/** Option management Hook */
	function useOption(key, title, defaultValue, type = "text") {
		const option = signal(typeof GM_getValue !== "undefined" ? GM_getValue(key, defaultValue) : defaultValue);
		if (typeof GM_setValue !== "undefined" && typeof GM_registerMenuCommand !== "undefined") {
			effect(() => {
				GM_setValue(key, option());
			});
			GM_registerMenuCommand(title, _asyncToGenerator(function* () {
				const result = yield showOptionModal(title, option(), type);
				if (result !== null) option(result);
			}));
		}
		return option;
	}

//#endregion
//#region src/index.ts
/** Main entry point for the userscript */
	function main() {
		const displayFormatOption = useOption("DISPLAY_FORMAT", "Change display format", "YY-MM-DD HH:mm");
		const tooltipFormatOption = useOption("TOOLTIP_FORMAT", "Change tooltip format", "YYYY-MM-DD HH:mm:ss");
		const debugLogOption = useOption("DEBUG_LOG", "Enable debug log", "false", "boolean");
		const loggerLevel = computed(() => debugLogOption() === "true" ? LogLevels.verbose : LogLevels.info);
		const runUpdate = () => {
			updateAllElements(displayFormatOption(), tooltipFormatOption());
		};
		effect(() => {
			runUpdate();
		});
		effect(() => {
			logger.level = loggerLevel();
		});
		logger.info(`GitHub Relative Time Format(v${version}) is loaded`);
		const debouncedUpdate = (0, ts_debounce.debounce)(runUpdate, 100);
		/** Initialize MutationObserver to monitor DOM changes for new relative-time elements */
		const initObserver = () => {
			new MutationObserver((mutations) => {
				let shouldUpdate = false;
				for (const mutation of mutations) {
					const { target, type } = mutation;
					if (type === "attributes" || type === "characterData") {
						if (isInsideRelativeTime(target)) {
							shouldUpdate = true;
							break;
						}
					} else if (type === "childList") {
						if (isInsideRelativeTime(target) || isContainingRelativeTime(target)) {
							shouldUpdate = true;
							break;
						}
					}
				}
				if (shouldUpdate) debouncedUpdate();
			}).observe(document.body, {
				childList: true,
				subtree: true,
				attributes: true,
				characterData: true,
				attributeFilter: ["datetime", "format"]
			});
		};
		initObserver();
	}
	main();

//#endregion
})(tsDebounce, dayjs);