botdocs 0.3.0 → 0.5.0

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 (44) hide show
  1. package/README.md +20 -2
  2. package/dist/src/builder/chunker.d.ts +18 -0
  3. package/dist/src/builder/chunker.js +62 -1
  4. package/dist/src/builder/embedder.js +5 -2
  5. package/dist/src/builder/index-size.d.ts +3 -0
  6. package/dist/src/builder/index-size.js +16 -0
  7. package/dist/src/builder/index.js +34 -3
  8. package/dist/src/builder/markdown-processor.d.ts +8 -1
  9. package/dist/src/builder/markdown-processor.js +40 -7
  10. package/dist/src/builder/paths.d.ts +6 -0
  11. package/dist/src/builder/paths.js +13 -0
  12. package/dist/src/builder/site-generator.d.ts +19 -2
  13. package/dist/src/builder/site-generator.js +117 -34
  14. package/dist/src/builder/template-engine.d.ts +4 -4
  15. package/dist/src/builder/template-engine.js +5 -1
  16. package/dist/src/builder/vector-db-builder.d.ts +1 -0
  17. package/dist/src/builder/vector-db-builder.js +1 -0
  18. package/dist/src/cli/index.js +61 -18
  19. package/dist/src/cli/options.d.ts +2 -0
  20. package/dist/src/cli/options.js +2 -1
  21. package/dist/src/cli/server.d.ts +6 -0
  22. package/dist/src/cli/server.js +79 -0
  23. package/dist/src/cli/watcher.d.ts +7 -0
  24. package/dist/src/cli/watcher.js +40 -0
  25. package/dist/src/shared/site-root.d.ts +2 -0
  26. package/dist/src/shared/site-root.js +9 -0
  27. package/dist/src/types/config.d.ts +4 -0
  28. package/dist/src/types/config.js +2 -0
  29. package/dist/src/types/document.d.ts +1 -1
  30. package/dist-client/assets/chatbox-Dw_HFrfR.js +8 -0
  31. package/dist-client/assets/rag-engine-B9wYRzqT.js +1 -0
  32. package/dist-client/bundle.js +1 -1
  33. package/dist-client/wasm/ort-wasm-simd-threaded.asyncify.wasm +0 -0
  34. package/man/botdocs.1 +193 -0
  35. package/package.json +18 -2
  36. package/src/styles/chat.css +144 -0
  37. package/src/styles/themes/classic.css +29 -0
  38. package/src/styles/themes/material.css +29 -0
  39. package/src/styles/themes/minimal.css +34 -0
  40. package/src/styles/themes/modern.css +34 -0
  41. package/src/styles/themes/slate.css +32 -36
  42. package/src/templates/layout.html +21 -2
  43. package/dist-client/assets/chatbox-CmTTiB2Z.js +0 -1
  44. package/dist-client/assets/rag-engine-L2vj3Y0G.js +0 -7
@@ -112,47 +112,49 @@ body {
112
112
  font-weight: 600;
113
113
  }
114
114
 
115
+ .nav-list li.nav-group > a {
116
+ color: var(--sidebar-text);
117
+ font-weight: 600;
118
+ position: relative;
119
+ padding-right: 1.75rem;
120
+ }
121
+
122
+ .nav-list li.nav-group > a::after {
123
+ content: 'â€ē';
124
+ position: absolute;
125
+ right: 1rem;
126
+ transition: transform 0.2s;
127
+ }
128
+
129
+ .nav-list li.nav-group:has(> .nav-list) > a::after {
130
+ transform: rotate(90deg);
131
+ }
132
+
133
+ .nav-list .nav-list {
134
+ margin-top: 0.125rem;
135
+ padding-left: 1rem;
136
+ }
137
+
138
+ .nav-list .nav-list a {
139
+ font-weight: 400;
140
+ font-size: 0.85rem;
141
+ }
142
+
115
143
  /* Main Content - Split screen with code examples */
116
144
  .main-content {
117
145
  margin-left: var(--sidebar-width);
118
146
  flex: 1;
119
147
  padding: 0;
120
148
  background: var(--bg-primary);
121
- display: flex;
122
- gap: 0;
123
149
  }
124
150
 
125
151
  .content-wrapper {
126
- flex: 1;
127
152
  max-width: none;
128
153
  padding: 3rem 2.5rem;
129
154
  background: var(--bg-primary);
130
155
  min-width: 0;
131
156
  }
132
157
 
133
- /* Code blocks stick to right side for split-screen effect */
134
- .content-wrapper pre {
135
- position: relative;
136
- margin-left: calc(-50vw + 50%);
137
- margin-right: -2.5rem;
138
- margin-top: -3rem;
139
- margin-bottom: 2rem;
140
- width: calc(100% + 50vw - 50% + 2.5rem);
141
- max-width: 800px;
142
- float: right;
143
- clear: right;
144
- }
145
-
146
- /* Adjust paragraph spacing when followed by code */
147
- .content-wrapper p + pre {
148
- margin-top: -2rem;
149
- }
150
-
151
- .content-wrapper h3 + pre,
152
- .content-wrapper h4 + pre {
153
- margin-top: 1rem;
154
- }
155
-
156
158
  /* Typography - clean and technical */
157
159
  h1, h2, h3, h4, h5, h6 {
158
160
  margin-top: 2.5rem;
@@ -228,8 +230,10 @@ code {
228
230
  }
229
231
 
230
232
  pre {
231
- background: var(--code-bg);
232
- color: var(--code-text);
233
+ /* Shiki inlines a light-theme background/color on the element itself;
234
+ override it so slate's dark code style actually wins. */
235
+ background: var(--code-bg) !important;
236
+ color: var(--code-text) !important;
233
237
  padding: 1.5rem;
234
238
  border-radius: 6px;
235
239
  overflow-x: auto;
@@ -692,14 +696,6 @@ img {
692
696
  padding: 2rem 1.5rem;
693
697
  }
694
698
 
695
- .content-wrapper pre {
696
- margin-left: 0;
697
- margin-right: 0;
698
- width: 100%;
699
- float: none;
700
- clear: both;
701
- }
702
-
703
699
  .layout {
704
700
  flex-direction: column;
705
701
  }
@@ -5,6 +5,15 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <meta name="description" content="{{description}}">
7
7
  <title>{{title}} - {{siteTitle}}</title>
8
+ <meta property="og:title" content="{{title}} - {{siteTitle}}">
9
+ <meta property="og:description" content="{{description}}">
10
+ <meta property="og:type" content="website">
11
+ {{#if ogUrl}}
12
+ <meta property="og:url" content="{{ogUrl}}">
13
+ <link rel="canonical" href="{{ogUrl}}">
14
+ {{/if}}
15
+ <meta name="twitter:card" content="summary">
16
+ <meta name="botdocs-root" content="{{root}}">
8
17
  <script>
9
18
  // Apply theme immediately to prevent flash
10
19
  (function() {
@@ -14,7 +23,7 @@
14
23
  document.documentElement.setAttribute('data-theme', theme);
15
24
  })();
16
25
  </script>
17
- <link rel="stylesheet" href="/assets/css/bundle.css">
26
+ <link rel="stylesheet" href="{{root}}assets/css/bundle.css">
18
27
  </head>
19
28
  <body>
20
29
  <div class="layout">
@@ -35,6 +44,13 @@
35
44
  {{content}}
36
45
  </div>
37
46
 
47
+ {{#if chatEnabled}}
48
+ <p class="ai-disclosure">
49
+ 🔒 This site's search assistant runs a local AI model in your browser — no cloud AI,
50
+ no tracking. See the â„šī¸ in the chat panel for details.
51
+ </p>
52
+ {{/if}}
53
+
38
54
  {{#if attribution}}
39
55
  <!-- Footer Attribution -->
40
56
  <footer class="botdocs-attribution">
@@ -61,6 +77,9 @@
61
77
  {{/if}}
62
78
  </div>
63
79
 
64
- <script type="module" src="/assets/js/bundle.js"></script>
80
+ {{#if chatEnabled}}
81
+ <script>window.__BOTDOCS_SEARCH_CONFIG__ = {{searchConfigJson}};</script>
82
+ {{/if}}
83
+ <script type="module" src="{{root}}assets/js/bundle.js"></script>
65
84
  </body>
66
85
  </html>
@@ -1 +0,0 @@
1
- import{_ as t}from"../bundle.js";function e(t){let e=t;return e=function(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}(e),e=e.replace(/```(\w+)?\n([\s\S]*?)```/g,(t,e,n)=>`<pre><code${e?` class="language-${e}"`:""}>${n.trim()}</code></pre>`),e=e.replace(/`([^`]+)`/g,"<code>$1</code>"),e=e.replace(/\*\*(.+?)\*\*/g,"<strong>$1</strong>"),e=e.replace(/__(.+?)__/g,"<strong>$1</strong>"),e=e.replace(/\*(.+?)\*/g,"<em>$1</em>"),e=e.replace(/_(.+?)_/g,"<em>$1</em>"),e=e.replace(/\[([^\]]+)\]\(([^)]+)\)/g,'<a href="$2" target="_blank">$1</a>'),e=e.replace(/^### (.+)$/gm,"<h3>$1</h3>"),e=e.replace(/^## (.+)$/gm,"<h2>$1</h2>"),e=e.replace(/^# (.+)$/gm,"<h1>$1</h1>"),e=e.replace(/^---$/gm,"<hr />"),e=e.replace(/\n\n/g,"</p><p>"),e=e.replace(/\n/g,"<br />"),e=`<p>${e}</p>`,e=e.replace(/<p><\/p>/g,""),e=e.replace(/<p>(<pre>)/g,"$1"),e=e.replace(/(<\/pre>)<\/p>/g,"$1"),e=e.replace(/<p>(<h[1-3]>)/g,"$1"),e=e.replace(/(<\/h[1-3]>)<\/p>/g,"$1"),e=e.replace(/<p>(<hr \/>)<\/p>/g,"$1"),e}let n=!1,a=[],s=!1;const c="botdocs_chat_history",o="botdocs_chat_open",i="botdocs_chat_timestamp",r=6e5;function l(){const t=document.getElementById("chat-toggle"),e=document.getElementById("chat-container");t&&e?(!function(){try{const t=localStorage.getItem(i),e=Date.now();if(t){if(e-parseInt(t,10)>r)return void I()}const s=localStorage.getItem(c);s&&(a=JSON.parse(s));const l=localStorage.getItem(o);l&&(n=JSON.parse(l))}catch(t){console.error("Failed to load chat state:",t),a=[],n=!1}}(),t.addEventListener("click",()=>{d()}),h(e),a.length>0&&function(){const t=document.getElementById("chat-messages");if(!t)return;t.innerHTML="";for(const e of a)y(e,t)}(),n&&(e.style.display="flex",s||g().then(()=>{s=!0}))):console.error("Chat elements not found")}async function d(){n=!n;const t=document.getElementById("chat-container");t&&(t.style.display=n?"flex":"none"),n&&!s&&(await g(),s=!0),function(){try{localStorage.setItem(o,JSON.stringify(n))}catch(t){console.error("Failed to save chat state:",t)}}()}function h(t){t.innerHTML='\n <div class="chat-header">\n <h3>Ask me anything</h3>\n <div class="chat-header-actions">\n <button class="chat-clear" id="chat-clear" title="Clear chat history">đŸ—‘ī¸</button>\n <button class="chat-close" id="chat-close">×</button>\n </div>\n </div>\n <div class="chat-status" id="chat-status" style="display: none;">\n Initializing chat...\n </div>\n <div class="chat-messages" id="chat-messages">\n <div class="chat-message assistant">\n <div class="message-content">\n 👋 Hi! I\'m your documentation assistant. Ask me anything about these docs!\n </div>\n </div>\n </div>\n <div class="chat-input-container">\n <div class="chat-input-wrapper">\n <textarea\n class="chat-input"\n id="chat-input"\n placeholder="Ask a question..."\n rows="1"\n ></textarea>\n <button class="chat-send" id="chat-send">Send</button>\n </div>\n </div>\n ';const e=document.getElementById("chat-close"),n=document.getElementById("chat-clear"),a=document.getElementById("chat-send"),c=document.getElementById("chat-input");if(e&&e.addEventListener("click",d),n&&n.addEventListener("click",m),a&&c&&(a.addEventListener("click",()=>u(c)),c.addEventListener("keypress",t=>{"Enter"!==t.key||t.shiftKey||(t.preventDefault(),u(c))}),c.addEventListener("input",()=>{c.style.height="auto",c.style.height=c.scrollHeight+"px"})),s){const t=document.getElementById("chat-status");t&&(t.style.display="none")}}async function g(){const e=document.getElementById("chat-status");if(e)try{e.style.display="block",e.textContent="Loading AI models...";const{initializeRAG:n,isRAGReady:a}=await t(async()=>{const{initializeRAG:t,isRAGReady:e}=await import("./rag-engine-L2vj3Y0G.js");return{initializeRAG:t,isRAGReady:e}},[]);await n(t=>{e.innerHTML=`\n Loading models... ${Math.round(t)}%\n <div class="progress-bar">\n <div class="progress-fill" style="width: ${t}%"></div>\n </div>\n `}),a()&&(e.style.display="none")}catch(n){console.error("Failed to initialize RAG:",n),e.textContent="âš ī¸ Chat unavailable"}}function m(){if(confirm("Clear chat history?")){I();const t=document.getElementById("chat-messages");t&&(t.innerHTML='\n <div class="chat-message assistant">\n <div class="message-content">\n 👋 Hi! I\'m your documentation assistant. Ask me anything about these docs!\n </div>\n </div>\n ')}}async function u(e){const n=e.value.trim();if(!n)return;p({role:"user",content:n}),e.value="",e.style.height="auto";const a=document.getElementById("chat-send");a&&(a.disabled=!0),e.disabled=!0,function(){const t=document.getElementById("chat-messages");if(!t)return;const e=document.createElement("div");e.id="loading-indicator",e.className="chat-message assistant",e.innerHTML='\n <div class="loading-indicator">\n <div class="loading-dot"></div>\n <div class="loading-dot"></div>\n <div class="loading-dot"></div>\n </div>\n ',t.appendChild(e),t.scrollTop=t.scrollHeight}();try{const{queryRAG:e}=await t(async()=>{const{queryRAG:t}=await import("./rag-engine-L2vj3Y0G.js");return{queryRAG:t}},[]),a=await e(n);v(),p({role:"assistant",content:a.answer,citations:a.sources})}catch(s){console.error("Chat error:",s),v(),p({role:"assistant",content:"Sorry, I encountered an error. Please try again."})}finally{a&&(a.disabled=!1),e.disabled=!1,e.focus()}}function p(t){a.push(t),function(){try{localStorage.setItem(c,JSON.stringify(a)),localStorage.setItem(i,Date.now().toString())}catch(t){console.error("Failed to save chat history:",t)}}();const e=document.getElementById("chat-messages");e&&y(t,e)}function y(t,n){const a=document.createElement("div");a.className=`chat-message ${t.role}`;let s="";s="user"===t.role?f(t.content):e(t.content);let c=`<div class="message-content">${s}</div>`;if(t.citations&&t.citations.length>0){c+='<div class="message-citations">',c+='<div class="citations-label">📚 Sources:</div>';for(const e of t.citations)c+=`<a href="${f(e.url)}" class="citation-link">${f(e.title)}</a>`;c+="</div>"}a.innerHTML=c,n.appendChild(a),n.scrollTo({top:n.scrollHeight,behavior:"smooth"})}function v(){const t=document.getElementById("loading-indicator");t&&t.remove()}function f(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}function I(){try{localStorage.removeItem(c),localStorage.removeItem(i),a=[]}catch(t){console.error("Failed to clear chat history:",t)}}export{p as addMessage,l as initChat,h as renderChatUI,d as toggleChat};