1
+ // Define the base settings
2
+ const inkeepSettings = {
3
+ isOpen : true ,
4
+ baseSettings : {
5
+ apiKey : "a58574ddc0e41c75990d1c0e890ad3c8725dc9e7c8ee3d3e" ,
6
+ integrationId : "clthv1rgg000sdjil26l2vg03" ,
7
+ organizationId : "org_SGvQFUfKzrYkf8z8" ,
8
+ primaryBrandColor : "#5DFECA"
9
+ } ,
10
+ aiChatSettings : {
11
+ chatSubjectName : "Vapi" ,
12
+ botAvatarSrcUrl : "https://storage.googleapis.com/organization-image-assets/vapi-botAvatarSrcUrl-1709929183314.png" ,
13
+ botAvatarDarkSrcUrl : "https://storage.googleapis.com/organization-image-assets/vapi-botAvatarDarkSrcUrl-1709929110474.png" ,
14
+ getHelpCallToActions : [
15
+ {
16
+ name : "Contact Us" ,
17
+ url : "mailto:support@vapi.ai" ,
18
+ icon : {
19
+ builtIn : "IoMail"
20
+ }
21
+ }
22
+ ] ,
23
+ quickQuestions : [
24
+ "What voices are supported?" ,
25
+ "What languages are supported?" ,
26
+ "How do I connect a custom LLM?" ,
27
+ "How do I fetch the prompt dynamically?"
28
+ ]
29
+ }
30
+ } ;
31
+
32
+ // Function to initialize search containers
33
+ function initializeSearchContainers ( ) {
34
+ const searchButtonContainerIds = [
35
+ "search-bar-entry" ,
36
+ "search-bar-entry-mobile" ,
37
+ ] ;
38
+
39
+ // Clone and replace search buttons to remove existing listeners
40
+ // Only process elements that exist
41
+ const clonedSearchButtonContainers = searchButtonContainerIds
42
+ . map ( ( id ) => {
43
+ const originalElement = document . getElementById ( id ) ;
44
+ if ( ! originalElement ) {
45
+ console . log ( `Search container ${ id } not found, skipping...` ) ;
46
+ return null ;
47
+ }
48
+ const clonedElement = originalElement . cloneNode ( true ) ;
49
+ originalElement . parentNode . replaceChild ( clonedElement , originalElement ) ;
50
+ return clonedElement ;
51
+ } )
52
+ . filter ( Boolean ) ; // Remove null entries
53
+
54
+ return clonedSearchButtonContainers ;
55
+ }
56
+
57
+ // Function to initialize Inkeep
58
+ function initializeInkeep ( ) {
59
+ // Color mode sync settings
60
+ const colorModeSettings = {
61
+ observedElement : document . documentElement ,
62
+ isDarkModeCallback : ( el ) => {
63
+ return el . classList . contains ( "dark" ) ;
64
+ } ,
65
+ colorModeAttribute : "class" ,
66
+ } ;
67
+
68
+ // Initialize the chat button
69
+ Inkeep ( ) . embed ( {
70
+ componentType : "ChatButton" ,
71
+ colorModeSync : colorModeSettings ,
72
+ properties : inkeepSettings ,
73
+ } ) ;
74
+
75
+ // Initialize the search modal
76
+ const inkeepSearchModal = Inkeep ( {
77
+ ...inkeepSettings . baseSettings ,
78
+ } ) . embed ( {
79
+ componentType : "CustomTrigger" ,
80
+ colorModeSync : colorModeSettings ,
81
+ properties : {
82
+ ...inkeepSettings ,
83
+ isOpen : false ,
84
+ onClose : ( ) => {
85
+ inkeepSearchModal . render ( {
86
+ isOpen : false ,
87
+ } ) ;
88
+ } ,
89
+ } ,
90
+ } ) ;
91
+
92
+ // Get search containers after DOM is ready
93
+ const clonedSearchButtonContainers = initializeSearchContainers ( ) ;
94
+
95
+ // Add click listeners to search buttons
96
+ clonedSearchButtonContainers . forEach ( ( trigger ) => {
97
+ trigger . addEventListener ( "click" , function ( ) {
98
+ inkeepSearchModal . render ( {
99
+ isOpen : true ,
100
+ } ) ;
101
+ } ) ;
102
+ } ) ;
103
+
104
+ // Add keyboard shortcut listener
105
+ window . addEventListener (
106
+ "keydown" ,
107
+ ( event ) => {
108
+ if (
109
+ ( event . metaKey || event . ctrlKey ) &&
110
+ ( event . key === "k" || event . key === "K" )
111
+ ) {
112
+ event . stopPropagation ( ) ;
113
+ inkeepSearchModal . render ( { isOpen : true } ) ;
114
+ return false ;
115
+ }
116
+ } ,
117
+ true
118
+ ) ;
119
+ }
120
+
121
+ // Create and inject the Inkeep script
122
+ const inkeepScript = document . createElement ( "script" ) ;
123
+ inkeepScript . type = "module" ;
124
+ inkeepScript . src = "https://unpkg.com/@inkeep/widgets-embed@latest/dist/embed.js" ;
125
+
126
+ // Wait for both DOM content and Inkeep script to load
127
+ let domReady = false ;
128
+ let scriptLoaded = false ;
129
+
130
+ function tryInitialize ( ) {
131
+ if ( domReady && scriptLoaded ) {
132
+ initializeInkeep ( ) ;
133
+ }
134
+ }
135
+
136
+ // Handle DOM content loaded
137
+ document . addEventListener ( 'DOMContentLoaded' , ( ) => {
138
+ domReady = true ;
139
+ tryInitialize ( ) ;
140
+ } ) ;
141
+
142
+ // Handle script load
143
+ inkeepScript . addEventListener ( "load" , ( ) => {
144
+ scriptLoaded = true ;
145
+ tryInitialize ( ) ;
146
+ } ) ;
147
+
148
+ // Handle case where DOMContentLoaded has already fired
149
+ if ( document . readyState === 'complete' || document . readyState === 'interactive' ) {
150
+ domReady = true ;
151
+ tryInitialize ( ) ;
152
+ }
153
+
154
+ // Inject the script
155
+ document . body . appendChild ( inkeepScript ) ;
0 commit comments