Added DialogButton to handle mobile.
Some checks are pending
Create docker images (cloud) / Build, push, and deploy (push) Waiting to run
Node.js CI / build (postgresql, 18.18, 10) (push) Waiting to run

This commit is contained in:
Mike Cao 2025-10-16 23:59:18 -07:00
parent 036748cdeb
commit 40492ec7c4
32 changed files with 2146 additions and 1807 deletions

View file

@ -1,25 +0,0 @@
import { ReactNode } from 'react';
import { Button, Icon, Modal, Text, DialogTrigger } from '@umami/react-zen';
export function ActionButton({
onClick,
icon,
title,
children,
}: {
onClick?: () => void;
icon?: ReactNode;
title?: string;
children?: ReactNode;
}) {
return (
<DialogTrigger>
<Text title={title}>
<Button variant="quiet" onPress={onClick}>
<Icon>{icon}</Icon>
</Button>
</Text>
<Modal>{children}</Modal>
</DialogTrigger>
);
}

View file

@ -0,0 +1,57 @@
import { CSSProperties, ReactNode } from 'react';
import {
Button,
ButtonProps,
Modal,
Dialog,
DialogTrigger,
DialogProps,
IconLabel,
} from '@umami/react-zen';
import { useMobile } from '@/components/hooks';
export interface DialogButtonProps extends Omit<ButtonProps, 'children'> {
icon?: ReactNode;
label?: ReactNode;
title?: ReactNode;
width?: string;
height?: string;
minWidth?: string;
minHeight?: string;
children?: DialogProps['children'];
}
export function DialogButton({
icon,
label,
title,
width = '800px',
height,
minWidth,
minHeight,
children,
...props
}: DialogButtonProps) {
const { isMobile } = useMobile();
const style: CSSProperties = { width, height, minWidth, minHeight, padding: '32px' };
if (isMobile) {
style.width = '100%';
style.height = '100%';
style.overflowY = 'auto';
}
return (
<DialogTrigger>
<Button {...props}>
<IconLabel icon={icon} label={label} />
</Button>
<Modal placement={isMobile ? 'fullscreen' : 'center'}>
<Dialog variant={isMobile ? 'sheet' : undefined} title={title || label} style={style}>
{children}
</Dialog>
</Modal>
</DialogTrigger>
);
}

View file

@ -13,7 +13,7 @@ import {
MenuItem,
Icon,
} from '@umami/react-zen';
import { useFields, useMessages } from '@/components/hooks';
import { useFields, useMessages, useMobile } from '@/components/hooks';
import { Plus } from '@/components/icons';
import { FilterRecord } from '@/components/common/FilterRecord';
import { Empty } from '@/components/common/Empty';
@ -30,6 +30,7 @@ export function FieldFilters({ websiteId, value, exclude = [], onChange }: Field
const { fields } = useFields();
const startDate = subMonths(endOfDay(new Date()), 6);
const endDate = endOfDay(new Date());
const { isMobile } = useMobile();
const updateFilter = (name: string, props: Record<string, any>) => {
onChange(value.map(filter => (filter.name === name ? { ...filter, ...props } : filter)));
@ -60,8 +61,11 @@ export function FieldFilters({ websiteId, value, exclude = [], onChange }: Field
<Plus />
</Icon>
</Button>
<Popover placement="bottom start">
<Menu onAction={handleAdd}>
<Popover placement={isMobile ? 'left' : 'bottom start'} shouldFlip>
<Menu
onAction={handleAdd}
style={{ maxHeight: 'calc(100vh - 2rem)', overflowY: 'auto' }}
>
{fields
.filter(({ name }) => !exclude.includes(name))
.map(field => {

View file

@ -34,7 +34,7 @@ export function WebsiteFilterButton({
</Icon>
{showText && <Text>{formatMessage(labels.filter)}</Text>}
</Button>
<Modal position={isMobile ? 'fullscreen' : 'center'}>
<Modal placement={isMobile ? 'fullscreen' : 'center'}>
<Dialog title={formatMessage(labels.filters)}>
{({ close }) => {
return <FilterEditForm websiteId={websiteId} onChange={handleChange} onClose={close} />;