Skip to content

Commit 3b34d27

Browse files
authored
Merge pull request #17 from objectstack-ai/copilot/add-complete-chatbot-component
2 parents c89087e + e02abdc commit 3b34d27

6 files changed

Lines changed: 667 additions & 0 deletions

File tree

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
import { SchemaRenderer } from '@object-ui/react';
2+
import '@object-ui/components';
3+
4+
const chatbotSchema = {
5+
type: 'div',
6+
className: 'min-h-screen bg-gradient-to-br from-slate-50 to-slate-100 p-8',
7+
body: [
8+
{
9+
type: 'div',
10+
className: 'max-w-4xl mx-auto space-y-8',
11+
body: [
12+
// Header
13+
{
14+
type: 'div',
15+
className: 'text-center space-y-4',
16+
body: [
17+
{
18+
type: 'div',
19+
className: 'text-4xl font-bold bg-gradient-to-r from-blue-600 to-purple-600 bg-clip-text text-transparent',
20+
body: {
21+
type: 'text',
22+
content: 'Object UI Chatbot Component'
23+
}
24+
},
25+
{
26+
type: 'div',
27+
className: 'text-lg text-muted-foreground',
28+
body: {
29+
type: 'text',
30+
content: 'A fully functional, schema-driven chatbot component'
31+
}
32+
}
33+
]
34+
},
35+
36+
// Chatbot Demo Card
37+
{
38+
type: 'card',
39+
className: 'shadow-2xl',
40+
body: [
41+
{
42+
type: 'div',
43+
className: 'p-6 border-b',
44+
body: {
45+
type: 'div',
46+
className: 'text-xl font-semibold',
47+
body: {
48+
type: 'text',
49+
content: 'Interactive Demo'
50+
}
51+
}
52+
},
53+
{
54+
type: 'div',
55+
className: 'p-6',
56+
body: {
57+
type: 'chatbot',
58+
messages: [
59+
{
60+
id: 'welcome',
61+
role: 'assistant',
62+
content: 'Hello! 👋 Welcome to Object UI Chatbot. I\'m here to help you explore this component. Try sending me a message!',
63+
},
64+
{
65+
id: 'info',
66+
role: 'assistant',
67+
content: 'This chatbot is built entirely from JSON schema. No React components needed!',
68+
}
69+
],
70+
placeholder: 'Type your message here...',
71+
showTimestamp: true,
72+
userAvatarFallback: 'You',
73+
assistantAvatarFallback: 'AI',
74+
maxHeight: '600px',
75+
autoResponse: true,
76+
autoResponseText: 'Thanks for your message! This is an automated response demonstrating the chatbot functionality. In a real application, you would connect this to your backend API or AI service.',
77+
autoResponseDelay: 1500,
78+
className: 'w-full'
79+
}
80+
}
81+
]
82+
},
83+
84+
// Features Section
85+
{
86+
type: 'div',
87+
className: 'grid md:grid-cols-2 gap-6',
88+
body: [
89+
{
90+
type: 'card',
91+
className: 'p-6 shadow-lg',
92+
body: [
93+
{
94+
type: 'div',
95+
className: 'text-lg font-semibold mb-3',
96+
body: {
97+
type: 'text',
98+
content: '✨ Key Features'
99+
}
100+
},
101+
{
102+
type: 'list',
103+
items: [
104+
'Message bubbles with user/assistant roles',
105+
'Avatar support for participants',
106+
'Scrollable message history',
107+
'Input field with send button',
108+
'Timestamp display (optional)',
109+
'Auto-response for demos',
110+
'Fully customizable styling'
111+
],
112+
className: 'text-sm'
113+
}
114+
]
115+
},
116+
{
117+
type: 'card',
118+
className: 'p-6 shadow-lg',
119+
body: [
120+
{
121+
type: 'div',
122+
className: 'text-lg font-semibold mb-3',
123+
body: {
124+
type: 'text',
125+
content: '🎨 Schema-Driven'
126+
}
127+
},
128+
{
129+
type: 'div',
130+
className: 'text-sm space-y-2',
131+
body: [
132+
{
133+
type: 'text',
134+
content: 'This entire chatbot is defined using pure JSON schema. Configure messages, styling, behavior, and more without writing any React code.'
135+
},
136+
{
137+
type: 'div',
138+
className: 'mt-4 p-3 bg-muted rounded-lg font-mono text-xs',
139+
body: {
140+
type: 'text',
141+
content: '{ type: "chatbot", messages: [...] }'
142+
}
143+
}
144+
]
145+
}
146+
]
147+
}
148+
]
149+
},
150+
151+
// Usage Example
152+
{
153+
type: 'card',
154+
className: 'p-6 shadow-lg',
155+
body: [
156+
{
157+
type: 'div',
158+
className: 'text-lg font-semibold mb-3',
159+
body: {
160+
type: 'text',
161+
content: '📝 Usage Example'
162+
}
163+
},
164+
{
165+
type: 'div',
166+
className: 'bg-slate-900 text-slate-50 p-4 rounded-lg overflow-x-auto',
167+
body: {
168+
type: 'text',
169+
content: `{
170+
"type": "chatbot",
171+
"messages": [
172+
{
173+
"id": "msg-1",
174+
"role": "assistant",
175+
"content": "Hello! How can I help?"
176+
}
177+
],
178+
"placeholder": "Type your message...",
179+
"showTimestamp": true,
180+
"autoResponse": true,
181+
"className": "w-full"
182+
}`
183+
}
184+
}
185+
]
186+
}
187+
]
188+
}
189+
]
190+
};
191+
192+
function ChatbotDemo() {
193+
return <SchemaRenderer schema={chatbotSchema} />;
194+
}
195+
196+
export default ChatbotDemo;
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { describe, it, expect, beforeAll } from 'vitest';
2+
import { ComponentRegistry } from '@object-ui/core';
3+
4+
describe('Chatbot Component', () => {
5+
// Import all renderers to register them
6+
beforeAll(async () => {
7+
await import('./index');
8+
});
9+
10+
it('should be registered in ComponentRegistry', () => {
11+
const chatbotRenderer = ComponentRegistry.get('chatbot');
12+
expect(chatbotRenderer).toBeDefined();
13+
});
14+
15+
it('should have proper metadata', () => {
16+
const config = ComponentRegistry.getConfig('chatbot');
17+
expect(config).toBeDefined();
18+
expect(config?.label).toBe('Chatbot');
19+
expect(config?.inputs).toBeDefined();
20+
expect(config?.defaultProps).toBeDefined();
21+
});
22+
23+
it('should have expected inputs', () => {
24+
const config = ComponentRegistry.getConfig('chatbot');
25+
const inputNames = config?.inputs?.map((input: any) => input.name) || [];
26+
27+
expect(inputNames).toContain('messages');
28+
expect(inputNames).toContain('placeholder');
29+
expect(inputNames).toContain('showTimestamp');
30+
expect(inputNames).toContain('userAvatarUrl');
31+
expect(inputNames).toContain('assistantAvatarUrl');
32+
});
33+
34+
it('should have sensible default props', () => {
35+
const config = ComponentRegistry.getConfig('chatbot');
36+
const defaults = config?.defaultProps;
37+
38+
expect(defaults).toBeDefined();
39+
expect(defaults?.placeholder).toBe('Type your message...');
40+
expect(defaults?.showTimestamp).toBe(false);
41+
expect(defaults?.messages).toBeDefined();
42+
expect(Array.isArray(defaults?.messages)).toBe(true);
43+
});
44+
});

0 commit comments

Comments
 (0)