Skip to content

Commit f091ba9

Browse files
authored
feat: improve UX of chat interface (#156)
1 parent e05ba43 commit f091ba9

File tree

6 files changed

+403
-51
lines changed

6 files changed

+403
-51
lines changed

media/animations.css

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/* Simple CSS animation to animate the agent cursor */
2+
@keyframes cursor-blink {
3+
0% {
4+
opacity: 0;
5+
}
6+
}
7+
8+
/* Animation for the typing dots */
9+
@keyframes typing-dots {
10+
0% {
11+
transform: translateY(0px);
12+
}
13+
14+
40% {
15+
transform: translateY(-0.25rem);
16+
opacity: 0.4;
17+
}
18+
19+
60% {
20+
transform: translateY(0px);
21+
}
22+
23+
100% {
24+
transform: translateY(0px);
25+
}
26+
}

media/chat.css

+233-5
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,239 @@
1-
.user-message {
2-
font-size: var(--vscode-editor-font-size);
1+
/* Sidebar sections */
2+
.sidebar__section-container {
3+
transition: all 0.3s ease;
4+
overflow: auto;
5+
max-height: 70vh;
6+
}
7+
8+
.sidebar__section-container.is-opening {
9+
max-height: 70vh;
10+
}
11+
12+
.sidebar__section-container:not(.active) {
13+
max-height: 0;
14+
overflow: hidden;
15+
}
16+
17+
/* ------------- Chat UI ------------- */
18+
.sidebar__chat-assistant--dialogue-container {
19+
padding: 0 var(--spacing-md);
20+
margin: 0;
21+
display: flex;
22+
flex-direction: column;
23+
}
24+
25+
.sidebar__chat-assistant--chat-bubble {
26+
display: inline-grid;
27+
align-items: flex-end;
28+
grid-gap: var(--spacing-md) var(--spacing-xs);
29+
margin-bottom: var(--spacing-md);
30+
word-break: break-word;
31+
}
32+
33+
/* Change width of columns based on agent/user */
34+
.sidebar__chat-assistant--chat-bubble-agent {
35+
grid-template-columns: 32px 1fr;
36+
}
37+
38+
.sidebar__chat-assistant--chat-bubble-user {
39+
grid-template-columns: 1fr 32px;
40+
}
41+
42+
/* Styles for avatars */
43+
.sidebar__chat-assistant--chat-avatar-container {
44+
background: var(--vscode-foreground);
45+
padding: var(--spacing-xs);
46+
border-radius: 100%;
47+
width: 2rem;
48+
height: 2rem;
49+
display: flex;
50+
align-items: center;
51+
justify-content: center;
52+
flex: auto;
53+
}
54+
55+
.sidebar__chat-assistant--agent-avatar-image {
56+
width: 100%;
57+
display: block;
58+
}
59+
60+
/* Styles for content inside chat bubbles */
61+
.sidebar__chat-assistant--chat-bubble-content-assistant,
62+
.sidebar__chat-assistant--code-block-container {
63+
background-color: var(--vscode-settings-textInputBackground);
64+
padding: var(--spacing-xs);
65+
border-radius: var(--spacing-xs);
66+
}
67+
68+
.sidebar__chat-assistant--chat-bubble-content-user {
69+
background-color: var(--vscode-settings-textInputBackground);
70+
padding: var(--spacing-xs);
71+
border-radius: var(--spacing-xs);
72+
}
73+
74+
.sidebar__chat-assistant--chat-bubble-text {
75+
margin: 0;
76+
color: var(--vscode-settings-textInputForeground);
77+
}
78+
79+
.sidebar__chat-assistant--chat-bubble-inline-button {
80+
/* Override a few things that are coming from the main CSS file */
81+
display: inline-block;
82+
width: auto;
83+
padding: 0;
84+
margin: 0;
85+
background: transparent;
86+
}
87+
88+
.sidebar__chat-assistant--code-block-container {
89+
background-color: var(--vscode-editor-background);
90+
color: var(--vscode-sideBar-foreground);
91+
}
92+
93+
.sidebar__chat-assistant--code-block {
94+
margin: 0;
395
font-family: var(--vscode-editor-font-family);
4-
background-color: var(--vscode-input-background);
96+
white-space: pre-line;
97+
}
98+
99+
.sidebar__chat-assistant--code-block code {
100+
font-size: var(--vscode-sidebar-font-size);
5101
}
6102

7-
.assistant-message {
8-
font-size: var(--vscode-editor-font-size);
103+
.sidebar__chat-assistant--chat-text-inline-code {
104+
display: inline-block;
9105
font-family: var(--vscode-editor-font-family);
106+
font-size: var(--vscode-sidebar-font-size);
107+
}
108+
109+
.sidebar__chat-assistant--chat-text-bold {
110+
font-weight: 600;
111+
}
112+
113+
.sidebar__chat-assistant--chat-text-separator {
114+
display: block;
115+
margin: var(--spacing-xxs);
116+
}
117+
118+
.sidebar__chat-assistant--chat-numbered-list {
119+
color: var(--vscode-editor-background);
120+
}
121+
122+
/* Hover functionality for inline code references in sidebar */
123+
.sidebar__chat-assistant--chat-bubble-inline-button
124+
.sidebar__chat-assistant--chat-text-inline-code {
125+
text-decoration: underline;
126+
text-underline-offset: var(--spacing-xxs);
127+
}
128+
129+
.sidebar__chat-assistant--chat-bubble-inline-button:hover {
130+
background: transparent;
131+
}
132+
133+
.sidebar__chat-assistant--chat-bubble-inline-button:hover
134+
.sidebar__chat-assistant--chat-text-inline-code {
135+
text-decoration: none;
136+
}
137+
138+
/* Don't round the specific corner where the avatar is, to make it look more like a chat bubble */
139+
.sidebar__chat-assistant--chat-bubble-agent
140+
.sidebar__chat-assistant--chat-bubble-content {
141+
border-bottom-left-radius: 0;
142+
}
143+
144+
.sidebar__chat-assistant--chat-bubble-user
145+
.sidebar__chat-assistant--chat-bubble-content {
146+
border-bottom-right-radius: 0;
147+
}
148+
149+
/* Make avatar bigger for user, since we're using an emoji for now */
150+
.sidebar__chat-assistant--chat-bubble-user
151+
.sidebar__chat-assistant--agent-avatar-image {
152+
font-size: 1.25rem;
153+
text-align: center;
154+
}
155+
156+
.sidebar__chat-assistant--cursor {
157+
display: inline-block;
158+
animation: cursor-blink 1.5s steps(2) infinite;
159+
width: 2px;
160+
}
161+
162+
/* Style and animate typing dots */
163+
.sidebar__chat-assistant--agent-typing-dot {
164+
display: inline-block;
165+
height: var(--spacing-xxs);
166+
width: var(--spacing-xxs);
10167
background-color: var(--vscode-editor-background);
168+
border-radius: 50%;
169+
animation-name: typing-dots;
170+
animation-duration: 0.8s;
171+
animation-timing-function: ease-in-out;
172+
animation-iteration-count: infinite;
173+
}
174+
175+
.sidebar__chat-assistant--agent-typing-dot:nth-of-type(1) {
176+
animation-delay: 0s;
177+
}
178+
179+
.sidebar__chat-assistant--agent-typing-dot:nth-of-type(2) {
180+
animation-delay: 0.2s;
181+
}
182+
183+
.sidebar__chat-assistant--agent-typing-dot:nth-of-type(3) {
184+
animation-delay: 0.4s;
185+
}
186+
187+
/* ------------- Text box container ------------- */
188+
.sidebar__chat-assistant--footer {
189+
border-bottom: 1px solid var(--vscode-sideBar-border);
190+
padding: var(--spacing-md);
191+
background-color: var(--vscode-sideBar-background);
192+
position: sticky;
193+
bottom: -1px;
194+
}
195+
196+
.sidebar__chat-assistant--textarea-container {
197+
position: relative;
198+
}
199+
200+
.sidebar__chat-assistant--textarea {
201+
font-weight: var(--vscode-font-weight);
202+
font-size: var(--vscode-font-size);
203+
border-radius: var(--spacing-xxs);
204+
background-color: var(--vscode-sideBar-dropBackground);
205+
padding-right: 3rem;
206+
outline: 1px solid transparent;
207+
resize: none;
208+
}
209+
210+
.sidebar__chat-assistant--textarea-send-button {
211+
position: absolute;
212+
right: 5px;
213+
bottom: 5px;
214+
outline: none;
215+
border-radius: var(--spacing-xxs);
216+
font-size: var(--vscode-sidebar-font-size);
217+
background-color: transparent;
218+
width: 2rem;
219+
height: 2rem;
220+
display: flex;
221+
align-items: center;
222+
justify-content: center;
223+
transition: background-color 0.3s ease-in-out;
224+
}
225+
226+
.sidebar__chat-assistant--textarea-send-icon {
227+
fill: orange;
228+
width: var(--spacing-lg);
229+
}
230+
231+
/* Disabled state for send button */
232+
.sidebar__textarea-send-button--disabled {
233+
pointer-events: none;
234+
background-color: transparent;
235+
}
236+
237+
.sidebar__textarea-send-button--disabled svg {
238+
opacity: 0.2;
11239
}

media/vscode.css

+12-4
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,17 @@
11
:root {
2-
--container-paddding: 20px;
3-
--input-padding-vertical: 6px;
4-
--input-padding-horizontal: 4px;
5-
--input-margin-vertical: 4px;
2+
/* Spacing. Converted them to rem and added a few more in-between values here */
3+
--container-padding: 1.25rem;
4+
--input-padding-vertical: 0.375rem;
5+
--input-padding-horizontal: 0.25rem;
6+
--input-margin-vertical: 0.25rem;
67
--input-margin-horizontal: 0;
8+
--spacing-xxs: 0.25rem;
9+
--spacing-xs: 0.375rem;
10+
--spacing-sm: 0.5rem;
11+
--spacing-md: 0.75rem;
12+
--spacing-lg: 1rem;
13+
--spacing-xl: 1.25rem;
14+
--spacing-xxl: 1.5rem;
715
}
816

917
body {

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,11 @@
5353
"sourcery-explorer": [
5454
{
5555
"id": "sourcery.chat",
56-
"name": "Chat",
56+
"name": "Coding Assistant",
5757
"type": "webview",
5858
"icon": "sourcery-icon.png",
59-
"contextualTitle": "Chat",
60-
"when": "sourcery.features.code_understanding"
59+
"contextualTitle": "Coding Assistant",
60+
"when": "sourcery.features.coding_assistant"
6161
},
6262
{
6363
"id": "sourcery.rules",

src/chat.ts

+29-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import * as vscode from "vscode";
22
import { randomBytes } from "crypto";
3-
import { getValidInput } from "./extension";
43

54
export class ChatProvider implements vscode.WebviewViewProvider {
65
public static readonly viewType = "sourcery.chat";
@@ -31,7 +30,11 @@ export class ChatProvider implements vscode.WebviewViewProvider {
3130
webviewView.webview
3231
);
3332

34-
const input = getValidInput();
33+
webviewView.onDidChangeVisibility(() => {
34+
if (this._view.visible) {
35+
this._view.webview.postMessage({ command: "focus" });
36+
}
37+
});
3538

3639
webviewView.webview.onDidReceiveMessage(async (data) => {
3740
switch (data.type) {
@@ -67,6 +70,9 @@ export class ChatProvider implements vscode.WebviewViewProvider {
6770
const styleMainUri = webview.asWebviewUri(
6871
vscode.Uri.joinPath(this._extensionUri, "media", "chat.css")
6972
);
73+
const animationsUri = webview.asWebviewUri(
74+
vscode.Uri.joinPath(this._extensionUri, "media", "animations.css")
75+
);
7076
// Use a nonce to only allow a specific script to be run.
7177
const nonce = randomBytes(16).toString("base64");
7278

@@ -97,13 +103,29 @@ export class ChatProvider implements vscode.WebviewViewProvider {
97103
<link href="${styleResetUri}" rel="stylesheet">
98104
<link href="${styleVSCodeUri}" rel="stylesheet">
99105
<link href="${styleMainUri}" rel="stylesheet">
106+
<link href="${animationsUri}" rel="stylesheet">
100107
</head>
101108
<body>
102-
<div class="chatContainer">
103-
</div>
104-
<div class="inputContainer">
105-
<input type="text" class="message-input" placeholder="Type your message..." autofocus>
106-
</div>
109+
<section class="sidebar__section-container active" data-section="chat-assistant">
110+
<ul class="sidebar__chat-assistant--dialogue-container">
111+
112+
</ul>
113+
<footer class="sidebar__chat-assistant--footer">
114+
<section class="sidebar__chat-assistant--textarea-container">
115+
<textarea class="sidebar__chat-assistant--textarea" placeholder="Type your message here!"
116+
id="user-prompt"></textarea>
117+
<button class="sidebar__chat-assistant--textarea-send-button sidebar__textarea-send-button--disabled"
118+
id="send-button">
119+
<svg viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg"
120+
class="sidebar__chat-assistant--textarea-send-icon">
121+
<path
122+
d="m498.1 5.6c10.1 7 15.4 19.1 13.5 31.2l-64 416c-1.5 9.7-7.4 18.2-16 23s-18.9 5.4-28 1.6l-119.6-49.7-68.5 74.1c-8.9 9.7-22.9 12.9-35.2 8.1s-20.3-16.7-20.3-29.9v-83.6c0-4 1.5-7.8 4.2-10.7l167.6-182.9c5.8-6.3 5.6-16-.4-22s-15.7-6.4-22-.7l-203.4 180.7-88.3-44.2c-10.6-5.3-17.4-15.9-17.7-27.7s5.9-22.8 16.1-28.7l448-256c10.7-6.1 23.9-5.5 34 1.4z" />
123+
</svg>
124+
</button>
125+
</section>
126+
</footer>
127+
</section>
128+
107129
</body>
108130
<script nonce="${nonce}" src="${scriptUri}"></script>
109131
</html>`;

0 commit comments

Comments
 (0)