rushchatbot 1.6.7

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 (51) hide show
  1. package/INTEGRATION.md +559 -0
  2. package/index.html +13 -0
  3. package/package/INTEGRATION.md +717 -0
  4. package/package/README.md +717 -0
  5. package/package/package-lock.json +3221 -0
  6. package/package/package.json +101 -0
  7. package/package/src/cli/index.ts +94 -0
  8. package/package/src/client/ChatWidget.tsx +163 -0
  9. package/package/src/client.ts +2 -0
  10. package/package/src/core/RushChatbot.ts +192 -0
  11. package/package/src/index.ts +5 -0
  12. package/package/src/server/guardrails.ts +107 -0
  13. package/package/src/server/index.ts +210 -0
  14. package/package/src/server/matcher.ts +140 -0
  15. package/package/src/shared/types.ts +58 -0
  16. package/package/src/shims-vue.d.ts +5 -0
  17. package/package/src/vanilla/index.ts +302 -0
  18. package/package/src/vanilla.ts +3 -0
  19. package/package/src/vue/ChatWidget.vue +198 -0
  20. package/package/src/vue.ts +3 -0
  21. package/package/src/vue2/ChatWidget.vue +204 -0
  22. package/package/src/vue2.ts +3 -0
  23. package/package/tsconfig.json +19 -0
  24. package/package/vite.config.ts +86 -0
  25. package/package.json +35 -0
  26. package/public/favicon.svg +1 -0
  27. package/public/icons.svg +24 -0
  28. package/server/data/analytics.json +795 -0
  29. package/server/data/chatbot.config.json +26 -0
  30. package/server/data/questions.json +238 -0
  31. package/server/data/questions.tl.json +182 -0
  32. package/server/index.ts +11 -0
  33. package/server/lib/guardrails.ts +107 -0
  34. package/server/lib/matcher.ts +140 -0
  35. package/server/routes/chat.ts +180 -0
  36. package/server/tsconfig.json +11 -0
  37. package/src/App.css +184 -0
  38. package/src/App.tsx +135 -0
  39. package/src/assets/hero.png +0 -0
  40. package/src/assets/react.svg +1 -0
  41. package/src/assets/vite.svg +1 -0
  42. package/src/components/ChatWidget.tsx +417 -0
  43. package/src/components/QuestionTree.tsx +57 -0
  44. package/src/hooks/useChatData.ts +49 -0
  45. package/src/index.css +111 -0
  46. package/src/main.tsx +10 -0
  47. package/src/types/index.ts +40 -0
  48. package/tsconfig.app.json +26 -0
  49. package/tsconfig.json +7 -0
  50. package/tsconfig.node.json +23 -0
  51. package/vite.config.ts +7 -0
@@ -0,0 +1,204 @@
1
+ <template>
2
+ <div v-if="state" :style="containerStyle">
3
+ <!-- Header -->
4
+ <div :style="{ background: theme.primaryColor, padding: '16px 20px', color: '#fff' }">
5
+ <div :style="{ fontWeight: 700, fontSize: '16px' }">{{ state.config.branding.title }}</div>
6
+ <div :style="{ fontSize: '12px', opacity: 0.85 }">{{ state.config.branding.subtitle }}</div>
7
+ </div>
8
+
9
+ <!-- Messages -->
10
+ <div ref="scrollEl" :style="messagesStyle">
11
+ <div v-for="msg in state.messages" :key="msg.id"
12
+ :style="{ display: 'flex', flexDirection: 'column', alignItems: msg.role === 'user' ? 'flex-end' : 'flex-start' }">
13
+ <div :style="bubbleStyle(msg.role === 'user')">
14
+ <template v-if="msg.subquestions && msg.subquestions.length > 0">
15
+ <div :style="{ marginBottom: '8px' }" v-html="md(msg.text)" />
16
+ <div :style="{ display: 'flex', flexDirection: 'column', gap: '4px' }">
17
+ <button v-for="sub in msg.subquestions" :key="sub.id"
18
+ @click="chat.clickSub(sub, msg.subquestions)"
19
+ :style="subBtnStyle">
20
+ {{ sub.question }}
21
+ </button>
22
+ <button @click="chat.backToMain()" :style="backBtnStyle">← Back to main menu</button>
23
+ </div>
24
+ </template>
25
+ <template v-else>
26
+ <div v-if="msg.role === 'bot'" v-html="md(msg.text)" />
27
+ <button v-if="msg.role === 'bot' && msg.isEndChat" @click="chat.startNewChat()" :style="newChatBtnStyle">🔄 Start a new chat</button>
28
+ <span v-else-if="msg.role === 'user'">{{ msg.text }}</span>
29
+ </template>
30
+ </div>
31
+ </div>
32
+
33
+ <!-- Thinking dots -->
34
+ <div v-if="state.loading" :style="{ alignSelf: 'flex-start', background: theme.botBubbleColor, padding: '10px 16px', borderRadius: '12px' }">
35
+ <span :style="{ display: 'flex', gap: '4px', alignItems: 'center' }">
36
+ <span v-for="(dot, i) in dots" :key="i" :style="dotStyle(i)" />
37
+ </span>
38
+ </div>
39
+
40
+ <!-- Main questions -->
41
+ <div v-if="state.showMain && state.questions.length > 0" :style="{ display: 'flex', flexDirection: 'column', gap: '4px', marginTop: '4px' }">
42
+ <button v-for="q in state.questions" :key="q.id"
43
+ @click="chat.clickMain(q)"
44
+ :style="mainBtnStyle">
45
+ {{ q.question }}
46
+ </button>
47
+ <button v-if="!hideEndChat" @click="chat.endChat()" :style="endBtnStyle">👋 I'm done, thanks!</button>
48
+ </div>
49
+
50
+ <div ref="bottom" />
51
+ </div>
52
+
53
+ <!-- Input -->
54
+ <form v-if="!hideInput" @submit.prevent="chat.submitQuery()" :style="{ display: 'flex', borderTop: '1px solid #e5e7eb', padding: '12px', gap: '8px' }">
55
+ <input
56
+ :value="state.input"
57
+ @input="chat.setInput($event.target.value)"
58
+ :placeholder="placeholder || 'Type a message...'"
59
+ :disabled="state.loading"
60
+ :style="inputStyle"
61
+ />
62
+ <button type="submit" :disabled="state.loading" :style="sendBtnStyle">{{ sendLabel || 'Send' }}</button>
63
+ </form>
64
+ </div>
65
+ </template>
66
+
67
+ <script>
68
+ import { RushChatbot, parseMarkdown } from '../core/RushChatbot'
69
+
70
+ export default {
71
+ name: 'RushChatbotWidget',
72
+ props: {
73
+ apiBase: { type: String, default: 'http://localhost:3001/api/chat' },
74
+ width: { type: Number, default: null },
75
+ height: { type: Number, default: null },
76
+ primaryColor: { type: String, default: null },
77
+ bgColor: { type: String, default: null },
78
+ borderRadius: { type: Number, default: 16 },
79
+ showShadow: { type: Boolean, default: true },
80
+ placeholder: { type: String, default: null },
81
+ sendLabel: { type: String, default: null },
82
+ hideInput: { type: Boolean, default: false },
83
+ hideEndChat: { type: Boolean, default: false },
84
+ },
85
+ data() {
86
+ return { state: null, chat: null, unsub: null }
87
+ },
88
+ mounted() {
89
+ this.chat = new RushChatbot({ apiBase: this.apiBase })
90
+ this.unsub = this.chat.subscribe(s => { this.state = s })
91
+ this.chat.init()
92
+ },
93
+ beforeDestroy() {
94
+ if (this.unsub) this.unsub()
95
+ },
96
+ watch: {
97
+ 'state.messages'() { this.$nextTick(() => this.scrollToBottom()) },
98
+ 'state.loading'() { this.$nextTick(() => this.scrollToBottom()) },
99
+ },
100
+ computed: {
101
+ dots() { return [0, 1, 2] },
102
+ theme() {
103
+ const base = (this.state && this.state.config && this.state.config.branding && this.state.config.branding.theme) || {}
104
+ return {
105
+ ...base,
106
+ ...(this.primaryColor ? { primaryColor: this.primaryColor } : {}),
107
+ ...(this.bgColor ? { backgroundColor: this.bgColor } : {}),
108
+ }
109
+ },
110
+ containerStyle() {
111
+ return {
112
+ fontFamily: this.theme.fontFamily,
113
+ color: this.theme.textColor,
114
+ background: this.theme.backgroundColor,
115
+ width: this.width ? this.width + 'px' : '100%',
116
+ height: this.height ? this.height + 'px' : '100%',
117
+ borderRadius: this.borderRadius + 'px',
118
+ boxShadow: this.showShadow ? '0 8px 32px rgba(0,0,0,0.15)' : 'none',
119
+ display: 'flex',
120
+ flexDirection: 'column',
121
+ overflow: 'hidden',
122
+ }
123
+ },
124
+ messagesStyle() {
125
+ return { flex: 1, overflowY: 'auto', padding: '16px', display: 'flex', flexDirection: 'column', gap: '8px' }
126
+ },
127
+ mainBtnStyle() {
128
+ return {
129
+ textAlign: 'left', padding: '8px 12px', borderRadius: '8px',
130
+ border: `1px solid ${this.theme.primaryColor}`, background: 'transparent',
131
+ color: this.theme.primaryColor, cursor: 'pointer', fontSize: '14px',
132
+ }
133
+ },
134
+ subBtnStyle() {
135
+ return {
136
+ display: 'block', width: '100%', textAlign: 'left',
137
+ padding: '8px 12px', borderRadius: '8px',
138
+ border: `1px solid ${this.theme.primaryColor}`, background: '#fff',
139
+ color: this.theme.primaryColor, cursor: 'pointer', fontSize: '14px',
140
+ }
141
+ },
142
+ backBtnStyle() {
143
+ return {
144
+ display: 'block', width: '100%', textAlign: 'left',
145
+ padding: '8px 12px', borderRadius: '8px',
146
+ border: '1px solid #6B7280', background: '#fff',
147
+ color: '#6B7280', cursor: 'pointer', fontSize: '14px',
148
+ }
149
+ },
150
+ endBtnStyle() {
151
+ return {
152
+ textAlign: 'left', padding: '8px 12px', borderRadius: '8px',
153
+ border: '1px solid #EF4444', background: 'transparent',
154
+ color: '#EF4444', cursor: 'pointer', fontSize: '14px', marginTop: '4px', width: '100%',
155
+ }
156
+ },
157
+ newChatBtnStyle() {
158
+ return {
159
+ display: 'block', marginTop: '10px', padding: '7px 14px', borderRadius: '8px',
160
+ border: 'none', background: this.theme.primaryColor,
161
+ color: '#fff', cursor: 'pointer', fontSize: '13px', width: '100%',
162
+ }
163
+ },
164
+ inputStyle() {
165
+ return { flex: 1, padding: '8px 12px', borderRadius: '8px', border: '1px solid #e5e7eb', fontSize: '14px', outline: 'none' }
166
+ },
167
+ sendBtnStyle() {
168
+ return {
169
+ background: this.theme.primaryColor, color: '#fff', border: 'none',
170
+ borderRadius: '8px', padding: '8px 16px',
171
+ cursor: (this.state && this.state.loading) ? 'not-allowed' : 'pointer', fontSize: '14px',
172
+ }
173
+ },
174
+ },
175
+ methods: {
176
+ md(text) { return parseMarkdown(text) },
177
+ bubbleStyle(isUser) {
178
+ return {
179
+ background: isUser ? this.theme.userBubbleColor : this.theme.botBubbleColor,
180
+ color: isUser ? '#fff' : this.theme.textColor,
181
+ padding: '10px 14px', borderRadius: '12px', maxWidth: '80%', fontSize: '14px', lineHeight: 1.5,
182
+ }
183
+ },
184
+ dotStyle(i) {
185
+ return {
186
+ width: '7px', height: '7px', borderRadius: '50%',
187
+ background: this.theme.primaryColor, display: 'inline-block',
188
+ animation: `rushchatbot2-bounce 1.2s ease-in-out ${i * 0.2}s infinite`,
189
+ }
190
+ },
191
+ scrollToBottom() {
192
+ const el = this.$refs.scrollEl
193
+ if (el) el.scrollTop = el.scrollHeight
194
+ },
195
+ },
196
+ }
197
+ </script>
198
+
199
+ <style>
200
+ @keyframes rushchatbot2-bounce {
201
+ 0%, 80%, 100% { transform: translateY(0); opacity: 0.4; }
202
+ 40% { transform: translateY(-6px); opacity: 1; }
203
+ }
204
+ </style>
@@ -0,0 +1,3 @@
1
+ export { default } from './vue2/ChatWidget.vue'
2
+ export { RushChatbot, parseMarkdown } from './core/RushChatbot'
3
+ export type { RushChatbotConfig, RushChatbotState } from './core/RushChatbot'
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "CommonJS",
5
+ "moduleResolution": "node",
6
+ "lib": ["ES2020", "DOM"],
7
+ "outDir": "./dist",
8
+ "rootDir": "./src",
9
+ "declaration": true,
10
+ "declarationMap": true,
11
+ "sourceMap": true,
12
+ "strict": true,
13
+ "esModuleInterop": true,
14
+ "skipLibCheck": true,
15
+ "jsx": "react-jsx"
16
+ },
17
+ "include": ["src/**/*"],
18
+ "exclude": ["src/client/**/*", "src/client.ts", "src/vue/**/*", "src/vue.ts", "src/vue2/**/*", "src/vue2.ts", "src/vanilla/**/*", "src/vanilla.ts"]
19
+ }
@@ -0,0 +1,86 @@
1
+ import { defineConfig } from 'vite'
2
+ import react from '@vitejs/plugin-react'
3
+ import vue from '@vitejs/plugin-vue'
4
+ import { resolve } from 'path'
5
+
6
+ const shared = {
7
+ outDir: 'dist',
8
+ emptyOutDir: false,
9
+ }
10
+
11
+ export default defineConfig(({ mode }) => {
12
+ if (mode === 'vue2') {
13
+ return {
14
+ plugins: [vue()],
15
+ build: {
16
+ ...shared,
17
+ lib: {
18
+ entry: resolve(__dirname, 'src/vue2.ts'),
19
+ name: 'RushChatbotVue2',
20
+ fileName: (format) => `vue2.${format}.js`,
21
+ formats: ['es', 'cjs'],
22
+ },
23
+ rollupOptions: {
24
+ external: ['vue', 'marked'],
25
+ output: { globals: { vue: 'Vue', marked: 'marked' } },
26
+ },
27
+ },
28
+ }
29
+ }
30
+
31
+ if (mode === 'vue') {
32
+ return {
33
+ plugins: [vue()],
34
+ build: {
35
+ ...shared,
36
+ lib: {
37
+ entry: resolve(__dirname, 'src/vue.ts'),
38
+ name: 'RushChatbotVue',
39
+ fileName: (format) => `vue.${format}.js`,
40
+ formats: ['es', 'cjs'],
41
+ },
42
+ rollupOptions: {
43
+ external: ['vue', 'marked'],
44
+ output: { globals: { vue: 'Vue', marked: 'marked' } },
45
+ },
46
+ },
47
+ }
48
+ }
49
+
50
+ if (mode === 'vanilla') {
51
+ return {
52
+ plugins: [],
53
+ build: {
54
+ ...shared,
55
+ lib: {
56
+ entry: resolve(__dirname, 'src/vanilla.ts'),
57
+ name: 'RushChatbotVanilla',
58
+ fileName: (format) => `vanilla.${format}.js`,
59
+ formats: ['es', 'iife'],
60
+ },
61
+ rollupOptions: {
62
+ external: ['marked'],
63
+ output: { globals: { marked: 'marked' } },
64
+ },
65
+ },
66
+ }
67
+ }
68
+
69
+ // Default: React
70
+ return {
71
+ plugins: [react()],
72
+ build: {
73
+ ...shared,
74
+ lib: {
75
+ entry: resolve(__dirname, 'src/client.ts'),
76
+ name: 'RushChatbotClient',
77
+ fileName: (format) => `client.${format}.js`,
78
+ formats: ['es', 'cjs'],
79
+ },
80
+ rollupOptions: {
81
+ external: ['react', 'react-dom', 'marked'],
82
+ output: { globals: { react: 'React', 'react-dom': 'ReactDOM', marked: 'marked' } },
83
+ },
84
+ },
85
+ }
86
+ })
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "rushchatbot",
3
+ "version": "1.6.7",
4
+ "scripts": {
5
+ "dev": "concurrently \"npm run dev:server\" \"npm run dev:client\"",
6
+ "dev:client": "vite",
7
+ "dev:server": "nodemon --exec ts-node server/index.ts",
8
+ "build": "vite build && tsc -p server/tsconfig.json",
9
+ "start": "node server/dist/index.js"
10
+ },
11
+ "dependencies": {
12
+ "@types/bad-words": "^3.0.3",
13
+ "axios": "^1.7.2",
14
+ "bad-words": "^4.1.5",
15
+ "cors": "^2.8.5",
16
+ "express": "^4.19.2",
17
+ "fuse.js": "^7.0.0",
18
+ "marked": "^18.0.13",
19
+ "react": "^19.1.0",
20
+ "react-dom": "^19.1.0"
21
+ },
22
+ "devDependencies": {
23
+ "@types/cors": "^2.8.17",
24
+ "@types/express": "^4.17.21",
25
+ "@types/node": "^22.0.0",
26
+ "@types/react": "^19.1.6",
27
+ "@types/react-dom": "^19.1.6",
28
+ "@vitejs/plugin-react": "^4.3.4",
29
+ "concurrently": "^9.0.0",
30
+ "nodemon": "^3.1.4",
31
+ "ts-node": "^10.9.2",
32
+ "typescript": "^5.5.3",
33
+ "vite": "^6.3.5"
34
+ }
35
+ }
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="48" height="46" fill="none" viewBox="0 0 48 46"><path fill="#863bff" d="M25.946 44.938c-.664.845-2.021.375-2.021-.698V33.937a2.26 2.26 0 0 0-2.262-2.262H10.287c-.92 0-1.456-1.04-.92-1.788l7.48-10.471c1.07-1.497 0-3.578-1.842-3.578H1.237c-.92 0-1.456-1.04-.92-1.788L10.013.474c.214-.297.556-.474.92-.474h28.894c.92 0 1.456 1.04.92 1.788l-7.48 10.471c-1.07 1.498 0 3.579 1.842 3.579h11.377c.943 0 1.473 1.088.89 1.83L25.947 44.94z" style="fill:#863bff;fill:color(display-p3 .5252 .23 1);fill-opacity:1"/><mask id="a" width="48" height="46" x="0" y="0" maskUnits="userSpaceOnUse" style="mask-type:alpha"><path fill="#000" d="M25.842 44.938c-.664.844-2.021.375-2.021-.698V33.937a2.26 2.26 0 0 0-2.262-2.262H10.183c-.92 0-1.456-1.04-.92-1.788l7.48-10.471c1.07-1.498 0-3.579-1.842-3.579H1.133c-.92 0-1.456-1.04-.92-1.787L9.91.473c.214-.297.556-.474.92-.474h28.894c.92 0 1.456 1.04.92 1.788l-7.48 10.471c-1.07 1.498 0 3.578 1.842 3.578h11.377c.943 0 1.473 1.088.89 1.832L25.843 44.94z" style="fill:#000;fill-opacity:1"/></mask><g mask="url(#a)"><g filter="url(#b)"><ellipse cx="5.508" cy="14.704" fill="#ede6ff" rx="5.508" ry="14.704" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -4.47 31.516)"/></g><g filter="url(#c)"><ellipse cx="10.399" cy="29.851" fill="#ede6ff" rx="10.399" ry="29.851" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -39.328 7.883)"/></g><g filter="url(#d)"><ellipse cx="5.508" cy="30.487" fill="#7e14ff" rx="5.508" ry="30.487" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.814 -25.913 -14.639)scale(1 -1)"/></g><g filter="url(#e)"><ellipse cx="5.508" cy="30.599" fill="#7e14ff" rx="5.508" ry="30.599" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.814 -32.644 -3.334)scale(1 -1)"/></g><g filter="url(#f)"><ellipse cx="5.508" cy="30.599" fill="#7e14ff" rx="5.508" ry="30.599" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="matrix(.00324 1 1 -.00324 -34.34 30.47)"/></g><g filter="url(#g)"><ellipse cx="14.072" cy="22.078" fill="#ede6ff" rx="14.072" ry="22.078" style="fill:#ede6ff;fill:color(display-p3 .9275 .9033 1);fill-opacity:1" transform="rotate(93.35 24.506 48.493)scale(-1 1)"/></g><g filter="url(#h)"><ellipse cx="3.47" cy="21.501" fill="#7e14ff" rx="3.47" ry="21.501" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.009 28.708 47.59)scale(-1 1)"/></g><g filter="url(#i)"><ellipse cx="3.47" cy="21.501" fill="#7e14ff" rx="3.47" ry="21.501" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(89.009 28.708 47.59)scale(-1 1)"/></g><g filter="url(#j)"><ellipse cx=".387" cy="8.972" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(39.51 .387 8.972)"/></g><g filter="url(#k)"><ellipse cx="47.523" cy="-6.092" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 47.523 -6.092)"/></g><g filter="url(#l)"><ellipse cx="41.412" cy="6.333" fill="#47bfff" rx="5.971" ry="9.665" style="fill:#47bfff;fill:color(display-p3 .2799 .748 1);fill-opacity:1" transform="rotate(37.892 41.412 6.333)"/></g><g filter="url(#m)"><ellipse cx="-1.879" cy="38.332" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 -1.88 38.332)"/></g><g filter="url(#n)"><ellipse cx="-1.879" cy="38.332" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 -1.88 38.332)"/></g><g filter="url(#o)"><ellipse cx="35.651" cy="29.907" fill="#7e14ff" rx="4.407" ry="29.108" style="fill:#7e14ff;fill:color(display-p3 .4922 .0767 1);fill-opacity:1" transform="rotate(37.892 35.651 29.907)"/></g><g filter="url(#p)"><ellipse cx="38.418" cy="32.4" fill="#47bfff" rx="5.971" ry="15.297" style="fill:#47bfff;fill:color(display-p3 .2799 .748 1);fill-opacity:1" transform="rotate(37.892 38.418 32.4)"/></g></g><defs><filter id="b" width="60.045" height="41.654" x="-19.77" y="16.149" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="c" width="90.34" height="51.437" x="-54.613" y="-7.533" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="d" width="79.355" height="29.4" x="-49.64" y="2.03" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="e" width="79.579" height="29.4" x="-45.045" y="20.029" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="f" width="79.579" height="29.4" x="-43.513" y="21.178" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="g" width="74.749" height="58.852" x="15.756" y="-17.901" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="7.659"/></filter><filter id="h" width="61.377" height="25.362" x="23.548" y="2.284" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="i" width="61.377" height="25.362" x="23.548" y="2.284" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="j" width="56.045" height="63.649" x="-27.636" y="-22.853" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="k" width="54.814" height="64.646" x="20.116" y="-38.415" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="l" width="33.541" height="35.313" x="24.641" y="-11.323" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="m" width="54.814" height="64.646" x="-29.286" y="6.009" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="n" width="54.814" height="64.646" x="-29.286" y="6.009" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="o" width="54.814" height="64.646" x="8.244" y="-2.416" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter><filter id="p" width="39.409" height="43.623" x="18.713" y="10.588" color-interpolation-filters="sRGB" filterUnits="userSpaceOnUse"><feFlood flood-opacity="0" result="BackgroundImageFix"/><feBlend in="SourceGraphic" in2="BackgroundImageFix" result="shape"/><feGaussianBlur result="effect1_foregroundBlur_2002_17158" stdDeviation="4.596"/></filter></defs></svg>
@@ -0,0 +1,24 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg">
2
+ <symbol id="bluesky-icon" viewBox="0 0 16 17">
3
+ <g clip-path="url(#bluesky-clip)"><path fill="#08060d" d="M7.75 7.735c-.693-1.348-2.58-3.86-4.334-5.097-1.68-1.187-2.32-.981-2.74-.79C.188 2.065.1 2.812.1 3.251s.241 3.602.398 4.13c.52 1.744 2.367 2.333 4.07 2.145-2.495.37-4.71 1.278-1.805 4.512 3.196 3.309 4.38-.71 4.987-2.746.608 2.036 1.307 5.91 4.93 2.746 2.72-2.746.747-4.143-1.747-4.512 1.702.189 3.55-.4 4.07-2.145.156-.528.397-3.691.397-4.13s-.088-1.186-.575-1.406c-.42-.19-1.06-.395-2.741.79-1.755 1.24-3.64 3.752-4.334 5.099"/></g>
4
+ <defs><clipPath id="bluesky-clip"><path fill="#fff" d="M.1.85h15.3v15.3H.1z"/></clipPath></defs>
5
+ </symbol>
6
+ <symbol id="discord-icon" viewBox="0 0 20 19">
7
+ <path fill="#08060d" d="M16.224 3.768a14.5 14.5 0 0 0-3.67-1.153c-.158.286-.343.67-.47.976a13.5 13.5 0 0 0-4.067 0c-.128-.306-.317-.69-.476-.976A14.4 14.4 0 0 0 3.868 3.77C1.546 7.28.916 10.703 1.231 14.077a14.7 14.7 0 0 0 4.5 2.306q.545-.748.965-1.587a9.5 9.5 0 0 1-1.518-.74q.191-.14.372-.293c2.927 1.369 6.107 1.369 8.999 0q.183.152.372.294-.723.437-1.52.74.418.838.963 1.588a14.6 14.6 0 0 0 4.504-2.308c.37-3.911-.63-7.302-2.644-10.309m-9.13 8.234c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.894 0 1.614.82 1.599 1.82.001 1-.705 1.82-1.6 1.82m5.91 0c-.878 0-1.599-.82-1.599-1.82 0-.998.705-1.82 1.6-1.82.893 0 1.614.82 1.599 1.82 0 1-.706 1.82-1.6 1.82"/>
8
+ </symbol>
9
+ <symbol id="documentation-icon" viewBox="0 0 21 20">
10
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="m15.5 13.333 1.533 1.322c.645.555.967.833.967 1.178s-.322.623-.967 1.179L15.5 18.333m-3.333-5-1.534 1.322c-.644.555-.966.833-.966 1.178s.322.623.966 1.179l1.534 1.321"/>
11
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M17.167 10.836v-4.32c0-1.41 0-2.117-.224-2.68-.359-.906-1.118-1.621-2.08-1.96-.599-.21-1.349-.21-2.848-.21-2.623 0-3.935 0-4.983.369-1.684.591-3.013 1.842-3.641 3.428C3 6.449 3 7.684 3 10.154v2.122c0 2.558 0 3.838.706 4.726q.306.383.713.671c.76.536 1.79.64 3.581.66"/>
12
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M3 10a2.78 2.78 0 0 1 2.778-2.778c.555 0 1.209.097 1.748-.047.48-.129.854-.503.982-.982.145-.54.048-1.194.048-1.749a2.78 2.78 0 0 1 2.777-2.777"/>
13
+ </symbol>
14
+ <symbol id="github-icon" viewBox="0 0 19 19">
15
+ <path fill="#08060d" fill-rule="evenodd" d="M9.356 1.85C5.05 1.85 1.57 5.356 1.57 9.694a7.84 7.84 0 0 0 5.324 7.44c.387.079.528-.168.528-.376 0-.182-.013-.805-.013-1.454-2.165.467-2.616-.935-2.616-.935-.349-.91-.864-1.143-.864-1.143-.71-.48.051-.48.051-.48.787.051 1.2.805 1.2.805.695 1.194 1.817.857 2.268.649.064-.507.27-.857.49-1.052-1.728-.182-3.545-.857-3.545-3.87 0-.857.31-1.558.8-2.104-.078-.195-.349-1 .077-2.078 0 0 .657-.208 2.14.805a7.5 7.5 0 0 1 1.946-.26c.657 0 1.328.092 1.946.26 1.483-1.013 2.14-.805 2.14-.805.426 1.078.155 1.883.078 2.078.502.546.799 1.247.799 2.104 0 3.013-1.818 3.675-3.558 3.87.284.247.528.714.528 1.454 0 1.052-.012 1.896-.012 2.156 0 .208.142.455.528.377a7.84 7.84 0 0 0 5.324-7.441c.013-4.338-3.48-7.844-7.773-7.844" clip-rule="evenodd"/>
16
+ </symbol>
17
+ <symbol id="social-icon" viewBox="0 0 20 20">
18
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M12.5 6.667a4.167 4.167 0 1 0-8.334 0 4.167 4.167 0 0 0 8.334 0"/>
19
+ <path fill="none" stroke="#aa3bff" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.35" d="M2.5 16.667a5.833 5.833 0 0 1 8.75-5.053m3.837.474.513 1.035c.07.144.257.282.414.309l.93.155c.596.1.736.536.307.965l-.723.73a.64.64 0 0 0-.152.531l.207.903c.164.715-.213.991-.84.618l-.872-.52a.63.63 0 0 0-.577 0l-.872.52c-.624.373-1.003.094-.84-.618l.207-.903a.64.64 0 0 0-.152-.532l-.723-.729c-.426-.43-.289-.864.306-.964l.93-.156a.64.64 0 0 0 .412-.31l.513-1.034c.28-.562.735-.562 1.012 0"/>
20
+ </symbol>
21
+ <symbol id="x-icon" viewBox="0 0 19 19">
22
+ <path fill="#08060d" fill-rule="evenodd" d="M1.893 1.98c.052.072 1.245 1.769 2.653 3.77l2.892 4.114c.183.261.333.48.333.486s-.068.089-.152.183l-.522.593-.765.867-3.597 4.087c-.375.426-.734.834-.798.905a1 1 0 0 0-.118.148c0 .01.236.017.664.017h.663l.729-.83c.4-.457.796-.906.879-.999a692 692 0 0 0 1.794-2.038c.034-.037.301-.34.594-.675l.551-.624.345-.392a7 7 0 0 1 .34-.374c.006 0 .93 1.306 2.052 2.903l2.084 2.965.045.063h2.275c1.87 0 2.273-.003 2.266-.021-.008-.02-1.098-1.572-3.894-5.547-2.013-2.862-2.28-3.246-2.273-3.266.008-.019.282-.332 2.085-2.38l2-2.274 1.567-1.782c.022-.028-.016-.03-.65-.03h-.674l-.3.342a871 871 0 0 1-1.782 2.025c-.067.075-.405.458-.75.852a100 100 0 0 1-.803.91c-.148.172-.299.344-.99 1.127-.304.343-.32.358-.345.327-.015-.019-.904-1.282-1.976-2.808L6.365 1.85H1.8zm1.782.91 8.078 11.294c.772 1.08 1.413 1.973 1.425 1.984.016.017.241.02 1.05.017l1.03-.004-2.694-3.766L7.796 5.75 5.722 2.852l-1.039-.004-1.039-.004z" clip-rule="evenodd"/>
23
+ </symbol>
24
+ </svg>