chroe: add todos example for miniapp (#3396)

This commit is contained in:
f00bar 2020-08-06 00:22:47 +08:00 committed by GitHub
parent 0bcbd669de
commit 105a496f68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 428 additions and 0 deletions

View File

@ -0,0 +1,3 @@
# todos example with react for miniapp
https://github.com/ice-lab/icejs/tree/master/examples

View File

@ -0,0 +1,3 @@
{
"targets": ["miniapp"]
}

View File

@ -0,0 +1,20 @@
{
"name": "todos-example-with-miniapp",
"description": "miniapp example",
"dependencies": {
"react": "^16.4.1",
"react-dom": "^16.4.1",
"universal-request": "^2.2.0"
},
"devDependencies": {
"miniapp-history": "^0.1.2",
"miniapp-render": "^1.0.1"
},
"scripts": {
"start": "icejs start",
"build": "icejs build"
},
"engines": {
"node": ">=8.0.0"
}
}

View File

@ -0,0 +1,12 @@
import { runApp } from 'ice';
runApp({
app: {
onShow() {
console.log('app show...');
},
onHide() {
console.log('app hide...');
}
}
});

View File

@ -0,0 +1,16 @@
{
"routes": [
{
"path": "/todos",
"source": "pages/todos/index"
},
{
"path": "/add-todo",
"source": "pages/add-todo/index"
}
],
"window": {
"defaultTitle": "Todo App",
"titleBarColor": "#323239"
}
}

View File

@ -0,0 +1,15 @@
import React from 'react';
import styles from './index.module.scss';
function AddButton (props) {
const { text, onClickMe } = props;
return (
<button type='button' className={styles['add-button']} onClick={onClickMe}>
<text className={styles['add-icon']}>+</text>
<text>{text}</text>
</button>
);
}
export default AddButton;

View File

@ -0,0 +1,13 @@
.add-button {
display: inline-block;
background: none;
color: #FFF;
border: none;
width: 300rpx;
}
.add-icon {
font-size: 52rpx;
color: #00FFD6;
margin-right: 10rpx;
}

View File

@ -0,0 +1,61 @@
import React, { useState } from 'react';
import AddButton from '@/components/add-button';
import styles from './index.module.scss';
const AddTodo = (props) => {
const { history } = props;
// state
const [value, setValue] = useState('');
// handlers
const onChange = (e) => {
setValue(e.target.value);
};
const add = () => {
const storageKey = 'todos';
// eslint-disable-next-line
const { data } = my.getStorageSync({
key: storageKey
});
if (data !== null) {
data.todos.push({
text: value,
completed: false
});
}
// eslint-disable-next-line
my.setStorageSync({
key: storageKey,
data: {
todos: data.todos
}
});
history.push('/todos');
};
return (
<view className={styles['page-add-todo']}>
<view className={styles['add-todo']}>
<input
className={styles['add-todo-input']}
placeholder="What needs to be done?"
value={value}
onChange={onChange} />
</view>
<view className={styles['todo-footer']}>
<AddButton text="Add Todo" onClickMe={add}/>
</view>
</view>
);
};
export default AddTodo;

View File

@ -0,0 +1,38 @@
page {
background: #323239;
font-family: "pingFang SC" "pingFang";
}
.page-add-todo {
font-family: "pingFang SC" "pingFang";
display: flex;
flex: 1;
flex-direction: column;
}
.add-todo {
padding: 40px;
flex-grow: 1;
display: flex;
justify-content: center;
align-items: center;
}
.add-todo-input {
display: block;
font-size: 50rpx;
font-weight: 100;
padding: 5px 5px;
background: none;
border:none;
border-bottom: 1px solid #DFDFDF;
color: #0EFFD6;
width: 100%;
}
.todo-footer {
padding: 50rpx 0 100rpx;
font-size: 48rpx;
font-weight: 200;
text-align: center;
}

View File

@ -0,0 +1,91 @@
import React, { useState } from 'react';
import { usePageShow } from 'ice';
import AddButton from '@/components/add-button';
import logo from '@/public/logo.svg';
import styles from './index.module.scss';
const Todos = (props) => {
const { history } = props;
// state
const [userInfo, setUserInfo] = useState({});
const [todos, setTodos] = useState([
{ text: 'Learning Javascript', completed: true },
{ text: 'Learning ES2016', completed: true },
{ text: 'Learning 小程序', completed: false },
]);
// handlers
const addTodo = () => {
history.push('/add-todo');
};
const onTodoChange = (text) => {
const changedTodos = todos.map(todo => {
const completed = todo.completed;
return {
...todo,
completed: text === todo.text ? !completed : completed
};
});
setTodos(changedTodos);
};
// lifecyle function
usePageShow(async () => {
// my is global variable in mini program
// eslint-disable-next-line
const myUserInfo = await my.getUserInfo();
setUserInfo(myUserInfo);
console.log('userInfo:', myUserInfo);
// eslint-disable-next-line
const { data } = my.getStorageSync({
key: 'todos'
});
if (data === null) {
// eslint-disable-next-line
my.setStorageSync({
key: 'todos',
data: {
todos
}
});
} else {
setTodos(data.todos);
}
});
return (
<view className={styles['page-todos']}>
<view className={styles.user}>
<image className={styles.avatar} src={userInfo.avatar ? logo : logo} alt="用户头像" />
<text className={styles.nickname}>{userInfo.nickName ? `${userInfo.nickName}'s` : 'My' } Todo List</text>
</view>
<view className={styles['todo-items']}>
<view className={styles['todo-items-group']}>
{
todos.map(todo => (
<view
className={`${styles['todo-item']} ${todo.completed ? styles.checked : ''}`}
onClick={() => onTodoChange(todo.text)}
key={todo.text}>
<checkbox className={styles['todo-item-checkbox']} checked={todo.completed} />
<text className={styles['todo-item-text']}>{todo.text}</text>
</view>
))
}
</view>
</view>
<view className={styles['todo-footer']}>
<AddButton text="Add Todo" onClickMe={addTodo} />
</view>
</view>
);
};
export default Todos;

View File

@ -0,0 +1,130 @@
page {
flex: 1;
display: flex;
background: #323239;
font-family: "pingFang SC" "pingFang";
}
.page-todos {
font-family: "pingFang SC" "pingFang";
display: flex;
flex-direction: column;
width: 750rpx;
max-height: 100vh;
}
.user {
display: flex;
flex-shrink: 0;
padding: 30px;
color: #FFF;
flex-direction: column;
align-items: center;
}
.avatar {
width: 130rpx;
height: 130rpx;
border-radius: 50%;
background-color: #FFF;
align-self: center;
}
.nickname {
padding-top: 40rpx;
text-align: center;
font-size: 40rpx;
font-weight: 100;
}
.todo-items {
flex-grow: 1;
font-size: 34rpx;
padding: 50rpx 120rpx;
color: #0EFFD6;
overflow: auto;
}
.todo-items-group {
display: flex;
flex-direction: column;
}
.todo-item {
position: relative;
margin-bottom: 50rpx;
padding-left:80rpx;
line-height: 70rpx;
height: 80rpx;
box-sizing: border-box;
border: 2px solid rgb(14, 255, 214);
border-radius: 100rpx;
overflow: hidden;
text-overflow: ellipsis;
/* white-space:nowrap; */
transition: border 0.2s;
}
.todo-item:last-child {
margin-bottom: 0;
}
.todo-item::before {
content: '';
position: absolute;
left: 12rpx;
margin-right: 20rpx;
width: 45rpx;
height: 45rpx;
background-color: rgba(14, 222, 255, 0.3);
border-radius: 50%;
top: 50%;
transform: translateY(-50%);
transition: background-color 0.2s;
}
.todo-item::after {
content: '';
position: absolute;
left: 29rpx;
width: 8rpx;
height: 18rpx;
top: 50%;
transform: translateY(-60%) rotate(38deg);
border: 4rpx solid #FFF;
border-width: 0 4rpx 4rpx 0;
opacity: 0;
transition: opacity 0.2s;
}
.todo-item-checkbox {
display: none;
}
.checked .todo-item-text {
text-decoration: line-through;
color: #1AA0B8;
}
.checked.todo-item {
border: 2px solid rgba(14, 222, 255, 0.2);
}
.checked.todo-item::before {
background-color: rgba(14, 222, 255, 0.2);
}
.checked.todo-item::after {
opacity: 1;
}
.todo-footer {
flex-shrink: 0;
padding: 50rpx 0 100rpx;
font-size: 48rpx;
font-weight: 200;
text-align: center;
}

View File

@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="-11.5 -10.23174 23 20.46348">
<title>React Logo</title>
<circle cx="0" cy="0" r="2.05" fill="#61dafb"/>
<g stroke="#61dafb" stroke-width="1" fill="none">
<ellipse rx="11" ry="4.2"/>
<ellipse rx="11" ry="4.2" transform="rotate(60)"/>
<ellipse rx="11" ry="4.2" transform="rotate(120)"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 366 B

View File

@ -0,0 +1,17 @@
{
"compileOnSave": false,
"buildOnSave": false,
"compilerOptions": {
"baseUrl": ".",
"module": "esnext",
"target": "es6",
"jsx": "react",
"moduleResolution": "node",
"sourceMap": true,
"alwaysStrict": true,
"paths": {
"@/*": ["./src/*"],
"ice": [".ice/index.ts"]
}
}
}