Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions examples/tutorial/.env.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Required: your Stream app's public key.
VITE_API_KEY=REPLACE_WITH_API_KEY
# Required: your Stream app's public key. This is the variable name that
# `getstream env --target vite` writes, so you can generate it instead of
# pasting it by hand. (VITE_API_KEY is still read as a fallback.)
VITE_STREAM_API_KEY=REPLACE_WITH_API_KEY

# Optional. If unset, the app defaults to user_id "react-tutorial" and
# derives user_name from it. You can also override either value per-run
Expand Down
94 changes: 93 additions & 1 deletion examples/tutorial/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,96 @@
This folder contains the source code for [Chat React tutorial](https://github.com/GetStream/getstream.io-tutorials/blob/main/chat/tutorials/react-tutorial.mdx). It contains multiple versions of apps representing the tutorial steps.
This folder contains the source code for the [Chat React tutorial](https://getstream.io/chat/sdk/react/tutorial/). It contains multiple versions of apps representing the tutorial steps.

The tutorial source lives in the website repo at [`content/pages/chat_sdk_react_tutorial.mdx`](https://github.com/GetStream/getstream.io/blob/main/content/pages/chat_sdk_react_tutorial.mdx). (It used to live in `GetStream/getstream.io-tutorials`, which is now archived.)

## Step folders

Folder names match the tutorial's step numbers, so `4-channel-list` is the tutorial's "Step 4 - Add a channel list". The tutorial's Step 0 (environment) and Step 1 (project + credentials) have no runnable counterpart, so the folders start at 2. The two `optional-*` folders are the tutorial's optional recipes, which sit after the numbered path.

| Folder | Tutorial section |
| --------------------------------- | ------------------------------------------------- |
| `2-client-setup` | Step 2 - Connect the client |
| `3-core-component-setup` | Step 3 - Get a working chat UI |
| `4-channel-list` | Step 4 - Add a channel list |
| `5-theming` | Step 5 - Theme it |
| `6-custom-ui-components` | Step 6 - Replace an SDK component |
| `7-emoji-picker` | Step 7 - Enable the emoji picker and autocomplete |
| `optional-custom-attachment-type` | Optional - add a custom attachment type |
| `optional-livestream` | Optional - a livestream-style chat app |

If you change a step's code here, update the matching code block in the tutorial too, and vice versa.

### `layout.css` is duplicated on purpose

The tutorial has the reader create a single `src/layout.css` in Step 3 and
rewrite it in Step 5. Each step folder here carries its own copy so the folder is
a self-contained snapshot of the app at that step, which means there are only two
distinct versions of the file:

| Version | In |
| -------- | -------------------------------------------------------------------------- |
| Step 3's | `3-core-component-setup`, `4-channel-list` |
| Step 5's | `5-theming`, `6-custom-ui-components`, `7-emoji-picker`, both `optional-*` |

Every file in a group is byte-identical, so any drift shows up in a diff. If you
edit one, edit the whole group.

Parts of each copy are inert inside the step browser. That is expected, and none
of it should be "cleaned up" here, because the file has to stay a faithful copy of
what the tutorial tells the reader to write:

- The `custom-theme` tokens do nothing in `7-emoji-picker` and
`optional-livestream`, which don't pass `theme="custom-theme"` to `<Chat>`. The
reader's single `layout.css` holds the tokens and leaves them unused for those
same two examples.
- The `.str-chat__channel-list` / `__channel` / `__thread` widths are overridden
by `.tutorial-browser__step-shell .str-chat__*` in `tutorial-main.css`, which
wins on specificity (0,2,0 against 0,1,0). The tutorial's widths assume the app
owns the whole page; here it is sized to fit a preview card.
- The `html` / `body` / `#root` rules are real, but `tutorial-main.css` declares
them too, so the chrome does not depend on a step's stylesheet.

None of this costs bundle size: Vite collapses the identical copies, so the built
CSS contains one `width: 30%` and one `@layer stream`.

### One deliberate deviation: unlayered theme tokens

The tutorial puts the custom theme tokens in a CSS layer:

```css
@layer stream, stream-overrides;
@import 'stream-chat-react/dist/css/index.css' layer(stream);

@layer stream-overrides {
.custom-theme {
/* tokens */
}
}
```

The themed steps here declare them unlayered instead:

```css
@layer stream;
@import 'stream-chat-react/dist/css/index.css' layer(stream);

.str-chat.custom-theme {
/* tokens */
}
```

Why: the step browser renders every step in a single document, so all seven
stylesheets are live at once. Steps 3 and 4 import the SDK stylesheet
_unlayered_ (as the tutorial has them, since Step 5 is where you're taught to
move it into a layer), and unlayered CSS outranks every `@layer` regardless of
specificity. A layered override would silently do nothing.

`.str-chat.custom-theme` (specificity 0,2,0) also beats the SDK's own
`.str-chat` (0,1,0) regardless of source order, and it only matches the steps
that actually pass `theme="custom-theme"`, so the themed steps can't leak into
the unthemed ones.

**This deviation exists only to make the step browser work. In your own app,
follow the tutorial and keep the tokens in the layer.**

The tutorial app is a Yarn workspace (`@stream-io/stream-chat-react-tutorial`) under the repo's monorepo, so it consumes the local `stream-chat-react` SDK through `workspace:^` and shares its dependencies with the root install.

Expand Down
13 changes: 0 additions & 13 deletions examples/tutorial/src/1-client-setup/index.html

This file was deleted.

9 changes: 0 additions & 9 deletions examples/tutorial/src/1-client-setup/main.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,17 @@
// ?user_id=alice&user_name=Alice // + display name override
//
// Notes:
// - apiKey is the one thing you still need to set (via VITE_API_KEY).
// - apiKey is the one thing you still need to set. `getstream env --target vite`
// writes VITE_STREAM_API_KEY, which is what the tutorial tells you to run;
// VITE_API_KEY is still accepted for older local setups.
// - The token endpoint and environment default to the values shared with
// the other example apps in this repo; override with VITE_TOKEN_ENDPOINT
// and VITE_TOKEN_ENVIRONMENT if you're pointing at a different Stream
// app.

const searchParams = new URLSearchParams(window.location.search);

export const apiKey = import.meta.env.VITE_API_KEY;
export const apiKey = import.meta.env.VITE_STREAM_API_KEY || import.meta.env.VITE_API_KEY;

export const userId =
searchParams.get('user_id') || import.meta.env.VITE_USER_ID || 'react-tutorial';
Expand Down
13 changes: 0 additions & 13 deletions examples/tutorial/src/2-core-component-setup/index.html

This file was deleted.

9 changes: 0 additions & 9 deletions examples/tutorial/src/2-core-component-setup/main.tsx

This file was deleted.

13 changes: 0 additions & 13 deletions examples/tutorial/src/3-channel-list/index.html

This file was deleted.

53 changes: 0 additions & 53 deletions examples/tutorial/src/3-channel-list/layout.css

This file was deleted.

9 changes: 0 additions & 9 deletions examples/tutorial/src/3-channel-list/main.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {

import 'stream-chat-react/dist/css/index.css';
import './layout.css';
import { apiKey, tokenProvider, userId, userName } from '../1-client-setup/credentials';
import { apiKey, tokenProvider, userId, userName } from '../2-client-setup/credentials';

const user: User = {
id: userId,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
html,
body,
#root {
height: 100%;
height: 100%;
}
body {
margin: 0;
margin: 0;
}
#root {
display: flex;
display: flex;
}

.str-chat__channel-list {
width: 30%;
width: 30%;
}
.str-chat__channel {
width: 100%;
width: 100%;
}
.str-chat__thread {
width: 45%;
}
width: 45%;
}
57 changes: 57 additions & 0 deletions examples/tutorial/src/4-channel-list/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { ChannelFilters, ChannelOptions, ChannelSort, User } from 'stream-chat';
import {
Channel,
ChannelHeader,
ChannelList,
Chat,
MessageComposer,
MessageList,
Thread,
useCreateChatClient,
Window,
} from 'stream-chat-react';

import 'stream-chat-react/dist/css/index.css';
import './layout.css';
import { apiKey, tokenProvider, userId, userName } from '../2-client-setup/credentials';

const user: User = {
id: userId,
name: userName,
image: `https://getstream.io/random_png/?name=${userName}`,
};

const sort: ChannelSort = { last_message_at: -1 };
const filters: ChannelFilters = {
type: 'messaging',
members: { $in: [userId] },
};
const options: ChannelOptions = {
limit: 10,
};

const App = () => {
const client = useCreateChatClient({
apiKey,
tokenOrProvider: tokenProvider,
userData: user,
});

if (!client) return <div>Setting up client & connection...</div>;

return (
<Chat client={client}>
<ChannelList filters={filters} options={options} sort={sort} />
<Channel>
<Window>
<ChannelHeader />
<MessageList />
<MessageComposer />
</Window>
<Thread />
</Channel>
</Chat>
);
};

export default App;
21 changes: 21 additions & 0 deletions examples/tutorial/src/4-channel-list/layout.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
html,
body,
#root {
height: 100%;
}
body {
margin: 0;
}
#root {
display: flex;
}

.str-chat__channel-list {
width: 30%;
}
.str-chat__channel {
width: 100%;
}
.str-chat__thread {
width: 45%;
}
13 changes: 0 additions & 13 deletions examples/tutorial/src/4-custom-ui-components/index.html

This file was deleted.

Loading