Skip to content

Commit

Permalink
Improved Inbox view UI (#21600)
Browse files Browse the repository at this point in the history
ref https://linear.app/ghost/issue/AP-521/improve-inbox-view-alignmentstructure

- Improved the layout, spacing and typography of Inbox view
- Removed attachment counters for images in Inbox view
- Added a very very small variant of `APAvatar`
  • Loading branch information
djordjevlais authored Nov 13, 2024
1 parent ead408e commit 5863c40
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 38 deletions.
6 changes: 3 additions & 3 deletions apps/admin-x-activitypub/src/components/Inbox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,9 +76,9 @@ const Inbox: React.FC<InboxProps> = ({}) => {
</div>
) : activities.length > 0 ? (
<>
<div className={`mx-auto flex items-start ${layout === 'inbox' ? 'max-w-6xl gap-14' : 'gap-8'}`}>
<div className={`mx-auto flex items-start gap-8`}>
<div className='flex w-full min-w-0 items-start'>
<ul className={`mx-auto flex ${layout === 'inbox' ? 'w-full max-w-full' : 'max-w-[500px]'} flex-col`}>
<ul className={`mx-auto flex w-full flex-col ${layout === 'inbox' ? 'xxxl:max-w-[800px]' : 'max-w-[500px]'}`}>
{activities.map((activity, index) => (
<li
key={activity.id}
Expand Down Expand Up @@ -106,7 +106,7 @@ const Inbox: React.FC<InboxProps> = ({}) => {
)}
</ul>
</div>
<div className={`sticky top-[135px] ml-auto w-full max-w-[300px] max-lg:hidden ${layout === 'inbox' ? '' : ' xxxl:fixed xxxl:right-[40px]'}`}>
<div className='sticky top-[135px] ml-auto w-full max-w-[300px] max-lg:hidden xxxl:sticky xxxl:right-[40px]'>
<h2 className='mb-2 text-lg font-semibold'>You might also like...</h2>
{isLoadingSuggested ? (
<LoadingIndicator size="sm" />
Expand Down
55 changes: 21 additions & 34 deletions apps/admin-x-activitypub/src/components/feed/FeedItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {Button, Heading, Icon, Menu, MenuItem, showToast} from '@tryghost/admin-
import APAvatar from '../global/APAvatar';

import FeedItemStats from './FeedItemStats';
import clsx from 'clsx';
import getRelativeTimestamp from '../../utils/get-relative-timestamp';
import getUsername from '../../utils/get-username';
import stripHtml from '../../utils/strip-html';
Expand Down Expand Up @@ -83,7 +84,7 @@ export function renderFeedAttachment(object: ObjectProperties, layout: string) {
</div>;
default:
if (object.image) {
return <img alt='attachment' className='my-3 max-h-[280px] w-full rounded-md object-cover outline outline-1 -outline-offset-1 outline-black/10' src={object.image} />;
return <img alt='attachment' className='my-3 max-h-[280px] w-full rounded-md object-cover outline outline-1 -outline-offset-1 outline-black/[0.05]' src={object.image} />;
}
return null;
}
Expand All @@ -92,20 +93,16 @@ export function renderFeedAttachment(object: ObjectProperties, layout: string) {
function renderInboxAttachment(object: ObjectProperties) {
const attachment = getAttachment(object);

const videoAttachmentStyles = 'ml-8 shrink-0 rounded-md h-[80px] w-[120px] relative';
const imageAttachmentStyles = clsx('object-cover outline outline-1 -outline-offset-1 outline-black/[0.05]', videoAttachmentStyles);

if (!attachment) {
return null;
}

if (Array.isArray(attachment)) {
const attachmentCount = attachment.length;

return (
<div className='min-w-[120px]'>
<div className='relative'>
<img className={`h-[80px] w-[120px] rounded-md object-cover outline outline-1 -outline-offset-1 outline-black/10`} src={attachment[0].url} />
<div className='absolute bottom-1 right-1 z-10 rounded-full border border-[rgba(255,255,255,0.25)] bg-black px-2 py-0.5 font-semibold text-white'>+ {attachmentCount - 1}</div>
</div>
</div>
<img className={imageAttachmentStyles} src={attachment[0].url} />
);
}

Expand All @@ -114,14 +111,12 @@ function renderInboxAttachment(object: ObjectProperties) {
case 'image/png':
case 'image/gif':
return (
<div className='min-w-[120px]'>
<img className={`h-[80px] w-[120px] rounded-md object-cover outline outline-1 -outline-offset-1 outline-black/10`} src={attachment.url} />
</div>
<img className={imageAttachmentStyles} src={attachment.url} />
);
case 'video/mp4':
case 'video/webm':
return (
<div className='relative h-[80px]'>
<div className={videoAttachmentStyles}>
<video className='h-[80px] w-full rounded object-cover' src={attachment.url} />
<div className='absolute inset-0 rounded bg-grey-900 opacity-50'></div>
<div className='absolute inset-0 flex items-center justify-center'>
Expand All @@ -133,17 +128,15 @@ function renderInboxAttachment(object: ObjectProperties) {
case 'audio/mpeg':
case 'audio/ogg':
return (
<div className='min-w-[160px]'>
<div className='ml-8 w-[120px]'>
<div className='relative mb-4 mt-2 w-full'>
<audio className='w-full' src={attachment.url} controls/>
</div>
</div>
);
default:
if (object.image) {
return <div className='min-h-[80px] min-w-[120px]'>
<img className={`h-[80px] w-[120px] rounded-md object-cover outline outline-1 -outline-offset-1 outline-black/10`} src={object.image} />
</div>;
return <img className={imageAttachmentStyles} src={object.image} />;
}
return null;
}
Expand Down Expand Up @@ -391,31 +384,25 @@ const FeedItem: React.FC<FeedItemProps> = ({actor, object, layout, type, comment
return (
<>
{object && (
<div className='group/article relative -mx-4 -my-px flex min-w-0 cursor-pointer justify-between rounded-md p-4 hover:bg-grey-75' data-layout='inbox' data-object-id={object.id} onClick={onClick}>
<div className='flex w-full min-w-0 flex-col items-start justify-between gap-1 pr-4'>
<div className='z-10 flex w-full min-w-0 items-start gap-2 group-hover/article:border-transparent'>
<APAvatar author={author} size='xs'/>
<span className='min-w-0 truncate break-all font-semibold' data-test-activity-heading>{author.name}</span>
<span className='min-w-0 truncate text-grey-700'>{getUsername(author)}</span>
{/* <div className='flex gap-2'>
<span className='truncate min-w-0 break-all font-semibold' data-test-activity-heading>{author.name}</span>
<span className='min-w-0 truncate text-grey-700'>{getUsername(author)}</span>
</div> */}
<span className='shrink-0 whitespace-nowrap text-grey-700 before:mr-1 before:content-["·"]' title={`${timestamp}`}>{getRelativeTimestamp(date)}</span>
<div className='group/article relative -mx-4 -my-px flex min-h-[112px] min-w-0 cursor-pointer items-center justify-between rounded-md p-4 hover:bg-grey-75' data-layout='inbox' data-object-id={object.id} onClick={onClick}>
<div className='flex min-h-[73px] w-full min-w-0 flex-col items-start justify-start'>
<div className='z-10 mb-1 flex w-full min-w-0 items-center gap-1.5 text-base text-grey-700 group-hover/article:border-transparent'>
<APAvatar author={author} size='2xs'/>
<span className='min-w-0 truncate break-all font-medium text-grey-900' data-test-activity-heading>{author.name}</span>
<span className='min-w-0 truncate'>{getUsername(author)}</span>
<span className='shrink-0 whitespace-nowrap before:mr-1 before:content-["·"]' title={`${timestamp}`}>{getRelativeTimestamp(date)}</span>
</div>
<Heading className='line-clamp-1 font-semibold leading-normal' level={5} data-test-activity-heading>
<Heading className='mb-1 line-clamp-1 w-full max-w-[600px] text-[1.6rem] font-semibold leading-snug' level={5} data-test-activity-heading>
{object.name ? object.name : (
<span dangerouslySetInnerHTML={{
__html: object.content.length > 30
? stripHtml(object.content).substring(0, 50) + '...'
: stripHtml(object.content)
__html: stripHtml(object.content)
}}></span>
)}
</Heading>
<div dangerouslySetInnerHTML={({__html: stripHtml(object.content)})} className='ap-note-content w-full truncate text-[1.5rem] text-grey-700'></div>
<div dangerouslySetInnerHTML={({__html: stripHtml(object.content)})} className='ap-note-content w-full max-w-[600px] truncate text-base leading-normal text-grey-700'></div>
</div>
{renderInboxAttachment(object)}
<div className='invisible absolute right-2 top-[9px] z-[49] flex flex-col gap-2 rounded-lg bg-white p-2 shadow-md-heavy group-hover/article:visible'>
<div className='invisible absolute right-4 top-[9px] z-[49] flex flex-col gap-2 rounded-lg bg-white p-2 shadow-md-heavy group-hover/article:visible'>
<FeedItemStats
commentCount={commentCount}
layout={layout}
Expand Down
7 changes: 6 additions & 1 deletion apps/admin-x-activitypub/src/components/global/APAvatar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import clsx from 'clsx';
import {ActorProperties} from '@tryghost/admin-x-framework/api/activitypub';
import {Icon} from '@tryghost/admin-x-design-system';

type AvatarSize = 'xs' | 'sm' | 'lg';
type AvatarSize = '2xs' | 'xs' | 'sm' | 'lg';
export type AvatarBadge = 'user-fill' | 'heart-fill' | 'comment-fill' | undefined;

interface APAvatarProps {
Expand Down Expand Up @@ -37,6 +37,11 @@ const APAvatar: React.FC<APAvatarProps> = ({author, size, badge}) => {
}

switch (size) {
case '2xs':
iconSize = 10;
containerClass = clsx('h-4 w-4 rounded ', containerClass);
imageClass = 'z-10 rounded w-4 h-4 object-cover';
break;
case 'xs':
iconSize = 12;
containerClass = clsx('h-5 w-5 rounded ', containerClass);
Expand Down

0 comments on commit 5863c40

Please sign in to comment.