better-github

A userscript to enhance GitHub's user experience.

Від 08.05.2026. Дивіться остання версія.

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

You will need to install an extension such as Tampermonkey to install this script.

You will need to install a user script manager extension to install this script.

(У мене вже є менеджер скриптів, дайте мені встановити його!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         better-github
// @namespace    npm/vite-plugin-monkey
// @version      1.0.0
// @author       ChouChiu
// @description  A userscript to enhance GitHub's user experience.
// @license      GPL-3.0-or-later
// @icon         https://vitejs.dev/logo.svg
// @homepageURL  https://github.com/ChouChiu/Better-Github
// @source       https://github.com/ChouChiu/Better-Github.git
// @supportURL   https://github.com/ChouChiu/Better-Github/issues
// @match        https://github.com/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.global.prod.js
// @grant        GM_addStyle
// @grant        GM_getValue
// @grant        GM_setValue
// ==/UserScript==

(function(vue) {
  'use strict';
	var s = new Set();
	var _css = async (t) => {
		if (s.has(t)) return;
		s.add(t);
		((c) => {
			if (typeof GM_addStyle === "function") GM_addStyle(c);
			else (document.head || document.documentElement).appendChild(document.createElement("style")).append(c);
		})(t);
	};
	_css(" .scroll-to-top[data-v-3ed65821]{cursor:pointer;-webkit-backdrop-filter:blur(6px);z-index:9999;color:#e6edf3;background:#1f2328d9;border:none;border-radius:50%;justify-content:center;align-items:center;width:44px;height:44px;padding:0;transition:background .2s;display:flex;position:fixed;bottom:32px;right:32px;box-shadow:0 2px 8px #0000004d}.scroll-to-top[data-v-3ed65821]:hover{background:#1f2328}.progress-ring[data-v-3ed65821]{position:absolute;top:0;left:0}.progress-ring__bg[data-v-3ed65821]{stroke:#6e768140}.progress-ring__circle[data-v-3ed65821]{stroke:#58a6ff;stroke-linecap:round;transform-origin:22px 22px;transition:stroke-dashoffset 80ms linear;transform:rotate(-90deg)}.arrow[data-v-3ed65821]{z-index:1;position:relative}.fade-enter-active[data-v-3ed65821],.fade-leave-active[data-v-3ed65821]{transition:opacity .25s,transform .25s}.fade-enter-from[data-v-3ed65821],.fade-leave-to[data-v-3ed65821]{opacity:0;transform:scale(.85)}.sp-settings[data-v-d0ee030c]{z-index:9998;position:fixed;bottom:88px;right:32px}.sp-toggle[data-v-d0ee030c]{cursor:pointer;-webkit-backdrop-filter:blur(6px);color:#8b949e;background:#1f2328d9;border:none;border-radius:50%;justify-content:center;align-items:center;width:44px;height:44px;padding:0;transition:background .2s,color .2s;display:flex;box-shadow:0 2px 8px #0000004d}.sp-toggle[data-v-d0ee030c]:hover,.sp-toggle--active[data-v-d0ee030c]{color:#e6edf3;background:#1f2328}.sp-panel[data-v-d0ee030c]{background:#161b22;border:1px solid #30363d;border-radius:12px;width:280px;max-height:calc(100vh - 140px);padding:12px;position:absolute;bottom:56px;right:0;overflow-y:auto;box-shadow:0 8px 24px #0006}.sp-panel-enter-active[data-v-d0ee030c],.sp-panel-leave-active[data-v-d0ee030c]{transition:opacity .15s,transform .15s}.sp-panel-enter-from[data-v-d0ee030c],.sp-panel-leave-to[data-v-d0ee030c]{opacity:0;transform:translateY(4px)scale(.96)}.rss-header[data-v-c1b67dc8]{color:#e6edf3;margin-bottom:10px;font-size:14px;font-weight:600}.rss-section[data-v-c1b67dc8]{margin-bottom:8px}.rss-section[data-v-c1b67dc8]:last-child{margin-bottom:0}.rss-label[data-v-c1b67dc8]{color:#8b949e;text-transform:uppercase;letter-spacing:.5px;margin-bottom:4px;font-size:11px;font-weight:500}.rss-options[data-v-c1b67dc8]{flex-direction:column;gap:1px;display:flex}.rss-option[data-v-c1b67dc8]{cursor:pointer;color:#c9d1d9;border-radius:6px;align-items:center;gap:8px;padding:4px 8px;font-size:13px;transition:background .15s;display:flex}.rss-option[data-v-c1b67dc8]:hover{background:#b1bac414}.rss-option--active[data-v-c1b67dc8]{color:#58a6ff;background:#58a6ff1f}.rss-option input[data-v-c1b67dc8]{accent-color:#58a6ff;margin:0}.rss-option__label[data-v-c1b67dc8]{flex:1}.rss-option__hint[data-v-c1b67dc8]{color:#8b949e;font-size:11px}.rss-keywords[data-v-c1b67dc8]{flex-wrap:wrap;gap:4px;display:flex}.rss-keyword[data-v-c1b67dc8]{color:#8b949e;background:#6e768126;border-radius:4px;padding:1px 5px;font-family:ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,monospace;font-size:11px}\n/*$vite$:1*/ ");
	_css("#app{all:unset}.better-gh-matched{background-color:#58a6ff14!important;border-left:3px solid #58a6ff!important}");
	var _hoisted_1$2 = {
		class: "progress-ring",
		width: "44",
		height: "44"
	};
	var _hoisted_2$1 = ["stroke-dashoffset"];
	var ScrollToTopButton_vue_vue_type_script_setup_true_lang_default = (0, vue.defineComponent)({
		__name: "ScrollToTopButton",
		setup(__props) {
			const scrollTop = (0, vue.ref)(0);
			const scrollHeight = (0, vue.ref)(0);
			const clientHeight = (0, vue.ref)(0);
			const visible = (0, vue.computed)(() => scrollTop.value > 100);
			const progress = (0, vue.computed)(() => {
				if (scrollHeight.value <= clientHeight.value) return 0;
				return scrollTop.value / (scrollHeight.value - clientHeight.value) * 100;
			});
			const circumference = 2 * Math.PI * 18;
			const strokeDashoffset = (0, vue.computed)(() => {
				return circumference - progress.value / 100 * circumference;
			});
			function onScroll() {
				scrollTop.value = document.documentElement.scrollTop;
				scrollHeight.value = document.documentElement.scrollHeight;
				clientHeight.value = document.documentElement.clientHeight;
			}
			function scrollToTop() {
				window.scrollTo({
					top: 0,
					behavior: "smooth"
				});
			}
			(0, vue.onMounted)(() => {
				onScroll();
				window.addEventListener("scroll", onScroll, { passive: true });
			});
			(0, vue.onUnmounted)(() => {
				window.removeEventListener("scroll", onScroll);
			});
			return (_ctx, _cache) => {
				return (0, vue.openBlock)(), (0, vue.createBlock)(vue.Transition, { name: "fade" }, {
					default: (0, vue.withCtx)(() => [(0, vue.withDirectives)((0, vue.createElementVNode)("button", {
						class: "scroll-to-top",
						"aria-label": "Scroll to top",
						onClick: scrollToTop
					}, [((0, vue.openBlock)(), (0, vue.createElementBlock)("svg", _hoisted_1$2, [_cache[0] || (_cache[0] = (0, vue.createElementVNode)("circle", {
						class: "progress-ring__bg",
						"stroke-width": "2.5",
						fill: "transparent",
						r: "18",
						cx: "22",
						cy: "22"
					}, null, -1)), (0, vue.createElementVNode)("circle", {
						class: "progress-ring__circle",
						"stroke-width": "2.5",
						fill: "transparent",
						r: "18",
						cx: "22",
						cy: "22",
						"stroke-dasharray": circumference,
						"stroke-dashoffset": strokeDashoffset.value
					}, null, 8, _hoisted_2$1)])), _cache[1] || (_cache[1] = (0, vue.createElementVNode)("svg", {
						class: "arrow",
						width: "18",
						height: "18",
						viewBox: "0 0 24 24",
						fill: "none",
						stroke: "currentColor",
						"stroke-width": "2.5",
						"stroke-linecap": "round",
						"stroke-linejoin": "round"
					}, [(0, vue.createElementVNode)("path", { d: "M18 15l-6-6-6 6" })], -1))], 512), [[vue.vShow, visible.value]])]),
					_: 1
				});
			};
		}
	});
	var _plugin_vue_export_helper_default = (sfc, props) => {
		const target = sfc.__vccOpts || sfc;
		for (const [key, val] of props) target[key] = val;
		return target;
	};
	var ScrollToTopButton_default = _plugin_vue_export_helper_default(ScrollToTopButton_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-3ed65821"]]);
	var OS_OPTIONS = [
		"auto",
		"windows",
		"macos",
		"linux",
		"android",
		"ios"
	];
	var OS_LABELS = {
		auto: "Auto",
		windows: "Windows",
		macos: "macOS",
		linux: "Linux",
		android: "Android",
		ios: "iOS"
	};
	var SYSTEM_KEYWORDS = {
		windows: ["win", "windows"],
		macos: ["mac", "macos"],
		linux: ["linux"],
		android: ["android"],
		ios: ["ios"]
	};
	var ARCH_OPTIONS = [
		"auto",
		"x64",
		"x86",
		"arm64",
		"arm",
		"universal"
	];
	var ARCH_LABELS = {
		auto: "Auto",
		x64: "x64",
		x86: "x86",
		arm64: "arm64",
		arm: "arm",
		universal: "Universal"
	};
	var ARCH_KEYWORDS = {
		x64: [
			"x64",
			"x86_64",
			"amd64"
		],
		x86: [
			"x86",
			"i386",
			"i686"
		],
		arm64: [
			"arm64",
			"aarch64",
			"arm64-v8a"
		],
		arm: [
			"arm",
			"armeabi-v7a",
			"armv7"
		],
		universal: ["universal"]
	};
	var PKG_OPTIONS = [
		"all",
		"installer",
		"portable"
	];
	var PKG_LABELS = {
		all: "All",
		installer: "Installer",
		portable: "Portable"
	};
	var PKG_KEYWORDS = {
		installer: {
			windows: [
				"exe",
				"msi",
				"msix"
			],
			macos: ["dmg", "pkg"],
			linux: ["deb", "rpm"],
			android: ["apk"],
			ios: ["ipa"]
		},
		portable: {
			windows: ["zip", "portable"],
			macos: ["zip", "appimage"],
			linux: ["zip", "appimage"],
			android: [],
			ios: []
		}
	};
	var OS_STORAGE_KEY = "better-gh:release-os";
	var ARCH_STORAGE_KEY = "better-gh:release-arch";
	var PKG_STORAGE_KEY = "better-gh:release-pkg";
	var RELEASE_PAGE_RE = /^\/[^/]+\/[^/]+\/releases(\/|$)/;
	var SOURCE_CODE_RE = /\.(tar\.gz|tar\.bz2|zip)$/i;
	var SOURCE_CODE_PATH_RE = /\/archive\//;
	function detectPlatform() {
		const ua = navigator.userAgent.toLowerCase();
		const platform = navigator.platform.toLowerCase();
		if (/android/.test(ua)) return "android";
		if (/iphone|ipad|ipod/.test(ua)) return "ios";
		if (/win/.test(platform) || /win/.test(ua)) return "windows";
		if (/mac/.test(platform) || /mac/.test(ua)) return "macos";
		if (/linux/.test(platform) || /linux/.test(ua)) return "linux";
		return "windows";
	}
	function getSelectedOs() {
		const saved = GM_getValue(OS_STORAGE_KEY, "auto");
		if (OS_OPTIONS.includes(saved)) return saved;
		return "auto";
	}
	function setSelectedOs(os) {
		GM_setValue(OS_STORAGE_KEY, os);
	}
	function detectArch() {
		const ua = navigator.userAgent.toLowerCase();
		if (/arm64|aarch64/.test(ua)) return "arm64";
		if (/arm/.test(ua)) return "arm";
		if (/x86/.test(ua) || /i386|i686/.test(ua)) return "x86";
		return "x64";
	}
	function getSelectedArch() {
		const saved = GM_getValue(ARCH_STORAGE_KEY, "auto");
		if (ARCH_OPTIONS.includes(saved)) return saved;
		return "auto";
	}
	function setSelectedArch(arch) {
		GM_setValue(ARCH_STORAGE_KEY, arch);
	}
	function getSelectedPkg() {
		const saved = GM_getValue(PKG_STORAGE_KEY, "all");
		if (PKG_OPTIONS.includes(saved)) return saved;
		return "all";
	}
	function setSelectedPkg(pkg) {
		GM_setValue(PKG_STORAGE_KEY, pkg);
	}
	function buildMatchKeywords() {
		const os = getSelectedOs();
		const arch = getSelectedArch();
		const pkg = getSelectedPkg();
		const resolvedOs = os === "auto" ? detectPlatform() : os;
		const keywords = new Set(SYSTEM_KEYWORDS[resolvedOs]);
		const resolvedArch = arch === "auto" ? detectArch() : arch;
		for (const kw of ARCH_KEYWORDS[resolvedArch]) keywords.add(kw);
		const pkgKws = PKG_KEYWORDS[pkg === "all" ? "installer" : pkg][resolvedOs];
		for (const kw of pkgKws) keywords.add(kw);
		if (pkg === "all") for (const kw of PKG_KEYWORDS.portable[resolvedOs]) keywords.add(kw);
		return keywords;
	}
	function getKeywordsPreview(os, arch, pkg) {
		const resolvedOs = os === "auto" ? detectPlatform() : os;
		const resolvedArch = arch === "auto" ? detectArch() : arch;
		const result = [...SYSTEM_KEYWORDS[resolvedOs], ...ARCH_KEYWORDS[resolvedArch]];
		result.push(...PKG_KEYWORDS.installer[resolvedOs]);
		if (pkg === "all") result.push(...PKG_KEYWORDS.portable[resolvedOs]);
		else result.push(...PKG_KEYWORDS[pkg][resolvedOs]);
		return result;
	}
	function isReleasePage() {
		return RELEASE_PAGE_RE.test(window.location.pathname);
	}
	function extractFilename(anchor) {
		const href = anchor.getAttribute("href");
		if (!href) return null;
		if (SOURCE_CODE_PATH_RE.test(href)) return null;
		const lastSegment = href.split("/").pop();
		if (!lastSegment) return null;
		const decoded = decodeURIComponent(lastSegment);
		if (SOURCE_CODE_RE.test(decoded)) return null;
		return decoded.toLowerCase();
	}
	function countMatches(filename, keywords) {
		let count = 0;
		for (const keyword of keywords) if (new RegExp(`(^|[^a-z0-9])${keyword}([^a-z0-9]|$)`).test(filename)) count++;
		return count;
	}
	function sortAndHighlight() {
		const keywords = buildMatchKeywords();
		const links = document.querySelectorAll("a[href*=\"/releases/download/\"]");
		const uls = new Set();
		for (const link of links) {
			const li = link.closest("li");
			if (li) {
				const ul = li.parentElement;
				if (ul instanceof HTMLUListElement) uls.add(ul);
			}
		}
		for (const ul of uls) {
			delete ul.dataset.betterGhSorted;
			const items = Array.from(ul.querySelectorAll(":scope > li"));
			if (items.length === 0) continue;
			const itemsWithScore = items.map((li, originalIndex) => {
				const anchor = li.querySelector("a[href*=\"/releases/download/\"]");
				let score = 0;
				if (anchor) {
					const filename = extractFilename(anchor);
					if (filename) score = countMatches(filename, keywords);
				}
				return {
					element: li,
					score,
					originalIndex
				};
			});
			for (const item of itemsWithScore) item.element.classList.remove("better-gh-matched");
			itemsWithScore.sort((a, b) => b.score - a.score || a.originalIndex - b.originalIndex);
			const maxScore = itemsWithScore[0]?.score ?? 0;
			for (const item of itemsWithScore) {
				ul.appendChild(item.element);
				if (item.score === maxScore && maxScore > 0) item.element.classList.add("better-gh-matched");
			}
			ul.dataset.betterGhSorted = "true";
		}
	}
	function initReleaseSorter() {
		if (isReleasePage()) sortAndHighlight();
		let turboTimeout = null;
		document.addEventListener("turbo:load", () => {
			if (!isReleasePage()) return;
			if (turboTimeout) clearTimeout(turboTimeout);
			turboTimeout = setTimeout(sortAndHighlight, 100);
		});
		let observerTimeout = null;
		new MutationObserver(() => {
			if (!isReleasePage()) return;
			if (observerTimeout) clearTimeout(observerTimeout);
			observerTimeout = setTimeout(sortAndHighlight, 100);
		}).observe(document.body, {
			childList: true,
			subtree: true
		});
	}
	var _hoisted_1$1 = {
		key: 0,
		class: "sp-settings"
	};
	var SettingsPanel_default = _plugin_vue_export_helper_default((0, vue.defineComponent)({
		__name: "SettingsPanel",
		setup(__props) {
			const open = (0, vue.ref)(false);
			const onReleasePage = (0, vue.ref)(isReleasePage());
			let checkInterval;
			(0, vue.onMounted)(() => {
				checkInterval = setInterval(() => {
					onReleasePage.value = isReleasePage();
				}, 1e3);
			});
			(0, vue.onUnmounted)(() => {
				clearInterval(checkInterval);
			});
			return (_ctx, _cache) => {
				return onReleasePage.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_1$1, [(0, vue.createVNode)(vue.Transition, { name: "sp-panel" }, {
					default: (0, vue.withCtx)(() => [open.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
						key: 0,
						class: "sp-panel",
						onWheel: _cache[0] || (_cache[0] = (0, vue.withModifiers)(() => {}, ["stop"]))
					}, [(0, vue.renderSlot)(_ctx.$slots, "default", {}, void 0, true)], 32)) : (0, vue.createCommentVNode)("", true)]),
					_: 3
				}), (0, vue.createElementVNode)("button", {
					class: (0, vue.normalizeClass)(["sp-toggle", { "sp-toggle--active": open.value }]),
					"aria-label": "Settings",
					onClick: _cache[1] || (_cache[1] = ($event) => open.value = !open.value)
				}, [..._cache[2] || (_cache[2] = [(0, vue.createElementVNode)("svg", {
					width: "18",
					height: "18",
					viewBox: "0 0 24 24",
					fill: "none",
					stroke: "currentColor",
					"stroke-width": "2",
					"stroke-linecap": "round",
					"stroke-linejoin": "round"
				}, [(0, vue.createElementVNode)("circle", {
					cx: "12",
					cy: "12",
					r: "3"
				}), (0, vue.createElementVNode)("path", { d: "M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z" })], -1)])], 2)])) : (0, vue.createCommentVNode)("", true);
			};
		}
	}), [["__scopeId", "data-v-d0ee030c"]]);
	var _hoisted_1 = { class: "rss-section" };
	var _hoisted_2 = { class: "rss-options" };
	var _hoisted_3 = [
		"value",
		"checked",
		"onChange"
	];
	var _hoisted_4 = { class: "rss-option__label" };
	var _hoisted_5 = {
		key: 0,
		class: "rss-option__hint"
	};
	var _hoisted_6 = { class: "rss-section" };
	var _hoisted_7 = { class: "rss-options" };
	var _hoisted_8 = [
		"value",
		"checked",
		"onChange"
	];
	var _hoisted_9 = { class: "rss-option__label" };
	var _hoisted_10 = {
		key: 0,
		class: "rss-option__hint"
	};
	var _hoisted_11 = { class: "rss-section" };
	var _hoisted_12 = { class: "rss-options" };
	var _hoisted_13 = [
		"value",
		"checked",
		"onChange"
	];
	var _hoisted_14 = { class: "rss-option__label" };
	var _hoisted_15 = { class: "rss-section" };
	var _hoisted_16 = { class: "rss-label" };
	var _hoisted_17 = { class: "rss-keywords" };
	var ReleaseSorterSettings_default = _plugin_vue_export_helper_default((0, vue.defineComponent)({
		__name: "ReleaseSorterSettings",
		setup(__props) {
			const selectedOs = (0, vue.ref)(getSelectedOs());
			const selectedArch = (0, vue.ref)(getSelectedArch());
			const selectedPkg = (0, vue.ref)(getSelectedPkg());
			const resolvedPlatform = (0, vue.computed)(() => {
				return selectedOs.value === "auto" ? detectPlatform() : selectedOs.value;
			});
			const resolvedArch = (0, vue.computed)(() => {
				return selectedArch.value === "auto" ? detectArch() : selectedArch.value;
			});
			const keywords = (0, vue.computed)(() => {
				return getKeywordsPreview(selectedOs.value, selectedArch.value, selectedPkg.value);
			});
			function selectOs(os) {
				selectedOs.value = os;
				setSelectedOs(os);
				sortAndHighlight();
			}
			function selectArch(arch) {
				selectedArch.value = arch;
				setSelectedArch(arch);
				sortAndHighlight();
			}
			function selectPkg(pkg) {
				selectedPkg.value = pkg;
				setSelectedPkg(pkg);
				sortAndHighlight();
			}
			return (_ctx, _cache) => {
				return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, [
					_cache[3] || (_cache[3] = (0, vue.createElementVNode)("div", { class: "rss-header" }, "Release Sorter", -1)),
					(0, vue.createElementVNode)("div", _hoisted_1, [_cache[0] || (_cache[0] = (0, vue.createElementVNode)("div", { class: "rss-label" }, "System", -1)), (0, vue.createElementVNode)("div", _hoisted_2, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)((0, vue.unref)(OS_OPTIONS), (os) => {
						return (0, vue.openBlock)(), (0, vue.createElementBlock)("label", {
							key: os,
							class: (0, vue.normalizeClass)(["rss-option", { "rss-option--active": selectedOs.value === os }])
						}, [
							(0, vue.createElementVNode)("input", {
								type: "radio",
								value: os,
								checked: selectedOs.value === os,
								onChange: ($event) => selectOs(os)
							}, null, 40, _hoisted_3),
							(0, vue.createElementVNode)("span", _hoisted_4, (0, vue.toDisplayString)((0, vue.unref)(OS_LABELS)[os]), 1),
							os === "auto" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_5, "(" + (0, vue.toDisplayString)((0, vue.unref)(OS_LABELS)[(0, vue.unref)(detectPlatform)()]) + ")", 1)) : (0, vue.createCommentVNode)("", true)
						], 2);
					}), 128))])]),
					(0, vue.createElementVNode)("div", _hoisted_6, [_cache[1] || (_cache[1] = (0, vue.createElementVNode)("div", { class: "rss-label" }, "Architecture", -1)), (0, vue.createElementVNode)("div", _hoisted_7, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)((0, vue.unref)(ARCH_OPTIONS), (arch) => {
						return (0, vue.openBlock)(), (0, vue.createElementBlock)("label", {
							key: arch,
							class: (0, vue.normalizeClass)(["rss-option", { "rss-option--active": selectedArch.value === arch }])
						}, [
							(0, vue.createElementVNode)("input", {
								type: "radio",
								value: arch,
								checked: selectedArch.value === arch,
								onChange: ($event) => selectArch(arch)
							}, null, 40, _hoisted_8),
							(0, vue.createElementVNode)("span", _hoisted_9, (0, vue.toDisplayString)((0, vue.unref)(ARCH_LABELS)[arch]), 1),
							arch === "auto" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("span", _hoisted_10, "(" + (0, vue.toDisplayString)((0, vue.unref)(ARCH_LABELS)[(0, vue.unref)(detectArch)()]) + ")", 1)) : (0, vue.createCommentVNode)("", true)
						], 2);
					}), 128))])]),
					(0, vue.createElementVNode)("div", _hoisted_11, [_cache[2] || (_cache[2] = (0, vue.createElementVNode)("div", { class: "rss-label" }, "Package Type", -1)), (0, vue.createElementVNode)("div", _hoisted_12, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)((0, vue.unref)(PKG_OPTIONS), (pkg) => {
						return (0, vue.openBlock)(), (0, vue.createElementBlock)("label", {
							key: pkg,
							class: (0, vue.normalizeClass)(["rss-option", { "rss-option--active": selectedPkg.value === pkg }])
						}, [(0, vue.createElementVNode)("input", {
							type: "radio",
							value: pkg,
							checked: selectedPkg.value === pkg,
							onChange: ($event) => selectPkg(pkg)
						}, null, 40, _hoisted_13), (0, vue.createElementVNode)("span", _hoisted_14, (0, vue.toDisplayString)((0, vue.unref)(PKG_LABELS)[pkg]), 1)], 2);
					}), 128))])]),
					(0, vue.createElementVNode)("div", _hoisted_15, [(0, vue.createElementVNode)("div", _hoisted_16, " Keywords (" + (0, vue.toDisplayString)((0, vue.unref)(OS_LABELS)[resolvedPlatform.value]) + " · " + (0, vue.toDisplayString)((0, vue.unref)(ARCH_LABELS)[resolvedArch.value]) + " · " + (0, vue.toDisplayString)((0, vue.unref)(PKG_LABELS)[selectedPkg.value]) + ") ", 1), (0, vue.createElementVNode)("div", _hoisted_17, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(keywords.value, (kw) => {
						return (0, vue.openBlock)(), (0, vue.createElementBlock)("span", {
							key: kw,
							class: "rss-keyword"
						}, (0, vue.toDisplayString)(kw), 1);
					}), 128))])])
				], 64);
			};
		}
	}), [["__scopeId", "data-v-c1b67dc8"]]);
	var App_default = (0, vue.defineComponent)({
		__name: "App",
		setup(__props) {
			return (_ctx, _cache) => {
				return (0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, [(0, vue.createVNode)(ScrollToTopButton_default), (0, vue.createVNode)(SettingsPanel_default, null, {
					default: (0, vue.withCtx)(() => [(0, vue.createVNode)(ReleaseSorterSettings_default)]),
					_: 1
				})], 64);
			};
		}
	});
	initReleaseSorter();
	(0, vue.createApp)(App_default).mount((() => {
		const app = document.createElement("div");
		document.body.append(app);
		return app;
	})());
})(Vue);