feat: add remote object integration databases list card (#4621)
* feat: add remote object integration databases list card Closes #4549 * fix: fixes after rebase
This commit is contained in:
@ -0,0 +1,92 @@
|
||||
import { ComponentType } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { SettingsListSkeletonCard } from '@/settings/components/SettingsListSkeletonCard';
|
||||
import { IconPlus } from '@/ui/display/icon';
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { Card } from '@/ui/layout/card/components/Card';
|
||||
import { CardFooter } from '@/ui/layout/card/components/CardFooter';
|
||||
|
||||
import { SettingsListItemCardContent } from './SettingsListItemCardContent';
|
||||
|
||||
const StyledFooter = styled(CardFooter)`
|
||||
align-items: center;
|
||||
display: flex;
|
||||
padding: ${({ theme }) => theme.spacing(1)};
|
||||
`;
|
||||
|
||||
const StyledButton = styled.button`
|
||||
align-items: center;
|
||||
background: ${({ theme }) => theme.background.primary};
|
||||
border: none;
|
||||
border-radius: ${({ theme }) => theme.border.radius.sm};
|
||||
color: ${({ theme }) => theme.font.color.secondary};
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
padding: 0 ${({ theme }) => theme.spacing(1)};
|
||||
padding-left: ${({ theme }) => theme.spacing(2)};
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
flex: 1 0 0;
|
||||
height: ${({ theme }) => theme.spacing(8)};
|
||||
width: 100%;
|
||||
|
||||
&:hover {
|
||||
background: ${({ theme }) => theme.background.transparent.light};
|
||||
}
|
||||
`;
|
||||
|
||||
type SettingsListCardProps<ListItem extends { id: string }> = {
|
||||
items: ListItem[];
|
||||
getItemLabel: (item: ListItem) => string;
|
||||
hasFooter?: boolean;
|
||||
isLoading?: boolean;
|
||||
onRowClick?: (item: ListItem) => void;
|
||||
RowIcon: IconComponent;
|
||||
RowRightComponent: ComponentType<{ item: ListItem }>;
|
||||
footerButtonLabel?: string;
|
||||
onFooterButtonClick?: () => void;
|
||||
};
|
||||
|
||||
export const SettingsListCard = <
|
||||
ListItem extends { id: string } = {
|
||||
id: string;
|
||||
},
|
||||
>({
|
||||
items,
|
||||
getItemLabel,
|
||||
hasFooter,
|
||||
isLoading,
|
||||
onRowClick,
|
||||
RowIcon,
|
||||
RowRightComponent,
|
||||
onFooterButtonClick,
|
||||
footerButtonLabel,
|
||||
}: SettingsListCardProps<ListItem>) => {
|
||||
const theme = useTheme();
|
||||
|
||||
if (isLoading === true) return <SettingsListSkeletonCard />;
|
||||
|
||||
return (
|
||||
<Card>
|
||||
{items.map((item, index) => (
|
||||
<SettingsListItemCardContent
|
||||
key={item.id}
|
||||
LeftIcon={RowIcon}
|
||||
label={getItemLabel(item)}
|
||||
rightComponent={<RowRightComponent item={item} />}
|
||||
divider={index < items.length - 1}
|
||||
onClick={() => onRowClick?.(item)}
|
||||
/>
|
||||
))}
|
||||
{hasFooter && (
|
||||
<StyledFooter divider={!!items.length}>
|
||||
<StyledButton onClick={onFooterButtonClick}>
|
||||
<IconPlus size={theme.icon.size.md} />
|
||||
{footerButtonLabel}
|
||||
</StyledButton>
|
||||
</StyledFooter>
|
||||
)}
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,47 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { useTheme } from '@emotion/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { IconComponent } from '@/ui/display/icon/types/IconComponent';
|
||||
import { CardContent } from '@/ui/layout/card/components/CardContent';
|
||||
|
||||
const StyledRow = styled(CardContent)`
|
||||
align-items: center;
|
||||
cursor: ${({ onClick }) => (onClick ? 'pointer' : 'default')};
|
||||
display: flex;
|
||||
font-size: ${({ theme }) => theme.font.size.sm};
|
||||
font-weight: ${({ theme }) => theme.font.weight.medium};
|
||||
gap: ${({ theme }) => theme.spacing(2)};
|
||||
padding: ${({ theme }) => theme.spacing(2)};
|
||||
padding-left: ${({ theme }) => theme.spacing(3)};
|
||||
`;
|
||||
|
||||
const StyledAccountHandle = styled.span`
|
||||
flex: 1 0 auto;
|
||||
`;
|
||||
|
||||
type SettingsListItemCardContentProps = {
|
||||
label: string;
|
||||
divider?: boolean;
|
||||
LeftIcon: IconComponent;
|
||||
onClick?: () => void;
|
||||
rightComponent: ReactNode;
|
||||
};
|
||||
|
||||
export const SettingsListItemCardContent = ({
|
||||
label,
|
||||
divider,
|
||||
LeftIcon,
|
||||
onClick,
|
||||
rightComponent,
|
||||
}: SettingsListItemCardContentProps) => {
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<StyledRow onClick={onClick} divider={divider}>
|
||||
<LeftIcon size={theme.icon.size.md} />
|
||||
<StyledAccountHandle>{label}</StyledAccountHandle>
|
||||
{rightComponent}
|
||||
</StyledRow>
|
||||
);
|
||||
};
|
||||
@ -0,0 +1,10 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
import { Card } from '@/ui/layout/card/components/Card';
|
||||
|
||||
const StyledCard = styled(Card)`
|
||||
background-color: ${({ theme }) => theme.background.secondary};
|
||||
height: 40px;
|
||||
`;
|
||||
|
||||
export { StyledCard as SettingsListSkeletonCard };
|
||||
Reference in New Issue
Block a user