|
1 | 1 | import { |
2 | | - AlertDialog, |
3 | | - AlertDialogBody, |
4 | | - AlertDialogContent, |
5 | | - AlertDialogFooter, |
6 | | - AlertDialogHeader, |
7 | | - AlertDialogOverlay, |
8 | 2 | Avatar, |
9 | 3 | Badge, |
10 | 4 | Box, |
@@ -48,19 +42,12 @@ const PopoverBodyAny = PopoverBody as unknown as React.FC< |
48 | 42 | Record<string, unknown> |
49 | 43 | > |
50 | 44 |
|
51 | | -const AlertDialogContentAny = AlertDialogContent as unknown as React.FC< |
52 | | - Record<string, unknown> |
53 | | -> |
54 | | - |
55 | 45 | const BoxAny = Box as unknown as React.FC<Record<string, unknown>> |
56 | 46 | const TextAny = Text as unknown as React.ElementType |
57 | 47 | const FlexAny = Flex as unknown as React.ElementType |
58 | 48 | const DividerAny = Divider as unknown as React.ElementType |
59 | 49 | const ButtonAny = Button as unknown as React.ElementType |
60 | 50 | const IconAny = Icon as unknown as React.ElementType |
61 | | -const AlertDialogHeaderAny = AlertDialogHeader as unknown as React.ElementType |
62 | | -const AlertDialogBodyAny = AlertDialogBody as unknown as React.ElementType |
63 | | -const AlertDialogFooterAny = AlertDialogFooter as unknown as React.ElementType |
64 | 51 | const InputGroupAny = InputGroup as unknown as React.ElementType |
65 | 52 | const InputLeftElementAny = InputLeftElement as unknown as React.ElementType |
66 | 53 | const InputAny = Input as unknown as React.ElementType |
@@ -88,7 +75,7 @@ export function TemplatesDropdown({ |
88 | 75 | ) |
89 | 76 | const searchRef = useRef<HTMLInputElement>(null) |
90 | 77 | const resultsScrollRef = useRef<HTMLDivElement>(null) |
91 | | - const cancelRef = useRef<HTMLButtonElement>(null) |
| 78 | + |
92 | 79 | const [isSavingAndContinuing, setIsSavingAndContinuing] = useState(false) |
93 | 80 |
|
94 | 81 | const [pendingTemplate, setPendingTemplate] = useState<TemplateRecord | null>( |
@@ -651,91 +638,164 @@ export function TemplatesDropdown({ |
651 | 638 | </PopoverContentAny> |
652 | 639 | </Popover> |
653 | 640 |
|
654 | | - <AlertDialog |
655 | | - isOpen={pendingTemplate !== null} |
656 | | - leastDestructiveRef={cancelRef} |
657 | | - onClose={() => { |
658 | | - if (isSavingAndContinuing) return |
659 | | - setPendingTemplate(null) |
660 | | - }} |
661 | | - isCentered |
662 | | - > |
663 | | - <AlertDialogOverlay> |
664 | | - <AlertDialogContentAny |
665 | | - w="45vw" |
666 | | - maxW="45vw" |
667 | | - h="40vh" |
668 | | - maxH="40vh" |
| 641 | + {pendingTemplate !== null && ( |
| 642 | + <Box |
| 643 | + position="fixed" |
| 644 | + inset={0} |
| 645 | + bg="blackAlpha.400" |
| 646 | + display="flex" |
| 647 | + alignItems="center" |
| 648 | + justifyContent="center" |
| 649 | + zIndex={1500} |
| 650 | + onClick={() => { |
| 651 | + if (isSavingAndContinuing) return |
| 652 | + setPendingTemplate(null) |
| 653 | + }} |
| 654 | + > |
| 655 | + <Box |
| 656 | + w="40vw" |
| 657 | + maxW="40vw" |
669 | 658 | bg="white" |
670 | 659 | borderRadius="xl" |
671 | | - overflow="hidden" |
672 | 660 | boxShadow="xl" |
673 | 661 | display="flex" |
674 | 662 | flexDirection="column" |
| 663 | + onClick={(e) => e.stopPropagation()} |
675 | 664 | > |
676 | | - <AlertDialogHeaderAny |
677 | | - fontSize="lg" |
678 | | - fontWeight="semibold" |
679 | | - color="editorGray.900" |
| 665 | + {/* Header */} |
| 666 | + <FlexAny |
680 | 667 | px="6" |
681 | 668 | py="4" |
682 | | - borderBottomWidth="0.5px" |
683 | | - borderColor="editorGray.50" |
684 | | - > |
685 | | - Unsaved changes |
686 | | - </AlertDialogHeaderAny> |
687 | | - <AlertDialogBodyAny |
688 | | - fontSize="lg" |
689 | | - color="editorGray.700" |
690 | | - p="6" |
691 | | - flex="1" |
692 | | - overflowY="auto" |
| 669 | + alignItems="center" |
| 670 | + justifyContent="space-between" |
| 671 | + borderBottomWidth="1px" |
| 672 | + borderColor="editorGray.300" |
693 | 673 | > |
694 | | - Your current changes haven't been saved yet. What would you like |
695 | | - to do before switching to{" "} |
696 | | - <Box as="span" fontWeight="semibold"> |
697 | | - {pendingTemplate |
698 | | - ? formatTemplateNameForUI(pendingTemplate.name) |
699 | | - : null} |
700 | | - </Box> |
701 | | - ? |
702 | | - </AlertDialogBodyAny> |
703 | | - <AlertDialogFooterAny |
704 | | - p="6" |
705 | | - borderTopWidth="0.5px" |
706 | | - borderColor="editorGray.50" |
| 674 | + <TextAny |
| 675 | + fontSize="lg" |
| 676 | + fontWeight="semibold" |
| 677 | + color="editorGray.900" |
| 678 | + > |
| 679 | + Unsaved changes |
| 680 | + </TextAny> |
| 681 | + </FlexAny> |
| 682 | + |
| 683 | + {/* Body */} |
| 684 | + <Box px="6" py="6" flex="1"> |
| 685 | + <TextAny fontSize="sm" color="editorGray.700" lineHeight="1.6"> |
| 686 | + Your current changes haven't been saved yet. What would you |
| 687 | + like to do before switching to{" "} |
| 688 | + <Box as="span" fontWeight="semibold" color="editorGray.900"> |
| 689 | + {formatTemplateNameForUI(pendingTemplate.name)} |
| 690 | + </Box> |
| 691 | + ? |
| 692 | + </TextAny> |
| 693 | + </Box> |
| 694 | + |
| 695 | + {/* Footer */} |
| 696 | + <FlexAny |
| 697 | + px="6" |
| 698 | + py="4" |
| 699 | + alignItems="center" |
| 700 | + justifyContent="flex-end" |
707 | 701 | gap="3" |
| 702 | + borderTopWidth="1px" |
| 703 | + borderColor="editorGray.300" |
708 | 704 | > |
709 | | - <ButtonAny |
710 | | - ref={cancelRef} |
711 | | - size="md" |
712 | | - variant="ghost" |
713 | | - onClick={() => setPendingTemplate(null)} |
714 | | - isDisabled={isSavingAndContinuing} |
| 705 | + {/* Cancel */} |
| 706 | + <Box |
| 707 | + as="button" |
| 708 | + display="inline-flex" |
| 709 | + alignItems="center" |
| 710 | + px="4" |
| 711 | + py="2" |
| 712 | + borderRadius="md" |
| 713 | + fontSize="sm" |
| 714 | + fontWeight="medium" |
| 715 | + color={isSavingAndContinuing ? "gray.400" : "editorGray.700"} |
| 716 | + cursor={isSavingAndContinuing ? "not-allowed" : "pointer"} |
| 717 | + _hover={{ bg: isSavingAndContinuing ? undefined : "gray.50" }} |
| 718 | + onClick={ |
| 719 | + isSavingAndContinuing |
| 720 | + ? undefined |
| 721 | + : () => setPendingTemplate(null) |
| 722 | + } |
| 723 | + aria-disabled={isSavingAndContinuing} |
715 | 724 | > |
716 | 725 | Cancel |
717 | | - </ButtonAny> |
718 | | - <ButtonAny |
719 | | - size="md" |
720 | | - variant="outline" |
721 | | - onClick={handleContinueWithoutSaving} |
722 | | - isDisabled={isSavingAndContinuing} |
| 726 | + </Box> |
| 727 | + |
| 728 | + {/* Continue without saving */} |
| 729 | + <Box |
| 730 | + as="button" |
| 731 | + display="inline-flex" |
| 732 | + alignItems="center" |
| 733 | + px="4" |
| 734 | + py="2" |
| 735 | + borderRadius="md" |
| 736 | + borderWidth="1px" |
| 737 | + borderColor={isSavingAndContinuing ? "gray.200" : "gray.300"} |
| 738 | + fontSize="sm" |
| 739 | + fontWeight="medium" |
| 740 | + color={isSavingAndContinuing ? "gray.400" : "editorGray.700"} |
| 741 | + cursor={isSavingAndContinuing ? "not-allowed" : "pointer"} |
| 742 | + _hover={{ bg: isSavingAndContinuing ? undefined : "gray.50" }} |
| 743 | + onClick={ |
| 744 | + isSavingAndContinuing |
| 745 | + ? undefined |
| 746 | + : handleContinueWithoutSaving |
| 747 | + } |
| 748 | + aria-disabled={isSavingAndContinuing} |
723 | 749 | > |
724 | 750 | Continue without saving |
725 | | - </ButtonAny> |
726 | | - <ButtonAny |
727 | | - size="md" |
728 | | - colorScheme="blue" |
729 | | - onClick={handleSaveAndContinue} |
730 | | - isLoading={isSavingAndContinuing} |
731 | | - isDisabled={templateStorageWriteBlocked} |
| 751 | + </Box> |
| 752 | + |
| 753 | + {/* Save and continue */} |
| 754 | + <Box |
| 755 | + as="button" |
| 756 | + display="inline-flex" |
| 757 | + alignItems="center" |
| 758 | + gap="2" |
| 759 | + px="4" |
| 760 | + py="2" |
| 761 | + borderRadius="md" |
| 762 | + bg={ |
| 763 | + isSavingAndContinuing || templateStorageWriteBlocked |
| 764 | + ? "blue.200" |
| 765 | + : "blue.500" |
| 766 | + } |
| 767 | + color="white" |
| 768 | + fontSize="sm" |
| 769 | + fontWeight="medium" |
| 770 | + cursor={ |
| 771 | + isSavingAndContinuing || templateStorageWriteBlocked |
| 772 | + ? "not-allowed" |
| 773 | + : "pointer" |
| 774 | + } |
| 775 | + _hover={{ |
| 776 | + bg: |
| 777 | + isSavingAndContinuing || templateStorageWriteBlocked |
| 778 | + ? "blue.200" |
| 779 | + : "blue.600", |
| 780 | + }} |
| 781 | + onClick={ |
| 782 | + isSavingAndContinuing || templateStorageWriteBlocked |
| 783 | + ? undefined |
| 784 | + : handleSaveAndContinue |
| 785 | + } |
| 786 | + aria-disabled={ |
| 787 | + isSavingAndContinuing || templateStorageWriteBlocked |
| 788 | + } |
732 | 789 | > |
733 | | - Save and continue |
734 | | - </ButtonAny> |
735 | | - </AlertDialogFooterAny> |
736 | | - </AlertDialogContentAny> |
737 | | - </AlertDialogOverlay> |
738 | | - </AlertDialog> |
| 790 | + {isSavingAndContinuing && ( |
| 791 | + <SpinnerAny size="xs" color="white" /> |
| 792 | + )} |
| 793 | + {isSavingAndContinuing ? "Saving…" : "Save and continue"} |
| 794 | + </Box> |
| 795 | + </FlexAny> |
| 796 | + </Box> |
| 797 | + </Box> |
| 798 | + )} |
739 | 799 | </> |
740 | 800 | ) |
741 | 801 | } |
0 commit comments