Zen components conversion.

This commit is contained in:
Mike Cao 2025-03-07 03:11:58 -08:00
parent aac1a12e51
commit 5999bf6256
142 changed files with 1235 additions and 1454 deletions

View file

@ -1,5 +1,5 @@
import { useMemo } from 'react';
import { StatusLight } from 'react-basics';
import { StatusLight } from '@umami/react-zen';
import { useApi } from '@/components/hooks';
import { useMessages } from '@/components/hooks';
import styles from './ActiveUsers.module.css';

View file

@ -1,5 +1,5 @@
import classNames from 'classnames';
import { Icon, Icons } from 'react-basics';
import { Icon, Icons } from '@umami/react-zen';
import { ReactNode } from 'react';
import styles from './ChangeLabel.module.css';
@ -35,7 +35,7 @@ export function ChangeLabel({
>
{!neutral && (
<Icon rotate={positive ? -90 : 90} size={size}>
<Icons.ArrowRight />
<Icons.Arrow />
</Icon>
)}
{children || value}

View file

@ -1,9 +1,9 @@
import { useState } from 'react';
import { Button, ButtonGroup, Calendar } from 'react-basics';
import { Button, Row, Calendar } from '@umami/react-zen';
import { isAfter, isBefore, isSameDay, startOfDay, endOfDay } from 'date-fns';
import { useLocale } from '@/components/hooks';
import { FILTER_DAY, FILTER_RANGE } from '@/lib/constants';
import { useMessages } from '@/components/hooks';
import { parseDate } from '@internationalized/date';
import styles from './DatePickerForm.module.css';
export function DatePickerForm({
@ -17,10 +17,9 @@ export function DatePickerForm({
const [selected, setSelected] = useState(
isSameDay(defaultStartDate, defaultEndDate) ? FILTER_DAY : FILTER_RANGE,
);
const [singleDate, setSingleDate] = useState(defaultStartDate);
const [startDate, setStartDate] = useState(defaultStartDate);
const [endDate, setEndDate] = useState(defaultEndDate);
const { dateLocale } = useLocale();
const [singleDate, setSingleDate] = useState(defaultStartDate || new Date());
const [startDate, setStartDate] = useState(defaultStartDate || new Date());
const [endDate, setEndDate] = useState(defaultEndDate || new Date());
const { formatMessage, labels } = useMessages();
const disabled =
@ -36,48 +35,41 @@ export function DatePickerForm({
}
};
console.log({ minDate, maxDate, singleDate, startDate, endDate, disabled });
return (
<div className={styles.container}>
<div className={styles.filter}>
<ButtonGroup selectedKey={selected} onSelect={key => setSelected(key as any)}>
<Button key={FILTER_DAY}>{formatMessage(labels.singleDay)}</Button>
<Button key={FILTER_RANGE}>{formatMessage(labels.dateRange)}</Button>
</ButtonGroup>
<Row>
<Button key={FILTER_DAY} onPress={key => setSelected(key as any)}>
{formatMessage(labels.singleDay)}
</Button>
<Button key={FILTER_RANGE} onPress={key => setSelected(key as any)}>
{formatMessage(labels.dateRange)}
</Button>
</Row>
</div>
<div className={styles.calendars}>
{selected === FILTER_DAY && (
<Calendar
date={singleDate}
minDate={minDate}
maxDate={maxDate}
locale={dateLocale}
onChange={setSingleDate}
value={parseDate(singleDate.toISOString().split('T')[0])}
onChange={d => setSingleDate(d.toDate('America/Los_Angeles'))}
/>
)}
{selected === FILTER_RANGE && (
<>
<Calendar
date={startDate}
minDate={minDate}
maxDate={endDate}
locale={dateLocale}
onChange={setStartDate}
/>
<Calendar
date={endDate}
minDate={startDate}
maxDate={maxDate}
locale={dateLocale}
onChange={setEndDate}
value={parseDate(startDate.toISOString().split('T')[0])}
onChange={d => setStartDate(d.toDate('America/Los_Angeles'))}
/>
</>
)}
</div>
<div className={styles.buttons}>
<Button variant="primary" onClick={handleSave} disabled={disabled}>
<Button variant="primary" onPress={handleSave} isDisabled={disabled}>
{formatMessage(labels.save)}
</Button>
<Button onClick={onClose}>{formatMessage(labels.cancel)}</Button>
<Button onPress={onClose}>{formatMessage(labels.cancel)}</Button>
</div>
</div>
);

View file

@ -1,5 +1,5 @@
import { MouseEvent } from 'react';
import { Button, Icon, Icons, Popup, PopupTrigger, Text } from 'react-basics';
import { Button, Icon, Icons, Popover, MenuTrigger, Text, Row } from '@umami/react-zen';
import {
useDateRange,
useFields,
@ -8,7 +8,6 @@ import {
useFormat,
useFilters,
} from '@/components/hooks';
import { PopupForm } from '@/app/(main)/reports/[reportId]/PopupForm';
import { FieldFilterEditForm } from '@/app/(main)/reports/[reportId]/FieldFilterEditForm';
import { OPERATOR_PREFIXES } from '@/lib/constants';
import { isSearchOperator, parseParameterValue } from '@/lib/params';
@ -59,8 +58,17 @@ export function FilterTags({
};
return (
<div className={styles.filters}>
<div className={styles.label}>{formatMessage(labels.filters)}</div>
<Row
gap="3"
backgroundColor="1"
alignItems="center"
paddingX="3"
paddingY="2"
borderRadius="2"
borderSize="1"
marginBottom="6"
>
<Text weight="bold">{formatMessage(labels.filters)}</Text>
{Object.keys(params).map(key => {
if (!params[key]) {
return null;
@ -70,44 +78,44 @@ export function FilterTags({
const paramValue = isSearchOperator(operator) ? value : formatValue(value, key);
return (
<PopupTrigger key={key}>
<div key={key} className={styles.tag}>
<Text className={styles.name}>{label}</Text>
<Text className={styles.operator}>{operatorLabels[operator]}</Text>
<Text className={styles.value}>{paramValue}</Text>
<Icon className={styles.icon} onClick={e => handleCloseFilter(key, e)}>
<Icons.Close />
</Icon>
</div>
<Popup alignment="start">
{(close: () => void) => {
<MenuTrigger key={key}>
<Button variant="outline">
<Row alignItems="center" gap="3">
<Text weight="bold">{label}</Text>
<Text>{operatorLabels[operator]}</Text>
<Text weight="bold">{paramValue}</Text>
<Icon onClick={e => handleCloseFilter(key, e)}>
<Icons.Close />
</Icon>
</Row>
</Button>
<Popover placement="start">
{({ close }: any) => {
return (
<PopupForm>
<FieldFilterEditForm
label={label}
type="string"
websiteId={websiteId}
name={key}
operator={operator}
defaultValue={value}
startDate={startDate}
endDate={endDate}
onChange={values => handleChangeFilter(values, close)}
/>
</PopupForm>
<FieldFilterEditForm
label={label}
type="string"
websiteId={websiteId}
name={key}
operator={operator}
defaultValue={value}
startDate={startDate}
endDate={endDate}
onChange={values => handleChangeFilter(values, close)}
/>
);
}}
</Popup>
</PopupTrigger>
</Popover>
</MenuTrigger>
);
})}
<WebsiteFilterButton websiteId={websiteId} alignment="center" showText={false} />
<Button className={styles.close} variant="quiet" onClick={handleResetFilter}>
<Button className={styles.close} variant="quiet" onPress={handleResetFilter}>
<Icon>
<Icons.Close />
</Icon>
<Text>{formatMessage(labels.clearAll)}</Text>
</Button>
</div>
</Row>
);
}

View file

@ -1,7 +1,7 @@
import { MetricsTable, MetricsTableProps } from './MetricsTable';
import { FilterLink } from '@/components/common/FilterLink';
import { useMessages } from '@/components/hooks';
import { Flexbox } from 'react-basics';
import { Flexbox } from '@umami/react-zen';
export function HostsTable(props: MetricsTableProps) {
const { formatMessage, labels } = useMessages();

View file

@ -1,4 +1,4 @@
import { StatusLight } from 'react-basics';
import { StatusLight } from '@umami/react-zen';
import { colord } from 'colord';
import classNames from 'classnames';
import { LegendItem } from 'chart.js/auto';

View file

@ -1,8 +1,8 @@
import { ReactNode } from 'react';
import { Loading, cloneChildren } from 'react-basics';
import { Loading, Row } from '@umami/react-zen';
import { cloneChildren } from '@/lib/react';
import { ErrorMessage } from '@/components/common/ErrorMessage';
import { formatLongNumber } from '@/lib/format';
import styles from './MetricsBar.module.css';
export interface MetricsBarProps {
isLoading?: boolean;
@ -15,15 +15,15 @@ export function MetricsBar({ children, isLoading, isFetched, error }: MetricsBar
const formatFunc = n => (n >= 0 ? formatLongNumber(n) : `-${formatLongNumber(Math.abs(n))}`);
return (
<div className={styles.bar}>
<Row>
{isLoading && !isFetched && <Loading icon="dots" />}
{error && <ErrorMessage />}
{!isLoading &&
!error &&
isFetched &&
cloneChildren(children, child => {
return { format: child.props.format || formatFunc };
return { format: child.props['format'] || formatFunc };
})}
</div>
</Row>
);
}

View file

@ -1,17 +1,11 @@
import { ReactNode, useMemo, useState } from 'react';
import { Loading, Icon, Text, SearchField } from 'react-basics';
import { Loading, Icon, Text, SearchField } from '@umami/react-zen';
import classNames from 'classnames';
import { ErrorMessage } from '@/components/common/ErrorMessage';
import { LinkButton } from '@/components/common/LinkButton';
import { DEFAULT_ANIMATION_DURATION } from '@/lib/constants';
import { percentFilter } from '@/lib/filters';
import {
useNavigation,
useWebsiteMetrics,
useMessages,
useLocale,
useFormat,
} from '@/components/hooks';
import { useNavigation, useWebsiteMetrics, useMessages, useFormat } from '@/components/hooks';
import { Icons } from '@/components/icons';
import { ListTable, ListTableProps } from './ListTable';
import styles from './MetricsTable.module.css';
@ -51,7 +45,6 @@ export function MetricsTable({
const { formatValue } = useFormat();
const { renderUrl } = useNavigation();
const { formatMessage, labels } = useMessages();
const { dir } = useLocale();
const { data, isLoading, isFetched, error } = useWebsiteMetrics(
websiteId,
@ -114,8 +107,8 @@ export function MetricsTable({
{showMore && data && !error && limit && (
<LinkButton href={renderUrl({ view: type })} variant="quiet">
<Text>{formatMessage(labels.more)}</Text>
<Icon size="sm" rotate={dir === 'rtl' ? 180 : 0}>
<Icons.ArrowRight />
<Icon size="sm">
<Icons.Arrow />
</Icon>
</LinkButton>
)}

View file

@ -5,7 +5,7 @@ import { MetricsTable, MetricsTableProps } from './MetricsTable';
import { FilterButtons } from '@/components/common/FilterButtons';
import thenby from 'thenby';
import { GROUPED_DOMAINS } from '@/lib/constants';
import { Flexbox } from 'react-basics';
import { Flexbox } from '@umami/react-zen';
export interface ReferrersTableProps extends MetricsTableProps {
allowFilter?: boolean;

View file

@ -1,7 +1,7 @@
import { MetricsTable, MetricsTableProps } from './MetricsTable';
import { FilterLink } from '@/components/common/FilterLink';
import { useMessages } from '@/components/hooks';
import { Flexbox } from 'react-basics';
import { Flexbox } from '@umami/react-zen';
export function TagsTable(props: MetricsTableProps) {
const { formatMessage, labels } = useMessages();