Merge branch 'tag-improvements' into 'develop'
Tag improvements See merge request soapbox-pub/soapbox!2458
This commit is contained in:
commit
b6a5c56859
10 changed files with 78 additions and 46 deletions
|
@ -248,6 +248,9 @@ const expandListTimeline = (id: string, { maxId }: Record<string, any> = {}, don
|
|||
const expandGroupTimeline = (id: string, { maxId }: Record<string, any> = {}, done = noOp) =>
|
||||
expandTimeline(`group:${id}`, `/api/v1/timelines/group/${id}`, { max_id: maxId }, done);
|
||||
|
||||
const expandGroupTimelineFromTag = (id: string, tagName: string, { maxId }: Record<string, any> = {}, done = noOp) =>
|
||||
expandTimeline(`group:tags:${id}:${tagName}`, `/api/v1/timelines/group/${id}/tags/${tagName}`, { max_id: maxId }, done);
|
||||
|
||||
const expandGroupMediaTimeline = (id: string | number, { maxId }: Record<string, any> = {}) =>
|
||||
expandTimeline(`group:${id}:media`, `/api/v1/timelines/group/${id}`, { max_id: maxId, only_media: true, limit: 40, with_muted: true });
|
||||
|
||||
|
@ -350,6 +353,7 @@ export {
|
|||
expandAccountMediaTimeline,
|
||||
expandListTimeline,
|
||||
expandGroupTimeline,
|
||||
expandGroupTimelineFromTag,
|
||||
expandGroupMediaTimeline,
|
||||
expandHashtagTimeline,
|
||||
expandTimelineRequest,
|
||||
|
|
|
@ -39,8 +39,6 @@ const GroupTagListItem = (props: IGroupMemberListItem) => {
|
|||
const { updateGroupTag } = useUpdateGroupTag(group.id, tag.id);
|
||||
|
||||
const isOwner = group.relationship?.role === GroupRoles.OWNER;
|
||||
const isAdmin = group.relationship?.role === GroupRoles.ADMIN;
|
||||
const canEdit = isOwner || isAdmin;
|
||||
|
||||
const toggleVisibility = () => {
|
||||
updateGroupTag({
|
||||
|
@ -123,16 +121,16 @@ const GroupTagListItem = (props: IGroupMemberListItem) => {
|
|||
|
||||
return (
|
||||
<HStack alignItems='center' justifyContent='between'>
|
||||
<Link to={`/groups/${group.id}/tag/${tag.id}`} className='group grow'>
|
||||
<Link to={`/group/${group.slug}/tag/${tag.id}`} className='group grow'>
|
||||
<Stack>
|
||||
<Text
|
||||
weight='bold'
|
||||
theme={(tag.visible || !canEdit) ? 'default' : 'subtle'}
|
||||
theme={(tag.visible || !isOwner) ? 'default' : 'subtle'}
|
||||
className='group-hover:underline'
|
||||
>
|
||||
#{tag.name}
|
||||
</Text>
|
||||
<Text size='sm' theme={(tag.visible || !canEdit) ? 'muted' : 'subtle'}>
|
||||
<Text size='sm' theme={(tag.visible || !isOwner) ? 'muted' : 'subtle'}>
|
||||
{intl.formatMessage(messages.total)}:
|
||||
{' '}
|
||||
<Text size='sm' theme='inherit' weight='semibold' tag='span'>
|
||||
|
@ -142,7 +140,7 @@ const GroupTagListItem = (props: IGroupMemberListItem) => {
|
|||
</Stack>
|
||||
</Link>
|
||||
|
||||
{canEdit ? (
|
||||
{isOwner ? (
|
||||
<HStack alignItems='center' space={2}>
|
||||
{tag.visible ? (
|
||||
renderPinIcon()
|
||||
|
|
|
@ -1,28 +1,66 @@
|
|||
import React from 'react';
|
||||
import React, { useEffect } from 'react';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Column } from 'soapbox/components/ui';
|
||||
import { expandGroupTimelineFromTag } from 'soapbox/actions/timelines';
|
||||
import { Column, Icon, Stack, Text } from 'soapbox/components/ui';
|
||||
import { useAppDispatch } from 'soapbox/hooks';
|
||||
import { useGroup, useGroupTag } from 'soapbox/hooks/api';
|
||||
|
||||
type RouteParams = { id: string, groupId: string };
|
||||
import Timeline from '../ui/components/timeline';
|
||||
|
||||
type RouteParams = { tagId: string, groupId: string };
|
||||
|
||||
interface IGroupTimeline {
|
||||
params: RouteParams
|
||||
}
|
||||
|
||||
const GroupTagTimeline: React.FC<IGroupTimeline> = (props) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const groupId = props.params.groupId;
|
||||
const tagId = props.params.id;
|
||||
const tagId = props.params.tagId;
|
||||
|
||||
const { group } = useGroup(groupId);
|
||||
const { tag } = useGroupTag(tagId);
|
||||
const { tag, isLoading } = useGroupTag(tagId);
|
||||
|
||||
if (!group) {
|
||||
const handleLoadMore = (maxId: string) => {
|
||||
dispatch(expandGroupTimelineFromTag(groupId, tag?.name as string, { maxId }));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (tag?.name) {
|
||||
dispatch(expandGroupTimelineFromTag(groupId, tag?.name));
|
||||
}
|
||||
}, [groupId, tag]);
|
||||
|
||||
|
||||
if (isLoading || !tag || !group) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<Column label={`#${tag}`}>
|
||||
{/* TODO */}
|
||||
<Column label={`#${tag.name}`}>
|
||||
<Timeline
|
||||
scrollKey='group_timeline'
|
||||
timelineId={`group:tags:${groupId}:${tag.name}`}
|
||||
onLoadMore={handleLoadMore}
|
||||
divideType='border'
|
||||
showGroup={false}
|
||||
emptyMessageCard={false}
|
||||
emptyMessage={
|
||||
<Stack space={4} className='py-6' justifyContent='center' alignItems='center'>
|
||||
<div className='rounded-full bg-gray-200 p-4 dark:bg-gray-800'>
|
||||
<Icon
|
||||
src={require('@tabler/icons/message-2.svg')}
|
||||
className='h-6 w-6 text-gray-600'
|
||||
/>
|
||||
</div>
|
||||
|
||||
<Text theme='muted'>
|
||||
<FormattedMessage id='empty_column.group' defaultMessage='There are no posts in this group yet.' />
|
||||
</Text>
|
||||
</Stack>
|
||||
}
|
||||
/>
|
||||
</Column>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -20,7 +20,7 @@ const GroupGridItem = forwardRef((props: IGroup, ref: React.ForwardedRef<HTMLDiv
|
|||
return (
|
||||
<div
|
||||
key={group.id}
|
||||
className='relative flex shrink-0 flex-col space-y-2 px-0.5'
|
||||
className='relative flex shrink-0 flex-col space-y-2 px-1'
|
||||
style={{
|
||||
width,
|
||||
}}
|
||||
|
@ -39,7 +39,11 @@ const GroupGridItem = forwardRef((props: IGroup, ref: React.ForwardedRef<HTMLDiv
|
|||
/>
|
||||
)}
|
||||
|
||||
<Stack justifyContent='end' className='z-10 p-4 text-white' space={3}>
|
||||
<div
|
||||
className='absolute inset-x-0 bottom-0 flex justify-center rounded-b-lg bg-gradient-to-t from-gray-900 to-transparent pb-8 pt-12 transition-opacity duration-500'
|
||||
/>
|
||||
|
||||
<Stack justifyContent='end' className='p-4 text-white' space={3}>
|
||||
<GroupAvatar
|
||||
group={group}
|
||||
size={44}
|
||||
|
@ -60,10 +64,6 @@ const GroupGridItem = forwardRef((props: IGroup, ref: React.ForwardedRef<HTMLDiv
|
|||
</HStack>
|
||||
</Stack>
|
||||
</Stack>
|
||||
|
||||
<div
|
||||
className='absolute inset-x-0 bottom-0 z-0 flex justify-center rounded-b-lg bg-gradient-to-t from-gray-900 to-transparent pb-8 pt-12 transition-opacity duration-500'
|
||||
/>
|
||||
</Stack>
|
||||
</Link>
|
||||
|
||||
|
|
|
@ -53,7 +53,7 @@ const PopularGroups = () => {
|
|||
{isFetching ? (
|
||||
new Array(4).fill(0).map((_, idx) => (
|
||||
<div
|
||||
className='relative flex shrink-0 flex-col space-y-2 px-0.5'
|
||||
className='relative flex shrink-0 flex-col space-y-2 px-1'
|
||||
style={{ width: width || 'auto' }}
|
||||
key={idx}
|
||||
>
|
||||
|
|
|
@ -46,10 +46,8 @@ export default (props: Props) => {
|
|||
</div>
|
||||
), []);
|
||||
|
||||
const renderGroupGrid = useCallback((group: Group, index: number) => (
|
||||
<div className='pb-4'>
|
||||
<GroupGridItem group={group} />
|
||||
</div>
|
||||
const renderGroupGrid = useCallback((group: Group) => (
|
||||
<GroupGridItem group={group} />
|
||||
), []);
|
||||
|
||||
return (
|
||||
|
@ -79,10 +77,10 @@ export default (props: Props) => {
|
|||
<VirtuosoGrid
|
||||
useWindowScroll
|
||||
data={groups}
|
||||
itemContent={(index, group) => renderGroupGrid(group, index)}
|
||||
itemContent={(_index, group) => renderGroupGrid(group)}
|
||||
components={{
|
||||
Item: (props) => (
|
||||
<div {...props} className='w-1/2 flex-none' />
|
||||
<div {...props} className='w-1/2 flex-none pb-4 [&:nth-last-of-type(-n+2)]:pb-0' />
|
||||
),
|
||||
List: GridList,
|
||||
}}
|
||||
|
|
|
@ -46,10 +46,8 @@ const Popular: React.FC = () => {
|
|||
</div>
|
||||
), []);
|
||||
|
||||
const renderGroupGrid = useCallback((group: Group, index: number) => (
|
||||
<div className='pb-4'>
|
||||
<GroupGridItem group={group} />
|
||||
</div>
|
||||
const renderGroupGrid = useCallback((group: Group) => (
|
||||
<GroupGridItem group={group} />
|
||||
), []);
|
||||
|
||||
return (
|
||||
|
@ -73,10 +71,10 @@ const Popular: React.FC = () => {
|
|||
<VirtuosoGrid
|
||||
useWindowScroll
|
||||
data={groups}
|
||||
itemContent={(index, group) => renderGroupGrid(group, index)}
|
||||
itemContent={(_index, group) => renderGroupGrid(group)}
|
||||
components={{
|
||||
Item: (props) => (
|
||||
<div {...props} className='w-1/2 flex-none' />
|
||||
<div {...props} className='w-1/2 flex-none pb-4 [&:nth-last-of-type(-n+2)]:pb-0' />
|
||||
),
|
||||
List: GridList,
|
||||
}}
|
||||
|
|
|
@ -46,10 +46,8 @@ const Suggested: React.FC = () => {
|
|||
</div>
|
||||
), []);
|
||||
|
||||
const renderGroupGrid = useCallback((group: Group, index: number) => (
|
||||
<div className='pb-4'>
|
||||
<GroupGridItem group={group} />
|
||||
</div>
|
||||
const renderGroupGrid = useCallback((group: Group) => (
|
||||
<GroupGridItem group={group} />
|
||||
), []);
|
||||
|
||||
return (
|
||||
|
@ -73,10 +71,10 @@ const Suggested: React.FC = () => {
|
|||
<VirtuosoGrid
|
||||
useWindowScroll
|
||||
data={groups}
|
||||
itemContent={(index, group) => renderGroupGrid(group, index)}
|
||||
itemContent={(_index, group) => renderGroupGrid(group)}
|
||||
components={{
|
||||
Item: (props) => (
|
||||
<div {...props} className='w-1/2 flex-none' />
|
||||
<div {...props} className='w-1/2 flex-none pb-4 [&:nth-last-of-type(-n+2)]:pb-0' />
|
||||
),
|
||||
List: GridList,
|
||||
}}
|
||||
|
|
|
@ -50,10 +50,8 @@ const Tag: React.FC<ITag> = (props) => {
|
|||
</div>
|
||||
), []);
|
||||
|
||||
const renderGroupGrid = useCallback((group: Group, index: number) => (
|
||||
<div className='pb-4'>
|
||||
<GroupGridItem group={group} />
|
||||
</div>
|
||||
const renderGroupGrid = useCallback((group: Group) => (
|
||||
<GroupGridItem group={group} />
|
||||
), []);
|
||||
|
||||
if (isLoading || !tag) {
|
||||
|
@ -100,10 +98,10 @@ const Tag: React.FC<ITag> = (props) => {
|
|||
<VirtuosoGrid
|
||||
useWindowScroll
|
||||
data={groups}
|
||||
itemContent={(index, group) => renderGroupGrid(group, index)}
|
||||
itemContent={(_index, group) => renderGroupGrid(group)}
|
||||
components={{
|
||||
Item: (props) => (
|
||||
<div {...props} className='w-1/2 flex-none' />
|
||||
<div {...props} className='w-1/2 flex-none pb-4 [&:nth-last-of-type(-n+2)]:pb-0' />
|
||||
),
|
||||
List: GridList,
|
||||
}}
|
||||
|
|
|
@ -327,7 +327,7 @@ const SwitchingColumnsArea: React.FC<ISwitchingColumnsArea> = ({ children }) =>
|
|||
{features.groups && <WrappedRoute path='/groups/:groupId/posts/:statusId' exact page={StatusPage} component={Status} content={children} />}
|
||||
|
||||
{features.groupsTags && <WrappedRoute path='/group/:groupSlug/tags' exact page={GroupPage} component={GroupTagsSlug} content={children} />}
|
||||
{features.groupsTags && <WrappedRoute path='/group/:groupSlug/tag/:id' exact page={GroupsPendingPage} component={GroupTagTimelineSlug} content={children} />}
|
||||
{features.groupsTags && <WrappedRoute path='/group/:groupSlug/tag/:tagId' exact page={GroupsPendingPage} component={GroupTagTimelineSlug} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/group/:groupSlug' exact page={GroupPage} component={GroupTimelineSlug} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/group/:groupSlug/members' exact page={GroupPage} component={GroupMembersSlug} content={children} />}
|
||||
{features.groups && <WrappedRoute path='/group/:groupSlug/media' publicRoute={!authenticatedProfile} component={GroupGallerySlug} page={GroupPage} content={children} />}
|
||||
|
|
Loading…
Reference in a new issue