Better GitHub Navigation

Supports adding commonly used sections such as Dashboard, Explore, Trending, Collections, and Stars to the navigation bar for one-click access. Allows customization of visibility and order. Supports dark mode and narrow-screen layouts. Also includes a “GitHub Top Repositories” feature for pinning repositories, making frequently used repositories easy to access.

Устаревшая версия за 14.03.2026. Перейдите к последней версии.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey, Greasemonkey или Violentmonkey.

Для установки этого скрипта вам необходимо установить расширение, такое как Tampermonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Violentmonkey.

Чтобы установить этот скрипт, вы сначала должны установить расширение браузера, например Tampermonkey или Userscripts.

Чтобы установить этот скрипт, сначала вы должны установить расширение браузера, например Tampermonkey.

Чтобы установить этот скрипт, вы должны установить расширение — менеджер скриптов.

(у меня уже есть менеджер скриптов, дайте мне установить скрипт!)

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение браузера, например Stylus.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

Чтобы установить этот стиль, сначала вы должны установить расширение — менеджер стилей.

(у меня уже есть менеджер стилей, дайте мне установить скрипт!)

// ==UserScript==
// @name         Better GitHub Navigation
// @name:zh-CN   更好的 GitHub 导航栏
// @namespace    https://github.com/ImXiangYu/better-github-nav
// @version      0.1.50
// @description  Supports adding commonly used sections such as Dashboard, Explore, Trending, Collections, and Stars to the navigation bar for one-click access. Allows customization of visibility and order. Supports dark mode and narrow-screen layouts. Also includes a “GitHub Top Repositories” feature for pinning repositories, making frequently used repositories easy to access.
// @description:zh-CN 支持将 DashBoard、Explore、Trending、Collections、Stars 等常用入口放入导航栏中一键直达。支持自定义是否显示,自定义顺序。支持深色模式、窄屏场景。同时加入了 Github Top repositories 显示仓库置顶功能,常用仓库一键置顶,方便查看。
// @author       Ayubass
// @license      MIT
// @match        https://github.com/*
// @icon         https://github.githubassets.com/pinned-octocat.svg
// @grant        GM_registerMenuCommand
// ==/UserScript==

(() => {
  // src/constants.js
  var SCRIPT_VERSION = "0.1.50";
  var CUSTOM_BUTTON_CLASS = "custom-gh-nav-btn";
  var CUSTOM_BUTTON_ACTIVE_CLASS = "custom-gh-nav-btn-active";
  var CUSTOM_BUTTON_COMPACT_CLASS = "custom-gh-nav-btn-compact";
  var QUICK_LINK_MARK_ATTR = "data-better-gh-nav-quick-link";
  var QUICK_LINK_HOST_MARK_ATTR = "data-better-gh-nav-quick-link-host";
  var QUICK_LINK_LAST_MARK_ATTR = "data-better-gh-nav-quick-link-last";
  var RESPONSIVE_TOGGLE_MARK_ATTR = "data-better-gh-nav-overflow-toggle";
  var CONFIG_STORAGE_KEY = "better-gh-nav-config-v1";
  var TOP_REPOSITORIES_PIN_STORAGE_KEY = "better-gh-nav-top-repositories-pins-v1";
  var UI_LANG_STORAGE_KEY = "better-gh-nav-ui-lang-v1";
  var THEME_ATTR = "data-better-github-nav-theme";
  var THEME_SOURCE_ATTR = "data-better-github-nav-theme-source";
  var SETTINGS_OVERLAY_ID = "custom-gh-nav-settings-overlay";
  var SETTINGS_PANEL_ID = "custom-gh-nav-settings-panel";
  var SETTINGS_MESSAGE_ID = "custom-gh-nav-settings-message";
  var DEFAULT_LINK_KEYS = ["dashboard", "explore", "trending", "collections", "stars"];
  var PRESET_LINKS = [
    { key: "dashboard", text: "Dashboard", path: "/dashboard", getHref: () => "/dashboard" },
    { key: "explore", text: "Explore", path: "/explore", getHref: () => "/explore" },
    { key: "trending", text: "Trending", path: "/trending", getHref: () => "/trending" },
    { key: "collections", text: "Collections", path: "/collections", getHref: () => "/collections" },
    { key: "stars", text: "Stars", path: "/stars", getHref: (username) => username ? `/${username}?tab=stars` : "/stars" }
  ];
  var PRESET_LINK_SHORTCUTS = {
    dashboard: "g d",
    explore: "g e",
    trending: "g t",
    collections: "g c",
    stars: "g s"
  };
  var I18N = {
    zh: {
      menuOpenSettings: "Better GitHub Nav: 打开设置面板",
      menuResetSettings: "Better GitHub Nav: 重置快捷链接配置",
      menuLangZh: "Better GitHub Nav: 界面语言 -> 中文",
      menuLangEn: "Better GitHub Nav: 界面语言 -> English",
      menuLangAuto: "Better GitHub Nav: 界面语言 -> 自动(跟随页面)",
      menuThemeLight: "Better GitHub Nav: 主题 -> 亮色",
      menuThemeDark: "Better GitHub Nav: 主题 -> 暗色",
      menuThemeAuto: "Better GitHub Nav: 主题 -> 自动(跟随 GitHub)",
      resetConfirm: "确认重置快捷链接配置为默认值吗?",
      panelTitle: "Better GitHub Nav 设置",
      panelDesc: "勾选决定显示项,拖动整行(或右侧手柄)调整显示顺序。",
      resetDefault: "恢复默认",
      cancel: "取消",
      saveAndRefresh: "保存并刷新",
      restoredPendingSave: "已恢复默认,点击保存后生效。",
      atLeastOneLink: "至少保留 1 个快捷链接。",
      openQuickLinksMenu: "展开快捷链接",
      closeQuickLinksMenu: "收起快捷链接",
      quickLinksMenu: "快捷链接",
      dragHandleTitle: "拖动调整顺序",
      dragRowTitle: "拖动整行调整顺序",
      pinTopRepository: "置顶仓库:{repo}",
      unpinTopRepository: "取消置顶仓库:{repo}"
    },
    en: {
      menuOpenSettings: "Better GitHub Nav: Open Settings Panel",
      menuResetSettings: "Better GitHub Nav: Reset Quick Link Config",
      menuLangZh: "Better GitHub Nav: UI Language -> 中文",
      menuLangEn: "Better GitHub Nav: UI Language -> English",
      menuLangAuto: "Better GitHub Nav: UI Language -> Auto (Follow Page)",
      menuThemeLight: "Better GitHub Nav: Theme -> Light",
      menuThemeDark: "Better GitHub Nav: Theme -> Dark",
      menuThemeAuto: "Better GitHub Nav: Theme -> Auto (Follow GitHub)",
      resetConfirm: "Reset quick-link config to defaults?",
      panelTitle: "Better GitHub Nav Settings",
      panelDesc: "Select visible links and drag the row (or handle) to reorder.",
      resetDefault: "Reset to Default",
      cancel: "Cancel",
      saveAndRefresh: "Save and Refresh",
      restoredPendingSave: "Defaults restored. Click save to apply.",
      atLeastOneLink: "Keep at least 1 quick link.",
      openQuickLinksMenu: "Show quick links",
      closeQuickLinksMenu: "Hide quick links",
      quickLinksMenu: "Quick links",
      dragHandleTitle: "Drag to reorder",
      dragRowTitle: "Drag row to reorder",
      pinTopRepository: "Pin repository: {repo}",
      unpinTopRepository: "Unpin repository: {repo}"
    }
  };

  // src/config.js
  function sanitizeThemePreference(themePreference) {
    return themePreference === "light" || themePreference === "dark" ? themePreference : "auto";
  }
  function sanitizeKeys(keys) {
    const validSet = new Set(DEFAULT_LINK_KEYS);
    const seen = /* @__PURE__ */ new Set();
    const result = [];
    keys.forEach((key) => {
      if (validSet.has(key) && !seen.has(key)) {
        seen.add(key);
        result.push(key);
      }
    });
    return result;
  }
  function sanitizeConfig(rawConfig) {
    const enabledKeys = sanitizeKeys(Array.isArray(rawConfig?.enabledKeys) ? rawConfig.enabledKeys : DEFAULT_LINK_KEYS);
    const orderKeysRaw = sanitizeKeys(Array.isArray(rawConfig?.orderKeys) ? rawConfig.orderKeys : DEFAULT_LINK_KEYS);
    const orderSet = new Set(orderKeysRaw);
    const orderKeys = [
      ...orderKeysRaw,
      ...DEFAULT_LINK_KEYS.filter((key) => !orderSet.has(key))
    ];
    const themePreference = sanitizeThemePreference(rawConfig?.themePreference);
    return {
      enabledKeys: enabledKeys.length ? enabledKeys : DEFAULT_LINK_KEYS.slice(),
      orderKeys: orderKeys.length ? orderKeys : DEFAULT_LINK_KEYS.slice(),
      themePreference
    };
  }
  function loadConfig() {
    try {
      const raw = localStorage.getItem(CONFIG_STORAGE_KEY);
      if (!raw) return sanitizeConfig({});
      return sanitizeConfig(JSON.parse(raw));
    } catch (e) {
      return sanitizeConfig({});
    }
  }
  function saveConfig(config) {
    localStorage.setItem(CONFIG_STORAGE_KEY, JSON.stringify(sanitizeConfig(config)));
  }
  function updateConfig(partialConfig) {
    const currentConfig = loadConfig();
    saveConfig({
      ...currentConfig,
      ...partialConfig
    });
  }
  function getConfiguredLinks(username) {
    const config = loadConfig();
    const presetMap = new Map(
      PRESET_LINKS.map((link) => [link.key, {
        ...link,
        id: `custom-gh-btn-${link.key}`,
        href: link.getHref(username)
      }])
    );
    return config.orderKeys.filter((key) => config.enabledKeys.includes(key)).map((key) => presetMap.get(key)).filter(Boolean);
  }
  function getDisplayNameByKey(key) {
    const link = PRESET_LINKS.find((item) => item.key === key);
    return link ? link.text : key;
  }

  // src/i18n.js
  var uiLang = detectUiLang();
  function t(key, vars = {}) {
    const dict = I18N[uiLang] || I18N.en;
    const fallback = I18N.en;
    const template = dict[key] || fallback[key] || key;
    return template.replace(/\{(\w+)\}/g, (_, varName) => String(vars[varName] ?? ""));
  }
  function detectUiLang() {
    try {
      const preferredLang = (localStorage.getItem(UI_LANG_STORAGE_KEY) || "").toLowerCase();
      if (preferredLang === "zh" || preferredLang === "en") return preferredLang;
    } catch (e) {
    }
    const autoLang = (document.documentElement.lang || navigator.language || "").toLowerCase();
    return autoLang.startsWith("zh") ? "zh" : "en";
  }
  function setUiLangPreference(lang) {
    try {
      if (lang === "zh" || lang === "en") {
        localStorage.setItem(UI_LANG_STORAGE_KEY, lang);
      } else {
        localStorage.removeItem(UI_LANG_STORAGE_KEY);
      }
    } catch (e) {
    }
    uiLang = detectUiLang();
  }

  // src/styles.js
  function ensureStyles() {
    if (document.getElementById("custom-gh-nav-style")) return;
    const style = document.createElement("style");
    style.id = "custom-gh-nav-style";
    style.textContent = `
        :root {
            --bgn-color-scheme: light;
            --bgn-fg-default: #1f2328;
            --bgn-fg-muted: #656d76;
            --bgn-fg-on-emphasis: #ffffff;
            --bgn-border-default: #d1d9e0;
            --bgn-border-muted: #d8dee4;
            --bgn-surface-default: #ffffff;
            --bgn-surface-subtle: #f6f8fa;
            --bgn-surface-hover: rgba(177, 186, 196, 0.12);
            --bgn-surface-active: rgba(177, 186, 196, 0.18);
            --bgn-accent-fg: #0969da;
            --bgn-accent-subtle: rgba(9, 105, 218, 0.08);
            --bgn-btn-bg: #f6f8fa;
            --bgn-btn-hover-bg: #f3f4f6;
            --bgn-btn-primary-bg: #1f883d;
            --bgn-btn-primary-hover-bg: #1a7f37;
            --bgn-btn-primary-text: #ffffff;
            --bgn-attention-fg: #9a6700;
            --bgn-tooltip-bg: #1f2328;
            --bgn-tooltip-kbd-bg: rgba(110, 118, 129, 0.4);
            --bgn-overlay-backdrop: rgba(0, 0, 0, 0.45);
            --bgn-shadow-medium: 0 8px 24px rgba(0, 0, 0, 0.2);
            --bgn-shadow-large: 0 16px 32px rgba(0, 0, 0, 0.16);
            --bgn-shadow-panel: 0 16px 40px rgba(0, 0, 0, 0.25);
        }
        :root[${THEME_SOURCE_ATTR}="auto"][${THEME_ATTR}="light"] {
            --bgn-color-scheme: light;
            --bgn-fg-default: var(--color-fg-default, #1f2328);
            --bgn-fg-muted: var(--color-fg-muted, #656d76);
            --bgn-fg-on-emphasis: var(--color-fg-on-emphasis, #ffffff);
            --bgn-border-default: var(--color-border-default, #d1d9e0);
            --bgn-border-muted: var(--color-border-muted, #d8dee4);
            --bgn-surface-default: var(--color-canvas-default, #ffffff);
            --bgn-surface-subtle: var(--color-canvas-subtle, #f6f8fa);
            --bgn-surface-hover: var(--color-neutral-muted, rgba(177, 186, 196, 0.12));
            --bgn-surface-active: var(--color-neutral-muted, rgba(177, 186, 196, 0.18));
            --bgn-accent-fg: var(--color-accent-fg, #0969da);
            --bgn-accent-subtle: var(--color-accent-subtle, rgba(9, 105, 218, 0.08));
            --bgn-btn-bg: var(--color-btn-bg, #f6f8fa);
            --bgn-btn-hover-bg: var(--color-btn-hover-bg, #f3f4f6);
            --bgn-btn-primary-bg: var(--color-btn-primary-bg, #1f883d);
            --bgn-btn-primary-hover-bg: var(--color-btn-primary-hover-bg, #1a7f37);
            --bgn-btn-primary-text: var(--color-btn-primary-text, #ffffff);
            --bgn-attention-fg: var(--color-attention-fg, #9a6700);
            --bgn-tooltip-bg: var(--color-neutral-emphasis-plus, #1f2328);
            --bgn-tooltip-kbd-bg: rgba(110, 118, 129, 0.4);
            --bgn-overlay-backdrop: rgba(0, 0, 0, 0.45);
            --bgn-shadow-medium: var(--color-shadow-medium, 0 8px 24px rgba(0, 0, 0, 0.2));
            --bgn-shadow-large: var(--color-shadow-large, 0 16px 32px rgba(0, 0, 0, 0.16));
            --bgn-shadow-panel: 0 16px 40px rgba(0, 0, 0, 0.25);
        }
        :root[${THEME_SOURCE_ATTR}="auto"][${THEME_ATTR}="dark"] {
            --bgn-color-scheme: dark;
            --bgn-fg-default: var(--color-fg-default, #e6edf3);
            --bgn-fg-muted: var(--color-fg-muted, #8b949e);
            --bgn-fg-on-emphasis: var(--color-fg-on-emphasis, #ffffff);
            --bgn-border-default: var(--color-border-default, #30363d);
            --bgn-border-muted: var(--color-border-muted, #30363d);
            --bgn-surface-default: var(--color-canvas-default, #0d1117);
            --bgn-surface-subtle: var(--color-canvas-subtle, #161b22);
            --bgn-surface-hover: var(--color-neutral-muted, rgba(110, 118, 129, 0.22));
            --bgn-surface-active: var(--color-neutral-muted, rgba(110, 118, 129, 0.32));
            --bgn-accent-fg: var(--color-accent-fg, #58a6ff);
            --bgn-accent-subtle: var(--color-accent-subtle, rgba(56, 139, 253, 0.18));
            --bgn-btn-bg: var(--color-btn-bg, #212830);
            --bgn-btn-hover-bg: var(--color-btn-hover-bg, #30363d);
            --bgn-btn-primary-bg: var(--color-btn-primary-bg, #238636);
            --bgn-btn-primary-hover-bg: var(--color-btn-primary-hover-bg, #2ea043);
            --bgn-btn-primary-text: var(--color-btn-primary-text, #ffffff);
            --bgn-attention-fg: var(--color-attention-fg, #d29922);
            --bgn-tooltip-bg: var(--color-neutral-emphasis-plus, #21262d);
            --bgn-tooltip-kbd-bg: rgba(139, 148, 158, 0.35);
            --bgn-overlay-backdrop: rgba(1, 4, 9, 0.72);
            --bgn-shadow-medium: var(--color-shadow-medium, 0 8px 24px rgba(1, 4, 9, 0.45));
            --bgn-shadow-large: var(--color-shadow-large, 0 16px 32px rgba(1, 4, 9, 0.5));
            --bgn-shadow-panel: 0 18px 42px rgba(1, 4, 9, 0.6);
        }
        :root[${THEME_SOURCE_ATTR}="custom"][${THEME_ATTR}="light"] {
            --bgn-color-scheme: light;
            --bgn-fg-default: #1f2328;
            --bgn-fg-muted: #656d76;
            --bgn-fg-on-emphasis: #ffffff;
            --bgn-border-default: #d1d9e0;
            --bgn-border-muted: #d8dee4;
            --bgn-surface-default: #ffffff;
            --bgn-surface-subtle: #f6f8fa;
            --bgn-surface-hover: rgba(177, 186, 196, 0.12);
            --bgn-surface-active: rgba(177, 186, 196, 0.18);
            --bgn-accent-fg: #0969da;
            --bgn-accent-subtle: rgba(9, 105, 218, 0.08);
            --bgn-btn-bg: #f6f8fa;
            --bgn-btn-hover-bg: #f3f4f6;
            --bgn-btn-primary-bg: #1f883d;
            --bgn-btn-primary-hover-bg: #1a7f37;
            --bgn-btn-primary-text: #ffffff;
            --bgn-attention-fg: #9a6700;
            --bgn-tooltip-bg: #1f2328;
            --bgn-tooltip-kbd-bg: rgba(110, 118, 129, 0.4);
            --bgn-overlay-backdrop: rgba(0, 0, 0, 0.45);
            --bgn-shadow-medium: 0 8px 24px rgba(0, 0, 0, 0.2);
            --bgn-shadow-large: 0 16px 32px rgba(0, 0, 0, 0.16);
            --bgn-shadow-panel: 0 16px 40px rgba(0, 0, 0, 0.25);
        }
        :root[${THEME_SOURCE_ATTR}="custom"][${THEME_ATTR}="dark"] {
            --bgn-color-scheme: dark;
            --bgn-fg-default: #e6edf3;
            --bgn-fg-muted: #8b949e;
            --bgn-fg-on-emphasis: #ffffff;
            --bgn-border-default: #30363d;
            --bgn-border-muted: #30363d;
            --bgn-surface-default: #0d1117;
            --bgn-surface-subtle: #161b22;
            --bgn-surface-hover: rgba(110, 118, 129, 0.22);
            --bgn-surface-active: rgba(110, 118, 129, 0.32);
            --bgn-accent-fg: #58a6ff;
            --bgn-accent-subtle: rgba(56, 139, 253, 0.18);
            --bgn-btn-bg: #212830;
            --bgn-btn-hover-bg: #30363d;
            --bgn-btn-primary-bg: #238636;
            --bgn-btn-primary-hover-bg: #2ea043;
            --bgn-btn-primary-text: #ffffff;
            --bgn-attention-fg: #d29922;
            --bgn-tooltip-bg: #21262d;
            --bgn-tooltip-kbd-bg: rgba(139, 148, 158, 0.35);
            --bgn-overlay-backdrop: rgba(1, 4, 9, 0.72);
            --bgn-shadow-medium: 0 8px 24px rgba(1, 4, 9, 0.45);
            --bgn-shadow-large: 0 16px 32px rgba(1, 4, 9, 0.5);
            --bgn-shadow-panel: 0 18px 42px rgba(1, 4, 9, 0.6);
        }
        a.${CUSTOM_BUTTON_CLASS} {
            border-radius: 6px;
            padding-inline: 8px;
            text-decoration: none;
        }
        a.${CUSTOM_BUTTON_CLASS}.${CUSTOM_BUTTON_COMPACT_CLASS} {
            padding-inline: 4px;
        }
        a.${CUSTOM_BUTTON_CLASS},
        a.${CUSTOM_BUTTON_CLASS} span {
            font-weight: 600;
        }
        a.${CUSTOM_BUTTON_CLASS},
        a.${CUSTOM_BUTTON_CLASS} * {
            cursor: pointer;
        }
        header [${QUICK_LINK_LAST_MARK_ATTR}="1"]::after,
        header [${QUICK_LINK_LAST_MARK_ATTR}="1"] > a::after,
        header a[${QUICK_LINK_MARK_ATTR}="1"][${QUICK_LINK_LAST_MARK_ATTR}="1"]::after {
            content: none !important;
            display: none !important;
        }
        a.${CUSTOM_BUTTON_CLASS}:hover {
            background-color: var(--color-neutral-muted, rgba(177, 186, 196, 0.12));
            text-decoration: none;
        }
        a.${CUSTOM_BUTTON_CLASS}.${CUSTOM_BUTTON_ACTIVE_CLASS} {
            background-color: var(--color-neutral-muted, rgba(177, 186, 196, 0.18));
            font-weight: 600;
        }
        .custom-gh-nav-overflow-host {
            position: relative;
            display: inline-flex;
            align-items: center;
            list-style: none;
        }
        .custom-gh-nav-overflow-toggle {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            width: 28px;
            min-width: 28px;
            min-height: 28px;
            padding: 0;
            border: 1px solid var(--bgn-border-default);
            border-radius: 6px;
            background: var(--bgn-surface-subtle);
            color: var(--bgn-fg-default);
            color-scheme: var(--bgn-color-scheme);
            font: inherit;
            font-weight: 600;
            line-height: 1;
            cursor: pointer;
        }
        .custom-gh-nav-overflow-toggle:hover,
        .custom-gh-nav-overflow-toggle[aria-expanded="true"] {
            background-color: var(--bgn-surface-hover);
        }
        .custom-gh-nav-overflow-toggle:focus-visible {
            outline: 2px solid var(--bgn-accent-fg);
            outline-offset: 1px;
        }
        .custom-gh-nav-overflow-toggle-icon {
            flex: 0 0 auto;
            transition: transform 120ms ease;
        }
        .custom-gh-nav-overflow-toggle[aria-expanded="true"] .custom-gh-nav-overflow-toggle-icon {
            transform: rotate(180deg);
        }
        .custom-gh-nav-overflow-menu {
            position: fixed;
            top: 0;
            left: 0;
            z-index: 2147483646;
            display: flex;
            flex-direction: column;
            gap: 2px;
            min-width: 220px;
            max-width: min(280px, calc(100vw - 16px));
            padding: 6px;
            border: 1px solid var(--bgn-border-default);
            border-radius: 12px;
            background: var(--bgn-surface-default);
            color: var(--bgn-fg-default);
            color-scheme: var(--bgn-color-scheme);
            box-shadow: var(--bgn-shadow-large);
            box-sizing: border-box;
        }
        .custom-gh-nav-overflow-menu[hidden] {
            display: none !important;
        }
        .custom-gh-nav-overflow-link {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            min-height: 32px;
            padding: 6px 10px;
            border-radius: 8px;
            color: var(--bgn-fg-default);
            font-size: 13px;
            font-weight: 600;
            text-decoration: none;
        }
        .custom-gh-nav-overflow-link:hover {
            background: var(--bgn-surface-hover);
            text-decoration: none;
        }
        .custom-gh-nav-overflow-link[aria-current="page"] {
            color: var(--bgn-accent-fg);
            background: var(--bgn-accent-subtle);
        }
        .custom-gh-nav-overflow-link-text {
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }
        .custom-gh-nav-overflow-link-kbd {
            flex: 0 0 auto;
            margin: 0;
            padding: 2px 6px;
            border: none !important;
            border-radius: 999px;
            background: var(--bgn-surface-active) !important;
            color: var(--bgn-fg-muted);
            box-shadow: none !important;
            font: inherit;
            font-size: 11px;
            line-height: 1.2;
            text-transform: uppercase;
        }
        .custom-gh-nav-tooltip {
            position: fixed;
            z-index: 2147483647;
            display: inline-flex;
            align-items: center;
            gap: 8px;
            max-width: min(320px, calc(100vw - 16px));
            background: var(--bgn-tooltip-bg);
            color: var(--bgn-fg-on-emphasis);
            border-radius: 6px;
            padding: 4px 8px;
            font-size: 12px;
            font-weight: 400;
            line-height: 16px;
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Noto Sans', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji';
            pointer-events: none;
            box-sizing: border-box;
            box-shadow: var(--bgn-shadow-medium);
            border: 1px solid var(--bgn-border-default);
            text-decoration: none;
        }
        .custom-gh-nav-tooltip[hidden] {
            display: none !important;
        }
        .custom-gh-nav-tooltip-text {
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            text-decoration: none;
        }
        .custom-gh-nav-tooltip-hint-container {
            display: inline-flex;
            align-items: center;
            flex-shrink: 0;
            margin-left: 4px;
            text-decoration: none;
        }
        .custom-gh-nav-tooltip-kbd {
            display: inline-flex;
            align-items: center;
            gap: 4px;
            margin: 0;
            padding: 0;
            border: none !important;
            box-shadow: none !important;
            font: inherit;
            color: inherit;
            background: transparent !important;
            text-decoration: none !important;
        }
        .custom-gh-nav-tooltip-chord {
            display: inline-block;
            vertical-align: middle;
            padding: 0 4px;
            border-radius: 4px;
            background: var(--bgn-tooltip-kbd-bg);
            color: #ffffff;
            font-size: 11px;
            font-weight: 400;
            line-height: 18px;
            font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
            text-transform: uppercase;
            box-sizing: border-box;
            border: none !important;
            box-shadow: none !important;
            text-decoration: none !important;
        }
        #${SETTINGS_OVERLAY_ID} {
            position: fixed;
            inset: 0;
            z-index: 2147483647;
            background: var(--bgn-overlay-backdrop);
            display: flex;
            align-items: center;
            justify-content: center;
            padding: 16px;
            box-sizing: border-box;
        }
        #${SETTINGS_PANEL_ID} {
            width: min(560px, 100%);
            max-height: min(80vh, 720px);
            overflow: auto;
            background: var(--bgn-surface-default);
            color: var(--bgn-fg-default);
            border: 1px solid var(--bgn-border-default);
            border-radius: 10px;
            color-scheme: var(--bgn-color-scheme);
            box-shadow: var(--bgn-shadow-panel);
            padding: 16px;
            box-sizing: border-box;
        }
        .custom-gh-nav-settings-title {
            margin: 0 0 8px;
            font-size: 16px;
            line-height: 1.4;
        }
        .custom-gh-nav-settings-desc {
            margin: 0 0 12px;
            color: var(--bgn-fg-muted);
            font-size: 13px;
        }
        .custom-gh-nav-settings-list {
            display: flex;
            flex-direction: column;
            gap: 8px;
        }
        .custom-gh-nav-settings-row {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 12px;
            border: 1px solid var(--bgn-border-muted);
            border-radius: 8px;
            padding: 8px 10px;
            background: var(--bgn-surface-subtle);
            cursor: grab;
        }
        .custom-gh-nav-settings-row:active {
            cursor: grabbing;
        }
        .custom-gh-nav-settings-row-left {
            display: inline-flex;
            align-items: center;
            gap: 8px;
            user-select: none;
            font-size: 13px;
        }
        .custom-gh-nav-settings-row-left input {
            cursor: pointer;
        }
        .custom-gh-nav-settings-row-actions {
            display: inline-flex;
            align-items: center;
            gap: 6px;
        }
        .custom-gh-nav-settings-drag-handle {
            border: 1px solid var(--bgn-border-default);
            background: var(--bgn-btn-bg);
            color: var(--bgn-fg-muted);
            border-radius: 6px;
            width: 32px;
            height: 26px;
            line-height: 1;
            font-size: 16px;
            display: inline-flex;
            align-items: center;
            justify-content: center;
            user-select: none;
            pointer-events: none;
        }
        .custom-gh-nav-settings-row-dragging {
            opacity: 0.55;
        }
        .custom-gh-nav-settings-row-drag-over {
            border-color: var(--bgn-accent-fg);
            background: var(--bgn-accent-subtle);
        }
        .custom-gh-nav-settings-btn {
            border: 1px solid var(--bgn-border-default);
            background: var(--bgn-btn-bg);
            color: var(--bgn-fg-default);
            border-radius: 6px;
            padding: 4px 10px;
            font-size: 12px;
            cursor: pointer;
        }
        .custom-gh-nav-settings-btn:hover {
            background: var(--bgn-btn-hover-bg);
        }
        .custom-gh-nav-settings-btn:disabled {
            opacity: 0.45;
            cursor: not-allowed;
        }
        .custom-gh-nav-settings-btn-primary {
            background: var(--bgn-btn-primary-bg);
            border-color: var(--bgn-btn-primary-bg);
            color: var(--bgn-btn-primary-text);
        }
        .custom-gh-nav-settings-btn-primary:hover {
            background: var(--bgn-btn-primary-hover-bg);
        }
        .custom-gh-nav-settings-footer {
            margin-top: 12px;
            display: flex;
            justify-content: flex-end;
            gap: 8px;
        }
        .custom-gh-nav-settings-message {
            min-height: 20px;
            margin-top: 8px;
            color: var(--bgn-attention-fg);
            font-size: 12px;
        }
        .custom-gh-top-repos-row {
            display: flex;
            align-items: center;
            gap: 6px;
            min-width: 0;
        }
        .custom-gh-top-repos-link {
            flex: 1 1 auto;
            min-width: 0;
        }
        .custom-gh-top-repos-pin {
            display: inline-flex;
            align-items: center;
            justify-content: center;
            flex: 0 0 auto;
            width: 20px;
            height: 20px;
            border: none;
            border-radius: 6px;
            padding: 0;
            background: transparent;
            color: var(--color-fg-muted, #656d76);
            cursor: pointer;
            opacity: 0.75;
        }
        .custom-gh-top-repos-pin-icon {
            width: 12px;
            height: 12px;
            overflow: visible;
        }
        .custom-gh-top-repos-pin:hover {
            background: var(--color-neutral-muted, rgba(177, 186, 196, 0.12));
            color: var(--color-fg-default, #1f2328);
            opacity: 1;
        }
        .custom-gh-top-repos-pin:focus-visible {
            outline: 2px solid var(--color-accent-fg, #0969da);
            outline-offset: 1px;
        }
        .custom-gh-top-repos-pin.${CUSTOM_BUTTON_ACTIVE_CLASS},
        .custom-gh-top-repos-pin-active {
            color: var(--color-accent-fg, #0969da);
            background: var(--color-accent-subtle, rgba(9, 105, 218, 0.08));
            opacity: 1;
        }
        .custom-gh-top-repos-divider {
            list-style: none;
            height: 1px;
            margin: 6px 0;
            background: var(--color-border-muted, rgba(208, 215, 222, 0.8));
        }
    `;
    document.head.appendChild(style);
  }
  function setActiveStyle(aTag, active, compact = false) {
    aTag.classList.add(CUSTOM_BUTTON_CLASS);
    if (compact) {
      aTag.classList.add(CUSTOM_BUTTON_COMPACT_CLASS);
    } else {
      aTag.classList.remove(CUSTOM_BUTTON_COMPACT_CLASS);
    }
    if (active) {
      aTag.setAttribute("aria-current", "page");
      aTag.classList.add(CUSTOM_BUTTON_ACTIVE_CLASS);
    } else {
      aTag.removeAttribute("aria-current");
      aTag.classList.remove(CUSTOM_BUTTON_ACTIVE_CLASS);
    }
  }

  // src/navigation.js
  var lastHotkeyConflictSignature = "";
  var hotkeyTooltipNode = null;
  var hotkeyTooltipTextNode = null;
  var hotkeyTooltipHintNode = null;
  var hotkeyTooltipAnchor = null;
  var hotkeyTooltipGlobalBound = false;
  var hotkeyTooltipBoundAnchors = /* @__PURE__ */ new WeakSet();
  var responsiveQuickLinksState = null;
  var responsiveQuickLinksGlobalBound = false;
  function normalizePath(href) {
    try {
      const url = new URL(href, location.origin);
      const path = url.pathname.replace(/\/+$/, "");
      return path || "/";
    } catch (e) {
      return "";
    }
  }
  function isCurrentPage(linkPath) {
    const currentPath = location.pathname.replace(/\/+$/, "") || "/";
    if (linkPath === "/dashboard") return currentPath === "/" || currentPath === "/dashboard";
    if (currentPath === linkPath) return true;
    if (linkPath !== "/" && currentPath.startsWith(`${linkPath}/`)) return true;
    return location.search.includes("tab=stars") && linkPath === normalizePath("/stars");
  }
  function setLinkText(aTag, text) {
    aTag.removeAttribute("aria-describedby");
    aTag.setAttribute("aria-label", text);
    const icons = aTag.querySelectorAll("svg");
    icons.forEach((icon) => icon.remove());
    const innerSpan = aTag.querySelector("span");
    if (innerSpan) {
      innerSpan.textContent = text;
    } else {
      aTag.textContent = text;
    }
  }
  function ensureAnchor(node, isLiParent) {
    let aTag = isLiParent ? node.querySelector("a") : node.tagName.toLowerCase() === "a" ? node : node.querySelector("a");
    if (aTag) return aTag;
    const fallbackText = (node.textContent || "").trim();
    const fallbackHref = !isLiParent && node.getAttribute && node.getAttribute("href") ? node.getAttribute("href") : `${location.pathname}${location.search}`;
    const classSource = isLiParent ? node.querySelector('[class*="contextCrumb"], [class*="Breadcrumbs-Item"]') : node;
    const spanTemplate = document.querySelector(
      'header a[class*="contextCrumb"] span[class*="contextCrumbLast"]'
    );
    const spanSource = isLiParent ? node.querySelector("span") : node.querySelector("span");
    aTag = document.createElement("a");
    if (classSource && classSource.className) {
      aTag.className = classSource.className.split(/\s+/).filter((cls) => cls && !cls.includes("contextCrumbStatic")).join(" ");
    }
    if (spanSource && spanSource.className) {
      const innerSpan = document.createElement("span");
      innerSpan.className = spanTemplate && spanTemplate.className ? spanTemplate.className : spanSource.className;
      if (fallbackText) innerSpan.textContent = fallbackText;
      aTag.appendChild(innerSpan);
    }
    if (!aTag.getAttribute("href") && fallbackHref) {
      aTag.setAttribute("href", fallbackHref);
    }
    if (!aTag.textContent.trim() && fallbackText) {
      const innerSpan = aTag.querySelector("span");
      if (innerSpan) {
        innerSpan.textContent = fallbackText;
      } else {
        aTag.textContent = fallbackText;
      }
    }
    if (isLiParent) {
      node.textContent = "";
      node.appendChild(aTag);
    } else {
      node.replaceChildren(aTag);
    }
    return aTag;
  }
  function getAnchorHostNode(anchor) {
    if (!anchor || !anchor.parentNode) return anchor;
    return anchor.parentNode.tagName.toLowerCase() === "li" ? anchor.parentNode : anchor;
  }
  function cleanupQuickLinksForContainer(renderParent, keepNode) {
    const quickAnchors = Array.from(
      document.querySelectorAll(
        'header a[id^="custom-gh-btn-"], header a[' + QUICK_LINK_MARK_ATTR + '="1"]'
      )
    );
    quickAnchors.forEach((anchor) => {
      const host = getAnchorHostNode(anchor);
      if (!host || !host.parentNode) return;
      if (host === keepNode) return;
      if (host.parentNode !== renderParent) {
        host.remove();
        return;
      }
      host.remove();
    });
  }
  function insertNodeAfter(parent, node, referenceNode) {
    if (!parent || !node || !referenceNode || referenceNode.parentNode !== parent) return;
    let insertionReference = referenceNode;
    while (insertionReference.nextSibling && insertionReference.nextSibling.nodeType === Node.TEXT_NODE) {
      const textContent = insertionReference.nextSibling.textContent || "";
      if (textContent.trim()) break;
      insertionReference = insertionReference.nextSibling;
    }
    if (isBreadcrumbSeparatorNode(insertionReference.nextSibling)) {
      insertionReference = insertionReference.nextSibling;
    }
    const nextSibling = insertionReference.nextSibling;
    if (node.parentNode === parent && node.previousSibling === insertionReference) return;
    if (nextSibling === node) return;
    parent.insertBefore(node, nextSibling);
  }
  function isBreadcrumbSeparatorNode(node) {
    if (!node) return false;
    if (node.nodeType === Node.TEXT_NODE) {
      return (node.textContent || "").trim() === "/";
    }
    if (node.nodeType !== Node.ELEMENT_NODE) return false;
    const text = (node.textContent || "").replace(/\s+/g, "");
    if (text === "/") return true;
    const className = typeof node.className === "string" ? node.className : "";
    return /breadcrumb|separator|divider/i.test(className) && text === "/";
  }
  function stripBreadcrumbSeparatorsFromHost(hostNode) {
    if (!hostNode || hostNode.nodeType !== Node.ELEMENT_NODE) return;
    const anchor = hostNode.tagName.toLowerCase() === "a" ? hostNode : hostNode.querySelector("a");
    Array.from(hostNode.childNodes).forEach((child) => {
      if (child === anchor) return;
      if (child.nodeType === Node.TEXT_NODE && isBreadcrumbSeparatorNode(child)) {
        child.remove();
      }
    });
    Array.from(hostNode.querySelectorAll("*")).forEach((node) => {
      if (anchor && anchor.contains(node)) return;
      if (isBreadcrumbSeparatorNode(node)) {
        node.remove();
      }
    });
  }
  function setQuickLinkHostMark(hostNode, enabled) {
    if (!hostNode || hostNode.nodeType !== Node.ELEMENT_NODE) return;
    if (enabled) {
      hostNode.setAttribute(QUICK_LINK_HOST_MARK_ATTR, "1");
    } else {
      hostNode.removeAttribute(QUICK_LINK_HOST_MARK_ATTR);
    }
  }
  function setQuickLinkLastMark(hostNode, enabled) {
    if (!hostNode || hostNode.nodeType !== Node.ELEMENT_NODE) return;
    const anchor = hostNode.tagName.toLowerCase() === "a" ? hostNode : hostNode.querySelector("a");
    if (enabled) {
      hostNode.setAttribute(QUICK_LINK_LAST_MARK_ATTR, "1");
      if (anchor && anchor.getAttribute(QUICK_LINK_MARK_ATTR) === "1") {
        anchor.setAttribute(QUICK_LINK_LAST_MARK_ATTR, "1");
      }
      return;
    }
    hostNode.removeAttribute(QUICK_LINK_LAST_MARK_ATTR);
    if (anchor) {
      anchor.removeAttribute(QUICK_LINK_LAST_MARK_ATTR);
    }
  }
  function createOverflowChevronIcon() {
    const ns = "http://www.w3.org/2000/svg";
    const svg = document.createElementNS(ns, "svg");
    svg.setAttribute("aria-hidden", "true");
    svg.setAttribute("focusable", "false");
    svg.setAttribute("viewBox", "0 0 16 16");
    svg.setAttribute("width", "16");
    svg.setAttribute("height", "16");
    svg.setAttribute("fill", "currentColor");
    svg.classList.add("custom-gh-nav-overflow-toggle-icon");
    const path = document.createElementNS(ns, "path");
    path.setAttribute(
      "d",
      "m4.427 7.427 3.396 3.396a.25.25 0 0 0 .354 0l3.396-3.396A.25.25 0 0 0 11.396 7H4.604a.25.25 0 0 0-.177.427Z"
    );
    svg.appendChild(path);
    return svg;
  }
  function createOverflowMenuLink(linkInfo) {
    const link = document.createElement("a");
    link.className = "custom-gh-nav-overflow-link";
    link.href = linkInfo.href;
    link.setAttribute("aria-label", linkInfo.text);
    const text = document.createElement("span");
    text.className = "custom-gh-nav-overflow-link-text";
    text.textContent = linkInfo.text;
    link.appendChild(text);
    const hotkey = normalizeHotkeyValue(PRESET_LINK_SHORTCUTS[linkInfo.key]);
    if (hotkey) {
      const hint = document.createElement("kbd");
      hint.className = "custom-gh-nav-overflow-link-kbd";
      hint.textContent = hotkey.toUpperCase();
      hint.setAttribute("aria-hidden", "true");
      link.appendChild(hint);
    }
    if (isCurrentPage(linkInfo.path)) {
      link.setAttribute("aria-current", "page");
    }
    return link;
  }
  function updateResponsiveQuickLinksToggle(state) {
    const label = state.menuOpen ? t("closeQuickLinksMenu") : t("openQuickLinksMenu");
    state.toggleButton.title = label;
    state.toggleButton.setAttribute("aria-label", label);
    state.toggleButton.setAttribute("aria-expanded", state.menuOpen ? "true" : "false");
  }
  function positionResponsiveQuickLinksMenu(state) {
    const viewportPadding = 8;
    const anchorRect = state.toggleButton.getBoundingClientRect();
    state.menuNode.style.left = `${viewportPadding}px`;
    state.menuNode.style.top = `${Math.round(anchorRect.bottom + viewportPadding)}px`;
    const menuRect = state.menuNode.getBoundingClientRect();
    const maxLeft = Math.max(viewportPadding, window.innerWidth - menuRect.width - viewportPadding);
    const preferredLeft = anchorRect.right - menuRect.width;
    const fallbackLeft = anchorRect.left;
    const unclampedLeft = preferredLeft >= viewportPadding ? preferredLeft : fallbackLeft;
    const left = Math.min(maxLeft, Math.max(viewportPadding, unclampedLeft));
    let top = anchorRect.bottom + viewportPadding;
    const fitsBelow = top + menuRect.height <= window.innerHeight - viewportPadding;
    const fitsAbove = anchorRect.top - viewportPadding - menuRect.height >= viewportPadding;
    if (!fitsBelow && fitsAbove) {
      top = anchorRect.top - viewportPadding - menuRect.height;
    } else if (!fitsBelow) {
      top = Math.max(
        viewportPadding,
        window.innerHeight - menuRect.height - viewportPadding
      );
    }
    state.menuNode.style.left = `${Math.round(left)}px`;
    state.menuNode.style.top = `${Math.round(top)}px`;
  }
  function closeResponsiveQuickLinksMenu() {
    const state = responsiveQuickLinksState;
    if (!state || !state.menuOpen) return;
    hideHotkeyTooltip();
    state.menuOpen = false;
    state.menuNode.hidden = true;
    state.menuNode.style.visibility = "";
    updateResponsiveQuickLinksToggle(state);
  }
  function toggleResponsiveQuickLinksMenu() {
    const state = responsiveQuickLinksState;
    if (!state || !state.isCollapsed) return;
    hideHotkeyTooltip();
    state.menuOpen = !state.menuOpen;
    state.menuNode.hidden = !state.menuOpen;
    if (state.menuOpen) {
      state.menuNode.style.visibility = "hidden";
      positionResponsiveQuickLinksMenu(state);
      state.menuNode.style.visibility = "";
    }
    updateResponsiveQuickLinksToggle(state);
  }
  function restoreResponsiveInlineNodes(state) {
    if (!state.inlineItems.length) return;
    let insertAfter = state.referenceNode;
    state.inlineItems.forEach((item) => {
      insertNodeAfter(state.renderParent, item.hostNode, insertAfter);
      insertAfter = item.hostNode;
    });
    insertNodeAfter(state.renderParent, state.toggleHostNode, insertAfter);
  }
  function collapseResponsiveInlineNodes(state) {
    state.inlineItems.forEach((item) => {
      if (item.hostNode.parentNode) {
        item.hostNode.remove();
      }
    });
    insertNodeAfter(state.renderParent, state.toggleHostNode, state.referenceNode);
  }
  function needsResponsiveQuickLinksCollapse(state) {
    const measureContainer = state.measureContainer;
    const baselineRect = state.referenceNode.getBoundingClientRect();
    const containerRect = measureContainer.getBoundingClientRect();
    const containerRight = Math.min(containerRect.right, window.innerWidth - 8);
    const wrapped = state.inlineItems.some((item) => {
      if (!item.hostNode.isConnected) return false;
      const rect = item.hostNode.getBoundingClientRect();
      if (rect.width <= 0 && rect.height <= 0) return false;
      return Math.abs(rect.top - baselineRect.top) > 4;
    });
    const overflowing = state.inlineItems.some((item) => {
      if (!item.hostNode.isConnected) return false;
      const rect = item.hostNode.getBoundingClientRect();
      if (rect.width <= 0 && rect.height <= 0) return false;
      return rect.right > containerRight;
    });
    const scrollOverflow = measureContainer.scrollWidth > measureContainer.clientWidth + 1 || state.renderParent.scrollWidth > state.renderParent.clientWidth + 1;
    return wrapped || overflowing || scrollOverflow;
  }
  function syncResponsiveQuickLinksState(state) {
    if (!state) return;
    if (!state.renderParent.isConnected || !state.referenceNode.isConnected) {
      destroyResponsiveQuickLinks();
      return;
    }
    hideHotkeyTooltip();
    closeResponsiveQuickLinksMenu();
    restoreResponsiveInlineNodes(state);
    state.toggleHostNode.hidden = true;
    const shouldCollapse = needsResponsiveQuickLinksCollapse(state);
    if (shouldCollapse) {
      collapseResponsiveInlineNodes(state);
      state.isCollapsed = true;
      state.toggleHostNode.hidden = false;
    } else {
      state.isCollapsed = false;
    }
    updateResponsiveQuickLinksToggle(state);
  }
  function scheduleResponsiveQuickLinksSync() {
    const state = responsiveQuickLinksState;
    if (!state || state.syncQueued) return;
    state.syncQueued = true;
    requestAnimationFrame(() => {
      const latestState = responsiveQuickLinksState;
      if (!latestState) return;
      latestState.syncQueued = false;
      syncResponsiveQuickLinksState(latestState);
    });
  }
  function destroyResponsiveQuickLinks() {
    closeResponsiveQuickLinksMenu();
    if (responsiveQuickLinksState?.resizeObserver) {
      responsiveQuickLinksState.resizeObserver.disconnect();
    }
    if (responsiveQuickLinksState?.toggleHostNode?.isConnected) {
      responsiveQuickLinksState.toggleHostNode.remove();
    }
    responsiveQuickLinksState = null;
  }
  function bindResponsiveQuickLinksGlobalHandlers() {
    if (responsiveQuickLinksGlobalBound) return;
    responsiveQuickLinksGlobalBound = true;
    window.addEventListener("resize", () => {
      closeResponsiveQuickLinksMenu();
      scheduleResponsiveQuickLinksSync();
    }, { passive: true });
    document.addEventListener("keydown", (event) => {
      if (event.key === "Escape") {
        closeResponsiveQuickLinksMenu();
      }
    }, true);
    document.addEventListener("pointerdown", (event) => {
      const state = responsiveQuickLinksState;
      if (!state || !state.menuOpen) return;
      const target = event.target;
      if (target && state.toggleHostNode.contains(target)) return;
      closeResponsiveQuickLinksMenu();
    }, true);
    document.addEventListener("scroll", () => {
      closeResponsiveQuickLinksMenu();
    }, true);
  }
  function setupResponsiveQuickLinks({
    renderParent,
    referenceNode,
    inlineItems
  }) {
    destroyResponsiveQuickLinks();
    if (!inlineItems.length) return;
    bindResponsiveQuickLinksGlobalHandlers();
    const hostTagName = inlineItems[0]?.hostNode?.tagName?.toLowerCase() || "div";
    const toggleHostNode = document.createElement(hostTagName === "li" ? "li" : "div");
    toggleHostNode.className = "custom-gh-nav-overflow-host";
    toggleHostNode.setAttribute(RESPONSIVE_TOGGLE_MARK_ATTR, "1");
    toggleHostNode.hidden = true;
    const toggleButton = document.createElement("button");
    toggleButton.type = "button";
    toggleButton.className = "custom-gh-nav-overflow-toggle";
    toggleButton.setAttribute("aria-haspopup", "true");
    toggleButton.setAttribute("aria-expanded", "false");
    toggleButton.appendChild(createOverflowChevronIcon());
    const menuNode = document.createElement("nav");
    menuNode.id = "custom-gh-nav-overflow-menu";
    menuNode.className = "custom-gh-nav-overflow-menu";
    menuNode.setAttribute("aria-label", t("quickLinksMenu"));
    menuNode.hidden = true;
    toggleButton.setAttribute("aria-controls", menuNode.id);
    inlineItems.forEach((item) => {
      menuNode.appendChild(createOverflowMenuLink(item.linkInfo));
    });
    toggleButton.addEventListener("click", (event) => {
      event.preventDefault();
      event.stopPropagation();
      toggleResponsiveQuickLinksMenu();
    });
    menuNode.addEventListener("click", (event) => {
      const link = event.target.closest("a[href]");
      if (!link) return;
      closeResponsiveQuickLinksMenu();
    });
    toggleHostNode.appendChild(toggleButton);
    toggleHostNode.appendChild(menuNode);
    insertNodeAfter(renderParent, toggleHostNode, inlineItems[inlineItems.length - 1].hostNode || referenceNode);
    const state = {
      inlineItems,
      isCollapsed: false,
      measureContainer: renderParent.closest("nav") || renderParent,
      menuNode,
      menuOpen: false,
      referenceNode,
      renderParent,
      resizeObserver: null,
      syncQueued: false,
      toggleButton,
      toggleHostNode,
      toggleLabelNode: null
    };
    if (typeof ResizeObserver === "function") {
      state.resizeObserver = new ResizeObserver(() => {
        scheduleResponsiveQuickLinksSync();
      });
      state.resizeObserver.observe(renderParent);
      if (state.measureContainer !== renderParent) {
        state.resizeObserver.observe(state.measureContainer);
      }
    }
    responsiveQuickLinksState = state;
    syncResponsiveQuickLinksState(state);
  }
  function normalizeHotkeyValue(value) {
    return String(value || "").trim().toLowerCase().replace(/\s+/g, " ");
  }
  function createChordNode(chord) {
    const chordNode = document.createElement("span");
    chordNode.className = "custom-gh-nav-tooltip-chord";
    chordNode.setAttribute("data-kbd-chord", "true");
    chordNode.textContent = chord.toUpperCase();
    return chordNode;
  }
  function ensureHotkeyTooltipNode() {
    const existing = document.getElementById("custom-gh-nav-hotkey-tooltip");
    if (existing) {
      hotkeyTooltipNode = existing;
      hotkeyTooltipTextNode = existing.querySelector(".custom-gh-nav-tooltip-text");
      hotkeyTooltipHintNode = existing.querySelector(".custom-gh-nav-tooltip-kbd");
      return existing;
    }
    const tooltip = document.createElement("span");
    tooltip.id = "custom-gh-nav-hotkey-tooltip";
    tooltip.className = "custom-gh-nav-tooltip";
    tooltip.setAttribute("role", "tooltip");
    tooltip.setAttribute("aria-hidden", "true");
    tooltip.hidden = true;
    const textNode = document.createElement("span");
    textNode.className = "custom-gh-nav-tooltip-text";
    tooltip.appendChild(textNode);
    const hintContainer = document.createElement("span");
    hintContainer.className = "custom-gh-nav-tooltip-hint-container";
    hintContainer.setAttribute("aria-hidden", "true");
    const kbdNode = document.createElement("kbd");
    kbdNode.className = "custom-gh-nav-tooltip-kbd";
    hintContainer.appendChild(kbdNode);
    tooltip.appendChild(hintContainer);
    document.body.appendChild(tooltip);
    hotkeyTooltipNode = tooltip;
    hotkeyTooltipTextNode = textNode;
    hotkeyTooltipHintNode = kbdNode;
    return tooltip;
  }
  function hideHotkeyTooltip() {
    const tooltip = hotkeyTooltipNode || document.getElementById("custom-gh-nav-hotkey-tooltip");
    if (!tooltip) return;
    tooltip.hidden = true;
    tooltip.setAttribute("aria-hidden", "true");
    tooltip.removeAttribute("data-direction");
    if (hotkeyTooltipAnchor) {
      hotkeyTooltipAnchor.removeAttribute("aria-describedby");
    }
    hotkeyTooltipAnchor = null;
  }
  function positionHotkeyTooltip(tooltip, anchor) {
    const spacing = 8;
    const rect = anchor.getBoundingClientRect();
    const tooltipRect = tooltip.getBoundingClientRect();
    let top = rect.bottom + spacing;
    let direction = "s";
    if (top + tooltipRect.height > window.innerHeight - spacing && rect.top - spacing - tooltipRect.height >= spacing) {
      top = rect.top - spacing - tooltipRect.height;
      direction = "n";
    }
    let left = rect.left + (rect.width - tooltipRect.width) / 2;
    if (left + tooltipRect.width > window.innerWidth - spacing) {
      left = window.innerWidth - tooltipRect.width - spacing;
    }
    if (left < spacing) {
      left = spacing;
    }
    tooltip.style.top = `${Math.round(top)}px`;
    tooltip.style.left = `${Math.round(left)}px`;
    tooltip.setAttribute("data-direction", direction);
  }
  function showHotkeyTooltip(anchor) {
    const hotkey = normalizeHotkeyValue(anchor.getAttribute("data-hotkey"));
    if (!hotkey) return;
    const tooltip = ensureHotkeyTooltipNode();
    const label = String(anchor.getAttribute("aria-label") || anchor.textContent || "").replace(/\s+/g, " ").trim();
    if (hotkeyTooltipTextNode) {
      hotkeyTooltipTextNode.textContent = label;
    }
    if (hotkeyTooltipHintNode) {
      hotkeyTooltipHintNode.textContent = "";
      const chords = hotkey.split(" ").filter(Boolean);
      chords.forEach((chord) => {
        hotkeyTooltipHintNode.appendChild(createChordNode(chord));
      });
    }
    tooltip.hidden = false;
    tooltip.setAttribute("aria-hidden", "false");
    positionHotkeyTooltip(tooltip, anchor);
    if (hotkeyTooltipAnchor && hotkeyTooltipAnchor !== anchor) {
      hotkeyTooltipAnchor.removeAttribute("aria-describedby");
    }
    hotkeyTooltipAnchor = anchor;
    anchor.setAttribute("aria-describedby", tooltip.id);
  }
  function bindHotkeyTooltipHandlers(anchor) {
    if (hotkeyTooltipBoundAnchors.has(anchor)) return;
    hotkeyTooltipBoundAnchors.add(anchor);
    anchor.addEventListener("mouseenter", () => showHotkeyTooltip(anchor));
    anchor.addEventListener("mouseleave", hideHotkeyTooltip);
    anchor.addEventListener("focus", () => showHotkeyTooltip(anchor));
    anchor.addEventListener("blur", hideHotkeyTooltip);
    anchor.addEventListener("mousedown", hideHotkeyTooltip);
  }
  function bindHotkeyTooltipGlobalHandlers() {
    if (hotkeyTooltipGlobalBound) return;
    hotkeyTooltipGlobalBound = true;
    window.addEventListener("resize", hideHotkeyTooltip, { passive: true });
    document.addEventListener("scroll", hideHotkeyTooltip, true);
    document.addEventListener("keydown", (event) => {
      if (event.key === "Escape") hideHotkeyTooltip();
    }, true);
    document.addEventListener("pointerdown", (event) => {
      const tooltip = hotkeyTooltipNode || document.getElementById("custom-gh-nav-hotkey-tooltip");
      if (!tooltip || tooltip.hidden) return;
      const target = event.target;
      if (target && hotkeyTooltipAnchor && hotkeyTooltipAnchor.contains(target)) return;
      if (target && tooltip.contains(target)) return;
      hideHotkeyTooltip();
    }, true);
  }
  function applyLinkShortcut(aTag, linkInfo) {
    aTag.removeAttribute("data-hotkey");
    aTag.removeAttribute("aria-keyshortcuts");
    aTag.removeAttribute("title");
    aTag.removeAttribute("aria-describedby");
    const hotkey = normalizeHotkeyValue(PRESET_LINK_SHORTCUTS[linkInfo.key]);
    if (!hotkey) return "";
    aTag.setAttribute("data-hotkey", hotkey);
    aTag.setAttribute("aria-keyshortcuts", hotkey);
    bindHotkeyTooltipGlobalHandlers();
    bindHotkeyTooltipHandlers(aTag);
    return hotkey;
  }
  function describeHotkeyTarget(node) {
    if (!node) return "";
    const label = String(node.getAttribute("aria-label") || node.textContent || "").replace(/\s+/g, " ").trim();
    if (label) return label;
    const href = node.getAttribute("href");
    if (href) return href;
    return node.tagName.toLowerCase();
  }
  function reportHotkeyConflicts(customAnchors) {
    const customSet = new Set(customAnchors.filter(Boolean));
    const customByHotkey = /* @__PURE__ */ new Map();
    customAnchors.forEach((anchor) => {
      const hotkey = normalizeHotkeyValue(anchor.getAttribute("data-hotkey"));
      if (!hotkey) return;
      const labels = customByHotkey.get(hotkey) || [];
      labels.push(describeHotkeyTarget(anchor));
      customByHotkey.set(hotkey, labels);
    });
    const conflictLines = [];
    customByHotkey.forEach((labels, hotkey) => {
      const uniqueLabels = Array.from(new Set(labels.filter(Boolean)));
      if (uniqueLabels.length > 1) {
        conflictLines.push(`${hotkey} -> ${uniqueLabels.join(" / ")}`);
      }
    });
    const nativeByHotkey = /* @__PURE__ */ new Map();
    const nativeHotkeyNodes = Array.from(
      document.querySelectorAll("a[data-hotkey], button[data-hotkey], summary[data-hotkey]")
    );
    nativeHotkeyNodes.forEach((node) => {
      if (customSet.has(node)) return;
      if (node.closest('[hidden], [aria-hidden="true"]')) return;
      const style = window.getComputedStyle(node);
      if (style.display === "none" || style.visibility === "hidden") return;
      const hotkey = normalizeHotkeyValue(node.getAttribute("data-hotkey"));
      if (!hotkey) return;
      if (!customByHotkey.has(hotkey)) return;
      const labels = nativeByHotkey.get(hotkey) || [];
      labels.push(describeHotkeyTarget(node));
      nativeByHotkey.set(hotkey, labels);
    });
    customByHotkey.forEach((labels, hotkey) => {
      const nativeLabels = nativeByHotkey.get(hotkey);
      if (!nativeLabels || !nativeLabels.length) return;
      const customLabel = Array.from(new Set(labels.filter(Boolean))).join(" / ");
      const nativeLabel = Array.from(new Set(nativeLabels.filter(Boolean))).slice(0, 2).join(" / ");
      conflictLines.push(`${hotkey} -> ${customLabel} <-> ${nativeLabel}`);
    });
    const uniqueConflictLines = Array.from(new Set(conflictLines));
    if (!uniqueConflictLines.length) {
      lastHotkeyConflictSignature = "";
      return;
    }
    const signature = uniqueConflictLines.join("|");
    if (signature === lastHotkeyConflictSignature) return;
    lastHotkeyConflictSignature = signature;
    console.warn(
      `[Better GitHub Navigation] 检测到快捷键冲突:${uniqueConflictLines.join("; ")}`
    );
  }
  function addCustomButtons() {
    destroyResponsiveQuickLinks();
    const userLoginMeta = document.querySelector('meta[name="user-login"]');
    const username = userLoginMeta ? userLoginMeta.getAttribute("content") : "";
    const navPresetLinks = getConfiguredLinks(username);
    if (!navPresetLinks.length) return;
    const primaryLink = navPresetLinks[0];
    const extraLinks = navPresetLinks.slice(1);
    const fixedPages = /* @__PURE__ */ new Set(["/dashboard", "/trending", "/explore", "/collections"]);
    const shortcutPaths = new Set(PRESET_LINKS.map((link) => link.path));
    const compactPages = /* @__PURE__ */ new Set(["/issues", "/pulls", "/repositories"]);
    const isOnPresetPage = Array.from(fixedPages).some((path) => isCurrentPage(path));
    const shouldUseCompactButtons = Array.from(compactPages).some((path) => isCurrentPage(path));
    let targetNode = null;
    let targetSource = "";
    if (isOnPresetPage) {
      targetNode = document.querySelector(
        'header nav a[href="/dashboard"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header nav a[href="/trending"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header nav a[href="/explore"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"])'
      );
      if (targetNode) targetSource = "preset-nav";
      if (!targetNode) {
        targetNode = document.querySelector(
          'header nav a[id^="custom-gh-btn-"], header nav a[' + QUICK_LINK_MARK_ATTR + '="1"]'
        );
        if (targetNode) targetSource = "preset-quick";
      }
    } else {
      const breadcrumbNodes = Array.from(document.querySelectorAll(
        'header nav[aria-label*="breadcrumb" i] a[href^="/"], header a[class*="contextCrumb"][href^="/"], header a[class*="Breadcrumbs-Item"][href^="/"]'
      )).filter((link) => {
        if (link.id && link.id.startsWith("custom-gh-btn-")) return false;
        if (link.getAttribute(QUICK_LINK_MARK_ATTR) === "1") return false;
        const href = normalizePath(link.getAttribute("href") || "");
        if (!href || href === "/") return false;
        if (shortcutPaths.has(href)) return false;
        return true;
      });
      if (breadcrumbNodes.length) {
        targetNode = breadcrumbNodes[breadcrumbNodes.length - 1];
        targetSource = "breadcrumb";
      }
    }
    if (!targetNode) {
      targetNode = document.querySelector(
        'header nav a[aria-current="page"]:not([id^="custom-gh-btn-"]), header nav a[data-active="true"]:not([id^="custom-gh-btn-"]), header nav [aria-current="page"]:not(a), header nav [data-active="true"]:not(a)'
      );
      if (targetNode) targetSource = "current-nav";
    }
    if (!targetNode) {
      const navLinks = document.querySelectorAll(
        'header a:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"])'
      );
      for (const link of navLinks) {
        const text = link.textContent.trim().toLowerCase();
        const href = link.getAttribute("href");
        if (text === "dashboard" || href === "/dashboard") {
          targetNode = link;
          targetSource = "legacy-dashboard";
          break;
        }
      }
    }
    if (!targetNode) {
      const currentPath = location.pathname.replace(/\/+$/, "") || "/";
      const globalNavCandidates = Array.from(
        document.querySelectorAll(
          'header nav[aria-label*="global" i] a[href^="/"], header nav[aria-label*="header" i] a[href^="/"], header nav a[href="/pulls"], header nav a[href="/issues"], header nav a[href="/repositories"], header nav a[href="/codespaces"], header nav a[href="/marketplace"], header nav a[href="/explore"]'
        )
      ).filter((link) => {
        const href = normalizePath(link.getAttribute("href") || "");
        if (!href || href === "/") return false;
        if (link.id && link.id.startsWith("custom-gh-btn-")) return false;
        if (link.getAttribute(QUICK_LINK_MARK_ATTR) === "1") return false;
        return true;
      });
      if (globalNavCandidates.length) {
        targetNode = globalNavCandidates.find((link) => {
          const href = normalizePath(link.getAttribute("href") || "");
          return href === currentPath;
        }) || globalNavCandidates[globalNavCandidates.length - 1];
        if (targetNode) targetSource = "global-nav";
      }
    }
    if (!targetNode) {
      const currentTextNode = document.querySelector(
        'header nav [aria-current="page"]:not(a), header nav [data-active="true"]:not(a)'
      );
      if (currentTextNode) {
        targetNode = currentTextNode;
        targetSource = "current-text";
      }
    }
    if (!targetNode) {
      const contextCrumbTextNodes = document.querySelectorAll(
        'header span[class*="contextCrumbStatic"], header span[class*="contextCrumb"][class*="Breadcrumbs-Item"], header .prc-Breadcrumbs-Item-jcraJ'
      );
      if (contextCrumbTextNodes.length) {
        targetNode = contextCrumbTextNodes[contextCrumbTextNodes.length - 1];
        targetSource = "crumb-text";
      }
    }
    let templateNode = targetNode;
    if (targetNode) {
      const localNav = targetNode.closest("nav, ul, ol");
      const localAnchors = localNav ? localNav.querySelectorAll(
        'a[href^="/"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"])'
      ) : [];
      if (localAnchors.length) {
        templateNode = localAnchors[localAnchors.length - 1];
      } else {
        const nativeNavAnchors = document.querySelectorAll(
          'header nav[aria-label*="breadcrumb" i] a[href^="/"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header a[class*="contextCrumb"][href^="/"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header a[class*="Breadcrumbs-Item"][href^="/"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header nav[aria-label*="global" i] a[href^="/"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header nav[aria-label*="header" i] a[href^="/"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header nav a[href="/pulls"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header nav a[href="/issues"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header nav a[href="/repositories"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header nav a[href="/codespaces"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header nav a[href="/marketplace"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"]), header nav a[href="/explore"]:not([id^="custom-gh-btn-"]):not([' + QUICK_LINK_MARK_ATTR + '="1"])'
        );
        if (nativeNavAnchors.length) {
          templateNode = nativeNavAnchors[nativeNavAnchors.length - 1];
        }
      }
    }
    if (targetNode) {
      const isTargetLiParent = targetNode.parentNode.tagName.toLowerCase() === "li";
      const insertAnchorNode = isTargetLiParent ? targetNode.parentNode : targetNode;
      const isTemplateLiParent = templateNode.parentNode.tagName.toLowerCase() === "li";
      const cloneTemplateNode = isTemplateLiParent ? templateNode.parentNode : templateNode;
      const targetHasAnchor = isTargetLiParent ? Boolean(insertAnchorNode.querySelector("a")) : insertAnchorNode.tagName.toLowerCase() === "a" || Boolean(insertAnchorNode.querySelector("a"));
      const shouldForceCreateAnchor = !targetHasAnchor && Boolean(targetNode.closest("header nav"));
      const anchorTag = targetHasAnchor || shouldForceCreateAnchor ? ensureAnchor(insertAnchorNode, isTargetLiParent) : null;
      cleanupQuickLinksForContainer(insertAnchorNode.parentNode, insertAnchorNode);
      const hasShortcutActive = navPresetLinks.some((link) => isCurrentPage(link.path));
      const renderedQuickAnchors = [];
      const renderedQuickItems = [];
      const quickHostNodes = [];
      if (isOnPresetPage && anchorTag && primaryLink) {
        setQuickLinkHostMark(insertAnchorNode, true);
        anchorTag.id = primaryLink.id;
        anchorTag.setAttribute(QUICK_LINK_MARK_ATTR, "1");
        anchorTag.href = primaryLink.href;
        setLinkText(anchorTag, primaryLink.text);
        applyLinkShortcut(anchorTag, primaryLink);
        renderedQuickAnchors.push(anchorTag);
        quickHostNodes.push(insertAnchorNode);
        setActiveStyle(anchorTag, isCurrentPage(primaryLink.path), shouldUseCompactButtons);
      } else {
        const wasQuickAnchor = Boolean(anchorTag) && (anchorTag.id && anchorTag.id.startsWith("custom-gh-btn-") || anchorTag.getAttribute(QUICK_LINK_MARK_ATTR) === "1");
        if (anchorTag && anchorTag.id && anchorTag.id.startsWith("custom-gh-btn-")) {
          anchorTag.removeAttribute("id");
        }
        if (anchorTag) {
          anchorTag.removeAttribute(QUICK_LINK_MARK_ATTR);
        }
        setQuickLinkHostMark(insertAnchorNode, false);
        setQuickLinkLastMark(insertAnchorNode, false);
        if (anchorTag && wasQuickAnchor) {
          anchorTag.removeAttribute("data-hotkey");
          anchorTag.removeAttribute("aria-keyshortcuts");
        }
        if (anchorTag) {
          setActiveStyle(anchorTag, !hasShortcutActive, shouldUseCompactButtons);
        }
      }
      let insertAfterNode = insertAnchorNode;
      const linksToRender = isOnPresetPage ? extraLinks : navPresetLinks;
      linksToRender.forEach((linkInfo) => {
        const newNode = cloneTemplateNode.cloneNode(true);
        const aTag = ensureAnchor(newNode, isTemplateLiParent);
        setQuickLinkHostMark(newNode, true);
        aTag.id = linkInfo.id;
        aTag.setAttribute(QUICK_LINK_MARK_ATTR, "1");
        aTag.href = linkInfo.href;
        setLinkText(aTag, linkInfo.text);
        applyLinkShortcut(aTag, linkInfo);
        renderedQuickAnchors.push(aTag);
        quickHostNodes.push(newNode);
        setActiveStyle(aTag, isCurrentPage(linkInfo.path), shouldUseCompactButtons);
        insertNodeAfter(insertAfterNode.parentNode, newNode, insertAfterNode);
        insertAfterNode = newNode;
        renderedQuickItems.push({
          anchor: aTag,
          hostNode: newNode,
          linkInfo
        });
      });
      quickHostNodes.forEach((node) => setQuickLinkLastMark(node, false));
      const lastQuickHostNode = quickHostNodes[quickHostNodes.length - 1];
      if (lastQuickHostNode) {
        setQuickLinkLastMark(lastQuickHostNode, true);
        stripBreadcrumbSeparatorsFromHost(lastQuickHostNode);
      }
      setupResponsiveQuickLinks({
        inlineItems: renderedQuickItems,
        referenceNode: insertAnchorNode,
        renderParent: insertAnchorNode.parentNode
      });
      reportHotkeyConflicts(renderedQuickAnchors.filter((anchor) => anchor.isConnected));
    }
  }

  // src/theme.js
  var themeSyncBound = false;
  var systemThemeQuery = null;
  function detectGitHubTheme() {
    const root = document.documentElement;
    const colorMode = String(root.getAttribute("data-color-mode") || "").toLowerCase();
    if (colorMode === "light" || colorMode === "dark") {
      return colorMode;
    }
    const rootStyle = getComputedStyle(root);
    const colorScheme = String(rootStyle.colorScheme || "").toLowerCase();
    if (colorScheme.includes("dark")) return "dark";
    if (colorScheme.includes("light")) return "light";
    if (!systemThemeQuery && typeof window.matchMedia === "function") {
      systemThemeQuery = window.matchMedia("(prefers-color-scheme: dark)");
    }
    return systemThemeQuery?.matches ? "dark" : "light";
  }
  function resolveThemePreference(preference = loadConfig().themePreference) {
    const safePreference = sanitizeThemePreference(preference);
    return safePreference === "auto" ? detectGitHubTheme() : safePreference;
  }
  function syncThemePreference() {
    const preference = sanitizeThemePreference(loadConfig().themePreference);
    const appliedTheme = resolveThemePreference(preference);
    document.documentElement.setAttribute(THEME_ATTR, appliedTheme);
    document.documentElement.setAttribute(THEME_SOURCE_ATTR, preference === "auto" ? "auto" : "custom");
    return appliedTheme;
  }
  function setThemePreference(preference) {
    updateConfig({ themePreference: preference });
    return syncThemePreference();
  }
  function bindThemePreferenceSync() {
    if (themeSyncBound) return;
    themeSyncBound = true;
    syncThemePreference();
    if (!systemThemeQuery && typeof window.matchMedia === "function") {
      systemThemeQuery = window.matchMedia("(prefers-color-scheme: dark)");
    }
    if (systemThemeQuery?.addEventListener) {
      systemThemeQuery.addEventListener("change", syncThemePreference);
    } else if (systemThemeQuery?.addListener) {
      systemThemeQuery.addListener(syncThemePreference);
    }
    const observer2 = new MutationObserver((mutations) => {
      const shouldSync = mutations.some((mutation) => mutation.type === "attributes" && (mutation.attributeName === "data-color-mode" || mutation.attributeName === "data-dark-theme" || mutation.attributeName === "data-light-theme"));
      if (shouldSync) {
        syncThemePreference();
      }
    });
    observer2.observe(document.documentElement, {
      attributes: true,
      attributeFilter: ["data-color-mode", "data-dark-theme", "data-light-theme"]
    });
  }

  // src/settings-panel.js
  var settingsEscHandler = null;
  function closeConfigPanel() {
    const overlay = document.getElementById(SETTINGS_OVERLAY_ID);
    if (overlay) overlay.remove();
    if (settingsEscHandler) {
      document.removeEventListener("keydown", settingsEscHandler);
      settingsEscHandler = null;
    }
  }
  function createPanelState(config) {
    const safeConfig = sanitizeConfig(config);
    return {
      order: safeConfig.orderKeys.slice(),
      enabledSet: new Set(safeConfig.enabledKeys)
    };
  }
  function reorderKeys(state, draggedKey, targetKey, placeAfter = false) {
    const fromIndex = state.order.indexOf(draggedKey);
    const targetIndex = state.order.indexOf(targetKey);
    if (fromIndex < 0 || targetIndex < 0 || fromIndex === targetIndex) return false;
    const [movedKey] = state.order.splice(fromIndex, 1);
    let insertIndex = targetIndex + (placeAfter ? 1 : 0);
    if (fromIndex < targetIndex) {
      insertIndex -= 1;
    }
    state.order.splice(insertIndex, 0, movedKey);
    return true;
  }
  function clearDragClasses(listEl) {
    const rows = listEl.querySelectorAll(".custom-gh-nav-settings-row");
    rows.forEach((row) => {
      row.classList.remove("custom-gh-nav-settings-row-dragging");
      row.classList.remove("custom-gh-nav-settings-row-drag-over");
    });
  }
  function renderPanelRows(listEl, state) {
    listEl.replaceChildren();
    state.order.forEach((key) => {
      const row = document.createElement("div");
      row.className = "custom-gh-nav-settings-row";
      row.draggable = true;
      row.title = t("dragRowTitle");
      row.dataset.rowKey = key;
      const left = document.createElement("label");
      left.className = "custom-gh-nav-settings-row-left";
      const checkbox = document.createElement("input");
      checkbox.type = "checkbox";
      checkbox.checked = state.enabledSet.has(key);
      checkbox.addEventListener("change", () => {
        if (checkbox.checked) {
          state.enabledSet.add(key);
        } else {
          state.enabledSet.delete(key);
        }
      });
      const text = document.createElement("span");
      text.textContent = `${getDisplayNameByKey(key)} (${key})`;
      left.appendChild(checkbox);
      left.appendChild(text);
      const actions = document.createElement("div");
      actions.className = "custom-gh-nav-settings-row-actions";
      const dragHandle = document.createElement("span");
      dragHandle.className = "custom-gh-nav-settings-drag-handle";
      dragHandle.textContent = "≡";
      dragHandle.title = t("dragHandleTitle");
      dragHandle.setAttribute("aria-hidden", "true");
      row.addEventListener("dragstart", (event) => {
        row.classList.add("custom-gh-nav-settings-row-dragging");
        listEl.dataset.dragKey = key;
        if (event.dataTransfer) {
          event.dataTransfer.effectAllowed = "move";
          event.dataTransfer.setData("text/plain", key);
        }
      });
      row.addEventListener("dragend", () => {
        delete listEl.dataset.dragKey;
        clearDragClasses(listEl);
      });
      row.addEventListener("dragover", (event) => {
        event.preventDefault();
        row.classList.add("custom-gh-nav-settings-row-drag-over");
        if (event.dataTransfer) {
          event.dataTransfer.dropEffect = "move";
        }
      });
      row.addEventListener("dragleave", () => {
        row.classList.remove("custom-gh-nav-settings-row-drag-over");
      });
      row.addEventListener("drop", (event) => {
        event.preventDefault();
        row.classList.remove("custom-gh-nav-settings-row-drag-over");
        const draggedKey = event.dataTransfer && event.dataTransfer.getData("text/plain") || listEl.dataset.dragKey || "";
        if (!draggedKey || draggedKey === key) return;
        const rect = row.getBoundingClientRect();
        const placeAfter = event.clientY > rect.top + rect.height / 2;
        if (reorderKeys(state, draggedKey, key, placeAfter)) {
          renderPanelRows(listEl, state);
        }
      });
      actions.appendChild(dragHandle);
      row.appendChild(left);
      row.appendChild(actions);
      listEl.appendChild(row);
    });
  }
  function openConfigPanel() {
    closeConfigPanel();
    ensureStyles();
    const state = createPanelState(loadConfig());
    const overlay = document.createElement("div");
    overlay.id = SETTINGS_OVERLAY_ID;
    const panel = document.createElement("div");
    panel.id = SETTINGS_PANEL_ID;
    const title = document.createElement("h3");
    title.className = "custom-gh-nav-settings-title";
    title.textContent = t("panelTitle");
    const desc = document.createElement("p");
    desc.className = "custom-gh-nav-settings-desc";
    desc.textContent = t("panelDesc");
    const list = document.createElement("div");
    list.className = "custom-gh-nav-settings-list";
    renderPanelRows(list, state);
    const message = document.createElement("div");
    message.id = SETTINGS_MESSAGE_ID;
    message.className = "custom-gh-nav-settings-message";
    message.setAttribute("role", "status");
    message.setAttribute("aria-live", "polite");
    const footer = document.createElement("div");
    footer.className = "custom-gh-nav-settings-footer";
    const resetBtn = document.createElement("button");
    resetBtn.type = "button";
    resetBtn.className = "custom-gh-nav-settings-btn";
    resetBtn.textContent = t("resetDefault");
    resetBtn.addEventListener("click", () => {
      state.order = DEFAULT_LINK_KEYS.slice();
      state.enabledSet = new Set(DEFAULT_LINK_KEYS);
      renderPanelRows(list, state);
      message.textContent = t("restoredPendingSave");
    });
    const cancelBtn = document.createElement("button");
    cancelBtn.type = "button";
    cancelBtn.className = "custom-gh-nav-settings-btn";
    cancelBtn.textContent = t("cancel");
    cancelBtn.addEventListener("click", closeConfigPanel);
    const saveBtn = document.createElement("button");
    saveBtn.type = "button";
    saveBtn.className = "custom-gh-nav-settings-btn custom-gh-nav-settings-btn-primary";
    saveBtn.textContent = t("saveAndRefresh");
    saveBtn.addEventListener("click", () => {
      const enabledKeys = state.order.filter((key) => state.enabledSet.has(key));
      if (!enabledKeys.length) {
        message.textContent = t("atLeastOneLink");
        return;
      }
      updateConfig({
        enabledKeys,
        orderKeys: state.order.slice()
      });
      closeConfigPanel();
      location.reload();
    });
    footer.appendChild(resetBtn);
    footer.appendChild(cancelBtn);
    footer.appendChild(saveBtn);
    panel.appendChild(title);
    panel.appendChild(desc);
    panel.appendChild(list);
    panel.appendChild(message);
    panel.appendChild(footer);
    overlay.appendChild(panel);
    overlay.addEventListener("click", (event) => {
      if (event.target === overlay) closeConfigPanel();
    });
    settingsEscHandler = (event) => {
      if (event.key === "Escape") closeConfigPanel();
    };
    document.addEventListener("keydown", settingsEscHandler);
    document.body.appendChild(overlay);
  }
  function registerConfigMenu() {
    if (typeof GM_registerMenuCommand !== "function") return;
    GM_registerMenuCommand(t("menuOpenSettings"), openConfigPanel);
    GM_registerMenuCommand(t("menuResetSettings"), () => {
      const shouldReset = confirm(t("resetConfirm"));
      if (!shouldReset) return;
      updateConfig({
        enabledKeys: DEFAULT_LINK_KEYS,
        orderKeys: DEFAULT_LINK_KEYS
      });
      closeConfigPanel();
      location.reload();
    });
    GM_registerMenuCommand(t("menuLangZh"), () => {
      setUiLangPreference("zh");
      closeConfigPanel();
      location.reload();
    });
    GM_registerMenuCommand(t("menuLangEn"), () => {
      setUiLangPreference("en");
      closeConfigPanel();
      location.reload();
    });
    GM_registerMenuCommand(t("menuLangAuto"), () => {
      setUiLangPreference("auto");
      closeConfigPanel();
      location.reload();
    });
    GM_registerMenuCommand(t("menuThemeLight"), () => {
      setThemePreference("light");
      closeConfigPanel();
    });
    GM_registerMenuCommand(t("menuThemeDark"), () => {
      setThemePreference("dark");
      closeConfigPanel();
    });
    GM_registerMenuCommand(t("menuThemeAuto"), () => {
      setThemePreference("auto");
      closeConfigPanel();
    });
  }

  // src/top-repositories.js
  var TOP_REPOSITORIES_HEADING_TEXT = "top repositories";
  var TOP_REPOSITORIES_BUTTON_CLASS = "custom-gh-top-repos-pin";
  var TOP_REPOSITORIES_BUTTON_ACTIVE_CLASS = "custom-gh-top-repos-pin-active";
  var TOP_REPOSITORIES_BUTTON_ICON_CLASS = "custom-gh-top-repos-pin-icon";
  var TOP_REPOSITORIES_DIVIDER_CLASS = "custom-gh-top-repos-divider";
  var TOP_REPOSITORIES_ROW_CLASS = "custom-gh-top-repos-row";
  var TOP_REPOSITORIES_LINK_CLASS = "custom-gh-top-repos-link";
  var TOP_REPOSITORIES_SHOW_MORE_PREFIXES = ["show more", "show less"];
  var SVG_NS = "http://www.w3.org/2000/svg";
  var RESERVED_FIRST_SEGMENTS = /* @__PURE__ */ new Set([
    "about",
    "account",
    "apps",
    "codespaces",
    "collections",
    "dashboard",
    "explore",
    "marketplace",
    "new",
    "notifications",
    "organizations",
    "orgs",
    "pulls",
    "repositories",
    "search",
    "sessions",
    "settings",
    "signup",
    "site",
    "sponsors",
    "stars",
    "topics",
    "trending",
    "users"
  ]);
  function normalizeText(text) {
    return String(text || "").replace(/\s+/g, " ").trim().toLowerCase();
  }
  function normalizeRepoKey(repoKey) {
    return normalizeText(repoKey).replace(/\s+/g, "");
  }
  function parseRepoInfoFromHref(href) {
    try {
      const url = new URL(href, location.origin);
      const segments = url.pathname.split("/").filter(Boolean);
      if (segments.length !== 2) return null;
      const owner = decodeURIComponent(segments[0] || "");
      const repo = decodeURIComponent(segments[1] || "");
      if (!owner || !repo) return null;
      if (RESERVED_FIRST_SEGMENTS.has(owner.toLowerCase())) return null;
      return {
        key: normalizeRepoKey(`${owner}/${repo}`),
        label: `${owner}/${repo}`
      };
    } catch (error) {
      return null;
    }
  }
  function getNodeDepth(node) {
    let depth = 0;
    let current = node;
    while (current && current.parentElement) {
      depth += 1;
      current = current.parentElement;
    }
    return depth;
  }
  function getDirectRepoRows(container) {
    if (!container) return [];
    const rowsByNode = /* @__PURE__ */ new Map();
    const anchors = Array.from(container.querySelectorAll('a[href^="/"]'));
    anchors.forEach((anchor) => {
      let rowNode = anchor;
      while (rowNode.parentElement && rowNode.parentElement !== container) {
        rowNode = rowNode.parentElement;
      }
      if (!rowNode.parentElement || rowNode.parentElement !== container) return;
      const repoInfo = parseRepoInfoFromHref(anchor.getAttribute("href") || "");
      if (!repoInfo) return;
      const existing = rowsByNode.get(rowNode);
      if (!existing) {
        rowsByNode.set(rowNode, {
          node: rowNode,
          anchor,
          repoKey: repoInfo.key,
          repoLabel: repoInfo.label
        });
        return;
      }
      if (anchor.textContent.trim().length > existing.anchor.textContent.trim().length) {
        existing.anchor = anchor;
        existing.repoKey = repoInfo.key;
        existing.repoLabel = repoInfo.label;
      }
    });
    return Array.from(rowsByNode.values());
  }
  function getTopRepositoriesHeading() {
    const candidates = Array.from(
      document.querySelectorAll('h1, h2, h3, h4, h5, h6, [role="heading"], summary, span, strong')
    );
    return candidates.find((node) => normalizeText(node.textContent) === TOP_REPOSITORIES_HEADING_TEXT) || null;
  }
  function findTopRepositoriesList() {
    const heading = getTopRepositoriesHeading();
    if (!heading) return null;
    const roots = [];
    const sectionRoot = heading.closest("section, aside");
    if (sectionRoot) roots.push(sectionRoot);
    if (heading.parentElement && !roots.includes(heading.parentElement)) {
      roots.push(heading.parentElement);
    }
    for (const root of roots) {
      const semanticCandidates = [
        ...root.matches("ul, ol, nav") ? [root] : [],
        ...Array.from(root.querySelectorAll("ul, ol, nav"))
      ];
      let bestSemanticMatch = null;
      semanticCandidates.forEach((candidate) => {
        const items = getDirectRepoRows(candidate);
        if (!items.length) return;
        const score = items.length * 1e3 + (items.length === candidate.children.length ? 100 : 0) + getNodeDepth(candidate);
        if (!bestSemanticMatch || score > bestSemanticMatch.score) {
          bestSemanticMatch = { container: candidate, items, score };
        }
      });
      if (bestSemanticMatch) {
        return { container: bestSemanticMatch.container, items: bestSemanticMatch.items };
      }
      const genericCandidates = [
        ...root.matches("div") ? [root] : [],
        ...Array.from(root.querySelectorAll("div"))
      ];
      let bestMatch = null;
      genericCandidates.forEach((candidate) => {
        const items = getDirectRepoRows(candidate);
        if (!items.length) return;
        const score = items.length * 1e3 + (items.length === candidate.children.length ? 100 : 0) + getNodeDepth(candidate);
        if (!bestMatch || score > bestMatch.score) {
          bestMatch = { container: candidate, items, score };
        }
      });
      if (bestMatch) {
        return { container: bestMatch.container, items: bestMatch.items };
      }
    }
    return null;
  }
  function sanitizePinnedRepositories(rawValue) {
    if (!Array.isArray(rawValue)) return [];
    const seen = /* @__PURE__ */ new Set();
    const result = [];
    rawValue.forEach((item) => {
      const repoKey = normalizeRepoKey(item);
      if (!repoKey || seen.has(repoKey)) return;
      seen.add(repoKey);
      result.push(repoKey);
    });
    return result;
  }
  function loadPinnedRepositories() {
    try {
      const raw = localStorage.getItem(TOP_REPOSITORIES_PIN_STORAGE_KEY);
      if (!raw) return [];
      return sanitizePinnedRepositories(JSON.parse(raw));
    } catch (error) {
      return [];
    }
  }
  function savePinnedRepositories(repoKeys) {
    const pinnedRepositories = sanitizePinnedRepositories(repoKeys);
    try {
      localStorage.setItem(TOP_REPOSITORIES_PIN_STORAGE_KEY, JSON.stringify(pinnedRepositories));
    } catch (error) {
    }
  }
  function togglePinnedRepository(repoKey) {
    const normalizedRepoKey = normalizeRepoKey(repoKey);
    if (!normalizedRepoKey) return;
    const pinnedSet = new Set(loadPinnedRepositories());
    if (pinnedSet.has(normalizedRepoKey)) {
      pinnedSet.delete(normalizedRepoKey);
    } else {
      pinnedSet.add(normalizedRepoKey);
    }
    savePinnedRepositories(Array.from(pinnedSet));
  }
  function createDividerElement(container) {
    const tagName = container.tagName.toLowerCase();
    const divider = document.createElement(tagName === "ul" || tagName === "ol" ? "li" : "div");
    divider.className = TOP_REPOSITORIES_DIVIDER_CLASS;
    divider.setAttribute("aria-hidden", "true");
    return divider;
  }
  function ensureRowNodeIsWrappable(item, container) {
    if (item.node.tagName.toLowerCase() !== "a") return item;
    const wrapperTag = container.tagName.toLowerCase() === "ul" || container.tagName.toLowerCase() === "ol" ? "li" : "div";
    const wrapper = document.createElement(wrapperTag);
    wrapper.className = TOP_REPOSITORIES_ROW_CLASS;
    item.node.replaceWith(wrapper);
    wrapper.appendChild(item.node);
    item.node = wrapper;
    return item;
  }
  function createSvgElement(name, attrs = {}) {
    const node = document.createElementNS(SVG_NS, name);
    Object.entries(attrs).forEach(([key, value]) => {
      node.setAttribute(key, String(value));
    });
    return node;
  }
  function createPinIcon(isPinned) {
    const svg = createSvgElement("svg", {
      viewBox: "0 0 16 16",
      "aria-hidden": "true",
      class: TOP_REPOSITORIES_BUTTON_ICON_CLASS
    });
    const head = createSvgElement("circle", {
      cx: "10",
      cy: "4",
      r: "1.9",
      fill: isPinned ? "currentColor" : "none",
      stroke: "currentColor",
      "stroke-width": "1.2"
    });
    const body = createSvgElement("rect", {
      x: "6.8",
      y: "5.4",
      width: "5.1",
      height: "2.5",
      rx: "0.8",
      fill: isPinned ? "currentColor" : "none",
      stroke: "currentColor",
      "stroke-width": "1.2",
      transform: "rotate(32 9.35 6.65)"
    });
    const needle = createSvgElement("path", {
      d: "M8.5 8.9 4.3 13.1",
      fill: "none",
      stroke: "currentColor",
      "stroke-width": "1.2",
      "stroke-linecap": "round"
    });
    svg.appendChild(head);
    svg.appendChild(body);
    svg.appendChild(needle);
    return svg;
  }
  function getPrimaryContentNode(item) {
    let current = item.anchor;
    while (current.parentElement && current.parentElement !== item.node) {
      if (current.parentElement.children.length !== 1) break;
      current = current.parentElement;
    }
    return current;
  }
  function renderPinButtons(container, items, pinnedSet) {
    items.forEach((item) => {
      ensureRowNodeIsWrappable(item, container);
      item.node.classList.add(TOP_REPOSITORIES_ROW_CLASS);
      getPrimaryContentNode(item).classList.add(TOP_REPOSITORIES_LINK_CLASS);
      item.node.querySelectorAll(`.${TOP_REPOSITORIES_BUTTON_CLASS}`).forEach((button) => button.remove());
      const isPinned = pinnedSet.has(item.repoKey);
      const pinButton = document.createElement("button");
      pinButton.type = "button";
      pinButton.className = TOP_REPOSITORIES_BUTTON_CLASS;
      pinButton.appendChild(createPinIcon(isPinned));
      pinButton.setAttribute("aria-pressed", isPinned ? "true" : "false");
      pinButton.title = isPinned ? t("unpinTopRepository", { repo: item.repoLabel }) : t("pinTopRepository", { repo: item.repoLabel });
      pinButton.setAttribute("aria-label", pinButton.title);
      if (isPinned) {
        pinButton.classList.add(TOP_REPOSITORIES_BUTTON_ACTIVE_CLASS);
      }
      pinButton.addEventListener("click", (event) => {
        event.preventDefault();
        event.stopPropagation();
        togglePinnedRepository(item.repoKey);
        enhanceTopRepositories();
      });
      item.node.appendChild(pinButton);
    });
  }
  function reorderRows(container, items, pinnedSet) {
    const pinnedItems = items.filter((item) => pinnedSet.has(item.repoKey));
    const regularItems = items.filter((item) => !pinnedSet.has(item.repoKey));
    container.querySelectorAll(`:scope > .${TOP_REPOSITORIES_DIVIDER_CLASS}`).forEach((node) => node.remove());
    const children = Array.from(container.children);
    const repoNodes = new Set(items.map((item) => item.node));
    const firstRepoIndex = children.findIndex((child) => repoNodes.has(child));
    const beforeRepoChildren = firstRepoIndex < 0 ? [] : children.slice(0, firstRepoIndex).filter((child) => !repoNodes.has(child));
    const afterRepoChildren = firstRepoIndex < 0 ? children.filter((child) => !repoNodes.has(child)) : children.slice(firstRepoIndex).filter((child) => !repoNodes.has(child));
    const orderedNodes = [
      ...pinnedItems.map((item) => item.node),
      ...pinnedItems.length && regularItems.length ? [createDividerElement(container)] : [],
      ...regularItems.map((item) => item.node)
    ];
    const fragment = document.createDocumentFragment();
    beforeRepoChildren.forEach((node) => fragment.appendChild(node));
    orderedNodes.forEach((node) => fragment.appendChild(node));
    afterRepoChildren.forEach((node) => fragment.appendChild(node));
    container.replaceChildren(fragment);
  }
  function isDashboardHomePage() {
    const path = location.pathname.replace(/\/+$/, "") || "/";
    return path === "/" || path === "/dashboard";
  }
  function hasTopRepositoriesHeading() {
    return Boolean(getTopRepositoriesHeading());
  }
  function needsTopRepositoriesEnhancement() {
    if (!isDashboardHomePage()) return false;
    const listMatch = findTopRepositoriesList();
    if (!listMatch || !listMatch.items.length) return false;
    return listMatch.items.some((item) => !item.node.querySelector(`.${TOP_REPOSITORIES_BUTTON_CLASS}`));
  }
  function isTopRepositoriesToggleTarget(target) {
    if (!(target instanceof Element)) return false;
    const heading = getTopRepositoriesHeading();
    if (!heading) return false;
    const root = heading.closest("section, aside") || heading.parentElement;
    if (!root) return false;
    const trigger = target.closest('button, a, summary, [role="button"]');
    if (!trigger || !root.contains(trigger)) return false;
    const expanded = trigger.getAttribute("aria-expanded");
    if (expanded === "true" || expanded === "false") return true;
    const text = normalizeText(trigger.textContent);
    return TOP_REPOSITORIES_SHOW_MORE_PREFIXES.some((prefix) => text.startsWith(prefix));
  }
  function enhanceTopRepositories() {
    if (!isDashboardHomePage()) return;
    const listMatch = findTopRepositoriesList();
    if (!listMatch || !listMatch.items.length) return;
    const pinnedSet = new Set(loadPinnedRepositories());
    renderPinButtons(listMatch.container, listMatch.items, pinnedSet);
    reorderRows(listMatch.container, listMatch.items, pinnedSet);
  }

  // src/main.js
  var renderQueued = false;
  function applyEnhancements() {
    syncThemePreference();
    ensureStyles();
    addCustomButtons();
    enhanceTopRepositories();
  }
  function scheduleEnhancements() {
    if (renderQueued) return;
    renderQueued = true;
    requestAnimationFrame(() => {
      renderQueued = false;
      applyEnhancements();
    });
  }
  console.info(`[Better GitHub Navigation] loaded v${SCRIPT_VERSION}`);
  window.__betterGithubNavVersion = SCRIPT_VERSION;
  window.__openBetterGithubNavSettings = openConfigPanel;
  bindThemePreferenceSync();
  registerConfigMenu();
  scheduleEnhancements();
  document.addEventListener("turbo:load", scheduleEnhancements);
  document.addEventListener("pjax:end", scheduleEnhancements);
  document.addEventListener("click", (event) => {
    if (!isTopRepositoriesToggleTarget(event.target)) return;
    setTimeout(scheduleEnhancements, 0);
  });
  var observer = new MutationObserver(() => {
    const hasHeader = Boolean(document.querySelector("header"));
    const hasCustomNavUi = Boolean(document.querySelector(
      '[id^="custom-gh-btn-"], [' + QUICK_LINK_MARK_ATTR + '="1"], [' + RESPONSIVE_TOGGLE_MARK_ATTR + '="1"]:not([hidden])'
    ));
    const missingNavButtons = hasHeader && !hasCustomNavUi;
    const missingTopRepoPins = isDashboardHomePage() && hasTopRepositoriesHeading() && needsTopRepositoriesEnhancement();
    if (missingNavButtons || missingTopRepoPins) scheduleEnhancements();
  });
  observer.observe(document.body, { childList: true, subtree: true });
})();