Skip to content

Commit 67bfa07

Browse files
authored
Merge pull request #6 from clue-labs/awesome-chat
Add awesome chat demo by @nlx-sascha
2 parents 8b6d828 + 020f73f commit 67bfa07

3 files changed

Lines changed: 269 additions & 0 deletions

File tree

examples/10-eventsource.html

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="utf-8"/>
5+
<title>EventSource Chat</title>
6+
<script>
7+
var es = new EventSource('chat'), username = '';
8+
es.addEventListener('message', function(event) {
9+
var data = JSON.parse(event.data);
10+
11+
var message = document.createElement('div');
12+
if (data.username) {
13+
var strong = document.createElement('strong');
14+
strong.appendChild(document.createTextNode(data.username));
15+
message.appendChild(strong);
16+
}
17+
message.appendChild(document.createTextNode(data.message));
18+
message.classList.add('chat-message');
19+
20+
var $messages = document.querySelector('.chat-messages');
21+
if ($messages.childNodes.length !== 0) {
22+
$messages.insertBefore(message, $messages.firstChild);
23+
} else {
24+
$messages.appendChild(message);
25+
}
26+
});
27+
28+
document.addEventListener('DOMContentLoaded', function() {
29+
var $chatForm = document.querySelector('.chat-form');
30+
$chatForm.addEventListener('submit', function($event) {
31+
$event.preventDefault();
32+
var $input = document.querySelector('.chat-form input');
33+
if ($input.value.length) {
34+
fetch('/message?message=' + encodeURIComponent($input.value) + '&username=' + encodeURIComponent(username)).then(function() {
35+
$input.value = '';
36+
});
37+
}
38+
});
39+
40+
var $chatForm = document.querySelector('.username-form');
41+
$chatForm.addEventListener('submit', function($event) {
42+
$event.preventDefault();
43+
var $input = document.querySelector('.username-form input');
44+
if ($input.value.length > 3) {
45+
document.activeElement.blur();
46+
username = $input.value;
47+
document.querySelector('.chat-header').innerText = username;
48+
document.body.classList.add('hide-username');
49+
setTimeout(function() {
50+
document.querySelector('.username-form-container').style.display = 'none';
51+
document.querySelector('.chat-form input').focus();
52+
}, 800);
53+
}
54+
});
55+
});
56+
</script>
57+
58+
<link href="styles.css" media="all" rel="stylesheet"/>
59+
</head>
60+
<body>
61+
<div class="chat">
62+
<div class="chat-header"></div>
63+
<div class="chat-messages"></div>
64+
<div class="chat-footer">
65+
<form class="chat-form">
66+
<input type="text" placeholder="Enter chat message">
67+
<button type="submit">Send</button>
68+
</form>
69+
</div>
70+
</div>
71+
<div class="username-form-container">
72+
<form class="username-form">
73+
<input type="text" placeholder="Enter username" autofocus>
74+
<button type="submit">Enter</button>
75+
</form>
76+
</div>
77+
</body>
78+
</html>

examples/10-styles.css

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
* {
2+
box-sizing: border-box;
3+
}
4+
5+
html {
6+
font-family: sans-serif;
7+
-ms-text-size-adjust: 100%;
8+
-webkit-text-size-adjust: 100%;
9+
}
10+
11+
body {
12+
margin: 10vh 10vw;
13+
background: linear-gradient(#2699e3, #2699e3 25vh, #e9e9e9 25vh, #e9e9e9);
14+
}
15+
16+
button {
17+
border: 0 none;
18+
padding: 0.5rem 1.5rem;
19+
background: #1188d4;
20+
color: #ffffff;
21+
text-transform: uppercase;
22+
}
23+
24+
button:focus {
25+
text-decoration: none;
26+
outline: 0 none;
27+
}
28+
29+
input {
30+
border: 0 none;
31+
padding: 0.5rem 1rem;
32+
}
33+
34+
input:focus {
35+
outline: 0 none;
36+
}
37+
38+
form {
39+
width: 100%;
40+
display: flex;
41+
flex-direction: row;
42+
}
43+
44+
form input {
45+
transition: all 0.5s;
46+
flex: 1
47+
}
48+
49+
.chat {
50+
max-width: 1100px;
51+
margin: 0 auto;
52+
}
53+
54+
.chat-header,
55+
.chat-footer {
56+
padding: 2rem;
57+
height: 10vh;
58+
background: #f7f7f7;
59+
display: flex;
60+
align-items: center;
61+
}
62+
63+
.chat-messages {
64+
height: 60vh;
65+
background: #ffffff;
66+
padding: 1rem 5rem;
67+
overflow: hidden;
68+
}
69+
70+
.chat-message {
71+
padding: 1rem 0 1rem 2.5rem;
72+
position: relative;
73+
min-height: 24px;
74+
}
75+
76+
.chat-message:before {
77+
content: '';
78+
background: url(data:image/svg+xml,%3Csvg%20fill%3D%22%23000000%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%20width%3D%2224%22%20xmlns%3D%22http%3A//www.w3.org/2000/svg%22%3E%0A%20%20%20%20%3Cpath%20d%3D%22M9%2011.75c-.69%200-1.25.56-1.25%201.25s.56%201.25%201.25%201.25%201.25-.56%201.25-1.25-.56-1.25-1.25-1.25zm6%200c-.69%200-1.25.56-1.25%201.25s.56%201.25%201.25%201.25%201.25-.56%201.25-1.25-.56-1.25-1.25-1.25zM12%202C6.48%202%202%206.48%202%2012s4.48%2010%2010%2010%2010-4.48%2010-10S17.52%202%2012%202zm0%2018c-4.41%200-8-3.59-8-8%200-.29.02-.58.05-.86%202.36-1.05%204.23-2.98%205.21-5.37C11.07%208.33%2014.05%2010%2017.42%2010c.78%200%201.53-.09%202.25-.26.21.71.33%201.47.33%202.26%200%204.41-3.59%208-8%208z%22/%3E%0A%20%20%20%20%3Cpath%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22/%3E%0A%3C/svg%3E);
79+
position: absolute;
80+
top: calc(50% - 12px);
81+
left: 0;
82+
width: 24px;
83+
height: 24px;
84+
}
85+
86+
.chat-message:not(:first-child) {
87+
border-top: 1px solid #e9e9e9;
88+
}
89+
90+
.chat-message strong {
91+
margin-right: 0.5rem;
92+
}
93+
94+
.username-form-container {
95+
transition: opacity 0.15s linear 0.55s;
96+
position: absolute;
97+
top: 0;
98+
left: 0;
99+
right: 0;
100+
bottom: 0;
101+
display: flex;
102+
align-items: center;
103+
justify-content: center;
104+
background: rgba(255, 255, 255, 0.95);
105+
}
106+
107+
.username-form-container .username-form {
108+
transition: transform 0.5s;
109+
width: calc(100% - 20vw - 4rem);
110+
max-width: calc(1100px - 4rem);
111+
}
112+
113+
.hide-username .username-form-container {
114+
opacity: 0;
115+
}
116+
117+
.hide-username .username-form {
118+
transform: translate3d(0, -35vh, 0);
119+
}
120+
121+
.hide-username .username-form input {
122+
padding: 0;
123+
height: 1rem;
124+
font-size: 1rem;
125+
background: transparent;
126+
}
127+
128+
.hide-username .username-form button {
129+
display: none;
130+
}

examples/11-chat.php

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
3+
require __DIR__ . '/../vendor/autoload.php';
4+
5+
use Clue\React\Sse\BufferedChannel;
6+
use React\Http\Request;
7+
use React\Http\Response;
8+
9+
$loop = React\EventLoop\Factory::create();
10+
$socket = new React\Socket\Server($loop);
11+
12+
$channel = new BufferedChannel();
13+
14+
$http = new React\Http\Server($socket);
15+
$http->on('request', function (Request $request, Response $response) use ($channel) {
16+
switch ($request->getPath()) {
17+
case '/':
18+
$response->writeHead('200', array('Content-Type' => 'text/html'));
19+
$response->end(file_get_contents(__DIR__ . '/10-eventsource.html'));
20+
21+
return;
22+
case '/styles.css':
23+
$response->writeHead('200', array('Content-Type' => 'text/css'));
24+
$response->end(file_get_contents(__DIR__ . '/10-styles.css'));
25+
return;
26+
case '/message':
27+
$query = $request->getQuery();
28+
if (isset($query['username'], $query['message'])) {
29+
$message = array('message' => $query['message'], 'username' =>$query['username']);
30+
$channel->writeMessage(json_encode($message));
31+
}
32+
$response->writeHead('201', array('Content-Type' => 'text/json'));
33+
$response->end();
34+
return;
35+
case '/chat':
36+
$id = $request->getHeaderLine('Last-Event-ID');
37+
38+
$response->writeHead(200, array('Content-Type' => 'text/event-stream'));
39+
$channel->connect($response, $id);
40+
41+
$message = array('message' => 'New person connected from '. $request->remoteAddress);
42+
$channel->writeMessage(json_encode($message));
43+
44+
$response->on('close', function () use ($response, $channel, $request) {
45+
$channel->disconnect($response);
46+
47+
$message = array('message' => 'Bye '. $request->remoteAddress);
48+
$channel->writeMessage(json_encode($message));
49+
});
50+
break;
51+
default:
52+
$response->writeHead(404);
53+
$response->end('Not Found');
54+
}
55+
});
56+
57+
$socket->listen(isset($argv[1]) ? $argv[1] : 0, '0.0.0.0');
58+
59+
echo 'Server now listening on http://localhost:' . $socket->getPort() . ' (port is first parameter)' . PHP_EOL;
60+
61+
$loop->run();

0 commit comments

Comments
 (0)