u
This commit is contained in:
@@ -2,9 +2,14 @@ import React, { useState } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import Button from '@mui/material/Button';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import TextInput from '../TextInput';
|
||||
import HelpOutlineRoundedIcon from '@mui/icons-material/HelpOutlineRounded';
|
||||
import SendRoundedIcon from '@mui/icons-material/SendRounded';
|
||||
import {
|
||||
ASK_PROMPT_BG_PAIR,
|
||||
ASK_PROMPT_BORDER_PAIR,
|
||||
byMode,
|
||||
} from '../../colors';
|
||||
|
||||
export default function AskUserPrompt({ askData, onAnswer, disabled = false }) {
|
||||
const { toolCallId, question, options = [] } = askData;
|
||||
@@ -30,8 +35,8 @@ export default function AskUserPrompt({ askData, onAnswer, disabled = false }) {
|
||||
my: 1,
|
||||
p: 2,
|
||||
borderRadius: 3,
|
||||
bgcolor: theme.palette.mode === 'dark' ? 'rgba(59, 91, 219, 0.12)' : '#eef2ff',
|
||||
border: `1px solid ${theme.palette.mode === 'dark' ? 'rgba(59, 91, 219, 0.3)' : '#c7d2fe'}`,
|
||||
bgcolor: byMode(theme, ASK_PROMPT_BG_PAIR),
|
||||
border: `1px solid ${byMode(theme, ASK_PROMPT_BORDER_PAIR)}`,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
gap: 1.5,
|
||||
@@ -97,28 +102,13 @@ export default function AskUserPrompt({ askData, onAnswer, disabled = false }) {
|
||||
onSubmit={handleCustomSubmit}
|
||||
sx={{ display: 'flex', gap: 1, mt: 0.5, alignItems: 'center' }}
|
||||
>
|
||||
<TextField
|
||||
size="small"
|
||||
<TextInput
|
||||
fullWidth
|
||||
autoFocus
|
||||
placeholder="Antwort eingeben…"
|
||||
value={customAnswer}
|
||||
onChange={(e) => setCustomAnswer(e.target.value)}
|
||||
disabled={disabled}
|
||||
slotProps={{
|
||||
htmlInput: {
|
||||
spellCheck: false,
|
||||
autoCorrect: 'off',
|
||||
autoCapitalize: 'off',
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
'& .MuiOutlinedInput-root': {
|
||||
borderRadius: 2,
|
||||
bgcolor: 'background.paper',
|
||||
fontSize: '0.82rem',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
|
||||
@@ -4,7 +4,7 @@ import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import IconButton from '@mui/material/IconButton';
|
||||
import Button from '@mui/material/Button';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import TextInput from '../TextInput';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import Select from '@mui/material/Select';
|
||||
import FormControl from '@mui/material/FormControl';
|
||||
@@ -20,6 +20,10 @@ import chatAutomat, { selectPendingAskUser } from '../../automats/chatAutomat';
|
||||
import userSettingsAutomat from '../../automats/userSettingsAutomat';
|
||||
import ChatFlowList from './ChatFlowList';
|
||||
import AskUserPrompt from './AskUserPrompt';
|
||||
import {
|
||||
BLUE_GLOW,
|
||||
SHADOW_DRAWER,
|
||||
} from '../../colors';
|
||||
|
||||
const DEFAULT_DRAWER_WIDTH = 460;
|
||||
const MIN_DRAWER_WIDTH = 320;
|
||||
@@ -489,11 +493,10 @@ export default class ChatDrawer extends PureComponent {
|
||||
)}
|
||||
|
||||
<Box sx={{ display: 'flex', alignItems: 'flex-end', gap: 1 }}>
|
||||
<TextField
|
||||
<TextInput
|
||||
inputRef={this.inputRef}
|
||||
multiline
|
||||
maxRows={4}
|
||||
size="small"
|
||||
fullWidth
|
||||
value={inputText}
|
||||
onChange={(e) => this.setState({ inputText: e.target.value })}
|
||||
@@ -502,22 +505,8 @@ export default class ChatDrawer extends PureComponent {
|
||||
placeholder={
|
||||
pendingAsk
|
||||
? 'Bitte Frage oben beantworten…'
|
||||
: 'Nachricht eingeben… (Enter)'
|
||||
: 'Nachricht eingeben…'
|
||||
}
|
||||
slotProps={{
|
||||
htmlInput: {
|
||||
spellCheck: false,
|
||||
autoCorrect: 'off',
|
||||
autoCapitalize: 'off',
|
||||
},
|
||||
}}
|
||||
sx={{
|
||||
'& .MuiOutlinedInput-root': {
|
||||
borderRadius: 2.5,
|
||||
bgcolor: 'background.default',
|
||||
fontSize: '0.875rem',
|
||||
},
|
||||
}}
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
@@ -576,7 +565,7 @@ export default class ChatDrawer extends PureComponent {
|
||||
maxWidth: '100vw',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
boxShadow: '-8px 0 32px rgba(0, 0, 0, 0.12)',
|
||||
boxShadow: SHADOW_DRAWER,
|
||||
position: 'fixed',
|
||||
overflow: 'visible',
|
||||
transition: isResizing ? 'none !important' : undefined,
|
||||
@@ -592,7 +581,7 @@ export default class ChatDrawer extends PureComponent {
|
||||
maxWidth: '100vw',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
boxShadow: '-8px 0 32px rgba(0, 0, 0, 0.12)',
|
||||
boxShadow: SHADOW_DRAWER,
|
||||
position: 'fixed',
|
||||
overflow: 'visible',
|
||||
transition: isResizing ? 'none !important' : undefined,
|
||||
@@ -625,7 +614,7 @@ export default class ChatDrawer extends PureComponent {
|
||||
height: 56,
|
||||
width: 4,
|
||||
opacity: 1,
|
||||
boxShadow: '0 0 10px rgba(59, 91, 219, 0.6)',
|
||||
boxShadow: `0 0 10px ${BLUE_GLOW}`,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -638,7 +627,7 @@ export default class ChatDrawer extends PureComponent {
|
||||
bgcolor: isResizing ? 'primary.main' : 'divider',
|
||||
opacity: isResizing ? 1 : 0.6,
|
||||
transition: 'background-color 0.15s, height 0.15s, width 0.15s, opacity 0.15s, box-shadow 0.15s',
|
||||
boxShadow: isResizing ? '0 0 10px rgba(59, 91, 219, 0.6)' : 'none',
|
||||
boxShadow: isResizing ? `0 0 10px ${BLUE_GLOW}` : 'none',
|
||||
}}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
@@ -10,6 +10,15 @@ import AutoAwesomeRoundedIcon from '@mui/icons-material/AutoAwesomeRounded';
|
||||
import HelpOutlineRoundedIcon from '@mui/icons-material/HelpOutlineRounded';
|
||||
|
||||
import chatAutomat, { selectPendingAskUser, selectHasPendingAsk } from '../../automats/chatAutomat';
|
||||
import {
|
||||
CHAT_BUSY,
|
||||
CHAT_FAB_BUSY,
|
||||
CHAT_FAB_PENDING, CHAT_FAB_SHADOW_BUSY,
|
||||
CHAT_FAB_SHADOW_IDLE,
|
||||
CHAT_FAB_SHADOW_PENDING, RED,
|
||||
RED_GLOW,
|
||||
WHITE,
|
||||
} from '../../colors';
|
||||
|
||||
export default class ChatFab extends PureComponent {
|
||||
constructor(props) {
|
||||
@@ -86,7 +95,7 @@ export default class ChatFab extends PureComponent {
|
||||
right: -8,
|
||||
bottom: -8,
|
||||
borderRadius: '50%',
|
||||
bgcolor: '#f59e0b',
|
||||
bgcolor: CHAT_BUSY,
|
||||
opacity: 0.5,
|
||||
animation: 'fabAskPulse 1.5s cubic-bezier(0.4, 0, 0.6, 1) infinite',
|
||||
'@keyframes fabAskPulse': {
|
||||
@@ -129,7 +138,7 @@ export default class ChatFab extends PureComponent {
|
||||
position: 'absolute',
|
||||
top: -6,
|
||||
left: -6,
|
||||
color: '#f59e0b',
|
||||
color: CHAT_BUSY,
|
||||
pointerEvents: 'none',
|
||||
}}
|
||||
/>
|
||||
@@ -146,14 +155,14 @@ export default class ChatFab extends PureComponent {
|
||||
sx={{
|
||||
'& .MuiBadge-badge': hasPendingAsk
|
||||
? {
|
||||
bgcolor: '#ef4444',
|
||||
color: '#ffffff',
|
||||
bgcolor: RED,
|
||||
color: WHITE,
|
||||
fontWeight: 900,
|
||||
fontSize: '0.85rem',
|
||||
minWidth: 22,
|
||||
height: 22,
|
||||
borderRadius: '50%',
|
||||
boxShadow: '0 2px 10px rgba(239, 68, 68, 0.6)',
|
||||
boxShadow: `0 2px 10px ${RED_GLOW}`,
|
||||
animation: 'badgePop 1.5s ease infinite',
|
||||
'@keyframes badgePop': {
|
||||
'0%, 100%': { transform: 'scale(1)' },
|
||||
@@ -171,10 +180,10 @@ export default class ChatFab extends PureComponent {
|
||||
width: 54,
|
||||
height: 54,
|
||||
boxShadow: hasPendingAsk
|
||||
? '0 8px 24px rgba(245, 158, 11, 0.45)'
|
||||
? CHAT_FAB_SHADOW_PENDING
|
||||
: isBusy
|
||||
? '0 8px 24px rgba(245, 158, 11, 0.35)'
|
||||
: '0 8px 24px rgba(59, 91, 219, 0.35)',
|
||||
? CHAT_FAB_SHADOW_BUSY
|
||||
: CHAT_FAB_SHADOW_IDLE,
|
||||
transition: 'transform 0.2s cubic-bezier(0.34, 1.56, 0.64, 1), background 0.2s',
|
||||
'&:hover': {
|
||||
transform: 'scale(1.06)',
|
||||
@@ -183,9 +192,9 @@ export default class ChatFab extends PureComponent {
|
||||
transform: 'scale(0.96)',
|
||||
},
|
||||
background: hasPendingAsk
|
||||
? 'linear-gradient(135deg, #f59e0b 0%, #ea580c 100%)'
|
||||
? CHAT_FAB_PENDING
|
||||
: isBusy
|
||||
? 'linear-gradient(135deg, #f59e0b 0%, #d97706 100%)'
|
||||
? CHAT_FAB_BUSY
|
||||
: `linear-gradient(135deg, ${theme.palette.primary.main} 0%, ${theme.palette.primary.dark} 100%)`,
|
||||
})}
|
||||
>
|
||||
|
||||
@@ -2,6 +2,13 @@ import React, { PureComponent, createRef } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
import HealingMarkdown from './HealingMarkdown';
|
||||
import {
|
||||
SHADOW_BUBBLE_ASSISTANT,
|
||||
SHADOW_BUBBLE_USER,
|
||||
SURFACE_RAISED,
|
||||
SURFACE_SUBTLE_PAIR,
|
||||
byMode,
|
||||
} from '../../colors';
|
||||
|
||||
function formatMessageTime(isoString) {
|
||||
if (!isoString) return '';
|
||||
@@ -109,7 +116,7 @@ function MessageRow({ msg, showTime = true }) {
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-start', py: 0.35, px: 2 }}>
|
||||
<Box
|
||||
sx={(theme) => ({
|
||||
bgcolor: theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.04)' : 'rgba(0,0,0,0.03)',
|
||||
bgcolor: byMode(theme, SURFACE_SUBTLE_PAIR),
|
||||
color: 'text.secondary',
|
||||
px: 1.25,
|
||||
py: 0.35,
|
||||
@@ -193,7 +200,7 @@ function MessageRow({ msg, showTime = true }) {
|
||||
<Box sx={{ display: 'flex', justifyContent: 'flex-start', py: 0.35, px: 2 }}>
|
||||
<Box
|
||||
sx={(theme) => ({
|
||||
bgcolor: theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.04)' : 'rgba(0,0,0,0.03)',
|
||||
bgcolor: byMode(theme, SURFACE_SUBTLE_PAIR),
|
||||
color: 'text.secondary',
|
||||
px: 1.25,
|
||||
py: 0.35,
|
||||
@@ -272,13 +279,13 @@ function MessageRow({ msg, showTime = true }) {
|
||||
? theme.palette.primary.main
|
||||
: theme.palette.mode === 'dark'
|
||||
? 'background.paper'
|
||||
: '#f4f6f8',
|
||||
: SURFACE_RAISED,
|
||||
color: isUser
|
||||
? theme.palette.primary.contrastText
|
||||
: theme.palette.text.primary,
|
||||
boxShadow: isUser
|
||||
? '0 2px 8px rgba(59, 91, 219, 0.25)'
|
||||
: '0 1px 4px rgba(0, 0, 0, 0.05)',
|
||||
? SHADOW_BUBBLE_USER
|
||||
: SHADOW_BUBBLE_ASSISTANT,
|
||||
border: isUser ? 'none' : `1px solid ${theme.palette.divider}`,
|
||||
wordBreak: 'break-word',
|
||||
whiteSpace: isUser ? 'pre-wrap' : 'normal',
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
import React, { memo, useState } from 'react';
|
||||
import Box from '@mui/material/Box';
|
||||
import {
|
||||
CODE_BLOCK_PAIR,
|
||||
CODE_INLINE_PAIR,
|
||||
SURFACE_SUBTLE_PAIR,
|
||||
TABLE_HEADER_PAIR,
|
||||
byMode,
|
||||
} from '../../colors';
|
||||
|
||||
/**
|
||||
* Healing markdown renderer.
|
||||
@@ -336,7 +343,7 @@ const rootSx = (theme) => ({
|
||||
fontSize: '0.82em',
|
||||
px: 0.5,
|
||||
borderRadius: 0.75,
|
||||
bgcolor: theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.06)',
|
||||
bbox: byMode(theme, CODE_INLINE_PAIR),
|
||||
},
|
||||
'& pre': {
|
||||
m: 0,
|
||||
@@ -344,7 +351,7 @@ const rootSx = (theme) => ({
|
||||
p: 1.25,
|
||||
borderRadius: 1.5,
|
||||
overflowX: 'auto',
|
||||
bgcolor: theme.palette.mode === 'dark' ? 'rgba(0,0,0,0.35)' : 'rgba(0,0,0,0.06)',
|
||||
bgcolor: byMode(theme, CODE_BLOCK_PAIR),
|
||||
},
|
||||
'& pre code': { p: 0, bgcolor: 'transparent', whiteSpace: 'pre' },
|
||||
'& hr': { border: 0, borderTop: `1px solid ${theme.palette.divider}`, my: 1.5 },
|
||||
@@ -357,7 +364,7 @@ const rootSx = (theme) => ({
|
||||
objectFit: 'contain',
|
||||
borderRadius: 1.5,
|
||||
border: `1px solid ${theme.palette.divider}`,
|
||||
bgcolor: theme.palette.mode === 'dark' ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.03)',
|
||||
bbox: byMode(theme, SURFACE_SUBTLE_PAIR),
|
||||
},
|
||||
'& .md-image-fallback': {
|
||||
display: 'inline-block',
|
||||
@@ -388,7 +395,7 @@ const rootSx = (theme) => ({
|
||||
'&:last-child': { borderRight: 'none' },
|
||||
},
|
||||
'& th': {
|
||||
bgcolor: theme.palette.mode === 'dark' ? 'rgba(255, 255, 255, 0.05)' : 'rgba(0, 0, 0, 0.04)',
|
||||
bbox: byMode(theme, TABLE_HEADER_PAIR),
|
||||
fontWeight: 600,
|
||||
},
|
||||
'& tr:last-child td': {
|
||||
|
||||
@@ -4,7 +4,7 @@ import DialogTitle from '@mui/material/DialogTitle';
|
||||
import DialogContent from '@mui/material/DialogContent';
|
||||
import DialogActions from '@mui/material/DialogActions';
|
||||
import Button from '@mui/material/Button';
|
||||
import TextField from '@mui/material/TextField';
|
||||
import TextInput from '../TextInput';
|
||||
import MenuItem from '@mui/material/MenuItem';
|
||||
import Box from '@mui/material/Box';
|
||||
import Typography from '@mui/material/Typography';
|
||||
@@ -12,6 +12,9 @@ import CircularProgress from '@mui/material/CircularProgress';
|
||||
import AutoAwesomeRoundedIcon from '@mui/icons-material/AutoAwesomeRounded';
|
||||
|
||||
import { PRESET_MODELS } from '../../automats/chatAutomat';
|
||||
import {
|
||||
SHADOW_DIALOG,
|
||||
} from '../../colors';
|
||||
|
||||
export default class NewConversationDialog extends PureComponent {
|
||||
constructor(props) {
|
||||
@@ -73,7 +76,7 @@ export default class NewConversationDialog extends PureComponent {
|
||||
sx: {
|
||||
borderRadius: 3,
|
||||
p: 1,
|
||||
boxShadow: '0 20px 40px rgba(0,0,0,0.2)',
|
||||
boxShadow: SHADOW_DIALOG,
|
||||
},
|
||||
}}
|
||||
>
|
||||
@@ -103,23 +106,21 @@ export default class NewConversationDialog extends PureComponent {
|
||||
Wähle das Sprachmodell für die neue Konversation aus.
|
||||
</Typography>
|
||||
|
||||
<TextField
|
||||
<TextInput
|
||||
label="Provider"
|
||||
value={provider}
|
||||
onChange={(e) => this.setState({ provider: e.target.value })}
|
||||
fullWidth
|
||||
size="small"
|
||||
disabled={loading}
|
||||
helperText="Standard: openrouter"
|
||||
/>
|
||||
|
||||
<TextField
|
||||
<TextInput
|
||||
select
|
||||
label="Modell Vorlage"
|
||||
value={isCustom ? '__custom__' : model}
|
||||
onChange={this.handleModelChange}
|
||||
fullWidth
|
||||
size="small"
|
||||
disabled={loading}
|
||||
>
|
||||
{PRESET_MODELS.map((item) => (
|
||||
@@ -128,16 +129,15 @@ export default class NewConversationDialog extends PureComponent {
|
||||
</MenuItem>
|
||||
))}
|
||||
<MenuItem value="__custom__">Anderes Modell eingeben…</MenuItem>
|
||||
</TextField>
|
||||
</TextInput>
|
||||
|
||||
{isCustom && (
|
||||
<TextField
|
||||
<TextInput
|
||||
label="Modell-Bezeichnung"
|
||||
placeholder="z. B. anthropic/claude-3.5-haiku"
|
||||
value={customModel}
|
||||
onChange={(e) => this.setState({ customModel: e.target.value })}
|
||||
fullWidth
|
||||
size="small"
|
||||
autoFocus
|
||||
disabled={loading}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user