Skip to content

Commit 127a1e0

Browse files
authored
feat: Adjust companion to new designs (#3650)
* adjust first components to new designs * feat: adjust input alignment * feat: adjusted code panels, implemented syntax highlighting * temporarily uninstall packages * reinstall packages * directly use ui5 color for styling messages * feat: add copy to clipboard functionality * fix: adjust disclaimer
1 parent 0c1486e commit 127a1e0

File tree

15 files changed

+688
-108
lines changed

15 files changed

+688
-108
lines changed

package-lock.json

Lines changed: 446 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@
6464
"@stoplight/json-ref-resolver": "^3.1.3",
6565
"@types/jsonpath": "^0.2.0",
6666
"@types/pluralize": "^0.0.29",
67+
"@types/react-syntax-highlighter": "^15.5.13",
6768
"@ui-schema/ui-schema": "^0.4.5",
6869
"@ui5/webcomponents": "^2.7.0",
6970
"@ui5/webcomponents-base": "^2.7.0",
@@ -103,6 +104,7 @@
103104
"react-dom": "^18.3.1",
104105
"react-i18next": "^11.18.6",
105106
"react-router-dom": "^6.3.0",
107+
"react-syntax-highlighter": "^15.6.1",
106108
"react-tippy": "^1.4.0",
107109
"recoil": "^0.7.5",
108110
"resize-observer-polyfill": "^1.5.1",

public/i18n/en.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -761,7 +761,8 @@ kyma-companion:
761761
subtitle: A temporary interruption occured. Please try again.
762762
introduction1: Hello there,
763763
introduction2: How can I help you?
764-
placeholder: Type something
764+
placeholder: Message Joule
765+
disclaimer: Joule is powered by generative AI, and the output must be reviewed before use. Do not enter any sensitive personal data, and avoid entering any other data you do not wish to be processed.
765766
tabs:
766767
chat: Chat
767768
page-insights: Page Insights

src/components/App/App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ export default function App() {
136136
<SplitterElement
137137
resizable={!showCompanion.fullScreen}
138138
size={showCompanion.fullScreen ? '100%' : '30%'}
139-
minSize={350}
139+
minSize={400}
140140
>
141141
<KymaCompanion />
142142
</SplitterElement>

src/components/KymaCompanion/components/Chat/Chat.scss

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
.chat-container {
2-
height: 100%;
2+
height: calc(100vh - 60px - 1rem);
33
overflow: hidden;
44

55
.chat-list {
@@ -13,19 +13,63 @@
1313
}
1414

1515
.left-aligned {
16+
position: relative;
1617
align-self: flex-start;
17-
background-color: var(--sapBackgroundColor);
1818
border-radius: 8px 8px 8px 0;
19+
z-index: 0;
20+
}
21+
22+
.left-aligned::before {
23+
content: '';
24+
position: absolute;
25+
top: 0;
26+
left: 0;
27+
right: 0;
28+
bottom: 0;
29+
background-color: var(--sapNeutralColor);
30+
opacity: 0.2;
31+
border-radius: 8px 8px 8px 0;
32+
z-index: -1;
1933
}
2034

2135
.right-aligned {
36+
position: relative;
2237
align-self: flex-end;
38+
border-radius: 8px 8px 0 8px;
39+
z-index: 0;
40+
}
41+
42+
.right-aligned::before {
43+
content: '';
44+
position: absolute;
45+
top: 0;
46+
left: 0;
47+
right: 0;
48+
bottom: 0;
2349
background-color: var(--sapContent_Illustrative_Color1);
50+
opacity: 0.25;
2451
border-radius: 8px 8px 0 8px;
52+
z-index: -1;
53+
}
54+
}
55+
56+
.outer-input-container {
57+
display: flex;
58+
flex-direction: column;
59+
gap: 0.5rem;
2560

26-
.text {
27-
color: white;
61+
.input-container {
62+
position: relative;
63+
64+
#text-area-icon {
65+
position: absolute;
66+
right: 0.5rem;
67+
bottom: 0.6rem;
2868
}
2969
}
70+
71+
#disclaimer {
72+
font-size: 0.65rem;
73+
}
3074
}
3175
}

src/components/KymaCompanion/components/Chat/Chat.tsx

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { useTranslation } from 'react-i18next';
22
import React, { useEffect, useRef, useState } from 'react';
33
import { useRecoilValue } from 'recoil';
4-
import { FlexBox, Icon, Input } from '@ui5/webcomponents-react';
4+
import { FlexBox, Icon, Text, TextArea } from '@ui5/webcomponents-react';
55
import { initialPromptState } from 'components/KymaCompanion/state/initalPromptAtom';
66
import Message from './messages/Message';
77
import Bubbles from './messages/Bubbles';
@@ -126,12 +126,15 @@ export default function Chat() {
126126
justifyContent="SpaceBetween"
127127
className="chat-container"
128128
>
129-
<div className="chat-list sap-margin-tiny" ref={containerRef}>
129+
<div
130+
className="chat-list sap-margin-x-tiny sap-margin-top-small"
131+
ref={containerRef}
132+
>
130133
{chatHistory.map((message, index) => {
131134
return message.author === 'ai' ? (
132135
<React.Fragment key={index}>
133136
<Message
134-
className="left-aligned"
137+
className="left-aligned sap-margin-begin-tiny"
135138
messageChunks={message.messageChunks}
136139
isLoading={message.isLoading}
137140
/>
@@ -145,7 +148,7 @@ export default function Chat() {
145148
) : (
146149
<Message
147150
key={index}
148-
className="right-aligned"
151+
className="right-aligned sap-margin-end-tiny"
149152
messageChunks={message.messageChunks}
150153
isLoading={message.isLoading}
151154
/>
@@ -158,16 +161,34 @@ export default function Chat() {
158161
/>
159162
)}
160163
</div>
161-
<div className="sap-margin-x-tiny">
162-
<Input
163-
className="full-width"
164-
disabled={chatHistory[chatHistory.length - 1]?.isLoading}
165-
placeholder={t('kyma-companion.placeholder')}
166-
value={inputValue}
167-
icon={<Icon name="paper-plane" onClick={onSubmitInput} />}
168-
onKeyDown={e => e.key === 'Enter' && onSubmitInput()}
169-
onInput={e => setInputValue(e.target.value)}
170-
/>
164+
<div className="outer-input-container sap-margin-x-small sap-margin-bottom-small sap-margin-top-tiny">
165+
<div className="input-container">
166+
<TextArea
167+
className="full-width"
168+
growing
169+
growingMaxRows={10}
170+
rows={1}
171+
placeholder={t('kyma-companion.placeholder')}
172+
value={inputValue}
173+
onKeyDown={e => {
174+
if (e.key === 'Enter' && !e.shiftKey) {
175+
e.preventDefault();
176+
onSubmitInput();
177+
}
178+
}}
179+
onInput={e => {
180+
setInputValue(e.target.value);
181+
}}
182+
valueState="None"
183+
/>
184+
<Icon
185+
id="text-area-icon"
186+
name="paper-plane"
187+
mode="Interactive"
188+
onClick={onSubmitInput}
189+
/>
190+
</div>
191+
<Text id="disclaimer">{t('kyma-companion.disclaimer')}</Text>
171192
</div>
172193
</FlexBox>
173194
);

src/components/KymaCompanion/components/Chat/messages/Bubbles.scss

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44

55
.bubble-button {
66
align-self: flex-start;
7-
color: var(--sapChart_OrderedColor_5);
7+
color: var(--sapLinkColor);
8+
border-radius: 0.75rem;
9+
border: none;
10+
box-shadow: 0 1px 3px var(--sapLinkColor);
811
}
912

1013
.bubble-button:hover {
11-
background-color: var(--sapBackgroundColor1);
12-
border-color: var(--sapChart_OrderedColor_5);
14+
background-color: var(--sapBackgroundColor);
1315
}
1416
}

src/components/KymaCompanion/components/Chat/messages/Bubbles.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,11 @@ export default function Bubbles({
1111
onClick,
1212
}: BubblesProps): JSX.Element {
1313
return suggestions ? (
14-
<FlexBox wrap="Wrap" justifyContent="Start" className={'bubbles-container'}>
14+
<FlexBox
15+
wrap="Wrap"
16+
justifyContent="Start"
17+
className="bubbles-container sap-margin-begin-tiny sap-margin-bottom-tiny"
18+
>
1519
{suggestions.map((suggestion, index) => (
1620
<Button
1721
key={index}
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,28 @@
11
.code-response {
2-
background-color: #484848;
3-
color: white;
2+
background-color: var(--sapBaseColor);
43
padding: 0.75rem;
54
border-radius: 4px;
5+
position: relative;
66

7-
.text {
8-
color: white;
7+
#copy-icon {
8+
position: absolute;
9+
top: 0.5rem;
10+
right: 0.75rem;
11+
}
12+
13+
#code-text {
14+
white-space: pre-wrap;
915
}
1016
}
1117

1218
.code-panel::part(header) {
13-
background-color: #484848;
14-
color: white;
19+
background-color: var(--sapBaseColor);
1520
border-radius: 4px 4px 0 0;
16-
font-size: 0.9rem;
21+
padding: 0.5rem 0.75rem !important;
1722
}
1823

1924
.code-panel::part(content) {
20-
background-color: #484848;
25+
background-color: var(--sapBaseColor);
2126
border-radius: 0 0 4px 4px;
22-
}
23-
24-
.code-panel {
25-
.text {
26-
color: white;
27-
}
27+
padding: 0;
2828
}
Lines changed: 80 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,95 @@
1-
import { Text, Panel } from '@ui5/webcomponents-react';
1+
import { Text, Panel, Title, Icon, FlexBox } from '@ui5/webcomponents-react';
22
import { formatCodeSegment } from 'components/KymaCompanion/utils/formatMarkdown';
3+
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
4+
import { useRecoilValue } from 'recoil';
5+
import {
6+
isCurrentThemeDark,
7+
Theme,
8+
themeState,
9+
} from 'state/preferences/themeAtom';
10+
import copyToCliboard from 'copy-to-clipboard';
311
import './CodePanel.scss';
412

13+
function getCustomTheme(theme: Theme) {
14+
const isDark = isCurrentThemeDark(theme);
15+
const monacoEditorKeyColorLight = '#008080';
16+
const monacoEditorKeyColorDark = '#3dc9b0';
17+
const monacoEditorTextColorLight = '#0451a5';
18+
const monacoEditorTextColorDark = '#ce9178';
19+
20+
return {
21+
'code[class*="language-"]': {
22+
color: isDark ? monacoEditorTextColorDark : monacoEditorTextColorLight,
23+
background: 'var(--sapBaseColor)',
24+
fontFamily: 'var(--sapFontFamily)',
25+
fontSize: '14px',
26+
},
27+
'pre[class*="language-"]': {
28+
background: 'var(--sapBaseColor)',
29+
padding: '0 0.75rem',
30+
margin: '0.5rem 0',
31+
borderRadius: '8px',
32+
},
33+
comment: {
34+
color: isDark ? 'var(--sapLinkColor)' : monacoEditorTextColorDark,
35+
},
36+
keyword: {
37+
color: isDark ? monacoEditorKeyColorDark : monacoEditorKeyColorLight,
38+
},
39+
key: {
40+
color: isDark ? monacoEditorKeyColorDark : monacoEditorKeyColorLight,
41+
},
42+
punctuation: {
43+
color: 'var(--sapTextColor)',
44+
},
45+
operator: { color: 'var(--sapTextColor)' },
46+
function: { color: 'var(--sapChart_OrderedColor_4)' },
47+
number: {
48+
color: 'var(--sapChart_OrderedColor_4)',
49+
},
50+
};
51+
}
52+
553
interface CodePanelProps {
654
text: string;
755
}
856

957
export default function CodePanel({ text }: CodePanelProps): JSX.Element {
58+
const theme = useRecoilValue(themeState);
59+
const syntaxTheme = getCustomTheme(theme);
1060
const { language, code } = formatCodeSegment(text);
1161
return !language ? (
12-
<div className="code-response">
13-
<Text className="text">{code}</Text>
62+
<div className="code-response sap-margin-y-small">
63+
<Icon
64+
id="copy-icon"
65+
mode="Interactive"
66+
name="copy"
67+
design="Information"
68+
onClick={() => copyToCliboard(code)}
69+
/>
70+
<Text id="code-text">{code}</Text>
1471
</div>
1572
) : (
16-
<Panel headerText={language} className="code-panel" fixed>
17-
<Text className="text">{code}</Text>
73+
<Panel
74+
className="code-panel sap-margin-y-small"
75+
header={
76+
<FlexBox alignItems="Center" fitContainer justifyContent="SpaceBetween">
77+
<Title level="H6" size="H6">
78+
{language}
79+
</Title>
80+
<Icon
81+
mode="Interactive"
82+
name="copy"
83+
design="Information"
84+
onClick={() => copyToCliboard(code)}
85+
/>
86+
</FlexBox>
87+
}
88+
fixed
89+
>
90+
<SyntaxHighlighter language={language} style={syntaxTheme} wrapLongLines>
91+
{code}
92+
</SyntaxHighlighter>
1893
</Panel>
1994
);
2095
}

0 commit comments

Comments
 (0)