diff --git a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/selection-controls/index.tsx b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/selection-controls/index.tsx index a609e712d8..090b5a89ba 100644 --- a/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/selection-controls/index.tsx +++ b/apps/dashboard/app/(app)/apis/[apiId]/keys/[keyAuthId]/_components/components/table/components/selection-controls/index.tsx @@ -2,7 +2,7 @@ import { ConfirmPopover } from "@/components/confirmation-popover"; import type { KeyDetails } from "@/lib/trpc/routers/api/keys/query-api-keys/schema"; import { ArrowOppositeDirectionY, Ban, CircleCheck, Trash, XMark } from "@unkey/icons"; import { Button } from "@unkey/ui"; -import { AnimatePresence, motion } from "framer-motion"; +import { cn } from "@unkey/ui/src/lib/utils"; import { useRef, useState } from "react"; import { useDeleteKey } from "../actions/components/hooks/use-delete-key"; import { useBatchUpdateKeyStatus } from "../actions/components/hooks/use-update-key-status"; @@ -24,6 +24,7 @@ export const SelectionControls = ({ const [isBatchEditExternalIdOpen, setIsBatchEditExternalIdOpen] = useState(false); const [isDisableConfirmOpen, setIsDisableConfirmOpen] = useState(false); const [isDeleteConfirmOpen, setIsDeleteConfirmOpen] = useState(false); + const disableButtonRef = useRef(null); const deleteButtonRef = useRef(null); @@ -57,98 +58,84 @@ export const SelectionControls = ({ (key) => selectedKeys.has(key.id) && key.identity_id, ).length; + if (selectedKeys.size === 0) { + return null; + } + return ( <> - - {selectedKeys.size > 0 && ( - -
-
- -
selected
-
-
- - - - - -
-
-
+
+ > +
+
+ +
selected
+
+
+ + + + + +
+
+
setIsBatchEditExternalIdOpen(false)} /> )} - - ); -}; -const AnimatedDigit = ({ digit, index }: { digit: string; index: number }) => { - return ( - - {digit} - + + ); }; export const AnimatedCounter = ({ value }: { value: number }) => { - const digits = value.toString().split(""); - return (
- -
- {digits.map((digit, index) => ( - // biome-ignore lint/suspicious/noArrayIndexKey: - - ))} -
-
+ {value}
); }; diff --git a/apps/dashboard/components/virtual-table/components/loading-indicator.tsx b/apps/dashboard/components/virtual-table/components/loading-indicator.tsx index f33adb75f0..af13272c71 100644 --- a/apps/dashboard/components/virtual-table/components/loading-indicator.tsx +++ b/apps/dashboard/components/virtual-table/components/loading-indicator.tsx @@ -1,4 +1,6 @@ +import { ArrowsToAllDirections, ArrowsToCenter } from "@unkey/icons"; import { Button } from "@unkey/ui"; +import { useCallback, useState } from "react"; type LoadMoreFooterProps = { onLoadMore?: () => void; @@ -26,46 +28,179 @@ export const LoadMoreFooter = ({ hide, headerContent, }: LoadMoreFooterProps) => { + const [isOpen, setIsOpen] = useState(true); + const shouldShow = !!onLoadMore; + const handleClose = useCallback(() => { + setIsOpen(false); + }, []); + + const handleOpen = useCallback(() => { + setIsOpen(true); + }, []); + if (hide) { - return; + return null; + } + + // Minimized state - parked at right side + if (!isOpen) { + return ( +
+ +
+ + + ); } return (
-
+
- {headerContent} -
- {countInfoText &&
{countInfoText}
} + {/* Header content */} + {headerContent && ( +
+ {headerContent} +
+ )} + +
+ {countInfoText &&
{countInfoText}
} {!countInfoText && ( -
- Viewing {totalVisible} +
+ Viewing + + {totalVisible} + of - {totalCount} + {totalCount} {itemLabel}
)} - +
+ +
+ +
+
+ + {/* CSS Keyframes */} +
); }; diff --git a/internal/icons/src/icons/arrows-to-all-directions.tsx b/internal/icons/src/icons/arrows-to-all-directions.tsx new file mode 100644 index 0000000000..49a1abf683 --- /dev/null +++ b/internal/icons/src/icons/arrows-to-all-directions.tsx @@ -0,0 +1,116 @@ +/** + * Copyright © Nucleo + * Version 1.3, January 3, 2024 + * Nucleo Icons + * https://nucleoapp.com/ + * - Redistribution of icons is prohibited. + * - Icons are restricted for use only within the product they are bundled with. + * + * For more details: + * https://nucleoapp.com/license + */ +import type React from "react"; +import { type IconProps, sizeMap } from "../props"; + +export const ArrowsToAllDirections: React.FC = ({ size = "xl-thin", ...props }) => { + const { size: pixelSize, strokeWidth } = sizeMap[size]; + + return ( + + + + + + + + + + + + + + ); +}; diff --git a/internal/icons/src/icons/arrows-to-center.tsx b/internal/icons/src/icons/arrows-to-center.tsx new file mode 100644 index 0000000000..d8f1bfa201 --- /dev/null +++ b/internal/icons/src/icons/arrows-to-center.tsx @@ -0,0 +1,116 @@ +/** + * Copyright © Nucleo + * Version 1.3, January 3, 2024 + * Nucleo Icons + * https://nucleoapp.com/ + * - Redistribution of icons is prohibited. + * - Icons are restricted for use only within the product they are bundled with. + * + * For more details: + * https://nucleoapp.com/license + */ +import type React from "react"; +import { type IconProps, sizeMap } from "../props"; + +export const ArrowsToCenter: React.FC = ({ size = "xl-thin", ...props }) => { + const { size: pixelSize, strokeWidth } = sizeMap[size]; + + return ( + + + + + + + + + + + + + + ); +}; diff --git a/internal/icons/src/index.ts b/internal/icons/src/index.ts index 5f251f936f..b8b10f5719 100644 --- a/internal/icons/src/index.ts +++ b/internal/icons/src/index.ts @@ -4,6 +4,8 @@ export * from "./icons/arrow-dotted-rotate-anticlockwise"; export * from "./icons/arrow-opposite-direction-y"; export * from "./icons/arrow-right"; export * from "./icons/arrow-up-right"; +export * from "./icons/arrows-to-all-directions"; +export * from "./icons/arrows-to-center"; export * from "./icons/ban"; export * from "./icons/bars-filter"; export * from "./icons/bolt";