ragged-chat-sdk 1.0.3 → 1.0.5
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/.github/workflows/npm-publish.yml +33 -0
- package/README.md +45 -2
- package/index.d.ts +4 -3
- package/index.js +454 -73
- package/package.json +1 -1
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
|
|
3
|
+
|
|
4
|
+
name: Node.js Package
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
release:
|
|
8
|
+
types: [created]
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
steps:
|
|
14
|
+
- uses: actions/checkout@v4
|
|
15
|
+
- uses: actions/setup-node@v4
|
|
16
|
+
with:
|
|
17
|
+
node-version: 20
|
|
18
|
+
- run: npm ci
|
|
19
|
+
- run: npm test
|
|
20
|
+
|
|
21
|
+
publish-npm:
|
|
22
|
+
needs: build
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v4
|
|
26
|
+
- uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: 20
|
|
29
|
+
registry-url: https://registry.npmjs.org/
|
|
30
|
+
- run: npm ci
|
|
31
|
+
- run: npm publish
|
|
32
|
+
env:
|
|
33
|
+
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
package/README.md
CHANGED
|
@@ -26,14 +26,57 @@ init({
|
|
|
26
26
|
| --- | --- | --- |
|
|
27
27
|
| `subdomain` | `string` | **Required**. The unique subdomain of your chatbot. |
|
|
28
28
|
| `apiUrl` | `string` | Optional. The base URL of the Ragged API. Defaults to `https://ragflowdb.onrender.com/api`. |
|
|
29
|
+
| `widgetShape` | `'circle' \| 'rounded-square'` | Optional. The shape of the floating widget button. Defaults to `'circle'`. |
|
|
30
|
+
| `widgetSize` | `'small' \| 'medium' \| 'large'` | Optional. The size of the floating widget button. Defaults to `'medium'`. |
|
|
29
31
|
|
|
30
|
-
|
|
32
|
+
### Widget Customization
|
|
33
|
+
|
|
34
|
+
You can customize the appearance of the floating chat widget button:
|
|
35
|
+
|
|
36
|
+
**Shape Options:**
|
|
37
|
+
- `'circle'` - Circular button (default)
|
|
38
|
+
- `'rounded-square'` - Square button with rounded corners
|
|
39
|
+
|
|
40
|
+
**Size Options:**
|
|
41
|
+
- `'small'` - 48x48 pixels
|
|
42
|
+
- `'medium'` - 56x56 pixels (default)
|
|
43
|
+
- `'large'` - 68x68 pixels
|
|
44
|
+
|
|
45
|
+
## Examples
|
|
46
|
+
|
|
47
|
+
### Basic Setup
|
|
31
48
|
|
|
32
49
|
```javascript
|
|
33
50
|
import { init } from 'ragged-chat-sdk';
|
|
34
51
|
|
|
35
|
-
// Initialize the chatbot
|
|
52
|
+
// Initialize the chatbot with default settings
|
|
36
53
|
init({
|
|
37
54
|
subdomain: 'my-awesome-bot'
|
|
38
55
|
});
|
|
39
56
|
```
|
|
57
|
+
|
|
58
|
+
### Custom Widget Appearance
|
|
59
|
+
|
|
60
|
+
```javascript
|
|
61
|
+
import { init } from 'ragged-chat-sdk';
|
|
62
|
+
|
|
63
|
+
// Large rounded square button
|
|
64
|
+
init({
|
|
65
|
+
subdomain: 'my-awesome-bot',
|
|
66
|
+
widgetShape: 'rounded-square',
|
|
67
|
+
widgetSize: 'large'
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Small Circular Button
|
|
72
|
+
|
|
73
|
+
```javascript
|
|
74
|
+
import { init } from 'ragged-chat-sdk';
|
|
75
|
+
|
|
76
|
+
// Small circular button
|
|
77
|
+
init({
|
|
78
|
+
subdomain: 'my-awesome-bot',
|
|
79
|
+
widgetShape: 'circle',
|
|
80
|
+
widgetSize: 'small'
|
|
81
|
+
});
|
|
82
|
+
```
|
package/index.d.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
export interface InitOptions {
|
|
2
|
-
subdomain
|
|
3
|
-
apiKey?: string;
|
|
2
|
+
subdomain: string;
|
|
4
3
|
apiUrl?: string;
|
|
4
|
+
widgetShape?: 'circle' | 'rounded-square';
|
|
5
|
+
widgetSize?: 'small' | 'medium' | 'large';
|
|
5
6
|
[key: string]: any;
|
|
6
7
|
}
|
|
7
8
|
|
|
8
|
-
export function init(config
|
|
9
|
+
export function init(config: InitOptions): void;
|
package/index.js
CHANGED
|
@@ -1,25 +1,14 @@
|
|
|
1
1
|
export function init(config = {}) {
|
|
2
|
-
// Configuration
|
|
3
|
-
// Automatically detect API URL if loaded via script tag, or use default production URL
|
|
4
|
-
let defaultApiUrl = 'https://ragflowdb.onrender.com/api';
|
|
5
2
|
|
|
6
|
-
// Attempt to detect API URL from the current script tag if in browser
|
|
7
|
-
if (typeof document !== 'undefined' && document.currentScript) {
|
|
8
|
-
try {
|
|
9
|
-
const scriptUrl = new URL(document.currentScript.src);
|
|
10
|
-
if (scriptUrl.origin.includes('ragflowdb.onrender.com') || scriptUrl.origin.includes('localhost')) {
|
|
11
|
-
defaultApiUrl = scriptUrl.origin + '/api';
|
|
12
|
-
}
|
|
13
|
-
} catch (e) {
|
|
14
|
-
// Fallback to default
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
3
|
|
|
18
|
-
|
|
19
|
-
const
|
|
4
|
+
// Configuration
|
|
5
|
+
const API_URL = config.apiUrl || 'https://ragflowdb.onrender.com/api';
|
|
6
|
+
const subdomain = config.subdomain;
|
|
7
|
+
let widgetShape = config.widgetShape || 'circle'; // Fallback to circle
|
|
8
|
+
let widgetSize = config.widgetSize || 'medium'; // Fallback to medium
|
|
20
9
|
|
|
21
|
-
if (!
|
|
22
|
-
console.error('[Ragged SDK] Error:
|
|
10
|
+
if (!subdomain) {
|
|
11
|
+
console.error('[Ragged SDK] Error: subdomain is required. Usage: Ragged.init({ subdomain: "your-subdomain" })');
|
|
23
12
|
return;
|
|
24
13
|
}
|
|
25
14
|
|
|
@@ -29,11 +18,13 @@ export function init(config = {}) {
|
|
|
29
18
|
let chatConfig = null;
|
|
30
19
|
let messages = [];
|
|
31
20
|
let isLoading = false;
|
|
21
|
+
let activeTab = 'chat';
|
|
22
|
+
let isSubmittingSupport = false;
|
|
32
23
|
|
|
33
24
|
// Fetch chatbot configuration
|
|
34
25
|
async function fetchConfig() {
|
|
35
26
|
try {
|
|
36
|
-
const response = await fetch(`${API_URL}/chat/${
|
|
27
|
+
const response = await fetch(`${API_URL}/chat/${subdomain}/config`);
|
|
37
28
|
chatConfig = await response.json();
|
|
38
29
|
} catch (error) {
|
|
39
30
|
console.error('[Ragged SDK] Failed to fetch config:', error);
|
|
@@ -43,7 +34,7 @@ export function init(config = {}) {
|
|
|
43
34
|
// Send message to chatbot
|
|
44
35
|
async function sendMessage(message) {
|
|
45
36
|
try {
|
|
46
|
-
const response = await fetch(`${API_URL}/chat/${
|
|
37
|
+
const response = await fetch(`${API_URL}/chat/${subdomain}`, {
|
|
47
38
|
method: 'POST',
|
|
48
39
|
headers: { 'Content-Type': 'application/json' },
|
|
49
40
|
body: JSON.stringify({ message, history: messages })
|
|
@@ -56,6 +47,101 @@ export function init(config = {}) {
|
|
|
56
47
|
}
|
|
57
48
|
}
|
|
58
49
|
|
|
50
|
+
// Switch between tabs
|
|
51
|
+
function switchTab(tabId) {
|
|
52
|
+
activeTab = tabId;
|
|
53
|
+
|
|
54
|
+
// Update tab buttons
|
|
55
|
+
const tabs = ['chat', 'links', 'support'];
|
|
56
|
+
tabs.forEach(t => {
|
|
57
|
+
const btn = document.getElementById(`ragged-tab-${t}`);
|
|
58
|
+
if (btn) {
|
|
59
|
+
if (t === tabId) btn.classList.add('active');
|
|
60
|
+
else btn.classList.remove('active');
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Update views
|
|
65
|
+
const views = {
|
|
66
|
+
'chat': document.getElementById('ragged-chat-view'),
|
|
67
|
+
'links': document.getElementById('ragged-links-view'),
|
|
68
|
+
'support': document.getElementById('ragged-support-view')
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
Object.keys(views).forEach(t => {
|
|
72
|
+
const view = views[t];
|
|
73
|
+
if (view) {
|
|
74
|
+
if (t === tabId) view.classList.remove('ragged-hidden');
|
|
75
|
+
else view.classList.add('ragged-hidden');
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
if (tabId === 'chat') renderMessages();
|
|
80
|
+
if (tabId === 'links') renderLinks();
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Render links
|
|
84
|
+
function renderLinks() {
|
|
85
|
+
const container = document.getElementById('ragged-links-list');
|
|
86
|
+
if (!container || !chatConfig?.settings?.bookmarks) return;
|
|
87
|
+
|
|
88
|
+
const links = chatConfig.settings.bookmarks;
|
|
89
|
+
container.innerHTML = links.map(link => `
|
|
90
|
+
<a href="${link.url}" target="_blank" rel="noopener noreferrer" class="ragged-link-item">
|
|
91
|
+
<span class="ragged-link-label">${link.label}</span>
|
|
92
|
+
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
93
|
+
<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"></path>
|
|
94
|
+
<polyline points="15 3 22 3 22 10"></polyline>
|
|
95
|
+
<line x1="10" y1="14" x2="22" y2="3"></line>
|
|
96
|
+
</svg>
|
|
97
|
+
</a>
|
|
98
|
+
`).join('');
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// Handle support form submission
|
|
102
|
+
async function handleSubmitSupport(e) {
|
|
103
|
+
e.preventDefault();
|
|
104
|
+
if (isSubmittingSupport) return;
|
|
105
|
+
|
|
106
|
+
const submitBtn = document.getElementById('ragged-support-submit');
|
|
107
|
+
const originalText = submitBtn.innerHTML;
|
|
108
|
+
|
|
109
|
+
const data = {
|
|
110
|
+
name: document.getElementById('ragged-support-name').value,
|
|
111
|
+
email: document.getElementById('ragged-support-email').value,
|
|
112
|
+
type: document.getElementById('ragged-support-type').value,
|
|
113
|
+
impact: document.getElementById('ragged-support-impact').value,
|
|
114
|
+
description: document.getElementById('ragged-support-desc').value
|
|
115
|
+
};
|
|
116
|
+
|
|
117
|
+
try {
|
|
118
|
+
isSubmittingSupport = true;
|
|
119
|
+
submitBtn.disabled = true;
|
|
120
|
+
submitBtn.innerHTML = '<div class="ragged-loading-spinner"></div> Sending...';
|
|
121
|
+
|
|
122
|
+
const response = await fetch(`${API_URL}/chatbots/${subdomain}/support`, {
|
|
123
|
+
method: 'POST',
|
|
124
|
+
headers: { 'Content-Type': 'application/json' },
|
|
125
|
+
body: JSON.stringify(data)
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
if (response.ok) {
|
|
129
|
+
alert('Support ticket submitted successfully!');
|
|
130
|
+
document.getElementById('ragged-support-form').reset();
|
|
131
|
+
switchTab('chat');
|
|
132
|
+
} else {
|
|
133
|
+
throw new Error('Failed to submit');
|
|
134
|
+
}
|
|
135
|
+
} catch (error) {
|
|
136
|
+
console.error('[Ragged SDK] Support submission failed:', error);
|
|
137
|
+
alert('Failed to submit support ticket. Please try again.');
|
|
138
|
+
} finally {
|
|
139
|
+
isSubmittingSupport = false;
|
|
140
|
+
submitBtn.disabled = false;
|
|
141
|
+
submitBtn.innerHTML = originalText;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
59
145
|
// Format message content (bold, tables, and links)
|
|
60
146
|
function formatMessage(content) {
|
|
61
147
|
if (!content) return '';
|
|
@@ -548,10 +634,7 @@ export function init(config = {}) {
|
|
|
548
634
|
}
|
|
549
635
|
|
|
550
636
|
#ragged-toggle-btn {
|
|
551
|
-
width: 56px;
|
|
552
|
-
height: 56px;
|
|
553
637
|
border: none;
|
|
554
|
-
border-radius: 50%;
|
|
555
638
|
color: white;
|
|
556
639
|
cursor: pointer;
|
|
557
640
|
display: flex;
|
|
@@ -563,6 +646,31 @@ export function init(config = {}) {
|
|
|
563
646
|
overflow: hidden;
|
|
564
647
|
}
|
|
565
648
|
|
|
649
|
+
/* Size variations */
|
|
650
|
+
#ragged-toggle-btn.size-small {
|
|
651
|
+
width: 48px;
|
|
652
|
+
height: 48px;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
#ragged-toggle-btn.size-medium {
|
|
656
|
+
width: 56px;
|
|
657
|
+
height: 56px;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
#ragged-toggle-btn.size-large {
|
|
661
|
+
width: 68px;
|
|
662
|
+
height: 68px;
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
/* Shape variations */
|
|
666
|
+
#ragged-toggle-btn.shape-circle {
|
|
667
|
+
border-radius: 50%;
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
#ragged-toggle-btn.shape-rounded-square {
|
|
671
|
+
border-radius: 16px;
|
|
672
|
+
}
|
|
673
|
+
|
|
566
674
|
#ragged-toggle-btn:hover {
|
|
567
675
|
transform: scale(1.1);
|
|
568
676
|
}
|
|
@@ -599,64 +707,291 @@ export function init(config = {}) {
|
|
|
599
707
|
}
|
|
600
708
|
|
|
601
709
|
.ragged-hidden {
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
710
|
+
display: none !important;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
#ragged-tabs {
|
|
714
|
+
display: flex;
|
|
715
|
+
background: #18181b;
|
|
716
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
|
717
|
+
flex-shrink: 0;
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
.ragged-tab-btn {
|
|
721
|
+
flex: 1;
|
|
722
|
+
padding: 12px 0;
|
|
723
|
+
background: transparent;
|
|
724
|
+
border: none;
|
|
725
|
+
color: #71717a;
|
|
726
|
+
font-size: 10px;
|
|
727
|
+
font-weight: 700;
|
|
728
|
+
text-transform: uppercase;
|
|
729
|
+
letter-spacing: 0.1em;
|
|
730
|
+
cursor: pointer;
|
|
731
|
+
display: flex;
|
|
732
|
+
flex-direction: column;
|
|
733
|
+
align-items: center;
|
|
734
|
+
gap: 4px;
|
|
735
|
+
transition: all 0.2s;
|
|
736
|
+
position: relative;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
.ragged-tab-btn:hover {
|
|
740
|
+
color: #e4e4e7;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
.ragged-tab-btn.active {
|
|
744
|
+
color: white;
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
.ragged-tab-btn.active::after {
|
|
748
|
+
content: '';
|
|
749
|
+
position: absolute;
|
|
750
|
+
bottom: 0;
|
|
751
|
+
left: 50%;
|
|
752
|
+
transform: translateX(-50%);
|
|
753
|
+
width: 4px;
|
|
754
|
+
height: 4px;
|
|
755
|
+
background: white;
|
|
756
|
+
border-radius: 50%;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
#ragged-links-view, #ragged-support-view {
|
|
760
|
+
flex: 1;
|
|
761
|
+
overflow-y: auto;
|
|
762
|
+
padding: 24px;
|
|
763
|
+
display: flex;
|
|
764
|
+
flex-direction: column;
|
|
765
|
+
gap: 12px;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
.ragged-view-title {
|
|
769
|
+
font-size: 10px;
|
|
770
|
+
font-weight: 700;
|
|
771
|
+
text-transform: uppercase;
|
|
772
|
+
letter-spacing: 0.1em;
|
|
773
|
+
color: #71717a;
|
|
774
|
+
margin-bottom: 12px;
|
|
775
|
+
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
|
776
|
+
padding-bottom: 8px;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
.ragged-link-item {
|
|
780
|
+
display: flex;
|
|
781
|
+
align-items: center;
|
|
782
|
+
justify-content: space-between;
|
|
783
|
+
padding: 16px;
|
|
784
|
+
background: rgba(255, 255, 255, 0.05);
|
|
785
|
+
border: 1px solid rgba(255, 255, 255, 0.05);
|
|
786
|
+
border-radius: 16px;
|
|
787
|
+
text-decoration: none;
|
|
788
|
+
color: #e4e4e7;
|
|
789
|
+
transition: all 0.2s;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
.ragged-link-item:hover {
|
|
793
|
+
background: rgba(255, 255, 255, 0.1);
|
|
794
|
+
transform: translateY(-2px);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
.ragged-link-label {
|
|
798
|
+
font-weight: 600;
|
|
799
|
+
font-size: 14px;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
.ragged-support-form {
|
|
803
|
+
display: flex;
|
|
804
|
+
flex-direction: column;
|
|
805
|
+
gap: 16px;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
.ragged-form-group {
|
|
809
|
+
display: flex;
|
|
810
|
+
flex-direction: column;
|
|
811
|
+
gap: 4px;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
.ragged-form-label {
|
|
815
|
+
font-size: 10px;
|
|
816
|
+
font-weight: 700;
|
|
817
|
+
text-transform: uppercase;
|
|
818
|
+
letter-spacing: 0.1em;
|
|
819
|
+
color: #71717a;
|
|
820
|
+
margin-left: 4px;
|
|
821
|
+
}
|
|
822
|
+
|
|
823
|
+
.ragged-form-input, .ragged-form-select, .ragged-form-textarea {
|
|
824
|
+
background: rgba(255, 255, 255, 0.05);
|
|
825
|
+
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
826
|
+
border-radius: 12px;
|
|
827
|
+
padding: 10px 14px;
|
|
828
|
+
color: white;
|
|
829
|
+
font-size: 14px;
|
|
830
|
+
outline: none;
|
|
831
|
+
width: 100%;
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
.ragged-form-input:focus, .ragged-form-select:focus, .ragged-form-textarea:focus {
|
|
835
|
+
border-color: rgba(255, 255, 255, 0.2);
|
|
836
|
+
background: rgba(255, 255, 255, 0.08);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
.ragged-form-textarea {
|
|
840
|
+
height: 100px;
|
|
841
|
+
resize: none;
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
.ragged-form-row {
|
|
845
|
+
display: grid;
|
|
846
|
+
grid-template-cols: 1fr 1fr;
|
|
847
|
+
gap: 12px;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
#ragged-support-submit {
|
|
851
|
+
margin-top: 8px;
|
|
852
|
+
height: 48px;
|
|
853
|
+
border-radius: 16px;
|
|
854
|
+
border: none;
|
|
855
|
+
color: white;
|
|
856
|
+
font-weight: 700;
|
|
857
|
+
cursor: pointer;
|
|
858
|
+
display: flex;
|
|
859
|
+
align-items: center;
|
|
860
|
+
justify-content: center;
|
|
861
|
+
gap: 8px;
|
|
862
|
+
transition: all 0.2s;
|
|
863
|
+
}
|
|
864
|
+
|
|
865
|
+
#ragged-support-submit:hover {
|
|
866
|
+
transform: translateY(-2px);
|
|
867
|
+
filter: brightness(1.1);
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
#ragged-support-submit:disabled {
|
|
871
|
+
opacity: 0.5;
|
|
872
|
+
cursor: not-allowed;
|
|
873
|
+
transform: none;
|
|
874
|
+
}
|
|
875
|
+
|
|
876
|
+
.ragged-loading-spinner {
|
|
877
|
+
width: 16px;
|
|
878
|
+
height: 16px;
|
|
879
|
+
border: 2px solid rgba(255, 255, 255, 0.3);
|
|
880
|
+
border-radius: 50%;
|
|
881
|
+
border-top-color: white;
|
|
882
|
+
animation: ragged-spin 0.6s linear infinite;
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
@keyframes ragged-spin {
|
|
886
|
+
to { transform: rotate(360deg); }
|
|
605
887
|
}
|
|
606
888
|
</style>
|
|
607
889
|
|
|
608
890
|
<div id="ragged-widget-container">
|
|
609
891
|
<div id="ragged-chat-window" class="ragged-hidden">
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
<rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect>
|
|
615
|
-
<path d="M7 11V7a5 5 0 0 1 10 0v4"></path>
|
|
892
|
+
<div id="ragged-tabs">
|
|
893
|
+
<button id="ragged-tab-chat" class="ragged-tab-btn active">
|
|
894
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-bottom: 2px;">
|
|
895
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
616
896
|
</svg>
|
|
897
|
+
<span>Chat</span>
|
|
898
|
+
</button>
|
|
899
|
+
<button id="ragged-tab-links" class="ragged-tab-btn ragged-hidden">
|
|
900
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-bottom: 2px;">
|
|
901
|
+
<path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"></path>
|
|
902
|
+
<path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"></path>
|
|
903
|
+
</svg>
|
|
904
|
+
<span>Links</span>
|
|
905
|
+
</button>
|
|
906
|
+
<button id="ragged-tab-support" class="ragged-tab-btn ragged-hidden">
|
|
907
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" style="margin-bottom: 2px;">
|
|
908
|
+
<circle cx="12" cy="12" r="10"></circle>
|
|
909
|
+
<circle cx="12" cy="12" r="4"></circle>
|
|
910
|
+
<line x1="4.93" y1="4.93" x2="9.17" y2="9.17"></line>
|
|
911
|
+
<line x1="14.83" y1="14.83" x2="19.07" y2="19.07"></line>
|
|
912
|
+
<line x1="14.83" y1="4.93" x2="10.59" y2="9.17"></line>
|
|
913
|
+
<line x1="4.93" y1="14.83" x2="9.17" y2="19.07"></line>
|
|
914
|
+
</svg>
|
|
915
|
+
<span>Support</span>
|
|
916
|
+
</button>
|
|
917
|
+
</div>
|
|
918
|
+
|
|
919
|
+
<div id="ragged-chat-view">
|
|
920
|
+
<div id="ragged-messages">
|
|
921
|
+
<div id="ragged-empty-state">
|
|
922
|
+
<div id="ragged-empty-icon">
|
|
923
|
+
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="#71717a" stroke-width="2">
|
|
924
|
+
<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z"></path>
|
|
925
|
+
</svg>
|
|
926
|
+
</div>
|
|
927
|
+
<div id="ragged-empty-title">How can I help you?</div>
|
|
928
|
+
<div id="ragged-empty-text">Ask anything about our services, products, or pricing. I'm here to help!</div>
|
|
929
|
+
</div>
|
|
617
930
|
</div>
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
<
|
|
931
|
+
|
|
932
|
+
<div id="ragged-input-container">
|
|
933
|
+
<form id="ragged-input-form">
|
|
934
|
+
<input
|
|
935
|
+
type="text"
|
|
936
|
+
id="ragged-input"
|
|
937
|
+
placeholder="Type your message here..."
|
|
938
|
+
autocomplete="off"
|
|
939
|
+
/>
|
|
940
|
+
<button type="submit" id="ragged-send-btn">
|
|
941
|
+
<span>Send</span>
|
|
942
|
+
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
943
|
+
<line x1="22" y1="2" x2="11" y2="13"></line>
|
|
944
|
+
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
|
|
945
|
+
</svg>
|
|
946
|
+
</button>
|
|
947
|
+
</form>
|
|
621
948
|
</div>
|
|
622
949
|
</div>
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
950
|
+
|
|
951
|
+
<div id="ragged-links-view" class="ragged-hidden">
|
|
952
|
+
<div class="ragged-view-title">Vital Resources</div>
|
|
953
|
+
<div id="ragged-links-list"></div>
|
|
954
|
+
</div>
|
|
955
|
+
|
|
956
|
+
<div id="ragged-support-view" class="ragged-hidden">
|
|
957
|
+
<div class="ragged-view-title">Support Ticket</div>
|
|
958
|
+
<form id="ragged-support-form" class="ragged-support-form">
|
|
959
|
+
<div class="ragged-form-group">
|
|
960
|
+
<label class="ragged-form-label">Name</label>
|
|
961
|
+
<input type="text" id="ragged-support-name" class="ragged-form-input" required placeholder="Your Name" />
|
|
962
|
+
</div>
|
|
963
|
+
<div class="ragged-form-group">
|
|
964
|
+
<label class="ragged-form-label">Email</label>
|
|
965
|
+
<input type="email" id="ragged-support-email" class="ragged-form-input" required placeholder="Your Email" />
|
|
966
|
+
</div>
|
|
967
|
+
<div class="ragged-form-row">
|
|
968
|
+
<div class="ragged-form-group">
|
|
969
|
+
<label class="ragged-form-label">Type</label>
|
|
970
|
+
<select id="ragged-support-type" class="ragged-form-select">
|
|
971
|
+
<option value="general question">General Question</option>
|
|
972
|
+
<option value="feature request">Feature Request</option>
|
|
973
|
+
<option value="issue/bug">Issue/Bug</option>
|
|
974
|
+
<option value="account creation">Account Creation</option>
|
|
975
|
+
<option value="unclear">Unclear</option>
|
|
976
|
+
</select>
|
|
977
|
+
</div>
|
|
978
|
+
<div class="ragged-form-group">
|
|
979
|
+
<label class="ragged-form-label">Impact</label>
|
|
980
|
+
<select id="ragged-support-impact" class="ragged-form-select">
|
|
981
|
+
<option value="low">Low</option>
|
|
982
|
+
<option value="moderate" selected>Moderate</option>
|
|
983
|
+
<option value="high">High</option>
|
|
984
|
+
<option value="blocking">Blocking</option>
|
|
985
|
+
</select>
|
|
986
|
+
</div>
|
|
987
|
+
</div>
|
|
988
|
+
<div class="ragged-form-group">
|
|
989
|
+
<label class="ragged-form-label">Message</label>
|
|
990
|
+
<textarea id="ragged-support-desc" class="ragged-form-textarea" required placeholder="Tell us more..."></textarea>
|
|
991
|
+
</div>
|
|
992
|
+
<button type="submit" id="ragged-support-submit">Submit Ticket</button>
|
|
993
|
+
</form>
|
|
640
994
|
</div>
|
|
641
|
-
</div>
|
|
642
|
-
|
|
643
|
-
<div id="ragged-input-container">
|
|
644
|
-
<form id="ragged-input-form">
|
|
645
|
-
<input
|
|
646
|
-
type="text"
|
|
647
|
-
id="ragged-input"
|
|
648
|
-
placeholder="Type your message here..."
|
|
649
|
-
autocomplete="off"
|
|
650
|
-
/>
|
|
651
|
-
<button type="submit" id="ragged-send-btn">
|
|
652
|
-
<span>Send</span>
|
|
653
|
-
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
|
654
|
-
<line x1="22" y1="2" x2="11" y2="13"></line>
|
|
655
|
-
<polygon points="22 2 15 22 11 13 2 9 22 2"></polygon>
|
|
656
|
-
</svg>
|
|
657
|
-
</button>
|
|
658
|
-
</form>
|
|
659
|
-
</div>
|
|
660
995
|
</div>
|
|
661
996
|
|
|
662
997
|
<button id="ragged-toggle-btn">
|
|
@@ -790,13 +1125,51 @@ export function init(config = {}) {
|
|
|
790
1125
|
const emptyTitle = document.getElementById('ragged-empty-title');
|
|
791
1126
|
const avatar = document.getElementById('ragged-chat-avatar');
|
|
792
1127
|
const toggleLogo = document.getElementById('ragged-toggle-logo');
|
|
1128
|
+
const supportSubmitBtn = document.getElementById('ragged-support-submit');
|
|
1129
|
+
|
|
1130
|
+
const primaryColor = chatConfig.settings?.primaryColor || '#000000';
|
|
1131
|
+
toggleBtn.style.backgroundColor = primaryColor;
|
|
1132
|
+
sendBtn.style.backgroundColor = primaryColor;
|
|
1133
|
+
if (supportSubmitBtn) supportSubmitBtn.style.backgroundColor = primaryColor;
|
|
793
1134
|
|
|
794
|
-
toggleBtn.style.backgroundColor = chatConfig.settings?.primaryColor || '#000000';
|
|
795
|
-
sendBtn.style.backgroundColor = chatConfig.settings?.primaryColor || '#3b82f6';
|
|
796
1135
|
chatTitle.textContent = chatConfig.name || 'AI Agent';
|
|
797
1136
|
input.placeholder = chatConfig.settings?.placeholder || 'Type your message here...';
|
|
798
1137
|
emptyTitle.textContent = chatConfig.settings?.welcomeMessage || 'How can I help you?';
|
|
799
1138
|
|
|
1139
|
+
// Show Tabs based on config
|
|
1140
|
+
if (chatConfig.settings?.bookmarks?.length > 0) {
|
|
1141
|
+
document.getElementById('ragged-tab-links').classList.remove('ragged-hidden');
|
|
1142
|
+
}
|
|
1143
|
+
if (chatConfig.settings?.supportSettings?.enabled) {
|
|
1144
|
+
document.getElementById('ragged-tab-support').classList.remove('ragged-hidden');
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// Apply widget shape and size customization
|
|
1148
|
+
if (chatConfig.settings) {
|
|
1149
|
+
// Prioritize backend settings if they exist, otherwise use init config
|
|
1150
|
+
if (chatConfig.settings.widgetShape) widgetShape = chatConfig.settings.widgetShape;
|
|
1151
|
+
if (chatConfig.settings.widgetSize) widgetSize = chatConfig.settings.widgetSize;
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
if (toggleBtn) {
|
|
1155
|
+
// Clear any existing shape/size classes
|
|
1156
|
+
toggleBtn.classList.remove('shape-circle', 'shape-rounded-square', 'size-small', 'size-medium', 'size-large');
|
|
1157
|
+
toggleBtn.classList.add(`shape-${widgetShape}`);
|
|
1158
|
+
toggleBtn.classList.add(`size-${widgetSize}`);
|
|
1159
|
+
|
|
1160
|
+
// Also update icon sizing
|
|
1161
|
+
const iconMessage = document.getElementById('ragged-icon-message');
|
|
1162
|
+
const iconClose = document.getElementById('ragged-icon-close');
|
|
1163
|
+
if (iconMessage) {
|
|
1164
|
+
iconMessage.setAttribute('width', widgetSize === 'small' ? '24' : widgetSize === 'large' ? '32' : '28');
|
|
1165
|
+
iconMessage.setAttribute('height', widgetSize === 'small' ? '24' : widgetSize === 'large' ? '32' : '28');
|
|
1166
|
+
}
|
|
1167
|
+
if (iconClose) {
|
|
1168
|
+
iconClose.setAttribute('width', widgetSize === 'small' ? '24' : widgetSize === 'large' ? '32' : '28');
|
|
1169
|
+
iconClose.setAttribute('height', widgetSize === 'small' ? '24' : widgetSize === 'large' ? '32' : '28');
|
|
1170
|
+
}
|
|
1171
|
+
}
|
|
1172
|
+
|
|
800
1173
|
// Set custom logo for all users (free platform)
|
|
801
1174
|
if (chatConfig.settings?.brandLogo) {
|
|
802
1175
|
const logoUrl = chatConfig.settings.brandLogo;
|
|
@@ -816,6 +1189,14 @@ export function init(config = {}) {
|
|
|
816
1189
|
document.getElementById('ragged-toggle-btn').addEventListener('click', toggleWidget);
|
|
817
1190
|
document.getElementById('ragged-close-btn').addEventListener('click', toggleWidget);
|
|
818
1191
|
document.getElementById('ragged-input-form').addEventListener('submit', handleSend);
|
|
1192
|
+
|
|
1193
|
+
// Tab Listeners
|
|
1194
|
+
document.getElementById('ragged-tab-chat').addEventListener('click', () => switchTab('chat'));
|
|
1195
|
+
document.getElementById('ragged-tab-links').addEventListener('click', () => switchTab('links'));
|
|
1196
|
+
document.getElementById('ragged-tab-support').addEventListener('click', () => switchTab('support'));
|
|
1197
|
+
|
|
1198
|
+
// Support Form Listener
|
|
1199
|
+
document.getElementById('ragged-support-form').addEventListener('submit', handleSubmitSupport);
|
|
819
1200
|
}
|
|
820
1201
|
|
|
821
1202
|
if (document.readyState === 'loading') {
|