diff --git a/.github/javadoc/javadoc-footer.html b/.github/javadoc/javadoc-footer.html new file mode 100644 index 000000000..487326dfc --- /dev/null +++ b/.github/javadoc/javadoc-footer.html @@ -0,0 +1,44 @@ + diff --git a/.github/javadoc/javadoc-header.html b/.github/javadoc/javadoc-header.html new file mode 100644 index 000000000..782ae85db --- /dev/null +++ b/.github/javadoc/javadoc-header.html @@ -0,0 +1,11 @@ +
+ +
+ CustomNPC+ + Javadoc Reference +
+
+ + Back to Index + +
diff --git a/.github/javadoc/javadoc-theme.css b/.github/javadoc/javadoc-theme.css new file mode 100644 index 000000000..d7ceb8275 --- /dev/null +++ b/.github/javadoc/javadoc-theme.css @@ -0,0 +1,954 @@ +/* ============================================================ + CustomNPC+ — Javadoc Theme (Javadoc 11) + Tokyo Night — Styled Edition + ============================================================ */ + +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap'); + +:root { + /* ── Tokyo Night palette ── */ + --bg: #1a1b26; + --bg2: #1f2335; + --bg3: #24283b; + --bg-elevated: #292e42; + --border: #3b4261; + --border2: #414868; + --text: #c0caf5; + --text-mid: #a9b1d6; + --text-dim: #565f89; + --green: #9ece6a; + --green-dim: rgba(158, 206, 106, 0.12); + --blue: #7aa2f7; + --blue-dim: rgba(122, 162, 247, 0.12); + --amber: #e0af68; + --amber-dim: rgba(224, 175, 104, 0.10); + --purple: #bb9af7; + --purple-dim: rgba(187, 154, 247, 0.10); + --cyan: #7dcfff; + --cyan-dim: rgba(125, 207, 255, 0.10); + --red: #f7768e; + --highlight-bg: rgba(122, 162, 247, 0.08); + --hover-bg: rgba(187, 154, 247, 0.08); + --nav-h: 44px; + --subnav-h: 36px; + + /* ── Font stacks ── */ + --font-ui: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; + --font-mono: 'JetBrains Mono', 'Cascadia Code', 'Fira Code', monospace; +} + +* { box-sizing: border-box !important; } + +html, body { + height: 100%; +} + +body { + background: var(--bg) !important; + color: var(--text) !important; + font-family: var(--font-mono) !important; + font-size: 13px !important; + line-height: 1.6 !important; + margin: 0 !important; + padding: 0 !important; + min-height: 100vh !important; + display: flex !important; + flex-direction: column !important; +} + +.skipNav { display: none !important; } + +/* ══════════════════════════════════════════════ + NAVIGATION + ══════════════════════════════════════════════ */ + +.fixedNav { + position: fixed !important; + top: 0 !important; left: 0 !important; right: 0 !important; + z-index: 100 !important; +} + +/* Top bar — gradient accent stripe on top */ +.topNav { + position: relative !important; + background: var(--bg2) !important; + border-bottom: 1px solid var(--border) !important; + height: var(--nav-h) !important; + margin: 0 !important; padding: 0 !important; + display: flex !important; + align-items: stretch !important; + overflow: visible !important; +} + +/* Gradient accent line across the very top */ +.topNav::before { + content: '' !important; + position: absolute !important; + top: 0 !important; left: 0 !important; right: 0 !important; + height: 2px !important; + background: linear-gradient(90deg, var(--blue), var(--purple), var(--cyan)) !important; + z-index: 10 !important; +} + +/* Nav list — leave room on right for brand */ +.topNav > ul.navList { + list-style: none !important; + margin: 0 !important; + padding: 2px 0 0 8px !important; + padding-right: 320px !important; + display: flex !important; + align-items: stretch !important; + flex-shrink: 0 !important; +} + +.topNav > ul.navList > li { + display: flex !important; + align-items: center !important; + margin: 0 !important; + padding: 0 16px !important; + height: var(--nav-h) !important; + font-family: var(--font-ui) !important; + font-size: 12px !important; + font-weight: 500 !important; + white-space: nowrap !important; + text-transform: none !important; + letter-spacing: 0.01em !important; + color: var(--text-dim) !important; + border-bottom: 2px solid transparent !important; + transition: color 0.2s !important; +} + +.topNav > ul.navList > li > a { + display: flex !important; + align-items: center !important; + height: var(--nav-h) !important; + margin: 0 -16px !important; + padding: 0 16px !important; + color: var(--text-dim) !important; + font-family: var(--font-ui) !important; + font-size: 12px !important; + font-weight: 500 !important; + text-decoration: none !important; + text-transform: none !important; + letter-spacing: 0.01em !important; + white-space: nowrap !important; + border-bottom: 2px solid transparent !important; + transition: color 0.2s, border-color 0.2s !important; +} + +.topNav > ul.navList > li > a:hover { + color: var(--text) !important; + border-bottom-color: var(--purple) !important; + background: transparent !important; + text-shadow: none !important; + text-decoration: none !important; +} + +/* Active item — gradient underline */ +.topNav > ul.navList > li.navBarCell1Rev { + color: var(--text) !important; + border-image: linear-gradient(90deg, var(--blue), var(--purple)) 1 !important; + border-bottom-width: 2px !important; + border-bottom-style: solid !important; +} + +/* ── Brand — pinned to far right of topNav ── */ +.topNav > .aboutLanguage { + position: absolute !important; + top: 0 !important; right: 0 !important; + height: var(--nav-h) !important; + display: flex !important; + align-items: center !important; + gap: 12px !important; + padding: 0 16px !important; + background: var(--bg2) !important; + border-left: 1px solid var(--border) !important; + z-index: 5 !important; +} + +/* Hide the duplicate in bottom nav */ +.bottomNav > .aboutLanguage, +.bottomNav .aboutLanguage { + display: none !important; +} + +#javadoc-header { + display: flex !important; + align-items: center !important; + gap: 12px !important; +} + +.header-brand { text-decoration: none !important; } + +/* Brand title — gradient text */ +.header-title { + font-family: var(--font-ui) !important; + font-size: 14px !important; + font-weight: 700 !important; + background: linear-gradient(135deg, var(--blue), var(--purple)) !important; + -webkit-background-clip: text !important; + -webkit-text-fill-color: transparent !important; + background-clip: text !important; + line-height: 1.4 !important; + white-space: nowrap !important; +} + +.header-title span { + display: block !important; + font-family: var(--font-mono) !important; + font-size: 9px !important; + font-weight: 400 !important; + background: none !important; + -webkit-text-fill-color: var(--text-dim) !important; + color: var(--text-dim) !important; + margin-top: 1px !important; + letter-spacing: 0.1em !important; + text-transform: uppercase !important; +} + +.header-back { + display: inline-flex !important; + align-items: center !important; + text-decoration: none !important; + color: var(--text-dim) !important; + font-family: var(--font-ui) !important; + font-size: 11px !important; + font-weight: 500 !important; + padding: 5px 12px !important; + border: 1px solid var(--border2) !important; + border-radius: 6px !important; + white-space: nowrap !important; + transition: all 0.2s !important; +} + +.header-back:hover { + color: var(--text) !important; + border-color: var(--purple) !important; + background: var(--purple-dim) !important; + text-decoration: none !important; + text-shadow: none !important; +} + +/* ── Sub nav ── */ +.subNav { + background: var(--bg3) !important; + border-bottom: 1px solid var(--border) !important; + height: var(--subnav-h) !important; + margin: 0 !important; + padding: 0 14px !important; + display: flex !important; + align-items: center !important; + gap: 12px !important; + overflow: hidden !important; +} + +/* Search first */ +.subNav > ul.navListSearch { + order: -1 !important; +} + +.subNav ul, +.subNav ul.navList, +.subNav ul.subNavList, +.subNav ul.navListSearch { + list-style: none !important; + margin: 0 !important; + padding: 0 !important; + display: flex !important; + align-items: center !important; + gap: 0 !important; +} + +.subNav li { + display: flex !important; + align-items: center !important; + font-family: var(--font-ui) !important; + font-size: 11px !important; + color: var(--text-dim) !important; + padding: 0 6px !important; + white-space: nowrap !important; + border: none !important; + height: auto !important; + text-transform: none !important; +} + +.subNav a { + color: var(--blue) !important; + text-decoration: none !important; + font-size: 11px !important; + font-family: var(--font-ui) !important; + transition: color 0.15s !important; +} + +.subNav a:hover { color: var(--purple) !important; text-shadow: none !important; } + +.subNav label { + font-family: var(--font-ui) !important; + font-size: 11px !important; + color: var(--text-dim) !important; + text-transform: none !important; + margin-right: 4px !important; +} + +/* ══════════════════════════════════════════════ + CONTENT + ══════════════════════════════════════════════ */ + +main { + background: var(--bg) !important; + padding: 28px !important; + flex: 1 0 auto !important; +} + +.contentContainer, div.contentContainer { + background: var(--bg) !important; + padding: 0 28px 0px !important; +} + +.header { + padding: 0 28px 0 !important; + margin-bottom: 20px !important; +} + +/* Subtitle under h1 on help/overview pages */ +.header .subTitle, +div.subTitle { + color: var(--text-mid) !important; + font-family: var(--font-ui) !important; + font-size: 13px !important; + line-height: 1.7 !important; + margin-top: 8px !important; +} + +.packageLabelInType { + font-family: var(--font-mono) !important; + font-size: 11px !important; + color: var(--text-dim) !important; +} + +/* ── Headings ── */ +h1, h2, h3, h4, h5, h6 { + font-family: var(--font-ui) !important; + font-weight: 600 !important; + line-height: 1.5 !important; + text-transform: none !important; + letter-spacing: -0.01em !important; +} + +/* Page title — gradient accent bar */ +h1.title, h2.title { + font-size: 22px !important; + font-weight: 700 !important; + color: var(--text) !important; + border-bottom: none !important; + padding-bottom: 16px !important; + padding-left: 16px !important; + margin-bottom: 24px !important; + margin-top: 0 !important; + border-left: 4px solid transparent !important; + border-image: linear-gradient(180deg, var(--blue), var(--purple)) 1 !important; +} + +/* Section h2 — colored panel */ +section > h2, +li.blockList > section > h2 { + font-size: 14px !important; + color: var(--green) !important; + border-left: 3px solid var(--green) !important; + border-bottom: none !important; + padding: 10px 14px !important; + margin: 0 !important; + background: var(--green-dim) !important; +} + +/* Generic h2 (table section headers like "Method Summary") */ +h2 { + font-size: 14px !important; + color: var(--amber) !important; + border-bottom: none !important; + border-left: 3px solid var(--amber) !important; + padding: 8px 12px !important; + margin-top: 28px !important; + margin-bottom: 12px !important; + background: var(--amber-dim) !important; +} + +/* h3 — table section headers inside blockList */ +h3 { + font-size: 12px !important; + color: var(--text-mid) !important; + margin: 0 !important; + padding: 10px 14px !important; + background: var(--bg3) !important; + border-bottom: 1px solid var(--border) !important; +} + +/* h4 — method detail names */ +h4 { + font-size: 13px !important; + font-weight: 600 !important; + color: var(--cyan) !important; + margin: 0 !important; + padding: 10px 14px !important; + background: var(--bg3) !important; + border-bottom: 1px solid var(--border) !important; + border-left: 3px solid var(--cyan) !important; +} + +/* ── blockList sections — card-like containers ── */ +ul.blockList > li.blockList, +ul.blockListLast > li.blockList { + border: 1px solid var(--border) !important; + border-radius: 6px !important; + margin-bottom: 14px !important; + padding: 0 !important; + background: var(--bg2) !important; + overflow: hidden !important; +} + +/* Help page: section cards with padding around their content */ +ul.blockList > li.blockList > section { + padding: 0 !important; +} + +ul.blockList > li.blockList > section > p, +ul.blockList > li.blockList > section > ul:not(.blockList):not(.blockListLast) { + padding: 14px 18px !important; + margin: 0 !important; + color: var(--text-mid) !important; + font-family: var(--font-ui) !important; + font-size: 13px !important; + line-height: 1.7 !important; +} + +/* Nested lists inside section content */ +ul.blockList > li.blockList > section > ul:not(.blockList):not(.blockListLast) > li { + color: var(--text-mid) !important; + font-family: var(--font-ui) !important; + font-size: 13px !important; + padding: 3px 0 !important; + list-style: none !important; +} + +ul.blockList > li.blockList > section > ul:not(.blockList):not(.blockListLast) > li::before { + content: '\203A' !important; + color: var(--purple) !important; + margin-right: 8px !important; + font-weight: 700 !important; +} + +/* ── Inherited methods block ── */ +ul.blockList > li.blockList > h3, +ul.blockList > li.blockList > ul.blockList > li.blockList > h3 { + font-size: 11px !important; + color: var(--text-dim) !important; + padding: 8px 14px !important; + background: var(--bg3) !important; + border-bottom: 1px solid var(--border) !important; + margin: 0 !important; +} + +/* The comma-separated code block of inherited method names */ +ul.blockList > li.blockList > code, +li.blockList > code { + display: block !important; + padding: 10px 16px !important; + color: var(--text-dim) !important; + font-family: var(--font-mono) !important; + font-size: 12px !important; + background: var(--bg) !important; + border: none !important; + line-height: 1.8 !important; +} + +/* ── Inheritance chain ── */ +ul.inheritance { + list-style: none !important; + padding: 0 !important; + margin: 0 0 16px !important; + font-size: 12px !important; + color: var(--text-dim) !important; +} +ul.inheritance li { padding-left: 16px !important; } +ul.inheritance li:first-child { padding-left: 0 !important; } + +/* ── General content lists (help page) ── */ +main ul:not(.blockList):not(.blockListLast):not(.navList):not(.subNavList):not(.navListSearch):not(.inheritance) { + padding-left: 0 !important; + margin: 4px 0 4px 12px !important; + list-style: none !important; +} +main ul:not(.blockList):not(.blockListLast):not(.navList):not(.subNavList):not(.navListSearch):not(.inheritance) > li { + color: var(--text-mid) !important; + font-family: var(--font-ui) !important; + font-size: 13px !important; + padding: 3px 0 !important; + line-height: 1.7 !important; +} +main ul:not(.blockList):not(.blockListLast):not(.navList):not(.subNavList):not(.navListSearch):not(.inheritance) > li::before { + content: '\203A' !important; + color: var(--purple) !important; + margin-right: 8px !important; + font-weight: 700 !important; +} + +/* General paragraphs in content */ +main > div p, .contentContainer p { + color: var(--text-mid) !important; + font-family: var(--font-ui) !important; + font-size: 13px !important; + line-height: 1.7 !important; + margin: 8px 0 !important; +} + +/* Emphasized phrase */ +.emphasizedPhrase { + display: block !important; + color: var(--text-dim) !important; + font-family: var(--font-mono) !important; + font-size: 12px !important; + font-style: italic !important; + border-left: 2px solid var(--purple) !important; + padding: 8px 14px !important; + margin-top: 16px !important; + background: var(--purple-dim) !important; + border-radius: 0 4px 4px 0 !important; +} + +/* Bottom footer subNav */ +footer { + /*margin-top: auto;*/ +} +footer .subNav { + background: var(--bg3) !important; + border-top: 1px solid var(--border) !important; + border-bottom: none !important; + height: var(--subnav-h) !important; + padding: 0 14px !important; + display: flex !important; + align-items: center !important; + gap: 12px !important; + overflow: hidden !important; +} + +/* ══════════════════════════════════════════════ + TABLES + ══════════════════════════════════════════════ */ + +table { + width: 100% !important; + border-collapse: collapse !important; + border: 1px solid var(--border) !important; + border-radius: 6px !important; + margin: 16px 0 !important; + font-size: 13px !important; + overflow: hidden !important; +} + +caption { + background: var(--bg3) !important; + padding: 8px 14px !important; + text-align: left !important; + border-bottom: 1px solid var(--border2) !important; + caption-side: top !important; +} + +/* Table tabs — pill style */ +.activeTableTab, .tableTab { + font-family: var(--font-ui) !important; + font-size: 11px !important; + font-weight: 500 !important; + text-transform: none !important; + padding: 4px 12px !important; + border: 1px solid var(--border2) !important; + border-radius: 20px !important; + display: inline-block !important; + margin-right: 6px !important; + cursor: pointer !important; + transition: all 0.2s !important; +} + +.activeTableTab { + color: var(--text) !important; + border-color: var(--blue) !important; + background: var(--blue-dim) !important; +} + +.tableTab { color: var(--text-dim) !important; background: var(--bg3) !important; } +.tableTab a { color: var(--text-dim) !important; text-decoration: none !important; } +.tableTab a:hover { color: var(--text) !important; text-shadow: none !important; } + +/* Column headers */ +th[scope="col"] { + background: var(--bg-elevated) !important; + color: var(--text-dim) !important; + font-family: var(--font-ui) !important; + font-size: 10px !important; + font-weight: 600 !important; + letter-spacing: 0.06em !important; + text-transform: uppercase !important; + padding: 10px 14px !important; + border-bottom: 2px solid var(--border2) !important; + text-align: left !important; +} + +/* Data cells */ +th[scope="row"], td { + background: var(--bg2) !important; + color: var(--text) !important; + padding: 10px 14px !important; + border-bottom: 1px solid var(--border) !important; + vertical-align: top !important; + text-align: left !important; + font-family: var(--font-mono) !important; + font-size: 12px !important; + font-weight: 400 !important; + text-transform: none !important; + letter-spacing: 0 !important; + transition: background 0.15s !important; +} + +/* Stronger alternating row contrast */ +tr.altColor > td, tr.altColor > th[scope="row"] { background: var(--bg) !important; } +tr.rowColor > td, tr.rowColor > th[scope="row"] { background: var(--bg2) !important; } + +tr:hover > td, tr:hover > th[scope="row"] { + background: var(--purple-dim) !important; + border-bottom-color: rgba(187, 154, 247, 0.25) !important; +} +tr:hover > td a, tr:hover > th[scope="row"] a { + color: var(--purple) !important; +} + +/* ── Links ── */ +a, a:visited { color: var(--blue) !important; text-decoration: none !important; transition: color 0.15s !important; } +a:hover { color: var(--purple) !important; text-decoration: none !important; } +.memberNameLink a { color: var(--cyan) !important; font-weight: 500 !important; } +.memberNameLink a:hover { color: var(--purple) !important; } +.externalLink { color: var(--blue) !important; } + +/* ── Description blocks ── */ +div.block { + color: var(--text-mid) !important; + font-family: var(--font-ui) !important; + font-size: 13px !important; + line-height: 1.7 !important; + padding: 4px 0 !important; +} +ul.blockList > li.blockList > div.block{ padding: 12px 16px !important; margin: 0 !important; } + +/* ── Method detail ── */ +ul.blockList, ul.blockListLast { list-style: none !important; padding: 0 !important; margin: 0 !important; } +ul.blockList > li.blockList, ul.blockListLast > li.blockList { + border: 1px solid var(--border) !important; + border-radius: 6px !important; + margin-bottom: 12px !important; + padding: 0 !important; + overflow: hidden !important; +} + +/* Method/type signatures — accent left bar */ +pre.methodSignature, pre.typeSignature { + background: var(--bg2) !important; + border: none !important; + border-bottom: 1px solid var(--border) !important; + border-left: 3px solid var(--cyan) !important; + margin: 0 !important; + padding: 14px 18px !important; + font-family: var(--font-mono) !important; + font-size: 12px !important; + color: var(--text) !important; + overflow-x: auto !important; + white-space: pre-wrap !important; +} + +pre { + background: var(--bg2) !important; + border: 1px solid var(--border) !important; + border-left: 3px solid var(--blue) !important; + border-radius: 6px !important; + padding: 14px 18px !important; + font-family: var(--font-mono) !important; + font-size: 12px !important; + color: var(--text) !important; + overflow-x: auto !important; + margin: 0 !important; + white-space: pre-wrap !important; +} + +code { + font-family: var(--font-mono) !important; + font-size: 12px !important; + color: var(--cyan) !important; + background: var(--bg3) !important; + padding: 2px 6px !important; + border-radius: 4px !important; +} + +dl { padding: 12px 16px !important; margin: 0 !important; } +dt { margin-bottom: 4px !important; } +dd { margin: 0 0 8px 16px !important; color: var(--text-mid) !important; font-size: 12px !important; } + +.paramLabel, .returnLabel, .throwsLabel, .seeLabel, .simpleTagLabel { + font-family: var(--font-ui) !important; + font-size: 10px !important; + font-weight: 600 !important; + color: var(--purple) !important; + text-transform: uppercase !important; + letter-spacing: 0.06em !important; +} + +.typeNameLabel { color: var(--cyan) !important; } + +.deprecationBlock { + background: var(--amber-dim) !important; + border-left: 3px solid var(--amber) !important; + border-radius: 0 6px 6px 0 !important; + padding: 10px 14px !important; + color: var(--amber) !important; + font-size: 12px !important; +} + +/* ── Inputs ── */ +input[type="text"] { + background: var(--bg) !important; + border: 1px solid var(--border2) !important; + color: var(--text) !important; + font-family: var(--font-mono) !important; + font-size: 12px !important; + padding: 5px 12px !important; + outline: none !important; + border-radius: 6px !important; + transition: border-color 0.2s, box-shadow 0.2s !important; +} +input[type="text"]:focus { + border-color: var(--blue) !important; + box-shadow: 0 0 0 2px var(--blue-dim) !important; +} +input[type="reset"] { + background: var(--bg3) !important; + border: 1px solid var(--border2) !important; + color: var(--text-dim) !important; + font-family: var(--font-ui) !important; + font-size: 11px !important; + padding: 5px 12px !important; + cursor: pointer !important; + border-radius: 6px !important; + transition: all 0.2s !important; +} +input[type="reset"]:hover { + border-color: var(--text-dim) !important; + color: var(--text-mid) !important; +} + +/* ══════════════════════════════════════════════ + BOTTOM NAV + ══════════════════════════════════════════════ */ + +.bottomNav { + background: var(--bg2) !important; + border-top: 1px solid var(--border) !important; + min-height: var(--nav-h) !important; + padding: 0 !important; + margin-top: 32px !important; + overflow: hidden !important; + position: relative !important; +} + +/* Gradient accent line on bottom nav too */ +.bottomNav::after { + content: '' !important; + position: absolute !important; + bottom: 0 !important; left: 0 !important; right: 0 !important; + height: 2px !important; + background: linear-gradient(90deg, var(--blue), var(--purple), var(--cyan)) !important; +} + +.bottomNav ul.navList[title="Navigation"] { + list-style: none !important; + margin: 0 !important; + padding: 0 0 0 8px !important; + display: flex !important; + align-items: stretch !important; + height: var(--nav-h) !important; +} + +.bottomNav ul.navList[title="Navigation"] li { + display: flex !important; + align-items: center !important; + margin: 0 !important; + padding: 0 16px !important; + height: var(--nav-h) !important; + font-family: var(--font-ui) !important; + font-size: 12px !important; + font-weight: 500 !important; + white-space: nowrap !important; + text-transform: none !important; + letter-spacing: 0.01em !important; + color: var(--text-dim) !important; + border-top: 2px solid transparent !important; + transition: color 0.2s !important; +} + +.bottomNav ul.navList[title="Navigation"] li > a { + display: flex !important; + align-items: center !important; + height: var(--nav-h) !important; + margin: 0 -16px !important; + padding: 0 16px !important; + color: var(--text-dim) !important; + text-decoration: none !important; + font-family: var(--font-ui) !important; + font-size: 12px !important; + font-weight: 500 !important; + transition: color 0.2s !important; +} + +.bottomNav ul.navList[title="Navigation"] li > a:hover { + color: var(--text) !important; + text-shadow: none !important; +} + +.bottomNav ul.navList[title="Navigation"] li.navBarCell1Rev { + color: var(--text) !important; + border-image: linear-gradient(90deg, var(--blue), var(--purple)) 1 !important; + border-top-width: 2px !important; + border-top-style: solid !important; +} + +.bottomNav .aboutLanguage { + display: none !important; +} + +.legalCopy { + background: var(--bg2) !important; + color: var(--text-dim) !important; + font-size: 11px !important; + font-family: var(--font-ui) !important; + padding: 14px 18px !important; + text-align: center !important; + border-top: 1px solid var(--border) !important; +} + +/* ══════════════════════════════════════════════ + SEARCH RESULTS DROPDOWN (jQuery UI Autocomplete) + ══════════════════════════════════════════════ */ + +.ui-autocomplete { + background: var(--bg2) !important; + border: 1px solid var(--border2) !important; + border-radius: 8px !important; + max-height: 400px !important; + overflow-y: auto !important; + overflow-x: hidden !important; + z-index: 9999 !important; + list-style: none !important; + padding: 4px 0 !important; + margin: 4px 0 0 !important; + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.5), 0 0 0 1px rgba(122, 162, 247, 0.05) !important; +} + +/* Category headers */ +.ui-autocomplete .ui-autocomplete-category { + background: var(--bg-elevated) !important; + color: var(--text-dim) !important; + font-family: var(--font-ui) !important; + font-size: 10px !important; + font-weight: 600 !important; + text-transform: uppercase !important; + letter-spacing: 0.06em !important; + padding: 6px 14px !important; + border-bottom: 1px solid var(--border) !important; + border-top: 1px solid var(--border) !important; + cursor: default !important; +} + +/* Individual result items */ +.ui-autocomplete .ui-menu-item { + background: var(--bg2) !important; + margin: 0 !important; + list-style: none !important; +} + +.ui-autocomplete .ui-menu-item > div, +.ui-autocomplete .ui-menu-item-wrapper { + background: var(--bg2) !important; + color: var(--text) !important; + font-family: var(--font-mono) !important; + font-size: 12px !important; + padding: 7px 14px !important; + border: none !important; + border-left: 2px solid transparent !important; + cursor: pointer !important; + line-height: 1.5 !important; + transition: all 0.1s !important; +} + +/* Hover / focus state */ +.ui-autocomplete .ui-menu-item > div.ui-state-active, +.ui-autocomplete .ui-menu-item > div.ui-state-focus, +.ui-autocomplete .ui-menu-item-wrapper.ui-state-active, +.ui-autocomplete .ui-menu-item-wrapper.ui-state-focus, +.ui-autocomplete .ui-state-active, +.ui-autocomplete .ui-state-focus { + background: var(--purple-dim) !important; + color: var(--text) !important; + border: none !important; + border-left: 2px solid var(--purple) !important; + margin: 0 !important; +} + +/* Highlighted matching text */ +.resultHighlight { + color: var(--cyan) !important; + font-weight: 600 !important; +} + +/* Search tag result extras */ +.searchTagHolderResult { + color: var(--text-dim) !important; + font-size: 11px !important; +} + +.searchTagDescResult { + color: var(--text-dim) !important; + font-size: 11px !important; + font-style: italic !important; +} + +/* "No results found" */ +.ui-autocomplete .ui-menu-item:only-child > div { + color: var(--text-dim) !important; + font-style: italic !important; +} + +/* Override jQuery UI defaults */ +.ui-widget { + font-family: var(--font-mono) !important; +} + +.ui-widget-content { + background: var(--bg2) !important; + color: var(--text) !important; + border-color: var(--border2) !important; +} + +.ui-menu .ui-menu-item { + padding: 0 !important; +} + +/* Watermark style for search input placeholder */ +.watermark { + color: var(--text-dim) !important; +} + +/* ══════════════════════════════════════════════ + MISC + ══════════════════════════════════════════════ */ + +::-webkit-scrollbar { width: 8px; height: 8px; } +::-webkit-scrollbar-track { background: var(--bg); } +::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 4px; } +::-webkit-scrollbar-thumb:hover { background: var(--text-dim); } +::selection { background: rgba(187, 154, 247, 0.25); color: var(--text); } +hr { border: none !important; border-top: 1px solid var(--border) !important; margin: 24px 0 !important; } diff --git a/.github/pages/index.html b/.github/pages/index.html new file mode 100644 index 000000000..5e467c986 --- /dev/null +++ b/.github/pages/index.html @@ -0,0 +1,14 @@ + + + + + + Javadoc Index + + + + +
+ + + diff --git a/.github/pages/package-lock.json b/.github/pages/package-lock.json new file mode 100644 index 000000000..3e8db3276 --- /dev/null +++ b/.github/pages/package-lock.json @@ -0,0 +1,1679 @@ +{ + "name": "javadoc-index", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "javadoc-index", + "version": "1.0.0", + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.2.1", + "vite": "^7.3.1" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz", + "integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.28.5", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", + "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", + "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-compilation-targets": "^7.28.6", + "@babel/helper-module-transforms": "^7.28.6", + "@babel/helpers": "^7.28.6", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", + "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", + "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.28.6", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", + "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "dev": true, + "dependencies": { + "@babel/traverse": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", + "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.28.6", + "@babel/helper-validator-identifier": "^7.28.5", + "@babel/traverse": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.28.6.tgz", + "integrity": "sha512-S9gzZ/bz83GRysI7gAD4wPT/AI3uCnY+9xn+Mx/KPs2JwHJIz1W8PZkg2cqyt3RNOBM8ejcXhV6y8Og7ly/Dug==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz", + "integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==", + "dev": true, + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", + "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.28.6", + "@babel/parser": "^7.28.6", + "@babel/types": "^7.28.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", + "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/generator": "^7.29.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/types": "^7.29.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.0.tgz", + "integrity": "sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==", + "dev": true, + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.1.tgz", + "integrity": "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "baseline-browser-mapping": "^2.9.0", + "caniuse-lite": "^1.0.30001759", + "electron-to-chromium": "^1.5.263", + "node-releases": "^2.0.27", + "update-browserslist-db": "^1.2.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001777", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", + "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", + "dev": true + }, + "node_modules/esbuild": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", + "integrity": "sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.3", + "@esbuild/android-arm": "0.27.3", + "@esbuild/android-arm64": "0.27.3", + "@esbuild/android-x64": "0.27.3", + "@esbuild/darwin-arm64": "0.27.3", + "@esbuild/darwin-x64": "0.27.3", + "@esbuild/freebsd-arm64": "0.27.3", + "@esbuild/freebsd-x64": "0.27.3", + "@esbuild/linux-arm": "0.27.3", + "@esbuild/linux-arm64": "0.27.3", + "@esbuild/linux-ia32": "0.27.3", + "@esbuild/linux-loong64": "0.27.3", + "@esbuild/linux-mips64el": "0.27.3", + "@esbuild/linux-ppc64": "0.27.3", + "@esbuild/linux-riscv64": "0.27.3", + "@esbuild/linux-s390x": "0.27.3", + "@esbuild/linux-x64": "0.27.3", + "@esbuild/netbsd-arm64": "0.27.3", + "@esbuild/netbsd-x64": "0.27.3", + "@esbuild/openbsd-arm64": "0.27.3", + "@esbuild/openbsd-x64": "0.27.3", + "@esbuild/openharmony-arm64": "0.27.3", + "@esbuild/sunos-x64": "0.27.3", + "@esbuild/win32-arm64": "0.27.3", + "@esbuild/win32-ia32": "0.27.3", + "@esbuild/win32-x64": "0.27.3" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/node-releases": { + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/react": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", + "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz", + "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==", + "dependencies": { + "loose-envify": "^1.1.0", + "scheduler": "^0.23.2" + }, + "peerDependencies": { + "react": "^18.3.1" + } + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/scheduler": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz", + "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==", + "dependencies": { + "loose-envify": "^1.1.0" + } + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } +} diff --git a/.github/pages/package.json b/.github/pages/package.json new file mode 100644 index 000000000..c7ccaf335 --- /dev/null +++ b/.github/pages/package.json @@ -0,0 +1,19 @@ +{ + "name": "javadoc-index", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "build": "vite build", + "preview": "vite preview" + }, + "dependencies": { + "react": "^18.2.0", + "react-dom": "^18.2.0" + }, + "devDependencies": { + "@vitejs/plugin-react": "^4.2.1", + "vite": "^7.3.1" + } +} diff --git a/.github/pages/src/App.jsx b/.github/pages/src/App.jsx new file mode 100644 index 000000000..b306112fa --- /dev/null +++ b/.github/pages/src/App.jsx @@ -0,0 +1,64 @@ +import styles from './App.module.css' +import { useDocs } from './useDocs' +import TerminalHeader from './components/TerminalHeader' +import Section from './components/Section' +import { ReleaseCard, ExperimentalCard } from './components/Card' +import { LoadingState, ErrorState, EmptyState } from './components/States' +import Footer from './components/Footer' + +export default function App() { + const { data, loading, error } = useDocs() + + const releases = data?.releases || [] + const experimental = data?.experimental || [] + + return ( +
+ + + {/* ── Releases ── */} +
+ {loading ? ( + + ) : error ? ( + + ) : releases.length === 0 ? ( + + ) : ( +
+ {releases.map((r, i) => ( + + ))} +
+ )} +
+ + {/* ── Experimental ── */} +
+ {loading ? ( + + ) : error ? null : experimental.length === 0 ? ( + + ) : ( +
+ {experimental.map((b, i) => ( + + ))} +
+ )} +
+ + {!loading && !error && ( +
+ ) +} diff --git a/.github/pages/src/App.module.css b/.github/pages/src/App.module.css new file mode 100644 index 000000000..395790dac --- /dev/null +++ b/.github/pages/src/App.module.css @@ -0,0 +1,16 @@ +.root { + max-width: 1100px; + margin: 0 auto; + padding: 48px 32px 96px; +} + +.grid { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); + gap: 10px; +} + +@media (max-width: 600px) { + .root { padding: 24px 16px 64px; } + .grid { grid-template-columns: 1fr; } +} diff --git a/.github/pages/src/components/Card.jsx b/.github/pages/src/components/Card.jsx new file mode 100644 index 000000000..73b1f7cf0 --- /dev/null +++ b/.github/pages/src/components/Card.jsx @@ -0,0 +1,97 @@ +import styles from './Card.module.css' +import { REPO_NAME } from '../config' + +const BASE_PATH = `/${REPO_NAME}` + +function formatDate(iso) { + if (!iso) return null + try { + return new Intl.DateTimeFormat('en-GB', { + day: '2-digit', month: 'short', year: 'numeric' + }).format(new Date(iso)) + } catch (e) { return null } +} + +export function ReleaseCard({ release, index }) { + const isLatest = release.isLatest + const date = formatDate(release.date) + const cardClass = isLatest + ? styles.card + ' ' + styles.latest + : styles.card + ' ' + styles.release + + return ( + +
+
+ {isLatest && ( + ● latest + )} + release +
+ → +
+ +
+ v{release.version} +
+
+ {date && ( +
+ date + {date} +
+ )} +
+ path + {release.path}/ +
+
+
+ ) +} + +export function ExperimentalCard({ branch, index }) { + const date = formatDate(branch.date) + + return ( + +
+ + experimental + + → +
+ +
+ {branch.branch} +
+ +
+ {date && ( +
+ date + {date} +
+ )} + {branch.hash && ( +
+ sha + {branch.hash} +
+ )} +
+ path + {branch.path}/ +
+
+
+ ) +} diff --git a/.github/pages/src/components/Card.module.css b/.github/pages/src/components/Card.module.css new file mode 100644 index 000000000..b19f37f72 --- /dev/null +++ b/.github/pages/src/components/Card.module.css @@ -0,0 +1,143 @@ +.card { + display: block; + text-decoration: none; + background: var(--bg2); + border: 1px solid var(--border); + border-radius: 6px; + padding: 20px 22px; + transition: border-color 0.15s, background 0.15s, transform 0.15s; + position: relative; + overflow: hidden; + animation: fadeUp 0.35s ease both; +} + +.card::before { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; + height: 2px; + opacity: 0; + transition: opacity 0.15s; +} + +.release::before { background: var(--green); } +.latest::before { background: linear-gradient(90deg, var(--green), var(--blue)); } +.experimental::before { background: var(--amber); } + +.card:hover { + border-color: var(--border2); + background: var(--bg3); + transform: translateY(-2px); +} + +.card:hover::before { opacity: 1; } + +/* ── Header ── */ +.header { + display: flex; + align-items: center; + justify-content: space-between; + margin-bottom: 14px; +} + +.badges { + display: flex; + align-items: center; + gap: 6px; +} + +.badge { + font-size: 9px; + font-weight: 600; + letter-spacing: 0.12em; + text-transform: uppercase; + padding: 2px 8px; + border-radius: 2px; + border: 1px solid; +} + +.badgeLatest { + color: var(--green); + border-color: var(--green-dim); + background: rgba(57, 211, 83, 0.08); + animation: pulseBorder 2s ease infinite; +} + +.badgeRelease { + color: var(--text-dim); + border-color: var(--border2); + background: transparent; +} + +.badgeExperimental { + color: var(--amber); + border-color: var(--amber-dim); + background: rgba(240, 160, 48, 0.08); +} + +.arrow { + font-size: 14px; + color: var(--border2); + transition: color 0.15s, transform 0.15s; +} + +.card:hover .arrow { + color: var(--text-mid); + transform: translateX(3px); +} + +/* ── Version ── */ +.version { + font-size: 20px; + font-weight: 500; + color: var(--text); + margin-bottom: 4px; + letter-spacing: -0.01em; +} + +.latest .version { color: var(--green); } +.versionBranch { font-size: 16px; color: var(--amber); } + +/* ── Meta ── */ +.meta { + display: flex; + flex-direction: column; + gap: 3px; + margin-top: 12px; + padding-top: 12px; + border-top: 1px solid var(--border); +} + +.metaRow { + display: flex; + align-items: center; + gap: 8px; + font-size: 10px; + color: var(--text-dim); +} + +.metaKey { + min-width: 36px; + color: var(--text-dim); +} + +.metaVal { + color: var(--text-mid); + font-family: 'IBM Plex Mono', monospace; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.hash { color: var(--blue); } + +/* ── Animations ── */ +@keyframes fadeUp { + from { opacity: 0; transform: translateY(10px); } + to { opacity: 1; transform: translateY(0); } +} + +@keyframes pulseBorder { + 0%, 100% { border-color: var(--green-dim); } + 50% { border-color: var(--green); } +} diff --git a/.github/pages/src/components/Footer.jsx b/.github/pages/src/components/Footer.jsx new file mode 100644 index 000000000..503f5e0f4 --- /dev/null +++ b/.github/pages/src/components/Footer.jsx @@ -0,0 +1,29 @@ +import styles from './Footer.module.css' +import { REPO_OWNER, REPO_NAME } from '../useDocs' + +export default function Footer({ source }) { + const now = new Intl.DateTimeFormat('en-GB', { + day: '2-digit', month: 'short', year: 'numeric', + hour: '2-digit', minute: '2-digit', timeZoneName: 'short' + }).format(new Date()) + + return ( + + ) +} diff --git a/.github/pages/src/components/Footer.module.css b/.github/pages/src/components/Footer.module.css new file mode 100644 index 000000000..26424d3b6 --- /dev/null +++ b/.github/pages/src/components/Footer.module.css @@ -0,0 +1,36 @@ +.footer { + margin-top: 64px; + padding-top: 20px; + border-top: 1px solid var(--border); + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 8px; + font-size: 11px; + color: var(--text-dim); +} + +.dot { + display: inline-block; + width: 6px; + height: 6px; + border-radius: 50%; + background: var(--green); + margin-right: 6px; + animation: blink 2s ease infinite; +} + +.link { + color: var(--blue); + text-decoration: none; +} + +.link:hover { + text-decoration: underline; +} + +@keyframes blink { + 0%, 100% { opacity: 1; } + 50% { opacity: 0.3; } +} diff --git a/.github/pages/src/components/Section.jsx b/.github/pages/src/components/Section.jsx new file mode 100644 index 000000000..dc28e1dbd --- /dev/null +++ b/.github/pages/src/components/Section.jsx @@ -0,0 +1,18 @@ +import styles from './Section.module.css' + +export default function Section({ label, count, variant, children }) { + return ( +
+
+ {label} +
+ {count !== undefined && ( + + {count} {label.toLowerCase()}{count !== 1 ? 's' : ''} + + )} +
+ {children} +
+ ) +} diff --git a/.github/pages/src/components/Section.module.css b/.github/pages/src/components/Section.module.css new file mode 100644 index 000000000..00f90a81a --- /dev/null +++ b/.github/pages/src/components/Section.module.css @@ -0,0 +1,46 @@ +.section { + margin-top: 40px; + margin-bottom: 8px; +} + +.header { + display: flex; + align-items: center; + gap: 12px; + margin-bottom: 16px; +} + +.tag { + font-size: 10px; + font-weight: 600; + letter-spacing: 0.15em; + text-transform: uppercase; + padding: 3px 10px; + border-radius: 3px; + border: 1px solid; + white-space: nowrap; +} + +.releases { + color: var(--green); + border-color: var(--green-dim); + background: rgba(57, 211, 83, 0.06); +} + +.experimental { + color: var(--amber); + border-color: var(--amber-dim); + background: rgba(240, 160, 48, 0.06); +} + +.line { + flex: 1; + height: 1px; + background: var(--border); +} + +.count { + font-size: 11px; + color: var(--text-dim); + white-space: nowrap; +} diff --git a/.github/pages/src/components/States.jsx b/.github/pages/src/components/States.jsx new file mode 100644 index 000000000..2827d401a --- /dev/null +++ b/.github/pages/src/components/States.jsx @@ -0,0 +1,30 @@ +import styles from './States.module.css' + +export function LoadingState() { + return ( +
+
+

Fetching documentation index...

+
+ ) +} + +export function ErrorState({ message }) { + return ( +
+
⚠
+

{message}

+

+ Check that the gh-pages branch exists and is publicly accessible. +

+
+ ) +} + +export function EmptyState({ label }) { + return ( +
+

No {label} found.

+
+ ) +} diff --git a/.github/pages/src/components/States.module.css b/.github/pages/src/components/States.module.css new file mode 100644 index 000000000..319fc6e52 --- /dev/null +++ b/.github/pages/src/components/States.module.css @@ -0,0 +1,47 @@ +.box { + border: 1px solid var(--border); + border-radius: 6px; + padding: 48px; + text-align: center; + background: var(--bg2); +} + +.empty { + padding: 24px; +} + +.spinner { + width: 22px; + height: 22px; + border: 2px solid var(--border2); + border-top-color: var(--green); + border-radius: 50%; + animation: spin 0.75s linear infinite; + margin: 0 auto 14px; +} + +.label { + font-size: 12px; + color: var(--text-dim); +} + +.errorIcon { + font-size: 22px; + margin-bottom: 10px; + color: var(--red); +} + +.errorMsg { + font-size: 13px; + color: var(--red); + margin-bottom: 6px; +} + +.errorSub { + font-size: 11px; + color: var(--text-dim); +} + +@keyframes spin { + to { transform: rotate(360deg); } +} diff --git a/.github/pages/src/components/TerminalHeader.jsx b/.github/pages/src/components/TerminalHeader.jsx new file mode 100644 index 000000000..e2efb2779 --- /dev/null +++ b/.github/pages/src/components/TerminalHeader.jsx @@ -0,0 +1,186 @@ +import { useState, useEffect } from 'react' +import styles from './TerminalHeader.module.css' +import { PROJECT_NAME, REPO_NAME, LINKS, AUTHORS } from '../config' + +function useGitHubProfile(username) { + const [profile, setProfile] = useState(null) + const [loading, setLoading] = useState(true) + + useEffect(() => { + const cacheKey = 'gh-profile-' + username + + // Check sessionStorage first — avoids hammering the API on every render + try { + const cached = sessionStorage.getItem(cacheKey) + if (cached) { + setProfile(JSON.parse(cached)) + setLoading(false) + return + } + } catch (e) {} + + fetch('https://api.github.com/users/' + username) + .then(r => { + if (!r.ok) throw new Error('HTTP ' + r.status) + return r.json() + }) + .then(d => { + // Don't cache error responses like rate limit messages + if (!d.message) { + try { sessionStorage.setItem(cacheKey, JSON.stringify(d)) } catch (e) {} + } + setProfile(d) + setLoading(false) + }) + .catch(() => setLoading(false)) + }, [username]) + + return { profile, loading } +} + +function AuthorTile({ username, active }) { + const { profile, loading } = useGitHubProfile(username) + const tileClass = styles.authorTile + (active ? ' ' + styles.authorTileActive : '') + + if (loading) { + return ( +
+
+
+
+
+
+
+
+ ) + } + + if (!profile || profile.message) { + return ( + +
+
+ {username} + @{username} +
+
+
+ ) + } + + return ( + + {profile.login} +
+ {profile.name || profile.login} + @{profile.login} + {profile.bio + ? {profile.bio} + :
+ } +
+
+ ) +} + +function AuthorsTiles() { + const [active, setActive] = useState(0) + + useEffect(() => { + if (AUTHORS.length <= 1) return + const t = setInterval(() => { + setActive(i => (i + 1) % AUTHORS.length) + }, 4000) + return () => clearInterval(t) + }, []) + + return ( +
+
+ › Authors: +
+
+ {AUTHORS.map((username, i) => ( + + ))} +
+
+ ) +} + +export default function TerminalHeader() { + return ( +
+
+
+
+
+ javadoc-index — bash +
+
+

+ {PROJECT_NAME} +

+ +
+ $ + browse-docs + {REPO_NAME} + --all-versions +
+ +
+ › Fetching available documentation builds... +
+
+ › Found project links: +
+ +
+ {LINKS.map(function(l) { + return ( + + + {l.tag} + + {l.label} + ↗ + + ) + })} +
+ + + +
+ $ + +
+
+
+ ) +} diff --git a/.github/pages/src/components/TerminalHeader.module.css b/.github/pages/src/components/TerminalHeader.module.css new file mode 100644 index 000000000..84853abac --- /dev/null +++ b/.github/pages/src/components/TerminalHeader.module.css @@ -0,0 +1,303 @@ +.wrap { + margin-bottom: 48px; +} + +.bar { + display: flex; + align-items: center; + gap: 6px; + background: var(--bg3); + border: 1px solid var(--border2); + border-bottom: none; + border-radius: 8px 8px 0 0; + padding: 10px 16px; +} + +.dot { + width: 12px; + height: 12px; + border-radius: 50%; +} +.red { background: #ff5f57; } +.amber { background: #febc2e; } +.green { background: #28c840; } + +.title { + margin-left: 8px; + font-size: 11px; + color: var(--text-dim); + letter-spacing: 0.05em; +} + +.body { + background: var(--bg2); + border: 1px solid var(--border2); + border-radius: 0 0 8px 8px; + padding: 16px 36px 36px; +} + +/* ── Heading ── */ +.heading { + font-family: 'IBM Plex Sans', sans-serif; + font-size: clamp(28px, 5vw, 52px); + font-weight: 300; + letter-spacing: -0.02em; + color: var(--text); + line-height: 1.05; + margin-bottom: 20px; +} + +.heading strong { + font-weight: 600; + color: var(--green); +} + +/* ── Prompt ── */ +.promptLine { + display: flex; + align-items: baseline; + gap: 10px; + margin-bottom: 6px; + font-size: 13px; + flex-wrap: wrap; +} + +.prompt { color: var(--green); font-weight: 600; } +.cmd { color: var(--text); } +.arg { color: var(--blue); } +.flag { color: var(--amber); } + +/* ── Output lines ── */ +.outputLine { + font-size: 12px; + color: var(--text-dim); + line-height: 1.8; + padding-left: 20px; +} + +.chevron { + color: var(--text-mid); + margin-right: 4px; +} + +/* ── Links ── */ +.links { + display: flex; + flex-direction: column; + gap: 4px; + padding-left: 36px; + margin-top: 4px; + margin-bottom: 12px; +} + +.link { + display: inline-flex; + align-items: center; + gap: 10px; + text-decoration: none; + padding: 3px 0; + width: fit-content; + transition: opacity 0.15s; +} + +.link:hover { opacity: 0.8; } + +.link:hover .linkLabel { + text-decoration: underline; + text-underline-offset: 3px; +} + +.linkTag { + font-size: 9px; + font-weight: 600; + letter-spacing: 0.1em; + border: 1px solid; + border-radius: 2px; + padding: 1px 5px; + min-width: 28px; + text-align: center; + opacity: 0.9; + font-family: 'IBM Plex Mono', monospace; +} + +.linkLabel { + font-size: 12px; + color: var(--text-mid); + font-family: 'IBM Plex Mono', monospace; +} + +.linkArrow { + font-size: 11px; + opacity: 0.6; + transition: opacity 0.15s, transform 0.15s; +} + +.link:hover .linkArrow { + opacity: 1; + transform: translate(2px, -2px); +} + +/* ── Authors ── */ +.authors { + margin-bottom: 8px; +} + +.authorRow { + display: flex; + flex-direction: row; + gap: 8px; + padding-left: 36px; + margin-top: 6px; + flex-wrap: wrap; +} + +/* ── Author tile ── */ +.authorTile { + display: flex; + align-items: center; + gap: 10px; + background: var(--bg3); + border: 1px solid var(--border); + border-radius: 6px; + padding: 8px 12px; + text-decoration: none; + cursor: pointer; + /* width is dynamic — grows with content */ + width: max-content; + min-width: 140px; + position: relative; + overflow: hidden; + transition: border-color 0.2s, background 0.2s, transform 0.2s; +} + +.authorTile::before { + content: ''; + position: absolute; + top: 0; left: 0; right: 0; + height: 2px; + background: var(--green); + opacity: 0; + transition: opacity 0.2s; +} + +.authorTileActive::before, +.authorTile:hover::before { + opacity: 1; +} + +.authorTileActive { + border-color: var(--green-dim); + background: rgba(57, 211, 83, 0.04); +} + +.authorTile:hover { + border-color: var(--border2); + background: #161b22; + transform: translateY(-1px); +} + +/* ── Author content ── */ +.authorAvatar { + width: 32px; + height: 32px; + border-radius: 50%; + border: 1px solid var(--border2); + flex-shrink: 0; +} + +.authorAvatarSkeleton { + width: 32px; + height: 32px; + border-radius: 50%; + background: var(--border2); + flex-shrink: 0; + animation: shimmer 1.5s ease infinite; +} + +.authorInfo { + display: flex; + flex-direction: column; + gap: 2px; + min-width: 0; +} + +.authorName { + font-size: 12px; + font-weight: 500; + color: var(--text); + font-family: 'IBM Plex Sans', sans-serif; + white-space: nowrap; +} + +.authorLogin { + font-size: 10px; + color: var(--blue); + font-family: 'IBM Plex Mono', monospace; + white-space: nowrap; +} + +/* Bio — always reserves vertical height, width animates open */ +.authorBio { + display: block; + font-size: 10px; + color: var(--text-dim); + font-family: 'IBM Plex Sans', sans-serif; + margin-top: 2px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + /* always reserve vertical space */ + height: 14px; + /* collapsed horizontally */ + width: 0; + opacity: 0; + transition: opacity 0.25s ease, width 0.3s ease; +} + +.authorTileActive .authorBio, +.authorTile:hover .authorBio { + width: 200px; + opacity: 1; +} + +/* Placeholder for loading/no-profile/no-bio states */ +.authorBioPlaceholder { + height: 14px; + margin-top: 2px; + width: 0; /* never takes horizontal space, never expands */ +} + +.authorSkeleton { + height: 9px; + border-radius: 4px; + background: var(--border2); + animation: shimmer 1.5s ease infinite; +} + +/* ── Cursor ── */ +.cursor { + display: inline-block; + width: 8px; + height: 13px; + background: var(--green); + margin-left: 2px; + vertical-align: text-bottom; + animation: blink 1s step-end infinite; +} + +/* ── Animations ── */ +@keyframes blink { + 0%, 100% { opacity: 1; } + 50% { opacity: 0; } +} + +@keyframes shimmer { + 0%, 100% { opacity: 0.4; } + 50% { opacity: 0.8; } +} + +@media (max-width: 600px) { + .body { padding: 20px; } + .links { padding-left: 20px; } + .authorRow { padding-left: 20px; } +} diff --git a/.github/pages/src/config.js b/.github/pages/src/config.js new file mode 100644 index 000000000..ed7a4baf9 --- /dev/null +++ b/.github/pages/src/config.js @@ -0,0 +1,38 @@ +// ─── Project Configuration ─────────────────────────────────── +// This is the ONLY file that should differ between projects. +// Everything else in the pages app is generic. +// ───────────────────────────────────────────────────────────── + +export const PROJECT_NAME = 'CustomNPC+' +export const REPO_OWNER = 'KAMKEEL' +export const REPO_NAME = 'CustomNPC-Plus' + +export const LINKS = [ + { + tag: 'GH', + label: 'github.com/KAMKEEL/CustomNPC-Plus', + href: 'https://github.com/KAMKEEL/CustomNPC-Plus', + color: '#e6edf3', + }, + { + tag: 'DC', + label: 'discord.gg/94qmjEDxkp', + href: 'https://discord.gg/94qmjEDxkp', + color: '#5865f2', + }, + { + tag: 'CF', + label: 'curseforge.com/minecraft/mc-mods/customnpc-plus', + href: 'https://www.curseforge.com/minecraft/mc-mods/customnpc-plus', + color: '#f16436', + }, + { + tag: 'MR', + label: 'modrinth.com/mod/customnpc-plus', + href: 'https://modrinth.com/mod/customnpc-plus/', + color: '#1bd96a', + }, +] + +// GitHub usernames — profiles are fetched at runtime +export const AUTHORS = ['kamkeel', 'c0508383', 'bigguy345', 'somehussar'] diff --git a/.github/pages/src/index.css b/.github/pages/src/index.css new file mode 100644 index 000000000..fef4fe128 --- /dev/null +++ b/.github/pages/src/index.css @@ -0,0 +1,50 @@ +*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } + +:root { + --bg: #080b0f; + --bg2: #0d1117; + --bg3: #131920; + --border: #1e2936; + --border2: #253040; + --green: #39d353; + --green-dim: #1a6b2a; + --amber: #f0a030; + --amber-dim: #7a4e10; + --blue: #58a6ff; + --blue-dim: #1a3a6b; + --text: #cdd9e5; + --text-dim: #636e7b; + --text-mid: #8b949e; + --red: #f85149; +} + +html, body { + height: 100%; + background: var(--bg); + color: var(--text); + font-family: 'IBM Plex Mono', monospace; + overflow-x: hidden; +} + +/* Scanlines */ +body::after { + content: ''; + position: fixed; + inset: 0; + background: repeating-linear-gradient( + 0deg, + transparent, + transparent 2px, + rgba(0,0,0,0.025) 2px, + rgba(0,0,0,0.025) 4px + ); + pointer-events: none; + z-index: 9999; +} + +a { color: inherit; text-decoration: none; } + +::-webkit-scrollbar { width: 6px; } +::-webkit-scrollbar-track { background: var(--bg2); } +::-webkit-scrollbar-thumb { background: var(--border2); border-radius: 3px; } +::-webkit-scrollbar-thumb:hover { background: var(--text-dim); } diff --git a/.github/pages/src/main.jsx b/.github/pages/src/main.jsx new file mode 100644 index 000000000..22bbe14e1 --- /dev/null +++ b/.github/pages/src/main.jsx @@ -0,0 +1,13 @@ +import React from 'react' +import ReactDOM from 'react-dom/client' +import App from './App' +import { PROJECT_NAME } from './config' +import './index.css' + +document.title = `${PROJECT_NAME} — Javadoc Index` + +ReactDOM.createRoot(document.getElementById('root')).render( + + + +) diff --git a/.github/pages/src/useDocs.js b/.github/pages/src/useDocs.js new file mode 100644 index 000000000..1c8c5b803 --- /dev/null +++ b/.github/pages/src/useDocs.js @@ -0,0 +1,94 @@ +import { useState, useEffect } from 'react' +import { REPO_OWNER, REPO_NAME } from './config' + +const BASE_PATH = `/${REPO_NAME}` +const API_BASE = `https://api.github.com/repos/${REPO_OWNER}/${REPO_NAME}` + +// Cache bust on every page load — appends current timestamp to manifest URL +// so the browser never serves a stale manifest.json +async function fetchFromManifest() { + const bust = `?t=${Date.now()}` + const res = await fetch(`${BASE_PATH}/manifest.json${bust}`, { + cache: 'no-store', // tells browser not to cache this request at all + }) + if (!res.ok) throw new Error('No manifest') + return res.json() +} + +async function fetchFromGitHubAPI() { + const refRes = await fetch(`${API_BASE}/git/ref/heads/gh-pages`) + if (!refRes.ok) throw new Error('gh-pages branch not found') + const refData = await refRes.json() + const sha = refData.object.sha + + const treeRes = await fetch(`${API_BASE}/git/trees/${sha}?recursive=1`) + if (!treeRes.ok) throw new Error('Could not fetch tree') + const treeData = await treeRes.json() + + const commitsRes = await fetch(`${API_BASE}/commits?sha=gh-pages&per_page=100`) + const commits = commitsRes.ok ? await commitsRes.json() : [] + + const commitMap = {} + commits.forEach(c => { + const date = c.commit?.committer?.date || c.commit?.author?.date || '' + const hash = c.sha?.slice(0, 7) || '' + const msg = c.commit?.message || '' + const vMatch = msg.match(/releases\/([\d.]+)/) + if (vMatch) commitMap[`releases/${vMatch[1]}`] = { date, hash } + const eMatch = msg.match(/experimental\/([\w-]+)/) + if (eMatch) commitMap[`experimental/${eMatch[1]}`] = { date, hash } + }) + + const releaseDirs = new Set() + const experimentalDirs = new Set() + + treeData.tree.forEach(item => { + if (item.type !== 'tree') return + const parts = item.path.split('/') + if (parts[0] === 'releases' && parts.length === 2) releaseDirs.add(parts[1]) + if (parts[0] === 'experimental' && parts.length === 2) experimentalDirs.add(parts[1]) + }) + + // Sort releases newest first, mark first as latest + const sortedReleases = [...releaseDirs] + .sort((a, b) => b.localeCompare(a, undefined, { numeric: true })) + + const releases = sortedReleases.map((v, i) => { + const c = commitMap[`releases/${v}`] || {} + return { + id: v, + version: v, + path: `releases/${v}`, + date: c.date, + hash: c.hash, + isLatest: i === 0, // newest version is always latest + } + }) + + const experimental = [...experimentalDirs].sort().map(b => { + const c = commitMap[`experimental/${b}`] || {} + return { id: b, branch: b, path: `experimental/${b}`, date: c.date, hash: c.hash } + }) + + return { releases, experimental, source: 'api' } +} + +export function useDocs() { + const [data, setData] = useState(null) + const [loading, setLoading] = useState(true) + const [error, setError] = useState(null) + + useEffect(() => { + fetchFromManifest() + .then(d => { setData(d); setLoading(false) }) + .catch(() => + fetchFromGitHubAPI() + .then(d => { setData(d); setLoading(false) }) + .catch(e => { setError(e.message); setLoading(false) }) + ) + }, []) + + return { data, loading, error } +} + +export { BASE_PATH, REPO_OWNER, REPO_NAME } diff --git a/.github/pages/vite.config.js b/.github/pages/vite.config.js new file mode 100644 index 000000000..1b00c454f --- /dev/null +++ b/.github/pages/vite.config.js @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import { REPO_NAME } from './src/config.js' + +export default defineConfig({ + plugins: [react()], + base: `/${REPO_NAME}/`, + build: { + outDir: '../../.github/pages-dist', + emptyOutDir: true, + } +}) diff --git a/.github/scripts/doc-config.sh b/.github/scripts/doc-config.sh new file mode 100644 index 000000000..37f6a0d90 --- /dev/null +++ b/.github/scripts/doc-config.sh @@ -0,0 +1,18 @@ +#!/bin/bash +# ----------------------------------------------- +# doc-config.sh — shared config for javadoc deploy +# +# Sourced by: +# - resolve-doc-path.sh +# - javadoc.yml (via sanity-check job) +# +# ADD WHITELISTED BRANCHES HERE AND NOWHERE ELSE. +# main is always handled automatically. +# ----------------------------------------------- + +MAIN_BRANCH_NAME="master" + +EXPERIMENTAL_WHITELIST=( + "dev" + # "new-branch" +) diff --git a/.github/scripts/generate-index.sh b/.github/scripts/generate-index.sh new file mode 100644 index 000000000..7651a800e --- /dev/null +++ b/.github/scripts/generate-index.sh @@ -0,0 +1,107 @@ +#!/bin/bash +set -e + +RELEASES=() +EXPERIMENTAL=() + +# Collect releases +if [ -d "./releases" ]; then + for dir in ./releases/*/; do + [ -d "$dir" ] || continue + name=$(basename "$dir") + RELEASES+=("$name") + done +fi + +# Collect experimental branches +if [ -d "./experimental" ]; then + for dir in ./experimental/*/; do + [ -d "$dir" ] || continue + name=$(basename "$dir") + EXPERIMENTAL+=("$name") + done +fi + +# Sort releases in reverse semver order (newest first) +if [ ${#RELEASES[@]} -gt 0 ]; then + IFS=$'\n' RELEASES=($(sort -rV <<< "${RELEASES[*]}")); unset IFS +fi + +# ── Store source commit metadata for this deploy ─────────────── +# DEPLOY_PATH, SOURCE_HASH, SOURCE_DATE are passed in as env vars from the workflow +if [ -n "$DEPLOY_PATH" ] && [ -n "$SOURCE_HASH" ]; then + mkdir -p ".doc-meta" + META_KEY="${DEPLOY_PATH//\//_}" + cat > ".doc-meta/${META_KEY}.json" << JSON +{"hash":"${SOURCE_HASH}","date":"${SOURCE_DATE}"} +JSON + echo "Stored source metadata for $DEPLOY_PATH → $SOURCE_HASH @ $SOURCE_DATE" +fi + +# ── Helper: get source commit hash + date for a path ────────── +get_commit_info() { + local path="$1" + + # If this is the path we just deployed, use the injected source commit + if [ "$path" = "$DEPLOY_PATH" ] && [ -n "$SOURCE_HASH" ]; then + echo "${SOURCE_HASH} ${SOURCE_DATE}" + return + fi + + # Try reading from stored metadata file (set by previous deploys) + local meta=".doc-meta/${path//\//_}.json" + if [ -f "$meta" ]; then + local hash date + hash=$(python3 -c "import json,sys; d=json.load(open('$meta')); print(d.get('hash',''))" 2>/dev/null || grep -o '"hash":"[^"]*"' "$meta" | cut -d'"' -f4) + date=$(python3 -c "import json,sys; d=json.load(open('$meta')); print(d.get('date',''))" 2>/dev/null || grep -o '"date":"[^"]*"' "$meta" | cut -d'"' -f4) + echo "${hash:-} ${date:-}" + return + fi + + # Last resort: gh-pages git log (hash will be wrong but better than empty) + local hash date + hash=$(git log --oneline -1 -- "$path" 2>/dev/null | awk '{print $1}') + date=$(git log --format="%cI" -1 -- "$path" 2>/dev/null) + echo "${hash:-} ${date:-}" +} + +# ── Build releases JSON ──────────────────────────────────────── +RELEASES_JSON="[" + +for i in "${!RELEASES[@]}"; do + version="${RELEASES[$i]}" + read -r HASH DATE <<< "$(get_commit_info "releases/$version")" + if [ "$i" -eq 0 ]; then + IS_LATEST="true" + else + IS_LATEST="false" + fi + RELEASES_JSON+="{\"id\":\"${version}\",\"version\":\"${version}\",\"path\":\"releases/${version}\",\"date\":\"${DATE}\",\"isLatest\":${IS_LATEST}}," +done + +RELEASES_JSON="${RELEASES_JSON%,}]" + +# ── Build experimental JSON ──────────────────────────────────── +EXPERIMENTAL_JSON="[" + +for branch in "${EXPERIMENTAL[@]}"; do + read -r HASH DATE <<< "$(get_commit_info "experimental/$branch")" + EXPERIMENTAL_JSON+="{\"id\":\"${branch}\",\"branch\":\"${branch}\",\"path\":\"experimental/${branch}\",\"hash\":\"${HASH}\",\"date\":\"${DATE}\"}," +done + +EXPERIMENTAL_JSON="${EXPERIMENTAL_JSON%,}]" + +# ── Write manifest.json ──────────────────────────────────────── +cat > manifest.json << JSON +{ + "releases": ${RELEASES_JSON}, + "experimental": ${EXPERIMENTAL_JSON}, + "generated": "$(date -u '+%Y-%m-%dT%H:%M:%SZ')", + "source": "manifest" +} +JSON + +echo "manifest.json generated:" +cat manifest.json +echo "" +echo "Done." diff --git a/.github/scripts/resolve-doc-path.sh b/.github/scripts/resolve-doc-path.sh new file mode 100644 index 000000000..92ad7ac8c --- /dev/null +++ b/.github/scripts/resolve-doc-path.sh @@ -0,0 +1,52 @@ +#!/bin/bash +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +source "$SCRIPT_DIR/doc-config.sh" + +BRANCH="${GITHUB_REF#refs/heads/}" +SAFE_BRANCH="${BRANCH//\//-}" + +if [ "$BRANCH" = "$MAIN_BRANCH_NAME" ]; then + # Version resolution order: + # -> check if gradle.properties has a `modVersion` tag. If it does, just grab it. + # -> check if it has the `version` tag. Grab it if it does + # -> check build.gradle for the version tag. + if [ -f "gradle.properties" ] && grep -q "^modVersion=" gradle.properties; then + VERSION=$(grep "^modVersion=" gradle.properties | cut -d'=' -f2 | tr -d '[:space:]') + elif [ -f "gradle.properties" ] && grep -q "^version=" gradle.properties; then + VERSION=$(grep "^version=" gradle.properties | cut -d'=' -f2 | tr -d '[:space:]') + elif [ -f "build.gradle" ]; then + VERSION=$(grep "^version" build.gradle | head -1 | sed "s/version\s*=\s*['\"]//;s/['\"].*//;s/\s//g") + elif [ -f "build.gradle.kts" ]; then + VERSION=$(grep "^version" build.gradle.kts | head -1 | sed "s/version\s*=\s*\"//;s/\".*//;s/\s//g") + else + echo "Could not find version. Defaulting to 'unknown'." + VERSION="unknown" + fi + + echo "Resolved version: $VERSION" + + # Only deploy to releases/ — isLatest is handled by generate-index.sh + echo "path=releases/$VERSION" >> $GITHUB_OUTPUT + echo "extra_path=" >> $GITHUB_OUTPUT + +else + MATCHED=false + for ALLOWED in "${EXPERIMENTAL_WHITELIST[@]}"; do + if [ "$BRANCH" = "$ALLOWED" ]; then + MATCHED=true + break + fi + done + + if [ "$MATCHED" = true ]; then + echo "path=experimental/$SAFE_BRANCH" >> $GITHUB_OUTPUT + echo "extra_path=" >> $GITHUB_OUTPUT + echo "Branch '$BRANCH' is whitelisted, deploying to experimental/$SAFE_BRANCH" + else + echo "path=" >> $GITHUB_OUTPUT + echo "extra_path=" >> $GITHUB_OUTPUT + echo "Branch '$BRANCH' is not whitelisted. Skipping deploy." + fi +fi diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 2d7779d62..c2fb186fe 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -24,8 +24,8 @@ jobs: with: fetch-depth: 0 - - name: Initialize CNPC+ API submodule - run: git submodule update --init --recursive src/api + - name: Initialize submodules + run: git submodule update --init --recursive - name: Checkout workflows repo uses: actions/checkout@v4 diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml new file mode 100644 index 000000000..52954f202 --- /dev/null +++ b/.github/workflows/javadoc.yml @@ -0,0 +1,224 @@ +name: Generate and Deploy Javadoc + +on: + push: + branches: + - master + - '**' + delete: + workflow_dispatch: + inputs: + force_deploy: + description: 'Force redeploy Javadocs without a new commit' + required: false + default: 'true' + +jobs: + sanity-check: + runs-on: ubuntu-latest + outputs: + should_deploy: ${{ steps.deploy_check.outputs.should_deploy }} + steps: + - uses: actions/checkout@v4 + - name: Check for deploy tag + id: deploy_check + run: | + source .github/scripts/doc-config.sh + + BRANCH="${GITHUB_REF#refs/heads/}" + + # Always deploy on manual trigger + if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then + echo "should_deploy=true" >> $GITHUB_OUTPUT + echo "Reason: workflow_dispatch" + exit 0 + fi + + # Main branch: only deploy if commit message contains [deploy-docs] + if [ "$BRANCH" = "$MAIN_BRANCH_NAME" ]; then + if echo "${{ github.event.head_commit.message }}" | grep -q "\[deploy-docs\]"; then + echo "should_deploy=true" >> $GITHUB_OUTPUT + echo "Reason: master branch with [deploy-docs] tag" + else + echo "should_deploy=false" >> $GITHUB_OUTPUT + echo "Reason: master branch without [deploy-docs] tag, skipping" + fi + exit 0 + fi + + # Experimental branches: only deploy if whitelisted + for ALLOWED in "${EXPERIMENTAL_WHITELIST[@]}"; do + if [ "$BRANCH" = "$ALLOWED" ]; then + echo "should_deploy=true" >> $GITHUB_OUTPUT + echo "Reason: branch '$BRANCH' is whitelisted" + exit 0 + fi + done + + echo "should_deploy=false" >> $GITHUB_OUTPUT + echo "Reason: branch '$BRANCH' is not whitelisted, skipping" + + build-and-deploy-javadoc: + needs: sanity-check + if: needs.sanity-check.outputs.should_deploy == 'true' + runs-on: ubuntu-latest + + steps: + - name: Checkout source branch + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Initialize submodules + run: git submodule update --init --recursive + + - name: Setup JDK 8 (compile) + uses: actions/setup-java@v4 + with: + java-version: '8' + distribution: 'temurin' + + - name: Set up JDK 8 (Zulu) + uses: actions/setup-java@v4 + with: + java-version: '8' + distribution: 'zulu' + - name: Setup JDK 11 (javadoc) + uses: actions/setup-java@v4 + with: + java-version: '11' + distribution: 'temurin' + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: '20' + + - name: Extract convention plugin version + id: convention + run: | + VERSION=$(grep "id 'com.gtnewhorizons.gtnhsettingsconvention'" settings.gradle settings.gradle.kts 2>/dev/null | grep -o "version '[0-9]\+\.[0-9]\+\.[0-9]\+'" | grep -o '[0-9]\+\.[0-9]\+\.[0-9]\+') + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Detected convention version: $VERSION" + + - name: Get source commit info + id: source_commit + run: | + echo "hash=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT + echo "date=$(git log -1 --format='%cI')" >> $GITHUB_OUTPUT + + - name: Cache Gradle wrapper + uses: actions/cache@v4 + with: + path: ~/.gradle/wrapper + key: gradle-wrapper-${{ hashFiles('**/gradle-wrapper.properties') }} + + - name: Cache Gradle dependencies + uses: actions/cache@v4 + with: + path: | + ~/.gradle/caches + ~/.gradle/caches/modules-* + ~/.gradle/caches/jars-* + key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties', '**/gradle.properties') }} + restore-keys: | + ${{ runner.os }}-gradle- + + - name: Cache RFG + uses: actions/cache@v4 + with: + path: | + build/rfg + build/tmp/.cache/expanded + build/tmp/deobfuscateMergedJarToSrg + key: ${{ runner.os }}-rfg-convention${{ steps.convention.outputs.version }} + restore-keys: | + ${{ runner.os }}-rfg- + + - name: Cache Node modules + uses: actions/cache@v4 + with: + path: .github/pages/node_modules + key: ${{ runner.os }}-node-${{ hashFiles('.github/pages/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + + - name: Generate Javadoc + run: ./gradlew javadoc + + - name: Get deploy path + id: deploy_path + run: bash .github/scripts/resolve-doc-path.sh + + - name: Deploy to gh-pages + if: steps.deploy_path.outputs.path != '' + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./build/docs/javadoc + destination_dir: ${{ steps.deploy_path.outputs.path }} + keep_files: true + + # Give GitHub a moment to settle after the peaceiris push + - name: Wait for gh-pages to settle + run: sleep 10 + + - name: Checkout gh-pages + uses: actions/checkout@v4 + with: + ref: gh-pages + path: gh-pages-index + + - name: Generate manifest + run: | + cd gh-pages-index + SOURCE_HASH="${{ steps.source_commit.outputs.hash }}" \ + SOURCE_DATE="${{ steps.source_commit.outputs.date }}" \ + DEPLOY_PATH="${{ steps.deploy_path.outputs.path }}" \ + bash ../.github/scripts/generate-index.sh + + - name: Install page dependencies + run: npm ci --prefix .github/pages + + - name: Build index page + run: | + mkdir -p .github/pages/public + cp gh-pages-index/manifest.json .github/pages/public/manifest.json + npm run build --prefix .github/pages + + - name: Deploy index to gh-pages + run: | + cp -r .github/pages-dist/* gh-pages-index/ + cd gh-pages-index + git config user.name "github-actions" + git config user.email "github-actions@github.com" + git add -A + git commit -m "Regenerate index and manifest [skip ci]" || echo "Unchanged" + git push + + cleanup-on-delete: + if: github.event_name == 'delete' && github.event.ref_type == 'branch' + runs-on: ubuntu-latest + + steps: + - name: Checkout gh-pages + uses: actions/checkout@v4 + with: + ref: 'gh-pages' + + - name: Remove deleted branch docs + run: | + BRANCH="${{ github.event.ref }}" + SAFE="experimental/${BRANCH//\//-}" + if [ -d "./$SAFE" ]; then + rm -rf "./$SAFE" + META_KEY="${SAFE//\//_}" + rm -f ".doc-meta/${META_KEY}.json" + git config user.name "github-actions" + git config user.email "github-actions@github.com" + git add -A + git commit -m "Remove docs for deleted branch: $BRANCH" + git push + else + echo "No docs found for $SAFE, skipping." + fi diff --git a/.gitignore b/.gitignore index 4d121433c..5d29506b6 100644 --- a/.gitignore +++ b/.gitignore @@ -45,4 +45,6 @@ src/main/resources/assets/customnpcs/api df/ tmp/ src/test +node_modules +.github/pages-dist diff --git a/build.gradle b/build.gradle index 01a710526..a76186d6d 100644 --- a/build.gradle +++ b/build.gradle @@ -6,7 +6,7 @@ plugins { id "dts.typescript-generator" } -version = "1.11-prerelease3" +version = "1.11" group= "kamkeel.customnpc-plus" archivesBaseName = "CustomNPC-Plus" @@ -81,11 +81,32 @@ processResources.dependsOn generateTypeScriptDefinitions sourcesJar.dependsOn generateTypeScriptDefinitions -// Register @hookName as a valid Javadoc tag -tasks.withType(Javadoc) { +// Javadoc configuration +javadoc { + options.encoding = 'UTF-8' + options.charSet = 'UTF-8' + options.docEncoding = 'UTF-8' + options.tags = [ 'hookName:a:Hook Name:' ] + + options.stylesheetFile = file('.github/javadoc/javadoc-theme.css') + options.header = file('.github/javadoc/javadoc-header.html').text.replaceAll('\\s+', ' ').trim() + + options.addBooleanOption('-allow-script-in-comments', true) + options.footer = file('.github/javadoc/javadoc-footer.html').text.replaceAll('\\s+', ' ').trim() + + // Only document the public API, not net.minecraft stubs + include 'noppes/npcs/api/**' + + options.links( + 'https://docs.oracle.com/en/java/javase/11/docs/api/' + ) + + javadocTool = javaToolchains.javadocToolFor { + languageVersion = JavaLanguageVersion.of(11) + } } // Modify the existing 'build' task to depend on 'updateAPI' diff --git a/src/api b/src/api index efce1a99b..f91e17ab3 160000 --- a/src/api +++ b/src/api @@ -1 +1 @@ -Subproject commit efce1a99b75dc6931e406b77bf188115befb54e2 +Subproject commit f91e17ab3ef4bf168836f8619c60cf6806f6ab84 diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java index c870f6a07..17316fcf2 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyBeam.java @@ -63,9 +63,9 @@ public class RenderEnergyBeam extends RenderEnergy { double renderOriginY = y - headOffsetY; double renderOriginZ = z - headOffsetZ; - // Get beam properties - float beamWidth = beam.getBeamWidth(); - float headSize = beam.getHeadSize(); + // Get beam properties (interpolated for smooth size transitions) + float beamWidth = beam.getInterpolatedBeamWidth(partialTicks); + float headSize = beam.getInterpolatedHeadSize(partialTicks); int innerColor = beam.getInnerColor(); int outerColor = beam.getOuterColor(); float outerAlpha = beam.getOuterColorAlpha() * proximityAlpha; @@ -105,7 +105,7 @@ public class RenderEnergyBeam extends RenderEnergy { * Grows from 0 to headSize based on charge progress. */ private void renderChargingOrb(EntityAbilityBeam beam, double x, double y, double z, float partialTicks, float proximityAlpha) { - float headSize = beam.getHeadSize(); + float headSize = beam.getInterpolatedHeadSize(partialTicks); float chargeProgress = beam.getInterpolatedChargeProgress(partialTicks); float size = headSize * chargeProgress; diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java index eb4d9f21c..93b90023e 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyDisc.java @@ -31,8 +31,8 @@ public class RenderEnergyDisc extends RenderEnergy { // Get interpolated values float size = disc.getInterpolatedSize(partialTicks); - float radius = disc.getDiscRadius() * size; - float thickness = disc.getDiscThickness() * size; + float radius = disc.getInterpolatedDiscRadius(partialTicks) * size; + float thickness = disc.getInterpolatedDiscThickness(partialTicks) * size; // Subtle pulsing effect float pulseTime = entity.ticksExisted + partialTicks; diff --git a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java index c2cfe716a..8b0c79b65 100644 --- a/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java +++ b/src/main/java/kamkeel/npcs/client/renderer/RenderEnergyLaser.java @@ -43,7 +43,7 @@ public class RenderEnergyLaser extends RenderEnergy { double endX = laser.getInterpolatedEndX(partialTicks); double endY = laser.getInterpolatedEndY(partialTicks); double endZ = laser.getInterpolatedEndZ(partialTicks); - float width = laser.getLaserWidth(); + float width = laser.getInterpolatedLaserWidth(partialTicks); float alpha = 1.0f; // Calculate render offset (entity position is used as reference) @@ -156,7 +156,7 @@ public class RenderEnergyLaser extends RenderEnergy { } private void renderChargingOrb(EntityAbilityLaser laser, double x, double y, double z, float partialTicks, float proximityAlpha) { - float headSize = laser.getLaserWidth() * 0.5f; + float headSize = laser.getInterpolatedLaserWidth(partialTicks) * 0.5f; float chargeProgress = laser.getInterpolatedChargeProgress(partialTicks); float size = headSize * chargeProgress; diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java index baeb7f81c..4e5e2e3cb 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityBeam.java @@ -41,6 +41,8 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { // Beam shape properties private float beamWidth = 0.3f; private float headSize = 0.5f; + private float prevBeamWidth = 0.3f; + private float prevHeadSize = 0.5f; // Trail - list of points showing beam path (RELATIVE to origin!) private List trailPoints = new ArrayList<>(); @@ -240,10 +242,12 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { return; } - // Store previous head offset for interpolation + // Store previous values for interpolation prevHeadOffsetX = headOffsetX; prevHeadOffsetY = headOffsetY; prevHeadOffsetZ = headOffsetZ; + prevBeamWidth = beamWidth; + prevHeadSize = headSize; // Age trail points for fading effect if (isFadingMode()) { @@ -580,7 +584,12 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { return beamWidth; } + public float getInterpolatedBeamWidth(float partialTicks) { + return prevBeamWidth + (beamWidth - prevBeamWidth) * partialTicks; + } + public void setBeamWidth(float beamWidth) { + this.prevBeamWidth = this.beamWidth; this.beamWidth = beamWidth; } @@ -588,7 +597,12 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { return headSize; } + public float getInterpolatedHeadSize(float partialTicks) { + return prevHeadSize + (headSize - prevHeadSize) * partialTicks; + } + public void setHeadSize(float headSize) { + this.prevHeadSize = this.headSize; this.headSize = headSize; } @@ -747,6 +761,8 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { @Override protected void applyProjectileClientSyncData(NBTTagCompound nbt) { + prevBeamWidth = beamWidth; + prevHeadSize = headSize; beamWidth = nbt.getFloat("BeamWidth"); headSize = nbt.getFloat("HeadSize"); setAttachedToOwner(nbt.getBoolean("AttachedToOwner")); @@ -758,6 +774,8 @@ public class EntityAbilityBeam extends EntityEnergyProjectile { protected void readProjectileNBT(NBTTagCompound nbt) { this.beamWidth = sanitize(nbt.hasKey("BeamWidth") ? nbt.getFloat("BeamWidth") : 0.3f, 0.3f, MAX_ENTITY_SIZE); this.headSize = sanitize(nbt.hasKey("HeadSize") ? nbt.getFloat("HeadSize") : 0.5f, 0.5f, MAX_ENTITY_SIZE); + this.prevBeamWidth = this.beamWidth; + this.prevHeadSize = this.headSize; this.headOffsetX = nbt.hasKey("HeadOffsetX") ? nbt.getDouble("HeadOffsetX") : 0; this.headOffsetY = nbt.hasKey("HeadOffsetY") ? nbt.getDouble("HeadOffsetY") : 0; this.headOffsetZ = nbt.hasKey("HeadOffsetZ") ? nbt.getDouble("HeadOffsetZ") : 0; diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java index 817357d9b..db5e2eb2c 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityDisc.java @@ -33,6 +33,8 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { // Disc shape properties private float discRadius = 1.0f; // Width of disc private float discThickness = 0.2f; // Height of disc + private float prevDiscRadius = 1.0f; + private float prevDiscThickness = 0.2f; // Boomerang owner-gone tracking private int returnOwnerNullTicks = 0; @@ -134,6 +136,10 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { @Override protected void updateProjectile() { + // Store previous values for interpolation + prevDiscRadius = discRadius; + prevDiscThickness = discThickness; + // Handle charging state (windup phase) if (isCharging()) { updateCharging(); @@ -347,7 +353,12 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { return discRadius; } + public float getInterpolatedDiscRadius(float partialTicks) { + return prevDiscRadius + (discRadius - prevDiscRadius) * partialTicks; + } + public void setDiscRadius(float radius) { + this.prevDiscRadius = this.discRadius; this.discRadius = radius; } @@ -355,7 +366,12 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { return discThickness; } + public float getInterpolatedDiscThickness(float partialTicks) { + return prevDiscThickness + (discThickness - prevDiscThickness) * partialTicks; + } + public void setDiscThickness(float thickness) { + this.prevDiscThickness = this.discThickness; this.discThickness = thickness; } @@ -443,6 +459,8 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { @Override protected void applyProjectileClientSyncData(NBTTagCompound nbt) { + prevDiscRadius = discRadius; + prevDiscThickness = discThickness; discRadius = nbt.getFloat("DiscRadius"); discThickness = nbt.getFloat("DiscThickness"); vertical = nbt.getBoolean("Vertical"); @@ -456,6 +474,8 @@ public class EntityAbilityDisc extends EntityEnergyProjectile { this.boomerangDelay = nbt.hasKey("BoomerangDelay") ? nbt.getInteger("BoomerangDelay") : 40; this.discRadius = sanitize(nbt.hasKey("DiscRadius") ? nbt.getFloat("DiscRadius") : 1.0f, 1.0f, MAX_ENTITY_SIZE); this.discThickness = sanitize(nbt.hasKey("DiscThickness") ? nbt.getFloat("DiscThickness") : 0.2f, 0.2f, MAX_ENTITY_SIZE); + this.prevDiscRadius = this.discRadius; + this.prevDiscThickness = this.discThickness; this.vertical = nbt.hasKey("Vertical") ? nbt.getBoolean("Vertical") : false; this.returning = nbt.hasKey("Returning") && nbt.getBoolean("Returning"); // Charging state (common fields handled by base) diff --git a/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java b/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java index 6e40ac999..f1eb9c617 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java +++ b/src/main/java/kamkeel/npcs/entity/EntityAbilityLaser.java @@ -33,6 +33,7 @@ public class EntityAbilityLaser extends EntityEnergyProjectile { // Laser-specific properties private float laserWidth = 0.2f; + private float prevLaserWidth = 0.2f; private float expansionSpeed = 2.0f; // Blocks per tick private float maxLength = 32.0f; // Maximum beam reach in blocks @@ -144,6 +145,9 @@ public class EntityAbilityLaser extends EntityEnergyProjectile { @Override protected void updateProjectile() { + // Store previous values for interpolation + prevLaserWidth = laserWidth; + if (isCharging()) { updateCharging(); return; @@ -703,7 +707,12 @@ public class EntityAbilityLaser extends EntityEnergyProjectile { return laserWidth; } + public float getInterpolatedLaserWidth(float partialTicks) { + return prevLaserWidth + (laserWidth - prevLaserWidth) * partialTicks; + } + public void setLaserWidth(float width) { + this.prevLaserWidth = this.laserWidth; this.laserWidth = width; } @@ -879,6 +888,7 @@ public class EntityAbilityLaser extends EntityEnergyProjectile { @Override protected void applyProjectileClientSyncData(NBTTagCompound nbt) { + prevLaserWidth = laserWidth; laserWidth = nbt.getFloat("LaserWidth"); expansionSpeed = nbt.getFloat("ExpansionSpeed"); maxLength = nbt.getFloat("MaxLength"); @@ -892,6 +902,7 @@ public class EntityAbilityLaser extends EntityEnergyProjectile { @Override protected void readProjectileNBT(NBTTagCompound nbt) { this.laserWidth = sanitize(nbt.hasKey("LaserWidth") ? nbt.getFloat("LaserWidth") : 0.2f, 0.2f, MAX_ENTITY_SIZE); + this.prevLaserWidth = this.laserWidth; this.expansionSpeed = sanitize(nbt.hasKey("ExpansionSpeed") ? nbt.getFloat("ExpansionSpeed") : 2.0f, 0.1f, MAX_ENTITY_SIZE); this.maxLength = sanitize(nbt.hasKey("MaxLength") ? nbt.getFloat("MaxLength") : 32.0f, 1.0f, MAX_ENTITY_SIZE); this.dirX = nbt.getDouble("DirX"); diff --git a/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java b/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java index 1527f644d..702c62c4d 100644 --- a/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java +++ b/src/main/java/kamkeel/npcs/entity/EntityEnergyProjectile.java @@ -348,7 +348,7 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility { // Fire tick event (server-side, non-preview only) if (!previewMode && !worldObj.isRemote) { - EventHooks.onEnergyProjectileTick(this); + EventHooks.onEnergyProjectileTick(this, ticksExisted); } debugLogTick(); @@ -738,8 +738,8 @@ public abstract class EntityEnergyProjectile extends EntityEnergyAbility { motionY = nbt.getDouble("MotionY"); motionZ = nbt.getDouble("MotionZ"); syncPositionStateToCurrent(true); - // Size & visual - setProjectileSize(nbt.getFloat("Size")); + // Size & visual (set target only - let the lerp in onUpdate smooth the transition) + this.size = nbt.getFloat("Size"); displayData.setRotationSpeed(nbt.getFloat("RotationSpeed")); displayData.setInnerAlpha(nbt.getFloat("InnerAlpha")); displayData.setOuterColorEnabled(nbt.getBoolean("OuterColorEnabled")); diff --git a/src/main/java/noppes/npcs/CustomNpcs.java b/src/main/java/noppes/npcs/CustomNpcs.java index cfd3ad7bb..5f020e507 100644 --- a/src/main/java/noppes/npcs/CustomNpcs.java +++ b/src/main/java/noppes/npcs/CustomNpcs.java @@ -124,7 +124,7 @@ import java.util.HashSet; import java.util.Set; import java.util.function.Consumer; -@Mod(modid = "customnpcs", name = "CustomNPC+", version = "1.11-prerelease3") +@Mod(modid = "customnpcs", name = "CustomNPC+", version = "1.11") public class CustomNpcs { @SidedProxy(clientSide = "noppes.npcs.client.ClientProxy", serverSide = "noppes.npcs.CommonProxy") diff --git a/src/main/java/noppes/npcs/EventHooks.java b/src/main/java/noppes/npcs/EventHooks.java index b783f98e0..92475f8b3 100644 --- a/src/main/java/noppes/npcs/EventHooks.java +++ b/src/main/java/noppes/npcs/EventHooks.java @@ -482,9 +482,9 @@ public class EventHooks { NpcAPI.EVENT_BUS.post(event); } - public static void onEnergyProjectileTick(EntityEnergyProjectile projectile) { + public static void onEnergyProjectileTick(EntityEnergyProjectile projectile, int tick) { IEnergyProjectile wrapped = (IEnergyProjectile) NpcAPI.Instance().getIEntity(projectile); - EnergyProjectileEvent.UpdateEvent event = new EnergyProjectileEvent.UpdateEvent(wrapped); + EnergyProjectileEvent.UpdateEvent event = new EnergyProjectileEvent.UpdateEvent(wrapped, tick); ScriptController.Instance.globalNpcScripts.callScript(EnumScriptType.ENERGY_PROJECTILE_TICK, event); Entity owner = projectile.worldObj.getEntityByID(projectile.getOwnerEntityId()); diff --git a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java index 0a175528a..6f95538c6 100644 --- a/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java +++ b/src/main/java/noppes/npcs/client/gui/util/script/interpreter/ScriptDocument.java @@ -88,7 +88,7 @@ public class ScriptDocument { // Also matches ',' as a delimiter so that "int x, y, z;" is recognized // (the first declarator "int x," is captured; continuations are scanned manually). private static final Pattern FIELD_DECL_PATTERN = Pattern.compile( - "\\b([A-Za-z_][a-zA-Z0-9_.<>,[ \\t]\\[\\]]*)[ \\t]+([a-zA-Z_][a-zA-Z0-9_]*)[ \\t]*(=|;|,)"); + "\\b([A-Za-z_][a-zA-Z0-9_.<>,[ \\t\\n\\r]\\[\\]]*)[ \\t]+([a-zA-Z_][a-zA-Z0-9_]*)[ \\t]*(=|;|,)"); private static final Pattern NEW_TYPE_PATTERN = Pattern.compile("\\bnew\\s+([A-Za-z_][a-zA-Z0-9_]*)\\s*(?:<([^>]*)>)?"); // Cast expression pattern: captures type name inside cast parentheses @@ -785,8 +785,10 @@ public class ScriptDocument { */ private void parseScriptTypes() { // ========== PASS 1: Discover all type declarations (flat list) ========== + // Regex only anchors on keyword + name — generic clauses are extracted manually + // below to correctly handle nested angle brackets like >. Pattern typeDecl = Pattern.compile( - "(?:(?:public|private|protected|static|final|abstract)\\s+)*(class|interface|enum)\\s+([A-Za-z_][a-zA-Z0-9_]*)\\s*(?:<([^>]*)>)?\\s*(?:\\(\\))?\\s*(?:extends\\s+([A-Za-z_][a-zA-Z0-9_.]*))?\\s*(?:implements\\s+([A-Za-z_][a-zA-Z0-9_.,\\s]*))?\\s*\\{"); + "(?:(?:public|private|protected|static|final|abstract)\\s+)*(class|interface|enum)\\s+([A-Za-z_][a-zA-Z0-9_]*)"); List rawDeclarations = new ArrayList<>(); Matcher m = typeDecl.matcher(text); @@ -796,16 +798,58 @@ public class ScriptDocument { String kindStr = m.group(1); String typeName = m.group(2); - String typeParamsClause = m.group(3); - String extendsClause = m.group(4); - String implementsClause = m.group(5); - int bodyStart = text.indexOf('{', m.start()); - int bodyEnd = findMatchingBrace(bodyStart); - if (bodyEnd < 0) { - bodyEnd = text.length(); + // Manually extract everything between the type name and the opening '{', + // handling nested angle brackets so > is captured whole. + int scanPos = m.end(); + while (scanPos < text.length() && Character.isWhitespace(text.charAt(scanPos))) + scanPos++; + + // Extract type params clause <...> if present (depth-aware) + String typeParamsClause = null; + if (scanPos < text.length() && text.charAt(scanPos) == '<') { + int depth = 1, i = scanPos + 1; + while (i < text.length() && depth > 0) { + char c = text.charAt(i++); + if (c == '<') depth++; + else if (c == '>') depth--; + } + if (depth == 0) { + typeParamsClause = text.substring(scanPos + 1, i - 1); + scanPos = i; + while (scanPos < text.length() && Character.isWhitespace(text.charAt(scanPos))) + scanPos++; + } } + // Find the opening brace, extracting extends/implements from text between here and '{' + int bracePos = scanPos; + int angleDepth = 0; + while (bracePos < text.length()) { + char c = text.charAt(bracePos); + if (c == '<') angleDepth++; + else if (c == '>') angleDepth--; + else if (c == '{' && angleDepth == 0) break; + bracePos++; + } + if (bracePos >= text.length()) continue; + + String betweenNameAndBrace = text.substring(scanPos, bracePos).trim(); + + // Parse extends/implements from that window + String extendsClause = null; + String implementsClause = null; + java.util.regex.Matcher extM = Pattern.compile( + "extends\\s+([A-Za-z_][a-zA-Z0-9_.]*(?:<[^{]*>)?)").matcher(betweenNameAndBrace); + if (extM.find()) extendsClause = extM.group(1).trim(); + java.util.regex.Matcher implM = Pattern.compile( + "implements\\s+(.+)$").matcher(betweenNameAndBrace); + if (implM.find()) implementsClause = implM.group(1).trim(); + + int bodyStart = bracePos; + int bodyEnd = findMatchingBrace(bodyStart); + if (bodyEnd < 0) bodyEnd = text.length(); + TypeInfo.Kind kind; switch (kindStr) { case "interface": kind = TypeInfo.Kind.INTERFACE; break; @@ -813,7 +857,7 @@ public class ScriptDocument { default: kind = TypeInfo.Kind.CLASS; break; } - String fullMatch = text.substring(m.start(), m.end()); + String fullMatch = text.substring(m.start(), bodyStart + 1); int modifiers = parseModifiers(fullMatch); JSDocInfo jsDoc = jsDocParser.extractJSDocBefore(text, m.start()); @@ -870,6 +914,11 @@ public class ScriptDocument { // Resolve extends clause (parent class inheritance) if (raw.extendsClause != null && !raw.extendsClause.trim().isEmpty()) { String parentName = raw.extendsClause.trim(); + // Strip generic args (e.g., "NumberBox" -> "NumberBox") for type resolution + int genIdx = parentName.indexOf('<'); + if (genIdx >= 0) { + parentName = parentName.substring(0, genIdx); + } TypeInfo parentType = resolveType(parentName, raw.declOffset); if (parentType == null) { parentType = TypeInfo.unresolved(parentName, parentName); @@ -884,6 +933,11 @@ public class ScriptDocument { String trimmedName = ifaceName.trim(); if (trimmedName.isEmpty()) continue; + // Strip generic args (e.g., "Comparable" -> "Comparable") + int genIdx = trimmedName.indexOf('<'); + if (genIdx >= 0) { + trimmedName = trimmedName.substring(0, genIdx); + } TypeInfo ifaceType = resolveType(trimmedName, raw.declOffset); if (ifaceType == null) { ifaceType = TypeInfo.unresolved(trimmedName, trimmedName); @@ -920,14 +974,16 @@ public class ScriptDocument { String boundName = null; if (extendsIdx >= 0) { String afterExtends = trimmed.substring(extendsIdx + 7).trim(); - if (!afterExtends.isEmpty()) { + // Split on & to get the primary bound (first one); additional bounds are interfaces + String primaryBound = afterExtends.split("&")[0].trim(); + if (!primaryBound.isEmpty()) { int boundEndIdx = 0; - while (boundEndIdx < afterExtends.length() && - (Character.isJavaIdentifierPart(afterExtends.charAt(boundEndIdx)) || afterExtends.charAt(boundEndIdx) == '.')) { + while (boundEndIdx < primaryBound.length() && + (Character.isJavaIdentifierPart(primaryBound.charAt(boundEndIdx)) || primaryBound.charAt(boundEndIdx) == '.')) { boundEndIdx++; } if (boundEndIdx > 0) { - boundName = afterExtends.substring(0, boundEndIdx); + boundName = primaryBound.substring(0, boundEndIdx); } } } @@ -941,7 +997,7 @@ public class ScriptDocument { } scriptType.addDeclaredTypeParam(typeParam); } - } + } private TypeInfo parameterizeWithClause(TypeInfo baseType, String typeArgsClause, int position) { String[] argNames = typeArgsClause.split(","); @@ -964,42 +1020,68 @@ public class ScriptDocument { private void markTypeParamDeclarations(List marks, int afterNameEnd, ScriptTypeInfo typeInfo) { int ltPos = text.indexOf('<', afterNameEnd); if (ltPos < 0 || ltPos > afterNameEnd + 5) return; - int gtPos = text.indexOf('>', ltPos); - if (gtPos < 0) return; - String clause = text.substring(ltPos + 1, gtPos); - int offset = ltPos + 1; - for (TypeParamInfo param : typeInfo.getDeclaredTypeParams()) { - int paramIdx = clause.indexOf(param.getName(), offset - (ltPos + 1)); - if (paramIdx >= 0) { - int paramStart = ltPos + 1 + paramIdx; - int paramLen = param.getName().length(); - int paramEnd = paramStart + paramLen; - marks.add(new ScriptLine.Mark(paramStart, paramEnd, TokenType.GENERIC_TYPE_PARAM, param)); + int depth = 1, i = ltPos + 1; + while (i < text.length() && depth > 0) { + char c = text.charAt(i++); + if (c == '<') depth++; + else if (c == '>') depth--; + } + if (depth != 0) return; + int gtPos = i - 1; - int searchFrom = paramIdx + param.getName().length(); - int extendsIdx = clause.indexOf("extends", searchFrom); - if (extendsIdx >= 0) { - int extendsStart = ltPos + 1 + extendsIdx; - marks.add(new ScriptLine.Mark(extendsStart, extendsStart + 7, TokenType.KEYWORD)); + markTypeParamsInClause(marks, ltPos + 1, gtPos - 1, typeInfo.getDeclaredTypeParams()); + } - TypeInfo boundType = param.getBoundTypeInfo(); - if (boundType != null) { - String remaining = clause.substring(extendsIdx + 7).trim(); - if (!remaining.isEmpty()) { - int boundEnd = remaining.indexOf(','); - if (boundEnd < 0) boundEnd = remaining.indexOf('&'); - String boundName = boundEnd < 0 ? remaining : remaining.substring(0, boundEnd).trim(); - if (!boundName.isEmpty()) { - int boundStart = extendsStart + 7; - while (boundStart < gtPos && Character.isWhitespace(text.charAt(boundStart))) boundStart++; - marks.add(new ScriptLine.Mark(boundStart, boundStart + boundName.length(), TokenType.getByType(boundType), boundType)); - } - } - } + private void markTypeParamsInClause(List marks, int clauseStart, int clauseEnd, List typeParams) { + if (clauseStart >= clauseEnd) return; + + String clause = text.substring(clauseStart, clauseEnd); + Map paramMap = new HashMap<>(); + for (TypeParamInfo param : typeParams) { + paramMap.put(param.getName(), param); + } + + int i = 0; + while (i < clause.length()) { + char c = clause.charAt(i); + + if (c == '<') { + int innerStart = clauseStart + i + 1; + int depth = 1; + int j = i + 1; + while (j < clause.length() && depth > 0) { + char innerC = clause.charAt(j); + if (innerC == '<') depth++; + else if (innerC == '>') depth--; + j++; } + if (depth == 0) { + markTypeParamsInClause(marks, innerStart, clauseStart + j - 1, typeParams); + i = j; + } else { + i++; + } + } else if (c == '&') { + i++; + } else if (c == ',') { + i++; + } else if (Character.isJavaIdentifierStart(c)) { + int start = i; + while (i < clause.length() && Character.isJavaIdentifierPart(clause.charAt(i))) { + i++; + } + String name = clause.substring(start, i); + TypeParamInfo param = paramMap.get(name); + if (param != null) { + int absStart = clauseStart + start; + int absEnd = clauseStart + i; + marks.add(new ScriptLine.Mark(absStart, absEnd, TokenType.GENERIC_TYPE_PARAM, param)); + } + } else { + i++; } - } + } } /** * Parse fields and methods inside a script-defined type. @@ -5038,8 +5120,8 @@ public class ScriptDocument { // Extended pattern to capture extends and implements clauses // Groups: 1=class|interface|enum, 2=TypeName, 3=extends clause, 4=implements clause Pattern classWithInheritance = Pattern.compile( - "\\b(class|interface|enum)\\s+([A-Za-z_][a-zA-Z0-9_]*)\\s*(?:<[^>]*>)?\\s*(?:\\(\\))?\\s*" + - "(?:(extends)\\s+([A-Za-z_][a-zA-Z0-9_.]*))?\\s*" + + "\\b(class|interface|enum)\\s+([A-Za-z_][a-zA-Z0-9_]*)\\s*(?:<[^{]*>)?\\s*(?:\\(\\))?\\s*" + + "(?:(extends)\\s+([A-Za-z_][a-zA-Z0-9_.]*)(?:<[^{]*>)?)?\\s*" + "(?:(implements)\\s+([A-Za-z_][a-zA-Z0-9_.,\\s]*))?\\s*(?=\\{)"); Matcher m = classWithInheritance.matcher(text); @@ -5087,7 +5169,7 @@ public class ScriptDocument { if (m.group(3) != null) { //Extends key word marks.add(new ScriptLine.Mark(m.start(3), m.end(3), TokenType.IMPORT_KEYWORD)); - markExtendsClause(marks, m.start(4), m.group(4)); + markExtendsClause(marks, m.start(4), m.group(4), typeInfo); } // Mark implements clause @@ -5126,36 +5208,50 @@ public class ScriptDocument { * Mark the extends clause with proper coloring. * The parent class is colored based on its resolved type. */ - private void markExtendsClause(List marks, int clauseStart, String parentName) { + private void markExtendsClause(List marks, int clauseStart, String parentName, ScriptTypeInfo typeInfo) { String trimmedName = parentName.trim(); if (trimmedName.isEmpty()) return; + int actualStart = clauseStart; + while (actualStart < clauseStart + trimmedName.length() && + Character.isWhitespace(text.charAt(actualStart))) { + actualStart++; + } + + int baseNameEnd = actualStart; + while (baseNameEnd < text.length() && Character.isJavaIdentifierPart(text.charAt(baseNameEnd))) { + baseNameEnd++; + } + String baseName = text.substring(actualStart, baseNameEnd); - // Resolve the parent type with position context for inner class names TypeInfo parentType = resolveType(trimmedName, clauseStart); TokenType tokenType; if (parentType != null && parentType.isResolved()) { - // Use the type's specific token type (CLASS, INTERFACE, ENUM) tokenType = parentType.getTokenType(); } else { - // Unresolved - mark as undefined tokenType = TokenType.UNDEFINED_VAR; if (parentType == null) { parentType = TypeInfo.unresolved(trimmedName, trimmedName); } } - // Find actual position in text (might have leading whitespace in the group) - int actualStart = clauseStart; - String fullClause = parentName; - while (actualStart < clauseStart + fullClause.length() && - Character.isWhitespace(text.charAt(actualStart))) { - actualStart++; - } + marks.add(new ScriptLine.Mark(actualStart, baseNameEnd, tokenType, parentType)); - marks.add(new ScriptLine.Mark(actualStart, actualStart + trimmedName.length(), tokenType, parentType)); + if (typeInfo != null && typeInfo.hasDeclaredTypeParams() && baseNameEnd < text.length() && text.charAt(baseNameEnd) == '<') { + int ltPos = baseNameEnd; + int depth = 1; + int i = ltPos + 1; + while (i < text.length() && depth > 0) { + char c = text.charAt(i++); + if (c == '<') depth++; + else if (c == '>') depth--; + } + if (depth == 0) { + markTypeParamsInClause(marks, ltPos + 1, i - 1, typeInfo.getDeclaredTypeParams()); + } + } } /** @@ -6059,7 +6155,7 @@ public class ScriptDocument { while (actualStart < i && Character.isWhitespace(text.charAt(actualStart))) { actualStart++; } - int actualEnd = i; + int actualEnd = i; while (actualEnd > actualStart && Character.isWhitespace(text.charAt(actualEnd - 1))) { actualEnd--; } diff --git a/src/main/java/noppes/npcs/scripted/event/EnergyProjectileEvent.java b/src/main/java/noppes/npcs/scripted/event/EnergyProjectileEvent.java index 4a1fab5a2..024376103 100644 --- a/src/main/java/noppes/npcs/scripted/event/EnergyProjectileEvent.java +++ b/src/main/java/noppes/npcs/scripted/event/EnergyProjectileEvent.java @@ -49,10 +49,16 @@ public class EnergyProjectileEvent extends CustomNPCsEvent implements IEnergyPro * energyProjectileTick */ public static class UpdateEvent extends EnergyProjectileEvent implements IEnergyProjectileEvent.UpdateEvent { - public UpdateEvent(IEnergyProjectile projectile) { + private final int tick; + + public UpdateEvent(IEnergyProjectile projectile, int tick) { super(projectile); + this.tick = tick; } + @Override + public int getTick() { return this.tick; } + @Override public String getHookName() { return EnumScriptType.ENERGY_PROJECTILE_TICK.function;