make page layout better

This commit is contained in:
Nate Kelley 2025-02-28 17:11:40 -07:00
parent 92fe355f47
commit b883ffc31c
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
13 changed files with 70 additions and 74 deletions

View File

@ -10,17 +10,16 @@ import { BusterListColumn, BusterListRow } from '@/components/ui/list';
import { ChatSelectedOptionPopup } from './ChatItemsSelectedPopup';
import { BusterList, ListEmptyStateWithButton } from '@/components/ui/list';
import { useCreateListByDate } from '@/components/ui/list/useCreateListByDate';
import { cn } from '@/lib/utils';
export const ChatItemsContainer: React.FC<{
chats: BusterChatListItem[];
className?: string;
openNewMetricModal: () => void;
loading: boolean;
}> = ({ chats = [], className = '', loading, openNewMetricModal }) => {
}> = ({ chats = [], className = '', loading }) => {
const [selectedRowKeys, setSelectedRowKeys] = useState<string[]>([]);
const renderedDates = useRef<Record<string, string>>({});
const renderedOwners = useRef<Record<string, React.ReactNode>>({});
const tableContainerRef = useRef<HTMLDivElement>(null);
const onSelectChange = useMemoizedFn((selectedRowKeys: string[]) => {
setSelectedRowKeys(selectedRowKeys);
@ -106,15 +105,13 @@ export const ChatItemsContainer: React.FC<{
);
return (
<div
ref={tableContainerRef}
className={`${className} relative flex h-full flex-col items-center`}>
<>
<BusterList
rows={chatsByDate}
columns={columns}
onSelectChange={onSelectChange}
selectedRowKeys={selectedRowKeys}
emptyState={<EmptyState loading={loading} openNewMetricModal={openNewMetricModal} />}
emptyState={<EmptyState loading={loading} />}
/>
<ChatSelectedOptionPopup
@ -122,31 +119,27 @@ export const ChatItemsContainer: React.FC<{
onSelectChange={onSelectChange}
hasSelected={hasSelected}
/>
</div>
</>
);
};
const EmptyState: React.FC<{
loading: boolean;
openNewMetricModal: () => void;
}> = React.memo(({ loading, openNewMetricModal }) => {
}> = React.memo(({ loading }) => {
if (loading) {
return <></>;
}
return <ChatsEmptyState openNewMetricModal={openNewMetricModal} />;
return <ChatsEmptyState />;
});
EmptyState.displayName = 'EmptyState';
const ChatsEmptyState: React.FC<{
openNewMetricModal: () => void;
}> = ({ openNewMetricModal }) => {
const ChatsEmptyState: React.FC<{}> = ({}) => {
return (
<ListEmptyStateWithButton
title="You don't have any chats yet."
description="You don't have any chats. As soon as you do, they will start to appear here."
buttonText="New chat"
onClick={openNewMetricModal}
/>
);
};

View File

@ -1,44 +1,15 @@
'use client';
import React, { useState } from 'react';
import { AppContentPage } from '@/components/ui/layouts/AppContentPage';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { useMemoizedFn, useMount } from 'ahooks';
import { useBusterChatListByFilter } from '@/context/Chats';
import { ChatListHeader } from './ChatListHeader';
import { ChatItemsContainer } from './ChatItemsContainer';
export const ChatListContainer: React.FC<{
className?: string;
}> = ({ className = '' }) => {
const onToggleChatsModal = useAppLayoutContextSelector((s) => s.onToggleChatsModal);
export const ChatListContainer: React.FC<{}> = ({}) => {
const [filters, setFilters] = useState<Parameters<typeof useBusterChatListByFilter>[0]>({
admin_view: false
});
const { list, isFetched } = useBusterChatListByFilter(filters);
const onSetFilters = useMemoizedFn(
(newFilters: Parameters<typeof useBusterChatListByFilter>[0]) => {
setFilters(newFilters);
}
);
useMount(async () => {
onSetFilters({ admin_view: false });
});
return (
<div className={`${className} flex h-full flex-col`}>
<ChatListHeader />
<AppContentPage>
<ChatItemsContainer
chats={list}
loading={!isFetched}
openNewMetricModal={onToggleChatsModal}
className="flex-col overflow-hidden"
/>
</AppContentPage>
</div>
);
return <ChatItemsContainer chats={list} loading={!isFetched} />;
};

View File

@ -1,17 +1,10 @@
'use client';
import React from 'react';
import { AppContentHeader } from '@/components/ui/layouts/AppContentHeader';
import { Text } from '@/components/ui';
import { Text } from '@/components/ui/typography';
export const ChatListHeader: React.FC<{}> = ({}) => {
return (
<AppContentHeader>
<div className="flex w-full items-center justify-between">
<div className="flex items-center space-x-2">
<Text>{'Chats'}</Text>
</div>
</div>
</AppContentHeader>
<>
<Text>{'Chats'}</Text>
</>
);
};

View File

@ -1,5 +1,11 @@
import { AppPageLayout } from '@/components/ui/layouts/AppPageLayout';
import { ChatListContainer } from './_ChatsListContainer';
import { ChatListHeader } from './_ChatsListContainer/ChatListHeader';
export default function ChatsPage() {
return <ChatListContainer />;
return (
<AppPageLayout headerVariant="list" header={<ChatListHeader />}>
<ChatListContainer />
</AppPageLayout>
);
}

View File

@ -14,6 +14,9 @@ import { Tooltip } from '@/components/ui/tooltip/Tooltip';
import Link from 'next/link';
import { useUserConfigContextSelector } from '@/context/Users';
import { useAppLayoutContextSelector } from '@/context/BusterAppLayout';
import { SupportModal } from '../modal/SupportModal';
import { InvitePeopleModal } from '../modal/InvitePeopleModal';
import { useMemoizedFn } from 'ahooks';
const topItems: ISidebarList = {
items: [
@ -126,7 +129,11 @@ export const SidebarPrimary = React.memo(() => {
}, [isAdmin, favorites, currentRoute]);
return (
<Sidebar content={sidebarItems} header={<SidebarPrimaryHeader />} activeItem={currentRoute} />
<>
<Sidebar content={sidebarItems} header={<SidebarPrimaryHeader />} activeItem={currentRoute} />
<GlobalModals />
</>
);
});
@ -148,7 +155,7 @@ const SidebarPrimaryHeader = React.memo(() => {
size="tall"
rounding={'large'}
prefix={
<div className="translate-x-[-1px] translate-y-[-1px]">
<div className="translate-x-[0px] translate-y-[-1px]">
<PencilSquareIcon />
</div>
}
@ -162,6 +169,25 @@ const SidebarPrimaryHeader = React.memo(() => {
SidebarPrimaryHeader.displayName = 'SidebarPrimaryHeader';
const GlobalModals = React.memo(() => {
const onToggleSupportModal = useAppLayoutContextSelector((s) => s.onToggleSupportModal);
const onToggleInviteModal = useAppLayoutContextSelector((s) => s.onToggleInviteModal);
const openSupportModal = useAppLayoutContextSelector((s) => s.openSupportModal);
const openInviteModal = useAppLayoutContextSelector((s) => s.openInviteModal);
const isAnonymousUser = useUserConfigContextSelector((state) => state.isAnonymousUser);
const onCloseInviteModal = useMemoizedFn(() => onToggleInviteModal(false));
const onCloseSupportModal = useMemoizedFn(() => onToggleSupportModal(false));
if (isAnonymousUser) return null;
return (
<>
<InvitePeopleModal open={openInviteModal} onClose={onCloseInviteModal} />
<SupportModal open={openSupportModal} onClose={onCloseSupportModal} />
</>
);
});
const favoritesDropdown = (favorites: BusterUserFavorite[]): ISidebarGroup => {
return {
label: 'Favorites',

View File

@ -1,6 +1,5 @@
import React, { PropsWithChildren } from 'react';
import { cn } from '@/lib/utils';
import { cva, type VariantProps } from 'class-variance-authority';
export const AppContentPage: React.FC<
PropsWithChildren<{
@ -11,7 +10,8 @@ export const AppContentPage: React.FC<
return (
<main
className={cn(
'bg-background app-content max-h-[100%] overflow-hidden p-0',
'app-content-page',
'bg-background app-content h-full max-h-[100%] overflow-hidden p-0',
scrollable && 'overflow-y-auto',
className
)}>

View File

@ -1,5 +1,5 @@
import { cn } from '@/lib/utils';
import React from 'react';
import { cn } from '@/lib/utils';
import { AppContentHeader } from './AppContentHeader';
import { AppContentPage } from './AppContentPage';
@ -18,7 +18,7 @@ export const AppPageLayout: React.FC<
className?: string;
headerVariant?: 'default' | 'list';
}>
> = ({ children, header, scrollable = true, className = '', headerVariant = 'default' }) => {
> = ({ children, header, scrollable = false, className = '', headerVariant = 'default' }) => {
return (
<div
className={cn(

View File

@ -1,5 +1,9 @@
export * from './AppSplitter';
export * from './PreventNavigation';
export * from './AppContentHeader_Old';
export * from './AppContentPage';
export * from './ClientRedirect';
//keepers
// export * from './AppPageLayout';
// export * from './AppSplitter';
// export * from './AppLayout';

View File

@ -1,14 +1,16 @@
import React from 'react';
import { AppMaterialIcons, Text, Title } from '@/components/ui';
import { Button } from 'antd';
import { Button } from '../buttons/Button';
import Link from 'next/link';
export const ListEmptyStateWithButton: React.FC<{
isAdmin?: boolean;
title: string;
description: string;
onClick: () => void;
onClick?: () => void;
buttonText: string;
loading?: boolean;
linkButton?: string;
}> = React.memo(({ isAdmin = true, title, buttonText, description, onClick, loading = false }) => {
return (
<div className="flex h-full w-full flex-col">
@ -27,8 +29,8 @@ export const ListEmptyStateWithButton: React.FC<{
{isAdmin && (
<Button
type="default"
icon={<AppMaterialIcons icon="add" />}
variant="default"
prefix={<AppMaterialIcons icon="add" />}
loading={loading}
onClick={onClick}>
{buttonText}

View File

@ -30,7 +30,7 @@ type ParagraphProps = {
} & VariantProps<typeof textColorVariants> &
VariantProps<typeof paragraphVariants>;
const Paragraph: React.FC<ParagraphProps> = ({
export const Paragraph: React.FC<ParagraphProps> = ({
onClick,
variant = 'default',
size = 'base',

View File

@ -33,7 +33,7 @@ type TextProps = {
} & VariantProps<typeof textVariants> &
VariantProps<typeof textColorVariants>;
const Text: React.FC<TextProps> = ({
export const Text: React.FC<TextProps> = ({
variant = 'default',
size = 'base',
truncate,
@ -53,5 +53,3 @@ const Text: React.FC<TextProps> = ({
</TextNode>
);
};
export default Text;

View File

@ -33,7 +33,7 @@ type TitleProps = {
} & VariantProps<typeof titleVariants> &
VariantProps<typeof textColorVariants>;
const Title: React.FC<TitleProps> = ({
export const Title: React.FC<TitleProps> = ({
as = 'h1',
variant = 'default',
size,

View File

@ -0,0 +1,3 @@
export * from './Text';
export * from './Title';
export * from './Paragraph';