0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-06 22:40:14 -05:00

Added SortMenu component to the design system (#19045)

refs https://github.com/TryGhost/Product/issues/4162

- this component is based on the existing PopOver component, and
customized for sorting function
This commit is contained in:
Sodbileg Gansukh 2023-11-21 09:48:41 +08:00 committed by GitHub
parent a398067159
commit 63f0265e28
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 110 additions and 0 deletions

View file

@ -0,0 +1,32 @@
import type {Meta, StoryObj} from '@storybook/react';
import SortMenu from './SortMenu';
const meta = {
title: 'Global / SortMenu',
component: SortMenu,
tags: ['autodocs']
} satisfies Meta<typeof SortMenu>;
export default meta;
type Story = StoryObj<typeof SortMenu>;
const items = [
{id: 'date-added', label: 'Date added', selected: true},
{id: 'name', label: 'Name'},
{id: 'redemptions', label: 'Redemptions'}
];
export const Default: Story = {
args: {
items: items,
onSortChange: () => {},
onDirectionChange: () => {},
position: 'left'
},
decorators: [
ThisStory => (
<div style={{maxWidth: '100px', margin: '0 auto'}}><ThisStory /></div>
)
]
};

View file

@ -0,0 +1,76 @@
import React, {useState, useEffect} from 'react';
import Button, {ButtonProps} from './Button';
import Popover, {PopoverPosition} from './Popover';
import {Icon} from '..';
export type SortItem = {
id: string,
label: string;
selected?: boolean;
}
export interface SortMenuProps {
items: SortItem[];
direction: string;
onSortChange: (selectedOption: string) => void;
onDirectionChange: (selectedDirection: string) => void;
trigger?: React.ReactNode;
triggerButtonProps?: ButtonProps;
position?: PopoverPosition;
}
const SortMenu: React.FC<SortMenuProps> = ({
items,
direction,
onSortChange,
onDirectionChange,
trigger,
triggerButtonProps,
position = 'left'
}) => {
const [localItems, setLocalItems] = useState<SortItem[]>(items);
const [localDirection, setLocalDirection] = useState<string>(direction || 'desc');
useEffect(() => {
setLocalItems(items);
}, [items]);
const handleSortChange = (selectedValue: string) => {
const updatedItems = localItems.map(item => ({
...item,
selected: item.id === selectedValue ? true : false
}));
setLocalItems(updatedItems);
onSortChange(selectedValue);
};
const handleSortDirection = () => {
setLocalDirection(currentDirection => (currentDirection === 'desc' ? 'asc' : 'desc'));
onDirectionChange(localDirection);
};
if (!trigger) {
trigger = <Button className='flex-row-reverse' icon={`${localDirection === 'asc' ? 'arrow-up' : 'arrow-down'}`} iconColorClass='!w-3 !h-3 !mr-0 ml-1.5' label={`${localItems.find(item => item.selected)?.label}`} {...triggerButtonProps} />;
}
return (
<Popover position={position} trigger={trigger}>
<div className="flex min-w-[160px] flex-col justify-stretch py-1" role="none">
{localItems.map(item => (
<button key={item.id} className="group relative mx-1 flex grow cursor-pointer items-center rounded-[2.5px] px-8 py-1.5 pr-12 text-left text-sm hover:bg-grey-100 dark:hover:bg-grey-800" type="button" onClick={() => {
handleSortChange(item.id);
}}>
{item.selected ? <Icon className='absolute left-2' name='check' size='sm' /> : null}
{item.label}
{item.selected ? <button className='absolute right-2 flex h-6 w-6 cursor-pointer items-center justify-center rounded-full bg-grey-200 opacity-0 group-hover:bg-grey-300 group-hover:opacity-100' title={`${localDirection === 'asc' ? 'Ascending' : 'Descending'}`} type='button' onClick={handleSortDirection}>
{localDirection === 'asc' ? <Icon name='arrow-up' size='xs' /> : <Icon name='arrow-down' size='xs' />}
</button> : null}
</button>
))}
</div>
</Popover>
);
};
export default SortMenu;

View file

@ -108,6 +108,8 @@ export {default as Separator} from './global/Separator';
export type {SeparatorProps} from './global/Separator';
export {DragIndicator, default as SortableList} from './global/SortableList';
export type {DragIndicatorProps, SortableItemContainerProps, SortableListProps} from './global/SortableList';
export {default as SortMenu} from './global/SortMenu';
export type {SortMenuProps} from './global/SortMenu';
export {default as StickyFooter} from './global/StickyFooter';
export type {StickyFooterProps} from './global/StickyFooter';
export {default as TabView} from './global/TabView';