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.
- package/README.md +20 -2
- package/dist/src/builder/chunker.d.ts +18 -0
- package/dist/src/builder/chunker.js +62 -1
- package/dist/src/builder/embedder.js +5 -2
- package/dist/src/builder/index-size.d.ts +3 -0
- package/dist/src/builder/index-size.js +16 -0
- package/dist/src/builder/index.js +34 -3
- package/dist/src/builder/markdown-processor.d.ts +8 -1
- package/dist/src/builder/markdown-processor.js +40 -7
- package/dist/src/builder/paths.d.ts +6 -0
- package/dist/src/builder/paths.js +13 -0
- package/dist/src/builder/site-generator.d.ts +19 -2
- package/dist/src/builder/site-generator.js +117 -34
- package/dist/src/builder/template-engine.d.ts +4 -4
- package/dist/src/builder/template-engine.js +5 -1
- package/dist/src/builder/vector-db-builder.d.ts +1 -0
- package/dist/src/builder/vector-db-builder.js +1 -0
- package/dist/src/cli/index.js +61 -18
- package/dist/src/cli/options.d.ts +2 -0
- package/dist/src/cli/options.js +2 -1
- package/dist/src/cli/server.d.ts +6 -0
- package/dist/src/cli/server.js +79 -0
- package/dist/src/cli/watcher.d.ts +7 -0
- package/dist/src/cli/watcher.js +40 -0
- package/dist/src/shared/site-root.d.ts +2 -0
- package/dist/src/shared/site-root.js +9 -0
- package/dist/src/types/config.d.ts +4 -0
- package/dist/src/types/config.js +2 -0
- package/dist/src/types/document.d.ts +1 -1
- package/dist-client/assets/chatbox-Dw_HFrfR.js +8 -0
- package/dist-client/assets/rag-engine-B9wYRzqT.js +1 -0
- package/dist-client/bundle.js +1 -1
- package/dist-client/wasm/ort-wasm-simd-threaded.asyncify.wasm +0 -0
- package/man/botdocs.1 +193 -0
- package/package.json +18 -2
- package/src/styles/chat.css +144 -0
- package/src/styles/themes/classic.css +29 -0
- package/src/styles/themes/material.css +29 -0
- package/src/styles/themes/minimal.css +34 -0
- package/src/styles/themes/modern.css +34 -0
- package/src/styles/themes/slate.css +32 -36
- package/src/templates/layout.html +21 -2
- package/dist-client/assets/chatbox-CmTTiB2Z.js +0 -1
- 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
|
|
232
|
-
|
|
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="
|
|
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
|
-
|
|
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};
|