diff --git a/app/javascript/flavours/glitch/components/form_fields/combobox.module.scss b/app/javascript/flavours/glitch/components/form_fields/combobox.module.scss
index 7947b698a5..732893200c 100644
--- a/app/javascript/flavours/glitch/components/form_fields/combobox.module.scss
+++ b/app/javascript/flavours/glitch/components/form_fields/combobox.module.scss
@@ -8,9 +8,9 @@
.menuButton {
position: absolute;
- inset-inline-end: 0;
- top: 0;
- padding: 9px;
+ inset-inline-end: 1px;
+ top: 1px;
+ padding: 7px;
&::before {
// Subtle divider line separating the button from the input field
diff --git a/app/javascript/flavours/glitch/components/form_fields/copy_link_field.module.scss b/app/javascript/flavours/glitch/components/form_fields/copy_link_field.module.scss
index 06834e9d91..68ee85c27c 100644
--- a/app/javascript/flavours/glitch/components/form_fields/copy_link_field.module.scss
+++ b/app/javascript/flavours/glitch/components/form_fields/copy_link_field.module.scss
@@ -8,7 +8,7 @@
.copyButton {
position: absolute;
- inset-inline-end: 0;
- top: 0;
- padding: 9px;
+ inset-inline-end: 1px;
+ top: 1px;
+ padding: 7px;
}
diff --git a/app/javascript/flavours/glitch/features/collections/components/collection_list_item.module.scss b/app/javascript/flavours/glitch/features/collections/components/collection_list_item.module.scss
index eaee216e6a..4fdd129a05 100644
--- a/app/javascript/flavours/glitch/features/collections/components/collection_list_item.module.scss
+++ b/app/javascript/flavours/glitch/features/collections/components/collection_list_item.module.scss
@@ -9,67 +9,6 @@
}
}
-.content {
- position: relative;
- flex-grow: 1;
- display: flex;
- align-items: center;
- column-gap: 12px;
-}
-
-.avatarGrid {
- position: relative;
- display: grid;
- grid-template-columns: repeat(2, min-content);
- gap: 2px;
-
- &.avatarGridSensitive {
- .avatar {
- filter: blur(4px);
- }
- }
-}
-
-.avatar {
- background: var(--color-bg-brand-softest);
-}
-
-.avatarSensitiveBadge {
- position: absolute;
- inset: 0;
- margin: auto;
- padding: 3px;
- width: 18px;
- height: 18px;
- border-radius: 8px;
- fill: var(--color-text-primary);
- background: var(--color-bg-warning-softest);
-}
-
-.link {
- display: block;
- font-size: 15px;
- font-weight: 500;
- text-decoration: none;
- color: var(--color-text-primary);
-
- &:hover {
- color: var(--color-text-brand);
- }
-
- &::after {
- // Increase clickable area by extending link across parent
- content: '';
- position: absolute;
- inset: 0;
- }
-}
-
-.info {
- font-size: 13px;
- color: var(--color-text-secondary);
-}
-
.menuButton {
padding: 4px;
margin-top: -2px;
diff --git a/app/javascript/flavours/glitch/features/collections/components/collection_list_item.tsx b/app/javascript/flavours/glitch/features/collections/components/collection_list_item.tsx
index cb9a875900..8f0573d6f2 100644
--- a/app/javascript/flavours/glitch/features/collections/components/collection_list_item.tsx
+++ b/app/javascript/flavours/glitch/features/collections/components/collection_list_item.tsx
@@ -1,69 +1,30 @@
import { useId } from 'react';
-import { FormattedMessage } from 'react-intl';
-
import classNames from 'classnames';
-import { Link } from 'react-router-dom';
-import { CollectionMenu } from '@/flavours/glitch/features/collections/components/collection_menu';
-import WarningIcon from '@/material-icons/400-24px/warning.svg?react';
-import type { ApiCollectionJSON } from 'flavours/glitch/api_types/collections';
-import { AvatarById } from 'flavours/glitch/components/avatar';
-import { useAccountHandle } from 'flavours/glitch/components/display_name/default';
-import { RelativeTimestamp } from 'flavours/glitch/components/relative_timestamp';
import { Article } from 'flavours/glitch/components/scrollable_list/components';
-import { useAccount } from 'flavours/glitch/hooks/useAccount';
-import { domain } from 'flavours/glitch/initial_state';
+import type { CollectionLockupProps } from 'flavours/glitch/features/collections/components/collection_lockup';
+import { CollectionLockup } from 'flavours/glitch/features/collections/components/collection_lockup';
+import { CollectionMenu } from 'flavours/glitch/features/collections/components/collection_menu';
import classes from './collection_list_item.module.scss';
-export const AvatarGrid: React.FC<{
- accountIds: (string | undefined)[];
- sensitive?: boolean;
-}> = ({ accountIds: ids, sensitive }) => {
- const avatarIds = [ids[0], ids[1], ids[2], ids[3]];
- return (
-
- {avatarIds.map((id) => (
-
- ))}
- {sensitive &&
}
-
- );
-};
-
-export const CollectionListItem: React.FC<{
- collection: ApiCollectionJSON;
+interface CollectionListItemProps extends CollectionLockupProps {
withoutBorder?: boolean;
- withAuthorHandle?: boolean;
- withTimestamp?: boolean;
positionInList: number;
listSize: number;
-}> = ({
+}
+
+export const CollectionListItem: React.FC = ({
collection,
withoutBorder,
- withAuthorHandle = true,
- withTimestamp,
positionInList,
listSize,
+ ...otherProps
}) => {
- const { id, name } = collection;
const uniqueId = useId();
const linkId = `${uniqueId}-link`;
const infoId = `${uniqueId}-info`;
- const authorAccount = useAccount(collection.account_id);
- const authorHandle = useAccountHandle(authorAccount, domain);
return (
-
-
item.account_id)}
- sensitive={collection.sensitive}
- />
-
-
-
- {name}
-
-
-
- {collection.sensitive && (
- -
-
-
- )}
- {withAuthorHandle && authorAccount && (
-
- )}
-
- {withTimestamp && (
-
- ),
- }}
- tagName='li'
- />
- )}
-
-
-
+
= ({ accountIds: ids, sensitive }) => {
+ const avatarIds = [ids[0], ids[1], ids[2], ids[3]];
+ return (
+
+ {avatarIds.map((id) => (
+
+ ))}
+ {sensitive &&
}
+
+ );
+};
+
+export interface CollectionLockupProps {
+ collection: ApiCollectionJSON;
+ withAuthorHandle?: boolean;
+ withTimestamp?: boolean;
+}
+
+export const CollectionLockup: React.FC = ({
+ collection,
+ withAuthorHandle = true,
+ withTimestamp,
+}) => {
+ const { id, name } = collection;
+ const uniqueId = useId();
+ const linkId = `${uniqueId}-link`;
+ const infoId = `${uniqueId}-info`;
+ const authorAccount = useAccount(collection.account_id);
+ const authorHandle = useAccountHandle(authorAccount, domain);
+
+ return (
+
+
item.account_id)}
+ sensitive={collection.sensitive}
+ />
+
+
+
+ {name}
+
+
+
+ {collection.sensitive && (
+ -
+
+
+ )}
+ {withAuthorHandle && authorAccount && (
+
+ )}
+
+ {withTimestamp && (
+
+ ),
+ }}
+ tagName='li'
+ />
+ )}
+
+
+
+ );
+};
diff --git a/app/javascript/flavours/glitch/features/collections/components/collection_preview_card.module.scss b/app/javascript/flavours/glitch/features/collections/components/collection_preview_card.module.scss
new file mode 100644
index 0000000000..16b883b72b
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/collections/components/collection_preview_card.module.scss
@@ -0,0 +1,8 @@
+.wrapper {
+ display: flex;
+ align-items: start;
+ padding: 12px;
+ gap: 12px;
+ border-radius: 12px;
+ border: 1px solid var(--color-border-primary);
+}
diff --git a/app/javascript/flavours/glitch/features/collections/components/collection_preview_card.tsx b/app/javascript/flavours/glitch/features/collections/components/collection_preview_card.tsx
new file mode 100644
index 0000000000..47899cc510
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/collections/components/collection_preview_card.tsx
@@ -0,0 +1,20 @@
+import type { CollectionLockupProps } from 'flavours/glitch/features/collections/components/collection_lockup';
+import { CollectionLockup } from 'flavours/glitch/features/collections/components/collection_lockup';
+
+import classes from './collection_preview_card.module.scss';
+
+interface CollectionPreviewCardProps extends CollectionLockupProps {
+ onRemove?: () => void;
+}
+
+export const CollectionPreviewCard: React.FC = ({
+ collection,
+ onRemove,
+ ...otherProps
+}) => {
+ return (
+
+
+
+ );
+};
diff --git a/app/javascript/flavours/glitch/features/collections/components/share_modal.module.scss b/app/javascript/flavours/glitch/features/collections/components/share_modal.module.scss
index 2344ea519e..de10bb63c0 100644
--- a/app/javascript/flavours/glitch/features/collections/components/share_modal.module.scss
+++ b/app/javascript/flavours/glitch/features/collections/components/share_modal.module.scss
@@ -5,27 +5,7 @@
}
.preview {
- display: flex;
- flex-wrap: wrap-reverse;
- align-items: start;
- justify-content: space-between;
- gap: 8px;
- padding: 16px;
margin-bottom: 16px;
- border-radius: 8px;
- color: var(--color-text-primary);
- background: linear-gradient(
- 145deg,
- var(--color-bg-brand-soft),
- var(--color-bg-primary)
- );
- border: 1px solid var(--color-bg-brand-base);
-}
-
-.previewHeading {
- font-size: 22px;
- line-height: 1.3;
- margin-bottom: 4px;
}
.actions {
diff --git a/app/javascript/flavours/glitch/features/collections/components/share_modal.tsx b/app/javascript/flavours/glitch/features/collections/components/share_modal.tsx
index 17caa1207a..91c3a45e8b 100644
--- a/app/javascript/flavours/glitch/features/collections/components/share_modal.tsx
+++ b/app/javascript/flavours/glitch/features/collections/components/share_modal.tsx
@@ -8,8 +8,6 @@ import { me } from '@/flavours/glitch/initial_state';
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
import { changeCompose, focusCompose } from 'flavours/glitch/actions/compose';
import type { ApiCollectionJSON } from 'flavours/glitch/api_types/collections';
-import { AvatarById } from 'flavours/glitch/components/avatar';
-import { AvatarGroup } from 'flavours/glitch/components/avatar_group';
import { Button } from 'flavours/glitch/components/button';
import { CopyLinkField } from 'flavours/glitch/components/form_fields';
import { IconButton } from 'flavours/glitch/components/icon_button';
@@ -20,8 +18,7 @@ import {
} from 'flavours/glitch/components/modal_shell';
import { useAppDispatch } from 'flavours/glitch/store';
-import { AuthorNote } from '../detail';
-
+import { CollectionPreviewCard } from './collection_preview_card';
import classes from './share_modal.module.scss';
const messages = defineMessages({
@@ -96,24 +93,13 @@ export const CollectionShareModal: React.FC<{
/>
-
-
- {collection.items.slice(0, 5).map(({ account_id }) => {
- if (!account_id) return;
- return (
-
- );
- })}
-
+
diff --git a/app/javascript/flavours/glitch/features/notifications_v2/components/notification_collection.tsx b/app/javascript/flavours/glitch/features/notifications_v2/components/notification_collection.tsx
new file mode 100644
index 0000000000..e9427dccc6
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/notifications_v2/components/notification_collection.tsx
@@ -0,0 +1,69 @@
+import { FormattedMessage } from 'react-intl';
+
+import classNames from 'classnames';
+
+import { DisplayNameSimple } from '@/flavours/glitch/components/display_name/simple';
+import { Icon } from '@/flavours/glitch/components/icon';
+import { useAccount } from '@/flavours/glitch/hooks/useAccount';
+import CollectionsFilledIcon from '@/material-icons/400-24px/category-fill.svg?react';
+import type {
+ NotificationGroupAddedToCollection,
+ NotificationGroupCollectionUpdate,
+} from 'flavours/glitch/models/notification_group';
+
+import { CollectionPreviewCard } from '../../collections/components/collection_preview_card';
+
+export const NotificationCollection: React.FC<{
+ notification:
+ | NotificationGroupAddedToCollection
+ | NotificationGroupCollectionUpdate;
+ unread: boolean;
+}> = ({ notification, unread }) => {
+ const { collection, type } = notification;
+ const collectionCreatorAccount = useAccount(collection.account_id);
+
+ return (
+
+
+
+
+
+
+
+
+ {type === 'added_to_collection' && (
+
+ ),
+ }}
+ />
+ )}
+ {type === 'collection_update' && (
+
+ ),
+ }}
+ />
+ )}
+
+
+
+
+
+
+ );
+};
diff --git a/app/javascript/flavours/glitch/features/notifications_v2/components/notification_group.tsx b/app/javascript/flavours/glitch/features/notifications_v2/components/notification_group.tsx
index 5382287935..ec0d63e259 100644
--- a/app/javascript/flavours/glitch/features/notifications_v2/components/notification_group.tsx
+++ b/app/javascript/flavours/glitch/features/notifications_v2/components/notification_group.tsx
@@ -9,6 +9,7 @@ import { useAppSelector, useAppDispatch } from 'flavours/glitch/store';
import { NotificationAdminReport } from './notification_admin_report';
import { NotificationAdminSignUp } from './notification_admin_sign_up';
import { NotificationAnnualReport } from './notification_annual_report';
+import { NotificationCollection } from './notification_collection';
import { NotificationFavourite } from './notification_favourite';
import { NotificationFollow } from './notification_follow';
import { NotificationFollowRequest } from './notification_follow_request';
@@ -156,6 +157,15 @@ export const NotificationGroup: React.FC<{
/>
);
break;
+ case 'added_to_collection':
+ case 'collection_update':
+ content = (
+
+ );
+ break;
default:
return null;
}