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

Fixed separator showing even after the last list item (#21620)

close
https://linear.app/ghost/issue/AP-528/remove-unnecessary-separator-after-last-list-items

- Previously, in some components, we relied on CSS and all elements in
the list being the same type of an HTML element to show the separator.
Now, we've extracted the separator into its own component and place
after all items during mapping except the last one.
This commit is contained in:
Djordje Vlaisavljevic 2024-11-14 17:42:43 +00:00 committed by GitHub
parent 0aae3bb1fc
commit af54b21bf3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 118 additions and 95 deletions

View file

@ -8,6 +8,7 @@ import APAvatar, {AvatarBadge} from './global/APAvatar';
import ActivityItem, {type Activity} from './activities/ActivityItem';
import ArticleModal from './feed/ArticleModal';
import MainNavigation from './navigation/MainNavigation';
import Separator from './global/Separator';
import ViewProfileModal from './global/ViewProfileModal';
import getUsername from '../utils/get-username';
@ -184,9 +185,9 @@ const Activities: React.FC<ActivitiesProps> = ({}) => {
(isLoading === false && activities.length > 0) && (
<>
<div className='mt-8 flex w-full max-w-[560px] flex-col'>
{activities?.map(activity => (
{activities?.map((activity, index) => (
<React.Fragment key={activity.id}>
<ActivityItem
key={activity.id}
url={getActivityUrl(activity) || getActorUrl(activity)}
onClick={() => handleActivityClick(activity)}
>
@ -199,13 +200,9 @@ const Activities: React.FC<ActivitiesProps> = ({}) => {
<div className=''>{getActivityDescription(activity)}</div>
{getExtendedDescription(activity)}
</div>
{/* <FollowButton
className='ml-auto'
following={isFollower(activity.actor.id)}
handle={getUsername(activity.actor)}
type='link'
/> */}
</ActivityItem>
{index < activities.length - 1 && <Separator />}
</React.Fragment>
))}
</div>
<div ref={loadMoreRef} className='h-1'></div>

View file

@ -5,6 +5,7 @@ import FeedItem from './feed/FeedItem';
import MainNavigation from './navigation/MainNavigation';
import NiceModal from '@ebay/nice-modal-react';
import React, {useEffect, useRef} from 'react';
import Separator from './global/Separator';
import ViewProfileModal from './global/ViewProfileModal';
import getName from '../utils/get-name';
import getUsername from '../utils/get-username';
@ -94,7 +95,7 @@ const Inbox: React.FC<InboxProps> = ({}) => {
onCommentClick={() => handleViewContent(activity, true, updateActivity)}
/>
{index < activities.length - 1 && (
<div className="h-px w-full bg-grey-200"></div>
<Separator />
)}
</li>
))}
@ -107,15 +108,16 @@ const Inbox: React.FC<InboxProps> = ({}) => {
</ul>
</div>
<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>
<h2 className='mb-2 text-lg font-semibold'>You might also like</h2>
{isLoadingSuggested ? (
<LoadingIndicator size="sm" />
) : (
<ul className='grow'>
{suggested.map((profile) => {
{suggested.map((profile, index) => {
const actor = profile.actor;
// const isFollowing = profile.isFollowing;
return (
<React.Fragment key={actor.id}>
<li key={actor.id}>
<ActivityItem url={actor.url} onClick={() => NiceModal.show(ViewProfileModal, {
profile: getUsername(actor),
@ -123,11 +125,9 @@ const Inbox: React.FC<InboxProps> = ({}) => {
onUnfollow: () => {}
})}>
<APAvatar author={actor} />
<div>
<div className='text-grey-600'>
<span className='mr-1 truncate font-bold text-black'>{getName(actor)}</span>
<div className='truncate text-sm'>{getUsername(actor)}</div>
</div>
<div className='flex min-w-0 flex-col'>
<span className='block w-full truncate font-bold text-black'>{getName(actor)}</span>
<span className='block w-full truncate text-sm text-grey-600'>{getUsername(actor)}</span>
</div>
{/* <FollowButton
className='ml-auto'
@ -139,6 +139,8 @@ const Inbox: React.FC<InboxProps> = ({}) => {
/> */}
</ActivityItem>
</li>
{index < suggested.length - 1 && <Separator />}
</React.Fragment>
);
})}
</ul>

View file

@ -8,6 +8,7 @@ import getName from '../utils/get-name';
import getUsername from '../utils/get-username';
import {ActorProperties} from '@tryghost/admin-x-framework/api/activitypub';
import Separator from './global/Separator';
import ViewProfileModal from './global/ViewProfileModal';
import {Button, Heading, List, NoValueLabel, Tab, TabView} from '@tryghost/admin-x-design-system';
import {handleViewContent} from '../utils/content-handlers';
@ -102,7 +103,7 @@ const Profile: React.FC<ProfileProps> = ({}) => {
onCommentClick={() => handleViewContent(activity, true)}
/>
{index < posts.length - 1 && (
<div className="h-px w-full bg-grey-200"></div>
<Separator />
)}
</li>
))}
@ -147,7 +148,7 @@ const Profile: React.FC<ProfileProps> = ({}) => {
onCommentClick={() => handleViewContent(activity, true)}
/>
{index < liked.length - 1 && (
<div className="h-px w-full bg-grey-200"></div>
<Separator />
)}
</li>
))}
@ -178,8 +179,9 @@ const Profile: React.FC<ProfileProps> = ({}) => {
</NoValueLabel>
) : (
<List>
{following.slice(0, visibleFollowing).map((item) => {
{following.slice(0, visibleFollowing).map((item, index) => {
return (
<React.Fragment key={item.id}>
<ActivityItem
key={item.id}
url={item.url}
@ -197,6 +199,8 @@ const Profile: React.FC<ProfileProps> = ({}) => {
alert('Implement me!');
}} /> */}
</ActivityItem>
{index < following.length - 1 && <Separator />}
</React.Fragment>
);
})}
</List>
@ -226,8 +230,9 @@ const Profile: React.FC<ProfileProps> = ({}) => {
</NoValueLabel>
) : (
<List>
{followers.slice(0, visibleFollowers).map((item) => {
{followers.slice(0, visibleFollowers).map((item, index) => {
return (
<React.Fragment key={item.id}>
<ActivityItem
key={item.id}
url={item.url}
@ -241,6 +246,8 @@ const Profile: React.FC<ProfileProps> = ({}) => {
</div>
</div>
</ActivityItem>
{index < followers.length - 1 && <Separator />}
</React.Fragment>
);
})}
</List>

View file

@ -12,6 +12,7 @@ import MainNavigation from './navigation/MainNavigation';
import NiceModal from '@ebay/nice-modal-react';
import ViewProfileModal from './global/ViewProfileModal';
import Separator from './global/Separator';
import {useSearchForUser, useSuggestedProfiles} from '../hooks/useActivityPubQueries';
interface SearchResultItem {
@ -103,13 +104,18 @@ const SuggestedAccounts: React.FC<{
<LoadingIndicator size='md'/>
</div>
)}
{profiles.map(profile => (
{profiles.map((profile, index) => {
return (
<React.Fragment key={profile.actor.id}>
<SearchResult
key={profile.actor.id}
result={profile}
update={onUpdate}
/>
))}
{index < profiles.length - 1 && <Separator />}
</React.Fragment>
);
})}
</>
);
};
@ -141,8 +147,8 @@ const Search: React.FC<SearchProps> = ({}) => {
return (
<>
<MainNavigation page='search' />
<div className='z-0 flex w-full flex-col items-center pt-8'>
<div className='relative flex w-full max-w-[560px] items-center '>
<div className='z-0 mx-auto flex w-full max-w-[560px] flex-col items-center pt-8'>
<div className='relative flex w-full items-center'>
<Icon className='absolute left-3 top-3 z-10' colorClass='text-grey-500' name='magnifying-glass' size='sm' />
<TextField
className='mb-6 mr-12 flex h-10 w-full items-center rounded-lg border border-transparent bg-grey-100 px-[33px] py-1.5 transition-colors focus:border-green focus:bg-white focus:outline-2 dark:border-transparent dark:bg-grey-925 dark:text-white dark:placeholder:text-grey-800 dark:focus:border-green dark:focus:bg-grey-950 tablet:mr-0'

View file

@ -23,7 +23,7 @@ const ActivityItem: React.FC<ActivityItemProps> = ({children, url = null, onClic
const childrenArray = React.Children.toArray(children);
const Item = (
<div className='relative flex w-full max-w-[560px] cursor-pointer flex-col border-b border-grey-100 before:absolute before:inset-x-[-8px] before:inset-y-[-1px] before:rounded-md before:bg-grey-50 before:opacity-0 before:transition-opacity hover:z-10 hover:cursor-pointer hover:border-b-transparent hover:before:opacity-100 dark:border-grey-950 dark:before:bg-grey-950' onClick={() => {
<div className='relative flex w-full max-w-[560px] cursor-pointer flex-col before:absolute before:inset-x-[-8px] before:inset-y-[-1px] before:rounded-md before:bg-grey-50 before:opacity-0 before:transition-opacity hover:z-10 hover:cursor-pointer hover:border-b-transparent hover:before:opacity-100 dark:before:bg-grey-950' onClick={() => {
if (!url && onClick) {
onClick();
}

View file

@ -0,0 +1,7 @@
import React from 'react';
const Separator: React.FC = () => {
return <div className='h-px w-full bg-grey-150 dark:bg-grey-950' />;
};
export default Separator;

View file

@ -13,6 +13,7 @@ import APAvatar from '../global/APAvatar';
import ActivityItem from '../activities/ActivityItem';
import FeedItem from '../feed/FeedItem';
import FollowButton from '../global/FollowButton';
import Separator from './Separator';
import getName from '../../utils/get-name';
import getUsername from '../../utils/get-username';
@ -81,8 +82,9 @@ const ActorList: React.FC<ActorListProps> = ({
</NoValueLabel>
) : (
<List>
{actorData.map(({actor, isFollowing}) => {
{actorData.map(({actor, isFollowing}, index) => {
return (
<React.Fragment key={actor.id}>
<ActivityItem key={actor.id} url={actor.url}>
<APAvatar author={actor} />
<div>
@ -98,6 +100,8 @@ const ActorList: React.FC<ActorListProps> = ({
type='link'
/>
</ActivityItem>
{index < actorData.length - 1 && <Separator />}
</React.Fragment>
);
})}
</List>
@ -188,7 +192,7 @@ const ViewProfileModal: React.FC<ViewProfileModalProps> = ({
onCommentClick={() => {}}
/>
{index < posts.length - 1 && (
<div className="h-px w-full bg-grey-200"></div>
<Separator />
)}
</div>
))}

View file

@ -29,7 +29,7 @@ const MainNavigation: React.FC<MainNavigationProps> = ({
</div>
<div className='col-[3/4] flex items-center justify-end gap-2 px-8'>
{page === 'home' &&
<div className='mr-3'>
<div>
<Tooltip content="Inbox">
<Button className='!px-2' icon='listview' iconColorClass={layout === 'inbox' ? 'text-black' : 'text-grey-400'} size='sm' onClick={setInbox} />
</Tooltip>