-
-
-
- {alt}
-
-
- {hasBadge && (
-
- {badgeContent}
-
+
+ style={{ width: sizeClass, height: sizeClass }}
+ role='img'
+ aria-label={alt}
+ >
+
+
+ {alt}
+
+
);
};
diff --git a/src/components/atoms/avatar/types.ts b/src/components/atoms/avatar/types.ts
index 3936299e..ec51360c 100644
--- a/src/components/atoms/avatar/types.ts
+++ b/src/components/atoms/avatar/types.ts
@@ -1,4 +1,4 @@
-import type { ReactNode } from 'react';
+type ThemeRounded = 'md' | 'full' | 'none';
export type AvatarProps = {
/** @control src */
@@ -9,13 +9,6 @@ export type AvatarProps = {
alt: string;
/** @control text */
className?: string;
- /**
- * @control boolean
- * @default false
- */
- hasBadge?: boolean;
- /** @control text */
- badgeContent?: string | ReactNode;
- /** @control text */
- badgeClassName?: string;
+ /** @control select */
+ rounded?: ThemeRounded;
};
diff --git a/src/components/atoms/avatar/useAvatar.ts b/src/components/atoms/avatar/useAvatar.ts
new file mode 100644
index 00000000..727dc2fe
--- /dev/null
+++ b/src/components/atoms/avatar/useAvatar.ts
@@ -0,0 +1,33 @@
+import type { AvatarProps } from './types';
+
+export const useAvatar = ({ src, alt = 'EG', className, size = 'md', rounded = 'md' }: AvatarProps) => {
+ const sizeClasses = {
+ sm: '30px',
+ md: '40px',
+ lg: '50px',
+ xl: '60px',
+ '2xl': '70px',
+ '3xl': '80px'
+ };
+ const textClasses = {
+ sm: 'text-[0.8em]',
+ md: 'text-[1em]',
+ lg: 'text-[1.2em]',
+ xl: 'text-[1.4em]',
+ '2xl': 'text-[1.6em]',
+ '3xl': 'text-[1.8em]'
+ };
+
+ const roundedClass = rounded ? `rounded-${rounded}` : '';
+ const sizeClass = sizeClasses[size];
+ const textClass = textClasses[size];
+
+ return {
+ src,
+ alt,
+ className,
+ sizeClass,
+ textClass,
+ roundedClass
+ };
+};
diff --git a/src/components/atoms/dropdown/Dropdown.tsx b/src/components/atoms/dropdown/Dropdown.tsx
index 0152b124..4e6b2f98 100644
--- a/src/components/atoms/dropdown/Dropdown.tsx
+++ b/src/components/atoms/dropdown/Dropdown.tsx
@@ -1,8 +1,10 @@
import { cn } from '@/lib/utils';
import * as DropdownMenuPrimitive from '@radix-ui/react-dropdown-menu';
import { ChevronRightIcon } from 'lucide-react';
+import type { FC } from 'react';
import { SpinnerCircular } from 'spinners-react';
import type { DropdownElement, DropdownProps } from './types';
+import { useDropdown } from './useDropdown';
const renderDropdownItem = (element: DropdownElement, index: number) => {
if (element.type === 'item') {
@@ -15,6 +17,7 @@ const renderDropdownItem = (element: DropdownElement, index: number) => {
className={cn(
'relative flex cursor-default justify-between items-center gap-2 rounded-sm px-2 py-1.5 text-sm',
'transition-opacity duration-300 ease-in-out',
+ 'hover:outline-offset-1 dark:hover:outline-white hover:outline-secondary hover:outline-1',
'focus-visible:outline-offset-1 dark:focus-visible:outline-white focus-visible:outline-secondary focus-visible:outline-1',
element.variant === 'destructive' && 'bg-secondary text-text-dark hover:bg-red-secondary-hover'
)}
@@ -40,6 +43,7 @@ const renderDropdownSubmenu = (element: DropdownElement, index: number) => {
className={cn(
'flex items-center rounded-md justify-between px-2 py-1.5 text-sm',
'transition-opacity duration-300 ease-in-out',
+ 'hover:outline-offset-1 dark:hover:outline-white hover:outline-secondary hover:outline-1',
'focus-visible:outline-offset-1 dark:focus-visible:outline-white focus-visible:outline-secondary focus-visible:outline-1'
)}
>
@@ -92,34 +96,26 @@ const renderDropdownElement = (element: DropdownElement, index: number) => {
}
};
-const Dropdown = ({
- width = '56px',
- position = 'bottom',
- align = 'center',
- offset = 1,
- closeOnSelect = true,
- items,
- loading = false,
- children,
- className
-}: DropdownProps) => {
- const marginClasses = {
- top: 'mb-2',
- bottom: 'mt-2',
- left: 'mr-2',
- right: 'ml-2'
- };
-
- const firstLabelId = items.find((item) => item.type === 'label')?.label
- ? `dropdown-label-${items.findIndex((item) => item.type === 'label')}`
- : undefined;
- const fallbackId = 'dropdown-fallback-label';
- const accessibleLabelId = firstLabelId || fallbackId;
+const Dropdown: FC
= ({ ...props }) => {
+ const {
+ items,
+ loading,
+ closeOnSelect,
+ position,
+ align,
+ offset,
+ width,
+ className,
+ accessibleLabelId,
+ marginClasses,
+ firstLabelId,
+ fallbackId
+ } = useDropdown(props);
return (
- {children}
+ {props.children}
{
+ const marginClasses = {
+ top: 'mb-2',
+ bottom: 'mt-2',
+ left: 'mr-2',
+ right: 'ml-2'
+ };
+
+ const firstLabelId = items.find((item) => item.type === 'label')?.label
+ ? `dropdown-label-${items.findIndex((item) => item.type === 'label')}`
+ : undefined;
+ const fallbackId = 'dropdown-fallback-label';
+ const accessibleLabelId = firstLabelId || fallbackId;
+
+ return {
+ items,
+ loading,
+ closeOnSelect,
+ position,
+ align,
+ offset,
+ width,
+ className,
+ accessibleLabelId,
+ marginClasses,
+ firstLabelId,
+ fallbackId
+ };
+};
diff --git a/src/components/atoms/icon-button/types.ts b/src/components/atoms/icon-button/types.ts
index b17430ba..2266bb3d 100644
--- a/src/components/atoms/icon-button/types.ts
+++ b/src/components/atoms/icon-button/types.ts
@@ -3,7 +3,7 @@ import { type VariantProps, cva } from 'class-variance-authority';
export const iconButtonVariants = cva(
[
- 'link relative overflow-hidden border-2 cursor-pointer px-2 py-2 max-w-full',
+ 'link relative overflow-hidden border-2 cursor-pointer px-1 py-1 max-w-full',
'transition-all duration-200 ease-in-out',
'flex items-center justify-start',
'whitespace-nowrap line-clamp-1 ',