1
0
mirror of https://github.com/fazo96/ipfs-boards synced 2025-01-10 12:24:20 +01:00

UI Improvements

This commit is contained in:
Enrico Fasoli 2018-02-07 23:00:50 +01:00
parent 1a91c3e679
commit 443cef55a5
No known key found for this signature in database
GPG Key ID: 1238873C5F27DB4D
11 changed files with 149 additions and 55 deletions

View File

@ -9,4 +9,5 @@ export const UPDATE_BOARD = 'UPDATE_BOARD'
export const BOARD_ERROR = 'BOARD_ERROR' export const BOARD_ERROR = 'BOARD_ERROR'
export const ORBITDB_WRITE = 'ORBITDB_WRITE' export const ORBITDB_WRITE = 'ORBITDB_WRITE'
export const ORBITDB_REPLICATE = 'ORBITDB_REPLICATE'
export const ORBITDB_REPLICATED = 'ORBITDB_REPLICATED' export const ORBITDB_REPLICATED = 'ORBITDB_REPLICATED'

View File

@ -4,7 +4,7 @@ import { Divider, Icon, Grid, Segment, Header, List, Button, Card } from 'semant
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { shortenAddress } from '../utils/orbitdb'; import { shortenAddress } from '../utils/orbitdb';
export default function Board({ address, posts, metadata }) { export default function Board({ address, posts, metadata, replicating }) {
const { email, website, title } = metadata || {} const { email, website, title } = metadata || {}
const url = window.location.href const url = window.location.href
return <Grid container divided colums={2}> return <Grid container divided colums={2}>
@ -39,10 +39,10 @@ export default function Board({ address, posts, metadata }) {
</List.Content> </List.Content>
</List.Item> </List.Item>
<List.Item> <List.Item>
<List.Icon name='wifi' size="large" verticalAlign="middle"/> <List.Icon color={replicating ? 'green' : null} name='wifi' size="large" verticalAlign="middle"/>
<List.Content> <List.Content>
<List.Header>Replication Status</List.Header> <List.Header>Replication</List.Header>
<List.Content>Idle</List.Content> <List.Content>{replicating ? 'Receiving Content...' : 'Idle'}</List.Content>
</List.Content> </List.Content>
</List.Item> </List.Item>
<List.Item> <List.Item>
@ -60,9 +60,16 @@ export default function Board({ address, posts, metadata }) {
</List.Content> </List.Content>
</List.Item> </List.Item>
</List> </List>
<div className='ui two buttons'> <div className='ui three buttons basic'>
<Button>Edit</Button> <Button>
<Button as={Link} to={shortenAddress(address)+'/p/new'}>New Post</Button> <Icon name='left arrow'/> Boards
</Button>
<Button>
<Icon name='pencil'/> Edit
</Button>
<Button as={Link} to={shortenAddress(address)+'/p/new'}>
<Icon name='plus'/> New Post
</Button>
</div> </div>
</Grid.Column> </Grid.Column>
<Grid.Column width={8}> <Grid.Column width={8}>

View File

@ -1,5 +1,7 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import { Form, Button } from 'semantic-ui-react' import { Redirect } from 'react-router-dom'
import { Container, Card, Form, Button } from 'semantic-ui-react'
import { shortenAddress } from '../utils/orbitdb'
export default class BoardForm extends Component { export default class BoardForm extends Component {
constructor(props){ constructor(props){
@ -16,22 +18,32 @@ export default class BoardForm extends Component {
render() { render() {
const { address } = this.state const { address } = this.state
const { onSave, creating } = this.props const { openBoard, opening } = this.props
return <Form> return <Container>
<Form.Field> <Card fluid centered style={{marginTop:'5em',maxWidth:'40em'}}>
<label>Address</label> <Card.Content>
<input <Card.Header>Open a Board</Card.Header>
placeholder="Paste an existing address or write your new board ID" <Card.Meta>
value={address} Boards is an experimental peer to peer application.<br/>
onChange={this.updateAddress.bind(this)} All content you publish will be public and may be lost or
/> changed at any time.<br/>
</Form.Field> Please do not use this version of Boards
<Button for anything other than testing purposes
type='submit' </Card.Meta>
onClick={() => onSave({ address })} </Card.Content>
disabled={creating} <Card.Content>
>Create</Button> <Form loading={opening}>
{creating ? 'Creating the board...' : ''} <Form.Field>
</Form> <input
placeholder="Paste an existing address or write your new board ID"
value={address}
onChange={this.updateAddress.bind(this)}
/>
</Form.Field>
<Button fluid onClick={() => openBoard({ address })}>Open</Button>
</Form>
</Card.Content>
</Card>
</Container>
} }
} }

View File

@ -1,12 +1,67 @@
import React from 'react' import React from 'react'
import { Button, Card } from 'semantic-ui-react' import { List, Icon, Segment, Divider, Grid, Header, Button, Card } from 'semantic-ui-react'
import { Link } from 'react-router-dom'
import BoardsItem from './BoardsItem' import BoardsItem from './BoardsItem'
export default function Boards({ boards, createBoard }) { export default function Boards({ boards, createBoard }) {
return <div> return <Grid container divided colums={2}>
<Card.Group> <Grid.Column width={8}>
{Object.values(boards).map(board => <BoardsItem key={board.address} {...board} />)} <Header size='large' style={{marginTop:'.5em'}}>
</Card.Group> <Header.Content>IPFS Boards</Header.Content>
<Button onClick={createBoard}>New Board</Button> <Header.Subheader>Experimental Build</Header.Subheader>
</div> </Header>
<Divider />
<List relaxed>
<List.Item>
<List.Icon name='file text outline' size="large" verticalAlign="middle"/>
<List.Content>
<List.Header>Boards</List.Header>
<List.Content>{Object.keys(boards).length}</List.Content>
</List.Content>
</List.Item>
<List.Item>
<List.Icon name='wifi' size="large" verticalAlign="middle"/>
<List.Content>
<List.Header>Connected Peers</List.Header>
<List.Content>?</List.Content>
</List.Content>
</List.Item>
<List.Item>
<List.Icon name='disk outline' size="large" verticalAlign="middle"/>
<List.Content>
<List.Header>Used Space</List.Header>
<List.Content>?</List.Content>
</List.Content>
</List.Item>
<List.Item>
<List.Icon name='user' size="large" verticalAlign="middle"/>
<List.Content>
<List.Header>IPFS ID</List.Header>
<List.Content>?</List.Content>
</List.Content>
</List.Item>
<List.Item>
<List.Icon name='key' size="large" verticalAlign="middle"/>
<List.Content>
<List.Header>OrbitDB Public Key</List.Header>
<List.Content>?</List.Content>
</List.Content>
</List.Item>
</List>
<div className="ui two buttons">
<Button as='a' href="https://github.com/fazo96/ipfs-boards">
<Icon name="github"/> GitHub
</Button>
<Button as={Link} to={'/b/new'}>
Open or Create Board
</Button>
</div>
</Grid.Column>
<Grid.Column width={8} style={{paddingTop:'3em'}}>
<Card.Group className="centered">
{Object.values(boards).map(board => <BoardsItem key={board.address} {...board} />)}
{Object.keys(boards).length === 0 ? <Segment>No boards opened</Segment> : null}
</Card.Group>
</Grid.Column>
</Grid>
} }

View File

@ -4,14 +4,16 @@ import { Link } from 'react-router-dom'
import { shortenAddress } from '../utils/orbitdb' import { shortenAddress } from '../utils/orbitdb'
export default function BoardsItem({ address, title }) { export default function BoardsItem({ address, title }) {
return <Card> return <Card fluid>
<Card.Content> <Card.Content>
<Card.Header> <Card.Header>
{ title || 'Untitled board' } { title || 'Unnamed board' }
</Card.Header> </Card.Header>
<Card.Meta> <Card.Meta>
Board Board
</Card.Meta> </Card.Meta>
</Card.Content>
<Card.Content>
<Card.Description style={{wordBreak:'break-all'}}> <Card.Description style={{wordBreak:'break-all'}}>
{address} {address}
</Card.Description> </Card.Description>

View File

@ -4,7 +4,10 @@ import { Card, Icon } from 'semantic-ui-react'
export default function Post({ title, multihash}) { export default function Post({ title, multihash}) {
return <Card fluid> return <Card fluid>
<Card.Content> <Card.Content>
<Icon name="file text outline"/> {title} <Card.Header>
{title}
</Card.Header>
<Card.Meta>Post</Card.Meta>
</Card.Content> </Card.Content>
<Card.Content style={{wordBreak:'break-all'}}> <Card.Content style={{wordBreak:'break-all'}}>
<Icon name="chain"/> <a href={'//ipfs.io/ipfs/'+multihash}>View</a> <Icon name="chain"/> <a href={'//ipfs.io/ipfs/'+multihash}>View</a>

View File

@ -3,13 +3,13 @@ import { connect } from 'react-redux'
import BoardForm from '../components/BoardForm' import BoardForm from '../components/BoardForm'
import { openBoard } from '../actions/board' import { openBoard } from '../actions/board'
function BoardEditor({ board, openBoard }) { function BoardEditor(props) {
return <BoardForm board={board} onSave={openBoard} /> return <BoardForm {...props} />
} }
function mapStateToProps(state){ function mapStateToProps(state){
return { return {
board: state.boardEditor.board opening: state.boardEditor.opening
} }
} }

View File

@ -5,19 +5,16 @@ import {
function getInitialState() { function getInitialState() {
return { return {
board: { opening: false
name: ''
},
creating: false
} }
} }
export default function BoardEditorReducer(state = getInitialState(), action) { export default function BoardEditorReducer(state = getInitialState(), action) {
switch (action.type) { switch (action.type) {
case OPEN_BOARD: case OPEN_BOARD:
return Object.assign({}, state, { board: action.board, opening: true }) return Object.assign({}, state, { opening: true })
case OPENED_BOARD: case OPENED_BOARD:
return Object.assign({}, state, { opening: false, board: action.board }) return Object.assign({}, state, { opening: false })
default: default:
return state return state
} }

View File

@ -1,4 +1,4 @@
import { OPENED_BOARD, UPDATE_BOARD } from '../actions/actionTypes' import { OPENED_BOARD, UPDATE_BOARD, ORBITDB_REPLICATED, ORBITDB_REPLICATE } from '../actions/actionTypes'
import { getBoardIdFromAddress } from '../utils/orbitdb' import { getBoardIdFromAddress } from '../utils/orbitdb'
function getInitialState() { function getInitialState() {
@ -7,20 +7,32 @@ function getInitialState() {
} }
} }
function updateBoard(existingBoards, address, value) {
return Object.assign({}, existingBoards, {
[address]: Object.assign({}, existingBoards[address] || {}, value)
})
}
export default function BoardsReducer(state = getInitialState(), action) { export default function BoardsReducer(state = getInitialState(), action) {
let address, newBoards let address
switch (action.type) { switch (action.type) {
case OPENED_BOARD: case OPENED_BOARD:
address = action.board.address address = action.board.address
newBoards = Object.assign({}, state.boards, { [address]: action.board }) return Object.assign({}, state, { boards: updateBoard(state.boards, address, action.board) })
return Object.assign({}, state, { boards: newBoards })
case UPDATE_BOARD: case UPDATE_BOARD:
address = action.address address = action.address
let { posts, metadata } = action let { posts, metadata } = action
newBoards = Object.assign({}, state.boards, { return Object.assign({}, state, { boards: updateBoard(state.boards, address, { posts, metadata })})
[address]: Object.assign({}, state.boards[address], { posts, metadata }) case ORBITDB_REPLICATE:
}) address = action.address
return Object.assign({}, state, { boards: newBoards }) return Object.assign({}, state, { boards: updateBoard(state.boards, address, {
replicating: true
})})
case ORBITDB_REPLICATED:
address = action.address
return Object.assign({}, state, { boards: updateBoard(state.boards, address, {
replicating: false
})})
default: default:
return state; return state;
} }

View File

@ -3,9 +3,13 @@ import { eventChannel } from 'redux-saga'
import { push } from 'react-router-redux' import { push } from 'react-router-redux'
import { open, connectDb } from '../orbitdb' import { open, connectDb } from '../orbitdb'
import { creatingBoard, createdBoard, boardError } from '../actions/board' import { creatingBoard, createdBoard, boardError } from '../actions/board'
import { getBoardIdFromAddress } from '../utils/orbitdb' import { getBoardIdFromAddress, shortenAddress } from '../utils/orbitdb'
import { UPDATE_BOARD } from '../actions/actionTypes' import { UPDATE_BOARD } from '../actions/actionTypes'
export function* goToBoard({ board }){
yield put(push(shortenAddress(board.address)))
}
export function* updateBoard({ address }){ export function* updateBoard({ address }){
const db = window.dbs[address] const db = window.dbs[address]
yield put({ yield put({

View File

@ -1,10 +1,11 @@
import { takeEvery } from 'redux-saga/effects' import { takeEvery } from 'redux-saga/effects'
import { OPEN_BOARD, ADD_POST, ORBITDB_REPLICATED, ORBITDB_WRITE } from '../actions/actionTypes' import { OPEN_BOARD, OPENED_BOARD, ADD_POST, ORBITDB_REPLICATED, ORBITDB_WRITE } from '../actions/actionTypes'
import { openBoard, updateBoard } from './boards' import { openBoard, updateBoard, goToBoard } from './boards'
import { addPost } from './posts' import { addPost } from './posts'
export default function* saga(){ export default function* saga(){
yield takeEvery(OPEN_BOARD, openBoard) yield takeEvery(OPEN_BOARD, openBoard)
yield takeEvery(OPENED_BOARD, goToBoard)
yield takeEvery(ADD_POST, addPost) yield takeEvery(ADD_POST, addPost)
yield takeEvery(ORBITDB_WRITE, updateBoard) yield takeEvery(ORBITDB_WRITE, updateBoard)
yield takeEvery(ORBITDB_REPLICATED, updateBoard) yield takeEvery(ORBITDB_REPLICATED, updateBoard)