Skip to content

Commit 87b411c

Browse files
Pin-indicator refresh
1 parent 8e62739 commit 87b411c

File tree

7 files changed

+68
-223
lines changed

7 files changed

+68
-223
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,8 @@ client/dist
7474
/.virtualgo
7575
.vscode/
7676
coverage.out
77+
78+
# stream-chat-css/docusaurus files
79+
docusaurus/docs/React/theming
80+
docusaurus/docs/React/assets/stream-chat-css*
81+
shared
-19.1 KB
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Loading
Original file line numberDiff line numberDiff line change
@@ -1,262 +1,102 @@
11
---
22
id: pin_indicator
3-
title: Pin Indicator and Permissions
3+
title: Pin Indicator
44
---
55

6-
import CustomPinMessage from '../../assets/CustomPinMessage.png';
7-
import CustomPinMessagePinned from '../../assets/CustomPinMessagePinned.png';
8-
import CustomPinMessagePinnedHover from '../../assets/CustomPinMessagePinnedHover.png';
6+
import Tabs from '@theme/Tabs';
7+
import TabItem from '@theme/TabItem';
98

10-
In this example, we will demonstrate how to create a custom pin indicator component for pinned messages, as well as set custom permissions for pinning.
9+
In this example, we will demonstrate how to create a custom pin indicator for pinned messages.
1110

12-
## Pin Permissions
11+
Let's start with the component based solution displaying the name of the user who pinned the message. We'll pass our custom component to the component context from which it'll be picked up by the [`MessageSimple`](../../components/message-components/message-ui.mdx) component to render.
1312

14-
Stream provides a default set of pin permissions for each user type within each channel type:
13+
<Tabs groupId="example">
14+
<TabItem value="js" label="React">
1515

16-
```tsx
17-
export const defaultPinPermissions: PinPermissions = {
18-
commerce: {
19-
admin: true,
20-
anonymous: false,
21-
channel_member: false,
22-
channel_moderator: true,
23-
guest: false,
24-
member: false,
25-
moderator: true,
26-
owner: true,
27-
user: false,
28-
},
29-
gaming: {
30-
admin: true,
31-
anonymous: false,
32-
channel_member: false,
33-
channel_moderator: true,
34-
guest: false,
35-
member: false,
36-
moderator: true,
37-
owner: false,
38-
user: false,
39-
},
40-
livestream: {
41-
admin: true,
42-
anonymous: false,
43-
channel_member: false,
44-
channel_moderator: true,
45-
guest: false,
46-
member: false,
47-
moderator: true,
48-
owner: true,
49-
user: false,
50-
},
51-
messaging: {
52-
admin: true,
53-
anonymous: false,
54-
channel_member: true,
55-
channel_moderator: true,
56-
guest: false,
57-
member: true,
58-
moderator: true,
59-
owner: true,
60-
user: false,
61-
},
62-
team: {
63-
admin: true,
64-
anonymous: false,
65-
channel_member: true,
66-
channel_moderator: true,
67-
guest: false,
68-
member: true,
69-
moderator: true,
70-
owner: true,
71-
user: false,
72-
},
73-
};
74-
```
75-
76-
:::important
77-
When using a custom channel type, these permissions must be set for each user role.
78-
:::
16+
```jsx
17+
import { Channel } from 'stream-chat-react';
7918

80-
If you want to use different user permissions or create a custom channel type, the new permissions would need to be passed to `MessageList` using the `pinPermissions` prop.
19+
const CustomPinIndicator = () => {
20+
const { message } = useMessageContext('CustomPinIndicator');
8121

82-
```tsx
83-
const CustomPermissions = {
84-
customChannelType: {
85-
admin: true,
86-
anonymous: false,
87-
channel_member: false,
88-
channel_moderator: true,
89-
guest: false,
90-
member: false,
91-
moderator: true,
92-
owner: true,
93-
user: false,
94-
},
95-
};
96-
```
22+
const pinnedBy = message.pinned_by?.name || message.pinned_by?.id;
9723

98-
```tsx
99-
<MessageList pinPermissions={CustomPermissions} />
100-
```
24+
if (!pinnedBy) return null;
10125

102-
## Custom Pin Indicator
103-
104-
To utilize pinned messages, we will create a basic message component as well as a custom pin indicator to display when a message has been pinned. The custom pin indicator component will simply display the text 'pinned'. This is where you could get creative with custom icons and styles.
105-
106-
```tsx
107-
export const CustomPinIndicator = () => {
108-
return (
109-
<div>
110-
<div className='pin-text'>pinned</div>
111-
</div>
112-
);
26+
return <div className='pin-indicator'>📌 Pinned by {pinnedBy}</div>;
11327
};
114-
```
115-
116-
```css
117-
.pin-text {
118-
font-style: italic;
119-
color: grey;
120-
}
121-
```
122-
123-
This component can now be passed to `Channel` and later pulled from the `ComponentContext` when used.
124-
125-
```tsx
126-
<Channel PinIndicator={CustomPinIndicator}>{/* children of Channel component */}</Channel>
127-
```
128-
129-
Now we will build a message component that changes its background from turquoise to yellow when a message is pinned. Our custom pin indicator will also replace the `MessageOptions` component unless the message is currently being hovered.
13028

131-
```tsx
132-
export const CustomMessage = () => {
133-
const [hovering, setHovering] = useState(false);
134-
135-
const { message } = useMessageContext();
136-
const { PinIndicator = DefaultPinIndicator } = useComponentContext();
137-
138-
const messageWrapperRef = useRef<HTMLDivElement>(null);
139-
140-
const { pinned } = message;
141-
142-
return (
143-
<div
144-
className={pinned ? 'pinned-custom-message-wrapper' : 'custom-message-wrapper'}
145-
onMouseEnter={() => setHovering(true)}
146-
onMouseLeave={() => setHovering(false)}
147-
>
148-
<div className='custom-message-wrapper-content'>
149-
<div className='custom-message-header'>
150-
<div className='custom-message-header-name'>{message.user?.name || message.user?.id}</div>
151-
</div>
152-
<MessageText />
153-
<MessageRepliesCountButton reply_count={message.reply_count} />
154-
</div>
155-
<div className='custom-message-right-wrapper'>
156-
{hovering ? (
157-
<MessageOptions messageWrapperRef={messageWrapperRef} />
158-
) : (
159-
pinned && <PinIndicator />
160-
)}
161-
</div>
162-
</div>
163-
);
29+
export const ChannelWrapper = ({ children }) => {
30+
return <Channel PinIndicator={CustomPinIndicator}>{children}</Channel>;
16431
};
16532
```
16633
167-
```css
168-
.custom-message-wrapper {
169-
display: flex;
170-
padding: 12px;
171-
width: fit-content;
172-
border-radius: 16px;
173-
}
174-
175-
.custom-message-wrapper-content {
176-
display: flex;
177-
flex-direction: column;
178-
width: 100%;
179-
}
34+
</TabItem>
18035
181-
.right-wrapper {
182-
margin-left: 80px;
183-
margin-right: 16px;
184-
width: 48px;
185-
}
36+
<TabItem value="css" label="CSS">
18637
187-
.custom-message-header-name {
188-
color: black;
189-
font-weight: bold;
190-
font-size: 14;
38+
```css
39+
.pin-indicator {
40+
grid-area: pin;
19141
}
19242

193-
.str-chat__message-text-inner {
194-
color: grey;
195-
background: white;
196-
border: none;
197-
padding: 0;
43+
.str-chat__message.str-chat__message--other,
44+
.str-chat__message.str-chat__quoted-message-preview {
45+
grid-template-areas:
46+
'. pin'
47+
'avatar message'
48+
'. replies'
49+
'. translation-notice'
50+
'. custom-metadata'
51+
'. metadata';
19852
}
19953

200-
.str-chat__message-simple__actions {
201-
display: flex;
54+
.str-chat__message.str-chat__message--me {
55+
grid-template-areas:
56+
'pin'
57+
'message'
58+
'replies'
59+
'translation-notice'
60+
'custom-metadata'
61+
'metadata';
20262
}
63+
```
20364
204-
.custom-message-wrapper {
205-
background: turquoise;
206-
box-shadow: 0 2px 1px 0 rgba(0, 0, 0, 0.07);
207-
}
65+
</TabItem>
20866
209-
.custom-message-wrapper:hover .str-chat__message-text-inner {
210-
background: turquoise;
211-
}
67+
</Tabs>
21268
213-
.str-chat__message-replies-count-button {
214-
align-self: flex-start;
215-
}
69+
![Custom Pin Indicator](../../assets/custom-pin-indicator.png)
21670
217-
/** Pinned Message */
71+
You can omit the component based solution altogether, all the class names you need are in place and toggled appropriately, here's solution based purely on styles; we'll add `::before` to our message bubble with a 📌 icon to display whenever message has been pinned.
21872
219-
.pinned-custom-message-wrapper {
73+
```css
74+
.str-chat__message--pinned .str-chat__message-bubble::before {
75+
content: '📌';
22076
display: flex;
221-
padding: 12px;
222-
width: fit-content;
223-
border-radius: 16px;
224-
}
225-
226-
.pinned-custom-message-wrapper {
227-
background: papayawhip;
228-
box-shadow: 0 2px 1px 0 rgba(0, 0, 0, 0.07);
77+
align-items: center;
78+
justify-content: center;
79+
position: absolute;
80+
background-color: papayawhip;
81+
font-size: 0.6rem;
82+
width: 1.4rem;
83+
height: 1.4rem;
84+
border-radius: 9999px;
85+
z-index: 1;
86+
top: -10px;
22987
}
23088

231-
.pinned-custom-message-wrapper:hover .str-chat__message-text-inner {
232-
background: papayawhip;
89+
.str-chat__message--other.str-chat__message--pinned .str-chat__message-bubble::before {
90+
right: -10px;
23391
}
23492

235-
.pinned-custom-message-wrapper .str-chat__message-text-inner {
236-
background: papayawhip;
93+
.str-chat__message--me.str-chat__message--pinned .str-chat__message-bubble::before {
94+
left: -10px;
23795
}
23896
```
23997
240-
From here all we need to do is override the default component in `Channel` at the `App.tsx` level:
241-
242-
```tsx
243-
<Channel Message={CustomMessage}>{/* children of Channel component */}</Channel>
244-
```
245-
246-
## The Result
247-
248-
Unpinned Message:
249-
250-
<img src={CustomPinMessage} alt='Custom Pin Indicator UI Component for Chat' width='650' />
251-
252-
Pinned Message (not hovered):
253-
254-
<img src={CustomPinMessagePinned} alt='Custom Pin Indicator UI Component for Chat' width='650' />
98+
![Custom Pin Indicator CSS Based Solution](../../assets/custom-pin-indicator-css.png)
25599
256-
Pinned Message (hovered):
100+
### Read More
257101
258-
<img
259-
src={CustomPinMessagePinnedHover}
260-
alt='Custom Pin Indicator UI Component for Chat'
261-
width='700'
262-
/>
102+
See more on permissions regarding message pinning in [_Permissions v2_](https://getstream.io/chat/docs/react/user_permissions/?language=javascript) section of our JS documentation.

0 commit comments

Comments
 (0)