commit
6e5d5df875
23
README.md
23
README.md
|
@ -18,7 +18,7 @@ Follow the [React Native Getting Started Guide](https://facebook.github.io/react
|
|||
$ brew install watchman
|
||||
$ brew install yarn
|
||||
```
|
||||
|
||||
|
||||
- Clone repository and configure:
|
||||
```bash
|
||||
$ git clone git@github.com:RocketChat/Rocket.Chat.ReactNative.git
|
||||
|
@ -69,3 +69,24 @@ Follow the [React Native Getting Started Guide](https://facebook.github.io/react
|
|||
- Start emulator
|
||||
- Start react packager: `$ react-native start`
|
||||
- Run in emulator: `$ react-native run-android`
|
||||
|
||||
# Storybook
|
||||
- General requirements
|
||||
- Install storybook
|
||||
```bash
|
||||
$ npm i -g @storybook/cli
|
||||
```
|
||||
|
||||
- Running storybook
|
||||
- Run storybook application
|
||||
```bash
|
||||
$ npm run storybook
|
||||
```
|
||||
- Run application in other shell
|
||||
```bash
|
||||
$ react-native run-ios
|
||||
```
|
||||
- Running storybook on browser to help stories navigation
|
||||
```
|
||||
open http://localhost:7007/
|
||||
```
|
||||
|
|
|
@ -8,10 +8,10 @@ import avatarInitialsAndColor from '../utils/avatarInitialsAndColor';
|
|||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
// flex: 1,
|
||||
flexDirection: 'row',
|
||||
paddingLeft: 16,
|
||||
paddingRight: 56,
|
||||
paddingRight: 16,
|
||||
height: 56,
|
||||
alignItems: 'center'
|
||||
},
|
||||
|
@ -23,15 +23,15 @@ const styles = StyleSheet.create({
|
|||
textAlign: 'center',
|
||||
overflow: 'hidden',
|
||||
fontSize: 14,
|
||||
right: 16,
|
||||
marginLeft: 16,
|
||||
position: 'absolute'
|
||||
paddingLeft: 5,
|
||||
paddingRight: 5
|
||||
},
|
||||
roomName: {
|
||||
flexGrow: 1,
|
||||
flex: 1,
|
||||
fontSize: 16,
|
||||
color: '#444',
|
||||
marginLeft: 16
|
||||
marginLeft: 16,
|
||||
marginRight: 4
|
||||
},
|
||||
iconContainer: {
|
||||
height: 40,
|
||||
|
@ -52,36 +52,39 @@ const styles = StyleSheet.create({
|
|||
borderRadius: 20
|
||||
},
|
||||
avatarInitials: {
|
||||
fontSize: 22,
|
||||
fontSize: 20,
|
||||
color: '#ffffff'
|
||||
}
|
||||
});
|
||||
|
||||
export default class RoomItem extends React.PureComponent {
|
||||
static propTypes = {
|
||||
item: PropTypes.object.isRequired,
|
||||
type: PropTypes.string.isRequired,
|
||||
name: PropTypes.string.isRequired,
|
||||
unread: PropTypes.number,
|
||||
baseUrl: PropTypes.string
|
||||
}
|
||||
|
||||
get icon() {
|
||||
const { type, name, baseUrl } = this.props;
|
||||
|
||||
const icon = {
|
||||
d: 'at',
|
||||
c: 'pound',
|
||||
p: 'lock',
|
||||
l: 'account'
|
||||
}[this.props.item.t];
|
||||
}[type];
|
||||
|
||||
if (!icon) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { name } = this.props.item;
|
||||
|
||||
if (this.props.item.t === 'd') {
|
||||
if (type === 'd') {
|
||||
const { initials, color } = avatarInitialsAndColor(name);
|
||||
return (
|
||||
<View style={[styles.iconContainer, { backgroundColor: color }]}>
|
||||
<Text style={styles.avatarInitials}>{initials}</Text>
|
||||
<CachedImage style={styles.avatar} source={{ uri: `${ this.props.baseUrl }/avatar/${ name }` }} />
|
||||
<CachedImage style={styles.avatar} source={{ uri: `${ baseUrl }/avatar/${ name }` }} />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
@ -95,26 +98,30 @@ export default class RoomItem extends React.PureComponent {
|
|||
);
|
||||
}
|
||||
|
||||
renderNumber = (item) => {
|
||||
if (item.unread) {
|
||||
return (
|
||||
<Text style={styles.number}>
|
||||
{ item.unread }
|
||||
</Text>
|
||||
);
|
||||
renderNumber = (unread) => {
|
||||
if (!unread || unread <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (unread >= 1000) {
|
||||
unread = '999+';
|
||||
}
|
||||
|
||||
return (
|
||||
<Text style={styles.number}>
|
||||
{ unread }
|
||||
</Text>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
let extraSpace = {};
|
||||
if (this.props.item.unread) {
|
||||
extraSpace = { paddingRight: 92 };
|
||||
}
|
||||
const { unread, name } = this.props;
|
||||
|
||||
return (
|
||||
<View style={[styles.container, extraSpace]}>
|
||||
<View style={styles.container}>
|
||||
{this.icon}
|
||||
<Text style={styles.roomName} ellipsizeMode='tail' numberOfLines={1}>{ this.props.item.name }</Text>
|
||||
{this.renderNumber(this.props.item)}
|
||||
<Text style={styles.roomName} ellipsizeMode='tail' numberOfLines={1}>{ name }</Text>
|
||||
{this.renderNumber(unread)}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -84,7 +84,9 @@ class RoomsListItem extends React.PureComponent {
|
|||
<TouchableOpacity key={item._id} onPress={() => this.props.onPress(item._id, item)}>
|
||||
<RoomItem
|
||||
id={item._id}
|
||||
item={item}
|
||||
type={item.t}
|
||||
name={item.name}
|
||||
unread={item.unread}
|
||||
baseUrl={this.props.baseUrl}
|
||||
/>
|
||||
</TouchableOpacity>
|
||||
|
|
|
@ -8,7 +8,8 @@
|
|||
"lint": "eslint .",
|
||||
"ios": "react-native run-ios",
|
||||
"log-android": "react-native log-android",
|
||||
"android": "react-native run-android"
|
||||
"android": "react-native run-android",
|
||||
"storybook": "storybook start -p 7007"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-plugin-transform-decorators-legacy": "^1.3.4",
|
||||
|
@ -56,7 +57,9 @@
|
|||
"eslint-plugin-react": "^7.1.0",
|
||||
"eslint-plugin-react-native": "^3.0.1",
|
||||
"jest": "20.0.4",
|
||||
"react-test-renderer": "16.0.0-alpha.12"
|
||||
"react-test-renderer": "16.0.0-alpha.12",
|
||||
"@storybook/react-native": "^3.2.4",
|
||||
"react-dom": "16.0.0-alpha.12"
|
||||
},
|
||||
"jest": {
|
||||
"preset": "react-native"
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
|
||||
|
||||
import '@storybook/addon-actions/register';
|
||||
import '@storybook/addon-links/register';
|
|
@ -0,0 +1,3 @@
|
|||
import StorybookUI from './storybook';
|
||||
|
||||
export default StorybookUI;
|
|
@ -0,0 +1,3 @@
|
|||
import StorybookUI from './storybook';
|
||||
|
||||
export default StorybookUI;
|
|
@ -0,0 +1,22 @@
|
|||
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
|
||||
|
||||
import React, { PropTypes } from 'react';
|
||||
import { TouchableNativeFeedback } from 'react-native';
|
||||
|
||||
export default function Button(props) {
|
||||
return (
|
||||
<TouchableNativeFeedback onPress={props.onPress}>
|
||||
{props.children}
|
||||
</TouchableNativeFeedback>
|
||||
);
|
||||
}
|
||||
|
||||
Button.defaultProps = {
|
||||
children: null,
|
||||
onPress: () => {},
|
||||
};
|
||||
|
||||
Button.propTypes = {
|
||||
children: PropTypes.node,
|
||||
onPress: PropTypes.func,
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
|
||||
|
||||
import React, { PropTypes } from 'react';
|
||||
import { TouchableHighlight } from 'react-native';
|
||||
|
||||
export default function Button(props) {
|
||||
return (
|
||||
<TouchableHighlight onPress={props.onPress}>
|
||||
{props.children}
|
||||
</TouchableHighlight>
|
||||
);
|
||||
}
|
||||
|
||||
Button.defaultProps = {
|
||||
children: null,
|
||||
onPress: () => {},
|
||||
};
|
||||
|
||||
Button.propTypes = {
|
||||
children: PropTypes.node,
|
||||
onPress: PropTypes.func,
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
|
||||
|
||||
import React, { PropTypes } from 'react';
|
||||
import { View } from 'react-native';
|
||||
import style from './style';
|
||||
|
||||
export default function CenterView(props) {
|
||||
return (
|
||||
<View style={style.main}>
|
||||
{props.children}
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
CenterView.defaultProps = {
|
||||
children: null,
|
||||
};
|
||||
|
||||
CenterView.propTypes = {
|
||||
children: PropTypes.node,
|
||||
};
|
|
@ -0,0 +1,8 @@
|
|||
export default {
|
||||
main: {
|
||||
flex: 1,
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
backgroundColor: '#F5FCFF',
|
||||
},
|
||||
};
|
|
@ -0,0 +1,65 @@
|
|||
import React from 'react';
|
||||
import { ScrollView } from 'react-native';
|
||||
|
||||
import RoomItem from '../../../app/components/RoomItem';
|
||||
|
||||
export default (
|
||||
<ScrollView>
|
||||
<RoomItem
|
||||
type='d'
|
||||
name='rocket.cat'
|
||||
baseUrl='https://demo.rocket.chat'
|
||||
/>
|
||||
<RoomItem
|
||||
type='d'
|
||||
unread={0}
|
||||
name='rocket.cat'
|
||||
baseUrl='https://demo.rocket.chat'
|
||||
/>
|
||||
<RoomItem
|
||||
type='d'
|
||||
unread={1}
|
||||
name='rocket.cat'
|
||||
baseUrl='https://demo.rocket.chat'
|
||||
/>
|
||||
<RoomItem
|
||||
type='d'
|
||||
unread={9}
|
||||
name="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries"
|
||||
baseUrl='https://demo.rocket.chat'
|
||||
/>
|
||||
<RoomItem
|
||||
type='d'
|
||||
unread={99}
|
||||
name="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries"
|
||||
baseUrl='https://demo.rocket.chat'
|
||||
/>
|
||||
<RoomItem
|
||||
type='d'
|
||||
unread={100}
|
||||
name="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries"
|
||||
baseUrl='https://demo.rocket.chat'
|
||||
/>
|
||||
<RoomItem
|
||||
type='d'
|
||||
unread={100000}
|
||||
name="Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. It has survived not only five centuries"
|
||||
baseUrl='https://demo.rocket.chat'
|
||||
/>
|
||||
<RoomItem
|
||||
type='d'
|
||||
name='W'
|
||||
unread={-100}
|
||||
/>
|
||||
<RoomItem
|
||||
type='d'
|
||||
name='WW'
|
||||
unread={-100}
|
||||
/>
|
||||
<RoomItem
|
||||
type='d'
|
||||
name=''
|
||||
unread={-100}
|
||||
/>
|
||||
</ScrollView>
|
||||
);
|
|
@ -0,0 +1,54 @@
|
|||
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
|
||||
|
||||
import React, { PropTypes } from 'react';
|
||||
import { View, Text, Button } from 'react-native';
|
||||
|
||||
export default class Welcome extends React.Component {
|
||||
styles = {
|
||||
wrapper: {
|
||||
flex: 1,
|
||||
padding: 24,
|
||||
justifyContent: 'center'
|
||||
},
|
||||
header: {
|
||||
fontSize: 18,
|
||||
marginBottom: 18
|
||||
},
|
||||
content: {
|
||||
fontSize: 12,
|
||||
marginBottom: 10,
|
||||
lineHeight: 18
|
||||
}
|
||||
};
|
||||
|
||||
showApp(event) {
|
||||
event.preventDefault();
|
||||
if (this.props.showApp) { this.props.showApp(); }
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View style={this.styles.wrapper}>
|
||||
<Text style={this.styles.header}>Welcome to React Native Storybook</Text>
|
||||
<Text style={this.styles.content}>
|
||||
This is a UI Component development environment for your React Native app. Here you can
|
||||
display and interact with your UI components as stories. A story is a single state of one
|
||||
or more UI components. You can have as many stories as you want. In other words a story is
|
||||
like a visual test case.
|
||||
</Text>
|
||||
<Text style={this.styles.content}>
|
||||
We have added some stories inside the "storybook/stories" directory for examples. Try
|
||||
editing the "storybook/stories/Welcome.js" file to edit this message.
|
||||
</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Welcome.defaultProps = {
|
||||
showApp: null
|
||||
};
|
||||
|
||||
Welcome.propTypes = {
|
||||
showApp: PropTypes.func
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions */
|
||||
|
||||
// import React from 'react';
|
||||
|
||||
import { storiesOf } from '@storybook/react-native';
|
||||
// import { action } from '@storybook/addon-actions';
|
||||
// import { linkTo } from '@storybook/addon-links';
|
||||
|
||||
import DirectMessage from './Channels/DirectMessage';
|
||||
|
||||
storiesOf('Channel Cell', module).add('Direct Messages', () => DirectMessage);
|
||||
|
||||
// storiesOf('Welcome', module).add('to Storybook', () => <Welcome showApp={linkTo('Button')} />);
|
||||
|
||||
// storiesOf('Button', module)
|
||||
// .addDecorator(getStory => (
|
||||
// <CenterView>
|
||||
// {getStory()}
|
||||
// </CenterView>
|
||||
// ))
|
||||
// .add('with text', () => (
|
||||
// <Button onPress={action('clicked-text')}>
|
||||
// <Text>Hello Button</Text>
|
||||
// </Button>
|
||||
// ))
|
|
@ -0,0 +1,25 @@
|
|||
/* eslint-disable import/no-extraneous-dependencies, import/no-unresolved, import/extensions, global-require */
|
||||
|
||||
import { Navigation } from 'react-native-navigation';
|
||||
import { getStorybookUI, configure } from '@storybook/react-native';
|
||||
|
||||
// import stories
|
||||
configure(() => {
|
||||
require('./stories');
|
||||
}, module);
|
||||
|
||||
// This assumes that storybook is running on the same host as your RN packager,
|
||||
// to set manually use, e.g. host: 'localhost' option
|
||||
const StorybookUI = getStorybookUI({ port: 7007, onDeviceUI: true });
|
||||
Navigation.registerComponent('storybook.UI', () => StorybookUI);
|
||||
Navigation.startSingleScreenApp({
|
||||
screen: {
|
||||
screen: 'storybook.UI',
|
||||
title: 'Storybook',
|
||||
navigatorStyle: {
|
||||
navBarHidden: true
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default StorybookUI;
|
Loading…
Reference in New Issue