Skip to content

Commit 9ad47b6

Browse files
style: update graphics (#1138)
* style: update new icon and NavLinks scale * style: new username update * refactor(Dropdown); style: general settings * style(Dropdown); adjust theme * style: dropdown and settings text * fix(Dropdown) system theme not working * style: topbar sticky; fix: general's menu settings transparent with light theme * fix(SubmitButton) stop generate button * fix: user_provided dialog for new dropdown * fix: TS error 'display' * fix(EditPresetDialog): for new dropdown * style: added green send button * converted textchat in tsx * style(SubmitButton): tooltip * test: fixed ThemeSelector and LangSelector * removed transition-opacity * fix all tests * removed empty cn call * chore: Update General.tsx to add Arabic option --------- Co-authored-by: Danny Avila <110412045+danny-avila@users.noreply.github.com>
1 parent 8b28fdf commit 9ad47b6

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+442
-318
lines changed

client/src/components/Endpoints/EditPresetDialog.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -91,14 +91,9 @@ const EditPresetDialog = ({ open, onOpenChange, preset: _preset, title }: TEditP
9191
</Label>
9292
<Dropdown
9393
value={endpoint || ''}
94-
onChange={setOption('endpoint')}
94+
onChange={(value) => setOption('endpoint')(value)}
9595
options={availableEndpoints}
96-
className={cn(
97-
defaultTextProps,
98-
'flex h-10 max-h-10 w-full resize-none ',
99-
removeFocusOutlines,
100-
)}
101-
containerClassName="flex w-full resize-none z-[51]"
96+
className={cn()}
10297
/>
10398
</div>
10499
</div>

client/src/components/Endpoints/Settings/Anthropic.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
4040
setValue={setModel}
4141
availableValues={models}
4242
disabled={readonly}
43-
className={cn(defaultTextProps, 'z-50 flex w-full resize-none', removeFocusOutlines)}
43+
className={cn(defaultTextProps, 'flex w-full resize-none', removeFocusOutlines)}
4444
containerClassName="flex w-full resize-none"
4545
/>
4646
</div>

client/src/components/Endpoints/Settings/Google.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export default function Settings({ conversation, setOption, models, readonly }:
4242
setValue={setModel}
4343
availableValues={models}
4444
disabled={readonly}
45-
className={cn(defaultTextProps, 'z-50 flex w-full resize-none', removeFocusOutlines)}
45+
className={cn(defaultTextProps, 'flex w-full resize-none', removeFocusOutlines)}
4646
containerClassName="flex w-full resize-none"
4747
/>
4848
</div>

client/src/components/Input/SetKeyDialog/SetKeyDialog.tsx

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type { TDialogProps } from '~/common';
33
import { Dialog, Dropdown } from '~/components/ui';
44
import DialogTemplate from '~/components/ui/DialogTemplate';
55
import { RevokeKeysButton } from '~/components/Nav';
6-
import { cn, defaultTextProps, removeFocusOutlines, alternateName } from '~/utils';
6+
import { cn, alternateName } from '~/utils';
77
import { useUserKey, useLocalize } from '~/hooks';
88
import GoogleConfig from './GoogleConfig';
99
import OpenAIConfig from './OpenAIConfig';
@@ -75,13 +75,7 @@ const SetKeyDialog = ({
7575
value={expiresAtLabel}
7676
onChange={handleExpirationChange}
7777
options={expirationOptions.map((option) => option.display)}
78-
className={cn(
79-
defaultTextProps,
80-
'flex h-full w-full resize-none',
81-
removeFocusOutlines,
82-
)}
83-
optionsClassName="max-h-72"
84-
containerClassName="flex w-1/2 md:w-1/3 resize-none z-[51]"
78+
width={185}
8579
/>
8680
<EndpointComponent userKey={userKey} setUserKey={setUserKey} endpoint={endpoint} />
8781
<HelpText endpoint={endpoint} />

client/src/components/Input/SubmitButton.tsx

Lines changed: 66 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ import React, { useState, useEffect, useCallback } from 'react';
22
import { StopGeneratingIcon } from '~/components';
33
import { Settings } from 'lucide-react';
44
import { SetKeyDialog } from './SetKeyDialog';
5-
import { useUserKey, useLocalize } from '~/hooks';
5+
import { useUserKey, useLocalize, useMediaQuery } from '~/hooks';
6+
import { SendMessageIcon } from '~/components/svg';
7+
import { TooltipProvider, Tooltip, TooltipTrigger, TooltipContent } from '~/components/ui/';
68

79
export default function SubmitButton({
810
conversation,
@@ -11,13 +13,24 @@ export default function SubmitButton({
1113
disabled,
1214
isSubmitting,
1315
userProvidesKey,
16+
hasText,
1417
}) {
1518
const { endpoint } = conversation;
1619
const [isDialogOpen, setDialogOpen] = useState(false);
1720
const { checkExpiry } = useUserKey(endpoint);
1821
const [isKeyProvided, setKeyProvided] = useState(userProvidesKey ? checkExpiry() : true);
1922
const isKeyActive = checkExpiry();
2023
const localize = useLocalize();
24+
const dots = ['·', '··', '···'];
25+
const [dotIndex, setDotIndex] = useState(0);
26+
27+
useEffect(() => {
28+
const interval = setInterval(() => {
29+
setDotIndex((prevDotIndex) => (prevDotIndex + 1) % dots.length);
30+
}, 500);
31+
32+
return () => clearInterval(interval);
33+
}, [dots.length]);
2134

2235
useEffect(() => {
2336
if (userProvidesKey) {
@@ -35,22 +48,43 @@ export default function SubmitButton({
3548
[submitMessage],
3649
);
3750

51+
const [isSquareGreen, setIsSquareGreen] = useState(false);
52+
3853
const setKey = useCallback(() => {
3954
setDialogOpen(true);
4055
}, []);
4156

42-
if (isSubmitting) {
57+
const isSmallScreen = useMediaQuery('(max-width: 768px)');
58+
59+
const iconContainerClass = `m-1 mr-0 rounded-md pb-[5px] pl-[6px] pr-[4px] pt-[5px] ${
60+
hasText ? (isSquareGreen ? 'bg-green-500' : '') : ''
61+
} group-hover:bg-19C37D group-disabled:hover:bg-transparent dark:${
62+
hasText ? (isSquareGreen ? 'bg-green-500' : '') : ''
63+
} dark:group-hover:text-gray-400 dark:group-disabled:hover:bg-transparent`;
64+
65+
useEffect(() => {
66+
setIsSquareGreen(hasText);
67+
}, [hasText]);
68+
69+
if (isSubmitting && isSmallScreen) {
4370
return (
44-
<button
45-
onClick={handleStopGenerating}
46-
type="button"
47-
className="group absolute bottom-0 right-0 z-[101] flex h-[100%] w-[50px] items-center justify-center bg-transparent p-1 text-gray-500"
48-
>
71+
<button onClick={handleStopGenerating} type="button">
4972
<div className="m-1 mr-0 rounded-md p-2 pb-[10px] pt-[10px] group-hover:bg-gray-100 group-disabled:hover:bg-transparent dark:group-hover:bg-gray-900 dark:group-hover:text-gray-400 dark:group-disabled:hover:bg-transparent">
5073
<StopGeneratingIcon />
5174
</div>
5275
</button>
5376
);
77+
} else if (isSubmitting) {
78+
return (
79+
<div className="relative flex h-full">
80+
<div
81+
className="absolute text-2xl"
82+
style={{ top: '50%', transform: 'translateY(-20%) translateX(-33px)' }}
83+
>
84+
{dots[dotIndex]}
85+
</div>
86+
</div>
87+
);
5488
} else if (!isKeyProvided) {
5589
return (
5690
<>
@@ -73,34 +107,31 @@ export default function SubmitButton({
73107
);
74108
} else {
75109
return (
76-
<button
77-
onClick={clickHandler}
78-
disabled={disabled}
79-
data-testid="submit-button"
80-
className="group absolute bottom-0 right-0 z-[101] flex h-[100%] w-[50px] items-center justify-center bg-transparent p-1 text-gray-500"
81-
>
82-
<div className="m-1 mr-0 rounded-md pb-[9px] pl-[9.5px] pr-[7px] pt-[11px] group-hover:bg-gray-100 group-disabled:hover:bg-transparent dark:group-hover:bg-gray-900 dark:group-hover:text-gray-400 dark:group-disabled:hover:bg-transparent">
83-
<svg
84-
stroke="currentColor"
85-
fill="none"
86-
strokeWidth="2"
87-
viewBox="0 0 24 24"
88-
strokeLinecap="round"
89-
strokeLinejoin="round"
90-
className="mr-1 h-4 w-4 "
91-
height="1em"
92-
width="1em"
93-
xmlns="http://www.w3.org/2000/svg"
94-
>
95-
<line x1="22" y1="2" x2="11" y2="13" />
96-
<polygon points="22 2 15 22 11 13 2 9 22 2" />
97-
</svg>
98-
</div>
99-
</button>
110+
<TooltipProvider delayDuration={50}>
111+
<Tooltip>
112+
<TooltipTrigger asChild>
113+
<button
114+
onClick={clickHandler}
115+
disabled={disabled}
116+
data-testid="submit-button"
117+
className="group absolute bottom-0 right-0 z-[101] flex h-[100%] w-[50px] items-center justify-center bg-transparent p-1 text-gray-500"
118+
>
119+
<div className={iconContainerClass}>
120+
{hasText ? (
121+
<div className="bg-19C37D flex h-[24px] w-[24px] items-center justify-center rounded-full text-white">
122+
<SendMessageIcon />
123+
</div>
124+
) : (
125+
<SendMessageIcon />
126+
)}
127+
</div>
128+
</button>
129+
</TooltipTrigger>
130+
<TooltipContent side="top" sideOffset={-5}>
131+
{localize('com_nav_send_message')}
132+
</TooltipContent>
133+
</Tooltip>
134+
</TooltipProvider>
100135
);
101136
}
102137
}
103-
104-
{
105-
/* <div class="text-2xl"><span class="">·</span><span class="">·</span><span class="invisible">·</span></div> */
106-
}

client/src/components/Input/TextChat.jsx renamed to client/src/components/Input/TextChat.tsx

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,43 @@
1-
import React, { useEffect, useContext, useRef } from 'react';
1+
import React, { useEffect, useContext, useRef, useState, useCallback } from 'react';
22
import TextareaAutosize from 'react-textarea-autosize';
33
import { useRecoilValue, useRecoilState, useSetRecoilState } from 'recoil';
44
import SubmitButton from './SubmitButton';
5+
56
import OptionsBar from './OptionsBar';
67
import { EndpointMenu } from './EndpointMenu';
78
import Footer from './Footer';
89
import { useMessageHandler, ThemeContext } from '~/hooks';
910
import { cn } from '~/utils';
1011
import store from '~/store';
1112

12-
export default function TextChat({ isSearchView = false }) {
13+
interface TextChatProps {
14+
isSearchView?: boolean;
15+
}
16+
17+
export default function TextChat({ isSearchView = false }: TextChatProps) {
1318
const { ask, isSubmitting, handleStopGenerating, latestMessage, endpointsConfig } =
1419
useMessageHandler();
1520
const conversation = useRecoilValue(store.conversation);
1621
const setShowBingToneSetting = useSetRecoilState(store.showBingToneSetting);
1722
const [text, setText] = useRecoilState(store.text);
1823
const { theme } = useContext(ThemeContext);
1924
const isComposing = useRef(false);
20-
const inputRef = useRef(null);
25+
const inputRef = useRef<HTMLTextAreaElement>(null);
26+
const [hasText, setHasText] = useState(false);
2127

2228
// TODO: do we need this?
2329
const disabled = false;
2430

25-
const isNotAppendable = latestMessage?.unfinished & !isSubmitting || latestMessage?.error;
31+
const isNotAppendable = (latestMessage?.unfinished && !isSubmitting) || latestMessage?.error;
2632
const { conversationId, jailbreak } = conversation || {};
2733

28-
// auto focus to input, when enter a conversation.
34+
// auto focus to input, when entering a conversation.
2935
useEffect(() => {
3036
if (!conversationId) {
3137
return;
3238
}
3339

34-
// Prevents Settings from not showing on new conversation, also prevents showing toneStyle change without jailbreak
40+
// Prevents Settings from not showing on a new conversation, also prevents showing toneStyle change without jailbreak
3541
if (conversationId === 'new' || !jailbreak) {
3642
setShowBingToneSetting(false);
3743
}
@@ -54,9 +60,10 @@ export default function TextChat({ isSearchView = false }) {
5460
const submitMessage = () => {
5561
ask({ text });
5662
setText('');
63+
setHasText(false);
5764
};
5865

59-
const handleKeyDown = (e) => {
66+
const handleKeyDown = (e: React.KeyboardEvent) => {
6067
if (e.key === 'Enter' && isSubmitting) {
6168
return;
6269
}
@@ -70,9 +77,9 @@ export default function TextChat({ isSearchView = false }) {
7077
}
7178
};
7279

73-
const handleKeyUp = (e) => {
74-
if (e.keyCode === 8 && e.target.value.trim() === '') {
75-
setText(e.target.value);
80+
const handleKeyUp = (e: React.KeyboardEvent<HTMLTextAreaElement>) => {
81+
if (e.keyCode === 8 && e.currentTarget.value.trim() === '') {
82+
setText(e.currentTarget.value);
7683
}
7784

7885
if (e.key === 'Enter' && e.shiftKey) {
@@ -92,12 +99,24 @@ export default function TextChat({ isSearchView = false }) {
9299
isComposing.current = false;
93100
};
94101

95-
const changeHandler = (e) => {
102+
const changeHandler = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
96103
const { value } = e.target;
97104

98105
setText(value);
106+
updateHasText(value);
99107
};
100108

109+
const updateHasText = useCallback(
110+
(text: string) => {
111+
setHasText(!!text.trim() || !!latestMessage?.error);
112+
},
113+
[setHasText, latestMessage],
114+
);
115+
116+
useEffect(() => {
117+
updateHasText(text);
118+
}, [text, latestMessage, updateHasText]);
119+
101120
const getPlaceholderText = () => {
102121
if (isSearchView) {
103122
return 'Click a message title to open its conversation.';
@@ -153,11 +172,11 @@ export default function TextChat({ isSearchView = false }) {
153172
<TextareaAutosize
154173
// set test id for e2e testing
155174
data-testid="text-input"
156-
tabIndex="0"
175+
tabIndex={0}
157176
autoFocus
158177
ref={inputRef}
159178
// style={{maxHeight: '200px', height: '24px', overflowY: 'hidden'}}
160-
rows="1"
179+
rows={1}
161180
value={disabled || isNotAppendable ? '' : text}
162181
onKeyUp={handleKeyUp}
163182
onKeyDown={handleKeyDown}
@@ -174,7 +193,12 @@ export default function TextChat({ isSearchView = false }) {
174193
handleStopGenerating={handleStopGenerating}
175194
disabled={disabled || isNotAppendable}
176195
isSubmitting={isSubmitting}
177-
userProvidesKey={endpointsConfig?.[conversation.endpoint]?.userProvide}
196+
userProvidesKey={
197+
conversation?.endpoint
198+
? endpointsConfig?.[conversation.endpoint]?.userProvide
199+
: undefined
200+
}
201+
hasText={hasText}
178202
/>
179203
</div>
180204
</div>

client/src/components/Messages/MessageHeader.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,8 +89,9 @@ const MessageHeader = ({ isSearchView = false }) => {
8989
<>
9090
<div
9191
className={cn(
92-
'flex min-h-[60px] w-full flex-wrap items-center justify-between gap-3 border-b border-black/10 bg-white text-sm text-gray-500 transition-all hover:bg-gray-50 hover:bg-opacity-30 dark:border-gray-900/50 dark:bg-gray-800 dark:hover:bg-gray-700 dark:hover:bg-opacity-100',
93-
isNotClickable ? '' : 'cursor-pointer ',
92+
'flex min-h-[60px] w-full flex-wrap items-center justify-between gap-3 border-b border-black/10 bg-white text-sm text-gray-500 transition-all hover:bg-gray-50 dark:border-gray-900/50 dark:bg-gray-800 dark:hover:bg-gray-700',
93+
isNotClickable ? '' : 'cursor-pointer',
94+
'sticky top-0 z-10',
9495
)}
9596
onClick={() => (isNotClickable ? null : setSaveAsDialogShow(true))}
9697
>

client/src/components/Nav/Nav.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -221,7 +221,7 @@ export default function Nav({ navVisible, setNavVisible }) {
221221
</div>
222222
</div>
223223
{!navVisible && (
224-
<div className="absolute left-2 top-2 z-10 hidden md:inline-block">
224+
<div className="absolute left-2 top-2 z-20 hidden md:inline-block">
225225
<TooltipTrigger asChild>
226226
<button
227227
type="button"

client/src/components/Nav/NavLinks.tsx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ export default function NavLinks() {
5050
)}
5151
<Menu.Button
5252
className={cn(
53-
'group-ui-open:bg-gray-800 flex w-full items-center gap-2.5 rounded-md px-3 py-3 text-sm transition-colors duration-200 hover:bg-gray-800',
53+
'group-ui-open:bg-gray-800 rounded-sd flex w-full items-center gap-2.5 px-3 py-2 text-sm transition-colors duration-200 hover:bg-gray-800',
5454
open ? 'bg-gray-800' : '',
5555
)}
5656
data-testid="nav-user"
@@ -69,18 +69,24 @@ export default function NavLinks() {
6969
/>
7070
</div>
7171
</div>
72-
<div className="grow overflow-hidden text-ellipsis whitespace-nowrap text-left text-white">
72+
<div
73+
className="grow overflow-hidden text-ellipsis whitespace-nowrap text-left font-bold text-white"
74+
style={{ marginTop: '-4px', marginLeft: '2px' }}
75+
>
7376
{user?.name || localize('com_nav_user')}
7477
</div>
75-
<DotsIcon />
78+
79+
<div style={{ marginBottom: '5px' }}>
80+
<DotsIcon />
81+
</div>
7682
</Menu.Button>
7783

7884
<Transition
7985
as={Fragment}
80-
enter="transition ease-out duration-100 transform"
86+
enter="transition ease-out duration-110 transform"
8187
enterFrom="translate-y-2 opacity-0"
8288
enterTo="translate-y-0 opacity-100"
83-
leave="transition ease-in duration-75 transform"
89+
leave="transition ease-in duration-100 transform"
8490
leaveFrom="translate-y-0 opacity-100"
8591
leaveTo="translate-y-2 opacity-0"
8692
>

0 commit comments

Comments
 (0)