pl-fe: improve empty column messages

Signed-off-by: nicole mikołajczyk <git@mkljczk.pl>
This commit is contained in:
nicole mikołajczyk
2025-10-13 14:33:27 +02:00
parent 7e17ec3ac0
commit 8cfda4b38d
58 changed files with 119 additions and 128 deletions

View File

@ -0,0 +1,24 @@
import React from 'react';
import Icon from './ui/icon';
import Stack from './ui/stack';
import Text from './ui/text';
interface IEmptyMessage {
text: React.ReactNode;
icon?: string;
}
const EmptyMessage: React.FC<IEmptyMessage> = ({ text, icon = require('@phosphor-icons/core/regular/empty.svg') }) => (
<Stack space={4} className='⁂-empty-message py-6' justifyContent='center' alignItems='center'>
<div className='rounded-full bg-gray-200 p-4 dark:bg-gray-800'>
<Icon src={icon} className='size-6 text-gray-600' />
</div>
<Text theme='muted' align='center'>
{text}
</Text>
</Stack>
);
export { EmptyMessage };

View File

@ -4,10 +4,11 @@ import { useHistory } from 'react-router-dom';
import { Virtuoso, Components, VirtuosoProps, VirtuosoHandle, ListRange, IndexLocationWithAlign } from 'react-virtuoso';
import LoadMore from 'pl-fe/components/load-more';
import Card from 'pl-fe/components/ui/card';
import Spinner from 'pl-fe/components/ui/spinner';
import { useSettings } from 'pl-fe/hooks/use-settings';
import { EmptyMessage } from './empty-message';
/** Custom Viruoso component context. */
type Context = {
itemClassName?: string;
@ -48,12 +49,12 @@ interface IScrollableList extends VirtuosoProps<any, any> {
hasMore?: boolean;
/** Additional element to display at the top of the list. */
prepend?: React.ReactNode;
/** Whether to display the prepended element. */
alwaysPrepend?: boolean;
/** Message to display when the list is loaded but empty. */
emptyMessage?: React.ReactNode;
/** Should the empty message be displayed in a Card */
emptyMessageCard?: boolean;
/** Message to display when the list is loaded but empty. */
emptyMessageText?: React.ReactNode;
/** Message to display next to the emptyMessage text. */
emptyMessageIcon?: string;
/** Scrollable content. */
children: Iterable<React.ReactNode>;
/** Callback when the list is scrolled to the top. */
@ -83,11 +84,11 @@ interface IScrollableList extends VirtuosoProps<any, any> {
const ScrollableList = React.forwardRef<VirtuosoHandle, IScrollableList>(({
scrollKey,
prepend = null,
alwaysPrepend,
children,
isLoading,
emptyMessage,
emptyMessageCard = true,
emptyMessageText,
emptyMessageIcon,
showLoading,
onScroll,
onScrollToTop,
@ -153,23 +154,13 @@ const ScrollableList = React.forwardRef<VirtuosoHandle, IScrollableList>(({
}, []);
/* Render an empty state instead of the scrollable list. */
const renderEmpty = (): JSX.Element => (
<div className='mt-2'>
{alwaysPrepend && prepend}
{isLoading ? (
<Spinner />
) : (
<>
{emptyMessageCard ? (
<Card variant='rounded' size='lg'>
{emptyMessage}
</Card>
) : emptyMessage}
</>
)}
</div>
);
const renderEmpty = (): JSX.Element => {
return isLoading ? (
<Spinner />
) : emptyMessageText ? (
<EmptyMessage text={emptyMessageText} icon={emptyMessageIcon} />
) : <>{emptyMessage}</>;
};
/** Render a single item. */
const renderItem = (_i: number, element: JSX.Element): JSX.Element => {
@ -250,9 +241,9 @@ const ScrollableList = React.forwardRef<VirtuosoHandle, IScrollableList>(({
itemClassName,
}}
components={{
Header: () => <>{prepend}</>,
Header: prepend ? () => <>{prepend}</> : undefined,
ScrollSeekPlaceholder: Placeholder as any,
EmptyPlaceholder: () => renderEmpty(),
EmptyPlaceholder: renderEmpty,
List,
Item,
Footer: loadMore,