V2 (#1)
29
packages/lib/src/components/base/Cell.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components/native';
|
||||
import {
|
||||
Body,
|
||||
Emphasis,
|
||||
} from './text';
|
||||
|
||||
const Wrapper = styled.View`
|
||||
flex-direction: row;
|
||||
padding: 10px;
|
||||
`;
|
||||
|
||||
const Left = styled.View`
|
||||
width: 100px;
|
||||
`;
|
||||
|
||||
const Row = ({
|
||||
left,
|
||||
right,
|
||||
}) => (
|
||||
<Wrapper>
|
||||
<Left>
|
||||
<Emphasis>{left}:</Emphasis>
|
||||
</Left>
|
||||
<Body selectable={true}>{right}</Body>
|
||||
</Wrapper>
|
||||
)
|
||||
|
||||
export default Row;
|
||||
20
packages/lib/src/components/base/CellHeader.js
Normal file
@@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components/native';
|
||||
import {
|
||||
Emphasis,
|
||||
} from './text';
|
||||
|
||||
const Wrapper = styled.View`
|
||||
flex-direction: row;
|
||||
padding: 10px;
|
||||
`;
|
||||
|
||||
const Row = ({
|
||||
children,
|
||||
}) => (
|
||||
<Wrapper>
|
||||
<Emphasis>{children}:</Emphasis>
|
||||
</Wrapper>
|
||||
)
|
||||
|
||||
export default Row;
|
||||
BIN
packages/lib/src/components/base/Icon/check.png
Normal file
|
After Width: | Height: | Size: 5.9 KiB |
BIN
packages/lib/src/components/base/Icon/close.png
Normal file
|
After Width: | Height: | Size: 4.2 KiB |
BIN
packages/lib/src/components/base/Icon/download.png
Normal file
|
After Width: | Height: | Size: 5.2 KiB |
BIN
packages/lib/src/components/base/Icon/filter.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
47
packages/lib/src/components/base/Icon/index.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components/native';
|
||||
|
||||
import reload from './reload.png';
|
||||
import trash from './trash.png';
|
||||
import remove from './return.png';
|
||||
import right from './right.png';
|
||||
import left from './left.png';
|
||||
import play from './play.png';
|
||||
import download from './download.png';
|
||||
import close from './close.png';
|
||||
import filter from './filter.png';
|
||||
import square from './square.png';
|
||||
import check from './check.png';
|
||||
|
||||
const icons = {
|
||||
reload,
|
||||
trash,
|
||||
remove,
|
||||
right,
|
||||
left,
|
||||
play,
|
||||
download,
|
||||
close,
|
||||
filter,
|
||||
square,
|
||||
check,
|
||||
}
|
||||
|
||||
const Image = styled.Image`
|
||||
height: ${({ height }) => height || '16'}px;
|
||||
width: ${({ width }) => width || '16'}px;
|
||||
`;
|
||||
|
||||
const Icon = ({
|
||||
name,
|
||||
width,
|
||||
height
|
||||
}) => (
|
||||
<Image
|
||||
width={width}
|
||||
height={height}
|
||||
source={icons[name]}
|
||||
/>
|
||||
);
|
||||
|
||||
export default Icon;
|
||||
BIN
packages/lib/src/components/base/Icon/left.png
Normal file
|
After Width: | Height: | Size: 3.0 KiB |
BIN
packages/lib/src/components/base/Icon/play.png
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
packages/lib/src/components/base/Icon/reload.png
Normal file
|
After Width: | Height: | Size: 9.6 KiB |
BIN
packages/lib/src/components/base/Icon/return.png
Normal file
|
After Width: | Height: | Size: 6.9 KiB |
BIN
packages/lib/src/components/base/Icon/right.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
packages/lib/src/components/base/Icon/square.png
Normal file
|
After Width: | Height: | Size: 4.4 KiB |
BIN
packages/lib/src/components/base/Icon/trash.png
Normal file
|
After Width: | Height: | Size: 6.2 KiB |
5
packages/lib/src/components/base/Modal/index.js
Normal file
@@ -0,0 +1,5 @@
|
||||
import {
|
||||
Modal
|
||||
} from 'react-native';
|
||||
|
||||
export default Modal;
|
||||
41
packages/lib/src/components/base/Modal/index.web.js
Normal file
@@ -0,0 +1,41 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { createPortal } from 'react-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Wrapper = styled.div`
|
||||
position: fixed;
|
||||
background: #fff;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
`;
|
||||
|
||||
const Modal = ({
|
||||
visible,
|
||||
children
|
||||
}) => {
|
||||
const [root, setRoot] = useState();
|
||||
useEffect(() => {
|
||||
const elm = document.createElement('div');
|
||||
document.body.appendChild(elm);
|
||||
setRoot(elm);
|
||||
}, []);
|
||||
|
||||
const elm = visible ? (
|
||||
<Wrapper>{children}</Wrapper>
|
||||
) : null;
|
||||
|
||||
if (!root) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return createPortal(
|
||||
elm,
|
||||
root,
|
||||
);
|
||||
};
|
||||
|
||||
export default Modal;
|
||||
37
packages/lib/src/components/base/Row.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components/native';
|
||||
|
||||
const Wrapper = styled.View`
|
||||
flex-direction: row;
|
||||
padding: 10px;
|
||||
border-left-width: ${props => props.selected ? '10px' : '0'};
|
||||
border-left-color: #2980b9;
|
||||
border-bottom-width: 1px;
|
||||
border-bottom-color: #efefef;
|
||||
`;
|
||||
|
||||
const Left = styled.View`
|
||||
`;
|
||||
|
||||
const Right = styled.View`
|
||||
`;
|
||||
|
||||
const Center = styled.View`
|
||||
flex: 1;
|
||||
margin: 0 10px;
|
||||
`;
|
||||
|
||||
const Row = ({
|
||||
left,
|
||||
right,
|
||||
children,
|
||||
selected,
|
||||
}) => (
|
||||
<Wrapper selected={selected}>
|
||||
{left && <Left>{left}</Left>}
|
||||
<Center>{children}</Center>
|
||||
{right && <Right>{right}</Right>}
|
||||
</Wrapper>
|
||||
)
|
||||
|
||||
export default Row;
|
||||
44
packages/lib/src/components/base/Status.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components/native';
|
||||
import {
|
||||
Body,
|
||||
} from '../base/text';
|
||||
|
||||
const getColor = (code) => {
|
||||
if (code === 'Error') {
|
||||
return '#c0392b';
|
||||
}
|
||||
if (code >= 500) {
|
||||
return '#c0392b';
|
||||
}
|
||||
if (code >= 400) {
|
||||
return '#f1c40f';
|
||||
}
|
||||
if (code >= 300) {
|
||||
return '#2980b9';
|
||||
}
|
||||
return '#2ecc71';
|
||||
}
|
||||
|
||||
const Wrapper = styled.View`
|
||||
flex-direction: row;
|
||||
`;
|
||||
|
||||
const Icon = styled.View`
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 8px;
|
||||
background: ${props => getColor(props.code)};
|
||||
margin-left: 5px;
|
||||
`;
|
||||
|
||||
const Status = ({
|
||||
code,
|
||||
}) => (
|
||||
<Wrapper>
|
||||
<Body>{code}</Body>
|
||||
{code !== 'Waiting' && <Icon code={code} />}
|
||||
</Wrapper>
|
||||
)
|
||||
|
||||
export default Status;
|
||||
31
packages/lib/src/components/base/Toolbar/Button.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components/native';
|
||||
import Icon from '../Icon';
|
||||
import {
|
||||
Body,
|
||||
} from '../text';
|
||||
|
||||
const Item = styled.TouchableOpacity`
|
||||
padding: 10px 10px;
|
||||
opacity: ${({ disabled }) => disabled ? 0.3 : 1};
|
||||
`;
|
||||
|
||||
const Button = ({
|
||||
name,
|
||||
icon,
|
||||
onPress,
|
||||
disabled,
|
||||
}) => (
|
||||
<Item
|
||||
onPress={disabled ? undefined : onPress}
|
||||
disabled={disabled}
|
||||
>
|
||||
{icon ? (
|
||||
<Icon name={icon} />
|
||||
) : (
|
||||
<Body color={disabled ? '#ccc' : undefined}>{name}</Body>
|
||||
)}
|
||||
</Item>
|
||||
);
|
||||
|
||||
export default Button;
|
||||
74
packages/lib/src/components/base/Toolbar/Selector.js
Normal file
@@ -0,0 +1,74 @@
|
||||
import React, { Fragment, useState } from 'react';
|
||||
import {
|
||||
SafeAreaView,
|
||||
TouchableOpacity,
|
||||
} from 'react-native';
|
||||
import Button from './Button';
|
||||
import Row from '../Row';
|
||||
import Icon from '../Icon';
|
||||
import Modal from '../Modal';
|
||||
import {
|
||||
Body,
|
||||
} from '../text';
|
||||
|
||||
const Selector = ({
|
||||
multiSelect = false,
|
||||
onSelect,
|
||||
options = [],
|
||||
...others
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<Fragment>
|
||||
<Button
|
||||
{...others}
|
||||
onPress={() => {
|
||||
setOpen(true);
|
||||
}}
|
||||
/>
|
||||
<Modal
|
||||
animationType="slide"
|
||||
transparent={false}
|
||||
visible={!!open}
|
||||
onRequestClose={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<SafeAreaView
|
||||
forceInset={{ top: 'always', vertical: 'always' }}
|
||||
style={{flex: 1}}
|
||||
>
|
||||
<Button
|
||||
name="Close"
|
||||
icon="close"
|
||||
onPress={() => {
|
||||
setOpen(false);
|
||||
}}
|
||||
/>
|
||||
{options.map((option) => (
|
||||
<TouchableOpacity
|
||||
key={option.name}
|
||||
onPress={() => {
|
||||
if (!multiSelect) {
|
||||
options.forEach(o => o.selected = false);
|
||||
}
|
||||
option.selected = !option.selected
|
||||
onSelect(options);
|
||||
}}
|
||||
>
|
||||
<Row
|
||||
left={(
|
||||
<Icon name={option.selected ? 'check' : 'square'} />
|
||||
)}
|
||||
>
|
||||
<Body>{option.name}</Body>
|
||||
</Row>
|
||||
</TouchableOpacity>
|
||||
))}
|
||||
</SafeAreaView>
|
||||
</Modal>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
export default Selector;
|
||||
7
packages/lib/src/components/base/Toolbar/Seperator.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import styled from 'styled-components/native';
|
||||
|
||||
const Seperator = styled.View`
|
||||
flex: 1;
|
||||
`;
|
||||
|
||||
export default Seperator;
|
||||
29
packages/lib/src/components/base/Toolbar/index.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import React from 'react';
|
||||
import styled from 'styled-components/native';
|
||||
import Button from './Button';
|
||||
import Seperator from './Seperator';
|
||||
import Selector from './Selector';
|
||||
|
||||
export {
|
||||
Button,
|
||||
Seperator,
|
||||
Selector,
|
||||
}
|
||||
|
||||
const Wrapper = styled.View`
|
||||
flex-direction: row;
|
||||
align-items: center;
|
||||
border-bottom-width: 1px;
|
||||
border-color: #ccc;
|
||||
padding: 0 10px;
|
||||
`;
|
||||
|
||||
const Toolbar = ({
|
||||
children,
|
||||
}) => (
|
||||
<Wrapper>
|
||||
{children}
|
||||
</Wrapper>
|
||||
)
|
||||
|
||||
export default Toolbar;
|
||||
14
packages/lib/src/components/base/text.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import styled from 'styled-components/native';
|
||||
|
||||
export const Body = styled.Text`
|
||||
color: ${props => props.color || 'black'};
|
||||
`;
|
||||
|
||||
export const Emphasis = styled.Text`
|
||||
font-weight: bold;
|
||||
color: ${props => props.color || 'black'};
|
||||
`;
|
||||
|
||||
export const Fixed = styled.Text`
|
||||
font-family: Menlo-Regular;
|
||||
`;
|
||||