optimize mobile experience
This commit is contained in:
parent
44145f11db
commit
a9523f036b
|
@ -144,8 +144,10 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-item:hover {
|
@media only screen and (min-width: 600px) {
|
||||||
background-color: var(--hover-color);
|
.chat-item:hover {
|
||||||
|
background-color: var(--hover-color);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.chat-item-selected {
|
.chat-item-selected {
|
||||||
|
@ -170,6 +172,13 @@
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@media only screen and (max-width: 600px) {
|
||||||
|
.chat-item-delete {
|
||||||
|
right: 10px;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.chat-item:hover > .chat-item-delete {
|
.chat-item:hover > .chat-item-delete {
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
right: 10px;
|
right: 10px;
|
||||||
|
@ -422,6 +431,7 @@
|
||||||
@media only screen and (max-width: 600px) {
|
@media only screen and (max-width: 600px) {
|
||||||
.chat-input {
|
.chat-input {
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
|
padding: 10px 5px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,7 +108,7 @@ export function ChatList() {
|
||||||
state.currentSessionIndex,
|
state.currentSessionIndex,
|
||||||
state.selectSession,
|
state.selectSession,
|
||||||
state.removeSession,
|
state.removeSession,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -202,7 +202,7 @@ export function Chat(props: {
|
||||||
setPromptHints(promptStore.search(text));
|
setPromptHints(promptStore.search(text));
|
||||||
},
|
},
|
||||||
100,
|
100,
|
||||||
{ leading: true, trailing: true }
|
{ leading: true, trailing: true },
|
||||||
);
|
);
|
||||||
|
|
||||||
const onPromptSelect = (prompt: Prompt) => {
|
const onPromptSelect = (prompt: Prompt) => {
|
||||||
|
@ -216,7 +216,7 @@ export function Chat(props: {
|
||||||
if (!dom) return;
|
if (!dom) return;
|
||||||
const paddingBottomNum: number = parseInt(
|
const paddingBottomNum: number = parseInt(
|
||||||
window.getComputedStyle(dom).paddingBottom,
|
window.getComputedStyle(dom).paddingBottom,
|
||||||
10
|
10,
|
||||||
);
|
);
|
||||||
dom.scrollTop = dom.scrollHeight - dom.offsetHeight + paddingBottomNum;
|
dom.scrollTop = dom.scrollHeight - dom.offsetHeight + paddingBottomNum;
|
||||||
};
|
};
|
||||||
|
@ -246,7 +246,7 @@ export function Chat(props: {
|
||||||
chatStore.onUserInput(userInput).then(() => setIsLoading(false));
|
chatStore.onUserInput(userInput).then(() => setIsLoading(false));
|
||||||
setUserInput("");
|
setUserInput("");
|
||||||
setPromptHints([]);
|
setPromptHints([]);
|
||||||
inputRef.current?.focus();
|
if (!isMobileScreen()) inputRef.current?.focus();
|
||||||
};
|
};
|
||||||
|
|
||||||
// stop response
|
// stop response
|
||||||
|
@ -290,6 +290,7 @@ export function Chat(props: {
|
||||||
|
|
||||||
// for auto-scroll
|
// for auto-scroll
|
||||||
const latestMessageRef = useRef<HTMLDivElement>(null);
|
const latestMessageRef = useRef<HTMLDivElement>(null);
|
||||||
|
const dialogBoxRef = useRef<HTMLDivElement>(null);
|
||||||
const [autoScroll, setAutoScroll] = useState(true);
|
const [autoScroll, setAutoScroll] = useState(true);
|
||||||
|
|
||||||
// preview messages
|
// preview messages
|
||||||
|
@ -304,7 +305,7 @@ export function Chat(props: {
|
||||||
preview: true,
|
preview: true,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []
|
: [],
|
||||||
)
|
)
|
||||||
.concat(
|
.concat(
|
||||||
userInput.length > 0
|
userInput.length > 0
|
||||||
|
@ -316,7 +317,7 @@ export function Chat(props: {
|
||||||
preview: true,
|
preview: true,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []
|
: [],
|
||||||
);
|
);
|
||||||
|
|
||||||
// auto scroll
|
// auto scroll
|
||||||
|
@ -324,6 +325,7 @@ export function Chat(props: {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const dom = latestMessageRef.current;
|
const dom = latestMessageRef.current;
|
||||||
const inputDom = inputRef.current;
|
const inputDom = inputRef.current;
|
||||||
|
const dialogBox = dialogBoxRef.current!;
|
||||||
|
|
||||||
// only scroll when input overlaped message body
|
// only scroll when input overlaped message body
|
||||||
let shouldScroll = true;
|
let shouldScroll = true;
|
||||||
|
@ -334,8 +336,9 @@ export function Chat(props: {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dom && autoScroll && shouldScroll) {
|
if (dom && autoScroll && shouldScroll) {
|
||||||
dom.scrollIntoView({
|
console.log(dialogBox.scrollHeight, dialogBox.clientHeight);
|
||||||
block: "end",
|
dialogBox.scrollTo({
|
||||||
|
top: dialogBox.scrollHeight - dialogBox.clientHeight,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, 500);
|
}, 500);
|
||||||
|
@ -354,7 +357,7 @@ export function Chat(props: {
|
||||||
const newTopic = prompt(Locale.Chat.Rename, session.topic);
|
const newTopic = prompt(Locale.Chat.Rename, session.topic);
|
||||||
if (newTopic && newTopic !== session.topic) {
|
if (newTopic && newTopic !== session.topic) {
|
||||||
chatStore.updateCurrentSession(
|
chatStore.updateCurrentSession(
|
||||||
(session) => (session.topic = newTopic!)
|
(session) => (session.topic = newTopic!),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
@ -397,7 +400,7 @@ export function Chat(props: {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles["chat-body"]}>
|
<div className={styles["chat-body"]} ref={dialogBoxRef}>
|
||||||
{messages.map((message, i) => {
|
{messages.map((message, i) => {
|
||||||
const isUser = message.role === "user";
|
const isUser = message.role === "user";
|
||||||
|
|
||||||
|
@ -445,8 +448,7 @@ export function Chat(props: {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{(message.preview || message.content.length === 0) &&
|
{message.preview || message.content.length === 0 ? (
|
||||||
!isUser ? (
|
|
||||||
<LoadingIcon />
|
<LoadingIcon />
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
|
@ -484,21 +486,21 @@ export function Chat(props: {
|
||||||
<textarea
|
<textarea
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
className={styles["chat-input"]}
|
className={styles["chat-input"]}
|
||||||
placeholder={Locale.Chat.Input(submitKey)}
|
placeholder={isMobileScreen() ? "" : Locale.Chat.Input(submitKey)}
|
||||||
rows={4}
|
rows={isMobileScreen() ? 2 : 4}
|
||||||
onInput={(e) => onInput(e.currentTarget.value)}
|
onInput={(e) => onInput(e.currentTarget.value)}
|
||||||
value={userInput}
|
value={userInput}
|
||||||
onKeyDown={(e) => onInputKeyDown(e as any)}
|
onKeyDown={(e) => onInputKeyDown(e as any)}
|
||||||
onFocus={() => setAutoScroll(true)}
|
onFocus={() => setAutoScroll(true)}
|
||||||
onBlur={() => {
|
onBlur={() => {
|
||||||
setAutoScroll(false);
|
if (!isMobileScreen()) setAutoScroll(false);
|
||||||
setTimeout(() => setPromptHints([]), 500);
|
setTimeout(() => setPromptHints([]), 500);
|
||||||
}}
|
}}
|
||||||
autoFocus={!props?.sideBarShowing}
|
autoFocus={!props?.sideBarShowing}
|
||||||
/>
|
/>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={<SendWhiteIcon />}
|
icon={<SendWhiteIcon />}
|
||||||
text={Locale.Chat.Send}
|
text={isMobileScreen() ? "" : Locale.Chat.Send}
|
||||||
className={styles["chat-input-send"] + " no-dark"}
|
className={styles["chat-input-send"] + " no-dark"}
|
||||||
onClick={onUserSubmit}
|
onClick={onUserSubmit}
|
||||||
/>
|
/>
|
||||||
|
@ -603,7 +605,7 @@ export function Home() {
|
||||||
state.newSession,
|
state.newSession,
|
||||||
state.currentSessionIndex,
|
state.currentSessionIndex,
|
||||||
state.removeSession,
|
state.removeSession,
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
const loading = !useHasHydrated();
|
const loading = !useHasHydrated();
|
||||||
const [showSideBar, setShowSideBar] = useState(true);
|
const [showSideBar, setShowSideBar] = useState(true);
|
||||||
|
@ -651,16 +653,6 @@ export function Home() {
|
||||||
|
|
||||||
<div className={styles["sidebar-tail"]}>
|
<div className={styles["sidebar-tail"]}>
|
||||||
<div className={styles["sidebar-actions"]}>
|
<div className={styles["sidebar-actions"]}>
|
||||||
<div className={styles["sidebar-action"] + " " + styles.mobile}>
|
|
||||||
<IconButton
|
|
||||||
icon={<CloseIcon />}
|
|
||||||
onClick={() => {
|
|
||||||
if (confirm(Locale.Home.DeleteChat)) {
|
|
||||||
removeSession(currentIndex);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className={styles["sidebar-action"]}>
|
<div className={styles["sidebar-action"]}>
|
||||||
<IconButton
|
<IconButton
|
||||||
icon={<SettingsIcon />}
|
icon={<SettingsIcon />}
|
||||||
|
|
Loading…
Reference in New Issue