diff --git a/frontend/src/assets/icons/AI.svg b/frontend/src/assets/icons/AI.svg new file mode 100644 index 0000000000..b6d25d059f --- /dev/null +++ b/frontend/src/assets/icons/AI.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/component/ai/AIChat.tsx b/frontend/src/component/ai/AIChat.tsx index 703e9ff4bc..92b4042919 100644 --- a/frontend/src/component/ai/AIChat.tsx +++ b/frontend/src/component/ai/AIChat.tsx @@ -1,6 +1,6 @@ import { mutate } from 'swr'; -import SmartToyIcon from '@mui/icons-material/SmartToy'; -import { IconButton, styled } from '@mui/material'; +import { ReactComponent as AIIcon } from 'assets/icons/AI.svg'; +import { IconButton, styled, useMediaQuery } from '@mui/material'; import { useEffect, useRef, useState } from 'react'; import useToast from 'hooks/useToast'; import { formatUnknownError } from 'utils/formatUnknownError'; @@ -16,6 +16,7 @@ import { AIChatHeader } from './AIChatHeader'; import { Resizable } from 'component/common/Resizable/Resizable'; import { AIChatDisclaimer } from './AIChatDisclaimer'; import { usePlausibleTracker } from 'hooks/usePlausibleTracker'; +import theme from 'themes/theme'; const AI_ERROR_MESSAGE = { role: 'assistant', @@ -26,10 +27,15 @@ type ScrollOptions = ScrollIntoViewOptions & { onlyIfAtEnd?: boolean; }; -const StyledAIIconContainer = styled('div')(({ theme }) => ({ +const StyledAIIconContainer = styled('div', { + shouldForwardProp: (prop) => prop !== 'demoStepsVisible', +})<{ demoStepsVisible: boolean }>(({ theme, demoStepsVisible }) => ({ position: 'fixed', bottom: 20, right: 20, + ...(demoStepsVisible && { + right: 260, + }), zIndex: theme.zIndex.fab, animation: 'fadeInBottom 0.5s', '@keyframes fadeInBottom': { @@ -44,10 +50,15 @@ const StyledAIIconContainer = styled('div')(({ theme }) => ({ }, })); -const StyledAIChatContainer = styled(StyledAIIconContainer)({ +const StyledAIChatContainer = styled(StyledAIIconContainer, { + shouldForwardProp: (prop) => prop !== 'demoStepsVisible', +})<{ demoStepsVisible: boolean }>(({ demoStepsVisible }) => ({ bottom: 10, right: 10, -}); + ...(demoStepsVisible && { + right: 250, + }), +})); const StyledResizable = styled(Resizable)(({ theme }) => ({ boxShadow: theme.boxShadows.popup, @@ -55,13 +66,20 @@ const StyledResizable = styled(Resizable)(({ theme }) => ({ })); const StyledAIIconButton = styled(IconButton)(({ theme }) => ({ - background: theme.palette.primary.light, + background: + theme.mode === 'light' + ? theme.palette.primary.main + : theme.palette.primary.light, color: theme.palette.primary.contrastText, boxShadow: theme.boxShadows.popup, transition: 'background 0.3s', '&:hover': { background: theme.palette.primary.dark, }, + '& > svg': { + width: theme.spacing(3), + height: theme.spacing(3), + }, })); const StyledChat = styled('div')(({ theme }) => ({ @@ -84,6 +102,8 @@ const StyledChatContent = styled('div')(({ theme }) => ({ export const AIChat = () => { const unleashAIEnabled = useUiFlag('unleashAI'); + const demoEnabled = useUiFlag('demo'); + const isSmallScreen = useMediaQuery(theme.breakpoints.down(768)); const { uiConfig: { unleashAIAvailable }, } = useUiConfig(); @@ -169,13 +189,15 @@ export const AIChat = () => { newChat(); }; + const demoStepsVisible = demoEnabled && !isSmallScreen; + if (!unleashAIEnabled || !unleashAIAvailable) { return null; } if (!open) { return ( - + { @@ -187,18 +209,18 @@ export const AIChat = () => { setOpen(true); }} > - + ); } return ( - + scrollToEnd({ onlyIfAtEnd: true })} > diff --git a/frontend/src/component/ai/AIChatHeader.tsx b/frontend/src/component/ai/AIChatHeader.tsx index 4c5ff46702..6087327c03 100644 --- a/frontend/src/component/ai/AIChatHeader.tsx +++ b/frontend/src/component/ai/AIChatHeader.tsx @@ -1,10 +1,13 @@ import { IconButton, styled, Tooltip, Typography } from '@mui/material'; -import SmartToyIcon from '@mui/icons-material/SmartToy'; +import { ReactComponent as AIIcon } from 'assets/icons/AI.svg'; import EditNoteIcon from '@mui/icons-material/EditNote'; import CloseIcon from '@mui/icons-material/Close'; const StyledHeader = styled('div')(({ theme }) => ({ - background: theme.palette.primary.light, + background: + theme.mode === 'light' + ? theme.palette.primary.main + : theme.palette.primary.light, color: theme.palette.primary.contrastText, display: 'flex', alignItems: 'center', @@ -41,7 +44,7 @@ export const AIChatHeader = ({ onNew, onClose }: IAIChatHeaderProps) => { return ( - + Unleash AI diff --git a/frontend/src/component/ai/AIChatMessage.tsx b/frontend/src/component/ai/AIChatMessage.tsx index 868e6fedc1..6680d2c5a0 100644 --- a/frontend/src/component/ai/AIChatMessage.tsx +++ b/frontend/src/component/ai/AIChatMessage.tsx @@ -1,5 +1,5 @@ import { Avatar, styled } from '@mui/material'; -import SmartToyIcon from '@mui/icons-material/SmartToy'; +import { ReactComponent as AIIcon } from 'assets/icons/AI.svg'; import { Markdown } from 'component/common/Markdown/Markdown'; import { useAuthUser } from 'hooks/api/getters/useAuth/useAuthUser'; import type { ChatMessage } from 'hooks/api/actions/useAIApi/useAIApi'; @@ -62,7 +62,10 @@ const StyledUserMessage = styled(StyledAIMessage)(({ theme }) => ({ const StyledAvatar = styled(Avatar)(({ theme }) => ({ width: theme.spacing(4.5), height: theme.spacing(4.5), - backgroundColor: theme.palette.primary.light, + backgroundColor: + theme.mode === 'light' + ? theme.palette.primary.main + : theme.palette.primary.light, color: theme.palette.primary.contrastText, })); @@ -89,7 +92,7 @@ export const AIChatMessage = ({ from, children }: IAIChatMessageProps) => { return ( - + {children} diff --git a/frontend/src/themes/dark-theme.ts b/frontend/src/themes/dark-theme.ts index 45f0db4a05..7dc17ce589 100644 --- a/frontend/src/themes/dark-theme.ts +++ b/frontend/src/themes/dark-theme.ts @@ -12,6 +12,7 @@ const actionColors = { }; const theme = { + mode: 'dark', breakpoints: { values: { xs: 0, @@ -309,7 +310,7 @@ const theme = { series: colors.chartSeries, }, }, -}; +} as const; export default createTheme({ ...theme, diff --git a/frontend/src/themes/theme.ts b/frontend/src/themes/theme.ts index c1ec1b52f7..98991269a5 100644 --- a/frontend/src/themes/theme.ts +++ b/frontend/src/themes/theme.ts @@ -4,6 +4,7 @@ import { alpha } from '@mui/material'; import { focusable } from 'themes/themeStyles'; export const theme = { + mode: 'light', breakpoints: { values: { xs: 0, @@ -294,7 +295,7 @@ export const theme = { series: colors.chartSeries, }, }, -}; +} as const; export default createTheme({ ...theme, diff --git a/frontend/src/themes/themeTypes.ts b/frontend/src/themes/themeTypes.ts index 79e59a06a6..7c3e053e68 100644 --- a/frontend/src/themes/themeTypes.ts +++ b/frontend/src/themes/themeTypes.ts @@ -3,6 +3,7 @@ import { FormHelperTextOwnProps } from '@mui/material/FormHelperText'; declare module '@mui/material/styles' { interface CustomTheme { + mode: 'light' | 'dark'; /** * @deprecated */