Skip to content

Commit 6239895

Browse files
authored
fix(examples): clean up tutorial examples for v14 (#3089)
### 🎯 Goal Align tutorial examples with v14 conventions and simplify the code to make the tutorial easier to follow. ### πŸ›  Implementation details - **CSS layers**: renamed `base`/`theme` β†’ `stream`/`stream-overrides` to match v14 naming conventions - **Layout CSS**: simplified across all steps β€” removed background gradients, redundant rules, and standardized widths - **Channel initialization**: simplified patterns (removed unnecessary `channel.watch()` calls where ChannelList handles it, used `isReady` boolean instead of storing channel in state) - **Step 4 (custom UI)**: replaced CSS classes with inline styles for `CustomChannelListItem` - **Step 5 (custom attachment)**: removed unused `ChannelList` and related imports - **Step 6 (emoji picker)**: fixed `WithComponents`/`Chat` nesting order - **Step 7 (livestream)**: replaced custom `tutorial-livestream` theme with generic `str-chat__theme-custom` ### 🎨 UI Changes No visual regressions β€” changes are structural/convention cleanup only.
1 parent 49d576e commit 6239895

11 files changed

Lines changed: 182 additions & 323 deletions

File tree

β€Žexamples/tutorial/src/2-core-component-setup/App.tsxβ€Ž

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { useState, useEffect } from 'react';
2-
import type { User, Channel as StreamChannel } from 'stream-chat';
2+
import { type User, Channel as StreamChannel } from 'stream-chat';
33
import {
44
useCreateChatClient,
55
Chat,
@@ -12,7 +12,6 @@ import {
1212
} from 'stream-chat-react';
1313

1414
import 'stream-chat-react/dist/css/index.css';
15-
// additionally
1615
import './layout.css';
1716
import { apiKey, userId, userName, userToken } from '../1-client-setup/credentials';
1817

@@ -33,27 +32,19 @@ const App = () => {
3332
useEffect(() => {
3433
if (!client) return;
3534

36-
const initChannel = async () => {
37-
const nextChannel = client.channel('messaging', 'react-tutorial', {
38-
image: 'https://getstream.io/random_png/?name=react-v14',
39-
name: 'Talk about React',
40-
members: [userId],
41-
});
42-
43-
await nextChannel.watch();
44-
setChannel(nextChannel);
45-
};
46-
47-
initChannel().catch((error) => {
48-
console.error('Failed to initialize tutorial channel', error);
35+
const channel = client.channel('messaging', 'custom_channel_id', {
36+
image: 'https://getstream.io/random_png/?name=react',
37+
name: 'Talk about React',
38+
members: [userId],
4939
});
40+
41+
setChannel(channel);
5042
}, [client]);
5143

5244
if (!client) return <div>Setting up client & connection...</div>;
53-
if (!channel) return <div>Loading tutorial channel...</div>;
5445

5546
return (
56-
<Chat client={client} theme='str-chat__theme-custom'>
47+
<Chat client={client}>
5748
<Channel channel={channel}>
5849
<Window>
5950
<ChannelHeader />

β€Žexamples/tutorial/src/3-channel-list/App.tsxβ€Ž

Lines changed: 2 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
import { useEffect, useState } from 'react';
2-
import type {
3-
User,
4-
Channel as StreamChannel,
5-
ChannelSort,
6-
ChannelFilters,
7-
ChannelOptions,
8-
} from 'stream-chat';
1+
import type { User, ChannelSort, ChannelFilters, ChannelOptions } from 'stream-chat';
92
import {
103
useCreateChatClient,
114
Chat,
@@ -37,39 +30,18 @@ const options: ChannelOptions = {
3730
};
3831

3932
const App = () => {
40-
const [channel, setChannel] = useState<StreamChannel>();
4133
const client = useCreateChatClient({
4234
apiKey,
4335
tokenOrProvider: userToken,
4436
userData: user,
4537
});
4638

47-
useEffect(() => {
48-
if (!client) return;
49-
50-
const initChannel = async () => {
51-
const nextChannel = client.channel('messaging', 'react-tutorial', {
52-
image: 'https://getstream.io/random_png/?name=react-v14',
53-
name: 'Talk about React',
54-
members: [userId],
55-
});
56-
57-
await nextChannel.watch();
58-
setChannel(nextChannel);
59-
};
60-
61-
initChannel().catch((error) => {
62-
console.error('Failed to initialize tutorial channel', error);
63-
});
64-
}, [client]);
65-
6639
if (!client) return <div>Setting up client & connection...</div>;
67-
if (!channel) return <div>Loading tutorial channel...</div>;
6840

6941
return (
7042
<Chat client={client} theme='str-chat__theme-custom'>
7143
<ChannelList filters={filters} sort={sort} options={options} />
72-
<Channel channel={channel}>
44+
<Channel>
7345
<Window>
7446
<ChannelHeader />
7547
<MessageList />
Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,52 +1,42 @@
1-
@layer base, theme;
2-
@import 'stream-chat-react/dist/css/index.css' layer(base);
1+
@layer stream, stream-overrides;
2+
@import 'stream-chat-react/dist/css/index.css' layer(stream);
33

4-
@layer theme {
5-
.str-chat__theme-custom {
6-
--brand-50: #edf7f7;
7-
--brand-100: #e0f2f1;
8-
--brand-150: #b2dfdb;
9-
--brand-200: #80cbc4;
10-
--brand-300: #4db6ac;
11-
--brand-400: #26a69a;
12-
--brand-500: #009688;
13-
--brand-600: #00897b;
14-
--brand-700: #00796b;
15-
--brand-800: #00695c;
16-
--brand-900: #004d40;
17-
--accent-primary: var(--brand-500);
18-
--radius-full: 18px;
19-
--str-chat__channel-list-width: min(360px, 32%);
20-
}
4+
@layer stream-overrides {
5+
.str-chat__theme-custom {
6+
--brand-50: #edf7f7;
7+
--brand-100: #e0f2f1;
8+
--brand-150: #b2dfdb;
9+
--brand-200: #80cbc4;
10+
--brand-300: #4db6ac;
11+
--brand-400: #26a69a;
12+
--brand-500: #009688;
13+
--brand-600: #00897b;
14+
--brand-700: #00796b;
15+
--brand-800: #00695c;
16+
--brand-900: #004d40;
17+
--accent-primary: var(--brand-500);
18+
--radius-full: 6px;
19+
}
2120
}
2221

2322
html,
2423
body,
2524
#root {
26-
height: 100%;
25+
height: 100%;
2726
}
2827
body {
29-
margin: 0;
30-
background: linear-gradient(180deg, #f4f7ff 0%, #e8f4f3 100%);
28+
margin: 0;
3129
}
3230
#root {
33-
display: flex;
34-
min-height: 100%;
35-
}
36-
37-
.str-chat {
38-
flex: 1;
31+
display: flex;
3932
}
4033

4134
.str-chat__channel-list {
42-
width: min(360px, 32%);
35+
width: 30%;
4336
}
44-
45-
.str-chat__channel,
46-
.str-chat__thread {
47-
width: 100%;
37+
.str-chat__channel {
38+
width: 100%;
4839
}
49-
5040
.str-chat__thread {
51-
width: min(420px, 45%);
41+
width: 45%;
5242
}

β€Žexamples/tutorial/src/4-custom-ui-components/App.tsxβ€Ž

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,5 @@
1-
import { useEffect, useState } from 'react';
2-
import type {
3-
Channel as StreamChannel,
4-
ChannelFilters,
5-
ChannelOptions,
6-
ChannelSort,
7-
User,
8-
} from 'stream-chat';
1+
import React, { useEffect, useState } from 'react';
2+
import type { ChannelFilters, ChannelOptions, ChannelSort, User } from 'stream-chat';
93
import {
104
Chat,
115
Channel,
@@ -15,10 +9,10 @@ import {
159
MessageComposer,
1610
MessageList,
1711
Thread,
18-
WithComponents,
1912
Window,
20-
useMessageContext,
13+
WithComponents,
2114
useCreateChatClient,
15+
useMessageContext,
2216
type ChannelListItemUIProps,
2317
} from 'stream-chat-react';
2418

@@ -61,24 +55,30 @@ const CustomChannelListItem = ({
6155
return (
6256
<button
6357
aria-pressed={active}
64-
className='tutorial-channel-list-item'
6558
onClick={handleClick}
59+
style={{
60+
width: '100%',
61+
padding: '12px',
62+
display: 'flex',
63+
gap: '12px',
64+
border: 'none',
65+
background: active ? '#d3f2ef' : 'transparent',
66+
textAlign: 'left',
67+
cursor: 'pointer',
68+
borderRadius: '20px',
69+
}}
6670
type='button'
6771
>
6872
<ChannelAvatar
6973
imageUrl={displayImage ?? channel.data?.image}
7074
size='xl'
7175
userName={displayTitle ?? channel.data?.name ?? 'Channel'}
7276
/>
73-
<div className='tutorial-channel-list-item__content'>
74-
<div className='tutorial-channel-list-item__title'>
75-
{displayTitle ?? channel.data?.name ?? 'Unnamed Channel'}
76-
</div>
77-
{latestMessagePreview && (
78-
<div className='tutorial-channel-list-item__preview'>
79-
{latestMessagePreview}
80-
</div>
81-
)}
77+
<div style={{ flex: 1 }}>
78+
<div>{displayTitle ?? channel.data?.name ?? 'Unnamed Channel'}</div>
79+
{latestMessagePreview ? (
80+
<div style={{ fontSize: '14px', opacity: 0.75 }}>{latestMessagePreview}</div>
81+
) : null}
8282
</div>
8383
</button>
8484
);
@@ -115,7 +115,7 @@ const CustomMessage = () => {
115115
};
116116

117117
const App = () => {
118-
const [channel, setChannel] = useState<StreamChannel>();
118+
const [isReady, setIsReady] = useState(false);
119119
const client = useCreateChatClient({
120120
apiKey,
121121
tokenOrProvider: userToken,
@@ -126,14 +126,14 @@ const App = () => {
126126
if (!client) return;
127127

128128
const initChannel = async () => {
129-
const nextChannel = client.channel('messaging', 'react-tutorial', {
129+
const channel = client.channel('messaging', 'react-tutorial', {
130130
image: 'https://getstream.io/random_png/?name=react-v14',
131131
name: 'Talk about React',
132132
members: [userId],
133133
});
134134

135-
await nextChannel.watch();
136-
setChannel(nextChannel);
135+
await channel.watch();
136+
setIsReady(true);
137137
};
138138

139139
initChannel().catch((error) => {
@@ -142,7 +142,7 @@ const App = () => {
142142
}, [client]);
143143

144144
if (!client) return <div>Setting up client & connection...</div>;
145-
if (!channel) return <div>Loading tutorial channel...</div>;
145+
if (!isReady) return <div>Loading tutorial channel...</div>;
146146

147147
return (
148148
<WithComponents
@@ -153,7 +153,7 @@ const App = () => {
153153
>
154154
<Chat client={client} theme='str-chat__theme-custom'>
155155
<ChannelList filters={filters} sort={sort} options={options} />
156-
<Channel channel={channel}>
156+
<Channel>
157157
<Window>
158158
<ChannelHeader />
159159
<MessageList />

0 commit comments

Comments
Β (0)