fix message layout

Signed-off-by: eternal-flame-AD <yume@yumechi.jp>
This commit is contained in:
eternal-flame-AD 2025-08-04 16:07:39 -05:00
parent 73d42c5857
commit d929e66aa2
No known key found for this signature in database
3 changed files with 100 additions and 49 deletions

View File

@ -11,6 +11,7 @@ import {Markdown} from '../common/Markdown';
import * as config from '../config'; import * as config from '../config';
import {IMessageExtras} from '../types'; import {IMessageExtras} from '../types';
import {contentType, RenderMode} from './extras'; import {contentType, RenderMode} from './extras';
import {makeIntlFormatter} from 'react-timeago/defaultFormatter';
const PREVIEW_LENGTH = 500; const PREVIEW_LENGTH = 500;
@ -39,14 +40,34 @@ const useStyles = makeStyles()((theme: Theme) => ({
width: 32, width: 32,
height: 32, height: 32,
}, },
[theme.breakpoints.down('sm')]: {
display: 'none',
},
},
appName: {
opacity: 0.7,
}, },
date: { date: {
[theme.breakpoints.down('md')]: { [theme.breakpoints.down('md')]: {
order: 1,
flexBasis: '100%',
opacity: 0.7, opacity: 0.7,
}, },
}, },
messageWrapper: {
display: 'grid',
gridTemplateColumns: '70px 1fr',
[theme.breakpoints.down('sm')]: {
gridTemplateColumns: '1fr',
},
gap: 16,
width: '100%',
},
actionsWrapper: {
flex: 1,
display: 'flex',
justifyContent: 'flex-end',
flexDirection: 'row',
alignItems: 'flex-start',
},
imageWrapper: { imageWrapper: {
display: 'flex', display: 'flex',
}, },
@ -81,6 +102,7 @@ interface IProps {
date: string; date: string;
content: string; content: string;
priority: number; priority: number;
appName: string;
fDelete: VoidFunction; fDelete: VoidFunction;
extras?: IMessageExtras; extras?: IMessageExtras;
expanded: boolean; expanded: boolean;
@ -105,6 +127,7 @@ const Message = ({
priority, priority,
content, content,
extras, extras,
appName,
onExpand, onExpand,
expanded: initialExpanded, expanded: initialExpanded,
}: IProps) => { }: IProps) => {
@ -140,56 +163,73 @@ const Message = ({
borderLeftWidth: 6, borderLeftWidth: 6,
borderLeftStyle: 'solid', borderLeftStyle: 'solid',
}}> }}>
<div style={{display: 'flex', width: '100%'}}> <div className={classes.messageWrapper}>
<div className={classes.imageWrapper}> {image !== null ? (
{image !== null ? ( <img
<img src={config.get('url') + image}
src={config.get('url') + image} alt={`${appName} logo`}
alt="app logo" width="70"
width="70" height="70"
height="70" className={classes.image}
className={classes.image} />
/> ) : null}
) : null} <div style={{width: '100%'}}>
</div> <div style={{display: 'flex', width: '100%'}}>
<div className={classes.messageContentWrapper}> <div className={classes.messageContentWrapper}>
<div className={classes.header}> <div className={classes.header}>
<Typography className={`${classes.headerTitle} title`} variant="h5"> <Typography
{title} className={`${classes.headerTitle} title`}
</Typography> variant="h5">
<Typography variant="body1" className={classes.date}> {title}
<TimeAgo date={date} /> </Typography>
</Typography> </div>
<IconButton <div className={classes.appName}>
onClick={fDelete} <Typography variant="body1" className={classes.date}>
className={`${classes.trash} delete`} {appName}
size="large"> </Typography>
<Delete /> </div>
</IconButton> </div>
<div className={classes.actionsWrapper}>
<Typography variant="body1" className={classes.date}>
<TimeAgo
date={date}
formatter={makeIntlFormatter({
style: 'narrow',
})}
/>
</Typography>
<IconButton
onClick={fDelete}
className={`${classes.trash} delete`}
size="large">
<Delete />
</IconButton>
</div>
</div> </div>
<div>
<Typography <Typography
component="div" component="div"
ref={setPreviewRef} ref={setPreviewRef}
className={`${classes.content} content ${ className={`${classes.content} content ${
isOverflowing && expanded ? 'expanded' : '' isOverflowing && expanded ? 'expanded' : ''
}`}> }`}>
{renderContent()} {renderContent()}
</Typography> </Typography>
</div>
{isOverflowing && (
<Button
style={{marginTop: 16}}
onClick={togglePreviewHeight}
variant="contained"
color="primary"
size="large"
fullWidth={true}
startIcon={expanded ? <ExpandLess /> : <ExpandMore />}>
{expanded ? 'Read Less' : 'Read More'}
</Button>
)}
</div> </div>
</div> </div>
{isOverflowing && (
<Button
style={{marginTop: 16}}
onClick={togglePreviewHeight}
variant="contained"
color="primary"
size="large"
fullWidth={true}
startIcon={expanded ? <ExpandLess /> : <ExpandMore />}>
{expanded ? 'Read Less' : 'Read More'}
</Button>
)}
</Container> </Container>
</div> </div>
); );

View File

@ -40,6 +40,7 @@ const Messages = observer(() => {
onExpand={(expanded) => (expandedState.current[message.id] = expanded)} onExpand={(expanded) => (expandedState.current[message.id] = expanded)}
title={message.title} title={message.title}
date={message.date} date={message.date}
appName={appStore.getName(message.appid)}
expanded={expandedState.current[message.id] ?? false} expanded={expandedState.current[message.id] ?? false}
content={message.message} content={message.message}
image={message.image} image={message.image}

View File

@ -1,9 +1,19 @@
declare module 'react-timeago' { declare module 'react-timeago' {
import React from 'react'; import React from 'react';
export type FormatterOptions = {
style?: 'long' | 'short' | 'narrow';
};
export type Formatter = (options: FormatterOptions) => React.ReactNode;
export interface ITimeAgoProps { export interface ITimeAgoProps {
date: string; date: string;
formatter?: Formatter;
} }
export default class TimeAgo extends React.Component<ITimeAgoProps, unknown> {} export default class TimeAgo extends React.Component<ITimeAgoProps, unknown> {}
} }
declare module 'react-timeago/defaultFormatter' {
declare function makeIntlFormatter(options: FormatterOptions): Formatter;
}