Files
2026-08-02 10:43:58 -07:00

186 lines
4.5 KiB
TypeScript

import { X } from '@hanzogui/lucide-icons-2'
import { memo } from 'react'
import { useWindowDimensions } from 'react-native'
import type { DialogCloseProps } from '@hanzo/gui'
import {
Button,
Dialog,
Fieldset,
Input,
Label,
Unspaced,
XStack,
YStack,
} from '@hanzo/gui'
import { rootStore } from '../state/RootStore'
import type {
ConfirmDeleteDialogProps,
CreateThemeDialogProps,
DialogTypes,
StudioAlertDialogProps,
} from '../state/types'
import { useGlobalState } from '../state/useGlobalState'
const DialogCloseButton = () => (
<Unspaced>
<Dialog.Close asChild="except-style">
<Button size="$3" position="absolute" t="$3" r="$3" circular icon={X} z={1000} />
</Dialog.Close>
</Unspaced>
)
export const Dialogs = memo(() => {
const state = useGlobalState()
const DialogContents = dialogs[state.dialog]
const dialogProps = state.dialogProps as any
const dimensions = useWindowDimensions()
if (!DialogContents) {
return null
}
return (
<Dialog
modal
open={state.dialog !== 'none'}
onOpenChange={(val) => {
if (val === false) {
rootStore.hideDialog()
}
}}
>
<Dialog.Portal zIndex={10000000000}>
<Dialog.Overlay
transition="quick"
opacity={0.5}
enterStyle={{ opacity: 0 }}
exitStyle={{ opacity: 0 }}
/>
<Dialog.Content
onPointerDownOutside={() => {
rootStore.hideDialog()
}}
elevate
key="content"
transition={[
'quickest',
{
opacity: {
overshootClamping: true,
},
},
]}
enterStyle={{ x: 0, y: -20, opacity: 0, scale: 0.9 }}
exitStyle={{ x: 0, y: 10, opacity: 0, scale: 0.95 }}
x={0}
scale={1}
opacity={1}
y={0}
maxW={dimensions.width * 75}
p="$5"
>
<DialogContents {...dialogProps} />
</Dialog.Content>
</Dialog.Portal>
</Dialog>
)
})
const DialogClose = (props: DialogCloseProps) => {
return (
<Dialog.Close
asChild
{...props}
onPress={() => {
rootStore.setConfirmationStatus(true)
}}
/>
)
}
const CreateThemeDialog = (props: CreateThemeDialogProps) => {
return (
<>
<DialogCloseButton />
<YStack gap="$4">
<YStack gap="$2">
<Dialog.Title size="$7">Create Theme</Dialog.Title>
<Dialog.Description size="$3" color="$color9">
Create a new theme in scope {props.category}.
</Dialog.Description>
</YStack>
<Fieldset gap="$4" horizontal>
<Label size="$3" width={160} justify="flex-end" htmlFor="theme-name">
Name
</Label>
<Input size="$3" flex={1} id="theme-name" />
</Fieldset>
<DialogClose>
<Button aria-label="Close">Create</Button>
</DialogClose>
</YStack>
</>
)
}
const ConfirmDeleteDialog = (props: ConfirmDeleteDialogProps) => {
return (
<>
<DialogCloseButton />
<YStack gap="$6" p="$2">
<YStack gap="$2">
<Dialog.Title size="$7">Delete {props.thingName}?</Dialog.Title>
<Dialog.Description size="$3" color="$color9">
Are you sure you want to delete {props.thingName}?
</Dialog.Description>
</YStack>
<XStack justify="flex-end" gap="$4">
<Dialog.Close asChild>
<Button>Cancel</Button>
</Dialog.Close>
<DialogClose>
<Button theme="red" aria-label="Close">
Delete
</Button>
</DialogClose>
</XStack>
</YStack>
</>
)
}
const AlertDialog = (props: StudioAlertDialogProps) => {
return (
<>
<DialogCloseButton />
<YStack gap="$6" p="$2">
<YStack gap="$2">
<Dialog.Title size="$7">{props.title}</Dialog.Title>
<Dialog.Description size="$3" color="$color9">
{props.message}
</Dialog.Description>
</YStack>
<XStack justify="flex-end" gap="$4">
<DialogClose>
<Button theme="accent" aria-label="Ok">
Ok
</Button>
</DialogClose>
</XStack>
</YStack>
</>
)
}
const dialogs: {
[Key in keyof DialogTypes]: (props: DialogTypes[Key]) => any
} = {
none: AlertDialog,
'create-theme': CreateThemeDialog,
'confirm-delete': ConfirmDeleteDialog,
alert: AlertDialog,
}