@stacksjs/bunpress 0.0.5 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/CHANGELOG.md +296 -0
  2. package/README.md +113 -26
  3. package/dist/bin/cli.js +2 -85
  4. package/dist/chunk-16hpnayn.js +505 -0
  5. package/dist/chunk-njjmvdjd.js +8 -0
  6. package/dist/chunk-nt1zw6bf.js +9632 -0
  7. package/dist/chunk-zabbw4a8.js +2 -0
  8. package/dist/config.d.ts +3 -5
  9. package/dist/highlighter.d.ts +37 -0
  10. package/dist/index.d.ts +2 -0
  11. package/dist/robots.d.ts +5 -0
  12. package/dist/rss.d.ts +16 -0
  13. package/dist/serve.d.ts +28 -0
  14. package/dist/sitemap.d.ts +5 -0
  15. package/dist/src/index.js +1 -242
  16. package/dist/template-loader.d.ts +16 -0
  17. package/dist/templates/blocks/alerts/caution.stx +9 -0
  18. package/dist/templates/blocks/alerts/important.stx +9 -0
  19. package/dist/templates/blocks/alerts/note.stx +9 -0
  20. package/dist/templates/blocks/alerts/tip.stx +9 -0
  21. package/dist/templates/blocks/alerts/warning.stx +9 -0
  22. package/dist/templates/blocks/containers/danger.stx +6 -0
  23. package/dist/templates/blocks/containers/details.stx +6 -0
  24. package/dist/templates/blocks/containers/info.stx +6 -0
  25. package/dist/templates/blocks/containers/raw.stx +3 -0
  26. package/dist/templates/blocks/containers/tip.stx +6 -0
  27. package/dist/templates/blocks/containers/warning.stx +6 -0
  28. package/dist/templates/blocks/inline/code.stx +1 -0
  29. package/dist/templates/blocks/inline/del.stx +1 -0
  30. package/dist/templates/blocks/inline/em.stx +1 -0
  31. package/dist/templates/blocks/inline/mark.stx +1 -0
  32. package/dist/templates/blocks/inline/strong.stx +1 -0
  33. package/dist/templates/blocks/inline/sub.stx +1 -0
  34. package/dist/templates/blocks/inline/sup.stx +1 -0
  35. package/dist/templates/features.stx +20 -0
  36. package/dist/templates/hero.stx +10 -0
  37. package/dist/templates/layout-doc.stx +157 -0
  38. package/dist/templates/layout-home.stx +23 -0
  39. package/dist/templates/page-toc.stx +267 -0
  40. package/dist/templates/sidebar-section.stx +42 -0
  41. package/dist/templates/sidebar.stx +54 -0
  42. package/dist/themes/bun/index.d.ts +34 -0
  43. package/dist/themes/index.d.ts +24 -0
  44. package/dist/themes/vitepress/base.css +549 -0
  45. package/dist/themes/vitepress/code-group.css +121 -0
  46. package/dist/themes/vitepress/custom-block.css +330 -0
  47. package/dist/themes/vitepress/index.d.ts +29 -0
  48. package/dist/themes/vitepress/index.ts +1963 -0
  49. package/dist/themes/vitepress/vars.css +436 -0
  50. package/dist/types.d.ts +154 -3
  51. package/package.json +32 -14
  52. package/dist/chunk-z2xpw4s7.js +0 -322
  53. package/dist/plugin.d.ts +0 -0
@@ -0,0 +1,157 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{ title }}</title>
7
+ <meta name="description" content="{{ description }}">
8
+ {{ meta }}
9
+ <style>
10
+ /* VitePress Theme CSS */
11
+ {{ customCSS }}
12
+ </style>
13
+ </head>
14
+ <body>
15
+ <div class="Layout">
16
+ <!-- VPNav - Header -->
17
+ <header class="VPNav" style="position: fixed; top: 0; left: 0; right: 0; height: var(--bp-nav-height, 64px); background-color: var(--bp-nav-bg-color, var(--bp-c-bg)); border-bottom: 1px solid var(--bp-c-divider); z-index: var(--bp-z-index-nav, 30);">
18
+ <div style="max-width: var(--bp-layout-max-width, 1440px); margin: 0 auto; width: 100%; height: 100%; display: flex; align-items: center; justify-content: space-between; padding: 0 24px;">
19
+ <!-- Left side: Logo/Title + Search -->
20
+ <div style="display: flex; align-items: center; gap: 24px; flex: 1; min-width: 0;">
21
+ <a href="/" class="VPNavBarTitle" style="font-size: 16px; font-weight: 600; color: var(--bp-c-text-1); white-space: nowrap; text-decoration: none;">{{ title }}</a>
22
+ <div class="VPNavBarSearch" style="position: relative; display: flex; align-items: center; max-width: 260px; width: 100%;">
23
+ <svg style="position: absolute; left: 12px; width: 16px; height: 16px; color: var(--bp-c-text-3);" fill="none" stroke="currentColor" viewBox="0 0 24 24">
24
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
25
+ </svg>
26
+ <input type="text" placeholder="Search" style="width: 100%; height: 32px; padding-left: 36px; padding-right: 48px; font-size: 13px; background-color: var(--bp-c-bg-alt); border: 1px solid var(--bp-c-divider); border-radius: 4px; color: var(--bp-c-text-1); outline: none; transition: border-color 0.25s, background-color 0.25s;" />
27
+ <kbd style="position: absolute; right: 8px; padding: 2px 6px; font-size: 11px; font-weight: 600; color: var(--bp-c-text-3); background-color: var(--bp-c-bg); border: 1px solid var(--bp-c-divider); border-radius: 4px;">⌘ K</kbd>
28
+ </div>
29
+ </div>
30
+
31
+ <!-- Right side: Navigation + Icons -->
32
+ <div style="display: flex; align-items: center; gap: 24px;">
33
+ {{ nav }}
34
+ <div class="VPSocialLinks" style="display: flex; align-items: center; gap: 12px; padding-left: 24px; border-left: 1px solid var(--bp-c-divider);">
35
+ <!-- Theme Toggle -->
36
+ <button class="theme-toggle" onclick="toggleTheme()" aria-label="Toggle dark mode" title="Toggle dark mode">
37
+ <svg class="sun-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
38
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path>
39
+ </svg>
40
+ <svg class="moon-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
41
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>
42
+ </svg>
43
+ </button>
44
+ <a href="https://github.com/stacksjs/bunpress" target="_blank" style="color: var(--bp-c-text-2); transition: color 0.25s;" onmouseover="this.style.color='var(--bp-c-text-1)'" onmouseout="this.style.color='var(--bp-c-text-2)'">
45
+ <svg style="width: 20px; height: 20px;" fill="currentColor" viewBox="0 0 24 24">
46
+ <path d="M12 0c-6.626 0-12 5.373-12 12 0 5.302 3.438 9.8 8.207 11.387.599.111.793-.261.793-.577v-2.234c-3.338.726-4.033-1.416-4.033-1.416-.546-1.387-1.333-1.756-1.333-1.756-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23.957-.266 1.983-.399 3.003-.404 1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222v3.293c0 .319.192.694.801.576 4.765-1.589 8.199-6.086 8.199-11.386 0-6.627-5.373-12-12-12z"/>
47
+ </svg>
48
+ </a>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </header>
53
+
54
+ <!-- VPSidebar -->
55
+ {{ sidebar }}
56
+
57
+ <!-- VPContent - Main content area -->
58
+ <main class="VPContent" style="position: fixed; top: var(--bp-nav-height, 64px); bottom: 0; overflow-y: auto; left: max(var(--bp-sidebar-width, 272px), calc((100vw - var(--bp-layout-max-width, 1440px)) / 2 + var(--bp-sidebar-width, 272px))); right: max(0px, calc((100vw - var(--bp-layout-max-width, 1440px)) / 2));">
59
+ <div class="VPDoc" style="padding: 32px 24px; padding-right: 32px;">
60
+ <div class="VPDocContent" style="max-width: 768px; margin: 0;">
61
+ <article class="bp-doc">
62
+ {{ content }}
63
+ </article>
64
+ </div>
65
+ </div>
66
+ </main>
67
+
68
+ <!-- Copy Page Dropdown (positioned via JS next to H1) -->
69
+ <div class="copy-page-dropdown" id="copy-page-dropdown">
70
+ <div class="copy-page-button-group">
71
+ <button class="copy-page-button copy-page-main" onclick="copyPageDirect(event)" aria-label="Copy page as markdown">
72
+ <svg class="copy-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
73
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
74
+ </svg>
75
+ <svg class="check-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" style="display: none;">
76
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
77
+ </svg>
78
+ <span class="button-text">Copy page</span>
79
+ </button>
80
+ <button class="copy-page-button copy-page-toggle" onclick="toggleCopyPageDropdown(event)" aria-label="More copy options">
81
+ <svg class="chevron" fill="none" stroke="currentColor" viewBox="0 0 24 24">
82
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
83
+ </svg>
84
+ </button>
85
+ </div>
86
+ <div class="copy-page-menu">
87
+ <!-- Copy page as Markdown -->
88
+ <div class="copy-page-menu-item" onclick="copyPageAsMarkdown(event)">
89
+ <div class="icon">
90
+ <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
91
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
92
+ </svg>
93
+ </div>
94
+ <div class="content">
95
+ <div class="title">Copy page</div>
96
+ <div class="description">Copy page as Markdown for LLMs</div>
97
+ </div>
98
+ </div>
99
+ <!-- View as Markdown -->
100
+ <div class="copy-page-menu-item" onclick="viewAsMarkdown(event)">
101
+ <div class="icon">
102
+ <svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
103
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
104
+ </svg>
105
+ </div>
106
+ <div class="content">
107
+ <div class="title">View as Markdown <svg class="external-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg></div>
108
+ <div class="description">View this page as plain text</div>
109
+ </div>
110
+ </div>
111
+ <div class="copy-page-menu-divider"></div>
112
+ <!-- Open in ChatGPT -->
113
+ <a class="copy-page-menu-item" onclick="openInChatGPT(event)" href="#">
114
+ <div class="icon">
115
+ <svg viewBox="0 0 24 24" fill="currentColor">
116
+ <path d="M22.2819 9.8211a5.9847 5.9847 0 0 0-.5157-4.9108 6.0462 6.0462 0 0 0-6.5098-2.9A6.0651 6.0651 0 0 0 4.9807 4.1818a5.9847 5.9847 0 0 0-3.9977 2.9 6.0462 6.0462 0 0 0 .7427 7.0966 5.98 5.98 0 0 0 .511 4.9107 6.051 6.051 0 0 0 6.5146 2.9001A5.9847 5.9847 0 0 0 13.2599 24a6.0557 6.0557 0 0 0 5.7718-4.2058 5.9894 5.9894 0 0 0 3.9977-2.9001 6.0557 6.0557 0 0 0-.7475-7.0729zm-9.022 12.6081a4.4755 4.4755 0 0 1-2.8764-1.0408l.1419-.0804 4.7783-2.7582a.7948.7948 0 0 0 .3927-.6813v-6.7369l2.02 1.1686a.071.071 0 0 1 .038.052v5.5826a4.504 4.504 0 0 1-4.4945 4.4944zm-9.6607-4.1254a4.4708 4.4708 0 0 1-.5346-3.0137l.142.0852 4.783 2.7582a.7712.7712 0 0 0 .7806 0l5.8428-3.3685v2.3324a.0804.0804 0 0 1-.0332.0615L9.74 19.9502a4.4992 4.4992 0 0 1-6.1408-1.6464zM2.3408 7.8956a4.485 4.485 0 0 1 2.3655-1.9728V11.6a.7664.7664 0 0 0 .3879.6765l5.8144 3.3543-2.0201 1.1685a.0757.0757 0 0 1-.071 0l-4.8303-2.7865A4.504 4.504 0 0 1 2.3408 7.8956zm16.5963 3.8558L13.1038 8.364 15.1192 7.2a.0757.0757 0 0 1 .071 0l4.8303 2.7913a4.4944 4.4944 0 0 1-.6765 8.1042v-5.6772a.79.79 0 0 0-.407-.667zm2.0107-3.0231l-.142-.0852-4.7735-2.7818a.7759.7759 0 0 0-.7854 0L9.409 9.2297V6.8974a.0662.0662 0 0 1 .0284-.0615l4.8303-2.7866a4.4992 4.4992 0 0 1 6.6802 4.66zM8.3065 12.863l-2.02-1.1638a.0804.0804 0 0 1-.038-.0567V6.0742a4.4992 4.4992 0 0 1 7.3757-3.4537l-.142.0805L8.704 5.459a.7948.7948 0 0 0-.3927.6813zm1.0976-2.3654l2.602-1.4998 2.6069 1.4998v2.9994l-2.5974 1.4997-2.6067-1.4997Z"/>
117
+ </svg>
118
+ </div>
119
+ <div class="content">
120
+ <div class="title">Open in ChatGPT <svg class="external-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg></div>
121
+ <div class="description">Copy content and open ChatGPT</div>
122
+ </div>
123
+ </a>
124
+ <!-- Open in Claude -->
125
+ <a class="copy-page-menu-item" onclick="openInClaude(event)" href="#">
126
+ <div class="icon">
127
+ <svg viewBox="0 0 24 24" fill="currentColor">
128
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z"/>
129
+ </svg>
130
+ </div>
131
+ <div class="content">
132
+ <div class="title">Open in Claude <svg class="external-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg></div>
133
+ <div class="description">Copy content and open Claude</div>
134
+ </div>
135
+ </a>
136
+ <!-- Open in Perplexity -->
137
+ <a class="copy-page-menu-item" onclick="openInPerplexity(event)" href="#">
138
+ <div class="icon">
139
+ <svg viewBox="0 0 24 24" fill="currentColor">
140
+ <path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/>
141
+ </svg>
142
+ </div>
143
+ <div class="content">
144
+ <div class="title">Open in Perplexity <svg class="external-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 6H6a2 2 0 00-2 2v10a2 2 0 002 2h10a2 2 0 002-2v-4M14 4h6m0 0v6m0-6L10 14"></path></svg></div>
145
+ <div class="description">Search with Perplexity AI</div>
146
+ </div>
147
+ </a>
148
+ </div>
149
+ </div>
150
+
151
+ <!-- VPDocAside - TOC -->
152
+ {{ pageTOC }}
153
+ </div>
154
+
155
+ {{ scripts }}
156
+ </body>
157
+ </html>
@@ -0,0 +1,23 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>{{ title }}</title>
7
+ <meta name="description" content="{{ description }}">
8
+ {{ meta }}
9
+ <style>
10
+ /* VitePress Theme CSS */
11
+ {{ customCSS }}
12
+ </style>
13
+ </head>
14
+ <body>
15
+ <div class="Layout">
16
+ <main class="VPHome">
17
+ {{ content }}
18
+ </main>
19
+ </div>
20
+
21
+ {{ scripts }}
22
+ </body>
23
+ </html>
@@ -0,0 +1,267 @@
1
+ <aside class="VPDocAside">
2
+ <div class="VPDocAsideOutline">
3
+ <p class="outline-title">On this page</p>
4
+ <nav class="page-toc">
5
+ <div class="outline-marker"></div>
6
+ {{ items }}
7
+ </nav>
8
+ </div>
9
+ </aside>
10
+
11
+ <style>
12
+ .VPDocAside {
13
+ position: fixed;
14
+ top: var(--bp-nav-height, 64px);
15
+ bottom: 0;
16
+ width: 224px;
17
+ overflow-y: auto;
18
+ overflow-x: hidden;
19
+ padding: 32px 16px 32px 16px;
20
+ display: none;
21
+ right: max(32px, calc((100vw - var(--bp-layout-max-width, 1440px)) / 2 + 32px));
22
+ background-color: var(--bp-c-bg);
23
+ scrollbar-width: none;
24
+ }
25
+
26
+ .VPDocAside::-webkit-scrollbar {
27
+ display: none;
28
+ }
29
+
30
+ .VPDocAsideOutline {
31
+ font-size: 14px;
32
+ }
33
+
34
+ .outline-title {
35
+ font-weight: 600;
36
+ color: var(--bp-c-text-1);
37
+ margin-bottom: 16px;
38
+ font-size: 13px;
39
+ letter-spacing: 0.4px;
40
+ text-transform: uppercase;
41
+ }
42
+
43
+ /* Show aside on xl screens and adjust main content */
44
+ @media (min-width: 1280px) {
45
+ .VPDocAside {
46
+ display: block !important;
47
+ }
48
+
49
+ .VPContent {
50
+ right: max(256px, calc((100vw - var(--bp-layout-max-width, 1440px)) / 2 + 256px)) !important;
51
+ }
52
+ }
53
+
54
+ .page-toc {
55
+ position: relative;
56
+ }
57
+
58
+ /* Animated marker indicator like VitePress */
59
+ .outline-marker {
60
+ position: absolute;
61
+ top: 0;
62
+ left: 0;
63
+ z-index: 0;
64
+ opacity: 0;
65
+ width: 2px;
66
+ border-radius: 2px;
67
+ height: 18px;
68
+ background-color: var(--bp-c-brand-1);
69
+ transition:
70
+ top 0.25s cubic-bezier(0, 1, 0.5, 1),
71
+ opacity 0.25s,
72
+ background-color 0.5s;
73
+ }
74
+
75
+ .page-toc a {
76
+ position: relative;
77
+ display: block;
78
+ padding: 4px 0 4px 16px;
79
+ color: var(--bp-c-text-2);
80
+ text-decoration: none;
81
+ border-left: 1px solid var(--bp-c-divider);
82
+ transition: color 0.25s;
83
+ font-size: 13px;
84
+ line-height: 20px;
85
+ }
86
+
87
+ .page-toc a:hover {
88
+ color: var(--bp-c-text-1);
89
+ }
90
+
91
+ .page-toc a.active {
92
+ color: var(--bp-c-text-1);
93
+ font-weight: 500;
94
+ border-left-color: transparent;
95
+ }
96
+
97
+ .page-toc a.level-3 {
98
+ padding-left: 28px;
99
+ }
100
+
101
+ .page-toc a.level-4 {
102
+ padding-left: 40px;
103
+ }
104
+
105
+ .page-toc a.level-5 {
106
+ padding-left: 52px;
107
+ }
108
+
109
+ .page-toc a.level-6 {
110
+ padding-left: 64px;
111
+ }
112
+ </style>
113
+
114
+ <script>
115
+ // VitePress-style scrollspy with animated marker
116
+ function initPageTOC() {
117
+ const tocContainer = document.querySelector('.page-toc');
118
+ const marker = document.querySelector('.outline-marker');
119
+ const tocLinks = document.querySelectorAll('.page-toc a');
120
+ const headings = Array.from(document.querySelectorAll('h2[id], h3[id], h4[id], h5[id], h6[id]'));
121
+ const scrollContainer = document.querySelector('.VPContent');
122
+
123
+ if (!tocLinks.length || !headings.length || !scrollContainer || !marker) return;
124
+
125
+ // Get scroll offset (nav height)
126
+ function getScrollOffset() {
127
+ return 100; // Account for nav + some padding
128
+ }
129
+
130
+ // Throttle and debounce utility
131
+ function throttleAndDebounce(fn, delay) {
132
+ let timeoutId;
133
+ let called = false;
134
+
135
+ return function() {
136
+ if (timeoutId) clearTimeout(timeoutId);
137
+ if (!called) {
138
+ fn();
139
+ called = true;
140
+ setTimeout(() => { called = false; }, delay);
141
+ } else {
142
+ timeoutId = setTimeout(fn, delay);
143
+ }
144
+ };
145
+ }
146
+
147
+ // Activate a TOC link by hash
148
+ function activateLink(hash) {
149
+ // Remove previous active class
150
+ tocLinks.forEach(link => link.classList.remove('active'));
151
+
152
+ if (hash) {
153
+ // Find and activate new link
154
+ const activeLink = tocContainer.querySelector('a[href="' + decodeURIComponent(hash) + '"]');
155
+
156
+ if (activeLink) {
157
+ activeLink.classList.add('active');
158
+
159
+ // Position the marker at the active link
160
+ const linkRect = activeLink.getBoundingClientRect();
161
+ const containerRect = tocContainer.getBoundingClientRect();
162
+ const top = linkRect.top - containerRect.top;
163
+
164
+ marker.style.top = top + 'px';
165
+ marker.style.opacity = '1';
166
+ } else {
167
+ marker.style.opacity = '0';
168
+ }
169
+ } else {
170
+ marker.style.opacity = '0';
171
+ }
172
+ }
173
+
174
+ // Set active link based on scroll position
175
+ function setActiveLink() {
176
+ const scrollY = scrollContainer.scrollTop;
177
+ const scrollOffset = getScrollOffset();
178
+
179
+ // Get heading positions relative to scroll container
180
+ const headingPositions = headings.map(heading => {
181
+ // Get the element's position relative to the scroll container
182
+ const rect = heading.getBoundingClientRect();
183
+ const containerRect = scrollContainer.getBoundingClientRect();
184
+ const top = rect.top - containerRect.top + scrollY;
185
+
186
+ return {
187
+ id: heading.id,
188
+ top: top
189
+ };
190
+ }).filter(h => !isNaN(h.top)).sort((a, b) => a.top - b.top);
191
+
192
+ // Find the last heading that's above the current scroll position
193
+ let activeId = null;
194
+ for (const { id, top } of headingPositions) {
195
+ if (top > scrollY + scrollOffset + 4) {
196
+ break;
197
+ }
198
+ activeId = id;
199
+ }
200
+
201
+ // If no heading found and we're at the top, use the first one
202
+ if (!activeId && headingPositions.length > 0 && scrollY < headingPositions[0].top) {
203
+ activeId = headingPositions[0].id;
204
+ }
205
+
206
+ // Activate the link
207
+ activateLink(activeId ? '#' + activeId : null);
208
+ }
209
+
210
+ // Throttled scroll handler
211
+ const onScroll = throttleAndDebounce(setActiveLink, 100);
212
+
213
+ // Smooth scroll to anchor
214
+ tocLinks.forEach(link => {
215
+ link.addEventListener('click', (e) => {
216
+ e.preventDefault();
217
+ const targetId = link.getAttribute('href').substring(1);
218
+ const targetElement = document.getElementById(targetId);
219
+ if (targetElement) {
220
+ // Calculate target position
221
+ const containerRect = scrollContainer.getBoundingClientRect();
222
+ const targetRect = targetElement.getBoundingClientRect();
223
+ const scrollTo = targetRect.top - containerRect.top + scrollContainer.scrollTop - 80;
224
+
225
+ scrollContainer.scrollTo({
226
+ top: scrollTo,
227
+ behavior: 'smooth'
228
+ });
229
+
230
+ // Update URL without page reload
231
+ history.pushState(null, '', '#' + targetId);
232
+ }
233
+ });
234
+ });
235
+
236
+ // Listen to scroll events on the actual scrolling container
237
+ scrollContainer.addEventListener('scroll', onScroll);
238
+
239
+ // Handle URL hash on page load
240
+ if (window.location.hash) {
241
+ setTimeout(() => {
242
+ const targetId = window.location.hash.substring(1);
243
+ const targetElement = document.getElementById(targetId);
244
+ if (targetElement) {
245
+ const containerRect = scrollContainer.getBoundingClientRect();
246
+ const targetRect = targetElement.getBoundingClientRect();
247
+ const scrollTo = targetRect.top - containerRect.top + scrollContainer.scrollTop - 80;
248
+
249
+ scrollContainer.scrollTo({
250
+ top: scrollTo,
251
+ behavior: 'smooth'
252
+ });
253
+ }
254
+ }, 100);
255
+ }
256
+
257
+ // Initial update
258
+ requestAnimationFrame(setActiveLink);
259
+ }
260
+
261
+ // Initialize when DOM is ready
262
+ if (document.readyState === 'loading') {
263
+ document.addEventListener('DOMContentLoaded', initPageTOC);
264
+ } else {
265
+ initPageTOC();
266
+ }
267
+ </script>
@@ -0,0 +1,42 @@
1
+ <div class="VPSidebarItem sidebar-section" style="margin-bottom: 16px;">
2
+ <button
3
+ style="width: 100%; display: flex; align-items: center; justify-content: space-between; padding: 8px 24px; font-size: 14px; font-weight: 600; color: var(--bp-c-text-1); background: transparent; border: none; cursor: pointer; transition: color 0.25s;"
4
+ onclick="toggleSection(this.parentElement)"
5
+ onmouseover="this.style.color='var(--bp-c-brand-1)'"
6
+ onmouseout="this.style.color='var(--bp-c-text-1)'"
7
+ >
8
+ <span>{{ title }}</span>
9
+ <svg class="chevron" style="width: 16px; height: 16px; transition: transform 0.2s ease-in-out;" fill="none" stroke="currentColor" viewBox="0 0 24 24">
10
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7"></path>
11
+ </svg>
12
+ </button>
13
+ <div class="sidebar-items-wrapper">
14
+ <ul class="sidebar-items" style="list-style: none; margin: 4px 0 0 0; padding: 0;">
15
+ {{ items }}
16
+ </ul>
17
+ </div>
18
+ </div>
19
+
20
+ <style>
21
+ .sidebar-items-wrapper {
22
+ overflow: hidden;
23
+ transition: max-height 0.3s ease-in-out, opacity 0.2s ease-in-out;
24
+ max-height: 500px;
25
+ opacity: 1;
26
+ }
27
+
28
+ .sidebar-section.collapsed .sidebar-items-wrapper {
29
+ max-height: 0;
30
+ opacity: 0;
31
+ }
32
+
33
+ .sidebar-section.collapsed .chevron {
34
+ transform: rotate(-90deg);
35
+ }
36
+ </style>
37
+
38
+ <script>
39
+ function toggleSection(section) {
40
+ section.classList.toggle('collapsed');
41
+ }
42
+ </script>
@@ -0,0 +1,54 @@
1
+ <nav class="VPSidebar">
2
+ <div class="sidebar-content">
3
+ {{ sections }}
4
+ </div>
5
+ </nav>
6
+
7
+ <style>
8
+ .VPSidebar {
9
+ position: fixed;
10
+ top: var(--bp-nav-height, 64px);
11
+ bottom: 0;
12
+ left: 0;
13
+ width: var(--bp-sidebar-width, 272px);
14
+ background-color: var(--bp-sidebar-bg-color, var(--bp-c-bg-alt));
15
+ border-right: 1px solid var(--bp-c-divider);
16
+ overflow-y: auto;
17
+ overflow-x: hidden;
18
+ padding: 24px 0 24px 0;
19
+ z-index: var(--bp-z-index-sidebar, 25);
20
+ }
21
+
22
+ .sidebar-content {
23
+ width: var(--bp-sidebar-width, 272px);
24
+ margin-left: auto;
25
+ }
26
+
27
+ /* At 960px+ (tablet), position sidebar normally */
28
+ @media (min-width: 960px) {
29
+ .VPSidebar {
30
+ left: 0;
31
+ width: var(--bp-sidebar-width, 272px);
32
+ }
33
+
34
+ .sidebar-content {
35
+ width: 100%;
36
+ margin-left: 0;
37
+ }
38
+ }
39
+
40
+ /* At 1440px+ (ultra-wide), extend sidebar to fill left margin */
41
+ @media (min-width: 1440px) {
42
+ .VPSidebar {
43
+ /* Extend width to include left margin area */
44
+ width: calc((100vw - var(--bp-layout-max-width, 1440px)) / 2 + var(--bp-sidebar-width, 272px));
45
+ /* Padding pushes content to the right position */
46
+ padding-left: calc((100vw - var(--bp-layout-max-width, 1440px)) / 2);
47
+ }
48
+
49
+ .sidebar-content {
50
+ width: var(--bp-sidebar-width, 272px);
51
+ margin-left: 0;
52
+ }
53
+ }
54
+ </style>
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Get all Bun theme CSS combined
3
+ */
4
+ export declare function getBunThemeCSS(): string;
5
+ /**
6
+ * Get Bun theme CSS variables only
7
+ */
8
+ export declare function getBunVars(): string;
9
+ /**
10
+ * Get Bun base styles only
11
+ */
12
+ export declare function getBunBase(): string;
13
+ /**
14
+ * Get Bun custom block styles only
15
+ */
16
+ export declare function getBunCustomBlocks(): string;
17
+ /**
18
+ * Get Bun code group styles only
19
+ */
20
+ export declare function getBunCodeGroups(): string;
21
+ /**
22
+ * Get Bun extra styles only
23
+ */
24
+ export declare function getBunExtras(): string;
25
+ export declare interface BunTheme {
26
+ name: string
27
+ getCSS: () => string
28
+ getVars: () => string
29
+ getBase: () => string
30
+ getCustomBlocks: () => string
31
+ getCodeGroups: () => string
32
+ getExtras: () => string
33
+ }
34
+ export default bunTheme;
@@ -0,0 +1,24 @@
1
+ import bunTheme, { getBunThemeCSS } from './bun';
2
+ import vitePressTheme, { getVitePressThemeCSS } from './vitepress';
3
+ /**
4
+ * Get theme CSS by name
5
+ */
6
+ export declare function getThemeCSS(themeName?: ThemeName): string;
7
+ /**
8
+ * Available themes
9
+ */
10
+ export declare const themes: {
11
+ vitepress: unknown;
12
+ bun: unknown
13
+ };
14
+ /**
15
+ * Default theme name
16
+ */
17
+ export declare const defaultTheme: ThemeName;
18
+ export declare interface Theme {
19
+ name: string
20
+ getCSS: () => string
21
+ }
22
+ export type ThemeName = 'vitepress' | 'bun'
23
+ export { getVitePressThemeCSS, vitePressTheme, getBunThemeCSS, bunTheme };
24
+ export default themes;