mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-28 05:11:24 +08:00
fix: improve image block layout and spacing (#9754)
- Adjust image block margin from 10px to 1em for better consistency - Fix single vs multi-image display logic with proper layout - Update ImageBlock component to handle single/multi display modes - Fix image model detection logic for better compatibility - Improve overall spacing between content blocks 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
parent
de8c7dbc93
commit
f599b2c846
@ -202,7 +202,7 @@
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
margin: 10px 0;
|
||||
margin: 1em 0;
|
||||
}
|
||||
|
||||
a,
|
||||
@ -321,6 +321,10 @@ emoji-picker {
|
||||
--border-size: 0;
|
||||
}
|
||||
|
||||
.block-wrapper + .block-wrapper {
|
||||
margin-top: 1em;
|
||||
}
|
||||
|
||||
.katex,
|
||||
mjx-container {
|
||||
display: inline-block;
|
||||
|
||||
@ -3045,10 +3045,8 @@ export function isGenerateImageModel(model: Model): boolean {
|
||||
}
|
||||
|
||||
const modelId = getLowerBaseModelName(model.id, '/')
|
||||
if (GENERATE_IMAGE_MODELS.includes(modelId)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
||||
return GENERATE_IMAGE_MODELS.some((imageModel) => modelId.includes(imageModel))
|
||||
}
|
||||
|
||||
export function isSupportedDisableGenerationModel(model: Model): boolean {
|
||||
|
||||
@ -7,32 +7,42 @@ import styled from 'styled-components'
|
||||
|
||||
interface Props {
|
||||
block: ImageMessageBlock
|
||||
isSingle?: boolean
|
||||
}
|
||||
|
||||
const ImageBlock: React.FC<Props> = ({ block }) => {
|
||||
if (block.status === MessageBlockStatus.PENDING) return <Skeleton.Image active style={{ width: 200, height: 200 }} />
|
||||
const ImageBlock: React.FC<Props> = ({ block, isSingle = false }) => {
|
||||
if (block.status === MessageBlockStatus.PENDING) {
|
||||
return <Skeleton.Image active style={{ width: 200, height: 200 }} />
|
||||
}
|
||||
|
||||
if (block.status === MessageBlockStatus.STREAMING || block.status === MessageBlockStatus.SUCCESS) {
|
||||
const images = block.metadata?.generateImageResponse?.images?.length
|
||||
? block.metadata?.generateImageResponse?.images
|
||||
: block?.file
|
||||
? [`file://${FileManager.getFilePath(block?.file)}`]
|
||||
: []
|
||||
|
||||
return (
|
||||
<Container>
|
||||
{images.map((src, index) => (
|
||||
<ImageViewer
|
||||
src={src}
|
||||
key={`image-${index}`}
|
||||
style={{ maxWidth: 500, maxHeight: 'min(500px, 50vh)', padding: 0, borderRadius: 8 }}
|
||||
style={
|
||||
isSingle
|
||||
? { maxWidth: 500, maxHeight: 'min(500px, 50vh)', padding: 0, borderRadius: 8 }
|
||||
: { width: 280, height: 280, objectFit: 'cover', padding: 0, borderRadius: 8 }
|
||||
}
|
||||
/>
|
||||
))}
|
||||
</Container>
|
||||
)
|
||||
} else return null
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
const Container = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
gap: 10px;
|
||||
display: block;
|
||||
`
|
||||
export default React.memo(ImageBlock)
|
||||
|
||||
@ -87,11 +87,20 @@ const MessageBlockRenderer: React.FC<Props> = ({ blocks, message }) => {
|
||||
{groupedBlocks.map((block) => {
|
||||
if (Array.isArray(block)) {
|
||||
const groupKey = block.map((imageBlock) => imageBlock.id).join('-')
|
||||
// 单张图片不使用 ImageBlockGroup 包装
|
||||
if (block.length === 1) {
|
||||
return (
|
||||
<AnimatedBlockWrapper key={groupKey} enableAnimation={message.status.includes('ing')}>
|
||||
<ImageBlock key={block[0].id} block={block[0] as ImageMessageBlock} isSingle={true} />
|
||||
</AnimatedBlockWrapper>
|
||||
)
|
||||
}
|
||||
// 多张图片使用 ImageBlockGroup 包装
|
||||
return (
|
||||
<AnimatedBlockWrapper key={groupKey} enableAnimation={message.status.includes('ing')}>
|
||||
<ImageBlockGroup count={block.length}>
|
||||
{block.map((imageBlock) => (
|
||||
<ImageBlock key={imageBlock.id} block={imageBlock as ImageMessageBlock} />
|
||||
<ImageBlock key={imageBlock.id} block={imageBlock as ImageMessageBlock} isSingle={false} />
|
||||
))}
|
||||
</ImageBlockGroup>
|
||||
</AnimatedBlockWrapper>
|
||||
@ -166,8 +175,8 @@ const MessageBlockRenderer: React.FC<Props> = ({ blocks, message }) => {
|
||||
export default React.memo(MessageBlockRenderer)
|
||||
|
||||
const ImageBlockGroup = styled.div<{ count: number }>`
|
||||
display: grid;
|
||||
grid-template-columns: repeat(${({ count }) => Math.min(count, 3)}, minmax(200px, 1fr));
|
||||
gap: 8px;
|
||||
max-width: 960px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: 10px;
|
||||
max-width: 100%;
|
||||
`
|
||||
|
||||
Loading…
Reference in New Issue
Block a user