Merge pull request #819 from gotify/upgrade-ui-fix-message-layout

fix message layout
This commit is contained in:
Jannis Mattheis 2025-08-06 17:03:08 +02:00 committed by GitHub
commit 43574a075c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 29 additions and 7 deletions

View File

@ -7,7 +7,7 @@ ifdef GOTOOLCHAIN
else else
GO_VERSION=$(shell go mod edit -json | jq -r .Toolchain | sed -e 's/go//') GO_VERSION=$(shell go mod edit -json | jq -r .Toolchain | sed -e 's/go//')
endif endif
DOCKER_BUILD_IMAGE=gotify/build DOCKER_BUILD_IMAGE=docker.io/gotify/build
DOCKER_WORKDIR=/proj DOCKER_WORKDIR=/proj
DOCKER_RUN=docker run --rm -e LD_FLAGS="$$LD_FLAGS" -v "$$PWD/.:${DOCKER_WORKDIR}" -v "`go env GOPATH`/pkg/mod/.:/go/pkg/mod:ro" -w ${DOCKER_WORKDIR} DOCKER_RUN=docker run --rm -e LD_FLAGS="$$LD_FLAGS" -v "$$PWD/.:${DOCKER_WORKDIR}" -v "`go env GOPATH`/pkg/mod/.:/go/pkg/mod:ro" -w ${DOCKER_WORKDIR}
DOCKER_GO_BUILD=go build -mod=readonly -a -installsuffix cgo -ldflags "$$LD_FLAGS" DOCKER_GO_BUILD=go build -mod=readonly -a -installsuffix cgo -ldflags "$$LD_FLAGS"

View File

@ -1,4 +1,4 @@
import {Button, Theme} from '@mui/material'; import {Button, Theme, useMediaQuery, useTheme} from '@mui/material';
import IconButton from '@mui/material/IconButton'; import IconButton from '@mui/material/IconButton';
import {makeStyles} from 'tss-react/mui'; import {makeStyles} from 'tss-react/mui';
import Typography from '@mui/material/Typography'; import Typography from '@mui/material/Typography';
@ -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;
@ -32,6 +33,7 @@ const useStyles = makeStyles()((theme: Theme) => ({
}, },
messageContentWrapper: { messageContentWrapper: {
minWidth: 200, minWidth: 200,
width: '100%',
}, },
image: { image: {
marginRight: 15, marginRight: 15,
@ -81,6 +83,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,13 +108,16 @@ const Message = ({
priority, priority,
content, content,
extras, extras,
appName,
onExpand, onExpand,
expanded: initialExpanded, expanded: initialExpanded,
}: IProps) => { }: IProps) => {
const theme = useTheme();
const [previewRef, setPreviewRef] = React.useState<HTMLDivElement | null>(null); const [previewRef, setPreviewRef] = React.useState<HTMLDivElement | null>(null);
const {classes} = useStyles(); const {classes} = useStyles();
const [expanded, setExpanded] = React.useState(initialExpanded); const [expanded, setExpanded] = React.useState(initialExpanded);
const [isOverflowing, setOverflowing] = React.useState(false); const [isOverflowing, setOverflowing] = React.useState(false);
const dateWrapped = useMediaQuery(theme.breakpoints.down('md'));
React.useEffect(() => { React.useEffect(() => {
setOverflowing(!!previewRef && previewRef.scrollHeight > previewRef.clientHeight); setOverflowing(!!previewRef && previewRef.scrollHeight > previewRef.clientHeight);
@ -145,7 +151,7 @@ const Message = ({
{image !== null ? ( {image !== null ? (
<img <img
src={config.get('url') + image} src={config.get('url') + image}
alt="app logo" alt={`${appName} logo`}
width="70" width="70"
height="70" height="70"
className={classes.image} className={classes.image}
@ -158,7 +164,12 @@ const Message = ({
{title} {title}
</Typography> </Typography>
<Typography variant="body1" className={classes.date}> <Typography variant="body1" className={classes.date}>
<TimeAgo date={date} /> <TimeAgo
date={date}
formatter={makeIntlFormatter({
style: dateWrapped ? 'long' : 'narrow',
})}
/>
</Typography> </Typography>
<IconButton <IconButton
onClick={fDelete} onClick={fDelete}

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;
}

View File

@ -1,7 +1,7 @@
import {defineConfig} from 'vite'; import {defineConfig} from 'vite';
import react from '@vitejs/plugin-react'; import react from '@vitejs/plugin-react';
const GOTIFY_PORT = process.env.GOTIFY_PORT ?? '80'; const GOTIFY_SERVER_PORT = process.env.GOTIFY_SERVER_PORT ?? '80';
export default defineConfig({ export default defineConfig({
build: { build: {
@ -21,12 +21,12 @@ export default defineConfig({
host: '0.0.0.0', host: '0.0.0.0',
proxy: { proxy: {
'^/(application|message|client|current|user|plugin|version|image)': { '^/(application|message|client|current|user|plugin|version|image)': {
target: `http://localhost:${GOTIFY_PORT}/`, target: `http://localhost:${GOTIFY_SERVER_PORT}/`,
changeOrigin: true, changeOrigin: true,
secure: false, secure: false,
}, },
'/stream': { '/stream': {
target: `ws://localhost:${GOTIFY_PORT}/`, target: `ws://localhost:${GOTIFY_SERVER_PORT}/`,
ws: true, ws: true,
rewriteWsOrigin: true, rewriteWsOrigin: true,
}, },