mirror of
https://github.com/Sonny93/my-links.git
synced 2025-12-10 15:35:35 +00:00
feat: add dropdown component
This commit is contained in:
56
inertia/components/common/dropdown/dropdown.tsx
Normal file
56
inertia/components/common/dropdown/dropdown.tsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import KEYS from '#constants/keys';
|
||||
import styled from '@emotion/styled';
|
||||
import { ReactNode, useRef } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import DropdownContainer from '~/components/common/dropdown/dropdown_container';
|
||||
import DropdownLabel from '~/components/common/dropdown/dropdown_label';
|
||||
import useClickOutside from '~/hooks/use_click_outside';
|
||||
import useGlobalHotkeys from '~/hooks/use_global_hotkeys';
|
||||
import useToggle from '~/hooks/use_modal';
|
||||
|
||||
const DropdownStyle = styled.div<{ opened: boolean }>(({ opened, theme }) => ({
|
||||
cursor: 'pointer',
|
||||
userSelect: 'none',
|
||||
position: 'relative',
|
||||
minWidth: 'fit-content',
|
||||
width: 'fit-content',
|
||||
maxWidth: '250px',
|
||||
backgroundColor: opened ? theme.colors.secondary : theme.colors.background,
|
||||
padding: '4px',
|
||||
borderRadius: theme.border.radius,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.colors.secondary,
|
||||
},
|
||||
|
||||
'& svg': {
|
||||
height: '24px',
|
||||
width: '24px',
|
||||
},
|
||||
}));
|
||||
|
||||
export default function Dropdown({
|
||||
children,
|
||||
label,
|
||||
}: {
|
||||
children: ReactNode;
|
||||
label: ReactNode | string;
|
||||
}) {
|
||||
const dropdownRef = useRef<HTMLDivElement>(null);
|
||||
const { isShowing, toggle, close } = useToggle();
|
||||
const { globalHotkeysEnabled } = useGlobalHotkeys();
|
||||
|
||||
useClickOutside(dropdownRef, close);
|
||||
|
||||
useHotkeys(KEYS.ESCAPE_KEY, close, {
|
||||
enabled: globalHotkeysEnabled,
|
||||
enableOnFormTags: ['INPUT'],
|
||||
});
|
||||
|
||||
return (
|
||||
<DropdownStyle opened={isShowing} onClick={toggle} ref={dropdownRef}>
|
||||
<DropdownLabel>{label}</DropdownLabel>
|
||||
<DropdownContainer show={isShowing}>{children}</DropdownContainer>
|
||||
</DropdownStyle>
|
||||
);
|
||||
}
|
||||
17
inertia/components/common/dropdown/dropdown_container.tsx
Normal file
17
inertia/components/common/dropdown/dropdown_container.tsx
Normal file
@@ -0,0 +1,17 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const DropdownContainer = styled.div<{ show: boolean }>(({ show, theme }) => ({
|
||||
position: 'absolute',
|
||||
top: 'calc(100% + 0.5em)',
|
||||
right: 0,
|
||||
minWidth: '175px',
|
||||
backgroundColor: show ? theme.colors.secondary : theme.colors.background,
|
||||
border: `2px solid ${theme.colors.secondary}`,
|
||||
borderRadius: theme.border.radius,
|
||||
boxShadow: theme.colors.boxShadow,
|
||||
display: show ? 'flex' : 'none',
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden',
|
||||
}));
|
||||
|
||||
export default DropdownContainer;
|
||||
16
inertia/components/common/dropdown/dropdown_item.tsx
Normal file
16
inertia/components/common/dropdown/dropdown_item.tsx
Normal file
@@ -0,0 +1,16 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const DropdownItem = styled.div(({ theme }) => ({
|
||||
fontSize: '14px',
|
||||
padding: '8px 12px',
|
||||
display: 'flex',
|
||||
gap: '0.35em',
|
||||
alignItems: 'center',
|
||||
borderRadius: theme.border.radius,
|
||||
|
||||
'&:hover': {
|
||||
backgroundColor: theme.colors.background,
|
||||
},
|
||||
}));
|
||||
|
||||
export default DropdownItem;
|
||||
11
inertia/components/common/dropdown/dropdown_label.tsx
Normal file
11
inertia/components/common/dropdown/dropdown_label.tsx
Normal file
@@ -0,0 +1,11 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const DropdownLabel = styled.p(({ theme }) => ({
|
||||
height: 'auto',
|
||||
width: 'auto',
|
||||
color: theme.colors.font,
|
||||
display: 'flex',
|
||||
gap: '0.35em',
|
||||
}));
|
||||
|
||||
export default DropdownLabel;
|
||||
@@ -4,13 +4,16 @@ import { router } from '@inertiajs/react';
|
||||
import { ReactNode } from 'react';
|
||||
import { useHotkeys } from 'react-hotkeys-hook';
|
||||
import useGlobalHotkeys from '~/hooks/use_global_hotkeys';
|
||||
import useSearchParam from '~/hooks/use_search_param';
|
||||
import { appendCollectionId } from '~/lib/navigation';
|
||||
|
||||
export default function BackToDashboard({ children }: { children: ReactNode }) {
|
||||
const collectionId = useSearchParam('collectionId');
|
||||
const { globalHotkeysEnabled } = useGlobalHotkeys();
|
||||
useHotkeys(
|
||||
KEYS.ESCAPE_KEY,
|
||||
() => {
|
||||
router.visit(PATHS.DASHBOARD);
|
||||
router.visit(appendCollectionId(PATHS.DASHBOARD, collectionId));
|
||||
},
|
||||
{ enabled: globalHotkeysEnabled, enableOnFormTags: ['INPUT'] }
|
||||
);
|
||||
Reference in New Issue
Block a user