🎨(ui) retour ui sources files (#37)
* ✨(ui) fix retour global ui correction retour ui * 🎨(ui) retour ui sources files fix retour ui source files * 🐛(fix) fix front build prettier - fix build front
This commit is contained in:
+2
-1
@@ -8,10 +8,11 @@ and this project adheres to
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
- ✨(ui) fix retour global ui
|
||||
- 🎨(ui) retour ui sources files
|
||||
|
||||
### Changed
|
||||
|
||||
- ✨(ui) fix retour global ui
|
||||
- 🐛(fix) broken staging css
|
||||
- 🎨(alpha) adjustment for alpha version
|
||||
- ✨(ui) delete flex message
|
||||
|
||||
@@ -38,7 +38,9 @@ export const AttachmentList = ({
|
||||
onRemove(idx);
|
||||
}
|
||||
};
|
||||
|
||||
if (!name) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<Box
|
||||
key={(name || 'attachment') + idx}
|
||||
@@ -49,6 +51,7 @@ export const AttachmentList = ({
|
||||
$background="var(--c--theme--colors--greyscale-050)"
|
||||
$minWidth="200px"
|
||||
$direction="row"
|
||||
$gap="xs"
|
||||
$align="center"
|
||||
$padding="xs"
|
||||
$css={`
|
||||
@@ -80,7 +83,7 @@ export const AttachmentList = ({
|
||||
</Text>
|
||||
</Box>
|
||||
<Text
|
||||
$size="sm"
|
||||
$size="xs"
|
||||
$color="var(--c--theme--colors--greyscale-850)"
|
||||
$css={`
|
||||
overflow: hidden;
|
||||
|
||||
@@ -66,6 +66,28 @@ export const Chat = ({
|
||||
setChatContainerRef(chatContainerRef);
|
||||
}, []);
|
||||
|
||||
// Détecter si l'utilisateur scroll vers le haut
|
||||
useEffect(() => {
|
||||
const container = chatContainerRef.current;
|
||||
if (!container) {
|
||||
return;
|
||||
}
|
||||
|
||||
const handleScroll = () => {
|
||||
const { scrollTop, scrollHeight, clientHeight } = container;
|
||||
const isAtBottom = scrollHeight - scrollTop - clientHeight < 50;
|
||||
|
||||
if (isAtBottom) {
|
||||
setUserScrolledUp(false);
|
||||
} else {
|
||||
setUserScrolledUp(true);
|
||||
}
|
||||
};
|
||||
|
||||
container.addEventListener('scroll', handleScroll);
|
||||
return () => container.removeEventListener('scroll', handleScroll);
|
||||
}, []);
|
||||
|
||||
const [initialConversationMessages, setInitialConversationMessages] =
|
||||
useState<Message[] | undefined>(undefined);
|
||||
const [pendingFirstMessage, setPendingFirstMessage] = useState<{
|
||||
@@ -78,6 +100,7 @@ export const Chat = ({
|
||||
const [streamingMessageHeight, setStreamingMessageHeight] = useState<
|
||||
number | null
|
||||
>(null);
|
||||
const [userScrolledUp, setUserScrolledUp] = useState(false);
|
||||
|
||||
const { mutate: createChatConversation } = useCreateChatConversation();
|
||||
|
||||
@@ -129,7 +152,7 @@ export const Chat = ({
|
||||
const stopGeneration = async () => {
|
||||
stopChat();
|
||||
|
||||
const response = await fetchAPI(`chats/${conversationId}/stop-steaming/`, {
|
||||
const response = await fetchAPI(`chats/${conversationId}/stop-streaming/`, {
|
||||
method: 'POST',
|
||||
});
|
||||
|
||||
@@ -230,7 +253,8 @@ export const Chat = ({
|
||||
|
||||
if (
|
||||
hasInitialized &&
|
||||
(status === 'streaming' || status === 'submitted')
|
||||
(status === 'streaming' || status === 'submitted') &&
|
||||
!userScrolledUp
|
||||
) {
|
||||
const lastUserMessage = userMessages[userMessages.length - 1];
|
||||
if (lastUserMessage) {
|
||||
@@ -251,7 +275,13 @@ export const Chat = ({
|
||||
}
|
||||
}
|
||||
}
|
||||
}, [messages, status, hasInitialized, calculateStreamingHeight]);
|
||||
}, [
|
||||
messages,
|
||||
status,
|
||||
hasInitialized,
|
||||
calculateStreamingHeight,
|
||||
userScrolledUp,
|
||||
]);
|
||||
|
||||
// Synchronize conversationId state with prop when it changes (e.g., after navigation)
|
||||
useEffect(() => {
|
||||
@@ -580,6 +610,7 @@ export const Chat = ({
|
||||
$theme="greyscale"
|
||||
$variation="550"
|
||||
$size="16px"
|
||||
className="action-chat-button-icon"
|
||||
/>
|
||||
{!isMobile && (
|
||||
<Text $theme="greyscale" $variation="550">
|
||||
@@ -589,41 +620,48 @@ export const Chat = ({
|
||||
</Box>
|
||||
{message.parts?.some(
|
||||
(part) => part.type === 'source',
|
||||
) && (
|
||||
<Box
|
||||
$direction="row"
|
||||
$align="center"
|
||||
$gap="4px"
|
||||
className="c__button--neutral action-chat-button"
|
||||
onClick={() => openSources(message.id)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
openSources(message.id);
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
<Icon
|
||||
iconName="book"
|
||||
$theme="greyscale"
|
||||
$variation="550"
|
||||
$size="16px"
|
||||
/>
|
||||
{!isMobile && (
|
||||
<Text
|
||||
$theme="greyscale"
|
||||
$variation="550"
|
||||
$weight="500"
|
||||
) &&
|
||||
(() => {
|
||||
const sourceCount =
|
||||
message.parts?.filter(
|
||||
(part) => part.type === 'source',
|
||||
).length || 0;
|
||||
return (
|
||||
<Box
|
||||
$direction="row"
|
||||
$align="center"
|
||||
$gap="4px"
|
||||
className={`c__button--neutral action-chat-button ${isSourceOpen ? 'action-chat-button--open' : ''}`}
|
||||
onClick={() => openSources(message.id)}
|
||||
onKeyDown={(e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
openSources(message.id);
|
||||
}
|
||||
}}
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
>
|
||||
{!isSourceOpen
|
||||
? t('Show sources')
|
||||
: t('Hide sources')}
|
||||
</Text>
|
||||
)}
|
||||
</Box>
|
||||
)}
|
||||
<Icon
|
||||
iconName="book"
|
||||
$theme="greyscale"
|
||||
$variation="550"
|
||||
$size="16px"
|
||||
className="action-chat-button-icon"
|
||||
/>
|
||||
<Text
|
||||
$theme="greyscale"
|
||||
$variation="550"
|
||||
$weight="500"
|
||||
$size="12px"
|
||||
>
|
||||
{t('Show') +
|
||||
` ${sourceCount} ` +
|
||||
t('sources')}
|
||||
</Text>
|
||||
</Box>
|
||||
);
|
||||
})()}
|
||||
</Box>
|
||||
)}
|
||||
{message.parts && isSourceOpen === message.id && (
|
||||
|
||||
@@ -8,6 +8,9 @@ const styles: Record<string, React.CSSProperties> = {
|
||||
color: '#222631',
|
||||
fontWeight: '500',
|
||||
whiteSpace: 'nowrap',
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
display: 'block',
|
||||
},
|
||||
};
|
||||
|
||||
@@ -124,32 +127,44 @@ export const SourceItem: React.FC<SourceItemProps> = ({ url }) => {
|
||||
|
||||
return (
|
||||
<Box $direction="row" $gap="4px" $align="center">
|
||||
{renderFavicon()}
|
||||
<Box $direction="row" $gap="4px" $align="center" $css="font-size: 14px;">
|
||||
<Box
|
||||
$direction="row"
|
||||
$align="center"
|
||||
$css="font-size: 14px;"
|
||||
$width="100%"
|
||||
>
|
||||
{url.startsWith('http') ? (
|
||||
<StyledLink
|
||||
href={url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
$css={`
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.4rem;
|
||||
border-radius: 4px;
|
||||
padding: 4px;
|
||||
width: 100%;
|
||||
text-decoration: none;
|
||||
background-color: transparent;
|
||||
transition: background-color 0.3s;
|
||||
color: var(--c--theme--colors--greyscale-500);
|
||||
&:hover {
|
||||
color: var(--c--theme--colors--greyscale-700);
|
||||
background-color: #EEF1F4;
|
||||
}
|
||||
`}
|
||||
>
|
||||
{renderFavicon()}
|
||||
|
||||
{new URL(url).hostname}
|
||||
|
||||
<Box
|
||||
$direction="row"
|
||||
$padding={{ left: '4px' }}
|
||||
$padding={{ right: '4px' }}
|
||||
$align="center"
|
||||
style={styles.title}
|
||||
>
|
||||
{title && title.length > 100
|
||||
? `${title.substring(0, 50)}...${title.substring(title.length - 20)}`
|
||||
: title}
|
||||
{title}
|
||||
</Box>
|
||||
</StyledLink>
|
||||
) : (
|
||||
|
||||
@@ -19,7 +19,7 @@ export const SourceItemList: React.FC<SourceItemListProps> = ({ parts }) => {
|
||||
$padding={{ all: 'sm' }}
|
||||
$gap="4px"
|
||||
$css={`
|
||||
border: 1px solid var(--c--theme--colors--greyscale-200);
|
||||
border: 1px solid var(--c--theme--colors--greyscale-100);
|
||||
border-radius: 8px;
|
||||
margin-top: 0.5rem;
|
||||
overflow: hidden;
|
||||
|
||||
@@ -60,7 +60,8 @@ nextjs-portal {
|
||||
}
|
||||
|
||||
.c__button--bordered,
|
||||
.c__button--bordered:hover {
|
||||
.c__button--bordered:hover,
|
||||
.c__button--bordered:focus {
|
||||
border: 1px solid var(--c--theme--colors--greyscale-200) !important;
|
||||
background-color: #fff !important;
|
||||
}
|
||||
@@ -80,7 +81,8 @@ nextjs-portal {
|
||||
font-weight: 500 !important;
|
||||
cursor: pointer !important;
|
||||
background-color: inherit !important;
|
||||
z-index: 100 !important;
|
||||
border: none !important;
|
||||
z-index: 100;
|
||||
font-size: 12px !important;
|
||||
padding: 4px !important;
|
||||
padding-right: 9px !important;
|
||||
@@ -96,7 +98,7 @@ nextjs-portal {
|
||||
padding: 9px !important;
|
||||
}
|
||||
|
||||
.c__button--neutral.action-chat-button span,
|
||||
.c__button--neutral.action-chat-button .action-chat-button-icon,
|
||||
.c__button--neutral.research-web-button .c__button__icon span,
|
||||
.c__button--neutral.attach-file-button .c__button__icon span {
|
||||
@media (width <= 768px) {
|
||||
@@ -104,8 +106,15 @@ nextjs-portal {
|
||||
}
|
||||
}
|
||||
|
||||
.c__button--neutral:hover {
|
||||
.c__button--neutral:hover,
|
||||
.c__button--neutral:active,
|
||||
.action-chat-button--open {
|
||||
background-color: #f2f5f4 !important;
|
||||
border: none !important;
|
||||
}
|
||||
|
||||
.c__button--neutral:active {
|
||||
background-color: inherit !important;
|
||||
}
|
||||
|
||||
ul a {
|
||||
@@ -139,6 +148,7 @@ ul a:hover {
|
||||
.c__button--info:hover,
|
||||
.c__button--info:active,
|
||||
.c__button--info:focus {
|
||||
outline: none !important;
|
||||
background-color: #b7d7ff !important;
|
||||
color: #265eaa !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user