Better Github

一个提升 GitHub 浏览体验的用户脚本

2026-05-09 기준 버전입니다. 최신 버전을 확인하세요.

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

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

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

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

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         Better Github
// @namespace    npm/vite-plugin-monkey
// @version      1.0.3
// @author       ChouChiu
// @description  一个提升 GitHub 浏览体验的用户脚本
// @license      GPL-3.0-or-later
// @icon         https://github.com/favicon.ico
// @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-664d618c]{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-664d618c]:hover{background:#1f2328}.progress-ring[data-v-664d618c]{position:absolute;top:0;left:0}.progress-ring__bg[data-v-664d618c]{stroke:#6e768140}.progress-ring__circle[data-v-664d618c]{stroke:#58a6ff;stroke-linecap:round;transform-origin:22px 22px;transition:stroke-dashoffset 80ms linear;transform:rotate(-90deg)}.arrow[data-v-664d618c]{z-index:1;position:relative}.fade-enter-active[data-v-664d618c],.fade-leave-active[data-v-664d618c]{transition:opacity .25s,transform .25s}.fade-enter-from[data-v-664d618c],.fade-leave-to[data-v-664d618c]{opacity:0;transform:scale(.85)}.sp-settings[data-v-0b3a6176]{z-index:9998;position:fixed;bottom:88px;right:32px}.sp-toggle[data-v-0b3a6176]{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-0b3a6176]:hover,.sp-toggle--active[data-v-0b3a6176]{color:#e6edf3;background:#1f2328}.sp-panel[data-v-0b3a6176]{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-0b3a6176],.sp-panel-leave-active[data-v-0b3a6176]{transition:opacity .15s,transform .15s}.sp-panel-enter-from[data-v-0b3a6176],.sp-panel-leave-to[data-v-0b3a6176]{opacity:0;transform:translateY(4px)scale(.96)}.rss-header[data-v-6943b166]{color:#e6edf3;margin-bottom:10px;font-size:14px;font-weight:600}.rss-section[data-v-6943b166]{margin-bottom:8px}.rss-section[data-v-6943b166]:last-child{margin-bottom:0}.rss-label[data-v-6943b166]{color:#8b949e;text-transform:uppercase;letter-spacing:.5px;margin-bottom:4px;font-size:11px;font-weight:500}.rss-options[data-v-6943b166]{flex-direction:column;gap:1px;display:flex}.rss-option[data-v-6943b166]{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-6943b166]:hover{background:#b1bac414}.rss-option--active[data-v-6943b166]{color:#58a6ff;background:#58a6ff1f}.rss-option input[data-v-6943b166]{accent-color:#58a6ff;margin:0}.rss-option__label[data-v-6943b166]{flex:1}.rss-option__hint[data-v-6943b166]{color:#8b949e;font-size:11px}.rss-keywords[data-v-6943b166]{flex-wrap:wrap;gap:4px;display:flex}.rss-keyword[data-v-6943b166]{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{font:inherit;color:inherit;background:0 0;border:none;margin:0;padding:0;display:contents;position:static}.better-gh-matched{background-color:#58a6ff14!important;border-left:3px solid #58a6ff!important}");
	var _hoisted_1$1 = {
		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 CIRCUMFERENCE = 2 * Math.PI * 18;
			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 strokeDashoffset = (0, vue.computed)(() => {
				return CIRCUMFERENCE - progress.value / 100 * CIRCUMFERENCE;
			});
			let ticking = false;
			function onScroll() {
				if (ticking) return;
				ticking = true;
				requestAnimationFrame(() => {
					scrollTop.value = document.documentElement.scrollTop;
					scrollHeight.value = document.documentElement.scrollHeight;
					clientHeight.value = document.documentElement.clientHeight;
					ticking = false;
				});
			}
			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$1, [_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-664d618c"]]);
	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",
				"setup"
			],
			macos: [
				"dmg",
				"pkg",
				"setup"
			],
			linux: [
				"deb",
				"rpm",
				"setup"
			],
			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(?!_64)/.test(ua) || /i386|i686/.test(ua)) return "x86";
		return "x64";
	}
	function resolveOs(os) {
		return os === "auto" ? detectPlatform() : os;
	}
	function resolveArch(arch) {
		return arch === "auto" ? detectArch() : arch;
	}
	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);
	}
	var keywordCache = null;
	var keywordCacheKey = "";
	var regexCache = new Map();
	function buildMatchKeywords() {
		const os = getSelectedOs();
		const arch = getSelectedArch();
		const pkg = getSelectedPkg();
		const cacheKey = `${os}:${arch}:${pkg}`;
		if (keywordCache && keywordCacheKey === cacheKey) return keywordCache;
		const resolvedOs = resolveOs(os);
		const keywords = new Set(SYSTEM_KEYWORDS[resolvedOs]);
		const resolvedArch = resolveArch(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);
		keywordCache = keywords;
		keywordCacheKey = cacheKey;
		return keywords;
	}
	function getKeywordsPreview(os, arch, pkg) {
		const resolvedOs = resolveOs(os);
		const resolvedArch = resolveArch(arch);
		const result = [
			...SYSTEM_KEYWORDS[resolvedOs],
			...ARCH_KEYWORDS[resolvedArch],
			...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) {
			let re = regexCache.get(keyword);
			if (!re) {
				re = new RegExp(`(^|[^a-z0-9])${keyword}([^a-z0-9]|$)`);
				regexCache.set(keyword, re);
			}
			if (re.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 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());
			const settingsRef = (0, vue.ref)();
			function checkPage() {
				onReleasePage.value = isReleasePage();
			}
			function onClickOutside(e) {
				if (open.value && settingsRef.value && !settingsRef.value.contains(e.target)) open.value = false;
			}
			(0, vue.onMounted)(() => {
				document.addEventListener("turbo:load", checkPage);
				window.addEventListener("popstate", checkPage);
				document.addEventListener("click", onClickOutside);
			});
			(0, vue.onUnmounted)(() => {
				document.removeEventListener("turbo:load", checkPage);
				window.removeEventListener("popstate", checkPage);
				document.removeEventListener("click", onClickOutside);
			});
			return (_ctx, _cache) => {
				return onReleasePage.value ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", {
					key: 0,
					ref_key: "settingsRef",
					ref: settingsRef,
					class: "sp-settings"
				}, [(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)], 512)) : (0, vue.createCommentVNode)("", true);
			};
		}
	}), [["__scopeId", "data-v-0b3a6176"]]);
	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-6943b166"]]);
	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();
	var app = document.createElement("div");
	document.body.append(app);
	(0, vue.createApp)(App_default).mount(app);
})(Vue);