initial commit

This commit is contained in:
cudr
2019-10-05 11:44:49 +03:00
commit a817eb1ceb
63 changed files with 1769 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
import React, { Component } from 'react'
import faker from 'faker'
import styled from '@emotion/styled'
import Room from './Room'
class App extends Component<{}, { rooms: string[] }> {
state = {
rooms: []
}
componentDidMount() {
this.addRoom()
}
render() {
const { rooms } = this.state
return (
<Container>
<AddButton type="button" onClick={this.addRoom}>
Add Room
</AddButton>
{rooms.map(room => (
<Room key={room} slug={room} removeRoom={this.removeRoom(room)} />
))}
</Container>
)
}
addRoom = () => {
const room = faker.lorem.slug(4)
this.setState({ rooms: [...this.state.rooms, room] })
}
removeRoom = (room: string) => () => {
this.setState({
rooms: this.state.rooms.filter(r => r !== room)
})
}
}
export default App
const Container = styled.div``
const Button = styled.button`
padding: 6px 14px;
display: block;
outline: none;
font-size: 14px;
max-width: 200px;
text-align: center;
color: palevioletred;
border: 2px solid palevioletred;
`
const AddButton = styled(Button)`
margin-left: 30px;
color: violet;
border: 2px solid violet;
`

View File

@@ -0,0 +1,101 @@
import React, { Component } from 'react'
import { Value, ValueJSON } from 'slate'
import { Editor } from 'slate-react'
import styled from '@emotion/styled'
import ClientPlugin from '@slate-collaborative/client'
import defaultValue from './defaultValue'
import { Instance, ClientFrame, Title, H4, Button } from './elements'
interface ClienProps {
name: string
id: string
slug: string
removeUser: (id: any) => void
}
class Client extends Component<ClienProps> {
editor: any
state = {
value: Value.fromJSON(defaultValue as ValueJSON),
isOnline: true,
plugins: []
}
componentDidMount() {
const plugin = ClientPlugin({
url: `http://localhost:9000/${this.props.slug}`,
connectOpts: {
query: {
name: this.props.name,
token: this.props.id,
slug: this.props.slug
}
},
// preloader: () => <div>PRELOADER!!!!!!</div>,
onConnect: this.onConnect,
onDisconnect: this.onDisconnect
})
this.setState({
plugins: [plugin]
})
}
render() {
const { plugins, isOnline, value } = this.state
const { id, name } = this.props
return (
<Instance online={isOnline}>
<Title>
<Head>Editor: {name}</Head>
<Button type="button" onClick={this.toggleOnline}>
Go {isOnline ? 'offline' : 'online'}
</Button>
<Button type="button" onClick={() => this.props.removeUser(id)}>
Remove
</Button>
</Title>
<ClientFrame>
<Editor
value={value}
ref={this.ref}
plugins={plugins}
onChange={this.onChange}
/>
</ClientFrame>
</Instance>
)
}
onChange = ({ value }: any) => {
this.setState({ value })
}
onConnect = () => this.setState({ isOnline: true })
onDisconnect = () => this.setState({ isOnline: false })
ref = node => {
this.editor = node
}
toggleOnline = () => {
const { isOnline } = this.state
const { connect, disconnect } = this.editor.connection
isOnline ? disconnect() : connect()
}
}
export default Client
const Head = styled(H4)`
margin-right: auto;
`

View File

@@ -0,0 +1,92 @@
import React, { Component, ChangeEvent } from 'react'
import faker from 'faker'
import debounce from 'lodash/debounce'
import { RoomWrapper, H4, Title, Button, Grid, Input } from './elements'
import Client from './Client'
interface User {
id: string
name: string
}
interface RoomProps {
slug: string
removeRoom: () => void
}
interface RoomState {
users: User[]
slug: string
rebuild: boolean
}
class Room extends Component<RoomProps, RoomState> {
state = {
users: [],
slug: this.props.slug,
rebuild: false
}
componentDidMount() {
this.addUser()
}
render() {
const { users, slug, rebuild } = this.state
return (
<RoomWrapper>
<Title>
<H4>Document slug:</H4>
<Input type="text" value={slug} onChange={this.changeSlug} />
<Button type="button" onClick={this.addUser}>
Add random user
</Button>
<Button type="button" onClick={this.props.removeRoom}>
Remove Room
</Button>
</Title>
<Grid>
{users.map(
(user: User) =>
!rebuild && (
<Client
{...user}
slug={slug}
key={user.id}
removeUser={this.removeUser}
/>
)
)}
</Grid>
</RoomWrapper>
)
}
addUser = () => {
const user = {
id: faker.random.uuid(),
name: `${faker.name.firstName()} ${faker.name.lastName()}`
}
this.setState({ users: [...this.state.users, user] })
}
removeUser = (userId: string) => {
this.setState({
users: this.state.users.filter((u: User) => u.id !== userId)
})
}
changeSlug = (e: ChangeEvent<HTMLInputElement>) => {
this.setState({ slug: e.target.value }, this.rebuildClient)
}
rebuildClient = debounce(() => {
this.setState({ rebuild: true }, () => this.setState({ rebuild: false }))
}, 300)
}
export default Room

View File

@@ -0,0 +1,17 @@
module.exports = {
document: {
nodes: [
{
object: 'block',
type: 'paragraph',
nodes: [
{
object: 'text',
marks: [],
text: 'Hello collaborator!'
}
]
}
]
}
}

View File

@@ -0,0 +1,64 @@
import styled from '@emotion/styled'
export const RoomWrapper = styled.div`
padding: 30px;
border-bottom: 2px solid #e8e8e8;
`
export const H4 = styled.h4`
margin: 0;
padding-right: 10px;
`
export const Input = styled.input`
padding: 6px 14px;
font-size: 14px;
margin-right: 10px;
min-width: 240px;
outline: none;
border: 2px solid palevioletred;
& + button {
margin-left: auto;
}
`
export const Button = styled.button`
padding: 6px 14px;
display: block;
outline: none;
font-size: 14px;
text-align: center;
color: palevioletred;
white-space: nowrap;
border: 2px solid palevioletred;
& + button {
margin-left: 10px;
}
`
export const Grid = styled.div`
display: grid;
grid-gap: 2vw;
grid-template-columns: 1fr 1fr;
`
export const Title = styled.div`
display: flex;
align-items: center;
margin-bottom: 20px;
`
export const Instance = styled.div<{ online: boolean }>`
background: ${props =>
props.online ? 'rgba(128, 128, 128, 0.1)' : 'rgba(247, 0, 0, 0.2)'};
padding: 20px 30px 40px;
`
export const ClientFrame = styled.div`
box-shadow: 2px 2px 4px rgba(128, 128, 128, 0.2);
padding: 10px;
min-height: 70px;
margin-left: -10px;
margin-right: -10px;
background: white;
`

View File

@@ -0,0 +1,6 @@
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
ReactDOM.render(<App />, document.getElementById('root'))

View File

@@ -0,0 +1 @@
/// <reference types="react-scripts" />