New goals page. Upgraded prisma.

This commit is contained in:
Mike Cao 2025-05-31 02:11:18 -07:00
parent 99330a1a4d
commit 49bcbfd7f9
65 changed files with 769 additions and 1195 deletions

View file

@ -4,15 +4,14 @@ import { Logo } from '@/components/icons';
export interface EmptyPlaceholderProps {
message?: string;
icon?: ReactNode;
children?: ReactNode;
}
export function EmptyPlaceholder({ message, children }: EmptyPlaceholderProps) {
export function EmptyPlaceholder({ message, icon, children }: EmptyPlaceholderProps) {
return (
<Column alignItems="center" justifyContent="center" gap="5" height="100%" width="100%">
<Icon size="xl" fillColor="3" strokeColor="3">
<Logo />
</Icon>
<Icon size="xl">{icon || <Logo />}</Icon>
<Text>{message}</Text>
<div>{children}</div>
</Column>

View file

@ -1,15 +0,0 @@
.error {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
margin: auto;
display: flex;
background-color: var(--base50);
padding: 10px;
z-index: 1;
}
.icon {
margin-inline-end: 10px;
}

View file

@ -1,5 +1,4 @@
import { Icon, Text } from '@umami/react-zen';
import styles from './ErrorMessage.module.css';
import { Icon, Text, Row } from '@umami/react-zen';
import { useMessages } from '@/components/hooks';
import { Alert } from '@/components/icons';
@ -7,11 +6,11 @@ export function ErrorMessage() {
const { formatMessage, messages } = useMessages();
return (
<div className={styles.error}>
<Icon className={styles.icon} size="lg">
<Row alignItems="center" justifyContent="center" gap>
<Icon>
<Alert />
</Icon>
<Text>{formatMessage(messages.error)}</Text>
</div>
</Row>
);
}

View file

@ -1,14 +1,4 @@
import {
Grid,
Row,
Column,
TextField,
Label,
ListItem,
Select,
Icon,
Button,
} from '@umami/react-zen';
import { Grid, Column, TextField, Label, ListItem, Select, Icon, Button } from '@umami/react-zen';
import { useFilters } from '@/components/hooks';
import { Close } from '@/components/icons';
@ -32,10 +22,10 @@ export function FilterRecord({
const { fields, operators } = useFilters();
return (
<Grid columns="1fr auto">
<Column>
<Label>{fields.find(f => f.name === name)?.label}</Label>
<Row gap alignItems="center">
<>
<Label>{fields.find(f => f.name === name)?.label}</Label>
<Grid columns="1fr auto" gap>
<Grid columns="200px 1fr" gap>
<Select
items={operators.filter(({ type }) => type === 'string')}
value={operator}
@ -50,15 +40,15 @@ export function FilterRecord({
}}
</Select>
<TextField value={value} onChange={e => onChange?.(name, e.target.value)} />
</Row>
</Column>
<Column justifyContent="flex-end">
<Button variant="quiet" onPress={() => onRemove?.(name)}>
<Icon>
<Close />
</Icon>
</Button>
</Column>
</Grid>
</Grid>
<Column justifyContent="flex-end">
<Button variant="quiet" onPress={() => onRemove?.(name)}>
<Icon>
<Close />
</Icon>
</Button>
</Column>
</Grid>
</>
);
}

View file

@ -1,36 +1,36 @@
import { ReactNode } from 'react';
import classNames from 'classnames';
import { Loading } from '@umami/react-zen';
import { Spinner, Dots } from '@umami/react-zen';
import { ErrorMessage } from '@/components/common/ErrorMessage';
import { Empty } from '@/components/common/Empty';
import styles from './LoadingPanel.module.css';
export function LoadingPanel({
data,
error,
isEmpty,
isFetched,
isLoading,
loadingIcon = 'dots',
renderEmpty = () => <Empty />,
className,
children,
}: {
data?: any;
error?: Error;
isEmpty?: boolean;
isFetched?: boolean;
isLoading?: boolean;
loadingIcon?: 'dots' | 'spinner';
isEmpty?: boolean;
renderEmpty?: () => ReactNode;
className?: string;
children: ReactNode;
}) {
const isEmpty = !isLoading && isFetched && data && Array.isArray(data) && data.length === 0;
return (
<div className={classNames(styles.panel, className)}>
{isLoading && !isFetched && <Loading className={styles.loading} icon={loadingIcon} />}
{isLoading && !isFetched && (loadingIcon === 'dots' ? <Dots /> : <Spinner />)}
{error && <ErrorMessage />}
{!error && isEmpty && <Empty />}
{!error && !isEmpty && data && children}
{!error && !isLoading && isEmpty && renderEmpty()}
{!error && !isLoading && !isEmpty && children}
</div>
);
}

View file

@ -1,11 +1,12 @@
import { ReactNode } from 'react';
import { Heading, Icon, Row, Text } from '@umami/react-zen';
import { Heading, Icon, Row, Text, RowProps } from '@umami/react-zen';
export function SectionHeader({
title,
description,
icon,
children,
...props
}: {
title?: string;
description?: string;
@ -13,9 +14,9 @@ export function SectionHeader({
allowEdit?: boolean;
className?: string;
children?: ReactNode;
}) {
} & RowProps) {
return (
<Row justifyContent="space-between" alignItems="center" height="60px">
<Row {...props} justifyContent="space-between" alignItems="center" height="60px">
<Row gap="3" alignItems="center">
{icon && <Icon>{icon}</Icon>}
{title && <Heading size="3">{title}</Heading>}