0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-01-20 22:42:53 -05:00

Added More menu for feed items and static Delete menu item

ref https://linear.app/tryghost/issue/AP-308/ui-for-deleting-replies

- Added `dotdotdot` icon
- Added optional `destructive` prop to `Menu` items
This commit is contained in:
Djordje Vlaisavljevic 2024-09-16 23:53:35 +01:00 committed by Fabien 'egg' O'Carroll
parent c41c44b02d
commit 1680817da2
3 changed files with 51 additions and 11 deletions

View file

@ -1,6 +1,6 @@
import React, {useState} from 'react'; import React, {useState} from 'react';
import {ActorProperties, ObjectProperties} from '@tryghost/admin-x-framework/api/activitypub'; import {ActorProperties, ObjectProperties} from '@tryghost/admin-x-framework/api/activitypub';
import {Button, Heading, Icon} from '@tryghost/admin-x-design-system'; import {Button, Heading, Icon, Menu, MenuItem} from '@tryghost/admin-x-design-system';
import APAvatar from '../global/APAvatar'; import APAvatar from '../global/APAvatar';
@ -220,11 +220,37 @@ const FeedItem: React.FC<FeedItemProps> = ({actor, object, layout, type, comment
// Don't need to know about setting timeouts or anything like that // Don't need to know about setting timeouts or anything like that
}; };
const handleDelete = () => {
// Handle delete action
};
let author = actor; let author = actor;
if (type === 'Announce' && object.type === 'Note') { if (type === 'Announce' && object.type === 'Note') {
author = typeof object.attributedTo === 'object' ? object.attributedTo as ActorProperties : actor; author = typeof object.attributedTo === 'object' ? object.attributedTo as ActorProperties : actor;
} }
const menuItems: MenuItem[] = [];
// TODO: If this is your own Note/Article, you should be able to delete it
menuItems.push({
id: 'delete',
label: 'Delete',
destructive: true,
onClick: handleDelete
});
const UserMenuTrigger = (
<Button
className='relative z-10 ml-auto self-start'
hideLabel={true}
icon='dotdotdot'
iconColorClass='text-grey-600'
id='more'
size='sm'
unstyled={true}
/>
);
if (layout === 'feed') { if (layout === 'feed') {
return ( return (
<> <>
@ -236,15 +262,18 @@ const FeedItem: React.FC<FeedItemProps> = ({actor, object, layout, type, comment
</div>} </div>}
<div className={`border-1 z-10 -my-1 grid grid-cols-[auto_1fr] grid-rows-[auto_1fr] gap-x-3 gap-y-2 border-b-grey-200 pb-6`} data-test-activity> <div className={`border-1 z-10 -my-1 grid grid-cols-[auto_1fr] grid-rows-[auto_1fr] gap-x-3 gap-y-2 border-b-grey-200 pb-6`} data-test-activity>
<APAvatar author={author}/> <APAvatar author={author}/>
{/* <div className='border-1 z-10 -mt-1 flex w-full flex-col items-start justify-between border-b border-b-grey-200 pb-4' data-test-activity> */} <div className='flex justify-between'>
<div className='relative z-10 flex w-full flex-col overflow-visible text-[1.5rem]'> <div className='relative z-10 flex w-full flex-col overflow-visible text-[1.5rem]'>
<div className='flex'> <div className='flex'>
<span className='truncate whitespace-nowrap font-bold' data-test-activity-heading>{author.name}</span> <span className='truncate whitespace-nowrap font-bold' data-test-activity-heading>{author.name}</span>
<span className='whitespace-nowrap text-grey-700 before:mx-1 before:content-["·"]' title={`${timestamp}`}>{getRelativeTimestamp(date)}</span> <span className='whitespace-nowrap text-grey-700 before:mx-1 before:content-["·"]' title={`${timestamp}`}>{getRelativeTimestamp(date)}</span>
</div> </div>
<div className='flex'> <div className='flex'>
<span className='truncate text-grey-700'>{getUsername(author)}</span> <span className='truncate text-grey-700'>{getUsername(author)}</span>
</div>
</div> </div>
<Menu items={menuItems} position='end' trigger={UserMenuTrigger}/>
</div> </div>
<div className={`relative z-10 col-start-2 col-end-3 w-full gap-4`}> <div className={`relative z-10 col-start-2 col-end-3 w-full gap-4`}>
<div className='flex flex-col'> <div className='flex flex-col'>

View file

@ -0,0 +1,10 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<defs>
<style>
circle{fill:currentColor}
</style>
</defs>
<circle cx="3.25" cy="12" r="2.6"/>
<circle cx="12" cy="12" r="2.6"/>
<circle cx="20.75" cy="12" r="2.6"/>
</svg>

After

Width:  |  Height:  |  Size: 256 B

View file

@ -5,6 +5,7 @@ import Popover, {PopoverPosition} from './Popover';
export type MenuItem = { export type MenuItem = {
id: string, id: string,
label: string; label: string;
destructive?: boolean;
onClick?: () => void onClick?: () => void
} }
@ -23,14 +24,14 @@ const Menu: React.FC<MenuProps> = ({
position = 'start' position = 'start'
}) => { }) => {
if (!trigger) { if (!trigger) {
trigger = <Button icon='ellipsis' label='Menu' hideLabel {...triggerButtonProps} />; trigger = <Button icon='ellipsis' label='Menu' hideLabel {...triggerButtonProps}/>;
} }
return ( return (
<Popover position={position} trigger={trigger} closeOnItemClick> <Popover position={position} trigger={trigger} closeOnItemClick>
<div className="flex min-w-[160px] flex-col justify-stretch py-1" role="none"> <div className="flex min-w-[160px] flex-col justify-stretch py-1" role="none">
{items.map(item => ( {items.map(item => (
<button key={item.id} className="mx-1 block cursor-pointer rounded-[2.5px] px-4 py-1.5 text-left text-sm hover:bg-grey-100 dark:hover:bg-grey-800" type="button" onClick={item.onClick}>{item.label}</button> <button key={item.id} className={`mx-1 block cursor-pointer rounded-[2.5px] px-4 py-1.5 text-left text-sm hover:bg-grey-100 ${item.destructive && ' text-red-500'}`} type="button" onClick={item.onClick}>{item.label}</button>
))} ))}
</div> </div>
</Popover> </Popover>